diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e22860d..530a58cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,7 +97,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in add_custom_target(doc COMMAND echo "Generating Project documentation." COMMAND doxygen "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile" - #COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_SOURCE_DIR}/doc + COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_SOURCE_DIR}/doc WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating API documentation with Doxygen" ) diff --git a/algorithms/CMakeLists.txt b/algorithms/CMakeLists.txt index 83933a57..d34f7c14 100644 --- a/algorithms/CMakeLists.txt +++ b/algorithms/CMakeLists.txt @@ -1,10 +1,10 @@ # Add subdirectories add_subdirectory(cc) -add_subdirectory(cutvertex) add_subdirectory(matching) +add_subdirectory(mfvs) add_subdirectory(misc) -add_subdirectory(partitioner) +#add_subdirectory(partitioner) add_subdirectory(scc) -add_subdirectory(toposort) +add_subdirectory(sorting) install_lib_headers("${CMAKE_CURRENT_SOURCE_DIR}") diff --git a/algorithms/cc/cc.cpp b/algorithms/cc/cc.cpp index 1156f717..c798d4de 100644 --- a/algorithms/cc/cc.cpp +++ b/algorithms/cc/cc.cpp @@ -17,10 +17,10 @@ ******************************************************************************/ -#include - #include "algorithms/cc/cc.hpp" +#include "sbg/set.hpp" #include "util/logger.hpp" +#include "util/time_profiler.hpp" namespace SBG { @@ -30,29 +30,34 @@ namespace LIB { // Connected components -------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -PWMap connectedComponents(SBG g) +PWMap connectedComponents(const SBG& sbg) { - auto begin = std::chrono::high_resolution_clock::now(); + Util::Internal::TimeProfiler profiler{"Total CC execution time:"}; - if (!g.V().isEmpty()) { - PWMap rmap = PW_FACT.createPWMap(g.V()), old_rmap = PW_FACT.createPWMap(); + Set V = sbg.V(); + if (!V.isEmpty()) { + PWMap rmap{V}; + PWMap old_rmap; - if (g.E().isEmpty()) + if (sbg.E().isEmpty()) { return rmap; + } + PWMap map1 = sbg.map1(); + PWMap map2 = sbg.map2(); do { old_rmap = rmap; - PWMap ermap1 = rmap.composition(g.map1()); - PWMap ermap2 = rmap.composition(g.map2()); + PWMap ermap1 = rmap.composition(map1); + PWMap ermap2 = rmap.composition(map2); - PWMap rmap1 = ermap1.minAdjMap(ermap2); - PWMap rmap2 = ermap2.minAdjMap(ermap1); - rmap1 = rmap1.combine(rmap); - rmap2 = rmap2.combine(rmap); + PWMap rmap1 = ermap1.minAdj(ermap2); + PWMap rmap2 = ermap2.minAdj(ermap1); + rmap1 = std::move(rmap1).combine(rmap); + rmap2 = std::move(rmap2).combine(rmap); - PWMap aux_rmap = rmap1.minMap(rmap2); - rmap = rmap.minMap(aux_rmap); + PWMap aux_rmap = rmap1.min(rmap2); + rmap = rmap.min(aux_rmap); if (!(rmap == old_rmap)) { rmap = aux_rmap; @@ -60,14 +65,11 @@ PWMap connectedComponents(SBG g) } } while (rmap != old_rmap); - return rmap.compact(); + rmap.compact(); + return rmap; } - auto end = std::chrono::high_resolution_clock::now(); - auto total = std::chrono::duration_cast( - end - begin); - Util::SBG_LOG << "Total CC exec time: " << total.count() << "\n"; - return PW_FACT.createPWMap(); + return PWMap{}; } } // namespace LIB diff --git a/algorithms/cc/cc.hpp b/algorithms/cc/cc.hpp index 0d1fa204..fd2379a8 100644 --- a/algorithms/cc/cc.hpp +++ b/algorithms/cc/cc.hpp @@ -21,9 +21,10 @@ ******************************************************************************/ -#ifndef SBG_CC_HPP -#define SBG_CC_HPP +#ifndef SBGRAPH_ALGORITHMS_CC_CC_HPP_ +#define SBGRAPH_ALGORITHMS_CC_CC_HPP_ +#include "sbg/pw_map.hpp" #include "sbg/sbg.hpp" namespace SBG { @@ -34,10 +35,10 @@ namespace LIB { // Connected components -------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -PWMap connectedComponents(SBG g); +PWMap connectedComponents(const SBG& g); } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_CC_CC_HPP_ diff --git a/algorithms/cutvertex/CMakeLists.txt b/algorithms/cutvertex/CMakeLists.txt deleted file mode 100644 index 5a1dc49d..00000000 --- a/algorithms/cutvertex/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -target_sources( - sbgraph - PRIVATE - cut_vertex.cpp - cv_fact.cpp - maxdeg_cv.cpp -) diff --git a/algorithms/cutvertex/cv_fact.hpp b/algorithms/cutvertex/cv_fact.hpp deleted file mode 100755 index dcae5f4b..00000000 --- a/algorithms/cutvertex/cv_fact.hpp +++ /dev/null @@ -1,80 +0,0 @@ -/** @file cv_fact.hpp - - @brief Vertex Cut Set Algorithm Factory - -
- - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -#ifndef SBG_CV_FACT_HPP -#define SBG_CV_FACT_HPP - -#include "cut_vertex.hpp" - -namespace SBG { - -namespace LIB { - -#define CV_FACT CVFactory::instance().cv_fact() - -class CVFact { - public: - virtual ~CVFact() = default; - CVFact() = default; - - virtual CutVertex createCVAlgorithm() const = 0; - virtual std::string prettyPrint() const = 0; -}; - -class MaxDegCVFact : public CVFact { - public: - MaxDegCVFact() = default; - - CutVertex createCVAlgorithm() const override; - std::string prettyPrint() const override; -}; - -using CVFactPtr = std::unique_ptr; - -/** - * @brief Single instance of cv factory to be used by clients in need of - * creating an instance of a cv algorithm. A client includes this file and - * calls CV_FACT.createCVAlgorithm(args). - */ -class CVFactory { - public: - ~CVFactory() = default; - - static CVFactory& instance() { - static CVFactory instance_; - return instance_; - } - CVFact& cv_fact(); - void set_cv_fact(CVFactPtr cv_fact); - - private: - CVFactory(); - - CVFactPtr cv_fact_; -}; - -} // namespace LIB - -} // namespace SBG - -#endif diff --git a/algorithms/cutvertex/maxdeg_cv.cpp b/algorithms/cutvertex/maxdeg_cv.cpp deleted file mode 100644 index 047e1a20..00000000 --- a/algorithms/cutvertex/maxdeg_cv.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/******************************************************************************* - - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -#include - -#include "algorithms/cutvertex/maxdeg_cv.hpp" -#include "algorithms/scc/scc.hpp" -#include "util/logger.hpp" - -namespace SBG { - -namespace LIB { - -//////////////////////////////////////////////////////////////////////////////// -// Maximum Degree Vertex Cut Set Algorithm ------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -MaxDegCutVertex::MaxDegCutVertex() {} - -PWMap MaxDegCutVertex::getDegMap(const DSBG& dsbg) const -{ - Set V = dsbg.V(); - PWMap mapB = dsbg.mapB(), mapD = dsbg.mapD(); - - auto dims = V.arity(); - MD_NAT zero(dims, 0), one(dims, 1); - PWMap dmap = PW_FACT.createPWMap(Map(V, Exp(zero))); - - for (const Map& SE : dsbg.subEmap()) { - Set dom = SE.dom(); - MD_NAT n(dims, dom.cardinal()); - Set vsB = mapB.image(dom), vsD = mapD.image(dom); - if (vsB.cardinal() == 1) { - PWMap ith = dmap.restrict(vsD).offsetImage(n); - dmap = ith.combine(dmap); - ith = dmap.restrict(vsB).offsetImage(one); - dmap = ith.combine(dmap); - } - else if (vsD.cardinal() == 1) { - PWMap ith = dmap.restrict(vsB).offsetImage(n); - dmap = ith.combine(dmap); - ith = dmap.restrict(vsD).offsetImage(one); - dmap = ith.combine(dmap); - } - else { - PWMap ith = dmap.restrict(vsB.cup(vsD)).offsetImage(one); - dmap = ith.combine(dmap); - } - } - - return dmap; -} - -Set MaxDegCutVertex::calculate(const DSBG& dsbg) const -{ - auto start = std::chrono::high_resolution_clock::now(); - - DSBG dg = dsbg; - PWMap Vmap = dg.Vmap(), mapB = dg.mapB(), mapD = dg.mapD(); - PWMap rmap = SCC_FACT.createSCCAlgorithm().calculate(dg).rmap(); - Set newD = SET_FACT.createSet(), oldD = newD, visitedV = newD, V = dg.V(); - - Util::DEBUG_LOG << "initial dg vertex cut set:\n" << dg << "\n"; - - // Degree map - PWMap dmap = getDegMap(dg); - Util::DEBUG_LOG << "initial dmap: " << dmap << "\n\n"; - - while (rmap.dom() != rmap.image()) { - oldD = newD; - - MD_NAT aux = dmap.image().maxElem(); - MD_NAT vmax = dmap.preImage(SET_FACT.createSet(aux)).minElem(); - Set vmaxSV = Vmap.image(SET_FACT.createSet(vmax)); - newD = newD.cup(SET_FACT.createSet(vmax)); - - if (!visitedV.intersection(vmaxSV).isEmpty()) { - MD_NAT vmaxD = newD.intersection(Vmap.preImage(vmaxSV)).minElem(); - - SetPiece mdi; - for (unsigned int j = 0; j < vmax.arity(); ++j) { - if (vmax[j] < vmaxD[j]) { - NAT st = vmaxD[j] - vmax[j]; - NAT beg = vmax[j] % st; - mdi.emplaceBack(Interval(beg, st, vmax[j])); - } - - else - mdi.emplaceBack(Interval(vmaxD[j], vmax[j] - vmaxD[j], Inf)); - } - - Util::DEBUG_LOG << "vmax: " << vmax << "\n"; - Util::DEBUG_LOG << "vmaxD: " << vmaxD << "\n"; - Util::DEBUG_LOG << "mdi: " << mdi << "\n\n"; - - Set mdi_set = SET_FACT.createSet(mdi); - newD = newD.cup(mdi_set.intersection(Vmap.preImage(vmaxSV))); - } - - // Update graph info erasing newD vertices - visitedV = visitedV.cup(vmaxSV); - dg = dg.eraseVertices(newD); - Vmap = dg.Vmap(); - mapB = dg.mapB(); - mapD = dg.mapD(); - - // Update degree map - dmap = getDegMap(dg); - - // Resulting SCC from induced graph - rmap = SCC_FACT.createSCCAlgorithm().calculate(dg).rmap(); - - Util::DEBUG_LOG << "oldD: " << oldD << "\n"; - Util::DEBUG_LOG << "newD: " << newD << "\n"; - Util::DEBUG_LOG << "resulting graph:\n" << dg << "\n"; - Util::DEBUG_LOG << "new degree map: " << dmap << "\n"; - Util::DEBUG_LOG << "new rmap: " << rmap << "\n\n"; - } - auto end = std::chrono::high_resolution_clock::now(); - - auto total = std::chrono::duration_cast( - end - start - ); - Util::SBG_LOG << "Total vertex cut set exec time: " << total.count() << " [μs]\n\n"; - - return newD.compact(); -} - -} // namespace LIB - -} // namespace SBG diff --git a/algorithms/matching/CMakeLists.txt b/algorithms/matching/CMakeLists.txt index 7c9cc99e..64657b44 100644 --- a/algorithms/matching/CMakeLists.txt +++ b/algorithms/matching/CMakeLists.txt @@ -4,5 +4,6 @@ target_sources( bfs_matching.cpp bfs_paths.cpp matching.cpp - matching_fact.cpp + match_data.cpp + matching_impl.cpp ) diff --git a/algorithms/matching/bfs_matching.cpp b/algorithms/matching/bfs_matching.cpp index b74a178c..452f266f 100644 --- a/algorithms/matching/bfs_matching.cpp +++ b/algorithms/matching/bfs_matching.cpp @@ -17,15 +17,16 @@ ******************************************************************************/ -#include - #include "algorithms/matching/bfs_matching.hpp" +#include "sbg/natural.hpp" #include "util/logger.hpp" namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // BFS Matching Algorithm ------------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// @@ -44,173 +45,149 @@ bool BFSMatching::ExitCondition::isSatisfied() // Algorithm ------------------------------------------------------------------- -BFSMatching::BFSMatching() : M_(SET_FACT.createSet()), dsbg_() - , direction_(Direction::kForward) {} +BFSMatching::BFSMatching() : _M(), _dsbg() , _direction(Direction::kForward) + , _X(), _Y() {} void BFSMatching::swapEdgesDirection(const Set& E) { - PWMap mapB = dsbg_.mapB(); - PWMap mapD = dsbg_.mapD(); + PWMap mapB = _dsbg.mapB(); + PWMap mapD = _dsbg.mapD(); PWMap temp_mapB = mapB.restrict(E); - mapB = mapD.restrict(E).combine(mapB); - mapD = temp_mapB.restrict(E).combine(mapD); + mapB = mapD.restrict(E).combine(std::move(mapB)); + mapD = temp_mapB.restrict(E).combine(std::move(mapD)); - dsbg_ = DSBG(dsbg_.V().compact(), dsbg_.Vmap().compact() - , mapB.compact(), mapD.compact(), dsbg_.Emap().compact() - , dsbg_.subEmap().compact()); + _dsbg = DirectedSBG{_dsbg.V(), _dsbg.Vmap(), mapB, mapD, _dsbg.Emap()}; +} - return; +void BFSMatching::swapDirection(const Set& E) +{ + swapEdgesDirection(E); + Set temp_X = _X; + _X = _Y; + _Y = temp_X; } PWMap BFSMatching::partitionSubsetEdges() const { - PWMap result = PW_FACT.createPWMap(); - Set free_edges = dsbg_.E().difference(M_); - unsigned int dims = free_edges.arity(); - unsigned int j = 1; - for (const Map& subset_edge : dsbg_.subEmap()) { - Set dom = subset_edge.dom(); - Exp matched_exp(MD_NAT(dims, j)); - Map matched_map(M_.intersection(dom), matched_exp); - ++j; - Exp free_exp(MD_NAT(dims, j)); - Map free_map(free_edges.intersection(dom), free_exp); + PWMap result; + Set free_edges = _dsbg.E().difference(_M); + std::size_t arity = free_edges.arity(); + NAT j = 1; + PWMap Emap = _dsbg.Emap(); + _dsbg.foreachSetEdge([&](const MD_NAT& SE) + { + Set domain_edges = Emap.preImage(Set{SE}); + + Expression matched_expr{MD_NAT{arity, j}}; + result.emplace(_M.intersection(domain_edges), matched_expr); ++j; - result.emplaceBack(matched_map); - result.emplaceBack(free_map); - } + Expression free_expr{MD_NAT{arity, j}}; + result.emplace(free_edges.intersection(domain_edges), free_expr); + ++j; + }); return result; } -Set BFSMatching::edgesInPaths(const PWMap& smap, const Set& E) const -{ - PWMap mapB = dsbg_.mapB().restrict(E); - PWMap mapD = dsbg_.mapD().restrict(E); - - // Vertices that are successors of other vertices in a path - Set not_fixed = smap.dom().difference(smap.fixedPoints()); - Set succs = smap.restrict(not_fixed).image(); - // Edges whose endings are successors - Set ending_edges = mapD.preImage(succs); - // Map from a 'successor' edge to its start - PWMap auxB = mapB.restrict(ending_edges); - // Map from edge to the successor of its start - PWMap map_succs = smap.composition(auxB); - - return map_succs.equalImage(mapD); -} - -Set BFSMatching::directedStep(const Set& E, const Set& right_vertices) +Set BFSMatching::directedStep(const Set& E) { - PWMap mapB = dsbg_.mapB().restrict(E).compact(); - PWMap mapD = dsbg_.mapD().restrict(E).compact(); - PWMap Emap = dsbg_.Emap().restrict(E).compact(); - PWMap subEmap = partitionSubsetEdges().restrict(E).compact(); + PWMap mapB = _dsbg.mapB().restrict(E); + PWMap mapD = _dsbg.mapD().restrict(E); + PWMap Emap = partitionSubsetEdges().restrict(E); // Calculate unmatched vertices in the side determined by the current // direction of edges - Set forward_vertices = dsbg_.V().difference(right_vertices); - Set matched_forward_vertices = mapB.image(M_); - if (direction_ == Direction::kBackward) { - forward_vertices = right_vertices; - } + Set matched_forward_vertices = mapB.image(_M); Set unmatched_forward_vertices - = forward_vertices.difference(matched_forward_vertices); + = _X.difference(matched_forward_vertices); // Detect paths leading to unmatched_forward_vertices - DSBG restricted_dsbg(dsbg_.V(), dsbg_.Vmap(), mapB, mapD, Emap, subEmap); + DirectedSBG restricted_dsbg{_dsbg.V(), _dsbg.Vmap(), mapB, mapD, Emap}; BFSPaths paths; - PWMap smap = paths.calculate(restricted_dsbg, unmatched_forward_vertices); - - // Keep edges - Set paths_edges = edgesInPaths(smap, E); - PWMap rmap = smap.mapInf(); - Set reach_unmatched = rmap.preImage(unmatched_forward_vertices); - paths_edges = paths_edges.intersection(mapD.preImage(reach_unmatched)); - - Util::DEBUG_LOG << "paths_edges in " << direction_ << " direction: " - << paths_edges << "\n"; - return paths_edges; + return paths.calculate(restricted_dsbg, unmatched_forward_vertices); } -BFSMatching::ExitCondition BFSMatching::step(const Set& right_vertices) +BFSMatching::ExitCondition BFSMatching::step() { - Set E = dsbg_.E(); + Set E = _dsbg.E(); // Forward direction - Set paths_edgesD = directedStep(E, right_vertices); + Set P = directedStep(E); // Backward direction - swapEdgesDirection(E); - direction_ = Direction::kBackward; - Set paths_edgesB = directedStep(paths_edgesD, right_vertices); + swapDirection(E); + _direction = Direction::kBackward; + Set augmenting_edges = directedStep(P); - // Calculate augmenting paths and swap edges in these paths - Set augmenting_edges = paths_edgesB.intersection(paths_edgesD); + // Swap direction for edges in augmenting paths Util::DEBUG_LOG << "augmenting paths: " << augmenting_edges << "\n"; - swapEdgesDirection(augmenting_edges); + swapDirection(augmenting_edges); // Swap directions in all graph swapEdgesDirection(E); - direction_ = Direction::kForward; + _direction = Direction::kForward; // Calculate new matched edges - M_ = dsbg_.mapD().preImage(right_vertices); + _M = _dsbg.mapD().preImage(_Y); // Calculate exit conditions - Set matchedU = dsbg_.mapD().image(M_); - bool full_match = right_vertices.difference(matchedU).isEmpty(); + Set matchedU = _dsbg.mapD().image(_M); + bool full_match = _Y.difference(matchedU).isEmpty(); bool found_paths = !augmenting_edges.isEmpty(); - return ExitCondition(full_match, found_paths); + return ExitCondition{full_match, found_paths}; } void BFSMatching::init(const BipartiteSBG& bsbg) { - PWMap map1 = bsbg.map1().compact(); - PWMap map2 = bsbg.map2().compact(); + PWMap map1 = bsbg.map1(); + map1.compact(); + PWMap map2 = bsbg.map2(); + map2.compact(); Set Y = bsbg.Y(); PWMap map1_toY = map1.restrict(map1.preImage(Y)); PWMap map2_toY = map2.restrict(map2.preImage(Y)); - PWMap mapB = map1_toY.concatenation(map2_toY); + PWMap mapB = std::move(map1_toY).concatenation(std::move(map2_toY)); Set X = bsbg.X(); PWMap map1_toX = map1.restrict(map1.preImage(X)); PWMap map2_toX = map2.restrict(map2.preImage(X)); - PWMap mapD = map1_toX.concatenation(map2_toX); - - dsbg_ = DSBG(bsbg.V().compact(), bsbg.Vmap().compact(), mapB, mapD - , bsbg.Emap().compact(), bsbg.subEmap().compact()); + PWMap mapD = std::move(map1_toX).concatenation(std::move(map2_toX)); + + Set V = bsbg.V(); + V.compact(); + PWMap Vmap = bsbg.Vmap(); + Vmap.compact(); + PWMap Emap = bsbg.Emap(); + Emap.compact(); + _dsbg = DirectedSBG{V, Vmap, mapB, mapD, Emap}; } MatchData BFSMatching::calculate(const BipartiteSBG& bsbg) { - Util::DEBUG_LOG << "Matching bsbg: \n" << bsbg << "\n\n"; - - auto begin = std::chrono::high_resolution_clock::now(); init(bsbg); - Set right_vertices = bsbg.Y(); + Util::SBG_LOG << "Matching bipartite SBG: " << bsbg << "\n\n"; + _X = bsbg.X(); + _Y = bsbg.Y(); - ExitCondition exit_cond(false, false); + ExitCondition exit_cond{false, false}; do { - exit_cond = step(right_vertices); + exit_cond = step(); } while (!exit_cond.isSatisfied()); - auto end = std::chrono::high_resolution_clock::now(); - auto total = std::chrono::duration_cast( - end - begin); - Util::SBG_LOG << "Total matching exec time: " << total.count() << " [μs]\n"; - MatchData result(bsbg, M_.compact(), exit_cond.full_match()); + _M.compact(); + MatchData result{bsbg, _M, exit_cond.full_match()}; Util::SBG_LOG << result << "\n\n"; return result; } +} // namespace detail + } // namespace LIB } // namespace SBG diff --git a/algorithms/matching/bfs_matching.hpp b/algorithms/matching/bfs_matching.hpp index ede72046..ae84473e 100644 --- a/algorithms/matching/bfs_matching.hpp +++ b/algorithms/matching/bfs_matching.hpp @@ -21,19 +21,24 @@ ******************************************************************************/ -#ifndef SBG_BFS_MATCH_HPP -#define SBG_BFS_MATCH_HPP +#ifndef SBGRAPH_ALGORITHMS_MATCHING_BFS_MATCHING_HPP_ +#define SBGRAPH_ALGORITHMS_MATCHING_BFS_MATCHING_HPP_ #include "algorithms/matching/bfs_paths.hpp" -#include "algorithms/matching/matching.hpp" +#include "algorithms/matching/match_data.hpp" +#include "sbg/bipartite_sbg.hpp" #include "sbg/directed_sbg.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/set.hpp" namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// -// BFS Matching Algorithm Implementation (concrete strategy) ------------------- +// BFS Matching Algorithm Implementation --------------------------------------- //////////////////////////////////////////////////////////////////////////////// /** @@ -47,19 +52,19 @@ namespace LIB { * The algorithms stops once a full match is calculated (i.e. one that saturates * all right vertices), or when no more augmenting paths are found. */ -class BFSMatching : public MatchStrategy { - public: +class BFSMatching { +public: BFSMatching(); - MatchData calculate(const BipartiteSBG& bsbg) override; + MatchData calculate(const BipartiteSBG& bsbg); - private: +private: /** * @brief Auxiliary struct to represent the exit condition of the algorithm * loop. */ class ExitCondition { - public: + public: ExitCondition(bool full_match, bool found_paths_); bool full_match(); @@ -67,7 +72,7 @@ class BFSMatching : public MatchStrategy { bool isSatisfied(); - private: + private: bool full_match_; bool found_paths_; }; @@ -89,7 +94,7 @@ class BFSMatching : public MatchStrategy { * saturated and b) New paths weren't found. This is calculated here instead * of the main loop to avoid recalculation of certain values. */ - ExitCondition step(const Set& right_vertices); + ExitCondition step(); /** * @brief Computes alternating paths in a certain direction. @@ -98,7 +103,7 @@ class BFSMatching : public MatchStrategy { * @return Edges belonging to alternating paths that reach unmatched vertices * in the aforementioned direction. */ - Set directedStep(const Set& E, const Set& right_vertices); + Set directedStep(const Set& E); /** * @brief Modifies the `dsbg_` member, swapping mapB and mapD for elements of @@ -106,25 +111,25 @@ class BFSMatching : public MatchStrategy { */ void swapEdgesDirection(const Set& E); + void swapDirection(const Set& E); + /** * @brief Separates in different subset-edges matched and unmatched edges * belonging to the same subset-edge in `dsbg_`. */ PWMap partitionSubsetEdges() const; - /** - * @brief Returns edges in `E` that belong to the paths described by the - * successor map `smap`. - */ - Set edgesInPaths(const PWMap& smap, const Set& E) const; - - DSBG dsbg_; ///< Directed graph according to matching - Set M_; ///< Matched edges - Direction direction_; + DirectedSBG _dsbg; ///< Directed graph according to matching + Set _M; ///< Matched edges + Direction _direction; + Set _X; + Set _Y; }; +} // namespace detail + } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_MATCHING_BFS_MATCHING_HPP_ diff --git a/algorithms/matching/bfs_paths.cpp b/algorithms/matching/bfs_paths.cpp index ec5601c5..81cdf46e 100644 --- a/algorithms/matching/bfs_paths.cpp +++ b/algorithms/matching/bfs_paths.cpp @@ -24,67 +24,83 @@ namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // Path Finder BFS Implementation ---------------------------------------------- //////////////////////////////////////////////////////////////////////////////// BFSPaths::BFSPaths() {} -PWMap BFSPaths::calculate(const DSBG& dsbg, const Set& endings) +Set BFSPaths::calculate(const DirectedSBG& dsbg, const Set& endings) { - Set dsbgV = dsbg.V(); - PWMap dsbgB = dsbg.mapB(); - PWMap dsbgD = dsbg.mapD(); - PWMap subEmap = dsbg.subEmap(); + Set V = dsbg.V(); + PWMap mapB = dsbg.mapB(); + PWMap auxB = mapB; + PWMap mapD = dsbg.mapD(); + PWMap auxD = mapD; + PWMap Emap = dsbg.Emap(); - // Unmatched vertices in forward direction - PWMap res = PW_FACT.createPWMap(endings); + // Successor map to unmatched vertices + PWMap smap{endings}; // A record of allowed edges to keep out cycle edges - Set allowed_edges = dsbg.E(); - // Ingoing edges to vertices that reach unmatched_D - Set ingoing = dsbgD.preImage(endings); + Set E = dsbg.E(); + // Ingoing edges to vertices that reach endings + Set ingoing = mapD.preImage(endings); // A record of visited set-edges - Set visitedE = SET_FACT.createSet(); + Set visitedSE; do { // Calculate successor for ith vertices - PWMap ingB = dsbgB.restrict(ingoing), ingD = dsbgD.restrict(ingoing); - PWMap ith_smap = ingB.minAdjMap(ingD); + PWMap ingoingB = auxB.restrict(ingoing); + PWMap ingoingD = auxD.restrict(ingoing); + PWMap ith_smap = ingoingB.minAdj(ingoingD); Util::DEBUG_LOG << "ith_smap: " << ith_smap << "\n"; // Edges that lead to a successor - Set Eith = dsbgD.equalImage(ith_smap.composition(dsbgB)); + Set Ei = auxD.equalImage(ith_smap.composition(auxB)); // Visited set-edges - Set Erec = visitedE.intersection(subEmap.image(Eith)); - // Handle recursion - if (!Erec.isEmpty()) { - Set Eplus = subEmap.preImage(Erec); - PWMap rec_smap = dsbgB.restrict(Eplus).minAdjMap(dsbgD.restrict(Eplus)); - Util::DEBUG_LOG << "rec_smap: " << rec_smap << "\n"; - ith_smap = ith_smap.combine(rec_smap); + Set repeatedSE = visitedSE.intersection(Emap.image(Ei)); + if (!repeatedSE.isEmpty()) { + // Propose candidate successors for repetitive paths + Set Eplus = Emap.preImage(repeatedSE); + PWMap smap_plus = auxB.restrict(Eplus).minAdj(auxD.restrict(Eplus)); + Util::DEBUG_LOG << "smap_plus: " << smap_plus << "\n"; + ith_smap = ith_smap.combine(smap_plus); + visitedSE = visitedSE.difference(repeatedSE); + } else { + visitedSE = visitedSE.disjointCup(Emap.image(Ei)); } - res = ith_smap.combine(res); - + smap = ith_smap.combine(smap); + // Take out other outgoing edges to avoid cycles - allowed_edges = allowed_edges.difference(dsbgB.preImage(res.dom())); - dsbgD = dsbgD.restrict(allowed_edges); - dsbgB = dsbgB.restrict(allowed_edges); + E = E.difference(auxB.preImage(smap.domain())); + auxD = auxD.restrict(E); + auxB = auxB.restrict(E); // Edges that reach vertices with a successor - ingoing = dsbgD.preImage(res.dom()).intersection(allowed_edges); - - visitedE = visitedE.cup(subEmap.image(Eith)); + ingoing = auxD.preImage(smap.domain()).intersection(E); - Util::DEBUG_LOG << "Eith: " << Eith << "\n"; - Util::DEBUG_LOG << "Erec: " << Erec << "\n"; - Util::DEBUG_LOG << "visitedE: " << visitedE << "\n"; - Util::DEBUG_LOG << "res: " << res << "\n\n"; + Util::DEBUG_LOG << "Ei: " << Ei << "\n"; + Util::DEBUG_LOG << "repeatedSE: " << repeatedSE << "\n"; + Util::DEBUG_LOG << "visitedSE: " << visitedSE << "\n"; + Util::DEBUG_LOG << "smap: " << smap << "\n\n"; } while (!ingoing.isEmpty()); - return res; + // Keep edges that reach vertices in U + Set P = smap.composition(mapB).equalImage(mapD); + PWMap rmap = smap.mapInf(); + Set reach_unmatched = rmap.preImage(endings); + P = P.intersection(mapD.preImage(reach_unmatched)); + + Util::DEBUG_LOG << "BFS Paths P: " << P << "\n\n"; + + return P; } +} // namespace detail + } // namespace LIB } // namespace SBG diff --git a/algorithms/matching/bfs_paths.hpp b/algorithms/matching/bfs_paths.hpp index 5b8b699c..03f7f405 100644 --- a/algorithms/matching/bfs_paths.hpp +++ b/algorithms/matching/bfs_paths.hpp @@ -23,15 +23,20 @@ ******************************************************************************/ -#ifndef SBG_BFS_PATH_HPP -#define SBG_BFS_PATH_HPP +#ifndef SBGRAPH_ALGORITHMS_MATCHING_BFS_PATHS_HPP_ +#define SBGRAPH_ALGORITHMS_MATCHING_BFS_PATHS_HPP_ #include "algorithms/matching/paths.hpp" +#include "sbg/directed_sbg.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/set.hpp" namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // Paths Discoverer Algorithm -------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// @@ -40,21 +45,23 @@ namespace LIB { * @brief Backward BFS implementation to calculate paths. */ class BFSPaths : public PathsContext { - public: +public: BFSPaths(); /** * @brief Concrete implementation that starts with the identity pw for * vertices belonging to `endings`. In each step adds adjacent vertices to - * the map. It also detects recursions (i.e. if a Set-Vertex is visited more) + * the map. It also detects repetitions (i.e. if a set-vertex is visited more) * than once, replicating the same path for every element of the same - * Set-Vertex. + * set-vertex. */ - PWMap calculate(const DSBG& dsbg, const Set& endings); + Set calculate(const DirectedSBG& dsbg, const Set& endings); }; +} // namespace detail + } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_MATCHING_BFS_PATHS_HPP_ diff --git a/algorithms/matching/match_data.cpp b/algorithms/matching/match_data.cpp new file mode 100644 index 00000000..73adeace --- /dev/null +++ b/algorithms/matching/match_data.cpp @@ -0,0 +1,72 @@ +/******************************************************************************* + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "algorithms/matching/match_data.hpp" +#include "util/debug.hpp" + +namespace SBG { + +namespace LIB { + +std::ostream& operator<<(std::ostream& out, const Direction& direction) +{ + switch (direction) { + case Direction::kForward: { + out << "forward"; + break; + } + + case Direction::kBackward: { + out << "backward"; + break; + } + + default: { + Util::ERROR("Unsupported direction"); + break; + } + } + + return out; +} + +MatchData::MatchData(BipartiteSBG bsbg, Set M, bool full_match) + : _bsbg(bsbg), _M(M), _full_match(full_match) {} + +const BipartiteSBG& MatchData::bsbg() const { return _bsbg; } + +const Set& MatchData::M() const { return _M; } + +const bool& MatchData::full_match() const { return _full_match; } + +std::ostream& operator<<(std::ostream& out, const MatchData& data) +{ + out << data.M(); + if (data.full_match()) { + out << " [FULLY MATCHED]"; + } else { + out << " [UNMATCHED]"; + } + + return out; +} + +} // namespace LIB + +} // namespace SBG diff --git a/algorithms/matching/match_data.hpp b/algorithms/matching/match_data.hpp new file mode 100644 index 00000000..03f766af --- /dev/null +++ b/algorithms/matching/match_data.hpp @@ -0,0 +1,64 @@ +/** @file match_data.hpp + + @brief Input and Output Matching data structure + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_ALGORITHMS_MATCHING_MATCH_DATA_HPP_ +#define SBGRAPH_ALGORITHMS_MATCHING_MATCH_DATA_HPP_ + +#include "sbg/bipartite_sbg.hpp" + +namespace SBG { + +namespace LIB { + +//////////////////////////////////////////////////////////////////////////////// +// Auxiliary structures -------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +enum class Direction { kForward, kBackward }; + +std::ostream& operator<<(std::ostream& out, const Direction& direction); + +/** + * @brief Saves input and output data from a matching algorithm run. + */ +class MatchData { +public: + MatchData(BipartiteSBG bsbg, Set M, bool full_match); + + const BipartiteSBG& bsbg() const; + const Set& M() const; + const bool& full_match() const; + +private: + BipartiteSBG _bsbg; ///< Original input for the algorithm + Set _M; ///< Matched edges + bool _full_match; ///< Returns true if all right vertices are saturated +}; + +std::ostream& operator<<(std::ostream& out, const MatchData& data); + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_ALGORITHMS_MATCHING_MATCH_DATA_HPP_ diff --git a/algorithms/matching/matching.cpp b/algorithms/matching/matching.cpp index 7d54c33c..9551b2e2 100644 --- a/algorithms/matching/matching.cpp +++ b/algorithms/matching/matching.cpp @@ -17,66 +17,40 @@ ******************************************************************************/ -#include - #include "algorithms/matching/matching.hpp" -#include "util/logger.hpp" +#include "algorithms/matching/matching_impl.hpp" +#include "util/debug.hpp" +#include "util/time_profiler.hpp" namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Auxiliary structures -------------------------------------------------------- +// Matching Algorithm Interface ------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// -std::ostream& operator<<(std::ostream& out, const Direction& direction) +Matching::Matching() : _impl() { - switch (direction) { - case Direction::kForward: - out << "forward"; - break; - case Direction::kBackward: - out << "backward"; + MatchKind kind = MATCH_IMPL.kind(); + switch (kind) { + case MatchKind::kBFSPaths: { + _impl = detail::BFSMatching{}; break; - } - - return out; -} + } -MatchData::MatchData(BipartiteSBG bsbg, Set M, bool full_match) - : bsbg_(bsbg), M_(M), full_match_(full_match) {} - -const BipartiteSBG& MatchData::bsbg() const { return bsbg_; } -const Set& MatchData::M() const { return M_; } -const bool& MatchData::full_match() const { return full_match_; } - -std::ostream& operator<<(std::ostream& out, const MatchData& data) -{ - out << data.M(); - if (data.full_match()) - out << " [FULLY MATCHED]"; - else - out << " [UNMATCHED]"; - - return out; + default: { + Util::ERROR("Unsupported matching algorithm implementation"); + break; + } + } } -//////////////////////////////////////////////////////////////////////////////// -// Matching Algorithm Abstract Strategy Constructors --------------------------- -//////////////////////////////////////////////////////////////////////////////// - -MatchStrategy::MatchStrategy() {} - -//////////////////////////////////////////////////////////////////////////////// -// Matching Algorithm Interface ------------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -Matching::Matching(MatchStratPtr strat) : strategy_(std::move(strat)) {} - MatchData Matching::calculate(const BipartiteSBG& bsbg) { - return strategy_->calculate(bsbg); + Util::Internal::TimeProfiler profiler{"Total matching execution time: "}; + + return std::visit([&](auto& a) { return a.calculate(bsbg); }, _impl); } } // namespace LIB diff --git a/algorithms/matching/matching.hpp b/algorithms/matching/matching.hpp index e229dadb..bdcc91ff 100644 --- a/algorithms/matching/matching.hpp +++ b/algorithms/matching/matching.hpp @@ -1,6 +1,6 @@ /** @file matching.hpp - @brief SBG Matching Algorithm Abstract Interface + @brief SBG Matching Algorithm
@@ -21,74 +21,45 @@ ******************************************************************************/ -#ifndef SBG_MATCH_HPP -#define SBG_MATCH_HPP +#ifndef SBGRAPH_ALGORITHMS_MATCHING_MATCHING_HPP_ +#define SBGRAPH_ALGORITHMS_MATCHING_MATCHING_HPP_ +#include "algorithms/matching/bfs_matching.hpp" +#include "algorithms/matching/match_data.hpp" #include "sbg/bipartite_sbg.hpp" +#include + namespace SBG { namespace LIB { -//////////////////////////////////////////////////////////////////////////////// -// Auxiliary structures -------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -enum class Direction { kForward, kBackward }; -std::ostream& operator<<(std::ostream& out, const Direction& direction); - -/** - * @brief Saves input and output data from a matching algorithm run. - */ -struct MatchData { - public: - MatchData(BipartiteSBG bsbg, Set M, bool full_match); - - const BipartiteSBG& bsbg() const; - const Set& M() const; - const bool& full_match() const; - - private: - BipartiteSBG bsbg_; ///< Original input for the algorithm - Set M_; ///< Matched edges - bool full_match_; ///< Returns true if all right vertices are saturated -}; -std::ostream& operator<<(std::ostream& out, const MatchData& data); +namespace detail { //////////////////////////////////////////////////////////////////////////////// -// Matching Algorithm Abstract Strategy ---------------------------------------- +// Matching Algorithm Implementations ------------------------------------------ //////////////////////////////////////////////////////////////////////////////// -class MatchStrategy; - -typedef std::unique_ptr MatchStratPtr; - -class MatchStrategy { - public: - virtual ~MatchStrategy() = default; - - MatchStrategy(); - - virtual MatchData calculate(const BipartiteSBG& bsbg) = 0; -}; +using MatchImpl = std::variant; +} // namespace detail //////////////////////////////////////////////////////////////////////////////// -// Matching Algorithm Interface (context) -------------------------------------- +// Matching Algorithm ---------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// class Matching { - public: - Matching(MatchStratPtr strat); +public: + Matching(); MatchData calculate(const BipartiteSBG& bsbg); - private: - MatchStratPtr strategy_; +private: + detail::MatchImpl _impl; }; } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_MATCHING_MATCHING_HPP_ diff --git a/algorithms/matching/matching_fact.hpp b/algorithms/matching/matching_fact.hpp deleted file mode 100755 index c69a9f71..00000000 --- a/algorithms/matching/matching_fact.hpp +++ /dev/null @@ -1,80 +0,0 @@ -/** @file matching_fact.hpp - - @brief Matching Algorithm Factory - -
- - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -#ifndef SBG_MATCHING_FACT_HPP -#define SBG_MATCHING_FACT_HPP - -#include "algorithms/matching/matching.hpp" - -namespace SBG { - -namespace LIB { - -#define MATCH_FACT MatchFactory::instance().match_fact() - -class MatchingFact { - public: - virtual ~MatchingFact() = default; - MatchingFact() = default; - - virtual Matching createMatchAlgorithm() const = 0; - virtual std::string prettyPrint() const = 0; -}; - -class BFSMatchingFact : public MatchingFact { - public: - BFSMatchingFact() = default; - - Matching createMatchAlgorithm() const override; - std::string prettyPrint() const override; -}; - -using MatchFactPtr = std::unique_ptr; - -/** - * @brief Single instance of match factory to be used by clients in need of - * creating an instance of a matching algorithm. A client includes this file and - * calls MATCH_FACT.createMatchAlgorithm(args). - */ -class MatchFactory { - public: - ~MatchFactory() = default; - - static MatchFactory& instance() { - static MatchFactory instance_; - return instance_; - } - MatchingFact& match_fact(); - void set_match_fact(MatchFactPtr match_fact); - - private: - MatchFactory(); - - MatchFactPtr match_fact_; -}; - -} // namespace LIB - -} // namespace SBG - -#endif diff --git a/algorithms/cutvertex/cut_vertex.cpp b/algorithms/matching/matching_impl.cpp old mode 100644 new mode 100755 similarity index 59% rename from algorithms/cutvertex/cut_vertex.cpp rename to algorithms/matching/matching_impl.cpp index c24a5ede..3af58e85 --- a/algorithms/cutvertex/cut_vertex.cpp +++ b/algorithms/matching/matching_impl.cpp @@ -17,33 +17,46 @@ ******************************************************************************/ -#include - -#include "algorithms/cutvertex/cut_vertex.hpp" -#include "algorithms/scc/scc.hpp" -#include "util/logger.hpp" +#include "algorithms/matching/matching_impl.hpp" +#include "util/debug.hpp" namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Vertex Cut Set Algorithm Abstract Strategy Constructors --------------------- +// Matching implementations ---------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -CVStrategy::CVStrategy() {} - -//////////////////////////////////////////////////////////////////////////////// -// Vertex Cut Set Algorithm Interface ------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// +std::ostream& operator<<(std::ostream& out, const MatchKind kind) +{ + switch (kind) { + case MatchKind::kBFSPaths: { + out << "BFS paths"; + break; + } + + default: { + Util::ERROR("Unsupported matching algorithm implementation"); + break; + } + } + + return out; +} -CutVertex::CutVertex(CVStratPtr strat) : strategy_(std::move(strat)) {} +MatchImplementation::MatchImplementation() : _kind(MatchKind::kBFSPaths) {} -Set CutVertex::calculate(const DSBG& dsbg) const +MatchImplementation& MatchImplementation::instance() { - return strategy_->calculate(dsbg); + static MatchImplementation _instance; + return _instance; } +const MatchKind& MatchImplementation::kind() const { return _kind; } + +void MatchImplementation::set_match_fact(MatchKind kind) { _kind = kind; } + } // namespace LIB } // namespace SBG diff --git a/algorithms/matching/matching_impl.hpp b/algorithms/matching/matching_impl.hpp new file mode 100755 index 00000000..fb1c8a98 --- /dev/null +++ b/algorithms/matching/matching_impl.hpp @@ -0,0 +1,65 @@ +/** @file matching_impl.hpp + + @brief Matching Algorithm Implementation + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_ALGORITHMS_MATCHING_MATCHING_IMPL_HPP_ +#define SBGRAPH_ALGORITHMS_MATCHING_MATCHING_IMPL_HPP_ + +#include + +namespace SBG { + +namespace LIB { + +//////////////////////////////////////////////////////////////////////////////// +// Matching implementations ---------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +enum class MatchKind { kBFSPaths }; + +std::ostream& operator<<(std::ostream& out, const MatchKind kind); + +#define MATCH_IMPL MatchImplementation::instance() + +/** + * @brief Singleton that keeps record of the chosen matching implementation. + */ +class MatchImplementation { +public: + ~MatchImplementation() = default; + + static MatchImplementation& instance(); + + const MatchKind& kind() const; + void set_match_fact(MatchKind kind); + +private: + MatchImplementation(); + + MatchKind _kind; +}; + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_ALGORITHMS_MATCHING_MATCHING_IMPL_HPP_ diff --git a/algorithms/matching/paths.hpp b/algorithms/matching/paths.hpp index 5d698df4..29589d58 100644 --- a/algorithms/matching/paths.hpp +++ b/algorithms/matching/paths.hpp @@ -23,15 +23,19 @@ ******************************************************************************/ -#ifndef SBG_PATH_HPP -#define SBG_PATH_HPP +#ifndef SBGRAPH_ALGORITHMS_MATCHING_PATHS_HPP_ +#define SBGRAPH_ALGORITHMS_MATCHING_PATHS_HPP_ #include "sbg/directed_sbg.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/set.hpp" namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // Paths Discoverer Algorithm -------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// @@ -44,24 +48,26 @@ namespace LIB { */ template class PathsContext { - public: +public: /** * @brief For every vertex of `dsbg` calculates a path starting from itself * up to a vertex in `endings`. * @return The resulting pw is such that if pw(x) = y, then y is the successor * of x in the path. */ - inline PWMap calculate(const DSBG& dsbg, const Set& endings) + inline PWMap calculate(const DirectedSBG& dsbg, const Set& endings) { return static_cast(this)->calculate(dsbg, endings); } - protected: +protected: PathsContext() = default; }; +} // namespace detail + } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_MATCHING_PATHS_HPP_ diff --git a/algorithms/mfvs/CMakeLists.txt b/algorithms/mfvs/CMakeLists.txt new file mode 100644 index 00000000..1fd3cbb1 --- /dev/null +++ b/algorithms/mfvs/CMakeLists.txt @@ -0,0 +1,8 @@ +target_sources( + sbgraph + PRIVATE + greedy_mfvs.cpp + min_feedback_vertex_set.cpp + mfvs_impl.cpp + smallest_sv_mfvs.cpp +) diff --git a/algorithms/mfvs/greedy_mfvs.cpp b/algorithms/mfvs/greedy_mfvs.cpp new file mode 100644 index 00000000..cd0d2ca4 --- /dev/null +++ b/algorithms/mfvs/greedy_mfvs.cpp @@ -0,0 +1,113 @@ +/******************************************************************************* + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "algorithms/mfvs/greedy_mfvs.hpp" +#include "algorithms/scc/scc.hpp" +#include "sbg/natural.hpp" +#include "sbg/pw_map.hpp" +#include "util/logger.hpp" + +#include + +namespace SBG { + +namespace LIB { + +namespace detail { + +//////////////////////////////////////////////////////////////////////////////// +// Greedy MFVS Algorithm ------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +GreedyMFVS::GreedyMFVS() {} + +/** + * @brief It calculates the minimum vertex with maximum degree. + */ +MD_NAT maxDegreeVertex(const DirectedSBG& dsbg) +{ + PWMap multB = dsbg.mapB().imageMultiplicity(); + PWMap multD = dsbg.mapD().imageMultiplicity(); + PWMap mmap = multB + multD; + + MD_NAT max_mult{dsbg.V().arity(), 0}; + Set remaining = mmap.image(); + while (!remaining.isEmpty()) { + MD_NAT jth_mult = remaining.minElem(); + NAT current_degree = std::accumulate(max_mult.begin(), max_mult.end(), 0); + NAT jth_degree = std::accumulate(jth_mult.begin(), jth_mult.end(), 0); + if (jth_degree > current_degree) { + max_mult = jth_mult; + } + + remaining = remaining.difference(Set{jth_mult}); + } + + Set max_mult_set{max_mult}; + Set max_degree_vertices = mmap.preImage(max_mult_set); + + return max_degree_vertices.minElem(); +} + +Set GreedyMFVS::calculate(const DirectedSBG& input_dsbg) const +{ + DirectedSBG dsbg = input_dsbg; + + Util::DEBUG_LOG << "initial mfvs dsbg:\n" << dsbg << "\n"; + + PWMap rmap = SCC{}.calculate(dsbg).rmap(); + Set fvs_result; + Set visitedSV; + while (rmap.fixedPoints() != rmap.domain()) { + // Get minimum vertex with maximum degree + MD_NAT max_degree_vertex = maxDegreeVertex(dsbg); + Set Vj{max_degree_vertex}; + fvs_result = std::move(fvs_result).disjointCup(Vj); + + // Handle repetition + PWMap Vmap = dsbg.Vmap(); + Set repeatedSV = visitedSV.intersection(Vmap.image(Vj)); + if (!repeatedSV.isEmpty()) { + Set V_plus = Vmap.preImage(Vmap.image(Vj)); + fvs_result = std::move(fvs_result).cup(std::move(V_plus)); + + visitedSV = repeatedSV.difference(Vmap.image(Vj)); + } else { + visitedSV = std::move(repeatedSV).disjointCup(Vmap.image(Vj)); + } + + // Erase selected vertices + dsbg.eraseVertices(fvs_result); + + // Resulting SCC from induced graph + rmap = SCC{}.calculate(dsbg).rmap(); + + Util::DEBUG_LOG << "Vj: " << Vj << "\n"; + Util::DEBUG_LOG << "new rmap: " << rmap << "\n\n"; + } + + fvs_result.compact(); + return fvs_result; +} + +} // namespace detail + +} // namespace LIB + +} // namespace SBG diff --git a/algorithms/cutvertex/maxdeg_cv.hpp b/algorithms/mfvs/greedy_mfvs.hpp similarity index 60% rename from algorithms/cutvertex/maxdeg_cv.hpp rename to algorithms/mfvs/greedy_mfvs.hpp index 8081f725..5a142935 100644 --- a/algorithms/cutvertex/maxdeg_cv.hpp +++ b/algorithms/mfvs/greedy_mfvs.hpp @@ -1,6 +1,6 @@ -/** @file maxdeg_cv.hpp +/** @file greedy_mfvs.hpp - @brief SBG Maximum Degree Vertex Cut Set Algorithm implementation + @brief Concrete SBG Greedy MFVS Algorithm implementation
@@ -21,35 +21,37 @@ ******************************************************************************/ -#ifndef SBG_MAXDEG_CUTVERTEX_HPP -#define SBG_MAXDEG_CUTVERTEX_HPP +#ifndef SBGRAPH_ALGORITHMS_MFVS_GREEDY_MFVS_HPP_ +#define SBGRAPH_ALGORITHMS_MFVS_GREEDY_MFVS_HPP_ -#include "algorithms/cutvertex/cut_vertex.hpp" -#include "algorithms/scc/scc_fact.hpp" +#include "sbg/directed_sbg.hpp" +#include "sbg/set.hpp" namespace SBG { namespace LIB { +namespace detail { + /////////////////////////////////////////////////////////////////////////////// -// Maximum Degree Vertex Cut Set Algorithm Implementation (concrete strategy) - +// Degree Greedy MFVS Algorithm Implementation -------------------------------- /////////////////////////////////////////////////////////////////////////////// /** - * @brief In each step takes out the vertex of maximum degree. + * @brief In each step takes out the vertex of maximum degree. When a + * set-vertex is visited again, it takes out all those vertices. */ -class MaxDegCutVertex : public CVStrategy { - public: - MaxDegCutVertex(); - - Set calculate(const DSBG& dsbg) const override; +class GreedyMFVS { +public: + GreedyMFVS(); - private: - PWMap getDegMap(const DSBG& dsbg) const; + Set calculate(const DirectedSBG& input_dsbg) const; }; +} // namespace detail + } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_MFVS_GREEDY_MFVS_HPP_ diff --git a/algorithms/matching/matching_fact.cpp b/algorithms/mfvs/mfvs_impl.cpp similarity index 56% rename from algorithms/matching/matching_fact.cpp rename to algorithms/mfvs/mfvs_impl.cpp index 8f8f7508..69f4665a 100755 --- a/algorithms/matching/matching_fact.cpp +++ b/algorithms/mfvs/mfvs_impl.cpp @@ -17,43 +17,50 @@ ******************************************************************************/ -#include "algorithms/matching/bfs_matching.hpp" -#include "algorithms/matching/matching_fact.hpp" +#include "algorithms/mfvs/mfvs_impl.hpp" +#include "util/debug.hpp" namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Minimum Reachable SCC Factory ----------------------------------------------- +// MFVS implementations -------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -Matching BFSMatchingFact::createMatchAlgorithm() const +std::ostream& operator<<(std::ostream& out, const MFVSKind kind) { - return Matching(std::make_unique()); + switch (kind) { + case MFVSKind::kGreedy: { + out << "maximum degree greedy"; + break; + } + + case MFVSKind::kSmallSV: { + out << "smallest set-vertex"; + break; + } + + default: { + Util::ERROR("MFVSKind::operator<<: unsupported MFVS implementation"); + break; + } + } + + return out; } -std::string BFSMatchingFact::prettyPrint() const -{ - return "BFS paths"; -} - -//////////////////////////////////////////////////////////////////////////////// -// Factory for clients --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// +MFVSImplementation::MFVSImplementation() : _kind(MFVSKind::kSmallSV) {} -MatchFactory::MatchFactory() - : match_fact_(std::make_unique()) {} - -MatchingFact& MatchFactory::match_fact() +MFVSImplementation& MFVSImplementation::instance() { - return *match_fact_; + static MFVSImplementation _instance; + return _instance; } -void MatchFactory::set_match_fact(MatchFactPtr match_fact) -{ - match_fact_ = std::move(match_fact); -} +const MFVSKind& MFVSImplementation::kind() const { return _kind; } + +void MFVSImplementation::set_mfvs_fact(MFVSKind kind) { _kind = kind; } } // namespace LIB diff --git a/algorithms/mfvs/mfvs_impl.hpp b/algorithms/mfvs/mfvs_impl.hpp new file mode 100755 index 00000000..3b20f673 --- /dev/null +++ b/algorithms/mfvs/mfvs_impl.hpp @@ -0,0 +1,65 @@ +/** @file mfvs_impl.hpp + + @brief Minimum Feedback Vertex Set Algorithm Implementation + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_ALGORITHMS_MFVS_MFVS_IMPL_HPP_ +#define SBGRAPH_ALGORITHMS_MFVS_MFVS_IMPL_HPP_ + +#include + +namespace SBG { + +namespace LIB { + +//////////////////////////////////////////////////////////////////////////////// +// MFVS implementations -------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +enum class MFVSKind { kGreedy, kSmallSV }; + +std::ostream& operator<<(std::ostream& out, const MFVSKind kind); + +#define MFVS_IMPL MFVSImplementation::instance() + +/** + * @brief Singleton that keeps record of the chosen MFVS implementation. + */ +class MFVSImplementation { +public: + ~MFVSImplementation() = default; + + static MFVSImplementation& instance(); + + const MFVSKind& kind() const; + void set_mfvs_fact(MFVSKind kind); + +private: + MFVSImplementation(); + + MFVSKind _kind; +}; + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_ALGORITHMS_MFVS_MFVS_IMPL_HPP_ diff --git a/algorithms/cutvertex/cv_fact.cpp b/algorithms/mfvs/min_feedback_vertex_set.cpp old mode 100755 new mode 100644 similarity index 57% rename from algorithms/cutvertex/cv_fact.cpp rename to algorithms/mfvs/min_feedback_vertex_set.cpp index 3d59fca9..015a2541 --- a/algorithms/cutvertex/cv_fact.cpp +++ b/algorithms/mfvs/min_feedback_vertex_set.cpp @@ -17,41 +17,45 @@ ******************************************************************************/ -#include "algorithms/cutvertex/cv_fact.hpp" -#include "algorithms/cutvertex/maxdeg_cv.hpp" +#include "algorithms/mfvs/min_feedback_vertex_set.hpp" +#include "algorithms/mfvs/mfvs_impl.hpp" +#include "util/debug.hpp" +#include "util/time_profiler.hpp" namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Maximum Degree Cut Vertex Factory ------------------------------------------- +// MFVS Algorithm Interface ---------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -CutVertex MaxDegCVFact::createCVAlgorithm() const +MinFeedbackVertexSet::MinFeedbackVertexSet() : _impl() { - return CutVertex(std::make_unique()); + MFVSKind kind = MFVS_IMPL.kind(); + switch (kind) { + case MFVSKind::kGreedy: { + _impl = detail::GreedyMFVS{}; + break; + } + + case MFVSKind::kSmallSV: { + _impl = detail::SmallestSVMFVS{}; + break; + } + + default: { + Util::ERROR("MinFeedbackVertexSet: unsupported MFVS implementation"); + break; + } + } } -std::string MaxDegCVFact::prettyPrint() const +Set MinFeedbackVertexSet::calculate(const DirectedSBG& dsbg) { - return "maximum degree vertex"; -} - -//////////////////////////////////////////////////////////////////////////////// -// Factory for clients --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -CVFactory::CVFactory() : cv_fact_(std::make_unique()) {} + Util::Internal::TimeProfiler profiler{"Total MFVS exec time: "}; -CVFact& CVFactory::cv_fact() -{ - return *cv_fact_; -} - -void CVFactory::set_cv_fact(CVFactPtr cv_fact) -{ - cv_fact_ = std::move(cv_fact); + return std::visit([&](auto& a) { return a.calculate(dsbg); }, _impl); } } // namespace LIB diff --git a/algorithms/cutvertex/cut_vertex.hpp b/algorithms/mfvs/min_feedback_vertex_set.hpp similarity index 59% rename from algorithms/cutvertex/cut_vertex.hpp rename to algorithms/mfvs/min_feedback_vertex_set.hpp index ac5a7923..0b197efe 100644 --- a/algorithms/cutvertex/cut_vertex.hpp +++ b/algorithms/mfvs/min_feedback_vertex_set.hpp @@ -21,54 +21,46 @@ ******************************************************************************/ -#ifndef SBG_CUTVERTEX_HPP -#define SBG_CUTVERTEX_HPP +#ifndef SBGRAPH_ALGORITHMS_MFVS_MIN_FEEDBACK_VERTEX_SET_HPP_ +#define SBGRAPH_ALGORITHMS_MFVS_MIN_FEEDBACK_VERTEX_SET_HPP_ -#include "algorithms/scc/scc_fact.hpp" +#include "algorithms/mfvs/greedy_mfvs.hpp" +#include "algorithms/mfvs/smallest_sv_mfvs.hpp" +#include "sbg/directed_sbg.hpp" + +#include +#include namespace SBG { namespace LIB { +namespace detail { + /////////////////////////////////////////////////////////////////////////////// -// Vertex Cut Set Algorithm Abstract Strategy --------------------------------- +// Minimum Feedback Vertex Set Implementations -------------------------------- /////////////////////////////////////////////////////////////////////////////// -class CVStrategy; - -typedef std::unique_ptr CVStratPtr; +using MFVSImpl = std::variant; -/** -* @brief Aims to calculate a minimum cut set of vertices, that is, a set of -* vertices such that if these vertices are taken out, the resulting graph has no -* SCC left. Since this is a NP-hard problem, heuristics are used, and thus is -* not guaranteed that the set is actually minimum. -*/ -class CVStrategy { - public: - virtual ~CVStrategy() = default; - - CVStrategy(); - - virtual Set calculate(const DSBG& dsbg) const = 0; -}; +} /////////////////////////////////////////////////////////////////////////////// -// Vertex Cut Set Algorithm Interface (context) ------------------------------- +// Minimum Feedback Vertex Set Algorithm -------------------------------------- /////////////////////////////////////////////////////////////////////////////// -class CutVertex { - public: - CutVertex(CVStratPtr strat); +class MinFeedbackVertexSet { +public: + MinFeedbackVertexSet(); - Set calculate(const DSBG& dsbg) const; + Set calculate(const DirectedSBG& dsbg); - private: - CVStratPtr strategy_; +private: + detail::MFVSImpl _impl; }; } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_MFVS_MIN_FEEDBACK_VERTEX_SET_HPP_ diff --git a/algorithms/mfvs/smallest_sv_mfvs.cpp b/algorithms/mfvs/smallest_sv_mfvs.cpp new file mode 100644 index 00000000..44a1ffa5 --- /dev/null +++ b/algorithms/mfvs/smallest_sv_mfvs.cpp @@ -0,0 +1,113 @@ +/******************************************************************************* + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "algorithms/mfvs/smallest_sv_mfvs.hpp" +#include "algorithms/scc/scc.hpp" +#include "sbg/natural.hpp" +#include "sbg/pw_map.hpp" +#include "util/logger.hpp" + +#include + +namespace SBG { + +namespace LIB { + +namespace detail { + +//////////////////////////////////////////////////////////////////////////////// +// Greedy MFVS Algorithm ------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +SmallestSVMFVS::SmallestSVMFVS() {} + +/** + * @brief It calculates the minimum vertex from the smallest SV. + */ +MD_NAT getVertexFromSmallestSV(const DirectedSBG& dsbg) +{ + PWMap Vmap = dsbg.Vmap(); + PWMap mmap = Vmap.imageMultiplicity(); + + MD_NAT min_mult{dsbg.V().arity(), Inf}; + Set remaining = mmap.image(); + while (!remaining.isEmpty()) { + MD_NAT jth_mult = remaining.minElem(); + NAT current_degree = std::accumulate(min_mult.begin(), min_mult.end() + , 0); + NAT jth_degree = std::accumulate(jth_mult.begin(), jth_mult.end(), 0); + if (jth_degree < current_degree) { + min_mult = jth_mult; + } + + remaining = remaining.difference(Set{jth_mult}); + } + + Set small_sv = mmap.preImage(Set{min_mult}); + Set vertex = Vmap.preImage(small_sv); + + return vertex.minElem(); +} + +Set SmallestSVMFVS::calculate(const DirectedSBG& input_dsbg) const +{ + DirectedSBG dsbg = input_dsbg; + + Util::DEBUG_LOG << "initial smallest set-vertex mfvs dsbg:\n" << dsbg << "\n"; + + PWMap rmap = SCC{}.calculate(dsbg).rmap(); + Set fvs_result; + Set visitedSV; + while (rmap.fixedPoints() != rmap.domain()) { + // Get vertex from smallest set-vertex + MD_NAT smallest_sv_vertex = getVertexFromSmallestSV(dsbg); + Set Vj{smallest_sv_vertex}; + fvs_result = std::move(fvs_result).disjointCup(Vj); + + // Handle repetition + PWMap Vmap = dsbg.Vmap(); + Set repeatedSV = visitedSV.intersection(Vmap.image(Vj)); + if (!repeatedSV.isEmpty()) { + Set V_plus = Vmap.preImage(Vmap.image(Vj)); + fvs_result = std::move(fvs_result).cup(std::move(V_plus)); + + visitedSV = repeatedSV.difference(Vmap.image(Vj)); + } else { + visitedSV = std::move(repeatedSV).disjointCup(Vmap.image(Vj)); + } + + // Erase selected vertices + dsbg.eraseVertices(fvs_result); + + // Resulting SCC from induced graph + rmap = SCC{}.calculate(dsbg).rmap(); + + Util::DEBUG_LOG << "Vj: " << Vj << "\n"; + Util::DEBUG_LOG << "new rmap: " << rmap << "\n\n"; + } + + fvs_result.compact(); + return fvs_result; +} + +} // namespace detail + +} // namespace LIB + +} // namespace SBG diff --git a/algorithms/mfvs/smallest_sv_mfvs.hpp b/algorithms/mfvs/smallest_sv_mfvs.hpp new file mode 100644 index 00000000..aac249ba --- /dev/null +++ b/algorithms/mfvs/smallest_sv_mfvs.hpp @@ -0,0 +1,58 @@ +/** @file smallest_sv_mfvs.hpp + + @brief Concrete SBG Smallest SV MFVS Algorithm implementation + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_ALGORITHMS_MFVS_SMALLEST_SV_MFVS_HPP_ +#define SBGRAPH_ALGORITHMS_MFVS_SMALLEST_SV_MFVS_HPP_ + +#include "sbg/directed_sbg.hpp" +#include "sbg/set.hpp" + +namespace SBG { + +namespace LIB { + +namespace detail { + +/////////////////////////////////////////////////////////////////////////////// +// Smallest set-vertex MFVS Algorithm Implementation -------------------------- +/////////////////////////////////////////////////////////////////////////////// + +/** + * @brief In each step takes out vertices of the smallest set-vertex available. + * This way, it is first checked if it is possible to disconnect the SBG + * with a constant number of elements. + */ +class SmallestSVMFVS { +public: + SmallestSVMFVS(); + + Set calculate(const DirectedSBG& input_dsbg) const; +}; + +} // namespace detail + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_ALGORITHMS_MFVS_GREEDY_MFVS_HPP_ diff --git a/algorithms/misc/causalization_builders.cpp b/algorithms/misc/causalization_builders.cpp index e529d055..6447d57b 100644 --- a/algorithms/misc/causalization_builders.cpp +++ b/algorithms/misc/causalization_builders.cpp @@ -17,30 +17,46 @@ ******************************************************************************/ -#include - #include "algorithms/misc/causalization_builders.hpp" -#include "sbg/pwmap_fact.hpp" -#include "util/logger.hpp" +#include "sbg/bipartite_sbg.hpp" +#include "sbg/map.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/set.hpp" +#include "util/time_profiler.hpp" -namespace MISC { +#include -SBG::LIB::DSBG buildSCCFromMatching(const SBG::LIB::MatchData& data) -{ - auto start = std::chrono::high_resolution_clock::now(); +namespace misc { +//////////////////////////////////////////////////////////////////////////////// +// Algebraic loops detection graph builder ------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +std::tuple buildSCCVertices( + const SBG::LIB::MatchData& data) +{ const SBG::LIB::BipartiteSBG& bsbg = data.bsbg(); SBG::LIB::Set M = data.M(); - SBG::LIB::Set free_edges = bsbg.E().difference(M); - SBG::LIB::Set V = M.compact(); - SBG::LIB::PWMap auxVmap = data.bsbg().subEmap().restrict(M); - SBG::LIB::PWMap Vmap = SBG::LIB::PW_FACT.createPWMap(); - for (const SBG::LIB::Map& map : auxVmap) { - Vmap.emplaceBack(SBG::LIB::Map(map.dom().compact() - , map.exp())); + M.compact(); + SBG::LIB::Set V = M; + SBG::LIB::PWMap auxVmap = data.bsbg().Emap().restrict(M); + SBG::LIB::PWMap Vmap; + for (const SBG::LIB::Map& m : auxVmap) { + SBG::LIB::Set domain = m.domain(); + domain.compact(); + Vmap.emplace(domain, m.law()); } + return {V, Vmap}; +} + +std::tuple buildSCCEdges( + const SBG::LIB::MatchData& data, const SBG::LIB::PWMap& Vmap) +{ + const SBG::LIB::BipartiteSBG& bsbg = data.bsbg(); + SBG::LIB::Set M = data.M(); + SBG::LIB::PWMap map1 = bsbg.map1(); SBG::LIB::PWMap map2 = bsbg.map2(); @@ -54,59 +70,124 @@ SBG::LIB::DSBG buildSCCFromMatching(const SBG::LIB::MatchData& data) SBG::LIB::PWMap map2_toY = map2.restrict(map2.preImage(Y)); SBG::LIB::PWMap mapU = map1_toY.concatenation(map2_toY); + SBG::LIB::Set free_edges = bsbg.E().difference(M); SBG::LIB::PWMap matchedF_inv = mapF.restrict(M).inverse(); SBG::LIB::PWMap unmatchedF = mapF.restrict(free_edges); SBG::LIB::PWMap mapB = matchedF_inv.composition(unmatchedF); - mapB = mapB.compact(); + mapB.compact(); + SBG::LIB::PWMap matchedU_inv = mapU.restrict(M).inverse(); SBG::LIB::PWMap unmatchedU = mapU.restrict(free_edges); SBG::LIB::PWMap mapD = matchedU_inv.composition(unmatchedU); - mapD = mapD.compact(); + mapD.compact(); SBG::LIB::PWMap Emap = bsbg.Emap().restrict(free_edges); - SBG::LIB::PWMap subEmap = bsbg.subEmap().restrict(free_edges); + Emap.compact(); - SBG::LIB::DSBG res(V, Vmap, mapB, mapD, Emap, subEmap); - auto end = std::chrono::high_resolution_clock::now(); - auto total = std::chrono::duration_cast( - end - start - ); - SBG::Util::SBG_LOG << "SBG SCC builder: " << total.count() << " [μs]\n\n"; + return {mapB, mapD, Emap}; +} - return res; +void partitionEmap(SBG::LIB::DirectedSBG& dsbg) +{ + SBG::LIB::Set V = dsbg.V(); + SBG::LIB::PWMap Vmap = dsbg.Vmap(); + SBG::LIB::PWMap mapB = dsbg.mapB(); + SBG::LIB::PWMap mapD = dsbg.mapD(); + SBG::LIB::PWMap Emap = dsbg.Emap(); + + std::size_t arity = V.arity(); + SBG::LIB::NAT j = 1; + SBG::LIB::PWMap partitioned_Emap; + dsbg.foreachSetEdge([&](const SBG::LIB::MD_NAT& SE) + { + SBG::LIB::Set E = Emap.preImage(SBG::LIB::Set{SE}); + SBG::LIB::Set SV_starts = Vmap.image(mapB.image(E)); + SBG::LIB::Set SV_ends = Vmap.image(mapD.image(E)); + if (SV_starts.cardinal()*SV_ends.cardinal() > 1) { + SBG::LIB::Set remaining1 = SV_starts; + while (!remaining1.isEmpty()) { + SBG::LIB::Set SV1 = SBG::LIB::Set{remaining1.minElem()}; + SBG::LIB::Set V1 = Vmap.preImage(SV1); + + SBG::LIB::Set remaining2 = SV_ends; + while (!remaining2.isEmpty()) { + SBG::LIB::Set SV2 = SBG::LIB::Set{remaining2.minElem()}; + SBG::LIB::Set V2 = Vmap.preImage(SV2); + + SBG::LIB::Set edges_V1_V2 = mapB.preImage(V1).intersection( + mapD.preImage(V2)); + partitioned_Emap.emplace(E.intersection(edges_V1_V2) + , SBG::LIB::Expression{SBG::LIB::MD_NAT{arity, j}}); + ++j; + + remaining2 = remaining2.difference(SV2); + } + remaining1 = remaining1.difference(SV1); + } + } else { + partitioned_Emap.emplace(E + , SBG::LIB::Expression{SBG::LIB::MD_NAT{arity, j}}); + ++j; + } + }); + + dsbg = SBG::LIB::DirectedSBG{V, Vmap, mapB, mapD, partitioned_Emap}; } -SBG::LIB::DSBG buildSortFromSCC(const SBG::LIB::SCCData& data) +SBG::LIB::DirectedSBG buildLoopDetectionSBG(const SBG::LIB::MatchData& data) { - auto start = std::chrono::high_resolution_clock::now(); + SBG::Util::Internal::TimeProfiler profiler{"SBG Loop Detection builder: "}; - const SBG::LIB::DSBG& dsbg = data.dsbg(); - SBG::LIB::PWMap rmap = data.rmap(); - SBG::LIB::Set Ediff = data.Ediff(); + SBG::LIB::Set V; + SBG::LIB::PWMap Vmap; + std::tie(V, Vmap) = buildSCCVertices(data); - SBG::LIB::PWMap mapB = rmap.composition(dsbg.mapB().restrict(Ediff)); - mapB = mapB.compact(); - SBG::LIB::PWMap mapD = rmap.composition(dsbg.mapD().restrict(Ediff)); - mapD = mapD.compact(); + SBG::LIB::PWMap mapB; + SBG::LIB::PWMap mapD; + SBG::LIB::PWMap Emap; + std::tie(mapB, mapD, Emap) = buildSCCEdges(data, Vmap); - SBG::LIB::PWMap aux_rmap = rmap.compact(); - SBG::LIB::PWMap reps_rmap = aux_rmap.restrict(aux_rmap.fixedPoints()); - SBG::LIB::Set V = reps_rmap.dom(); + SBG::LIB::DirectedSBG dsbg{V, Vmap, mapB, mapD, Emap}; + partitionEmap(dsbg); + + return dsbg; +} + +//////////////////////////////////////////////////////////////////////////////// +// Algebraic loops breaker graph builder --------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +SBG::LIB::DirectedSBG buildTearingSBG(const SBG::LIB::SCCData& data) +{ + SBG::Util::Internal::TimeProfiler profiler{"SBG Tearing builder: "}; + + SBG::LIB::DirectedSBG dsbg = data.dsbg(); + dsbg.eraseEdges(data.Ediff()); + + return dsbg; +} + +//////////////////////////////////////////////////////////////////////////////// +// Vertical sort graph builder ------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +SBG::LIB::DirectedSBG buildVerticalSortingSBG(const SBG::LIB::SCCData& data + , const SBG::LIB::Set& mfvs) +{ + SBG::Util::Internal::TimeProfiler profiler{"SBG Vertical Sorting builder: "}; - SBG::LIB::PWMap Vmap = dsbg.Vmap().restrict(V); + const SBG::LIB::DirectedSBG& dsbg = data.dsbg(); - SBG::LIB::PWMap Emap = dsbg.Emap().restrict(Ediff); - SBG::LIB::PWMap subEmap = dsbg.subEmap().restrict(Ediff); + SBG::LIB::Set V = dsbg.V(); + SBG::LIB::PWMap Vmap = dsbg.Vmap(); - SBG::LIB::DSBG res(V, Vmap, mapB, mapD, Emap, subEmap); - auto end = std::chrono::high_resolution_clock::now(); - auto total = std::chrono::duration_cast( - end - start - ); - SBG::Util::SBG_LOG << "SBG Topological Sort builder: " << total.count() - << " [μs]\n\n"; + SBG::LIB::Set dependencies = dsbg.mapD().preImage(mfvs); + SBG::LIB::Set E = dsbg.E().difference(dependencies); + SBG::LIB::PWMap mapB = dsbg.mapB().restrict(E); + SBG::LIB::PWMap mapD = dsbg.mapD().restrict(E); + SBG::LIB::PWMap Emap = dsbg.Emap().restrict(E); - return res; + return SBG::LIB::DirectedSBG{V, Vmap, mapB, mapD, Emap}; } -} // namespace MISC +} // namespace misc diff --git a/algorithms/misc/causalization_builders.hpp b/algorithms/misc/causalization_builders.hpp index 95f2d08f..180d39fb 100644 --- a/algorithms/misc/causalization_builders.hpp +++ b/algorithms/misc/causalization_builders.hpp @@ -25,18 +25,37 @@ ******************************************************************************/ -#ifndef MISC_CAUSALIZATION_BUILDERS_HPP -#define MISC_CAUSALIZATION_BUILDERS_HPP - -#include "algorithms/matching/matching.hpp" -#include "algorithms/scc/scc.hpp" - -namespace MISC { - -SBG::LIB::DSBG buildSCCFromMatching(const SBG::LIB::MatchData& data); - -SBG::LIB::DSBG buildSortFromSCC(const SBG::LIB::SCCData& data); - -} // namespace MISC - -#endif +#ifndef SBGRAPH_ALGORITHMS_MISC_CAUSALIZATION_BUILDERS_HPP_ +#define SBGRAPH_ALGORITHMS_MISC_CAUSALIZATION_BUILDERS_HPP_ + +#include "algorithms/matching/match_data.hpp" +#include "algorithms/scc/scc_data.hpp" +#include "sbg/directed_sbg.hpp" + +namespace misc { + +/** + * @brief Builds the directed SBG used to detect algebraic loops. To do so, + * it merges the matched edges of the input SBG of \p data, adding them + * as vertices of the new graphs. Then, it adds an edge (u, v) if in the + * input bipartite SBG there was an unmatched edge between the matched edges + * represented by u and v. The direction of (u, v) is from left to right + * according to the input bipartite SBG. + */ +SBG::LIB::DirectedSBG buildLoopDetectionSBG(const SBG::LIB::MatchData& data); + +/** + * @brief Builds the directed SBG used to identify tearing variables. To do so, + * it erases the edges of the input SBG of \p data that connect different SCC. + */ +SBG::LIB::DirectedSBG buildTearingSBG(const SBG::LIB::SCCData& data); + +/** + * @brief Builds the directed acyclic SBG used to order vertically equations. + */ +SBG::LIB::DirectedSBG buildVerticalSortingSBG(const SBG::LIB::SCCData& data + , const SBG::LIB::Set& mfvs); + +} // namespace misc + +#endif // SBGRAPH_ALGORITHMS_MISC_CAUSALIZATION_BUILDERS_HPP_ diff --git a/algorithms/misc/causalization_json.cpp b/algorithms/misc/causalization_json.cpp index 29d830ea..b2ee1535 100644 --- a/algorithms/misc/causalization_json.cpp +++ b/algorithms/misc/causalization_json.cpp @@ -17,119 +17,78 @@ ******************************************************************************/ +#include "algorithms/misc/causalization_json.hpp" + #include "rapidjson/document.h" #include "rapidjson/filewritestream.h" #include "rapidjson/prettywriter.h" -#include "algorithms/misc/causalization_json.hpp" - -namespace MISC { +namespace misc { using namespace SBG::LIB; -rapidjson::Value setJson(const Set &s - , rapidjson::Document::AllocatorType &alloc) -{ - rapidjson::Value res(rapidjson::kArrayType); - - for (const SetPiece &mdi : s) { - rapidjson::Value inter_array(rapidjson::kArrayType); - for (const Interval &i : mdi) { - rapidjson::Value inter(rapidjson::kArrayType); - - rapidjson::Value beg; - beg.SetInt(i.begin()); - inter.PushBack(beg, alloc); - rapidjson::Value st; - st.SetInt(i.step()); - inter.PushBack(st, alloc); - rapidjson::Value end; - end.SetInt(i.end()); - inter.PushBack(end, alloc); - - inter_array.PushBack(inter, alloc); - } - rapidjson::Value mdi_obj(rapidjson::kObjectType); - mdi_obj.AddMember("interval", inter_array, alloc); - res.PushBack(mdi_obj, alloc); - } - - return res; -} - -rapidjson::Value expJson(Exp exp, rapidjson::Document::AllocatorType &alloc) -{ - rapidjson::Value res(rapidjson::kArrayType); - - for (const LExp &le : exp) { - rapidjson::Value le_array(rapidjson::kArrayType); - - std::stringstream ssm; - ssm << le.slope(); - rapidjson::Value m; - m.SetString(ssm.str().c_str(), strlen(ssm.str().c_str()), alloc); - le_array.PushBack(m, alloc); +//////////////////////////////////////////////////////////////////////////////// +// Causalization result -------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// - std::stringstream ssh; - ssh << le.offset(); - rapidjson::Value h; - h.SetString(ssh.str().c_str(), strlen(ssh.str().c_str()), alloc); - le_array.PushBack(h, alloc); +CausalizationResult::CausalizationResult(SBG::LIB::Set horizontal_sorting + , SBG::LIB::PWMap algebraic_loops + , SBG::LIB::Set mfvs + , SBG::LIB::PWMap vertical_sorting) : _horizontal_sorting(horizontal_sorting) + , _algebraic_loops(algebraic_loops) + , _mfvs(mfvs) + , _vertical_sorting(vertical_sorting) {} - res.PushBack(le_array, alloc); - } - - return res; +const SBG::LIB::Set& CausalizationResult::horizontal_sorting() const +{ + return _horizontal_sorting; } -rapidjson::Value mapJson( - const PWMap &pw, rapidjson::Document::AllocatorType &alloc -) +const SBG::LIB::PWMap& CausalizationResult::algebraic_loops() const { - rapidjson::Value res(rapidjson::kArrayType); - - for (const Map &map : pw) { - rapidjson::Value ith(rapidjson::kObjectType); - - ith.AddMember("dom", setJson(map.dom(), alloc), alloc); - ith.AddMember("exp", expJson(map.exp(), alloc), alloc); + return _algebraic_loops; +} - res.PushBack(ith, alloc); - } +const SBG::LIB::Set& CausalizationResult::mfvs() const { return _mfvs; } - return res; +const SBG::LIB::PWMap& CausalizationResult::vertical_sorting() const +{ + return _vertical_sorting; } -void buildJson(const Set &matching, const PWMap &scc, const PWMap &order) +//////////////////////////////////////////////////////////////////////////////// +// Build JSON file ------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +void toJSON(const CausalizationResult& causalized) { - rapidjson::Document d; - d.SetObject(); - rapidjson::Document::AllocatorType& alloc = d.GetAllocator(); + // Initialize rapidJSON + rapidjson::Document document; + document.SetObject(); + rapidjson::Document::AllocatorType& alloc = document.GetAllocator(); + + // Save causalization results + document.AddMember("horizontal_sorting" + , causalized.horizontal_sorting().toJSON(alloc), alloc); - // Create matching information - rapidjson::Value edges = setJson(matching, alloc); - d.AddMember("matching", edges, alloc); + document.AddMember("algebraic_loops" + , causalized.algebraic_loops().toJSON(alloc), alloc); - // Create SCC information - rapidjson::Value scc_rmap = mapJson(scc, alloc); - d.AddMember("scc", scc_rmap, alloc); + document.AddMember("mfvs", causalized.mfvs().toJSON(alloc), alloc); - // Create sort information - rapidjson::Value order_rmap = mapJson(order, alloc); - d.AddMember("sort", order_rmap, alloc); + document.AddMember("vertical_sorting" + , causalized.vertical_sorting().toJSON(alloc), alloc); + // Write file with rapidJSON FILE *fp = fopen("output.json", "w"); char write_buffer[65536]; rapidjson::FileWriteStream os(fp, write_buffer, sizeof(write_buffer)); rapidjson::PrettyWriter writer(os); rapidjson::PrettyFormatOptions opt = rapidjson::kFormatSingleLineArray; writer.SetFormatOptions(opt); - d.Accept(writer); + document.Accept(writer); fclose(fp); - - return; } -} // namespace MISC - +} // namespace misc diff --git a/algorithms/misc/causalization_json.hpp b/algorithms/misc/causalization_json.hpp index b9908a7d..11ea1356 100644 --- a/algorithms/misc/causalization_json.hpp +++ b/algorithms/misc/causalization_json.hpp @@ -25,16 +25,35 @@ ******************************************************************************/ -#ifndef MISC_CAUSALIZATION_JSON_HPP -#define MISC_CAUSALIZAITON_JSON_HPP +#ifndef SBGRAPH_ALGORITHMS_MISC_CAUSALIZATION_JSON_HPP_ +#define SBGRAPH_ALGORITHMS_MISC_CAUSALIZAITON_JSON_HPP_ -#include +#include "sbg/pw_map.hpp" +#include "sbg/set.hpp" -namespace MISC { +namespace misc { -void buildJson(const SBG::LIB::Set &matching, const SBG::LIB::PWMap &scc - , const SBG::LIB::PWMap &order); +class CausalizationResult { +public: + CausalizationResult(SBG::LIB::Set horizontal_sorting + , SBG::LIB::PWMap algebraic_loops + , SBG::LIB::Set mfvs + , SBG::LIB::PWMap vertical_sorting); -} // namespace MISC + const SBG::LIB::Set& horizontal_sorting() const; + const SBG::LIB::PWMap& algebraic_loops() const; + const SBG::LIB::Set& mfvs() const; + const SBG::LIB::PWMap& vertical_sorting() const; -#endif +private: + SBG::LIB::Set _horizontal_sorting; + SBG::LIB::PWMap _algebraic_loops; + SBG::LIB::Set _mfvs; + SBG::LIB::PWMap _vertical_sorting; +}; + +void toJSON(const CausalizationResult& causalized); + +} // namespace misc + +#endif // SBGRAPH_ALGORITHMS_MISC_CAUSALIZATION_JSON_HPP_ diff --git a/algorithms/scc/CMakeLists.txt b/algorithms/scc/CMakeLists.txt index f9b20d1f..d673ae96 100644 --- a/algorithms/scc/CMakeLists.txt +++ b/algorithms/scc/CMakeLists.txt @@ -5,5 +5,6 @@ target_sources( minadj_mrv.cpp minreach_scc.cpp scc.cpp - scc_fact.cpp + scc_data.cpp + scc_impl.cpp ) diff --git a/algorithms/scc/decreasing_edges_mrv.cpp b/algorithms/scc/decreasing_edges_mrv.cpp index 015bc568..723c2c0b 100644 --- a/algorithms/scc/decreasing_edges_mrv.cpp +++ b/algorithms/scc/decreasing_edges_mrv.cpp @@ -20,6 +20,8 @@ #include "algorithms/scc/decreasing_edges_mrv.hpp" #include "util/logger.hpp" +#include + namespace SBG { namespace LIB { @@ -28,16 +30,16 @@ namespace LIB { // Minimum Adjacent MRV Implementation ----------------------------------------- //////////////////////////////////////////////////////////////////////////////// -LtEdgesMRV::LtEdgesMRV() : dsbg_(), smap_(PW_FACT.createPWMap()) - , visitedSE_(SET_FACT.createSet()) {} +LtEdgesMRV::LtEdgesMRV() : _dsbg(), _smap(), _visitedSE(), _n(0) {} Set LtEdgesMRV::decreasingRepresentative(const PWMap& rmap) const { - PWMap mapB = dsbg_.mapB(); - PWMap mapD = dsbg_.mapD(); + PWMap mapB = _dsbg.mapB(); + PWMap mapD = _dsbg.mapD(); - if (mapB.isEmpty() || mapD.isEmpty()) - return SET_FACT.createSet(); + if (mapB.isEmpty() || mapD.isEmpty()) { + return Set{}; + } PWMap rmapB = rmap.composition(mapB); PWMap rmapD = rmap.composition(mapD); @@ -46,82 +48,70 @@ Set LtEdgesMRV::decreasingRepresentative(const PWMap& rmap) const return result; } -Set LtEdgesMRV::edgesInPaths(const PWMap& smap) const +PWMap LtEdgesMRV::repetitivePaths(const PWMap& rmap + , const PWMap& decreasing_smap) { - PWMap mapB = dsbg_.mapB(); - PWMap mapD = dsbg_.mapD(); - - // Vertices that are successors of other vertices in a path - Set not_fixed = smap.dom().difference(smap.fixedPoints()); - Set succs = smap.restrict(not_fixed).image(); - // Edges whose endings are successors - Set ending_edges = mapD.preImage(succs); - // Map from a 'successor' edge to its start - PWMap auxB = mapB.restrict(ending_edges); - // Map from edge to the successor of its start - PWMap map_succs = smap.composition(auxB); - - return map_succs.equalImage(mapD); -} + PWMap result; -PWMap LtEdgesMRV::recursivePaths(const Set& ith_paths_edges, const Set& outgoing) -{ - PWMap result = PW_FACT.createPWMap(); + // Calculate edges in paths described by decreasing_smap + const PWMap& mapB = _dsbg.mapB(); + const PWMap& mapD = _dsbg.mapD(); + Set Pj = decreasing_smap.composition(mapB).equalImage(mapD); - PWMap subEmap = dsbg_.subEmap(); - Set ithSE = subEmap.image(ith_paths_edges); - visitedSE_ = visitedSE_.cup(ithSE); - Set repeatedSE = visitedSE_.intersection(ithSE); + // Check if there is a repetition + PWMap Emap = _dsbg.Emap(); + Set repeatedSE = _visitedSE.intersection(Emap.image(Pj)); if (!repeatedSE.isEmpty()) { - PWMap mapB = dsbg_.mapB(); - PWMap mapD = dsbg_.mapD(); - - Set ith_start = smap_.dom().difference(smap_.image()); - Set E = SET_FACT.createSet(); - PWMap subEmap = dsbg_.subEmap(); - Set ithE = mapB.preImage(ith_start).intersection(ith_paths_edges); - if (!ithE.isEmpty()) { - bool exit_condition = true; - do { - ithE = mapB.preImage(ith_start).intersection(ith_paths_edges); - E = E.disjointCup(ithE); - ith_start = mapD.image(ithE); - exit_condition = !repeatedSE.intersection(subEmap.image(E)).isEmpty(); - } while (!exit_condition); + Set Vi = decreasing_smap.domain().difference(decreasing_smap.image()); + Set V = Vi; + for (unsigned int j = 0; j < _n; ++j) { + Vi = _smap.image(Vi); + V = V.disjointCup(Vi); } - - Set smap_edges = edgesInPaths(smap_); - Set adj = mapB.preImage(mapB.image(smap_edges)); - - Set E_plus = subEmap.preImage(subEmap.image(E)); - E_plus = E_plus.difference(mapB.preImage(outgoing)); - E_plus = E_plus.difference(adj); - PWMap mapB_plus = dsbg_.mapB().restrict(E_plus); - PWMap mapD_plus = dsbg_.mapD().restrict(E_plus); - result = mapB_plus.minAdjMap(mapD_plus); + PWMap smap_rep = _smap.restrict(V); + Set E_repetition = smap_rep.composition(mapB).equalImage(mapD); + + Set E_plus = Emap.preImage(Emap.image(E_repetition)); + // In the presence of a cycle, if the minimum vertex belongs to the + // repetition, it will be assigned a successor. This results in a cycling + // smap, which is an error. For example, if there's a cycle + // 1 -> 2 -> ... -> 10 -> 1, this function calculates smap(1) = 2, + // when it should be smap(1) = 1. To avoid this, we erase outgoing edges + // from the MRVs of the repetition. + Set outgoing = mapB.preImage(rmap.image(V)); + E_plus = E_plus.difference(outgoing); + + PWMap mapB_plus = _dsbg.mapB().restrict(E_plus); + PWMap mapD_plus = _dsbg.mapD().restrict(E_plus); + result = mapB_plus.minAdj(mapD_plus); + + _visitedSE = _visitedSE.difference(Emap.image(E_repetition)); + _n = 0; + } else { + _visitedSE = std::move(_visitedSE).disjointCup(Emap.image(Pj)); + ++_n; } return result; } -PWMap LtEdgesMRV::calculate(const DSBG& dsbg) +PWMap LtEdgesMRV::calculate(const DirectedSBG& dsbg) { Util::DEBUG_LOG << "LtEdgesMRV dsbg:\n" << dsbg << "\n\n"; - dsbg_ = dsbg; - PWMap mapB = dsbg_.mapB(); - PWMap mapD = dsbg_.mapD(); - PWMap subEmap = dsbg_.subEmap(); - visitedSE_ = SET_FACT.createSet(); + _dsbg = dsbg; + PWMap mapB = _dsbg.mapB(); + PWMap mapD = _dsbg.mapD(); + _visitedSE; - smap_ = PW_FACT.createPWMap(dsbg.V()); - PWMap rmap = smap_; + _smap = PWMap{dsbg.V()}; + PWMap rmap = _smap; - if (!dsbg_.V().isEmpty() && !dsbg_.E().isEmpty()) { - PWMap old_rmap = PW_FACT.createPWMap(); - Set E = SET_FACT.createSet(); - Set paths_edges = SET_FACT.createSet(); + if (!_dsbg.V().isEmpty() && !_dsbg.E().isEmpty()) { + _n = 0; + PWMap old_rmap; + Set E; do { old_rmap = rmap; @@ -129,18 +119,16 @@ PWMap LtEdgesMRV::calculate(const DSBG& dsbg) E = decreasingRepresentative(rmap); PWMap decreasingB = mapB.restrict(E); PWMap decreasingD = mapD.restrict(E); - PWMap decreasing_smap = decreasingB.minAdjMap(decreasingD); - smap_ = decreasing_smap.combine(smap_); + PWMap decreasing_smap = decreasingB.minAdj(decreasingD); + _smap = decreasing_smap.combine(std::move(_smap)); - // Recursive paths - Set ith_paths_edges = edgesInPaths(decreasing_smap); - Set outgoing = rmap.image(mapD.image(ith_paths_edges)); - PWMap smap_plus = recursivePaths(ith_paths_edges, outgoing); - smap_ = smap_plus.combine(smap_); + // Repetitive paths + _smap = repetitivePaths(rmap, decreasing_smap).combine(std::move(_smap)); // Calculate representatives map - rmap = smap_.mapInf(); - rmap = rmap.minMap(old_rmap).combine(rmap); + rmap = _smap.mapInf(); + rmap = rmap.min(old_rmap).combine(std::move(rmap)); + rmap.compact(); } while (!E.isEmpty()); } diff --git a/algorithms/scc/decreasing_edges_mrv.hpp b/algorithms/scc/decreasing_edges_mrv.hpp index f3931fed..92772d8d 100644 --- a/algorithms/scc/decreasing_edges_mrv.hpp +++ b/algorithms/scc/decreasing_edges_mrv.hpp @@ -23,10 +23,13 @@ ******************************************************************************/ -#ifndef SBG_DECREASING_EDGES_MRV_HPP -#define SBG_DECREASING_EDGES_MRV_HPP +#ifndef SBGRAPH_ALGORITHMS_SCC_DECREASING_EDGES_MRV_HPP_ +#define SBGRAPH_ALGORITHMS_SCC_DECREASING_EDGES_MRV_HPP_ #include "algorithms/scc/mrv.hpp" +#include "sbg/directed_sbg.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/set.hpp" namespace SBG { @@ -40,7 +43,7 @@ namespace LIB { * @brief Decreasing Edges implementation to calculate MRV. */ class LtEdgesMRV : public MRVContext { - public: +public: LtEdgesMRV(); /** @@ -48,12 +51,12 @@ class LtEdgesMRV : public MRVContext { * vertex. Then, it finds edges with a greater representative in its start * than its end. With those edges it constructs a successor map, which is * composed with itself up to convergence. - * It also handles recursive paths (i.e. paths that have a length depending + * It also handles repetitive paths (i.e. paths that have a length depending * on the size of the intervals that define the DSBG). */ - PWMap calculate(const DSBG& dsbg); + PWMap calculate(const DirectedSBG& dsbg); - private: +private: /** * @brief Given the current state of rmap_, returns the set of edges (u, v) * such that rmap_(u) > rmap_(v), which are edges leading to a new @@ -61,20 +64,19 @@ class LtEdgesMRV : public MRVContext { */ Set decreasingRepresentative(const PWMap& rmap) const; - Set edgesInPaths(const PWMap& smap) const; - /* - * @brief Calculates the MRV for recursive paths. + * @brief Calculates the MRV for repetitive paths. */ - PWMap recursivePaths(const Set& paths_edges, const Set& outgoing); + PWMap repetitivePaths(const PWMap& rmap, const PWMap& decreasing_smap); - DSBG dsbg_; - PWMap smap_; - Set visitedSE_; + DirectedSBG _dsbg; + PWMap _smap; + Set _visitedSE; + unsigned int _n; }; } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_SCC_DECREASING_EDGES_MRV_HPP_ diff --git a/algorithms/scc/minadj_mrv.cpp b/algorithms/scc/minadj_mrv.cpp index e7f105bf..5a01773c 100644 --- a/algorithms/scc/minadj_mrv.cpp +++ b/algorithms/scc/minadj_mrv.cpp @@ -30,79 +30,91 @@ namespace LIB { MinAdjMRV::MinAdjMRV() {} -PWMap MinAdjMRV::calculate(const DSBG& dsbg) +PWMap MinAdjMRV::calculate(const DirectedSBG& dsbg) { - Set V = dsbg.V(), E = dsbg.E(); - PWMap mapB = dsbg.mapB(), mapD = dsbg.mapD(), subEmap = dsbg.subEmap(); + Set V = dsbg.V(); + Set E = dsbg.E(); + PWMap mapB = dsbg.mapB(); + PWMap mapD = dsbg.mapD(); + PWMap Emap = dsbg.Emap(); if (!V.isEmpty()) { - unsigned int copies = V.arity(); - PWMap rmap = PW_FACT.createPWMap(V), old_rmap = PW_FACT.createPWMap(); + std::size_t arity = V.arity(); + PWMap rmap{V}; + PWMap old_rmap; - if (E.isEmpty()) + if (E.isEmpty()) { return rmap; + } - Set Vc = SET_FACT.createSet(); + Set Vc; do { old_rmap = rmap; PWMap ermapD = rmap.composition(mapD); - PWMap new_rmap = mapB.minAdjMap(ermapD); - rmap = rmap.minMap(new_rmap).combine(rmap); + PWMap new_rmap = mapB.minAdj(ermapD); + rmap = rmap.min(new_rmap).combine(std::move(rmap)); Util::DEBUG_LOG << "rmap before rec: " << rmap << "\n\n"; - PWMap rec_rmap = PW_FACT.createPWMap(); + PWMap rec_rmap; Vc = V.difference(old_rmap.equalImage(rmap)); if (!Vc.isEmpty()) { // If the mrv is in the same SV, the algorithm would detect a false - // recursion, i.e. if we have a cycle 1 -> 2 -> ... -> 10 -> 1, - // where SV = [1:10], then it detects a recursion when mrv(10) - // becomes "1" (false recursion). So we take self mrvs out. - Set other_rep = rmap.dom().difference(rmap.fixedPoints()); - for (const Map &subv : dsbg.Vmap()) { - Set vs = subv.dom(); + // repetition, i.e. if we have a cycle 1 -> 2 -> ... -> 10 -> 1, + // where SV = [1:10], then it detects a repetition when mrv(10) + // becomes "1" (false repetition). So we take self mrvs out. + Set other_rep = rmap.domain().difference(rmap.fixedPoints()); + PWMap Vmap = dsbg.Vmap(); + Set set_vertices = Vmap.image(); + while (!set_vertices.isEmpty()) { + Set min_elem_set{set_vertices.minElem()}; + Set vs = Vmap.preImage(min_elem_set); if (!vs.intersection(Vc).isEmpty()) { // Vertices in the set-vertex that share its rep with other vertex // in the set-vertex Set VR = rmap.restrict(vs.intersection(other_rep)).sharedImage(); - // There is a recursive vertex that changed its rep in the last step - // (to avoid computing again an already found recursion) + // There is a repeated vertex that changed its rep in the last step + // (to avoid computing again an already found repetition). if (!VR.intersection(Vc).isEmpty()) { // Vertices that reach the shared representative Set repV = rmap.preImage(rmap.image(VR)); Set end = VR.difference(Vc); // Edges with both endings in VR (path to a minimum rep) - Set ERB = mapB.preImage(repV), ERD = mapD.preImage(repV); + Set ERB = mapB.preImage(repV); + Set ERD = mapD.preImage(repV); Set ER = ERB.intersection(ERD); if (!end.isEmpty() && !ER.isEmpty()) { // Distance map - PWMap dmap = PW_FACT.createPWMap(); + PWMap dmap; Set ith = end; NAT dist = 0; // Calculate distance for vertices in same_rep that reach reps - for (; dmap.dom().intersection(Vc.intersection(VR)).isEmpty();) { - Set dom = ith.difference(dmap.dom()); - Exp exp(MD_NAT(copies, dist)); - dmap.emplaceBack(Map(dom, exp)); + for (; dmap.domain().intersection(Vc.intersection(VR)).isEmpty();) { + Set domain = ith.difference(dmap.domain()); + Expression expr(MD_NAT{arity, dist}); + dmap.emplace(domain, expr); // Update ith to vertices that have outgoing edges entering ith ith = mapB.image(mapD.preImage(ith)); ++dist; } - PWMap dmapB = dmap.composition(mapB), dmapD = dmap.composition(mapD); + PWMap dmapB = dmap.composition(mapB); + PWMap dmapD = dmap.composition(mapD); // Get edges where the end is closer to the rep than the beginning Set not_cycle_edges = dmapD.lessImage(dmapB); ER = ER.intersection(not_cycle_edges); // Extend to subset-edge - Set ER_plus = subEmap.preImage(subEmap.image(ER)); + Set ER_plus = Emap.preImage(Emap.image(ER)); // Calculate a succesor - PWMap auxB = mapB.restrict(ER_plus), auxD = mapD.restrict(ER_plus); + PWMap auxB = mapB.restrict(ER_plus); + PWMap auxD = mapD.restrict(ER_plus); PWMap smap_plus = rmap.restrict(VR); - smap_plus = smap_plus.combine(auxB.minAdjMap(auxD)); + smap_plus = std::move(smap_plus).combine(auxB.minAdj(auxD)); - // Update rmap for recursion, and leave the rest unchanged - rec_rmap = smap_plus.combine(rec_rmap).compact(); + // Update rmap for repetition, and leave the rest unchanged + rec_rmap = std::move(smap_plus).combine(rec_rmap); + rec_rmap.compact(); Util::DEBUG_LOG << "VR: " << VR << "\n"; Util::DEBUG_LOG << "repV: " << repV << "\n"; @@ -115,10 +127,12 @@ PWMap MinAdjMRV::calculate(const DSBG& dsbg) } } } + set_vertices = set_vertices.difference(min_elem_set); } - PWMap rmap_plus = rec_rmap.combine(rmap); + PWMap rmap_plus = std::move(rec_rmap).combine(std::move(rmap)); rmap_plus = rmap_plus.mapInf(); - rmap = rmap.minMap(rmap_plus).compact(); + rmap = rmap.min(rmap_plus); + rmap.compact(); Util::DEBUG_LOG << "rmap after rec: " << rmap << "\n\n"; } @@ -127,7 +141,7 @@ PWMap MinAdjMRV::calculate(const DSBG& dsbg) return rmap; } - return PW_FACT.createPWMap(); + return PWMap{}; } } // namespace LIB diff --git a/algorithms/scc/minadj_mrv.hpp b/algorithms/scc/minadj_mrv.hpp index 0a00cd6d..e7040942 100644 --- a/algorithms/scc/minadj_mrv.hpp +++ b/algorithms/scc/minadj_mrv.hpp @@ -23,10 +23,12 @@ ******************************************************************************/ -#ifndef SBG_MINADJ_MRV_HPP -#define SBG_MINADJ_MRV_HPP +#ifndef SBGRAPH_ALGORITHMS_SCC_MINADJ_MRV_HPP_ +#define SBGRAPH_ALGORITHMS_SCC_MINADJ_MRV_HPP_ #include "algorithms/scc/mrv.hpp" +#include "sbg/directed_sbg.hpp" +#include "sbg/pw_map.hpp" namespace SBG { @@ -40,21 +42,21 @@ namespace LIB { * @brief Minimum Adjacent implementation to calculate MRV. */ class MinAdjMRV : public MRVContext { - public: +public: MinAdjMRV(); /** * @brief Concrete implementation that starts with the identity pw for every * vertex. Then, for every vertex it compares the current MRV with the MRVs * of their adjacent reachable vertices. - * It also handles recursive paths (i.e. paths that have a length depending + * It also handles repetitive paths (i.e. paths that have a length depending * on the size of the intervals that define the DSBG). */ - PWMap calculate(const DSBG& dsbg); + PWMap calculate(const DirectedSBG& dsbg); }; } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_SCC_MINADJ_MRV_HPP_ diff --git a/algorithms/scc/minreach_scc.cpp b/algorithms/scc/minreach_scc.cpp index b469d3d2..aa8aadf5 100644 --- a/algorithms/scc/minreach_scc.cpp +++ b/algorithms/scc/minreach_scc.cpp @@ -17,8 +17,6 @@ ******************************************************************************/ -#include - #include "algorithms/scc/decreasing_edges_mrv.hpp" #include "algorithms/scc/minreach_scc.hpp" #include "algorithms/scc/minadj_mrv.hpp" @@ -28,66 +26,56 @@ namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // Minimum Reachable SCC Algorithm --------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -MinReachSCC::MinReachSCC() : dsbg_(), E_(SET_FACT.createSet()) {} +MinReachSCC::MinReachSCC() : _dsbg(), _E() {} void MinReachSCC::swapEdgesDirection(const Set& E) { - PWMap mapB = dsbg_.mapB(); - PWMap mapD = dsbg_.mapD(); + PWMap mapB = _dsbg.mapB(); + PWMap mapD = _dsbg.mapD(); PWMap temp_mapB = mapB.restrict(E); mapB = mapD.restrict(E); mapD = temp_mapB.restrict(E); - PWMap Emap = dsbg_.Emap().restrict(E); - PWMap subEmap = dsbg_.subEmap().restrict(E); - - dsbg_ = DSBG(dsbg_.V().compact(), dsbg_.Vmap().compact() - , mapB.compact(), mapD.compact(), Emap.compact(), subEmap.compact()); + PWMap Emap = _dsbg.Emap().restrict(E); - return; + _dsbg = DirectedSBG{_dsbg.V(), _dsbg.Vmap(), mapB, mapD, Emap}; } -void MinReachSCC::init(const DSBG& dsbg) +void MinReachSCC::init(const DirectedSBG& dsbg) { - dsbg_ = dsbg; - E_ = dsbg.E(); - - return; + _dsbg = dsbg; + _E = dsbg.E(); } -SCCData MinReachSCC::calculate(const DSBG& dsbg) +SCCData MinReachSCC::calculate(const DirectedSBG& dsbg) { Util::DEBUG_LOG << "MinReachSCC dsbg: \n" << dsbg << "\n\n"; init(dsbg); - auto begin = std::chrono::high_resolution_clock::now(); - PWMap rmap = PW_FACT.createPWMap(); - Set Ediff = SET_FACT.createSet(); + PWMap rmap = sccStep(); + rmap.compact(); Set oldE = dsbg.E(); - Set deleted_edges = SET_FACT.createSet(); + Set Ediff = oldE.difference(_dsbg.E()); + Set deleted_edges = Ediff; do { - oldE = dsbg_.E(); + oldE = _dsbg.E(); rmap = sccStep(); - Ediff = oldE.difference(dsbg_.E()); - deleted_edges = deleted_edges.disjointCup(Ediff); - } while (Ediff != SET_FACT.createSet()); - rmap = rmap.compact(); - auto end = std::chrono::high_resolution_clock::now(); - - auto total = std::chrono::duration_cast( - end - begin - ); - Util::SBG_LOG << "Total MinReachSCC exec time: " << total.count() << " [μs]\n\n"; + rmap.compact(); + Ediff = oldE.difference(_dsbg.E()); + deleted_edges = std::move(deleted_edges).disjointCup(Ediff); + } while (Ediff != Set{}); Util::DEBUG_LOG << "MinReachSCC result: " << rmap << "\n\n"; - return SCCData(dsbg, rmap, deleted_edges); + return SCCData{dsbg, rmap, deleted_edges}; } //////////////////////////////////////////////////////////////////////////////// @@ -100,19 +88,19 @@ PWMap MinReachSCCV1::sccStep() { // Calculate MRV MinAdjMRV mrv; - PWMap new_rmap = mrv.calculate(dsbg_); + PWMap new_rmap = mrv.calculate(_dsbg); Util::DEBUG_LOG << "MinReachSCCV1 new_rmap: " << new_rmap << "\n"; // Leave edges in the same SCC - PWMap rmapB = new_rmap.composition(dsbg_.mapB()); - PWMap rmapD = new_rmap.composition(dsbg_.mapD()); + PWMap rmapB = new_rmap.composition(_dsbg.mapB()); + PWMap rmapD = new_rmap.composition(_dsbg.mapD()); Set Esame = rmapB.equalImage(rmapD); - E_ = Esame; + _E = Esame; Util::DEBUG_LOG << "MinReachSCCV1 erased edges: " - << dsbg_.E().difference(E_) << "\n\n"; + << _dsbg.E().difference(_E) << "\n\n"; // Swap directions - swapEdgesDirection(E_); + swapEdgesDirection(_E); return new_rmap; } @@ -127,23 +115,25 @@ PWMap MinReachSCCV2::sccStep() { // Calculate MRV LtEdgesMRV mrv; - PWMap new_rmap = mrv.calculate(dsbg_); + PWMap new_rmap = mrv.calculate(_dsbg); Util::DEBUG_LOG << "MinReachSCCV2 new_rmap: " << new_rmap << "\n"; // Leave edges in the same SCC - PWMap rmapB = new_rmap.composition(dsbg_.mapB()); - PWMap rmapD = new_rmap.composition(dsbg_.mapD()); + PWMap rmapB = new_rmap.composition(_dsbg.mapB()); + PWMap rmapD = new_rmap.composition(_dsbg.mapD()); Set Esame = rmapB.equalImage(rmapD); - E_ = Esame; + _E = Esame; Util::DEBUG_LOG << "MinReachSCCV2 erased edges: " - << dsbg_.E().difference(E_) << "\n\n"; + << _dsbg.E().difference(_E) << "\n\n"; // Swap directions - swapEdgesDirection(E_); + swapEdgesDirection(_E); return new_rmap; } +} // namespace detail + } // namespace LIB } // namespace SBG diff --git a/algorithms/scc/minreach_scc.hpp b/algorithms/scc/minreach_scc.hpp index 2d0cadc8..4888056f 100644 --- a/algorithms/scc/minreach_scc.hpp +++ b/algorithms/scc/minreach_scc.hpp @@ -21,15 +21,20 @@ ******************************************************************************/ -#ifndef SBG_MINREACH_SCC_HPP -#define SBG_MINREACH_SCC_HPP +#ifndef SBGRAPH_ALGORITHMS_SCC_MINREACH_SCC_HPP_ +#define SBGRAPH_ALGORITHMS_SCC_MINREACH_SCC_HPP_ -#include "algorithms/scc/scc.hpp" +#include "algorithms/scc/scc_data.hpp" +#include "sbg/directed_sbg.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/set.hpp" namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // Minimum Reachable SCC Algorithm Implementation (concrete strategy) ---------- //////////////////////////////////////////////////////////////////////////////// @@ -42,17 +47,17 @@ namespace LIB { * SCC are deleted. When this process ends each SCC is identified by its * minimum vertex. */ -class MinReachSCC : public SCCStrategy { - public: +class MinReachSCC { +public: MinReachSCC(); - SCCData calculate(const DSBG& dsbg) override; + SCCData calculate(const DirectedSBG& dsbg); - protected: +protected: /** * @brief Initializes data members determined by the input SBG. */ - void init(const DSBG& dsbg); + void init(const DirectedSBG& dsbg); /** * @brief Performs a step of the algorithm in a certain direction, detecting @@ -61,7 +66,7 @@ class MinReachSCC : public SCCStrategy { virtual PWMap sccStep() = 0; /** - * @brief Modifies the `dsbg_` member, restricting the domain of edges maps + * @brief Modifies the `_dsbg` member, restricting the domain of edges maps * to `E`, and swaps mapB and mapD for elements also in `E`. */ void swapEdgesDirection(const Set& E); @@ -69,10 +74,10 @@ class MinReachSCC : public SCCStrategy { /** * @brief Calculates the MRV for every vertex in DSBG. */ - PWMap sccMinReach(const DSBG& dsbg) const; + PWMap sccMinReach(const DirectedSBG& dsbg) const; - DSBG dsbg_; ///< Input DSBG - Set E_; ///< Edges with both endings in the same SCC + DirectedSBG _dsbg; ///< Input DSBG + Set _E; ///< Edges with both endings in the same SCC }; //////////////////////////////////////////////////////////////////////////////// @@ -80,11 +85,11 @@ class MinReachSCC : public SCCStrategy { //////////////////////////////////////////////////////////////////////////////// class MinReachSCCV1 : public MinReachSCC { - public: +public: MinReachSCCV1(); - protected: - PWMap sccStep() override; +protected: + PWMap sccStep(); }; //////////////////////////////////////////////////////////////////////////////// @@ -92,15 +97,17 @@ class MinReachSCCV1 : public MinReachSCC { //////////////////////////////////////////////////////////////////////////////// class MinReachSCCV2 : public MinReachSCC { - public: +public: MinReachSCCV2(); - protected: - PWMap sccStep() override; +protected: + PWMap sccStep(); }; +} // namespace detail + } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_SCC_MINREACH_SCC_HPP_ diff --git a/algorithms/scc/mrv.hpp b/algorithms/scc/mrv.hpp index 44bb1cf7..124a3084 100644 --- a/algorithms/scc/mrv.hpp +++ b/algorithms/scc/mrv.hpp @@ -23,10 +23,11 @@ ******************************************************************************/ -#ifndef SBG_MRV_HPP -#define SBG_MRV_HPP +#ifndef SBGRAPH_ALGORITHMS_SCC_MRV_HPP_ +#define SBGRAPH_ALGORITHMS_SCC_MRV_HPP_ #include "sbg/directed_sbg.hpp" +#include "sbg/pw_map.hpp" namespace SBG { @@ -44,17 +45,17 @@ namespace LIB { */ template class MRVContext { - public: +public: /** * @brief For every vertex of `dsbg` calculates its minimum reachable vertex. * @return The resulting pw is such that if pw(x) = y then MRV(x) = y. */ - inline PWMap calculate(const DSBG& dsbg) + inline PWMap calculate(const DirectedSBG& dsbg) { return static_cast(this)->calculate(dsbg); } - protected: +protected: MRVContext() = default; }; @@ -62,4 +63,4 @@ class MRVContext { } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_SCC_MRV_HPP_ diff --git a/algorithms/scc/scc.cpp b/algorithms/scc/scc.cpp index 362034ac..080fe30b 100644 --- a/algorithms/scc/scc.cpp +++ b/algorithms/scc/scc.cpp @@ -17,42 +17,47 @@ ******************************************************************************/ -#include - #include "algorithms/scc/mrv.hpp" #include "algorithms/scc/scc.hpp" +#include "algorithms/scc/scc_impl.hpp" +#include "util/debug.hpp" #include "util/logger.hpp" +#include "util/time_profiler.hpp" namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Auxiliary structures -------------------------------------------------------- +// SCC Algorithm --------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -SCCData::SCCData(DSBG dsbg, PWMap rmap, Set Ediff) - : dsbg_(dsbg), rmap_(rmap), Ediff_(Ediff) {} - -const DSBG& SCCData::dsbg() const { return dsbg_; } -const PWMap& SCCData::rmap() const { return rmap_; } -const Set& SCCData::Ediff() const { return Ediff_; } - -//////////////////////////////////////////////////////////////////////////////// -// SCC Algorithm Abstract Strategy Constructors -------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -SCCStrategy::SCCStrategy() {} - -//////////////////////////////////////////////////////////////////////////////// -// SCC Algorithm Interface ----------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -SCC::SCC(SCCStratPtr strat) : strategy_(std::move(strat)) {} +SCC::SCC() : _impl() +{ + SCCKind kind = SCC_IMPL.kind(); + switch (kind) { + case SCCKind::kMinReachV1: { + _impl = detail::MinReachSCCV1{}; + break; + } + + case SCCKind::kMinReachV2: { + _impl = detail::MinReachSCCV2{}; + break; + } + + default: { + Util::ERROR("Unsupported SCC implementation"); + break; + } + } +} -SCCData SCC::calculate(const DSBG& dsbg) +SCCData SCC::calculate(const DirectedSBG& dsbg) { - return strategy_->calculate(dsbg); + Util::Internal::TimeProfiler profiler{"Total SCC execution time: "}; + + return std::visit([&](auto& a) { return a.calculate(dsbg); }, _impl); } } // namespace LIB diff --git a/algorithms/scc/scc.hpp b/algorithms/scc/scc.hpp index 38b7f67f..5da187d3 100644 --- a/algorithms/scc/scc.hpp +++ b/algorithms/scc/scc.hpp @@ -21,69 +21,47 @@ ******************************************************************************/ -#ifndef SBG_SCC_HPP -#define SBG_SCC_HPP +#ifndef SBGRAPH_ALGORITHMS_SCC_SCC_HPP_ +#define SBGRAPH_ALGORITHMS_SCC_SCC_HPP_ +#include "algorithms/scc/minreach_scc.hpp" +#include "algorithms/scc/scc_data.hpp" #include "sbg/directed_sbg.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/set.hpp" + +#include namespace SBG { namespace LIB { -//////////////////////////////////////////////////////////////////////////////// -// Auxiliary classures -------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -/** - * @brief Saves input and output data from a SCC algorithm run. - */ -struct SCCData { - public: - SCCData(DSBG dsbg, PWMap rmap, Set Ediff); - - const DSBG& dsbg() const; - const PWMap& rmap() const; - const Set& Ediff() const; - - private: - DSBG dsbg_; ///< Original input directed SBG - PWMap rmap_; ///< Resulting SCCs - Set Ediff_; ///< Edges connecting vertices in different SCC -}; +namespace detail { //////////////////////////////////////////////////////////////////////////////// -// SCC Algorithm Abstract Strategy --------------------------------------------- +// SCC Algorithm implementations ----------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -class SCCStrategy; +using SCCImpl = std::variant; -typedef std::unique_ptr SCCStratPtr; - -class SCCStrategy { - public: - virtual ~SCCStrategy() = default; - - SCCStrategy(); - - virtual SCCData calculate(const DSBG& dsbg) = 0; -}; +} // namespace detail //////////////////////////////////////////////////////////////////////////////// -// SCC Algorithm Interface (context) ------------------------------------------- +// SCC Algorithm --------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// class SCC { - public: - SCC(SCCStratPtr strat); +public: + SCC(); - SCCData calculate(const DSBG& dsbg); + SCCData calculate(const DirectedSBG& dsbg); - private: - SCCStratPtr strategy_; +private: + detail::SCCImpl _impl; }; } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_SCC_SCC_HPP_ diff --git a/algorithms/scc/scc_data.cpp b/algorithms/scc/scc_data.cpp new file mode 100644 index 00000000..5c3df4ca --- /dev/null +++ b/algorithms/scc/scc_data.cpp @@ -0,0 +1,37 @@ +/******************************************************************************* + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "algorithms/scc/scc_data.hpp" + +namespace SBG { + +namespace LIB { + +SCCData::SCCData(DirectedSBG dsbg, PWMap rmap, Set Ediff) + : _dsbg(dsbg), _rmap(rmap), _Ediff(Ediff) {} + +const DirectedSBG& SCCData::dsbg() const { return _dsbg; } + +const PWMap& SCCData::rmap() const { return _rmap; } + +const Set& SCCData::Ediff() const { return _Ediff; } + +} // namespace LIB + +} // namespace SBG diff --git a/algorithms/toposort/min_vertex_ts.hpp b/algorithms/scc/scc_data.hpp similarity index 56% rename from algorithms/toposort/min_vertex_ts.hpp rename to algorithms/scc/scc_data.hpp index 15e70c54..b72a8cd8 100644 --- a/algorithms/toposort/min_vertex_ts.hpp +++ b/algorithms/scc/scc_data.hpp @@ -1,7 +1,6 @@ -/** @file min_vertex_ts.hpp +/** @file scc_data.hpp - @brief Concrete SBG Minimum Vertex Topological Sort Algorithm - implementation + @brief SCC Input and Ouput data structure
@@ -22,31 +21,40 @@ ******************************************************************************/ -#ifndef SBG_MIN_VERTEX_TS_HPP -#define SBG_MIN_VERTEX_TS_HPP +#ifndef SBGRAPH_ALGORITHMS_SCC_SCC_DATA_HPP_ +#define SBGRAPH_ALGORITHMS_SCC_SCC_DATA_HPP_ -#include "algorithms/toposort/topo_sort.hpp" +#include "sbg/directed_sbg.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/set.hpp" namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Minimum Vertex Topological Sort Algorithm Implementation (concrete strategy) +// SCC Factory implementations ------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /** - * @brief In each step takes out the minimum vertex without dependencies. + * @brief Saves input and output data from a SCC algorithm run. */ -class MinVertexTopoSort : public TSStrategy { - public: - MinVertexTopoSort(); - - PWMap calculate(const DSBG& dsbg) const override; +class SCCData { +public: + SCCData(DirectedSBG dsbg, PWMap rmap, Set Ediff); + + const DirectedSBG& dsbg() const; + const PWMap& rmap() const; + const Set& Ediff() const; + +private: + DirectedSBG _dsbg; ///< Original input directed SBG + PWMap _rmap; ///< Resulting SCCs + Set _Ediff; ///< Edges connecting vertices in different SCC }; } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_SCC_SCC_DATA_HPP_ diff --git a/algorithms/scc/scc_fact.cpp b/algorithms/scc/scc_fact.cpp deleted file mode 100755 index 78b3739f..00000000 --- a/algorithms/scc/scc_fact.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/******************************************************************************* - - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -#include "algorithms/scc/minreach_scc.hpp" -#include "algorithms/scc/scc_fact.hpp" - -namespace SBG { - -namespace LIB { - -//////////////////////////////////////////////////////////////////////////////// -// Minimum Reachable SCC V1 Factory -------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -SCC MinReachSCCV1Fact::createSCCAlgorithm() const -{ - return SCC(std::make_unique()); -} - -std::string MinReachSCCV1Fact::prettyPrint() const -{ - return "MRV V1"; -} - -//////////////////////////////////////////////////////////////////////////////// -// Minimum Reachable SCC V2 Factory -------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -SCC MinReachSCCV2Fact::createSCCAlgorithm() const -{ - return SCC(std::make_unique()); -} - -std::string MinReachSCCV2Fact::prettyPrint() const -{ - return "MRV V2"; -} - -//////////////////////////////////////////////////////////////////////////////// -// Factory for clients --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -SCCFactory::SCCFactory() : scc_fact_(std::make_unique()) {} - -SCCFact& SCCFactory::scc_fact() -{ - return *scc_fact_; -} - -void SCCFactory::set_scc_fact(SCCFactPtr scc_fact) -{ - scc_fact_ = std::move(scc_fact); -} - -} // namespace LIB - -} // namespace SBG diff --git a/algorithms/scc/scc_fact.hpp b/algorithms/scc/scc_fact.hpp deleted file mode 100755 index cd464115..00000000 --- a/algorithms/scc/scc_fact.hpp +++ /dev/null @@ -1,88 +0,0 @@ -/** @file scc_fact.hpp - - @brief SCC Algorithm Factory - -
- - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -#ifndef SBG_SCC_FACT_HPP -#define SBG_SCC_FACT_HPP - -#include "scc.hpp" - -namespace SBG { - -namespace LIB { - -#define SCC_FACT SCCFactory::instance().scc_fact() - -class SCCFact { - public: - virtual ~SCCFact() = default; - SCCFact() = default; - - virtual SCC createSCCAlgorithm() const = 0; - virtual std::string prettyPrint() const = 0; -}; - -class MinReachSCCV1Fact : public SCCFact { - public: - MinReachSCCV1Fact() = default; - - SCC createSCCAlgorithm() const override; - std::string prettyPrint() const override; -}; - -class MinReachSCCV2Fact : public SCCFact { - public: - MinReachSCCV2Fact() = default; - - SCC createSCCAlgorithm() const override; - std::string prettyPrint() const override; -}; - -using SCCFactPtr = std::unique_ptr; - -/** - * @brief Single instance of scc factory to be used by clients in need of - * creating an instance of a scc algorithm. A client includes this file and - * calls SCC_FACT.createSCCAlgorithm(args). - */ -class SCCFactory { - public: - ~SCCFactory() = default; - - static SCCFactory& instance() { - static SCCFactory instance_; - return instance_; - } - SCCFact& scc_fact(); - void set_scc_fact(SCCFactPtr scc_fact); - - private: - SCCFactory(); - - SCCFactPtr scc_fact_; -}; - -} // namespace LIB - -} // namespace SBG - -#endif diff --git a/algorithms/toposort/ts_fact.cpp b/algorithms/scc/scc_impl.cpp similarity index 57% rename from algorithms/toposort/ts_fact.cpp rename to algorithms/scc/scc_impl.cpp index cba4d31e..2a6963fe 100755 --- a/algorithms/toposort/ts_fact.cpp +++ b/algorithms/scc/scc_impl.cpp @@ -17,42 +17,50 @@ ******************************************************************************/ -#include "algorithms/toposort/ts_fact.hpp" -#include "algorithms/toposort/min_vertex_ts.hpp" +#include "algorithms/scc/scc_impl.hpp" +#include "util/debug.hpp" namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Minimum Vertex Topological Sort Factory ------------------------------------- +// SCC implementations --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -TopoSort MinVertexTSFact::createTSAlgorithm() const +std::ostream& operator<<(std::ostream& out, const SCCKind kind) { - return TopoSort(std::make_unique()); + switch (kind) { + case SCCKind::kMinReachV1: { + out << "minimum reachable V1"; + break; + } + + case SCCKind::kMinReachV2: { + out << "minimum reachable V2"; + break; + } + + default: { + Util::ERROR("Unsupported SCC implementation"); + break; + } + } + + return out; } -std::string MinVertexTSFact::prettyPrint() const -{ - return "minimum vertex"; -} - -//////////////////////////////////////////////////////////////////////////////// -// Factory for clients --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// +SCCImplementation::SCCImplementation() : _kind(SCCKind::kMinReachV2) {} -TSFactory::TSFactory() : ts_fact_(std::make_unique()) {} - -TSFact& TSFactory::ts_fact() +SCCImplementation& SCCImplementation::instance() { - return *ts_fact_; + static SCCImplementation _instance; + return _instance; } -void TSFactory::set_ts_fact(TSFactPtr ts_fact) -{ - ts_fact_ = std::move(ts_fact); -} +const SCCKind& SCCImplementation::kind() const { return _kind; } + +void SCCImplementation::set_scc_fact(SCCKind kind) { _kind = kind; } } // namespace LIB diff --git a/algorithms/scc/scc_impl.hpp b/algorithms/scc/scc_impl.hpp new file mode 100755 index 00000000..fb1f0ee7 --- /dev/null +++ b/algorithms/scc/scc_impl.hpp @@ -0,0 +1,65 @@ +/** @file scc_impl.hpp + + @brief SCC Algorithm Implementation + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_ALGORITHMS_SCC_SCC_IMPL_HPP_ +#define SBGRAPH_ALGORITHMS_SCC_SCC_IMPL_HPP_ + +#include + +namespace SBG { + +namespace LIB { + +//////////////////////////////////////////////////////////////////////////////// +// SCC implementations --------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +enum class SCCKind { kMinReachV1, kMinReachV2 }; + +std::ostream& operator<<(std::ostream& out, const SCCKind kind); + +#define SCC_IMPL SCCImplementation::instance() + +/** + * @brief Singleton that keeps record of the chosen SCC implementation. + */ +class SCCImplementation { +public: + ~SCCImplementation() = default; + + static SCCImplementation& instance(); + + const SCCKind& kind() const; + void set_scc_fact(SCCKind kind); + +private: + SCCImplementation(); + + SCCKind _kind; +}; + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_ALGORITHMS_SCC_SCC_IMPL_HPP_ diff --git a/algorithms/sorting/CMakeLists.txt b/algorithms/sorting/CMakeLists.txt new file mode 100644 index 00000000..197cf000 --- /dev/null +++ b/algorithms/sorting/CMakeLists.txt @@ -0,0 +1,4 @@ +# Add subdirectories +add_subdirectory(topological) + +install_lib_headers("${CMAKE_CURRENT_SOURCE_DIR}") diff --git a/algorithms/toposort/CMakeLists.txt b/algorithms/sorting/topological/CMakeLists.txt similarity index 56% rename from algorithms/toposort/CMakeLists.txt rename to algorithms/sorting/topological/CMakeLists.txt index 4cde5cc9..b55a9888 100644 --- a/algorithms/toposort/CMakeLists.txt +++ b/algorithms/sorting/topological/CMakeLists.txt @@ -2,6 +2,6 @@ target_sources( sbgraph PRIVATE min_vertex_ts.cpp - topo_sort.cpp - ts_fact.cpp + topological_sorting.cpp + ts_impl.cpp ) diff --git a/algorithms/sorting/topological/min_vertex_ts.cpp b/algorithms/sorting/topological/min_vertex_ts.cpp new file mode 100644 index 00000000..2889b68c --- /dev/null +++ b/algorithms/sorting/topological/min_vertex_ts.cpp @@ -0,0 +1,173 @@ +/******************************************************************************* + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "algorithms/sorting/topological/min_vertex_ts.hpp" +#include "sbg/natural.hpp" +#include "util/debug.hpp" +#include "util/logger.hpp" + +namespace SBG { + +namespace LIB { + +namespace detail { + +//////////////////////////////////////////////////////////////////////////////// +// Minimum Vertex Topological Sort Algorithm ----------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +MinVertexTS::MinVertexTS() + : _smap(), _dsbg(), _visitedSV(), _priority(), _same_SV(), _independent() + , _max_repetition_depth(0) {} + +/* + * @brief Given any two vertices u and v of the repetition, it checks that any + * (u, v) edge (if it exists) satisfies that u comes before v in the sorting. + */ +void checkSorting(const PWMap& result, const DirectedSBG& dsbg) +{ + PWMap mapB = dsbg.mapB(); + PWMap mapD = dsbg.mapD(); + Set result_vertices = result.domain().cup(result.image()); + Set ED = mapD.preImage(result_vertices); + Set EB = mapB.preImage(result_vertices); + Set E = EB.intersection(ED); + PWMap jth_result = result; + Set E_old = E; + while (!E.isEmpty()) { + Set Ej = jth_result.composition(mapD).equalImage(mapB); + E = E.difference(Ej); + Util::ERROR_UNLESS(E_old != E, "checkSorting: the sorting ", result + , " is incorrect\n"); + + jth_result = result.composition(jth_result); + } +} + +PWMap MinVertexTS::repetition(const Set& init_V + , const DirectedSBG& dsbg) const +{ + PWMap result; + + PWMap Vmap = dsbg.Vmap(); + Set Vj = init_V; + Set init_SV = Vmap.image(init_V); + Expression final_expr; + bool repetition = true; + unsigned int n = 0; + do { + PWMap jth_smap = _smap.restrict(Vj); + Set V_plus = Vmap.preImage(Vmap.image(Vj)).difference(_smap.domain()); + final_expr = (*jth_smap.begin()).law(); + result.emplace(V_plus, final_expr); + Vj = _smap.image(Vj); + repetition = !Vmap.image(Vj).intersection(init_SV).isEmpty(); + ++n; + } while (!repetition && n < _max_repetition_depth); + + if (repetition) { + Expression init_expr = (*_smap.restrict(init_V).begin()).law(); + if (init_expr == final_expr) { + checkSorting(result, dsbg); + } + } else { + result = PWMap{}; + } + + return result; +} + +MD_NAT MinVertexTS::getMinVertex() +{ + Set V = _dsbg.V(); + PWMap mapD = _dsbg.mapD(); + _independent = V.difference(mapD.image()); + + Set Vj = _independent; + if (Vj.isEmpty()) { + Util::ERROR("MinVertexTS::getMinVertex: the SBG is not acyclic\n"); + } + Set independent_priority = Vj.intersection(_priority); + if (!independent_priority.isEmpty()) { + Vj = independent_priority; + } + Set Vj_same_SV = Vj.intersection(_same_SV); + if (!Vj_same_SV.isEmpty()) { + Vj = Vj_same_SV; + } + + return Vj.minElem(); +} + +PWMap MinVertexTS::calculate(const DirectedSBG& dsbg + , const PWMap& pmap) +{ + Util::DEBUG_LOG << "Topological sort dsbg:\n" << dsbg << "\n\n"; + + _dsbg = dsbg; + + _smap = PWMap{}; + + if (dsbg.V().isEmpty()) { + return _smap; + } + + _priority = _dsbg.V(); + _same_SV = _dsbg.V(); + Set visited_SV; + Expression successor_expr{_dsbg.V().arity(), 1, 0}; + MD_NAT vj; + MD_NAT old_vj = _dsbg.V().difference(_dsbg.mapD().image()).minElem(); + do { + // Find new minimum vertex, and add it to the sorting + vj = getMinVertex(); + Set vj_set{vj}; + successor_expr = Expression{vj, old_vj}; + _smap.emplace(vj_set, successor_expr); + + // Handle repetition + PWMap Vmap = _dsbg.Vmap(); + Set repeatedSV = _visitedSV.intersection(Vmap.image(vj_set)); + if (!repeatedSV.isEmpty()) { + PWMap smap_plus = repetition(vj_set, dsbg); + _smap = std::move(smap_plus).combine(std::move(_smap)); + vj = _smap.domain().difference(_smap.image()).minElem(); + _max_repetition_depth = 0; + } else { + _visitedSV = std::move(_visitedSV).disjointCup(Vmap.image(vj_set)); + _max_repetition_depth++; + } + + // Update values for new iteration + _dsbg.eraseVertices(_smap.domain()); + old_vj = vj; + _priority = pmap.preImage(pmap.image(vj_set)); + _same_SV = Vmap.preImage(Vmap.image(vj_set)); + } while (!_dsbg.V().isEmpty()); + + _smap.compact(); + Util::DEBUG_LOG << "Topological sort result:\n" << _smap << "\n\n"; + return _smap; +} + +} // namespace detail + +} // namespace LIB + +} // namespace SBG diff --git a/algorithms/sorting/topological/min_vertex_ts.hpp b/algorithms/sorting/topological/min_vertex_ts.hpp new file mode 100644 index 00000000..44b807a2 --- /dev/null +++ b/algorithms/sorting/topological/min_vertex_ts.hpp @@ -0,0 +1,74 @@ +/** @file min_vertex_ts.hpp + + @brief Concrete SBG Minimum Vertex Topological Sorting Algorithm + implementation + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_ALGORITHMS_SORTING_TOPOLOGICAL_MIN_VERTEX_TS_HPP_ +#define SBGRAPH_ALGORITHMS_SORTING_TOPOLOGICAL_MIN_VERTEX_TS_HPP_ + +#include "sbg/directed_sbg.hpp" +#include "sbg/expression.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/set.hpp" + +namespace SBG { + +namespace LIB { + +namespace detail { + +//////////////////////////////////////////////////////////////////////////////// +// Minimum Vertex Topological Sorting Algorithm Implementation ----------------- +//////////////////////////////////////////////////////////////////////////////// + +class MinVertexTS { +public: + MinVertexTS(); + + /** + * @brief Concrete implementation that in each step takes out the minimum + * vertex without dependencies. It also implements different strategies to + * sort a large number of vertices. + */ + PWMap calculate(const DirectedSBG& dsbg, const PWMap& pmap); + +private: + MD_NAT getMinVertex(); + + PWMap repetition(const Set& init_V, const DirectedSBG& dsbg) const; + + PWMap _smap; + DirectedSBG _dsbg; + Set _priority; + Set _same_SV; + Set _independent; + Set _visitedSV; + unsigned int _max_repetition_depth; +}; + +} // namespace detail + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_ALGORITHMS_SORTING_TOPOLOGICAL_MIN_VERTEX_TS_HPP_ diff --git a/algorithms/sorting/topological/topological_sorting.cpp b/algorithms/sorting/topological/topological_sorting.cpp new file mode 100644 index 00000000..e3f0659d --- /dev/null +++ b/algorithms/sorting/topological/topological_sorting.cpp @@ -0,0 +1,59 @@ +/******************************************************************************* + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "algorithms/sorting/topological/topological_sorting.hpp" +#include "algorithms/sorting/topological/ts_impl.hpp" +#include "util/debug.hpp" +#include "util/time_profiler.hpp" + +namespace SBG { + +namespace LIB { + +//////////////////////////////////////////////////////////////////////////////// +// Topological Sorting Algorithm Interface ------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +TopologicalSorting::TopologicalSorting() : _impl() +{ + TSKind kind = TS_IMPL.kind(); + switch (kind) { + case TSKind::kMinVertex: { + _impl = detail::MinVertexTS{}; + break; + } + + default: { + Util::ERROR("TopologicalSorting::operator<<: unsupported topological " + , "sorting algorithm implementation"); + } + } +} + +PWMap TopologicalSorting::calculate(const DirectedSBG& dsbg, const PWMap& pmap) +{ + auto text = "Total topological sorting execution time: "; + Util::Internal::TimeProfiler profiler{text}; + + return std::visit([&](auto& a) { return a.calculate(dsbg, pmap); }, _impl); +} + +} // namespace LIB + +} // namespace SBG diff --git a/algorithms/toposort/topo_sort.hpp b/algorithms/sorting/topological/topological_sorting.hpp similarity index 67% rename from algorithms/toposort/topo_sort.hpp rename to algorithms/sorting/topological/topological_sorting.hpp index 9552cd48..7bcefeae 100644 --- a/algorithms/toposort/topo_sort.hpp +++ b/algorithms/sorting/topological/topological_sorting.hpp @@ -21,48 +21,42 @@ ******************************************************************************/ -#ifndef SBG_TOPOSORT_HPP -#define SBG_TOPOSORT_HPP +#ifndef SBGRAPH_ALGORITHMS_SORTING_TOPOLOGICAL_TOPOLOGICAL_SORTING_HPP_ +#define SBGRAPH_ALGORITHMS_SORTING_TOPOLOGICAL_TOPOLOGICAL_SORTING_HPP_ +#include "algorithms/sorting/topological/min_vertex_ts.hpp" #include "sbg/directed_sbg.hpp" namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// -// Topological Sort Algorithm Abstract Strategy -------------------------------- +// Topological Sorting Algorithm Implementations ------------------------------- //////////////////////////////////////////////////////////////////////////////// -class TSStrategy; - -typedef std::unique_ptr TSStratPtr; - -class TSStrategy { - public: - virtual ~TSStrategy() = default; +using TSImpl = std::variant; - TSStrategy(); - - virtual PWMap calculate(const DSBG& dsbg) const = 0; -}; +} // namespace detail //////////////////////////////////////////////////////////////////////////////// -// Topological Sort Algorithm Interface (context) ------------------------------ +// Topological Sorting Algorithm ----------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -class TopoSort { - private: - TSStratPtr strategy_; +class TopologicalSorting { +public: + TopologicalSorting(); - public: - TopoSort(TSStratPtr strat); + PWMap calculate(const DirectedSBG& dsbg, const PWMap& pmap); - PWMap calculate(const DSBG& dsbg) const; +private: + detail::TSImpl _impl; }; } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_SORTING_TOPOLOGICAL_TOPOLOGICAL_SORTING_HPP_ diff --git a/algorithms/sorting/topological/ts_impl.cpp b/algorithms/sorting/topological/ts_impl.cpp new file mode 100755 index 00000000..05ecfb17 --- /dev/null +++ b/algorithms/sorting/topological/ts_impl.cpp @@ -0,0 +1,63 @@ +/******************************************************************************* + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "algorithms/sorting/topological/ts_impl.hpp" +#include "util/debug.hpp" + +namespace SBG { + +namespace LIB { + +//////////////////////////////////////////////////////////////////////////////// +// Topological Sorting implementations +//////////////////////////////////////////////////////////////////////////////// + +std::ostream& operator<<(std::ostream& out, const TSKind kind) +{ + switch (kind) { + case TSKind::kMinVertex: { + out << "minimum vertex"; + break; + } + + default: { + Util::ERROR("TSKind::operator<<: unsupported topological sorting " + , "algorithm implementation"); + break; + } + } + + return out; +} + +TSImplementation::TSImplementation() : _kind(TSKind::kMinVertex) {} + +TSImplementation& TSImplementation::instance() +{ + static TSImplementation _instance; + return _instance; +} + +const TSKind& TSImplementation::kind() const { return _kind; } + +void TSImplementation::set_ts_fact(TSKind kind) { _kind = kind; } + +} // namespace LIB + +} // namespace SBG diff --git a/algorithms/sorting/topological/ts_impl.hpp b/algorithms/sorting/topological/ts_impl.hpp new file mode 100755 index 00000000..ef99e3ba --- /dev/null +++ b/algorithms/sorting/topological/ts_impl.hpp @@ -0,0 +1,65 @@ +/** @file ts_impl.hpp + + @brief Topological Sorting Algorithm Implementation + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_ALGORITHMS_SORTING_TOPOLOGICAL_TS_IMPL_HPP_ +#define SBGRAPH_ALGORITHMS_SORTING_TOPOLOGICAL_TS_IMPL_HPP_ + +#include + +namespace SBG { + +namespace LIB { + +//////////////////////////////////////////////////////////////////////////////// +// Topological Sorting implementations ----------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +enum class TSKind { kMinVertex }; + +std::ostream& operator<<(std::ostream& out, const TSKind kind); + +#define TS_IMPL TSImplementation::instance() + +/** + * @brief Singleton that keeps record of the chosen sorting implementation. + */ +class TSImplementation { +public: + ~TSImplementation() = default; + + static TSImplementation& instance(); + + const TSKind& kind() const; + void set_ts_fact(TSKind kind); + +private: + TSImplementation(); + + TSKind _kind; +}; + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_ALGORITHMS_SORTING_TOPOLOGICAL_TS_IMPL_HPP_ diff --git a/algorithms/toposort/min_vertex_ts.cpp b/algorithms/toposort/min_vertex_ts.cpp deleted file mode 100644 index 1a6b5706..00000000 --- a/algorithms/toposort/min_vertex_ts.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/******************************************************************************* - - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -#include - -#include "algorithms/toposort/min_vertex_ts.hpp" -#include "util/logger.hpp" - -namespace SBG { - -namespace LIB { - -//////////////////////////////////////////////////////////////////////////////// -// Minimum Vertex Topological Sort Algorithm ----------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -MinVertexTopoSort::MinVertexTopoSort() {} - -Exp calculateExp(const MD_NAT& from, const MD_NAT& to) -{ - Exp res; - - RATIONAL one(1, 1); - for (unsigned int j = 0; j < from.arity(); ++j) { - RATIONAL r_from(from[j]), r_to(to[j]); - res.emplaceBack(LExp(1, r_to - r_from)); - } - - return res; -} - -PWMap MinVertexTopoSort::calculate(const DSBG& dsbg) const -{ - Util::DEBUG_LOG << "Topological sort dsbg:\n" << dsbg << "\n\n"; - - auto begin = std::chrono::high_resolution_clock::now(); - PWMap mapB = dsbg.mapB(), mapD = dsbg.mapD(), Vmap = dsbg.Vmap(); - PWMap smap = PW_FACT.createPWMap(); - Set U = dsbg.V(), Nd = U.difference(mapB.image()); - if (!Nd.isEmpty()) { - MD_NAT vsucc = Nd.minElem(); - Set SV = SET_FACT.createSet(), E = dsbg.E(); - do { - Set vsucc_set = SET_FACT.createSet(SetPiece(vsucc)); - Set Nd_vsucc = Nd.intersection(Vmap.preImage(Vmap.image(vsucc_set))); - MD_NAT v = Nd.minElem(); - if (!Nd_vsucc.isEmpty()) - v = Nd_vsucc.minElem(); - Set d = SET_FACT.createSet(v); - Exp e = calculateExp(v, vsucc); - vsucc = v; - - Set SVd = Vmap.image(d); - bool cond = SVd.intersection(SV).isEmpty(); - if (!cond) { - Set dvs = Vmap.preImage(SVd); - for (const Map& map : smap.restrict(dvs)) { - if (e == map.exp()) { - d = dvs.difference(smap.dom()); - break; - } - } - } - smap.emplaceBack(Map(d, e)); - - Set Nsucc = U.difference(smap.dom()); - Set S = smap.dom().difference(smap.preImage(Nsucc)); - - E = E.difference(mapD.preImage(S)); - mapB = mapB.restrict(E); - mapD = mapD.restrict(E); - - U = U.difference(S); - Nd = U.difference(mapB.image()); - SV = SV.cup(Vmap.image(d)); - if (S == smap.dom()) { - Set start = smap.dom().difference(smap.image()); - if (!start.isEmpty()) - vsucc = start.minElem(); - } - - Util::DEBUG_LOG << "S: " << S << "\n"; - Util::DEBUG_LOG << "U: " << U << "\n"; - Util::DEBUG_LOG << "E: " << E << "\n"; - Util::DEBUG_LOG << "Nd: " << Nd << "\n"; - Util::DEBUG_LOG << "smap: " << smap << "\n\n"; - } while (!U.isEmpty()); - } - auto end = std::chrono::high_resolution_clock::now(); - - auto total = std::chrono::duration_cast( - end - begin - ); - Util::SBG_LOG << "Total topological sort exec time: " << total.count() << " [μs]\n\n"; - - Util::DEBUG_LOG << "Topological sort result:\n" << smap.compact() << "\n\n"; - - return smap.compact(); -} - -} // namespace LIB - -} // namespace SBG diff --git a/algorithms/toposort/ts_fact.hpp b/algorithms/toposort/ts_fact.hpp deleted file mode 100755 index b29fa838..00000000 --- a/algorithms/toposort/ts_fact.hpp +++ /dev/null @@ -1,81 +0,0 @@ -/** @file ts_fact.hpp - - @brief Topological Sort Algorithm Factory - -
- - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -#ifndef SBG_TS_FACT_HPP -#define SBG_TS_FACT_HPP - -#include "topo_sort.hpp" - -namespace SBG { - -namespace LIB { - -#define TS_FACT TSFactory::instance().ts_fact() - -class TSFact { - public: - virtual ~TSFact() = default; - TSFact() = default; - - virtual TopoSort createTSAlgorithm() const = 0; - virtual std::string prettyPrint() const = 0; -}; - -class MinVertexTSFact : public TSFact { - public: - MinVertexTSFact() = default; - - TopoSort createTSAlgorithm() const override; - std::string prettyPrint() const override; -}; - -using TSFactPtr = std::unique_ptr; - -/** - * @brief Single instance of ts factory to be used by clients in need of - * creating an instance of a ts algorithm. A client includes this file and - * calls TS_FACT.createTSAlgorithm(args). - */ -class TSFactory { - public: - ~TSFactory() = default; - - static TSFactory& instance() { - static TSFactory instance_; - return instance_; - } - TSFact& ts_fact(); - void set_ts_fact(TSFactPtr ts_fact); - - private: - TSFactory(); - - TSFactPtr ts_fact_; -}; - - -} // namespace LIB - -} // namespace SBG - -#endif diff --git a/ast/expr.cpp b/ast/expr.cpp index 82fd5b57..1302e589 100755 --- a/ast/expr.cpp +++ b/ast/expr.cpp @@ -19,6 +19,8 @@ #include "ast/expr.hpp" +#include + namespace SBG { namespace AST { @@ -235,9 +237,10 @@ std::ostream &operator<<(std::ostream &out, const PWLMap &pwl) // SBG ------------------------------------------------------------------------- -SBG::SBG() : _V(), _Vmap(), _map1(), _map2(), _Emap(), _subE_map() {} -SBG::SBG(Expr V, Expr Vmap, Expr map1, Expr map2, Expr Emap, Expr subE) : _V(V) - , _Vmap(Vmap), _map1(map1), _map2(map2), _Emap(Emap), _subE_map(subE) {} +SBG::SBG() : _V(), _Vmap(), _map1(), _map2(), _Emap() {} + +SBG::SBG(Expr V, Expr Vmap, Expr map1, Expr map2, Expr Emap) : _V(V) + , _Vmap(Vmap), _map1(map1), _map2(map2), _Emap(Emap) {} const Expr& SBG::V() const { return _V; } @@ -249,13 +252,10 @@ const Expr& SBG::map2() const { return _map2; } const Expr& SBG::Emap() const { return _Emap; } -const Expr& SBG::subE_map() const { return _subE_map; } - bool SBG::operator==(const SBG &other) const { return _V == other._V && _Vmap == other._Vmap && _map1 == other._map1 - && _map2 == other._map2 && _Emap == other._Emap - && _subE_map == other._subE_map; + && _map2 == other._map2 && _Emap == other._Emap; } std::ostream &operator<<(std::ostream &out, const SBG &g) @@ -265,7 +265,6 @@ std::ostream &operator<<(std::ostream &out, const SBG &g) out << "map1: " << g.map1() << "\n"; out << "map2: " << g.map2() << "\n"; out << "Emap: " << g.Emap() << "\n"; - out << "subE_map: " << g.subE_map(); return out; } @@ -273,9 +272,10 @@ std::ostream &operator<<(std::ostream &out, const SBG &g) // Bipartite SBG --------------------------------------------------------------- BipartiteSBG::BipartiteSBG() : _X(), _Y() {} + BipartiteSBG::BipartiteSBG(Expr V, Expr Vmap, Expr map1, Expr map2, Expr Emap - , Expr subE, Expr X, Expr Y) - : SBG(V, Vmap, map1, map2, Emap, subE), _X(X), _Y(Y) {} + , Expr X, Expr Y) + : SBG(V, Vmap, map1, map2, Emap), _X(X), _Y(Y) {} const Expr& BipartiteSBG::X() const { return _X; } @@ -285,7 +285,6 @@ bool BipartiteSBG::operator==(const BipartiteSBG &other) const { return _V == other._V && _Vmap == other._Vmap && _map1 == other._map1 && _map2 == other._map2 && _Emap == other._Emap - && _subE_map == other._subE_map && _X == other._X && _Y == other._Y; } @@ -296,7 +295,6 @@ std::ostream &operator<<(std::ostream &out, const BipartiteSBG &g) out << "map1: " << g.map1() << "\n"; out << "map2: " << g.map2() << "\n"; out << "Emap: " << g.Emap() << "\n"; - out << "subE_map: " << g.subE_map() << "\n\n"; out << "X: " << g.X() << "\n"; out << "Y: " << g.Y(); @@ -305,32 +303,30 @@ std::ostream &operator<<(std::ostream &out, const BipartiteSBG &g) // DSBG ------------------------------------------------------------------------ -DSBG::DSBG() : V_(), Vmap_(), mapB_(), mapD_(), Emap_(), subE_map_() {} -DSBG::DSBG(Expr V, Expr Vmap, Expr mapB, Expr mapD, Expr Emap, Expr subE) : V_(V) - , Vmap_(Vmap), mapB_(mapB), mapD_(mapD), Emap_(Emap), subE_map_(subE) {} +DSBG::DSBG() : V_(), Vmap_(), mapB_(), mapD_(), Emap_() {} + +DSBG::DSBG(Expr V, Expr Vmap, Expr mapB, Expr mapD, Expr Emap) + : V_(V), Vmap_(Vmap), mapB_(mapB), mapD_(mapD), Emap_(Emap) {} member_imp(DSBG, Expr, V); member_imp(DSBG, Expr, Vmap); member_imp(DSBG, Expr, mapB); member_imp(DSBG, Expr, mapD); member_imp(DSBG, Expr, Emap); -member_imp(DSBG, Expr, subE_map); bool DSBG::operator==(const DSBG &other) const { return V() == other.V() && Vmap() == other.Vmap() && mapB() == other.mapB() - && mapD() == other.mapD() && Emap() == other.Emap() - && subE_map() == other.subE_map(); + && mapD() == other.mapD() && Emap() == other.Emap(); } -std::ostream &operator<<(std::ostream &out, const DSBG &g) +std::ostream &operator<<(std::ostream &out, const DSBG &dg) { - out << "V: " << g.V() << "\n"; - out << "Vmap: " << g.Vmap() << "\n\n"; - out << "mapB: " << g.mapB() << "\n"; - out << "mapD: " << g.mapD() << "\n"; - out << "Emap: " << g.Emap() << "\n"; - out << "subE_map: " << g.subE_map() << "\n"; + out << "V: " << dg.V() << "\n"; + out << "Vmap: " << dg.Vmap() << "\n\n"; + out << "mapB: " << dg.mapB() << "\n"; + out << "mapD: " << dg.mapD() << "\n"; + out << "Emap: " << dg.Emap() << "\n"; return out; } diff --git a/ast/expr.hpp b/ast/expr.hpp index a39b7bb1..f7e59018 100755 --- a/ast/expr.hpp +++ b/ast/expr.hpp @@ -24,10 +24,13 @@ #ifndef PARSER_EXPR_AST_HPP #define PARSER_EXPR_AST_HPP +#include + #include #include #include "sbg/natural.hpp" +#include "util/defs.hpp" namespace SBG { @@ -187,14 +190,13 @@ std::ostream &operator<<(std::ostream &out, const PWLMap &pwl); class SBG { public: SBG(); - SBG(Expr V, Expr Vmap, Expr map1, Expr map2, Expr Emap, Expr subE); + SBG(Expr V, Expr Vmap, Expr map1, Expr map2, Expr Emap); const Expr& V() const; const Expr& Vmap() const; const Expr& map1() const; const Expr& map2() const; const Expr& Emap() const; - const Expr& subE_map() const; bool operator==(const SBG &sbg) const; @@ -204,7 +206,6 @@ class SBG { Expr _map1; Expr _map2; Expr _Emap; - Expr _subE_map; }; std::ostream &operator<<(std::ostream &out, const SBG &g); @@ -213,7 +214,7 @@ std::ostream &operator<<(std::ostream &out, const SBG &g); class BipartiteSBG : public SBG { public: BipartiteSBG(); - BipartiteSBG(Expr V, Expr Vmap, Expr map1, Expr map2, Expr Emap, Expr subE + BipartiteSBG(Expr V, Expr Vmap, Expr map1, Expr map2, Expr Emap , Expr X, Expr Y); const Expr& X() const; @@ -235,10 +236,9 @@ struct DSBG { member_class(Expr, mapB); member_class(Expr, mapD); member_class(Expr, Emap); - member_class(Expr, subE_map); DSBG(); - DSBG(Expr V, Expr Vmap, Expr mapB, Expr mapD, Expr Emap, Expr subE); + DSBG(Expr V, Expr Vmap, Expr mapB, Expr mapD, Expr Emap); bool operator==(const DSBG &dsbg) const; }; diff --git a/eval/base_type.hpp b/eval/base_type.hpp index c5e608f7..3e3f3b83 100755 --- a/eval/base_type.hpp +++ b/eval/base_type.hpp @@ -23,15 +23,22 @@ ******************************************************************************/ -#ifndef EVAL_BASE_TYPE_HPP -#define EVAL_BASE_TYPE_HPP +#ifndef SBGRAPH_EVAL_BASE_TYPE_HPP_ +#define SBGRAPH_EVAL_BASE_TYPE_HPP_ -#include - -#include "ast/expr.hpp" -#include "algorithms/matching/matching.hpp" -#include "sbg/directed_sbg.hpp" +#include "algorithms/matching/match_data.hpp" #include "sbg/bipartite_sbg.hpp" +#include "sbg/directed_sbg.hpp" +#include "sbg/expression.hpp" +#include "sbg/map.hpp" +#include "sbg/natural.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/rational.hpp" +#include "sbg/sbg.hpp" +#include "sbg/set.hpp" + +#include +#include namespace SBG { @@ -41,21 +48,21 @@ using ExprBaseType = std::variant; + using MaybeEBT = std::optional; + using EBTList = std::vector; } // namespace Eval } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_BASE_TYPE_HPP_ diff --git a/eval/eval_context.cpp b/eval/eval_context.cpp index 45ba61b3..b1cb07c1 100755 --- a/eval/eval_context.cpp +++ b/eval/eval_context.cpp @@ -23,6 +23,8 @@ namespace SBG { namespace Eval { +namespace detail { + EvalContext::EvalContext() : arity_(1), venv_(), fenv_() {} // Getters --------------------------------------------------------------------- @@ -59,6 +61,8 @@ void EvalContext::insertFunction(FuncEnv::FKey key, FuncEnv::FValue value) fenv_.insert(key, value); } +} // namespace detail + } // namespace Eval } // namespace SBG diff --git a/eval/eval_context.hpp b/eval/eval_context.hpp index 492896da..d87cd753 100755 --- a/eval/eval_context.hpp +++ b/eval/eval_context.hpp @@ -21,8 +21,8 @@ ******************************************************************************/ -#ifndef EVAL_CONTEXT_HPP -#define EVAL_CONTEXT_HPP +#ifndef SBGRAPH_EVAL_EVAL_CONTEXT_HPP_ +#define SBGRAPH_EVAL_EVAL_CONTEXT_HPP_ #include "eval/func_env.hpp" #include "eval/var_env.hpp" @@ -31,12 +31,14 @@ namespace SBG { namespace Eval { +namespace detail { + /** * @brief Evaluation context that keeps track of the arity of the evaluated * program, defined variables, and built-in functions. */ class EvalContext { - public: +public: EvalContext(); // Getters @@ -48,14 +50,16 @@ class EvalContext { void insertVariable(VarEnv::VKey key, VarEnv::VValue value); void insertFunction(FuncEnv::FKey key, FuncEnv::FValue value); - private: +private: unsigned int arity_; ///< Number of dimensions of the program VarEnv venv_; FuncEnv fenv_; }; +} // namespace detail + } // namespace Eval } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_EVAL_CONTEXT_HPP_ diff --git a/eval/eval_exec.cpp b/eval/eval_exec.cpp index ed8a57e9..a0a37252 100644 --- a/eval/eval_exec.cpp +++ b/eval/eval_exec.cpp @@ -17,22 +17,27 @@ ******************************************************************************/ -#include -#include -#include - -#include "algorithms/cutvertex/cv_fact.hpp" -#include "algorithms/matching/matching_fact.hpp" -#include "algorithms/scc/scc_fact.hpp" -#include "algorithms/toposort/ts_fact.hpp" +#include "algorithms/matching/matching_impl.hpp" +#include "algorithms/mfvs/mfvs_impl.hpp" +#include "algorithms/scc/scc_impl.hpp" +#include "algorithms/sorting/topological/ts_impl.hpp" #include "eval/eval_exec.hpp" #include "eval/file_evaluator.hpp" #include "eval/input_translator.hpp" #include "eval/file_evaluator.hpp" #include "eval/visitors/autom_impl_visitor.hpp" #include "parser/file_parser.hpp" +#include "sbg/pwmap_impl.hpp" +#include "sbg/set_impl.hpp" #include "util/debug.hpp" #include "util/logger.hpp" +#include "util/time_profiler.hpp" + +#include "boost/program_options.hpp" + +#include +#include +#include namespace SBG { @@ -46,14 +51,13 @@ void printHeader(Util::prog_opts::variables_map vm) { if (vm.count("debug")) { std::cout << "-----------------------------------\n"; - std::cout << "Set implementation: " << LIB::SET_FACT.prettyPrint() << "\n"; - std::cout << "PWMap implementation: " << LIB::PW_FACT.prettyPrint() << "\n"; + std::cout << "Set implementation: " << LIB::SET_IMPL.kind() << "\n"; + std::cout << "PWMap implementation: " << LIB::PWMAP_IMPL.kind() << "\n"; std::cout << "-----------------------------------\n"; - std::cout << "Matching algorithm: " << LIB::MATCH_FACT.prettyPrint() - << "\n"; - std::cout << "SCC algorithm: " << LIB::SCC_FACT.prettyPrint() << "\n"; - std::cout << "Cut vertex algorithm: " << LIB::CV_FACT.prettyPrint() << "\n"; - std::cout << "Topological sort algorithm: " << LIB::TS_FACT.prettyPrint() + std::cout << "Matching algorithm: " << LIB::MATCH_IMPL.kind() << "\n"; + std::cout << "SCC algorithm: " << LIB::SCC_IMPL.kind() << "\n"; + std::cout << "MFVS algorithm: " << LIB::MFVS_IMPL.kind() << "\n"; + std::cout << "Topological sorting algorithm: " << LIB::TS_IMPL.kind() << "\n"; } std::cout << "-----------------------------------\n"; @@ -65,64 +69,74 @@ void printHeader(Util::prog_opts::variables_map vm) // Evaluation Executor --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -EvalExecutor::EvalExecutor() : scc_impl_(1) +EvalExecutor::EvalExecutor() : _scc_impl(1), _mfvs_impl(1) { - config_.add_options() - ("set_impl,s", Util::prog_opts::value(&set_impl_), + _config.add_options() + ("set_impl,s", Util::prog_opts::value(&_set_impl), " Desired set implementation:" "\n - 0 for unordered sets (default option)" "\n - 1 for ordered sets" "\n - 2 for unidimensional ordered dense sets") - ("pw_impl,p", Util::prog_opts::value(&pw_impl_), + ("pw_impl,p", Util::prog_opts::value(&_pw_impl), " Desired PWMap implementation:" "\n - 0 for unordered PWMaps (default option)" "\n - 1 for ordered PWMaps" "\n - 2 for domain ordered PWMaps") - ("scc_impl", Util::prog_opts::value(&scc_impl_), + ("scc_impl", Util::prog_opts::value(&_scc_impl), "Desired SCC algorithm implementation:" "\n - 0 for V1 of minimum reachable SCC" - "\n - 1 for V2 of minimum reachable SCC (default option)"); - - cmd_line_opts_.add(generic_).add(config_).add(hidden_); - cfg_file_opts_.add(config_).add(hidden_); - visible_.add(generic_).add(config_); + "\n - 1 for V2 of minimum reachable SCC (default option)") + ("mfvs_impl", Util::prog_opts::value(&_mfvs_impl), + "Desired MFVS algorithm implementation:" + "\n - 0 for degree greedy MFVS" + "\n - 1 for smallest set-vertex MFVS (default option)"); + + // First option without name is the input file + _positional.add("input-file", 1); + _cmd_line_opts.add(_generic).add(_config).add(_hidden); + _cfg_file_opts.add(_config).add(_hidden); + _visible.add(_generic).add(_config); } -EvalUserInput EvalExecutor::chooseImplementation() +detail::EvalUserInput EvalExecutor::chooseImplementation() { - EvalUserInput result; + detail::EvalUserInput result; - AutomImplVisitor autom_impl_visitor; - EvalUserInput autom_impl = autom_impl_visitor.visit(Parser::parseFile( - *input_file_, false)); + detail::AutomImplVisitor autom_impl_visitor; + detail::EvalUserInput autom_impl = autom_impl_visitor.visit(Parser::parseFile( + *_input_file, false)); result.set_set_impl(autom_impl.set_impl()); result.set_pw_impl(autom_impl.pw_impl()); - if (set_impl_) { - if (set_impl_ > autom_impl.set_impl()) + if (_set_impl) { + if (_set_impl > autom_impl.set_impl()) { Util::ERROR("Incompatible set implementation for the SBG input\n"); + } - result.set_set_impl(set_impl_); + result.set_set_impl(_set_impl); } - if (pw_impl_) { - if (pw_impl_ > autom_impl.pw_impl()) - Util::ERROR("Incompatible PW implementation for the SBG input\n"); + if (_pw_impl) { + if (_pw_impl > autom_impl.pw_impl()) { + Util::ERROR("Incompatible PWMap implementation for the SBG input\n"); + } - result.set_pw_impl(pw_impl_); + result.set_pw_impl(_pw_impl); } - result.set_scc_impl(scc_impl_); + + result.set_scc_impl(_scc_impl); + result.set_mfvs_impl(_mfvs_impl); return result; } -void EvalExecutor::execute(int arg_count, char* args[]) +void EvalExecutor::execute(int argc, char* argv[]) { // Command line options handling --------------------------------------------- Util::prog_opts::variables_map vm; - store(Util::prog_opts::command_line_parser(arg_count, args) - .options(cmd_line_opts_).positional(positional_).run(), vm); + store(Util::prog_opts::command_line_parser(argc, argv) + .options(_cmd_line_opts).positional(_positional).run(), vm); notify(vm); // Help handling ------------------------------------------------------------- @@ -131,7 +145,7 @@ void EvalExecutor::execute(int arg_count, char* args[]) std::cout << "Usage: filename [options]\n"; std::cout << "Command line options are prioritized over configuration file" " options."; - std::cout << visible_ << "\n"; + std::cout << _visible << "\n"; return; } @@ -144,10 +158,10 @@ void EvalExecutor::execute(int arg_count, char* args[]) // Optional configuration file handling -------------------------------------- - if (config_file_) { - std::ifstream config_fs((*config_file_).c_str()); + if (_config_file) { + std::ifstream config_fs{(*_config_file).c_str()}; if (config_fs) { - store(parse_config_file(config_fs, cfg_file_opts_), vm); + store(parse_config_file(config_fs, _cfg_file_opts), vm); notify(vm); } } @@ -158,13 +172,14 @@ void EvalExecutor::execute(int arg_count, char* args[]) Util::SBGLogger::instance().setLevel(Util::LogLevel::Debug); } - if (input_file_) { - EvalUserInput input = chooseImplementation(); - InputTranslator input_translator; + if (_input_file) { + detail::EvalUserInput input = chooseImplementation(); + detail::InputTranslator input_translator; input_translator.translate(input); - ProgramIO eval_result = parseEvalFile(*input_file_); + ProgramIO eval_result = parseEvalFile(*_input_file); printHeader(vm); std::cout << eval_result; + Util::Internal::TimeProfiler::print_execution_time(); } else { std::cout << "Usage: filename [options]\n"; diff --git a/eval/eval_exec.hpp b/eval/eval_exec.hpp index 92163732..2c47c238 100644 --- a/eval/eval_exec.hpp +++ b/eval/eval_exec.hpp @@ -21,8 +21,8 @@ ******************************************************************************/ -#ifndef EVAL_EXEC_HPP -#define EVAL_EXEC_HPP +#ifndef SBGRAPH_EVAL_EXEC_HPP_ +#define SBGRAPH_EVAL_EXEC_HPP_ #include "eval/user_input.hpp" #include "util/user_input_handler.hpp" @@ -32,21 +32,22 @@ namespace SBG { namespace Eval { class EvalExecutor : public Util::UserInputHandler { - public: +public: EvalExecutor(); void execute(int arg_count, char* args[]) override; - private: - EvalUserInput chooseImplementation(); +private: + detail::EvalUserInput chooseImplementation(); - boost::optional set_impl_; - boost::optional pw_impl_; - boost::optional scc_impl_; + boost::optional _set_impl; + boost::optional _pw_impl; + boost::optional _scc_impl; + boost::optional _mfvs_impl; }; } // namespace Eval } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_EVAL_EXEC_HPP_ diff --git a/eval/file_evaluator.cpp b/eval/file_evaluator.cpp index 7ebf5311..ec73f550 100644 --- a/eval/file_evaluator.cpp +++ b/eval/file_evaluator.cpp @@ -17,12 +17,14 @@ ******************************************************************************/ -#include - #include "ast/sbg_program.hpp" +#include "eval/pretty_print.hpp" #include "eval/visitors/program_evaluator.hpp" #include "parser/file_parser.hpp" +#include +#include + namespace SBG { namespace Eval { @@ -31,8 +33,8 @@ ProgramIO parseEvalFile(std::string fname) { AST::SBGProgram parser_result = Parser::parseFile(fname); - Eval::ProgramEvaluator program_visit; - Eval::ProgramIO visit_result = program_visit.evaluate(parser_result); + detail::ProgramEvaluator program_visit; + ProgramIO visit_result = program_visit.evaluate(parser_result); return visit_result; } diff --git a/eval/file_evaluator.hpp b/eval/file_evaluator.hpp index c1e3aea6..7e5a718a 100644 --- a/eval/file_evaluator.hpp +++ b/eval/file_evaluator.hpp @@ -21,11 +21,12 @@ ******************************************************************************/ -#ifndef EVAL_FILE_HPP -#define EVAL_FILE_HPP +#ifndef SBGRAPH_EVAL_FILE_EVALUATOR_HPP_ +#define SBGRAPH_EVAL_FILE_EVALUATOR_HPP_ #include "eval/pretty_print.hpp" -#include "util/user_input_handler.hpp" + +#include namespace SBG { @@ -37,4 +38,4 @@ ProgramIO parseEvalFile(std::string fname); } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_FILE_EVALUATOR_HPP_ diff --git a/eval/func_env.cpp b/eval/func_env.cpp index 82058889..1b74d3ea 100755 --- a/eval/func_env.cpp +++ b/eval/func_env.cpp @@ -23,28 +23,32 @@ namespace SBG { namespace Eval { +namespace detail { + FuncEnv::FuncEnv() {} FuncEnv::FIt FuncEnv::begin() const { - return functions_.begin(); + return _functions.begin(); } FuncEnv::FIt FuncEnv::end() const { - return functions_.end(); + return _functions.end(); } FuncEnv::FIt FuncEnv::find(const FuncEnv::FKey& key) const { - return functions_.find(key); + return _functions.find(key); } void FuncEnv::insert(FuncEnv::FKey key, FuncEnv::FValue value) { - functions_[key] = value; + _functions[key] = value; } +} // namespace detail + } // namespace Eval } // namespace SBG diff --git a/eval/func_env.hpp b/eval/func_env.hpp index 60bde10b..e320a078 100755 --- a/eval/func_env.hpp +++ b/eval/func_env.hpp @@ -21,24 +21,27 @@ ******************************************************************************/ -#ifndef EVAL_FUNC_ENV_HPP -#define EVAL_FUNC_ENV_HPP - -#include +#ifndef SBGRAPH_EVAL_FUNC_ENV_HPP_ +#define SBGRAPH_EVAL_FUNC_ENV_HPP_ #include "ast/expr.hpp" #include "eval/base_type.hpp" +#include +#include + namespace SBG { namespace Eval { +namespace detail { + /** * @brief Function environment. Only has built-in functions: SBG programs can't * define new functions. */ class FuncEnv { - public: +public: using FKey = AST::Name; using FValue = std::function&)>; using FType = std::unordered_map; @@ -51,12 +54,14 @@ class FuncEnv { FIt find(const FKey& key) const; void insert(FKey key, FValue value); - private: - FType functions_; +private: + FType _functions; }; +} // namespace detail + } // namespace Eval } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_FUNC_ENV_HPP_ diff --git a/eval/input_translator.cpp b/eval/input_translator.cpp index 28d99167..8a3b8746 100755 --- a/eval/input_translator.cpp +++ b/eval/input_translator.cpp @@ -19,32 +19,31 @@ #include "eval/input_translator.hpp" #include "eval/user_impl_map.hpp" -#include "sbg/set_fact.hpp" +#include "util/debug.hpp" namespace SBG { namespace Eval { +namespace detail { + InputTranslator::InputTranslator() {} void InputTranslator::translate(EvalUserInput& input) { EvalUserInput::MaybeInt s = input.set_impl(); EvalUserInput::MaybeInt pw = input.pw_impl(); - if (pw && s) { - if (*pw == 2 && *s == 0) { + if (s && pw) { + if (*s == 0 && *pw == 2) { Util::ERROR("Domain ordered PWMap should be used with an ordered set" " implementation\n"); - } - else { + } else { setSetFactory(*s); setPWFactory(*pw); } - } - else if (s) { + } else if (s) { setSetFactory(*s); - } - else if (pw) { + } else if (pw) { setPWFactory(*pw); } @@ -53,9 +52,14 @@ void InputTranslator::translate(EvalUserInput& input) setSCCFactory(*scc); } - return; + EvalUserInput::MaybeInt mfvs = input.mfvs_impl(); + if (mfvs) { + setMFVSFactory(*mfvs); + } } +} // namespace detail + } // namespace Eval } // namespace SBG diff --git a/eval/input_translator.hpp b/eval/input_translator.hpp index 872fb64d..13d4ade8 100755 --- a/eval/input_translator.hpp +++ b/eval/input_translator.hpp @@ -21,8 +21,8 @@ ******************************************************************************/ -#ifndef EVAL_INPUT_TRANSLATOR_HPP -#define EVAL_INPUT_TRANSLATOR_HPP +#ifndef SBGRAPH_EVAL_INPUT_TRANSLATOR_HPP_ +#define SBGRAPH_EVAL_INPUT_TRANSLATOR_HPP_ #include "eval/user_input.hpp" @@ -30,15 +30,19 @@ namespace SBG { namespace Eval { +namespace detail { + class InputTranslator { - public: +public: InputTranslator(); - void translate(EvalUserInput& input); + static void translate(EvalUserInput& input); }; +} // namespace detail + } // namespace Eval } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_INPUT_TRANSLATOR_HPP_ diff --git a/eval/main.cpp b/eval/main.cpp index 2c894635..5705f462 100755 --- a/eval/main.cpp +++ b/eval/main.cpp @@ -29,7 +29,7 @@ #include "eval/eval_exec.hpp" -int main(int argc, char**argv) +int main(int argc, char* argv[]) { std::cout << std::boolalpha; diff --git a/eval/pretty_print.cpp b/eval/pretty_print.cpp index 9fa5ff30..2d8fa40f 100755 --- a/eval/pretty_print.cpp +++ b/eval/pretty_print.cpp @@ -19,67 +19,72 @@ #include "eval/pretty_print.hpp" +#include + namespace SBG { namespace Eval { template -std::ostream &operator<<(std::ostream &out, const std::variant &v) +std::ostream& operator<<(std::ostream& out, const std::variant& v) { - std::visit([&out](auto&& arg) { - out << arg; - }, v); + std::visit([&out](auto&& arg){ out << arg; }, v); return out; } -template std::ostream &operator<<(std::ostream &out, const ExprBaseType &v); +template std::ostream& operator<<(std::ostream& out, const ExprBaseType& v); -std::ostream &operator<<(std::ostream &out, const ExprResult &e) +std::ostream& operator<<(std::ostream& out, const ExprResult& e) { out << std::get<0>(e) << "\n --> " << std::get<1>(e) << "\n"; return out; } -std::ostream &operator<<(std::ostream &out, const ExprResultList &ee) +std::ostream& operator<<(std::ostream& out, const ExprResultList& ee) { - for (ExprResult e : ee) + for (ExprResult e : ee) { out << e << "\n"; + } return out; } -std::ostream &operator<<(std::ostream &out, const StmResult &s) +std::ostream& operator<<(std::ostream& out, const StmResult& s) { out << std::get<0>(s) << " = " << std::get<1>(s) << ";"; return out; } -std::ostream &operator<<(std::ostream &out, const StmResultList &ss) +std::ostream& operator<<(std::ostream& out, const StmResultList& ss) { - for (StmResult s : ss) + for (StmResult s : ss) { out << s << "\n"; + } return out; } ProgramIO::ProgramIO(StmResultList stms, ExprResultList exprs) - : nmbr_dims_(1), stms_(stms), exprs_(exprs) {} -ProgramIO::ProgramIO(unsigned int nmbr_dims, StmResultList stms - , ExprResultList exprs) - : nmbr_dims_(nmbr_dims), stms_(stms), exprs_(exprs) {} + : _arity(1), _stms(stms), _exprs(exprs) {} + +ProgramIO::ProgramIO(std::size_t n, StmResultList stms, ExprResultList exprs) + : _arity(n), _stms(stms), _exprs(exprs) {} + +const std::size_t& ProgramIO::arity() const { return _arity; } + +const StmResultList& ProgramIO::stms() const { return _stms; } -member_imp(ProgramIO, unsigned int, nmbr_dims); -member_imp(ProgramIO, StmResultList, stms); -member_imp(ProgramIO, ExprResultList, exprs); +const ExprResultList& ProgramIO::exprs() const { return _exprs; } -std::ostream &operator<<(std::ostream &out, const ProgramIO &p) +std::ostream& operator<<(std::ostream& out, const ProgramIO& p) { out << p.stms(); - if (p.stms().size() != 0) + if (p.stms().size() != 0) { out << "\n"; + } out << p.exprs(); return out; diff --git a/eval/pretty_print.hpp b/eval/pretty_print.hpp index 15dbf9a7..f1d61722 100755 --- a/eval/pretty_print.hpp +++ b/eval/pretty_print.hpp @@ -21,26 +21,31 @@ ******************************************************************************/ -#ifndef EVAL_PRETTY_PRINT_HPP -#define EVAL_PRETTY_PRINT_HPP +#ifndef SBGRAPH_EVAL_PRETTY_PRINT_HPP_ +#define SBGRAPH_EVAL_PRETTY_PRINT_HPP_ +#include "ast/expr.hpp" #include "eval/base_type.hpp" +#include +#include +#include + namespace SBG { namespace Eval { template -std::ostream &operator<<(std::ostream &out, const std::variant &v); +std::ostream& operator<<(std::ostream& out, const std::variant& v); using ExprResult = std::tuple; -std::ostream &operator<<(std::ostream &out, const ExprResult &e); +std::ostream& operator<<(std::ostream& out, const ExprResult& e); using ExprResultList = std::vector; -std::ostream &operator<<(std::ostream &out, const ExprResultList &ee); +std::ostream& operator<<(std::ostream& out, const ExprResultList& ee); using StmResult = std::tuple; -std::ostream &operator<<(std::ostream &out, const StmResult &s); +std::ostream& operator<<(std::ostream& out, const StmResult& s); using StmResultList = std::vector; -std::ostream &operator<<(std::ostream &out, const StmResultList &ss); +std::ostream& operator<<(std::ostream& out, const StmResultList& ss); /** * @brief Class to pretty print a program and its correspondent evaluation. @@ -48,18 +53,25 @@ std::ostream &operator<<(std::ostream &out, const StmResultList &ss); * - There will be a tuple for each expression with its original form and * the result of evaluating it. */ -struct ProgramIO { - member_class(unsigned int, nmbr_dims); - member_class(StmResultList, stms); - member_class(ExprResultList, exprs); - +class ProgramIO { +public: ProgramIO(StmResultList stms, ExprResultList exprs); - ProgramIO(unsigned int nmbr_dims, StmResultList stms, ExprResultList exprs); + ProgramIO(std::size_t n, StmResultList stms, ExprResultList exprs); + + const std::size_t& arity() const; + const StmResultList& stms() const; + const ExprResultList& exprs() const; + +private: + std::size_t _arity; + StmResultList _stms; + ExprResultList _exprs; }; -std::ostream &operator<<(std::ostream &out, const ProgramIO &p); + +std::ostream& operator<<(std::ostream& out, const ProgramIO& p); } // namespace Eval } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_PRETTY_PRINT_HPP_ diff --git a/eval/user_impl_map.cpp b/eval/user_impl_map.cpp index bd36d4a7..00ef5dea 100755 --- a/eval/user_impl_map.cpp +++ b/eval/user_impl_map.cpp @@ -18,64 +18,67 @@ ******************************************************************************/ #include "eval/user_impl_map.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/set.hpp" +#include "util/debug.hpp" namespace SBG { namespace Eval { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // Single Structure Implementation Map ----------------------------------------- //////////////////////////////////////////////////////////////////////////////// -UserImplMap::StructImplMap::StructImplMap() : is_frozen_(false) {} +UserImplMap::StructImplMap::StructImplMap() : _is_frozen(false) {} UserImplMap::StructImplMap::SValue& UserImplMap::StructImplMap::operator[] (const SKey& key) { - Util::ERROR_UNLESS(!is_frozen_, "StructImplMap: map is frozen, insertion is" + Util::ERROR_UNLESS(!_is_frozen, "StructImplMap: map is frozen, insertion is" " prohibited.\n"); - return struct_impls_[key]; + return _struct_impls[key]; } const UserImplMap::StructImplMap::SValue& UserImplMap::StructImplMap::operator[] (const SKey& key) const { - Util::ERROR_UNLESS(struct_impls_.find(key) != struct_impls_.end() + Util::ERROR_UNLESS(_struct_impls.find(key) != _struct_impls.end() , "StructImplMap: undefined implementation.\n"); - return struct_impls_.at(key); + return _struct_impls.at(key); } void UserImplMap::StructImplMap::freeze() { - is_frozen_ = true; + _is_frozen = true; } UserImplMap::StructImplMap setMap() { UserImplMap::StructImplMap set_mapping; - set_mapping[0] = []() { return std::make_unique(); }; - set_mapping[1] = []() { return std::make_unique(); }; - set_mapping[2] = []() { - return std::make_unique(); - }; + set_mapping[0] = LIB::SetKind::kUnordered; + set_mapping[1] = LIB::SetKind::kOrdered; + set_mapping[2] = LIB::SetKind::kOrdUnidimDense; set_mapping.freeze(); return set_mapping; } UserImplMap::StructImplMap pwMap() { - UserImplMap::StructImplMap pw_mapping; - pw_mapping[0] = []() { return std::make_unique(); }; - pw_mapping[1] = []() { return std::make_unique(); }; - pw_mapping[2] = []() { return std::make_unique(); }; - pw_mapping.freeze(); - return pw_mapping; + UserImplMap::StructImplMap pwmap_mapping; + pwmap_mapping[0] = LIB::PWMapKind::kUnordered; + pwmap_mapping[1] = LIB::PWMapKind::kOrdered; + pwmap_mapping[2] = LIB::PWMapKind::kDomOrdered; + pwmap_mapping.freeze(); + return pwmap_mapping; } UserImplMap::StructImplMap matchMap() { UserImplMap::StructImplMap match_mapping; - match_mapping[0] = []() { return std::make_unique(); }; + match_mapping[0] = LIB::MatchKind::kBFSPaths; match_mapping.freeze(); return match_mapping; } @@ -83,28 +86,29 @@ UserImplMap::StructImplMap matchMap() UserImplMap::StructImplMap sccMap() { UserImplMap::StructImplMap scc_mapping; - scc_mapping[0] = []() { return std::make_unique(); }; - scc_mapping[1] = []() { return std::make_unique(); }; + scc_mapping[0] = LIB::SCCKind::kMinReachV1; + scc_mapping[1] = LIB::SCCKind::kMinReachV2; scc_mapping.freeze(); return scc_mapping; } +UserImplMap::StructImplMap mfvsMap() +{ + UserImplMap::StructImplMap mfvs_mapping; + mfvs_mapping[0] = LIB::MFVSKind::kGreedy; + mfvs_mapping[1] = LIB::MFVSKind::kSmallSV; + mfvs_mapping.freeze(); + return mfvs_mapping; +} + UserImplMap::StructImplMap tsMap() { UserImplMap::StructImplMap ts_mapping; - ts_mapping[0] = []() { return std::make_unique(); }; + ts_mapping[0] = LIB::TSKind::kMinVertex; ts_mapping.freeze(); return ts_mapping; } -UserImplMap::StructImplMap cvMap() -{ - UserImplMap::StructImplMap cv_mapping; - cv_mapping[0] = []() { return std::make_unique(); }; - cv_mapping.freeze(); - return cv_mapping; -} - //////////////////////////////////////////////////////////////////////////////// // User Implementation Map ----------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// @@ -112,46 +116,53 @@ UserImplMap::StructImplMap cvMap() UserImplMap::UserImplMap() { implementations_["set"] = setMap(); - implementations_["pw"] = pwMap(); + implementations_["pwmap"] = pwMap(); implementations_["match"] = matchMap(); implementations_["scc"] = sccMap(); + implementations_["mfvs"] = mfvsMap(); implementations_["ts"] = tsMap(); - implementations_["cv"] = cvMap(); } -ImplFactory UserImplMap::getFactory(std::string strct, int impl) +Kind UserImplMap::getFactory(std::string strct, int impl) { const StructImplMap& struct_map = implementations_[strct]; - return struct_map[impl](); + return struct_map[impl]; } +} // namespace detail + //////////////////////////////////////////////////////////////////////////////// // Extra operations ------------------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// void setSetFactory(int set_impl) { - LIB::SetFactPtr set_fact = std::get(IMPL_MAP.getFactory("set" - , set_impl)); - LIB::SetFactory::instance().set_set_fact(std::move(set_fact)); - - return; + LIB::SetKind set_fact = std::get(detail::IMPL_MAP.getFactory( + "set", set_impl)); + LIB::SET_IMPL.set_set_fact(set_fact); } void setPWFactory(int pw_impl) { - LIB::PWMapFactPtr pw_fact = std::get( - IMPL_MAP.getFactory("pw", pw_impl)); - LIB::PWFactory::instance().set_pw_fact(std::move(pw_fact)); + LIB::PWMapKind pwmap_fact = std::get( + detail::IMPL_MAP.getFactory("pwmap", pw_impl)); + LIB::PWMAP_IMPL.set_pwmap_fact(pwmap_fact); +} + +void setSCCFactory(int scc_impl) +{ + LIB::SCCKind scc_fact = std::get( + detail::IMPL_MAP.getFactory("scc", scc_impl)); + LIB::SCC_IMPL.set_scc_fact(scc_fact); return; } -void setSCCFactory(int scc_impl) +void setMFVSFactory(int mfvs_impl) { - LIB::SCCFactPtr scc_fact = std::get(IMPL_MAP.getFactory("scc" - , scc_impl)); - LIB::SCCFactory::instance().set_scc_fact(std::move(scc_fact)); + LIB::MFVSKind mfvs_fact = std::get( + detail::IMPL_MAP.getFactory("mfvs", mfvs_impl)); + LIB::MFVS_IMPL.set_mfvs_fact(mfvs_fact); return; } diff --git a/eval/user_impl_map.hpp b/eval/user_impl_map.hpp index 2f1f46c1..b2476cc0 100755 --- a/eval/user_impl_map.hpp +++ b/eval/user_impl_map.hpp @@ -26,24 +26,28 @@ ******************************************************************************/ -#ifndef EVAL_USER_IMPL_MAP_HPP -#define EVAL_USER_IMPL_MAP_HPP +#ifndef SBGRAPH_EVAL_USER_IMPL_MAP_HPP_ +#define SBGRAPH_EVAL_USER_IMPL_MAP_HPP_ + +#include "algorithms/matching/matching_impl.hpp" +#include "algorithms/mfvs/mfvs_impl.hpp" +#include "algorithms/scc/scc_impl.hpp" +#include "algorithms/sorting/topological/ts_impl.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/pwmap_impl.hpp" +#include "sbg/set.hpp" +#include "sbg/set_impl.hpp" #include #include #include -#include "algorithms/cutvertex/cv_fact.hpp" -#include "algorithms/matching/matching_fact.hpp" -#include "algorithms/scc/scc_fact.hpp" -#include "algorithms/toposort/ts_fact.hpp" -#include "sbg/pwmap_fact.hpp" -#include "sbg/set_fact.hpp" - namespace SBG { namespace Eval { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // User input to implementation map -------------------------------------------- //////////////////////////////////////////////////////////////////////////////// @@ -51,24 +55,28 @@ namespace Eval { #define IMPL_MAP UserImplMap::instance() /** - * @brief Type defined to be used in ImplEnv. + * @brief Type defined to be used in UserImplMap. */ -using ImplFactory = std::variant; +using Kind = std::variant; /** * @brief Mapping for all structures such as Set, PW and algorithms. */ class UserImplMap { - public: +public: /** * @brief Mapping of a single structure. For example, it maps numbers to the * different Set implementations. */ class StructImplMap { - public: + public: using SKey = int; - using SValue = std::function; + using SValue = Kind; using SType = std::unordered_map; StructImplMap(); @@ -77,9 +85,9 @@ class UserImplMap { const SValue& operator[](const SKey& key) const; void freeze(); - private: - bool is_frozen_; - SType struct_impls_; + private: + bool _is_frozen; + SType _struct_impls; }; using IKey = std::string; @@ -90,14 +98,16 @@ class UserImplMap { static UserImplMap instance_; return instance_; } - ImplFactory getFactory(std::string strct, int impl); + Kind getFactory(std::string strct, int impl); - private: +private: UserImplMap(); IType implementations_; }; +} // namespace detail + //////////////////////////////////////////////////////////////////////////////// // Extra operations ------------------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// @@ -105,9 +115,10 @@ class UserImplMap { void setSetFactory(int set_impl); void setPWFactory(int pw_impl); void setSCCFactory(int scc_impl); +void setMFVSFactory(int mfvs_impl); } // namespace Eval } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_USER_IMPL_MAP_HPP diff --git a/eval/user_input.cpp b/eval/user_input.cpp index 619716ba..7d60ece9 100755 --- a/eval/user_input.cpp +++ b/eval/user_input.cpp @@ -23,6 +23,8 @@ namespace SBG { namespace Eval { +namespace detail { + // Constructors ---------------------------------------------------------------- EvalUserInput::EvalUserInput() {} @@ -31,66 +33,68 @@ EvalUserInput::EvalUserInput() {} EvalUserInput::MaybeInt EvalUserInput::set_impl() const { - return set_impl_; + return _set_impl; } EvalUserInput::MaybeInt EvalUserInput::pw_impl() const { - return pw_impl_; + return _pw_impl; } EvalUserInput::MaybeInt EvalUserInput::match_impl() const { - return match_impl_; + return _match_impl; } EvalUserInput::MaybeInt EvalUserInput::scc_impl() const { - return scc_impl_; + return _scc_impl; } -EvalUserInput::MaybeInt EvalUserInput::ts_impl() const +EvalUserInput::MaybeInt EvalUserInput::mfvs_impl() const { - return ts_impl_; + return _mfvs_impl; } -EvalUserInput::MaybeInt EvalUserInput::cv_impl() const +EvalUserInput::MaybeInt EvalUserInput::ts_impl() const { - return cv_impl_; + return _ts_impl; } // Setters --------------------------------------------------------------------- void EvalUserInput::set_set_impl(MaybeInt set_impl) { - set_impl_ = set_impl; + _set_impl = set_impl; } void EvalUserInput::set_pw_impl(MaybeInt pw_impl) { - pw_impl_ = pw_impl; + _pw_impl = pw_impl; } void EvalUserInput::set_match_impl(MaybeInt match_impl) { - match_impl_ = match_impl; + _match_impl = match_impl; } void EvalUserInput::set_scc_impl(MaybeInt scc_impl) { - scc_impl_ = scc_impl; + _scc_impl = scc_impl; } -void EvalUserInput::set_ts_impl(MaybeInt ts_impl) +void EvalUserInput::set_mfvs_impl(MaybeInt mfvs_impl) { - ts_impl_ = ts_impl; + _mfvs_impl = mfvs_impl; } -void EvalUserInput::set_cv_impl(MaybeInt cv_impl) +void EvalUserInput::set_ts_impl(MaybeInt ts_impl) { - cv_impl_ = cv_impl; + _ts_impl = ts_impl; } +} // namespace detail + } // namespace Eval } // namespace SBG diff --git a/eval/user_input.hpp b/eval/user_input.hpp index 808dab04..e2215f02 100755 --- a/eval/user_input.hpp +++ b/eval/user_input.hpp @@ -24,8 +24,8 @@ ******************************************************************************/ -#ifndef EVAL_USER_INPUT_HPP -#define EVAL_USER_INPUT_HPP +#ifndef SBGRAPH_EVAL_USER_INPUT_HPP_ +#define SBGRAPH_EVAL_USER_INPUT_HPP_ #include "boost/optional.hpp" @@ -33,8 +33,10 @@ namespace SBG { namespace Eval { +namespace detail { + class EvalUserInput { - public: +public: using MaybeInt = boost::optional; EvalUserInput(); @@ -44,27 +46,29 @@ class EvalUserInput { MaybeInt pw_impl() const; MaybeInt match_impl() const; MaybeInt scc_impl() const; + MaybeInt mfvs_impl() const; MaybeInt ts_impl() const; - MaybeInt cv_impl() const; // Setters void set_set_impl(MaybeInt set_impl); void set_pw_impl(MaybeInt pw_impl); void set_match_impl(MaybeInt match_impl); void set_scc_impl(MaybeInt scc_impl); + void set_mfvs_impl(MaybeInt mfvs_impl); void set_ts_impl(MaybeInt ts_impl); - void set_cv_impl(MaybeInt cv_impl); - - private: - MaybeInt set_impl_; - MaybeInt pw_impl_; - MaybeInt match_impl_; - MaybeInt scc_impl_; - MaybeInt ts_impl_; - MaybeInt cv_impl_; + +private: + MaybeInt _set_impl; + MaybeInt _pw_impl; + MaybeInt _match_impl; + MaybeInt _scc_impl; + MaybeInt _ts_impl; + MaybeInt _mfvs_impl; }; +} // detail + } // namespace Eval } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_USER_INPUT_HPP_ diff --git a/eval/var_env.cpp b/eval/var_env.cpp index 058d3fd7..f2a95774 100755 --- a/eval/var_env.cpp +++ b/eval/var_env.cpp @@ -23,28 +23,32 @@ namespace SBG { namespace Eval { -VarEnv::VarEnv() : variables_() {} +namespace detail { + +VarEnv::VarEnv() : _variables() {} VarEnv::VIt VarEnv::begin() const { - return variables_.begin(); + return _variables.begin(); } VarEnv::VIt VarEnv::end() const { - return variables_.end(); + return _variables.end(); } VarEnv::VIt VarEnv::find(const VarEnv::VKey& key) const { - return variables_.find(key); + return _variables.find(key); } void VarEnv::insert(VarEnv::VKey key, VarEnv::VValue value) { - variables_[key] = value; + _variables[key] = value; } +} // namespace detail + } // namespace Eval } // namespace SBG diff --git a/eval/var_env.hpp b/eval/var_env.hpp index 4ddbaf39..3e361ca7 100755 --- a/eval/var_env.hpp +++ b/eval/var_env.hpp @@ -21,24 +21,26 @@ ******************************************************************************/ -#ifndef EVAL_VAR_ENV_HPP -#define EVAL_VAR_ENV_HPP - -#include +#ifndef SBGRAPH_EVAL_VAR_ENV_HPP_ +#define SBGRAPH_EVAL_VAR_ENV_HPP_ #include "ast/expr.hpp" #include "eval/base_type.hpp" +#include + namespace SBG { namespace Eval { +namespace detail { + /** * @brief Variable environment (with expressions already evaluated). This env * will be populated by StmEvaluator, and used by ExprEvaluator. */ class VarEnv { - public: +public: using VKey = AST::Name; using VValue = ExprBaseType; using VType = std::unordered_map; @@ -51,12 +53,14 @@ class VarEnv { VIt find(const VKey& key) const; void insert(VKey key, VValue value); - private: - mutable VType variables_; +private: + mutable VType _variables; }; +} // namespace detail + } // namespace Eval } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_VAR_ENV_HPP_ diff --git a/eval/visitors/autom_impl_visitor.cpp b/eval/visitors/autom_impl_visitor.cpp index 43bf3a24..18115780 100755 --- a/eval/visitors/autom_impl_visitor.cpp +++ b/eval/visitors/autom_impl_visitor.cpp @@ -21,12 +21,13 @@ #include "eval/visitors/autom_impl_visitor.hpp" #include "eval/visitors/stm_evaluator.hpp" #include "eval/visitors/set_impl_visitor.hpp" -#include "sbg/pwmap_fact.hpp" namespace SBG { namespace Eval { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // Automatic Implementation Visitor -------------------------------------------- //////////////////////////////////////////////////////////////////////////////// @@ -37,25 +38,26 @@ EvalUserInput AutomImplVisitor::visit(AST::SBGProgram p) const { // Statement inspection ------------------------------------------------------ - LIB::NAT dims = 1; AST::IsConfig cfg_visit; - EvalContext eval_ctx; + EvalContext eval_context; if (!p.stms().empty()) { AST::Statement first = p.stms()[0]; - if (boost::apply_visitor(cfg_visit, first)) - eval_ctx.setArity(boost::get(first).nmbr_dims()); + if (boost::apply_visitor(cfg_visit, first)) { + eval_context.setArity(boost::get(first).nmbr_dims()); + } } - StmEvaluator stm_eval(eval_ctx); + StmEvaluator stm_eval{eval_context}; for (AST::Statement stm : p.stms()) { - if (!boost::apply_visitor(cfg_visit, stm)) + if (!boost::apply_visitor(cfg_visit, stm)) { StmResult se = boost::apply_visitor(stm_eval, stm); + } } // Set Implementation -------------------------------------------------------- int auto_set_impl = 2; - SetImplExprVisitor set_impl_visit(stm_eval.eval_ctx().venv()); + SetImplExprVisitor set_impl_visit{stm_eval.eval_context().venv()}; for (AST::Expr expr : p.exprs()) { int ith_set_impl = boost::apply_visitor(set_impl_visit, expr); auto_set_impl = std::min(auto_set_impl, ith_set_impl); @@ -74,6 +76,8 @@ EvalUserInput AutomImplVisitor::visit(AST::SBGProgram p) const return result; } +} // namespace detail + } // namespace Eval } // namespace SBG diff --git a/eval/visitors/autom_impl_visitor.hpp b/eval/visitors/autom_impl_visitor.hpp index a4a78844..e4aeede3 100755 --- a/eval/visitors/autom_impl_visitor.hpp +++ b/eval/visitors/autom_impl_visitor.hpp @@ -25,10 +25,8 @@ ******************************************************************************/ -#ifndef AUTOM_IMPL_VISITOR -#define AUTOM_IMPL_VISITOR - -#include +#ifndef SBGRAPH_EVAL_VISITORS_AUTOM_IMPL_VISITOR_HPP_ +#define SBGRAPH_EVAL_VISITORS_AUTOM_IMPL_VISITOR_HPP_ #include "ast/sbg_program.hpp" #include "eval/user_input.hpp" @@ -37,15 +35,19 @@ namespace SBG { namespace Eval { +namespace detail { + class AutomImplVisitor { - public: +public: AutomImplVisitor(); EvalUserInput visit(AST::SBGProgram p) const; }; +} // namespace detail + } // namespace Eval } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_VISITORS_AUTOM_IMPL_VISITOR_HPP_ diff --git a/eval/visitors/expr_evaluator.cpp b/eval/visitors/expr_evaluator.cpp index bc0651f2..19b354ee 100755 --- a/eval/visitors/expr_evaluator.cpp +++ b/eval/visitors/expr_evaluator.cpp @@ -17,30 +17,25 @@ ******************************************************************************/ -#include "algorithms/cc/cc.hpp" -#include "algorithms/cutvertex/cv_fact.hpp" -#include "algorithms/matching/bfs_matching.hpp" -#include "algorithms/matching/matching_fact.hpp" -#include "algorithms/scc/scc_fact.hpp" -#include "algorithms/toposort/ts_fact.hpp" -#include "algorithms/misc/causalization_builders.hpp" -#include "algorithms/misc/causalization_json.hpp" #include "eval/visitors/expr_evaluator.hpp" #include "eval/visitors/func_evaluator.hpp" #include "eval/visitors/linear_expr_evaluator.hpp" #include "eval/visitors/nat_evaluator.hpp" #include "eval/visitors/rational_evaluator.hpp" +#include "util/debug.hpp" namespace SBG { namespace Eval { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // Expression evaluator -------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// template -T eval(const ExprEvaluator &visit, AST::Expr e, std::string t = "UNDEF") +T eval(const ExprEvaluator& visit, AST::Expr e, std::string t = "UNDEF") { ExprBaseType visited = boost::apply_visitor(visit, e); @@ -50,7 +45,7 @@ T eval(const ExprEvaluator &visit, AST::Expr e, std::string t = "UNDEF") return std::get(visited); } -ExprEvaluator::ExprEvaluator(EvalContext& eval_ctx) : eval_ctx_(eval_ctx) +ExprEvaluator::ExprEvaluator(EvalContext& eval_ctx) : _eval_context(eval_ctx) { // Set built-in functions eval_ctx.insertFunction("isEmpty", BuiltInFunctions::emptyEvaluator); @@ -63,17 +58,19 @@ ExprEvaluator::ExprEvaluator(EvalContext& eval_ctx) : eval_ctx_(eval_ctx) eval_ctx.insertFunction("preImage", BuiltInFunctions::preImageEvaluator); eval_ctx.insertFunction("dom", BuiltInFunctions::domEvaluator); eval_ctx.insertFunction("combine", BuiltInFunctions::combineEvaluator); - eval_ctx.insertFunction("firstInv", BuiltInFunctions::firstInvEvaluator); eval_ctx.insertFunction("minMap", BuiltInFunctions::minMapEvaluator); - eval_ctx.insertFunction("reduce", BuiltInFunctions::reduceEvaluator); eval_ctx.insertFunction("minAdj", BuiltInFunctions::minAdjEvaluator); eval_ctx.insertFunction("mapInf", BuiltInFunctions::mapInfEvaluator); + eval_ctx.insertFunction("imgMult", BuiltInFunctions::imageMultEvaluator); eval_ctx.insertFunction("cc", BuiltInFunctions::connectedEvaluator); eval_ctx.insertFunction("match", BuiltInFunctions::matchingEvaluator); eval_ctx.insertFunction("scc", BuiltInFunctions::sccEvaluator); - eval_ctx.insertFunction("sort", BuiltInFunctions::topoSortEvaluator); - eval_ctx.insertFunction("cut", BuiltInFunctions::cutVertexEvaluator); eval_ctx.insertFunction("matchSCC", BuiltInFunctions::matchSCCEvaluator); + eval_ctx.insertFunction("mfvs", BuiltInFunctions::mfvsEvaluator); + eval_ctx.insertFunction("matchSCCMFVS" + , BuiltInFunctions::matchSCCMFVSEvaluator); + eval_ctx.insertFunction("sort", BuiltInFunctions::topoSortEvaluator); + eval_ctx.insertFunction("causalize", BuiltInFunctions::causalizationEvaluator); } ExprBaseType ExprEvaluator::operator()(AST::Natural v) const @@ -83,19 +80,19 @@ ExprBaseType ExprEvaluator::operator()(AST::Natural v) const ExprBaseType ExprEvaluator::operator()(AST::Rational v) const { - return boost::apply_visitor(RationalEvaluator(eval_ctx_.venv()) - , AST::Expr(v)); + return boost::apply_visitor(RationalEvaluator{_eval_context.venv()} + , AST::Expr{v}); } ExprBaseType ExprEvaluator::operator()(AST::Name v) const { - auto var_definition = eval_ctx_.venv().find(v); - if (var_definition != eval_ctx_.venv().end()) { + auto var_definition = _eval_context.venv().find(v); + if (var_definition != _eval_context.venv().end()) { return var_definition->second; } Util::ERROR("ExprEvaluator: variable ", v, " undefined\n"); - return ExprBaseType(); + return ExprBaseType{}; } ExprBaseType ExprEvaluator::operator()(AST::UnaryOp v) const @@ -122,8 +119,8 @@ ExprBaseType ExprEvaluator::operator()(AST::Call v) const { std::string func_name = v.name(); - auto func_definition = eval_ctx_.fenv().find(func_name); - if (func_definition != eval_ctx_.fenv().end()) { + auto func_definition = _eval_context.fenv().find(func_name); + if (func_definition != _eval_context.fenv().end()) { std::vector evaluated_args; for (AST::Expr a : v.args()) { evaluated_args.push_back(boost::apply_visitor(*this, a)); @@ -133,98 +130,113 @@ ExprBaseType ExprEvaluator::operator()(AST::Call v) const } Util::ERROR("ExprEvaluator: function ", func_name, " doesn't exist\n"); - return ExprBaseType(); + return ExprBaseType{}; } ExprBaseType ExprEvaluator::operator()(AST::Interval v) const { - NatEvaluator visit_nat(eval_ctx_.venv()); + NatEvaluator nat_evaluator{_eval_context.venv()}; - LIB::NAT b = boost::apply_visitor(visit_nat, v.begin()); - LIB::NAT s = boost::apply_visitor(visit_nat, v.step()); - LIB::NAT e = boost::apply_visitor(visit_nat, v.end()); + LIB::NAT b = boost::apply_visitor(nat_evaluator, v.begin()); + LIB::NAT s = boost::apply_visitor(nat_evaluator, v.step()); + LIB::NAT e = boost::apply_visitor(nat_evaluator, v.end()); - return LIB::Interval(b, s, e); + return LIB::Set{b, s, e}; } ExprBaseType ExprEvaluator::operator()(AST::MultiDimInter v) const { - LIB::SetPiece res; - - for (const AST::Expr &e : v.intervals()) - res.emplaceBack(eval(*this, e, "Interval")); + LIB::Set result; + + int i = 0; + for (const AST::Expr& e : v.intervals()) { + LIB::Set kth_component = eval(*this, e, "Set"); + if (i == 0) { + result = std::move(kth_component); + } else { + result = result.cartesianProduct(kth_component); + } + ++i; + } - Util::ERROR_UNLESS(res.arity() == eval_ctx_.arity() || res.arity() == 0 - , "EvalMDI[nmbr_dims = ", eval_ctx_.arity(), "]: arity(", res, ") = " - , res.arity(), "\n"); + Util::ERROR_UNLESS(result.arity() == _eval_context.arity() + || result.arity() == 0, "EvalMDI[arity = ", _eval_context.arity() + , "]: arity(", result, ") = ", result.arity(), "\n"); - return res; + return result; } ExprBaseType ExprEvaluator::operator()(AST::Set v) const { - LIB::Set res = LIB::SET_FACT.createSet(); + LIB::Set result; - for (const AST::Expr &e : v.pieces()) - res.emplaceBack(eval(*this, e, "SetPiece")); + for (const AST::Expr& e : v.pieces()) { + LIB::Set jth_element = eval(*this, e, "Set"); + result = std::move(result).disjointCup(std::move(jth_element)); + } - Util::ERROR_UNLESS(res.arity() == eval_ctx_.arity() || res.arity() == 0 - , "ExprEvaluator[nmbr_dims = ", eval_ctx_.arity(), "]: arity(", res, ") = " - , res.arity(), "\n"); + Util::ERROR_UNLESS(result.arity() == _eval_context.arity() + || result.arity() == 0, "ExprEvaluator[arity = ", _eval_context.arity() + , "]: arity(", result, ") = ", result.arity(), "\n"); - return res; + return result; } ExprBaseType ExprEvaluator::operator()(AST::LinearExp v) const { - LinearExprEvaluator visit_le(eval_ctx_.venv()); - return boost::apply_visitor(visit_le, AST::Expr(v)); + LinearExprEvaluator linear_expr_evaluator{_eval_context.venv()}; + LIB::detail::LinearExpr linear_expr + = boost::apply_visitor(linear_expr_evaluator, AST::Expr(v)); + return LIB::Expression{linear_expr.slope(), linear_expr.offset()}; } ExprBaseType ExprEvaluator::operator()(AST::MDLExp v) const { - LIB::Exp res; - - LinearExprEvaluator visit_le(eval_ctx_.venv()); - for (const AST::Expr &e : v.exps()) { - LIB::LExp ith = boost::apply_visitor(visit_le, e); - res.emplaceBack(ith); + LIB::Expression result; + + LinearExprEvaluator linear_expr_evaluator{_eval_context.venv()}; + for (const AST::Expr& e : v.exps()) { + LIB::detail::LinearExpr kth_component + = boost::apply_visitor(linear_expr_evaluator, e); + result = result.cartesianProduct(LIB::Expression{kth_component.slope() + , kth_component.offset()}); } - Util::ERROR_UNLESS(res.arity() == eval_ctx_.arity() || res.arity() == 0 - , "ExprEvaluator[nmbr_dims = ", eval_ctx_.arity(), "]: arity(", res, ") = " - , res.arity(), "\n"); + Util::ERROR_UNLESS(result.arity() == _eval_context.arity() + || result.arity() == 0, "ExprEvaluator[arity = ", _eval_context.arity(), + "]: arity(", result, ") = ", result.arity(), "\n"); - return res; + return result; } ExprBaseType ExprEvaluator::operator()(AST::LinearMap v) const { - LIB::Set d = eval(*this, v.dom(), "Set"); - LIB::Exp e = eval(*this, v.lexp(), "Exp"); + LIB::Set domain = eval(*this, v.dom(), "Set"); + LIB::Expression law = eval(*this, v.lexp(), "Expression"); - LIB::Map res(d, e); + LIB::Map result{domain, law}; - Util::ERROR_UNLESS(res.arity() == eval_ctx_.arity() || res.arity() == 0 - , "ExprEvaluator[nmbr_dims = ", eval_ctx_.arity(), "]: arity(", res, ") = " - , res.arity(), "\n"); + Util::ERROR_UNLESS(result.arity() == _eval_context.arity() + || result.arity() == 0, "ExprEvaluator[arity = ", _eval_context.arity() + , "]: arity(", result, ") = ", result.arity(), "\n"); - return res; + return result; } ExprBaseType ExprEvaluator::operator()(AST::PWLMap v) const { - LIB::PWMap res = LIB::PW_FACT.createPWMap(); + LIB::PWMap result; - for (const AST::Expr &e : v.maps()) - res.emplaceBack(eval(*this, e, "Map")); + for (const AST::Expr& e : v.maps()) { + result.insert(eval(*this, e, "Map")); + } - Util::ERROR_UNLESS(res.arity() == eval_ctx_.arity() || res.arity() == 0 - , "ExprEvaluator[nmbr_dims = ", eval_ctx_.arity(), "]: arity(", res, ") = " - , res.arity(), "\n"); + Util::ERROR_UNLESS(result.arity() == _eval_context.arity() + || result.arity() == 0, "ExprEvaluator[arity = ", _eval_context.arity() + , "]: arity(", result, ") = ", result.arity(), "\n"); - return res; + return result; } ExprBaseType ExprEvaluator::operator()(AST::SBG v) const @@ -234,20 +246,8 @@ ExprBaseType ExprEvaluator::operator()(AST::SBG v) const LIB::PWMap map1 = eval(*this, v.map1(), "PWMap"); LIB::PWMap map2 = eval(*this, v.map2(), "PWMap"); LIB::PWMap Emap = eval(*this, v.Emap(), "PWMap"); - LIB::PWMap subE = eval(*this, v.subE_map(), "PWMap"); - - if (subE.dom().isEmpty() && !Emap.dom().isEmpty()) { - unsigned int j = 1; - for (const LIB::Map &m : Emap) { - for (const LIB::SetPiece &mdi : m.dom()) { - LIB::Exp off(LIB::MD_NAT(mdi.arity(), j)); - subE.emplaceBack(LIB::Map(LIB::SET_FACT.createSet(mdi), off)); - ++j; - } - } - } - return LIB::SBG(V, Vmap, map1, map2, Emap, subE); + return LIB::SBG{V, Vmap, map1, map2, Emap}; } ExprBaseType ExprEvaluator::operator()(AST::BipartiteSBG v) const @@ -257,22 +257,10 @@ ExprBaseType ExprEvaluator::operator()(AST::BipartiteSBG v) const LIB::PWMap map1 = eval(*this, v.map1(), "PWMap"); LIB::PWMap map2 = eval(*this, v.map2(), "PWMap"); LIB::PWMap Emap = eval(*this, v.Emap(), "PWMap"); - LIB::PWMap subE = eval(*this, v.subE_map(), "PWMap"); LIB::Set X = eval(*this, v.X(), "Set"); LIB::Set Y = eval(*this, v.Y(), "Set"); - if (subE.dom().isEmpty() && !Emap.dom().isEmpty()) { - unsigned int j = 1; - for (const LIB::Map &m : Emap) { - for (const LIB::SetPiece &mdi : m.dom()) { - LIB::Exp off(LIB::MD_NAT(mdi.arity(), j)); - subE.emplaceBack(LIB::Map(LIB::SET_FACT.createSet(mdi), off)); - ++j; - } - } - } - - return LIB::BipartiteSBG(V, Vmap, map1, map2, Emap, subE, X, Y); + return LIB::BipartiteSBG{V, Vmap, map1, map2, Emap, X, Y}; } ExprBaseType ExprEvaluator::operator()(AST::DSBG v) const @@ -282,20 +270,8 @@ ExprBaseType ExprEvaluator::operator()(AST::DSBG v) const LIB::PWMap mapB = eval(*this, v.mapB(), "PWMap"); LIB::PWMap mapD = eval(*this, v.mapD(), "PWMap"); LIB::PWMap Emap = eval(*this, v.Emap(), "PWMap"); - LIB::PWMap subE = eval(*this, v.subE_map(), "PWMap"); - - if (subE.dom().isEmpty() && !Emap.dom().isEmpty()) { - unsigned int j = 1; - for (const LIB::Map &m : Emap) { - for (const LIB::SetPiece &mdi : m.dom()) { - LIB::Exp off(LIB::MD_NAT(mdi.arity(), j)); - subE.emplaceBack(LIB::Map(LIB::SET_FACT.createSet(mdi), off)); - ++j; - } - } - } - return LIB::DSBG(V, Vmap, mapB, mapD, Emap, subE); + return LIB::DirectedSBG{V, Vmap, mapB, mapD, Emap}; } ExprBaseType ExprEvaluator::operator()(AST::ParenExpr v) const @@ -303,6 +279,8 @@ ExprBaseType ExprEvaluator::operator()(AST::ParenExpr v) const return boost::apply_visitor(*this, v.e()); } +} // namespace detail + } // namespace Eval } // namespace SBG diff --git a/eval/visitors/expr_evaluator.hpp b/eval/visitors/expr_evaluator.hpp index 648c165e..68895cd2 100755 --- a/eval/visitors/expr_evaluator.hpp +++ b/eval/visitors/expr_evaluator.hpp @@ -21,17 +21,23 @@ ******************************************************************************/ -#ifndef EXPR_EVALUATOR -#define EXPR_EVALUATOR +#ifndef SBGRAPH_EVAL_VISITORS_EXPR_EVALUATOR_HPP_ +#define SBGRAPH_EVAL_VISITORS_EXPR_EVALUATOR_HPP_ +#include "ast/expr.hpp" +#include "eval/base_type.hpp" #include "eval/eval_context.hpp" +#include + namespace SBG { namespace Eval { +namespace detail { + class ExprEvaluator : public boost::static_visitor { - public: +public: ExprEvaluator(EvalContext& eval_ctx); ExprBaseType operator()(AST::Natural v) const; @@ -52,12 +58,14 @@ class ExprEvaluator : public boost::static_visitor { ExprBaseType operator()(AST::DSBG v) const; ExprBaseType operator()(AST::ParenExpr v) const; - private: - EvalContext& eval_ctx_; +private: + EvalContext& _eval_context; }; +} // namespace detail + } // namespace Eval } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_VISITORS_EXPR_EVALUATOR_HPP_ diff --git a/eval/visitors/func_evaluator.cpp b/eval/visitors/func_evaluator.cpp index 62046ad9..c0896509 100755 --- a/eval/visitors/func_evaluator.cpp +++ b/eval/visitors/func_evaluator.cpp @@ -17,19 +17,33 @@ ******************************************************************************/ +#include "eval/visitors/func_evaluator.hpp" #include "algorithms/cc/cc.hpp" -#include "algorithms/cutvertex/cv_fact.hpp" -#include "algorithms/matching/matching_fact.hpp" +#include "algorithms/matching/matching.hpp" +#include "algorithms/mfvs/min_feedback_vertex_set.hpp" #include "algorithms/misc/causalization_builders.hpp" -#include "algorithms/scc/scc_fact.hpp" -#include "algorithms/toposort/ts_fact.hpp" -#include "eval/visitors/func_evaluator.hpp" +#include "algorithms/misc/causalization_json.hpp" +#include "algorithms/scc/scc.hpp" +#include "algorithms/sorting/topological/topological_sorting.hpp" +#include "eval/base_type.hpp" +#include "sbg/bipartite_sbg.hpp" +#include "sbg/expression.hpp" +#include "sbg/interval.hpp" +#include "sbg/map.hpp" +#include "sbg/multidim_inter.hpp" +#include "sbg/natural.hpp" +#include "sbg/rational.hpp" +#include "sbg/set.hpp" +#include "sbg/pw_map.hpp" #include "util/debug.hpp" +#include "util/defs.hpp" namespace SBG { namespace Eval { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // Built-in operators evaluators ----------------------------------------------- //////////////////////////////////////////////////////////////////////////////// @@ -39,14 +53,17 @@ ExprBaseType BuiltInOperators::oppositeEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "oppositeEvaluator: wrong number of arguments\n"); - auto opposite_evaluator = Overload { - [](LIB::NAT a) { return ExprBaseType(LIB::RATIONAL(a, -1)); }, - [](LIB::RATIONAL a) { return ExprBaseType(LIB::RATIONAL(-1)*a); }, - [](LIB::Set a) { return ExprBaseType(a.complement()); }, + auto opposite_evaluator = Util::Overload { + [](LIB::NAT a) + { + return ExprBaseType{LIB::RATIONAL{static_cast(a), -1}}; + }, + [](LIB::RATIONAL a) { return ExprBaseType{LIB::RATIONAL{-1}*a}; }, + [](LIB::Set a) { return ExprBaseType{a.complement()}; }, [](auto a) { Util::ERROR("oppositeEvaluator: wrong type argument ", a , " for - (opposite)\n"); - return ExprBaseType(LIB::RATIONAL(0)); + return ExprBaseType{LIB::RATIONAL{0}}; } }; return std::visit(opposite_evaluator, args[0]); @@ -57,9 +74,7 @@ ExprBaseType BuiltInOperators::cardinalEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "cardinalEvaluator: wrong number of arguments\n"); - const auto cardinal_evaluator = Overload { - [](LIB::Interval a) { return (LIB::NAT) a.cardinal(); }, - [](LIB::MultiDimInter a) { return (LIB::NAT) a.cardinal(); }, + const auto cardinal_evaluator = Util::Overload { [](LIB::Set a) { return (LIB::NAT) a.cardinal(); }, [](auto a) { Util::ERROR("cardinalEvaluator: wrong argument ", a, " for #\n"); @@ -74,12 +89,12 @@ ExprBaseType BuiltInOperators::complementEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "complementEvaluator: wrong number of arguments\n"); - const auto complement_evaluator = Overload { - [](LIB::Set a) { return ExprBaseType(a.complement()); }, + const auto complement_evaluator = Util::Overload { + [](LIB::Set a) { return ExprBaseType{a.complement()}; }, [](auto a) { Util::ERROR("complementEvaluator: wrong argument ", a , " for \' (complement)\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(complement_evaluator, args[0]); @@ -90,23 +105,23 @@ ExprBaseType BuiltInOperators::addEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "addEvaluator: wrong number of arguments\n"); - const auto add_evaluator = Overload { - [](LIB::NAT a, LIB::NAT b) { return ExprBaseType(a + b); }, - [](LIB::MD_NAT a, LIB::MD_NAT b) { return ExprBaseType(a + b); }, - [](LIB::RATIONAL a, LIB::RATIONAL b) { return ExprBaseType(a + b); }, + const auto add_evaluator = Util::Overload { + [](LIB::NAT a, LIB::NAT b) { return ExprBaseType{a + b}; }, + [](LIB::MD_NAT a, LIB::MD_NAT b) { return ExprBaseType{a + b}; }, + [](LIB::RATIONAL a, LIB::RATIONAL b) { return ExprBaseType{a + b}; }, [](LIB::NAT a, LIB::RATIONAL b) { - return ExprBaseType(LIB::RATIONAL(a) + b); + return ExprBaseType{LIB::RATIONAL{static_cast(a)} + b}; }, [](LIB::RATIONAL a, LIB::NAT b) { - return ExprBaseType(a + LIB::RATIONAL(b)); + return ExprBaseType{a + LIB::RATIONAL{static_cast(b)}}; }, - [](LIB::Exp a, LIB::Exp b) { return ExprBaseType(a + b); }, - [](LIB::Map a, LIB::Map b) { return ExprBaseType(a + b); }, - [](LIB::PWMap a, LIB::PWMap b) { return ExprBaseType(a + b); }, + [](LIB::Expression a, LIB::Expression b) { return ExprBaseType{a + b}; }, + [](LIB::Map a, LIB::Map b) { return ExprBaseType{a + b}; }, + [](LIB::PWMap a, LIB::PWMap b) { return ExprBaseType{a + b}; }, [](auto a, auto b) { Util::ERROR("addEvaluator: wrong arguments ", a, ", ", b , " for operator+\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(add_evaluator, args[0], args[1]); @@ -117,25 +132,27 @@ ExprBaseType BuiltInOperators::subEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "subEvaluator: wrong number of arguments\n"); - const auto sub_evaluator = Overload { + const auto sub_evaluator = Util::Overload { [](LIB::NAT a, LIB::NAT b) { - if (a > b) - return ExprBaseType(LIB::NAT(a - b)); - else - return ExprBaseType(LIB::RATIONAL(a) - LIB::RATIONAL(b)); + if (a > b) { + return ExprBaseType{LIB::NAT{a - b}}; + } else { + return ExprBaseType{LIB::RATIONAL{static_cast(a)} + - LIB::RATIONAL{static_cast(b)}}; + } }, - [](LIB::RATIONAL a, LIB::RATIONAL b) { return ExprBaseType(a - b); }, + [](LIB::RATIONAL a, LIB::RATIONAL b) { return ExprBaseType{a - b}; }, [](LIB::NAT a, LIB::RATIONAL b) { - return ExprBaseType(LIB::RATIONAL(a) - b); + return ExprBaseType{LIB::RATIONAL{static_cast(a)} - b}; }, [](LIB::RATIONAL a, LIB::NAT b) { - return ExprBaseType(a - LIB::RATIONAL(b)); + return ExprBaseType{a - LIB::RATIONAL{static_cast(b)}}; }, - [](LIB::Exp a, LIB::Exp b) { return ExprBaseType(a - b); }, + [](LIB::Expression a, LIB::Expression b) { return ExprBaseType{a - b}; }, [](auto a, auto b) { Util::ERROR("subEvaluator: wrong arguments ", a, ", ", b , " for operator-\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(sub_evaluator, args[0], args[1]); @@ -146,15 +163,24 @@ ExprBaseType BuiltInOperators::multEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "multEvaluator: wrong number of arguments\n"); - const auto mult_evaluator = Overload { - [](LIB::NAT a, LIB::NAT b) { return ExprBaseType(a*b); }, - [](LIB::RATIONAL a, LIB::RATIONAL b) { return ExprBaseType(a*b); }, - [](LIB::NAT a, LIB::RATIONAL b) { return ExprBaseType(LIB::RATIONAL(a)*b); }, - [](LIB::RATIONAL a, LIB::NAT b) { return ExprBaseType(a*LIB::RATIONAL(b)); }, + const auto mult_evaluator = Util::Overload { + [](LIB::NAT a, LIB::NAT b) + { + return ExprBaseType{LIB::RATIONAL{static_cast(a*b)}}; + }, + [](LIB::RATIONAL a, LIB::RATIONAL b) { return ExprBaseType{a*b}; }, + [](LIB::NAT a, LIB::RATIONAL b) + { + return ExprBaseType{LIB::RATIONAL{static_cast(a)}*b}; + }, + [](LIB::RATIONAL a, LIB::NAT b) + { + return ExprBaseType{a*LIB::RATIONAL{static_cast(b)}}; + }, [](auto a, auto b) { Util::ERROR("multEvaluator: wrong arguments ", a, ", ", b , " for operator*\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(mult_evaluator, args[0], args[1]); @@ -165,13 +191,11 @@ ExprBaseType BuiltInOperators::eqEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "eqEvaluator: wrong number of arguments\n"); - const auto eq_evaluator = Overload { + const auto eq_evaluator = Util::Overload { [](LIB::MD_NAT a, LIB::MD_NAT b) { return a == b; }, [](LIB::RATIONAL a, LIB::RATIONAL b) { return a == b; }, - [](LIB::Interval a, LIB::Interval b) { return a == b; }, - [](LIB::SetPiece a, LIB::SetPiece b) { return a == b; }, [](LIB::Set a, LIB::Set b) { return a == b; }, - [](LIB::Exp a, LIB::Exp b) { return a == b; }, + [](LIB::Expression a, LIB::Expression b) { return a == b; }, [](LIB::Map a, LIB::Map b) { return a == b; }, [](LIB::PWMap a, LIB::PWMap b) { return a == b; }, [](auto a, auto b) { @@ -188,11 +212,9 @@ ExprBaseType BuiltInOperators::lessEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "lessEvaluator: wrong number of arguments\n"); - const auto less_evaluator = Overload { + const auto less_evaluator = Util::Overload { [](LIB::MD_NAT a, LIB::MD_NAT b) { return a < b; }, [](LIB::RATIONAL a, LIB::RATIONAL b) { return a < b; }, - [](LIB::Interval a, LIB::Interval b) { return a < b; }, - [](LIB::SetPiece a, LIB::SetPiece b) { return a < b; }, [](auto a, auto b) { Util::ERROR("lessEvaluator: wrong arguments ", a, ", ", b , " for operator<\n"); @@ -207,18 +229,12 @@ ExprBaseType BuiltInOperators::capEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "capEvaluator: wrong number of arguments\n"); - const auto cap_evaluator = Overload{ - [](LIB::Interval a, LIB::Interval b) { - return ExprBaseType(a.intersection(b)); - }, - [](LIB::SetPiece a, LIB::SetPiece b) { - return ExprBaseType(a.intersection(b)); - }, - [](LIB::Set a, LIB::Set b) { return ExprBaseType(a.intersection(b)); }, + const auto cap_evaluator = Util::Overload{ + [](LIB::Set a, LIB::Set b) { return ExprBaseType{a.intersection(b)}; }, [](auto a, auto b) { Util::ERROR("capEvaluator: wrong arguments ", a, ", ", b , " for intersection\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(cap_evaluator, args[0], args[1]); @@ -229,12 +245,12 @@ ExprBaseType BuiltInOperators::cupEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "cupEvaluator: wrong number of arguments\n"); - const auto cup_evaluator = Overload{ - [](LIB::Set a, LIB::Set b) { return ExprBaseType(a.cup(b)); }, - [](auto a, auto b) { + const auto cup_evaluator = Util::Overload{ + [](LIB::Set a, LIB::Set b) { return ExprBaseType{a.cup(b)}; }, + [](auto a, auto b) { Util::ERROR("cupEvaluator: wrong arguments ", a, ", ", b , " for union\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(cup_evaluator, args[0], args[1]); @@ -245,12 +261,12 @@ ExprBaseType BuiltInOperators::diffEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "diffEvaluator: wrong number of arguments\n"); - const auto diff_evaluator = Overload{ - [](LIB::Set a, LIB::Set b) { return ExprBaseType(a.difference(b)); }, - [](auto a, auto b) { + const auto diff_evaluator = Util::Overload{ + [](LIB::Set a, LIB::Set b) { return ExprBaseType{a.difference(b)}; }, + [](auto a, auto b) { Util::ERROR("diffEvaluator: wrong arguments ", a, ", ", b , " for difference\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(diff_evaluator, args[0], args[1]); @@ -263,24 +279,27 @@ UnaryOpEvaluator::UnaryOpEvaluator() {} ExprBaseType UnaryOpEvaluator::evaluate(EBTList& evaluated_args, AST::UnOp op) { switch (op) { - case AST::UnOp::oppo: + case AST::UnOp::oppo: { return BuiltInOperators::oppositeEvaluator(evaluated_args); break; + } - case AST::UnOp::card: + case AST::UnOp::card: { return BuiltInOperators::cardinalEvaluator(evaluated_args); break; + } - case AST::UnOp::comp: + case AST::UnOp::comp: { return BuiltInOperators::complementEvaluator(evaluated_args); break; + } default: Util::ERROR("UnaryOpEvaluator: UnaryOp ", op, " unsupported\n"); - return ExprBaseType(); + return ExprBaseType{}; } - return ExprBaseType(); + return ExprBaseType{}; } BinOpEvaluator::BinOpEvaluator() {} @@ -288,44 +307,53 @@ BinOpEvaluator::BinOpEvaluator() {} ExprBaseType BinOpEvaluator::evaluate(EBTList& evaluated_args, AST::Op op) { switch (op) { - case AST::Op::add: + case AST::Op::add: { return BuiltInOperators::addEvaluator(evaluated_args); break; + } - case AST::Op::sub: + case AST::Op::sub: { return BuiltInOperators::subEvaluator(evaluated_args); break; + } - case AST::Op::mult: + case AST::Op::mult: { return BuiltInOperators::multEvaluator(evaluated_args); break; + } - case AST::Op::eq: + case AST::Op::eq: { return BuiltInOperators::eqEvaluator(evaluated_args); break; + } - case AST::Op::less: + case AST::Op::less: { return BuiltInOperators::lessEvaluator(evaluated_args); break; + } - case AST::Op::cap: + case AST::Op::cap: { return BuiltInOperators::capEvaluator(evaluated_args); break; + } - case AST::Op::cup: + case AST::Op::cup: { return BuiltInOperators::cupEvaluator(evaluated_args); break; + } - case AST::Op::diff: + case AST::Op::diff: { return BuiltInOperators::diffEvaluator(evaluated_args); break; + } - default: + default: { Util::ERROR("BinOpEvaluator: BinOp ", op, " unsupported\n"); - return ExprBaseType(); + return ExprBaseType{}; + } } - return ExprBaseType(); + return ExprBaseType{}; } //////////////////////////////////////////////////////////////////////////////// @@ -337,9 +365,7 @@ ExprBaseType BuiltInFunctions::emptyEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "emptyEvaluator: wrong number of arguments\n"); - const auto empty_evaluator = Overload { - [](LIB::Interval a) { return a.isEmpty(); }, - [](LIB::MultiDimInter a) { return a.isEmpty(); }, + const auto empty_evaluator = Util::Overload { [](LIB::Set a) { return a.isEmpty(); }, [](auto a) { Util::ERROR("emptyEvaluator: wrong argument ", a, " for isEmpty\n"); @@ -354,13 +380,11 @@ ExprBaseType BuiltInFunctions::minEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "minEvaluator: wrong number of arguments\n"); - const auto min_evaluator = Overload { - [](LIB::Interval a) { return LIB::MD_NAT(a.begin()); }, - [](LIB::MultiDimInter a) { return a.minElem(); }, + const auto min_evaluator = Util::Overload { [](LIB::Set a) { return a.minElem(); }, [](auto a) { Util::ERROR("minEvaluator: wrong argument ", a, " for minElem\n"); - return LIB::MD_NAT(); + return LIB::MD_NAT{}; } }; return std::visit(min_evaluator, args[0]); @@ -371,13 +395,11 @@ ExprBaseType BuiltInFunctions::maxEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "maxEvaluator: wrong number of arguments\n"); - const auto max_evaluator = Overload { - [](LIB::Interval a) { return LIB::MD_NAT(a.end()); }, - [](LIB::MultiDimInter a) { return a.maxElem(); }, + const auto max_evaluator = Util::Overload { [](LIB::Set a) { return a.maxElem(); }, [](auto a) { Util::ERROR("maxEvaluator: wrong argument ", a, " for maxElem\n"); - return LIB::MD_NAT(); + return LIB::MD_NAT{}; } }; return std::visit(max_evaluator, args[0]); @@ -388,12 +410,12 @@ ExprBaseType BuiltInFunctions::restrictEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "restrictEvaluator: wrong number of arguments\n"); - const auto restrict_evaluator = Overload { - [](LIB::PWMap a, LIB::Set b) { return ExprBaseType(a.restrict(b)); }, + const auto restrict_evaluator = Util::Overload { + [](LIB::PWMap a, LIB::Set b) { return ExprBaseType{a.restrict(b)}; }, [](auto a, auto b) { Util::ERROR("restrictEvaluator: wrong arguments ", a, ", ", b , " for restrict\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(restrict_evaluator, args[0], args[1]); @@ -404,15 +426,17 @@ ExprBaseType BuiltInFunctions::composeEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "composeEvaluator: wrong number of arguments\n"); - const auto compose_evaluator = Overload { - [](LIB::LExp a, LIB::LExp b) { return ExprBaseType(a.composition(b)); }, - [](LIB::Exp a, LIB::Exp b) { return ExprBaseType(a.composition(b)); }, - [](LIB::Map a, LIB::Map b) { return ExprBaseType(a.composition(b)); }, - [](LIB::PWMap a, LIB::PWMap b) { return ExprBaseType(a.composition(b)); }, + const auto compose_evaluator = Util::Overload { + [](LIB::Expression a, LIB::Expression b) + { + return ExprBaseType{a.composition(b)}; + }, + [](LIB::Map a, LIB::Map b) { return ExprBaseType{a.composition(b)}; }, + [](LIB::PWMap a, LIB::PWMap b) { return ExprBaseType{a.composition(b)}; }, [](auto a, auto b) { Util::ERROR("composeEvaluator: wrong arguments ", a, ", ", b , " for compose\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(compose_evaluator, args[0], args[1]); @@ -423,14 +447,12 @@ ExprBaseType BuiltInFunctions::inverseEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "inverseEvaluator: wrong number of arguments\n"); - const auto inverse_evaluator = Overload { - [](LIB::LExp a) { return ExprBaseType(a.inverse()); }, - [](LIB::Exp a) { return ExprBaseType(a.inverse()); }, - [](LIB::Map a) { return ExprBaseType(a.minInv()); }, - [](LIB::PWMap a) { return ExprBaseType(a.inverse()); }, + const auto inverse_evaluator = Util::Overload { + [](LIB::Expression a) { return ExprBaseType{a.inverse()}; }, + [](LIB::PWMap a) { return ExprBaseType{a.inverse()}; }, [](auto a) { Util::ERROR("inverseEvaluator: wrong arguments ", a, " for inverse\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(inverse_evaluator, args[0]); @@ -439,24 +461,24 @@ ExprBaseType BuiltInFunctions::inverseEvaluator(const EBTList& args) ExprBaseType BuiltInFunctions::imageEvaluator(const EBTList& args) { if (args.size() == 1) { - const auto image_evaluator = Overload { - [](LIB::Map a) { return ExprBaseType(a.image()); }, - [](LIB::PWMap a) { return ExprBaseType(a.image()); }, + const auto image_evaluator = Util::Overload { + [](LIB::Map a) { return ExprBaseType{a.image()}; }, + [](LIB::PWMap a) { return ExprBaseType{a.image()}; }, [](auto a) { Util::ERROR("imageEvaluator: wrong argument ", a, " for image\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(image_evaluator, args[0]); } else if (args.size() == 2) { - const auto image2_evaluator = Overload { - [](LIB::Set a, LIB::Map b) { return ExprBaseType(b.image(a)); }, - [](LIB::Set a, LIB::PWMap b) { return ExprBaseType(b.image(a)); }, + const auto image2_evaluator = Util::Overload { + [](LIB::Set a, LIB::Map b) { return ExprBaseType{b.image(a)}; }, + [](LIB::Set a, LIB::PWMap b) { return ExprBaseType{b.image(a)}; }, [](auto a, auto b) { Util::ERROR("imageEvaluator: wrong arguments ", a, ", ", b , " for image\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(image2_evaluator, args[0], args[1]); @@ -464,7 +486,7 @@ ExprBaseType BuiltInFunctions::imageEvaluator(const EBTList& args) Util::ERROR_UNLESS("imageEvaluator: wrong number of arguments\n"); - return ExprBaseType(); + return ExprBaseType{}; } ExprBaseType BuiltInFunctions::preImageEvaluator(const EBTList& args) @@ -472,13 +494,13 @@ ExprBaseType BuiltInFunctions::preImageEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "preImageEvaluator: wrong number of arguments\n"); - const auto pre_image_evaluator = Overload { - [](LIB::Set a, LIB::Map b) { return ExprBaseType(b.preImage(a)); }, - [](LIB::Set a, LIB::PWMap b) { return ExprBaseType(b.preImage(a)); }, + const auto pre_image_evaluator = Util::Overload { + [](LIB::Set a, LIB::Map b) { return ExprBaseType{b.preImage(a)}; }, + [](LIB::Set a, LIB::PWMap b) { return ExprBaseType{b.preImage(a)}; }, [](auto a, auto b) { Util::ERROR("preImageEvaluator: wrong arguments ", a, ", ", b , " for pre-image2\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(pre_image_evaluator, args[0], args[1]); @@ -489,11 +511,11 @@ ExprBaseType BuiltInFunctions::domEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "domEvaluator: wrong number of arguments\n"); - const auto dom_evaluator = Overload { - [](LIB::PWMap a) { return ExprBaseType(a.dom()); }, + const auto dom_evaluator = Util::Overload { + [](LIB::PWMap a) { return ExprBaseType{a.domain()}; }, [](auto a) { Util::ERROR("domEvaluator: wrong arguments ", a, "for dom\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(dom_evaluator, args[0]); @@ -504,74 +526,44 @@ ExprBaseType BuiltInFunctions::combineEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "combineEvaluator: wrong number of arguments\n"); - const auto combine_evaluator = Overload { - [](LIB::PWMap a, LIB::PWMap b) { return ExprBaseType(a.combine(b)); }, + const auto combine_evaluator = Util::Overload { + [](LIB::PWMap a, LIB::PWMap b) { return ExprBaseType{a.combine(b)}; }, [](auto a, auto b) { Util::ERROR("combineEvaluator: wrong arguments ", a, ", ", b , " for combine\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(combine_evaluator, args[0], args[1]); } -ExprBaseType BuiltInFunctions::firstInvEvaluator(const EBTList& args) -{ - Util::ERROR_UNLESS(args.size() == 1 - , "firstInvEvaluator: wrong number of arguments\n"); - - const auto first_inv_evaluator = Overload { - [](LIB::PWMap a) { return ExprBaseType(a.firstInv()); }, - [](auto a) { - Util::ERROR("firstInvEvaluator: wrong argument ", a, " for firstInv\n"); - return ExprBaseType(); - } - }; - return std::visit(first_inv_evaluator, args[0]); -} - ExprBaseType BuiltInFunctions::minMapEvaluator(const EBTList& args) { Util::ERROR_UNLESS(args.size() == 2 , "minMapEvaluator: wrong number of arguments\n"); - const auto min_map_evaluator = Overload { - [](LIB::PWMap a, LIB::PWMap b) { return ExprBaseType(a.minMap(b)); }, + const auto min_map_evaluator = Util::Overload { + [](LIB::PWMap a, LIB::PWMap b) { return ExprBaseType{a.min(b)}; }, [](auto a, auto b) { Util::ERROR("minMapEvaluator: wrong arguments ", a, ", ", b , " for minMap\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(min_map_evaluator, args[0], args[1]); } - -ExprBaseType BuiltInFunctions::reduceEvaluator(const EBTList& args) -{ - Util::ERROR_UNLESS(args.size() == 1 - , "reduceEvaluator: wrong number of arguments\n"); - const auto reduce_evaluator = Overload { - [](LIB::PWMap a) { return ExprBaseType(a.reduce()); }, - [](auto a) { - Util::ERROR("reduceEvaluator: wrong argument ", a, " for reduce\n"); - return ExprBaseType(); - } - }; - return std::visit(reduce_evaluator, args[0]); -} - ExprBaseType BuiltInFunctions::minAdjEvaluator(const EBTList& args) { Util::ERROR_UNLESS(args.size() == 2 , "minAdjEvaluator: wrong number of arguments\n"); - const auto min_adj_evaluator = Overload { - [](LIB::PWMap a, LIB::PWMap b) { return ExprBaseType(a.minAdjMap(b)); }, + const auto min_adj_evaluator = Util::Overload { + [](LIB::PWMap a, LIB::PWMap b) { return ExprBaseType{a.minAdj(b)}; }, [](auto a, auto b) { Util::ERROR("minAdjEvaluator: wrong arguments ", a, ", ", b , " for minAdj\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(min_adj_evaluator, args[0], args[1]); @@ -582,15 +574,31 @@ ExprBaseType BuiltInFunctions::mapInfEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "mapInfEvaluator: wrong number of arguments\n"); - const auto inf_evaluator = Overload { - [](LIB::PWMap a) { return ExprBaseType(a.mapInf()); }, + const auto inf_evaluator = Util::Overload { + [](LIB::PWMap a) { return ExprBaseType{a.mapInf()}; }, [](auto a) { Util::ERROR("mapInfEvaluator: wrong argument ", a, " for mapInf\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(inf_evaluator, args[0]); } + +ExprBaseType BuiltInFunctions::imageMultEvaluator(const EBTList& args) +{ + Util::ERROR_UNLESS(args.size() == 1 + , "imageMultEvaluator: wrong number of arguments\n"); + + const auto img_mult_evaluator = Util::Overload { + [](LIB::PWMap a) { return ExprBaseType{a.imageMultiplicity()}; }, + [](auto a) { + Util::ERROR("imageMultEvaluator: wrong argument ", a + , " for imageMultiplicity\n"); + return ExprBaseType{}; + } + }; + return std::visit(img_mult_evaluator, args[0]); +} // Algorithms evaluators ------------------------------------------------------ @@ -599,11 +607,11 @@ ExprBaseType BuiltInFunctions::connectedEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "connectedEvaluator: wrong number of arguments\n"); - const auto connected_evaluator = Overload { - [](LIB::SBG a) { return ExprBaseType(connectedComponents(a)); }, + const auto connected_evaluator = Util::Overload { + [](LIB::SBG a) { return ExprBaseType{connectedComponents(a)}; }, [](auto a) { Util::ERROR("connectedEvaluator: wrong argument ", a, " for CC\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(connected_evaluator, args[0]); @@ -614,18 +622,18 @@ ExprBaseType BuiltInFunctions::matchingEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "matchingEvaluator: wrong number of arguments\n"); - LIB::Matching match_impl = LIB::MATCH_FACT.createMatchAlgorithm(); - const auto matching_evaluator = Overload { + LIB::Matching match_impl; + const auto matching_evaluator = Util::Overload { [&match_impl](LIB::BipartiteSBG a, LIB::NAT b) { - return ExprBaseType(match_impl.calculate(a.copy(b))); + return ExprBaseType{match_impl.calculate(copy(b, a))}; }, [&match_impl](LIB::BipartiteSBG a, LIB::MD_NAT b) { - return ExprBaseType(match_impl.calculate(a.copy(b[0]))); + return ExprBaseType{match_impl.calculate(copy(b[0], a))}; }, [](auto a, auto b) { Util::ERROR("matchingEvaluator: wrong arguments ", a, ", ", b , " for matching\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(matching_evaluator, args[0], args[1]); @@ -636,117 +644,116 @@ ExprBaseType BuiltInFunctions::sccEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "sccEvaluator: wrong number of arguments\n"); - LIB::SCC scc_impl = LIB::SCC_FACT.createSCCAlgorithm(); - const auto scc_evaluator = Overload { - [&scc_impl](LIB::DSBG a) { - return ExprBaseType(scc_impl.calculate(a).rmap()); + LIB::SCC scc_impl; + const auto scc_evaluator = Util::Overload { + [&scc_impl](LIB::DirectedSBG a) { + return ExprBaseType{scc_impl.calculate(a).rmap()}; }, [](auto a) { Util::ERROR("sccEvaluator: wrong argument ", a, " for scc\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(scc_evaluator, args[0]); } -ExprBaseType BuiltInFunctions::topoSortEvaluator(const EBTList& args) +ExprBaseType BuiltInFunctions::matchSCCEvaluator(const EBTList& args) +{ + Util::ERROR_UNLESS(args.size() == 2 + , "matchSCCEvaluator: wrong number of arguments"); + + const ExprBaseType match_base_type = matchingEvaluator(args); + + const LIB::MatchData match_result = std::get(match_base_type); + LIB::DirectedSBG dsbg = misc::buildLoopDetectionSBG(match_result); + LIB::SCC scc_impl; + LIB::SCCData scc_result = scc_impl.calculate(dsbg); + + return ExprBaseType{scc_result.rmap()}; +} + +ExprBaseType BuiltInFunctions::mfvsEvaluator(const EBTList& args) { Util::ERROR_UNLESS(args.size() == 1 - , "topoSortEvaluator: wrong number of arguments\n"); + , "mfvsEvaluator: wrong number of arguments\n"); - LIB::TopoSort ts_impl = LIB::TS_FACT.createTSAlgorithm(); - const auto ts_evaluator = Overload { - [&ts_impl](LIB::DSBG a) { - return ExprBaseType(ts_impl.calculate(a)); + LIB::MinFeedbackVertexSet mfvs_impl; + const auto mfvs_evaluator = Util::Overload { + [&mfvs_impl](LIB::DirectedSBG a) { + return ExprBaseType{mfvs_impl.calculate(a)}; }, [](auto a) { - Util::ERROR("topoSortEvaluator: wrong argument ", a, " for sort\n"); - return ExprBaseType(); + Util::ERROR("mfvsEvaluator: wrong type of argument ", a + , " for MFVS algorithm\n"); + return ExprBaseType{}; } }; - return std::visit(ts_evaluator, args[0]); + return std::visit(mfvs_evaluator, args[0]); +} + +ExprBaseType BuiltInFunctions::matchSCCMFVSEvaluator(const EBTList& args) +{ + Util::ERROR_UNLESS(args.size() == 2 + , "matchSCCMFVSEvaluator: wrong number of arguments"); + + const ExprBaseType match_base_type = matchingEvaluator(args); + + const LIB::MatchData match_result = std::get(match_base_type); + LIB::DirectedSBG dsbg = misc::buildLoopDetectionSBG(match_result); + LIB::SCC scc_impl; + LIB::SCCData scc_result = scc_impl.calculate(dsbg); + + dsbg = misc::buildTearingSBG(scc_result); + LIB::MinFeedbackVertexSet mfvs_impl; + return ExprBaseType{mfvs_impl.calculate(dsbg)}; } -ExprBaseType BuiltInFunctions::cutVertexEvaluator(const EBTList& args) +ExprBaseType BuiltInFunctions::topoSortEvaluator(const EBTList& args) { Util::ERROR_UNLESS(args.size() == 1 - , "cutVertexEvaluator: wrong number of arguments\n"); + , "topoSortEvaluator: wrong number of arguments\n"); - LIB::CutVertex cv_impl = LIB::CV_FACT.createCVAlgorithm(); - const auto cv_evaluator = Overload { - [&cv_impl](LIB::DSBG a) { - return ExprBaseType(cv_impl.calculate(a)); + LIB::TopologicalSorting ts_impl; + const auto ts_evaluator = Util::Overload { + [&ts_impl](LIB::DirectedSBG a) { + return ExprBaseType{ts_impl.calculate(a, SBG::LIB::PWMap{})}; }, [](auto a) { Util::ERROR("topoSortEvaluator: wrong argument ", a, " for sort\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; - return std::visit(cv_evaluator, args[0]); + return std::visit(ts_evaluator, args[0]); } -ExprBaseType BuiltInFunctions::matchSCCEvaluator(const EBTList& args) +ExprBaseType BuiltInFunctions::causalizationEvaluator(const EBTList& args) { Util::ERROR_UNLESS(args.size() == 2 - , "matchSCCEvaluator: wrong number of arguments"); + , "causalizationEvaluator: wrong number of arguments"); - LIB::Matching match_impl = LIB::MATCH_FACT.createMatchAlgorithm(); - LIB::SCC scc_impl = LIB::SCC_FACT.createSCCAlgorithm(); - const auto match_scc_evaluator = Overload { - [&match_impl, &scc_impl](LIB::BipartiteSBG a, LIB::NAT b) { - LIB::MatchData match_result = match_impl.calculate(a.copy(b)); - LIB::DSBG dsbg = MISC::buildSCCFromMatching(match_result); - return ExprBaseType(scc_impl.calculate(dsbg).rmap()); - }, - [&match_impl, &scc_impl](LIB::BipartiteSBG a, LIB::MD_NAT b) { - LIB::MatchData match_result = match_impl.calculate(a.copy(b[0])); - LIB::DSBG dsbg = MISC::buildSCCFromMatching(match_result); - return ExprBaseType(scc_impl.calculate(dsbg).rmap()); - }, - [](auto a, auto b) { - Util::ERROR("match_scc_evaluator: wrong arguments ", a, ", ", b - , " for matchSCC\n"); - return ExprBaseType(); - } - }; + const ExprBaseType match_base_type = matchingEvaluator(args); - return std::visit(match_scc_evaluator, args[0], args[1]); -} + const LIB::MatchData match_result = std::get(match_base_type); + LIB::DirectedSBG dsbg = misc::buildLoopDetectionSBG(match_result); + LIB::SCC scc_impl; + LIB::SCCData scc_result = scc_impl.calculate(dsbg); -/* -ExprBaseType BuiltInFunctions::matchSCCTSEvaluator(const EBTList& args) -{ - const auto match_scc_ts_evaluator = Overload { - [](LIB::SBG a, LIB::NAT b, bool c) { - LIB::BFSMatching match(a.copy(b), c); - LIB::Set match_res = match.calculate().matched_edges(); - LIB::SCC scc(MISC::buildSCCFromMatching(match), c); - LIB::PWMap scc_res = scc.calculate(); - LIB::DSBG ts_dsbg = MISC::buildSortFromSCC(scc, scc_res); - LIB::TopoSort ts = LIB::MinVertexTSAF().createTSAlgorithm(ts_dsbg); - LIB::PWMap ts_res = ts.calculate(); - MISC::buildJson(match_res, scc_res, ts_res); - return ExprBaseType(ts_res); - }, - [](LIB::SBG a, LIB::MD_NAT b, bool c) { - LIB::BFSMatching match(a.copy(b[0]), c); - LIB::Set match_res = match.calculate().matched_edges(); - LIB::SCC scc(MISC::buildSCCFromMatching(match), c); - LIB::PWMap scc_res = scc.calculate(); - LIB::DSBG ts_dsbg = MISC::buildSortFromSCC(scc, scc_res); - LIB::TopoSort ts = LIB::MinVertexTSAF().createTSAlgorithm(ts_dsbg); - LIB::PWMap ts_res = ts.calculate(); - MISC::buildJson(match_res, scc_res, ts_res); - return ExprBaseType(ts_res); - }, - [](auto a, auto b, auto c) { - Util::ERROR("match_scc_ts_evaluator: wrong arguments ", a, ", ", b - , " for matchSCCTS\n"); - return ExprBaseType(); - } - }; + dsbg = misc::buildTearingSBG(scc_result); + LIB::MinFeedbackVertexSet mfvs_impl; + LIB::Set mfvs_result = mfvs_impl.calculate(dsbg); + + dsbg = misc::buildVerticalSortingSBG(scc_result, mfvs_result); + LIB::TopologicalSorting ts_impl; + LIB::PWMap ts_result = ts_impl.calculate(dsbg, scc_result.rmap()); + + misc::CausalizationResult causalized{match_result.M(), scc_result.rmap() + , mfvs_result, ts_result}; + misc::toJSON(causalized); + + return ExprBaseType{ts_result}; } -*/ + +} // namespace detail } // namespace Eval diff --git a/eval/visitors/func_evaluator.hpp b/eval/visitors/func_evaluator.hpp index 440a2080..d3967e6c 100755 --- a/eval/visitors/func_evaluator.hpp +++ b/eval/visitors/func_evaluator.hpp @@ -24,42 +24,24 @@ ******************************************************************************/ -#ifndef FUNC_EVALUATOR -#define FUNC_EVALUATOR +#ifndef SBGRAPH_EVAL_VISITORS_FUNC_EVALUATOR_HPP_ +#define SBGRAPH_EVAL_VISITORS_FUNC_EVALUATOR_HPP_ -#include "algorithms/cutvertex/cut_vertex.hpp" -#include "algorithms/matching/matching.hpp" -#include "algorithms/scc/scc.hpp" -#include "algorithms/toposort/topo_sort.hpp" +#include "ast/expr.hpp" #include "eval/base_type.hpp" namespace SBG { namespace Eval { -//////////////////////////////////////////////////////////////////////////////// -// Overload pattern ------------------------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -/** - * @brief Provides in-place lambdas for visitation for the different - * operations. These are needed because different structures share the same - * functions (for example, isEmpty can be applied to intervals, sets, etc.). - */ - -template class Overload : Ts... { - public: - using Ts::operator()...; - Overload(Ts... ts) : Ts(ts)... {}; -}; -template Overload(Ts...) -> Overload; +namespace detail { //////////////////////////////////////////////////////////////////////////////// // Built-in Operators ---------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// class BuiltInOperators { - public: +public: static ExprBaseType oppositeEvaluator(const EBTList& args); static ExprBaseType cardinalEvaluator(const EBTList& args); static ExprBaseType complementEvaluator(const EBTList& args); @@ -74,14 +56,14 @@ class BuiltInOperators { }; class UnaryOpEvaluator { - public: +public: UnaryOpEvaluator(); ExprBaseType evaluate(EBTList& evaluated_args, AST::UnOp op); }; class BinOpEvaluator { - public: +public: BinOpEvaluator(); ExprBaseType evaluate(EBTList& evaluated_args, AST::Op op); @@ -92,7 +74,7 @@ class BinOpEvaluator { //////////////////////////////////////////////////////////////////////////////// class BuiltInFunctions { - public: +public: static ExprBaseType emptyEvaluator(const EBTList& args); static ExprBaseType minEvaluator(const EBTList& args); static ExprBaseType maxEvaluator(const EBTList& args); @@ -108,16 +90,21 @@ class BuiltInFunctions { static ExprBaseType reduceEvaluator(const EBTList& args); static ExprBaseType minAdjEvaluator(const EBTList& args); static ExprBaseType mapInfEvaluator(const EBTList& args); + static ExprBaseType imageMultEvaluator(const EBTList& args); static ExprBaseType connectedEvaluator(const EBTList& args); static ExprBaseType matchingEvaluator(const EBTList& args); static ExprBaseType sccEvaluator(const EBTList& args); - static ExprBaseType topoSortEvaluator(const EBTList& args); - static ExprBaseType cutVertexEvaluator(const EBTList& args); static ExprBaseType matchSCCEvaluator(const EBTList& args); + static ExprBaseType mfvsEvaluator(const EBTList& args); + static ExprBaseType matchSCCMFVSEvaluator(const EBTList& args); + static ExprBaseType topoSortEvaluator(const EBTList& args); + static ExprBaseType causalizationEvaluator(const EBTList& args); }; +} // namespace detail + } // namespace Eval } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_VISITORS_FUNC_EVALUTOR_HPP_ diff --git a/eval/visitors/int_evaluator.cpp b/eval/visitors/int_evaluator.cpp index 7e08ad74..dd4db119 100755 --- a/eval/visitors/int_evaluator.cpp +++ b/eval/visitors/int_evaluator.cpp @@ -18,20 +18,27 @@ ******************************************************************************/ #include "eval/visitors/int_evaluator.hpp" +#include "util/debug.hpp" + +#include namespace SBG { namespace Eval { -IntEvaluator::IntEvaluator() : venv_() {} -IntEvaluator::IntEvaluator(VarEnv &venv) : venv_(venv) {} +namespace detail { + +IntEvaluator::IntEvaluator() : _venv() {} + +IntEvaluator::IntEvaluator(VarEnv &venv) : _venv(venv) {} LIB::INT IntEvaluator::operator()(AST::Natural v) const { return (LIB::INT) v; } LIB::INT IntEvaluator::operator()(AST::Rational v) const { - if (boost::apply_visitor(*this, v.den()) == 1) + if (boost::apply_visitor(*this, v.den()) == 1) { return boost::apply_visitor(*this, v.num()); + } Util::ERROR("IntEvaluator: trying to evaluate Rational ", v, "\n"); return 0; @@ -39,16 +46,15 @@ LIB::INT IntEvaluator::operator()(AST::Rational v) const LIB::INT IntEvaluator::operator()(AST::Name v) const { - auto var_definition = venv_.find(v); - if (var_definition != venv_.end()) { + auto var_definition = _venv.find(v); + if (var_definition != _venv.end()) { ExprBaseType value = var_definition->second; - if (std::holds_alternative(value)) - return (LIB::INT)(std::get(value)); - else if (std::holds_alternative(value)) { + if (std::holds_alternative(value)) { + return static_cast(std::get(value)); + } else if (std::holds_alternative(value)) { LIB::MD_NAT x = std::get(value); - return (LIB::INT)(x[0]); - } - else if (std::holds_alternative(value)) { + return static_cast(x[0]); + } else if (std::holds_alternative(value)) { LIB::RATIONAL x = std::get(value); return x.toInt(); } @@ -62,12 +68,14 @@ LIB::INT IntEvaluator::operator()(AST::UnaryOp v) const { LIB::INT x = boost::apply_visitor(*this, v.expr()); switch (v.op()) { - case AST::UnOp::oppo: + case AST::UnOp::oppo: { return -x; + } - default: + default: { Util::ERROR("IntEvaluator: BinOp ", v.op(), " unsupported\n"); return 0; + } } } @@ -76,21 +84,26 @@ LIB::INT IntEvaluator::operator()(AST::BinOp v) const LIB::INT l = boost::apply_visitor(*this, v.left()); LIB::INT r = boost::apply_visitor(*this, v.right()); switch (v.op()) { - case AST::Op::add: + case AST::Op::add: { return l + r; + } - case AST::Op::sub: + case AST::Op::sub: { return l - r; + } - case AST::Op::mult: + case AST::Op::mult: { return l * r; + } - case AST::Op::expo: + case AST::Op::expo: { return pow(l, r); + } - default: + default: { Util::ERROR("IntEvaluator: BinOp ", v.op(), " unsupported\n"); return 0; + } } } @@ -156,7 +169,7 @@ LIB::INT IntEvaluator::operator()(AST::BipartiteSBG v) const LIB::INT IntEvaluator::operator()(AST::DSBG v) const { - Util::ERROR("IntEvaluator: trying to evaluate DSBG ", v, "\n"); + Util::ERROR("IntEvaluator: trying to evaluate DirectedSBG ", v, "\n"); return 0; } @@ -165,6 +178,8 @@ LIB::INT IntEvaluator::operator()(AST::ParenExpr v) const return boost::apply_visitor(*this, v.e()); } +} // namespace detail + } // namespace Eval } // namespace SBG diff --git a/eval/visitors/int_evaluator.hpp b/eval/visitors/int_evaluator.hpp index f533b231..98d3e08b 100755 --- a/eval/visitors/int_evaluator.hpp +++ b/eval/visitors/int_evaluator.hpp @@ -21,19 +21,25 @@ ******************************************************************************/ -#ifndef INT_EVALUATOR -#define INT_EVALUATOR +#ifndef SBGRAPH_EVAL_VISITORS_INT_EVALUATOR_HPP_ +#define SBGRAPH_EVAL_VISITORS_INT_EVALUATOR_HPP_ +#include "ast/expr.hpp" #include "eval/var_env.hpp" +#include "sbg/rational.hpp" + +#include "boost/variant.hpp" namespace SBG { namespace Eval { +namespace detail { + class IntEvaluator : public boost::static_visitor { - public: +public: IntEvaluator(); - IntEvaluator(VarEnv &venv); + IntEvaluator(VarEnv& venv); LIB::INT operator()(AST::Natural v) const; LIB::INT operator()(AST::Rational v) const; @@ -53,12 +59,14 @@ class IntEvaluator : public boost::static_visitor { LIB::INT operator()(AST::DSBG v) const; LIB::INT operator()(AST::ParenExpr v) const; - private: - mutable VarEnv venv_; +private: + mutable VarEnv _venv; }; +} // namespace detail + } // namespace Eval } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_VISITORS_INT_EVALUTOR_HPP_ diff --git a/eval/visitors/linear_expr_evaluator.cpp b/eval/visitors/linear_expr_evaluator.cpp index 2d1afe8c..8e6ab6bd 100755 --- a/eval/visitors/linear_expr_evaluator.cpp +++ b/eval/visitors/linear_expr_evaluator.cpp @@ -20,163 +20,181 @@ #include "eval/visitors/int_evaluator.hpp" #include "eval/visitors/linear_expr_evaluator.hpp" #include "eval/visitors/rational_evaluator.hpp" +#include "util/debug.hpp" namespace SBG { namespace Eval { -LinearExprEvaluator::LinearExprEvaluator(VarEnv &venv) : venv_(venv) {} +namespace detail { -LIB::LExp LinearExprEvaluator::operator()(AST::Natural v) const +LinearExprEvaluator::LinearExprEvaluator(VarEnv &venv) : _venv(venv) {} + +LIB::detail::LinearExpr LinearExprEvaluator::operator()(AST::Natural v) const { - return LIB::LExp(0, LIB::RATIONAL(v)); + return LIB::detail::LinearExpr{0, LIB::RATIONAL{static_cast(v)}}; } -LIB::LExp LinearExprEvaluator::operator()(AST::Rational v) const +LIB::detail::LinearExpr LinearExprEvaluator::operator()(AST::Rational v) const { - IntEvaluator visit_int(venv_); + IntEvaluator visit_int{_venv}; LIB::INT p = boost::apply_visitor(visit_int, v.num()); LIB::INT q = boost::apply_visitor(visit_int, v.den()); - return LIB::LExp(0, LIB::RATIONAL(p, q)); + return LIB::detail::LinearExpr{0, LIB::RATIONAL{p, q}}; } -LIB::LExp LinearExprEvaluator::operator()(AST::Name v) const +LIB::detail::LinearExpr LinearExprEvaluator::operator()(AST::Name v) const { - if (v == "x") - return LIB::LExp(1, 0); + if (v == "x") { + return LIB::detail::LinearExpr{1, 0}; + } - LIB::RATIONAL off = boost::apply_visitor(RationalEvaluator(venv_) - , AST::Expr(v)); - return LIB::LExp(0, off); + LIB::RATIONAL off = boost::apply_visitor(RationalEvaluator{_venv} + , AST::Expr{v}); + return LIB::detail::LinearExpr{0, off}; } -LIB::LExp LinearExprEvaluator::operator()(AST::UnaryOp v) const +LIB::detail::LinearExpr LinearExprEvaluator::operator()(AST::UnaryOp v) const { - LIB::LExp le = boost::apply_visitor(*this, v.expr()); + LIB::detail::LinearExpr le = boost::apply_visitor(*this, v.expr()); switch (v.op()) { - case AST::UnOp::oppo: - return LIB::LExp(-le.slope(), -le.offset()); - break; + case AST::UnOp::oppo: { + return LIB::detail::LinearExpr{-le.slope(), -le.offset()}; + } - default: - Util::ERROR("LinearExprEvaluator: UnaryOp ", v.op(), " is not arithmetic\n"); + default: { + Util::ERROR("LinearExprEvaluator: UnaryOp ", v.op() + , " is not arithmetic\n"); break; + } }; - return LIB::LExp(); + return LIB::detail::LinearExpr{}; } -LIB::LExp LinearExprEvaluator::operator()(AST::BinOp v) const +LIB::detail::LinearExpr LinearExprEvaluator::operator()(AST::BinOp v) const { - LIB::LExp vl = boost::apply_visitor(*this, v.left()); - LIB::LExp vr = boost::apply_visitor(*this, v.right()); + LIB::detail::LinearExpr vl = boost::apply_visitor(*this, v.left()); + LIB::detail::LinearExpr vr = boost::apply_visitor(*this, v.right()); switch (v.op()) { - case AST::Op::add: - return LIB::LExp(vl.slope() + vr.slope(), vl.offset() + vr.offset()); - break; - - case AST::Op::sub: - return LIB::LExp(vl.slope() - vr.slope(), vl.offset() - vr.offset()); - break; - - case AST::Op::mult: - if (vl.slope() == 0 && vr.slope() == 0) - return LIB::LExp(0, vr.offset()*vl.offset()); - - else if (vl.slope() == 0) - return LIB::LExp(vl.offset()*vr.slope(), vl.offset()*vr.offset()); - - else if (vr.slope() == 0) - return LIB::LExp(vl.slope()*vr.offset(), vl.offset()*vr.offset()); + case AST::Op::add: { + return LIB::detail::LinearExpr{vl.slope() + vr.slope() + , vl.offset() + vr.offset()}; + } + + case AST::Op::sub: { + return LIB::detail::LinearExpr{vl.slope() - vr.slope() + , vl.offset() - vr.offset()}; + } + + case AST::Op::mult: { + if (vl.slope() == 0 && vr.slope() == 0) { + return LIB::detail::LinearExpr{0, vr.offset()*vl.offset()}; + } else if (vl.slope() == 0) { + return LIB::detail::LinearExpr{vl.offset()*vr.slope() + , vl.offset()*vr.offset()}; + } else if (vr.slope() == 0) { + return LIB::detail::LinearExpr{vl.slope()*vr.offset() + , vl.offset()*vr.offset()}; + } Util::ERROR("LinearExprEvaluator: expression ", v, " is not linear\n"); break; + } - default: - Util::ERROR("LinearExprEvaluator: BinOp ", v.op(), " is not arithmetic\n"); + default: { + Util::ERROR("LinearExprEvaluator: BinOp ", v.op() + , " is not arithmetic\n"); break; + } }; - return LIB::LExp(); + return LIB::detail::LinearExpr{}; } -LIB::LExp LinearExprEvaluator::operator()(AST::Call v) const +LIB::detail::LinearExpr LinearExprEvaluator::operator()(AST::Call v) const { Util::ERROR("LinearExprEvaluator: trying to evaluate Call ", v, "\n"); - return LIB::LExp(); + return LIB::detail::LinearExpr{}; } -LIB::LExp LinearExprEvaluator::operator()(AST::Interval v) const +LIB::detail::LinearExpr LinearExprEvaluator::operator()(AST::Interval v) const { Util::ERROR("LinearExprEvaluator: trying to evaluate Interval ", v, "\n"); - return LIB::LExp(); + return LIB::detail::LinearExpr{}; } -LIB::LExp LinearExprEvaluator::operator()(AST::MultiDimInter v) const +LIB::detail::LinearExpr LinearExprEvaluator::operator()(AST::MultiDimInter v) + const { - Util::ERROR("LinearExprEvaluator: trying to evaluate MultiDimInter ", v, "\n"); - return LIB::LExp(); + Util::ERROR("LinearExprEvaluator: trying to evaluate MultiDimInter ", v + , "\n"); + return LIB::detail::LinearExpr{}; } -LIB::LExp LinearExprEvaluator::operator()(AST::Set v) const +LIB::detail::LinearExpr LinearExprEvaluator::operator()(AST::Set v) const { Util::ERROR("LinearExprEvaluator: trying to evaluate Set ", v, "\n"); - return LIB::LExp(); + return LIB::detail::LinearExpr{}; } -LIB::LExp LinearExprEvaluator::operator()(AST::LinearExp v) const +LIB::detail::LinearExpr LinearExprEvaluator::operator()(AST::LinearExp v) const { - RationalEvaluator visit_rat(venv_); + RationalEvaluator visit_rat{_venv}; AST::Expr m = v.slope(); AST::Expr h = v.offset(); - return LIB::LExp(boost::apply_visitor(visit_rat, m) - , boost::apply_visitor(visit_rat, h)); + return LIB::detail::LinearExpr{boost::apply_visitor(visit_rat, m) + , boost::apply_visitor(visit_rat, h)}; } -LIB::LExp LinearExprEvaluator::operator()(AST::MDLExp v) const +LIB::detail::LinearExpr LinearExprEvaluator::operator()(AST::MDLExp v) + const { Util::ERROR("LinearExprEvaluator: trying to evaluate MDLExp ", v, "\n"); - return LIB::LExp(); + return LIB::detail::LinearExpr{}; } -LIB::LExp LinearExprEvaluator::operator()(AST::LinearMap v) const +LIB::detail::LinearExpr LinearExprEvaluator::operator()(AST::LinearMap v) const { Util::ERROR("LinearExprEvaluator: trying to evaluate LinearMap ", v, "\n"); - return LIB::LExp(); + return LIB::detail::LinearExpr{}; } -LIB::LExp LinearExprEvaluator::operator()(AST::PWLMap v) const +LIB::detail::LinearExpr LinearExprEvaluator::operator()(AST::PWLMap v) const { Util::ERROR("LinearExprEvaluator: trying to evaluate PWLMap ", v, "\n"); - return LIB::LExp(); + return LIB::detail::LinearExpr{}; } -LIB::LExp LinearExprEvaluator::operator()(AST::SBG v) const +LIB::detail::LinearExpr LinearExprEvaluator::operator()(AST::SBG v) const { Util::ERROR("LinearExprEvaluator: trying to evaluate SBG ", v, "\n"); - return LIB::LExp(); + return LIB::detail::LinearExpr{}; } -LIB::LExp LinearExprEvaluator::operator()(AST::BipartiteSBG v) const +LIB::detail::LinearExpr LinearExprEvaluator::operator()(AST::BipartiteSBG v) + const { Util::ERROR("LinearExprEvaluator: trying to evaluate BipartiteSBG ", v, "\n"); - return LIB::LExp(); + return LIB::detail::LinearExpr{}; } -LIB::LExp LinearExprEvaluator::operator()(AST::DSBG v) const +LIB::detail::LinearExpr LinearExprEvaluator::operator()(AST::DSBG v) const { - Util::ERROR("LinearExprEvaluator: trying to evaluate DSBG ", v, "\n"); - return LIB::LExp(); + Util::ERROR("LinearExprEvaluator: trying to evaluate DirectedSBG ", v, "\n"); + return LIB::detail::LinearExpr{}; } -LIB::LExp LinearExprEvaluator::operator()(AST::ParenExpr v) const +LIB::detail::LinearExpr LinearExprEvaluator::operator()(AST::ParenExpr v) const { return boost::apply_visitor(*this, v.e()); } +} // namespace detail + } // namespace Eval } // namespace SBG diff --git a/eval/visitors/linear_expr_evaluator.hpp b/eval/visitors/linear_expr_evaluator.hpp index 4b44e9d0..ec3e5c43 100755 --- a/eval/visitors/linear_expr_evaluator.hpp +++ b/eval/visitors/linear_expr_evaluator.hpp @@ -21,44 +21,52 @@ ******************************************************************************/ -#ifndef LE_EVALUATOR -#define LE_EVALUATOR +#ifndef SBGRAPH_EVAL_VISITORS_LINEAR_EXPR_EVALUTOR_HPP_ +#define SBGRAPH_EVAL_VISITORS_LINEAR_EXPR_EVALUTOR_HPP_ +#include "ast/expr.hpp" #include "eval/var_env.hpp" -#include "sbg/lexp.hpp" +#include "sbg/linear_expr.hpp" + +#include "boost/variant.hpp" namespace SBG { namespace Eval { -class LinearExprEvaluator : public boost::static_visitor { - public: +namespace detail { + +class LinearExprEvaluator + : public boost::static_visitor { +public: LinearExprEvaluator(VarEnv &venv); - LIB::LExp operator()(AST::Natural v) const; - LIB::LExp operator()(AST::Rational v) const; - LIB::LExp operator()(AST::Name v) const; - LIB::LExp operator()(AST::UnaryOp v) const; - LIB::LExp operator()(AST::BinOp v) const; - LIB::LExp operator()(AST::Call v) const; - LIB::LExp operator()(AST::Interval v) const; - LIB::LExp operator()(AST::MultiDimInter v) const; - LIB::LExp operator()(AST::Set v) const; - LIB::LExp operator()(AST::LinearExp v) const; - LIB::LExp operator()(AST::MDLExp v) const; - LIB::LExp operator()(AST::LinearMap v) const; - LIB::LExp operator()(AST::PWLMap v) const; - LIB::LExp operator()(AST::SBG v) const; - LIB::LExp operator()(AST::BipartiteSBG v) const; - LIB::LExp operator()(AST::DSBG v) const; - LIB::LExp operator()(AST::ParenExpr v) const; - - private: - mutable VarEnv venv_; + LIB::detail::LinearExpr operator()(AST::Natural v) const; + LIB::detail::LinearExpr operator()(AST::Rational v) const; + LIB::detail::LinearExpr operator()(AST::Name v) const; + LIB::detail::LinearExpr operator()(AST::UnaryOp v) const; + LIB::detail::LinearExpr operator()(AST::BinOp v) const; + LIB::detail::LinearExpr operator()(AST::Call v) const; + LIB::detail::LinearExpr operator()(AST::Interval v) const; + LIB::detail::LinearExpr operator()(AST::MultiDimInter v) const; + LIB::detail::LinearExpr operator()(AST::Set v) const; + LIB::detail::LinearExpr operator()(AST::LinearExp v) const; + LIB::detail::LinearExpr operator()(AST::MDLExp v) const; + LIB::detail::LinearExpr operator()(AST::LinearMap v) const; + LIB::detail::LinearExpr operator()(AST::PWLMap v) const; + LIB::detail::LinearExpr operator()(AST::SBG v) const; + LIB::detail::LinearExpr operator()(AST::BipartiteSBG v) const; + LIB::detail::LinearExpr operator()(AST::DSBG v) const; + LIB::detail::LinearExpr operator()(AST::ParenExpr v) const; + +private: + mutable VarEnv _venv; }; +} // namespace detail + } // namespace Eval } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_VISITORS_LINEAR_EXPR_EVALUTOR_HPP_ diff --git a/eval/visitors/nat_evaluator.cpp b/eval/visitors/nat_evaluator.cpp index 3eb43322..ef4dea63 100755 --- a/eval/visitors/nat_evaluator.cpp +++ b/eval/visitors/nat_evaluator.cpp @@ -18,20 +18,27 @@ ******************************************************************************/ #include "eval/visitors/nat_evaluator.hpp" +#include "util/debug.hpp" + +#include namespace SBG { namespace Eval { -NatEvaluator::NatEvaluator() : venv_() {} -NatEvaluator::NatEvaluator(VarEnv &venv) : venv_(venv) {} +namespace detail { + +NatEvaluator::NatEvaluator() : _venv() {} + +NatEvaluator::NatEvaluator(VarEnv &venv) : _venv(venv) {} LIB::NAT NatEvaluator::operator()(AST::Natural v) const { return v; } LIB::NAT NatEvaluator::operator()(AST::Rational v) const { - if (boost::apply_visitor(*this, v.den()) == 1) + if (boost::apply_visitor(*this, v.den()) == 1) { return boost::apply_visitor(*this, v.num()); + } Util::ERROR("NatEvaluator: trying to evaluate Rational ", v, "\n"); return 0; @@ -39,21 +46,21 @@ LIB::NAT NatEvaluator::operator()(AST::Rational v) const LIB::NAT NatEvaluator::operator()(AST::Name v) const { - auto var_definition = venv_.find(v); - if (var_definition != venv_.end()) { + auto var_definition = _venv.find(v); + if (var_definition != _venv.end()) { ExprBaseType value = var_definition->second; - if (std::holds_alternative(value)) + if (std::holds_alternative(value)) { return std::get(value); - - else if (std::holds_alternative(value)) { + } else if (std::holds_alternative(value)) { LIB::MD_NAT x = std::get(value); - if (x.arity() == 1) + if (x.arity() == 1) { return x[0]; - } - - else - if (std::holds_alternative(value)) + } + } else { + if (std::holds_alternative(value)) { return std::get(value).toNat(); + } + } } Util::ERROR("NatEvaluator: variable ", v, " undefined\n"); @@ -71,21 +78,26 @@ LIB::NAT NatEvaluator::operator()(AST::BinOp v) const LIB::NAT l = boost::apply_visitor(*this, v.left()); LIB::NAT r = boost::apply_visitor(*this, v.right()); switch (v.op()) { - case AST::Op::add: + case AST::Op::add: { return l + r; + } - case AST::Op::sub: + case AST::Op::sub: { return l - r; + } - case AST::Op::mult: + case AST::Op::mult: { return l * r; + } - case AST::Op::expo: + case AST::Op::expo: { return pow(l, r); + } - default: + default: { Util::ERROR("NatEvaluator: BinOp ", v.op(), " unsupported\n"); return 0; + } } } @@ -151,7 +163,7 @@ LIB::NAT NatEvaluator::operator()(AST::BipartiteSBG v) const LIB::NAT NatEvaluator::operator()(AST::DSBG v) const { - Util::ERROR("NatEvaluator: trying to evaluate DSBG ", v, "\n"); + Util::ERROR("NatEvaluator: trying to evaluate DirectedSBG ", v, "\n"); return 0; } @@ -160,6 +172,8 @@ LIB::NAT NatEvaluator::operator()(AST::ParenExpr v) const return boost::apply_visitor(*this, v.e()); } +} // namespace detail + } // namespace Eval } // namespace SBG diff --git a/eval/visitors/nat_evaluator.hpp b/eval/visitors/nat_evaluator.hpp index 68690d0c..44bda79a 100755 --- a/eval/visitors/nat_evaluator.hpp +++ b/eval/visitors/nat_evaluator.hpp @@ -21,17 +21,23 @@ ******************************************************************************/ -#ifndef NAT_EVALUATOR -#define NAT_EVALUATOR +#ifndef SBGRAPH_EVAL_VISITORS_NAT_EVALUATOR_HPP_ +#define SBGRAPH_EVAL_VISITORS_NAT_EVALUATOR_HPP_ +#include "ast/expr.hpp" #include "eval/var_env.hpp" +#include "sbg/natural.hpp" + +#include "boost/variant.hpp" namespace SBG { namespace Eval { +namespace detail { + class NatEvaluator : public boost::static_visitor { - public: +public: NatEvaluator(); NatEvaluator(VarEnv &venv); @@ -53,12 +59,14 @@ class NatEvaluator : public boost::static_visitor { LIB::NAT operator()(AST::DSBG v) const; LIB::NAT operator()(AST::ParenExpr) const; - private: - mutable VarEnv venv_; +private: + mutable VarEnv _venv; }; +} // namespace detail + } // namespace Eval } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_VISITORS_NAT_EVALUTOR_HPP_ diff --git a/eval/visitors/program_evaluator.cpp b/eval/visitors/program_evaluator.cpp index 8f06102d..f84e485e 100755 --- a/eval/visitors/program_evaluator.cpp +++ b/eval/visitors/program_evaluator.cpp @@ -19,28 +19,32 @@ #include "eval/visitors/expr_evaluator.hpp" #include "eval/visitors/program_evaluator.hpp" +#include "eval/visitors/stm_evaluator.hpp" #include "util/logger.hpp" namespace SBG { namespace Eval { +namespace detail { + ProgramEvaluator::ProgramEvaluator() {} ProgramIO ProgramEvaluator::evaluate(AST::SBGProgram p) const { LIB::NAT dims = 1; - EvalContext eval_ctx; + EvalContext eval_context; AST::IsConfig cfg_visit; if (!p.stms().empty()) { AST::Statement first = p.stms()[0]; - if (boost::apply_visitor(cfg_visit, first)) - eval_ctx.setArity(boost::get(first).nmbr_dims()); + if (boost::apply_visitor(cfg_visit, first)) { + eval_context.setArity(boost::get(first).nmbr_dims()); + } } StmResultList stms; - StmEvaluator stm_visit(eval_ctx); + StmEvaluator stm_visit{eval_context}; for (AST::Statement s : p.stms()) { if (!boost::apply_visitor(cfg_visit, s)) { StmResult se = boost::apply_visitor(stm_visit, s); @@ -49,15 +53,17 @@ ProgramIO ProgramEvaluator::evaluate(AST::SBGProgram p) const } ExprResultList exprs; - ExprEvaluator eval_expr(eval_ctx); + ExprEvaluator eval_expr{eval_context}; for (AST::Expr e : p.exprs()) { ExprBaseType expr_res = boost::apply_visitor(eval_expr, e); - exprs.push_back(ExprResult(e, expr_res)); + exprs.emplace_back(e, expr_res); } - return ProgramIO(dims, stms, exprs); + return ProgramIO{dims, stms, exprs}; } +} // namespace detail + } // namespace Eval } // namespace SBG diff --git a/eval/visitors/program_evaluator.hpp b/eval/visitors/program_evaluator.hpp index 0653cc41..4b784482 100755 --- a/eval/visitors/program_evaluator.hpp +++ b/eval/visitors/program_evaluator.hpp @@ -24,27 +24,31 @@ ******************************************************************************/ -#ifndef PROGRAM_EVALUATOR -#define PROGRAM_EVALUATOR - -#include +#ifndef SBGRAPH_EVAL_VISITORS_PROGRAM_EVALUATOR_HPP_ +#define SBGRAPH_EVAL_VISITORS_PROGRAM_EVALUATOR_HPP_ #include "ast/sbg_program.hpp" -#include "eval/visitors/stm_evaluator.hpp" +#include "eval/pretty_print.hpp" + +#include namespace SBG { namespace Eval { +namespace detail { + class ProgramEvaluator { - public: +public: ProgramEvaluator(); ProgramIO evaluate(AST::SBGProgram p) const; }; +} // namespace detail + } // namespace Eval } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_VISITORS_PROGRAM_EVALUATOR_HPP_ diff --git a/eval/visitors/rational_evaluator.cpp b/eval/visitors/rational_evaluator.cpp index 64df39f8..b4ec02bf 100755 --- a/eval/visitors/rational_evaluator.cpp +++ b/eval/visitors/rational_evaluator.cpp @@ -19,62 +19,67 @@ #include "eval/visitors/int_evaluator.hpp" #include "eval/visitors/rational_evaluator.hpp" +#include "util/debug.hpp" namespace SBG { namespace Eval { -RationalEvaluator::RationalEvaluator() : venv_() {} -RationalEvaluator::RationalEvaluator(VarEnv &venv) : venv_(venv) {} +namespace detail { + +RationalEvaluator::RationalEvaluator() : _venv() {} + +RationalEvaluator::RationalEvaluator(VarEnv& venv) : _venv(venv) {} LIB::RATIONAL RationalEvaluator::operator()(AST::Natural v) const { - return LIB::RATIONAL(v, 1); + return LIB::RATIONAL{static_cast(v)}; } LIB::RATIONAL RationalEvaluator::operator()(AST::Rational v) const { - IntEvaluator visit_int(venv_); + IntEvaluator visit_int{_venv}; return LIB::RATIONAL(boost::apply_visitor(visit_int, v.num()) , boost::apply_visitor(visit_int, v.den())); } LIB::RATIONAL RationalEvaluator::operator()(AST::Name v) const { - auto var_definition = venv_.find(v); - if (var_definition != venv_.end()) { + auto var_definition = _venv.find(v); + if (var_definition != _venv.end()) { ExprBaseType value = var_definition->second; - if (std::holds_alternative(value)) + if (std::holds_alternative(value)) { return std::get(value); - else if (std::holds_alternative(value)) { + } else if (std::holds_alternative(value)) { LIB::MD_NAT x = std::get(value); - if (x.arity() == 1) - return LIB::RATIONAL(x[0]); - } - else if (std::holds_alternative(value)) - return LIB::RATIONAL(std::get(value)); - - else { + if (x.arity() == 1) { + return LIB::RATIONAL(static_cast(x[0])); + } + } else if (std::holds_alternative(value)) { + return LIB::RATIONAL{static_cast(std::get(value))}; + } else { Util::ERROR("RationalEvaluator: variable ", v, " is not rational\n"); - return LIB::RATIONAL(0, 1); + return 0; } } Util::ERROR("RationalEvaluator: variable ", v, " undefined\n"); - return LIB::RATIONAL(0, 1); + return 0; } LIB::RATIONAL RationalEvaluator::operator()(AST::UnaryOp v) const { - RationalEvaluator visit_rat(venv_); + RationalEvaluator visit_rat{_venv}; LIB::RATIONAL result = boost::apply_visitor(visit_rat, v.expr()); switch (v.op()) { - case AST::UnOp::oppo: + case AST::UnOp::oppo: { return -result; + } - default: + default: { Util::ERROR("RationalEvaluator: UnaryOp ", v.op(), " unsupported\n"); return 0; + } } Util::ERROR("RationalEvaluator: UnaryOp ", v.op(), " unsupported\n"); @@ -86,18 +91,22 @@ LIB::RATIONAL RationalEvaluator::operator()(AST::BinOp v) const LIB::RATIONAL l = boost::apply_visitor(*this, v.left()); LIB::RATIONAL r = boost::apply_visitor(*this, v.right()); switch (v.op()) { - case AST::Op::add: + case AST::Op::add: { return l + r; + } - case AST::Op::sub: + case AST::Op::sub: { return l - r; + } - case AST::Op::mult: + case AST::Op::mult: { return l * r; + } - default: + default: { Util::ERROR("RationalEvaluator: BinOp ", v.op(), " unsupported\n"); - return LIB::RATIONAL(0, 1); + return 0; + } } Util::ERROR("RationalEvaluator: BinOp ", v.op(), " unsupported\n"); @@ -107,67 +116,67 @@ LIB::RATIONAL RationalEvaluator::operator()(AST::BinOp v) const LIB::RATIONAL RationalEvaluator::operator()(AST::Call v) const { Util::ERROR("RationalEvaluator: trying to evaluate Call ", v, "\n"); - return LIB::RATIONAL(0, 1); + return 0; } LIB::RATIONAL RationalEvaluator::operator()(AST::Interval v) const { Util::ERROR("RationalEvaluator: trying to evaluate Interval ", v, "\n"); - return LIB::RATIONAL(0, 1); + return 0; } LIB::RATIONAL RationalEvaluator::operator()(AST::MultiDimInter v) const { Util::ERROR("RationalEvaluator: trying to evaluate MultiDimInter ", v, "\n"); - return LIB::RATIONAL(0, 1); + return 0; } LIB::RATIONAL RationalEvaluator::operator()(AST::Set v) const { Util::ERROR("RationalEvaluator: trying to evaluate Set ", v, "\n"); - return LIB::RATIONAL(0, 1); + return 0; } LIB::RATIONAL RationalEvaluator::operator()(AST::LinearExp v) const { Util::ERROR("RationalEvaluator: trying to evaluate LinearExp ", v, "\n"); - return LIB::RATIONAL(0, 1); + return 0; } LIB::RATIONAL RationalEvaluator::operator()(AST::MDLExp v) const { Util::ERROR("RationalEvaluator: trying to evaluate MDLExp ", v, "\n"); - return LIB::RATIONAL(0, 1); + return 0; } LIB::RATIONAL RationalEvaluator::operator()(AST::LinearMap v) const { Util::ERROR("RationalEvaluator: trying to evaluate LinearMap ", v, "\n"); - return LIB::RATIONAL(0, 1); + return 0; } LIB::RATIONAL RationalEvaluator::operator()(AST::PWLMap v) const { Util::ERROR("RationalEvaluator: trying to evaluate PWLMap ", v, "\n"); - return LIB::RATIONAL(0, 1); + return 0; } LIB::RATIONAL RationalEvaluator::operator()(AST::SBG v) const { Util::ERROR("RationalEvaluator: trying to evaluate SBG ", v, "\n"); - return LIB::RATIONAL(0, 1); + return 0; } LIB::RATIONAL RationalEvaluator::operator()(AST::BipartiteSBG v) const { Util::ERROR("RationalEvaluator: trying to evaluate BipartiteSBG ", v, "\n"); - return LIB::RATIONAL(0, 1); + return 0; } LIB::RATIONAL RationalEvaluator::operator()(AST::DSBG v) const { - Util::ERROR("RationalEvaluator: trying to evaluate DSBG ", v, "\n"); - return LIB::RATIONAL(0, 1); + Util::ERROR("RationalEvaluator: trying to evaluate DirectedSBG ", v, "\n"); + return 0; } LIB::RATIONAL RationalEvaluator::operator()(AST::ParenExpr v) const @@ -175,6 +184,8 @@ LIB::RATIONAL RationalEvaluator::operator()(AST::ParenExpr v) const return boost::apply_visitor(*this, v.e()); } +} // namespace detail + } // namespace Eval } // namespace SBG diff --git a/eval/visitors/rational_evaluator.hpp b/eval/visitors/rational_evaluator.hpp index aa2d2e19..e53c1793 100755 --- a/eval/visitors/rational_evaluator.hpp +++ b/eval/visitors/rational_evaluator.hpp @@ -21,18 +21,23 @@ ******************************************************************************/ -#ifndef RATIONAL_EVALUATOR -#define RATIONAL_EVALUATOR +#ifndef SBGRAPH_EVAL_VISITORS_RATIONAL_EVALUATOR_HPP_ +#define SBGRAPH_EVAL_VISITORS_RATIONAL_EVALUATOR_HPP_ +#include "ast/expr.hpp" #include "eval/var_env.hpp" #include "sbg/rational.hpp" +#include "boost/variant.hpp" + namespace SBG { namespace Eval { +namespace detail { + class RationalEvaluator : public boost::static_visitor { - public: +public: RationalEvaluator(); RationalEvaluator(VarEnv &venv); @@ -54,12 +59,14 @@ class RationalEvaluator : public boost::static_visitor { LIB::RATIONAL operator()(AST::DSBG v) const; LIB::RATIONAL operator()(AST::ParenExpr) const; - private: - mutable VarEnv venv_; +private: + mutable VarEnv _venv; }; +} // namespace detail + } // namespace Eval } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_VISITORS_RATIONAL_EVALUATOR_HPP_ diff --git a/eval/visitors/set_impl_visitor.cpp b/eval/visitors/set_impl_visitor.cpp index ff4fca68..80f82e27 100755 --- a/eval/visitors/set_impl_visitor.cpp +++ b/eval/visitors/set_impl_visitor.cpp @@ -26,11 +26,13 @@ namespace SBG { namespace Eval { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // Set Implementation single Expression Visitor -------------------------------- //////////////////////////////////////////////////////////////////////////////// -SetImplExprVisitor::SetImplExprVisitor(VarEnv& venv) : venv_(venv) {} +SetImplExprVisitor::SetImplExprVisitor(VarEnv& venv) : _venv(venv) {} int SetImplExprVisitor::operator()(AST::Natural v) const { return 2; } @@ -45,7 +47,6 @@ int SetImplExprVisitor::operator()(AST::UnaryOp v) const int SetImplExprVisitor::operator()(AST::BinOp v) const { - int impl = 2; int limpl = boost::apply_visitor(*this, v.left()); int rimpl = boost::apply_visitor(*this, v.right()); @@ -55,15 +56,16 @@ int SetImplExprVisitor::operator()(AST::BinOp v) const int SetImplExprVisitor::operator()(AST::Call v) const { int impl = 2; - for (const AST::Expr &e : v.args()) + for (const AST::Expr& e : v.args()) { impl = std::min(impl, boost::apply_visitor(*this, e)); + } return impl; } int SetImplExprVisitor::operator()(AST::Interval v) const { - NatEvaluator visit_nat(venv_); + NatEvaluator visit_nat{_venv}; return boost::apply_visitor(visit_nat, v.step()) == 1 ? 2 : 1; } @@ -71,11 +73,13 @@ int SetImplExprVisitor::operator()(AST::MultiDimInter v) const { int impl = 2; - if (v.intervals().size() > 1) + if (v.intervals().size() > 1) { return 1; + } - for (const AST::Expr &e : v.intervals()) + for (const AST::Expr& e : v.intervals()) { impl = std::min(impl, boost::apply_visitor(*this, e)); + } return impl; } @@ -83,15 +87,16 @@ int SetImplExprVisitor::operator()(AST::MultiDimInter v) const int SetImplExprVisitor::operator()(AST::Set v) const { int impl = 2; - for (const AST::Expr &e : v.pieces()) + for (const AST::Expr& e : v.pieces()) { impl = std::min(impl, boost::apply_visitor(*this, e)); + } return impl; } int SetImplExprVisitor::operator()(AST::LinearExp v) const { - RationalEvaluator visit_rat(venv_); + RationalEvaluator visit_rat{_venv}; LIB::RATIONAL r = boost::apply_visitor(visit_rat, v.slope()); return (r == 0 || r == 1) ? 2 : 1; @@ -100,8 +105,9 @@ int SetImplExprVisitor::operator()(AST::LinearExp v) const int SetImplExprVisitor::operator()(AST::MDLExp v) const { int impl = 2; - for (const AST::Expr &e : v.exps()) + for (const AST::Expr& e : v.exps()) { impl = std::min(impl, boost::apply_visitor(*this, e)); + } return impl; } @@ -117,8 +123,9 @@ int SetImplExprVisitor::operator()(AST::LinearMap v) const int SetImplExprVisitor::operator()(AST::PWLMap v) const { int impl = 2; - for (const AST::Expr &e : v.maps()) + for (const AST::Expr& e : v.maps()) { impl = std::min(impl, boost::apply_visitor(*this, e)); + } return impl; } @@ -169,6 +176,8 @@ int SetImplExprVisitor::operator()(AST::ParenExpr v) const return boost::apply_visitor(*this, v.e()); } +} // namespace detail + } // namespace Eval } // namespace SBG diff --git a/eval/visitors/set_impl_visitor.hpp b/eval/visitors/set_impl_visitor.hpp index d4d5359c..1a17e5e5 100755 --- a/eval/visitors/set_impl_visitor.hpp +++ b/eval/visitors/set_impl_visitor.hpp @@ -25,20 +25,20 @@ ******************************************************************************/ -#ifndef SET_IMPL_VISITOR -#define SET_IMPL_VISITOR - -#include - -#include +#ifndef SBGRAPH_EVAL_VISITORS_SET_IMPL_VISITOR_HPP_ +#define SBGRAPH_EVAL_VISITORS_SET_IMPL_VISITOR_HPP_ #include "ast/sbg_program.hpp" #include "eval/var_env.hpp" +#include + namespace SBG { namespace Eval { +namespace detail { + /** * @brief Single expression visitor to pick the optimal representation for * sets. The visitor will return an int value, each one representing a @@ -49,7 +49,7 @@ namespace Eval { * - 2: unidimensional ordered sets. */ class SetImplExprVisitor : public boost::static_visitor { - public: +public: SetImplExprVisitor(VarEnv& venv); int operator()(AST::Natural v) const; @@ -70,12 +70,14 @@ class SetImplExprVisitor : public boost::static_visitor { int operator()(AST::DSBG v) const; int operator()(AST::ParenExpr) const; - private: - VarEnv& venv_; +private: + VarEnv& _venv; }; +} // namespace detail + } // namespace Eval } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_VISITORS_SET_IMPL_VISITOR_HPP_ diff --git a/eval/visitors/stm_evaluator.cpp b/eval/visitors/stm_evaluator.cpp index 0ec8fb86..8442b34f 100755 --- a/eval/visitors/stm_evaluator.cpp +++ b/eval/visitors/stm_evaluator.cpp @@ -24,18 +24,20 @@ namespace SBG { namespace Eval { -StmEvaluator::StmEvaluator(EvalContext& eval_ctx) : eval_ctx_(eval_ctx) {} +namespace detail { -EvalContext& StmEvaluator::eval_ctx() const +StmEvaluator::StmEvaluator(EvalContext& eval_ctx) : _eval_context(eval_ctx) {} + +EvalContext& StmEvaluator::eval_context() const { - return eval_ctx_; + return _eval_context; } StmResult StmEvaluator::operator()(AST::Assign assgn) const { - ExprEvaluator eval_expr(eval_ctx_); + ExprEvaluator eval_expr(_eval_context); ExprBaseType e = boost::apply_visitor(eval_expr, assgn.r()); - eval_ctx_.insertVariable(assgn.l(), e); + _eval_context.insertVariable(assgn.l(), e); return StmResult(assgn.l(), e); } @@ -45,6 +47,8 @@ StmResult StmEvaluator::operator()(AST::ConfigDims cfg) const return StmResult("", cfg.nmbr_dims()); } +} // namespace detail + } // namespace Eval } // namespace SBG diff --git a/eval/visitors/stm_evaluator.hpp b/eval/visitors/stm_evaluator.hpp index 27c7c566..6e77e640 100755 --- a/eval/visitors/stm_evaluator.hpp +++ b/eval/visitors/stm_evaluator.hpp @@ -25,8 +25,8 @@ ******************************************************************************/ -#ifndef STM_EVALUATOR -#define STM_EVALUATOR +#ifndef SBGRAPH_EVAL_STM_EVALUATOR_HPP_ +#define SBGRAPH_EVAL_STM_EVALUATOR_HPP_ #include "ast/statement.hpp" #include "eval/eval_context.hpp" @@ -36,20 +36,24 @@ namespace SBG { namespace Eval { +namespace detail { + class StmEvaluator : public boost::static_visitor { - public: +public: StmEvaluator(EvalContext& eval_ctx); - EvalContext& eval_ctx() const; + EvalContext& eval_context() const; StmResult operator()(AST::Assign assgn) const; StmResult operator()(AST::ConfigDims cfg) const; - private: - EvalContext& eval_ctx_; +private: + EvalContext& _eval_context; }; +} // namespace detail + } // namespace Eval } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_STM_EVALUATOR_HPP_ diff --git a/parser/expr.hpp b/parser/expr.hpp index 3b9a6a83..8059aa33 100755 --- a/parser/expr.hpp +++ b/parser/expr.hpp @@ -23,8 +23,8 @@ ******************************************************************************/ -#ifndef EXPR_PARSER_HPP -#define EXPR_PARSER_HPP +#ifndef SBGRAPH_PARSER_EXPR_HPP_ +#define SBGRAPH_PARSER_EXPR_HPP_ #include "ast/expr.hpp" #include "parser/skipper.hpp" @@ -36,7 +36,8 @@ namespace Parser { namespace qi = boost::spirit::qi; template -struct ExprRule : qi::grammar, AST::ExprList()> { +class ExprRule : qi::grammar, AST::ExprList()> { +public: ExprRule(Iterator &it); // Rules with no skip @@ -47,7 +48,7 @@ struct ExprRule : qi::grammar, AST::ExprList()> { // Operators tokens qi::rule OPAREN, CPAREN, OBRACKET, CBRACKET, OBRACE, CBRACE, COLON , RAT, COMA, DIV, ARROW, OANGLE, CANGLE, CARTPROD, SLO, VAR, ADD, SUB, PIPE - , SEMI, V, VMAP, MAP1, MAP2, EMAP, SUBE, MAPB, MAPD, X, Y; + , SEMI, V, VMAP, MAP1, MAP2, EMAP, MAPB, MAPD, X, Y; // Other rules qi::rule, LIB::NAT()> nat; @@ -100,4 +101,4 @@ struct ExprRule : qi::grammar, AST::ExprList()> { } // namespace SBG -#endif +#endif // SBGRAPH_PARSER_EXPR_HPP_ diff --git a/parser/expr_def.hpp b/parser/expr_def.hpp index a6c3244a..68231a1f 100755 --- a/parser/expr_def.hpp +++ b/parser/expr_def.hpp @@ -17,20 +17,20 @@ ******************************************************************************/ -#ifndef EXPR_DEF_PARSER_HPP -#define EXPR_DEF_PARSER_HPP +#ifndef SBGRAPH_PARSER_EXPR_DEF_HPP_ +#define SBGRAPH_PARSER_EXPR_DEF_HPP_ + +#include "ast/expr.hpp" +#include "sbg/rational.hpp" #include #include #include #include -#include "ast/expr.hpp" -#include "sbg/rational.hpp" - // Adapt structures ------------------------------------------------------------ -BOOST_FUSION_ADAPT_STRUCT(SBG::LIB::MD_NAT, (SBG::LIB::VNAT, value_)) +BOOST_FUSION_ADAPT_STRUCT(SBG::LIB::MD_NAT, (SBG::LIB::MD_NAT::VNAT, value_)) BOOST_FUSION_ADAPT_STRUCT( SBG::LIB::RATIONAL, (boost::rational, value_) @@ -166,7 +166,6 @@ ExprRule::ExprRule(Iterator &it) : , MAP1("map1:") , MAP2("map2:") , EMAP("Emap:") - , SUBE("subE:") , MAPB("mapB:") , MAPD("mapD:") , X("X:") @@ -271,14 +270,8 @@ ExprRule::ExprRule(Iterator &it) : >> VMAP >> sbg_expr >> MAP1 >> sbg_expr >> MAP2 >> sbg_expr - >> EMAP >> sbg_expr - >> -(SUBE >> sbg_expr))[qi::_val = phx::if_else(qi::_6 - , phx::construct(qi::_1, qi::_2, qi::_3, qi::_4, qi::_5 - , *qi::_6) - , phx::construct(qi::_1, qi::_2, qi::_3, qi::_4, qi::_5 - , phx::construct()) - ) - ]; + >> EMAP >> sbg_expr)[qi::_val + = phx::construct(qi::_1, qi::_2, qi::_3, qi::_4, qi::_5)]; // ------------ // @@ -287,15 +280,10 @@ ExprRule::ExprRule(Iterator &it) : >> MAP1 >> sbg_expr >> MAP2 >> sbg_expr >> EMAP >> sbg_expr - >> -(SUBE >> sbg_expr) >> X >> sbg_expr - >> Y >> sbg_expr)[qi::_val = phx::if_else(qi::_6 - , phx::construct(qi::_1, qi::_2, qi::_3, qi::_4 - , qi::_5, *qi::_6, qi::_7, qi::_8) - , phx::construct(qi::_1, qi::_2, qi::_3, qi::_4 - , qi::_5, phx::construct(), qi::_7, qi::_8) - ) - ]; + >> Y >> sbg_expr)[qi::_val + = phx::construct(qi::_1, qi::_2, qi::_3, qi::_4, qi::_5 + , qi::_6, qi::_7)]; // ------------ // @@ -303,14 +291,8 @@ ExprRule::ExprRule(Iterator &it) : >> VMAP >> sbg_expr >> MAPB >> sbg_expr >> MAPD >> sbg_expr - >> EMAP >> sbg_expr - >> -(SUBE >> sbg_expr))[qi::_val = phx::if_else(qi::_6 - , phx::construct(qi::_1, qi::_2, qi::_3, qi::_4, qi::_5 - , *qi::_6) - , phx::construct(qi::_1, qi::_2, qi::_3, qi::_4, qi::_5 - , phx::construct()) - ) - ]; + >> EMAP >> sbg_expr)[qi::_val + = phx::construct(qi::_1, qi::_2, qi::_3, qi::_4, qi::_5)]; // ------------ // @@ -340,4 +322,4 @@ ExprRule::ExprRule(Iterator &it) : } // namespace SBG -#endif +#endif // SBGRAPH_PARSER_EXPR_DEF_HPP_ diff --git a/parser/parser_exec.cpp b/parser/parser_exec.cpp index d0cafe36..f6cfb58e 100644 --- a/parser/parser_exec.cpp +++ b/parser/parser_exec.cpp @@ -36,9 +36,11 @@ namespace Parser { ParserExecutor::ParserExecutor() : UserInputHandler() { - cmd_line_opts_.add(generic_).add(config_).add(hidden_); - cfg_file_opts_.add(config_).add(hidden_); - visible_.add(generic_).add(config_); + // First option without name is the input file + _positional.add("input-file", 1); + _cmd_line_opts.add(_generic).add(_config).add(_hidden); + _cfg_file_opts.add(_config).add(_hidden); + _visible.add(_generic).add(_config); } void ParserExecutor::execute(int arg_count, char* args[]) @@ -47,7 +49,7 @@ void ParserExecutor::execute(int arg_count, char* args[]) Util::prog_opts::variables_map vm; store(Util::prog_opts::command_line_parser(arg_count, args) - .options(cmd_line_opts_).positional(positional_).run(), vm); + .options(_cmd_line_opts).positional(_positional).run(), vm); notify(vm); // Help handling ------------------------------------------------------------- @@ -56,7 +58,7 @@ void ParserExecutor::execute(int arg_count, char* args[]) std::cout << "Usage: filename [options]\n"; std::cout << "Command line options are prioritized over configuration file" " options."; - std::cout << visible_ << "\n"; + std::cout << _visible << "\n"; return; } @@ -69,18 +71,18 @@ void ParserExecutor::execute(int arg_count, char* args[]) // Optional configuration file handling -------------------------------------- - if (config_file_) { - std::ifstream config_fs((*config_file_).c_str()); + if (_config_file) { + std::ifstream config_fs((*_config_file).c_str()); if (config_fs) { - store(parse_config_file(config_fs, cfg_file_opts_), vm); + store(parse_config_file(config_fs, _cfg_file_opts), vm); notify(vm); } } // Input SBG program file handling ------------------------------------------- - if (input_file_) { - parseFile(*input_file_); + if (_input_file) { + parseFile(*_input_file); } else { std::cout << "Usage: filename [options]"; diff --git a/sbg/CMakeLists.txt b/sbg/CMakeLists.txt index d528027c..01a2c1b2 100644 --- a/sbg/CMakeLists.txt +++ b/sbg/CMakeLists.txt @@ -10,24 +10,29 @@ target_sources( bipartite_sbg.cpp directed_sbg.cpp dom_ord_pwmap.cpp + expression.cpp + fixed_points.cpp interval.cpp - lexp.cpp + linear_expr.cpp map.cpp + map_detail.cpp map_entry.cpp multidim_inter.cpp - multidim_lexp.cpp natural.cpp + ord_pwmap.cpp ord_set.cpp ord_unidim_dense_set.cpp - ord_pwmap.cpp + perimeter.cpp pw_map.cpp - pwmap_fact.cpp + pwmap_detail.cpp + pwmap_impl.cpp rational.cpp sbg.cpp set.cpp - set_fact.cpp - unord_set.cpp + set_detail.cpp + set_impl.cpp unord_pwmap.cpp + unord_set.cpp ) add_custom_target(sbg-doc diff --git a/sbg/bipartite_sbg.cpp b/sbg/bipartite_sbg.cpp index 6520f2df..853e4470 100644 --- a/sbg/bipartite_sbg.cpp +++ b/sbg/bipartite_sbg.cpp @@ -18,25 +18,30 @@ ******************************************************************************/ #include "sbg/bipartite_sbg.hpp" +#include "sbg/natural.hpp" +#include "util/debug.hpp" + +#include namespace SBG { namespace LIB { +// Constructors/Destructors ---------------------------------------------------- + BipartiteSBG::BipartiteSBG() - : _V(SET_FACT.createSet()), _Vmap(PW_FACT.createPWMap()) - , _E(SET_FACT.createSet()), _map1(PW_FACT.createPWMap()) - , _map2(PW_FACT.createPWMap()), _Emap(PW_FACT.createPWMap()) - , _subEmap(PW_FACT.createPWMap()) - , _X(SET_FACT.createSet()), _Y(SET_FACT.createSet()) {} + : _V(), _Vmap() + , _E(), _map1() + , _map2(), _Emap() + , _X(), _Y() {} BipartiteSBG::BipartiteSBG(const Set& V, const PWMap& Vmap - , const PWMap& map1, const PWMap& map2 - , const PWMap& Emap, const PWMap& subEmap + , const PWMap& map1, const PWMap& map2, const PWMap& Emap , const Set& X, const Set& Y) - : _V(V), _Vmap(Vmap), _E(map1.dom().intersection(map2.dom())) - , _map1(map1), _map2(map2), _Emap(Emap), _subEmap(subEmap) - , _X(X), _Y(Y) {} + : _V(V), _Vmap(Vmap), _E(map1.domain().intersection(map2.domain())) + , _map1(map1), _map2(map2), _Emap(Emap), _X(X), _Y(Y) {} + +// Getters --------------------------------------------------------------------- const Set& BipartiteSBG::V() const { return _V; } @@ -50,27 +55,59 @@ const PWMap& BipartiteSBG::map2() const { return _map2; } const PWMap& BipartiteSBG::Emap() const { return _Emap; } -const PWMap& BipartiteSBG::subEmap() const { return _subEmap; } - const Set& BipartiteSBG::X() const { return _X; } const Set& BipartiteSBG::Y() const { return _Y; } -BipartiteSBG& BipartiteSBG::operator=(const BipartiteSBG& other) +// Setters --------------------------------------------------------------------- + +void BipartiteSBG::addSetVertex(const Set& X, const Set& Y) +{ + Set vertices = X.cup(Y); + if (!vertices.intersection(_V).isEmpty()) { + Util::ERROR("BipartiteSBG::addSetVertex: trying to add existing vertices: " + , vertices, " to SBG\n"); + } else if (!vertices.isEmpty()) { + _V = _V.cup(vertices); + Set set_vertices = _Vmap.image(); + std::size_t arity = vertices.arity(); + MD_NAT max = set_vertices.isEmpty() ? MD_NAT{arity, 0} + : set_vertices.maxElem(); + MD_NAT one_all_dims{arity, 1}; + _Vmap.emplace(vertices, max + one_all_dims); + _X = _X.cup(X); + _Y = _Y.cup(Y); + } +} + +void BipartiteSBG::addSetEdge(const PWMap& pw1, const PWMap& pw2) { - _V = other._V; - _Vmap = other._Vmap; - _E = other._E; - _map1 = other._map1; - _map2 = other._map2; - _Emap = other._Emap; - _subEmap = other._subEmap; - _X = other._X; - _Y = other._Y; - - return *this; + Set edges1 = pw1.domain(); + Set edges2 = pw2.domain(); + if (edges1 != edges2) { + Util::ERROR("BipartiteSBG::addSetEdge: ", edges1, " is different from " + , edges2, "\n"); + } else if (edges1.intersection(_E).isEmpty()) { + Set edges = edges1; + if (!edges.isEmpty()) { + _E = std::move(_E).cup(std::move(edges)); + Set set_edges = _Emap.image(); + std::size_t arity = edges.arity(); + MD_NAT max = set_edges.isEmpty() ? MD_NAT{arity, 0} + : set_edges.maxElem(); + MD_NAT one_all_dims{arity, 1}; + _map1 = std::move(_map1).concatenation(pw1); + _map2 = std::move(_map2).concatenation(pw2); + _Emap.emplace(edges, max + one_all_dims); + } + } else { + Util::ERROR("BipartiteSBG::addSetEdge: trying to add existing edges: " + , edges1, " to SBG\n"); + } } +// Operators ------------------------------------------------------------------- + std::ostream& operator<<(std::ostream& out, const BipartiteSBG& g) { out << "V: " << g.V() << "\n"; @@ -79,121 +116,73 @@ std::ostream& operator<<(std::ostream& out, const BipartiteSBG& g) out << "map1: " << g.map1() << "\n"; out << "map2: " << g.map2() << "\n"; out << "Emap: " << g.Emap() << "\n"; - out << "subEmap: " << g.subEmap() << "\n"; out << "X: " << g.X() << "\n"; out << "Y: " << g.Y() << "\n"; return out; } -void BipartiteSBG::addSV(const Set& X, const Set& Y) -{ - Set vertices = X.cup(Y); - if (!vertices.intersection(_V).isEmpty()) { - Util::ERROR("Trying to add existing vertices: ", vertices, " to SBG\n"); - } else if (!vertices.isEmpty() && vertices.intersection(_V).isEmpty()) { - _V = _V.cup(vertices); - Set SV = _Vmap.image(); - std::size_t dims = vertices.arity(); - MD_NAT max = SV.isEmpty() ? MD_NAT(dims, 0) : SV.maxElem(); - for (unsigned int j = 0; j < dims; ++j) { - max[j] = max[j] + 1; - } - _Vmap.emplaceBack(Map(vertices, Exp(max))); - _X = _X.cup(X); - _Y = _Y.cup(Y); - } -} +// Extra operations ------------------------------------------------------------ -void BipartiteSBG::addSE(const PWMap& pw1, const PWMap& pw2) +BipartiteSBG copy(unsigned int copies, BipartiteSBG sbg) { - Set edges = SET_FACT.createSet(), edges1 = pw1.dom(), edges2 = pw2.dom(); - if (!edges.intersection(_E).isEmpty()) { - Util::ERROR("Trying to add existing edges: ", edges, " to SBG\n"); + if (copies == 0) { + Util::ERROR("BipartiteSBG::copy: zeros copies is not allowed\n"); } - else if (edges1 == edges2) { - edges = edges1; - if (!edges.isEmpty() && edges.intersection(_E).isEmpty()) { - Set SE = _Emap.image(); - std::size_t dims = edges.arity(); - MD_NAT max = SE.isEmpty() ? MD_NAT(dims, 0) : SE.maxElem(); - for (unsigned int j = 0; j < dims; ++j) { - max[j] = max[j] + 1; - } - _map1 = _map1.concatenation(pw1); - _map2 = _map2.concatenation(pw2); - _Emap.emplaceBack(Map(edges, max)); + + Set X = sbg.X(); + Set Y = sbg.Y(); + Set V = sbg.V(); + PWMap Vmap = sbg.Vmap(); + PWMap map1 = sbg.map1(); + PWMap map2 = sbg.map2(); + PWMap Emap = sbg.Emap(); + Set E = sbg.E(); + + for (unsigned int j = 1; j < copies; ++j) { + MD_NAT max_v = sbg.V().maxElem(); + Set set_vertices = Vmap.image(); + while (!set_vertices.isEmpty()) { + Set min_elem_set{set_vertices.minElem()}; + Set vertices = Vmap.preImage(min_elem_set); + Set jth_X = vertices.intersection(X); + Set jth_Y = vertices.intersection(Y); + sbg.addSetVertex(jth_X.offset(max_v), jth_Y.offset(max_v)); + + set_vertices = set_vertices.difference(min_elem_set); } - } -} -BipartiteSBG BipartiteSBG::copy(unsigned int times) const -{ - Set ith_V = _V; - Set new_V = ith_V; - PWMap ith_Vmap = _Vmap; - PWMap new_Vmap = ith_Vmap; - PWMap ith_map1 = _map1; - PWMap new_map1 = ith_map1; - PWMap ith_map2 = _map2; - PWMap new_map2 = ith_map2; - PWMap ith_Emap = _Emap; - PWMap new_Emap = ith_Emap; - PWMap ith_subE = _subEmap; - PWMap new_subE = ith_subE; - Set ith_X = _X; - Set new_X = ith_X; - Set ith_Y = _Y; - Set new_Y = ith_Y; - - if (!ith_V.isEmpty()) { - MD_NAT maxv = ith_V.maxElem(); - auto dims = maxv.arity(); - MD_NAT maxV - = ith_Vmap.isEmpty() ? MD_NAT(dims, 0) : ith_Vmap.image().maxElem(); - MD_NAT maxe = _E.isEmpty() ? MD_NAT(dims, 0) : _E.maxElem(); - MD_NAT maxE - = ith_Emap.isEmpty() ? MD_NAT(dims, 0) : ith_Emap.image().maxElem(); - - Exp off; - for (unsigned int j = 0; j < dims; ++j) { - RATIONAL o = RATIONAL(maxv[j]) - RATIONAL(maxe[j]); - off.emplaceBack(LExp(0, o)); + Expression offset_v; + for (std::size_t k = 0; k < max_v.arity(); ++k) { + offset_v = offset_v.cartesianProduct(Expression{RATIONAL{1} + , RATIONAL{max_v[k]}}); } + PWMap offset_pw_v{Map{V, offset_v}}; - for (unsigned int j = 0; j < times; ++j) { - if (j > 0) { - new_V = new_V.disjointCup(ith_V); - new_Vmap = new_Vmap.concatenation(ith_Vmap); - new_map1 = new_map1.concatenation(ith_map1); - new_map2 = new_map2.concatenation(ith_map2); - new_Emap = new_Emap.concatenation(ith_Emap); - new_subE = new_subE.concatenation(ith_subE); - new_X = new_X.disjointCup(ith_X); - new_Y = new_Y.disjointCup(ith_Y); - } - - ith_V = ith_V.offset(maxv); - ith_Vmap = ith_Vmap.offsetDom(maxv); - ith_Vmap = ith_Vmap.offsetImage(maxV); - - ith_map1 = ith_map1.offsetDom(maxe); - ith_map1 = ith_map1.offsetImage(off); - ith_map2 = ith_map2.offsetDom(maxe); - ith_map2 = ith_map2.offsetImage(off); - ith_Emap = ith_Emap.offsetDom(maxe); - ith_Emap = ith_Emap.offsetImage(maxE); - ith_subE = ith_subE.offsetDom(maxe); - ith_subE = ith_subE.offsetImage(maxE); - - ith_X = ith_X.offset(maxv); - ith_Y = ith_Y.offset(maxv); + MD_NAT max_e = sbg.E().maxElem(); + Expression offset_e; + for (std::size_t k = 0; k < max_e.arity(); ++k) { + offset_e = offset_e.cartesianProduct(Expression{RATIONAL{1} + , RATIONAL{max_e[k]}}); + } + PWMap offset_pw_e{Map{E, offset_e}}; + PWMap inverse_offset_pw_e = offset_pw_e.inverse(); + + Set set_edges = Emap.image(); + while (!set_edges.isEmpty()) { + Set min_elem_set{set_edges.minElem()}; + Set edges = Emap.preImage(min_elem_set); + PWMap pw1 = map1.restrict(edges); + PWMap pw2 = map2.restrict(edges); + pw1 = offset_pw_v.composition(pw1.composition(inverse_offset_pw_e)); + pw2 = offset_pw_v.composition(pw2.composition(inverse_offset_pw_e)); + sbg.addSetEdge(pw1, pw2); + + set_edges = set_edges.difference(min_elem_set); } } - BipartiteSBG result(new_V, new_Vmap, new_map1, new_map2, new_Emap, new_subE - , new_X, new_Y); - return result; + return sbg; } } // namespace LIB diff --git a/sbg/bipartite_sbg.hpp b/sbg/bipartite_sbg.hpp index 9c0914de..9152e308 100644 --- a/sbg/bipartite_sbg.hpp +++ b/sbg/bipartite_sbg.hpp @@ -24,11 +24,13 @@ ******************************************************************************/ -#ifndef SBG_BIPARTITE_SBG_HPP -#define SBG_BIPARTITE_SBG_HPP +#ifndef SBGRAPH_SBG_BIPARTITE_SBG_HPP_ +#define SBGRAPH_SBG_BIPARTITE_SBG_HPP_ -#include "sbg/sbg.hpp" -#include "util/debug.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/set.hpp" + +#include namespace SBG { @@ -39,7 +41,7 @@ namespace LIB { //////////////////////////////////////////////////////////////////////////////// class BipartiteSBG { - public: +public: /** * @brief Empyt Bipartite SBG. */ @@ -51,12 +53,12 @@ class BipartiteSBG { * domain of map1_ and map2_. * Preconditions: * - \p V = dom(\p Vmap). - * - dom(\p map1) = dom(\p map2) = dom(\p Emap) = dom(\p subEmap). + * - dom(\p map1) = dom(\p map2) = dom(\p Emap). * - \p X, \p Y is a bipartition of \p V. */ BipartiteSBG(const Set& V, const PWMap& Vmap , const PWMap& map1, const PWMap& map2 - , const PWMap& Emap, const PWMap& subEmap + , const PWMap& Emap , const Set& X, const Set& Y); const Set& V() const; @@ -65,7 +67,6 @@ class BipartiteSBG { const PWMap& map1() const; const PWMap& map2() const; const PWMap& Emap() const; - const PWMap& subEmap() const; const Set& X() const; const Set& Y() const; @@ -75,37 +76,63 @@ class BipartiteSBG { * be added to _X, and the same goes for \p Y and _Y. * Precondition: \p X ∩ \p Y = {}. */ - void addSV(const Set& X, const Set& Y); + void addSetVertex(const Set& X, const Set& Y); /** * @brief Adds a set-edge to the bipartite SBG. * Preconditions: dom(\p pw1) = dom(\p pw2). */ - void addSE(const PWMap& pw1, const PWMap& pw2); + void addSetEdge(const PWMap& pw1, const PWMap& pw2); - BipartiteSBG& operator=(const BipartiteSBG& other); + template + void foreachSetVertex(FuncT&& f) const; - /** - * @brief Returns a new bipartite SBG constructed by copying \p times the - * the current bipartite SBG, disconnected one from each other. - */ - BipartiteSBG copy(unsigned int times) const; + template + void foreachSetEdge(FuncT&& f) const; - private: +private: Set _V; ///< Vertex definitions PWMap _Vmap; Set _E; ///< Edge definitions PWMap _map1; PWMap _map2; PWMap _Emap; - PWMap _subEmap; Set _X; ///< "Left" vertices by convention of the bipartite SBG Set _Y; ///< "Right" vertices by convention of the bipartite SBG }; + std::ostream& operator<<(std::ostream& out, const BipartiteSBG& g); +// Template definitions -------------------------------------------------------- + +template +inline void BipartiteSBG::foreachSetVertex(FuncT&& f) const +{ + Set remaining = _Vmap.image(); + while (!remaining.isEmpty()) { + const MD_NAT& x = remaining.minElem(); + f(x); + remaining = remaining.difference(Set{x}); + } +} + +template +inline void BipartiteSBG::foreachSetEdge(FuncT&& f) const +{ + Set remaining = _Emap.image(); + while (!remaining.isEmpty()) { + const MD_NAT& x = remaining.minElem(); + f(x); + remaining = remaining.difference(Set{x}); + } +} + +// Extra operations ------------------------------------------------------------ + +BipartiteSBG copy(unsigned int copies, BipartiteSBG sbg); + } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_BIPARTITE_SBG_HPP_ diff --git a/sbg/directed_sbg.cpp b/sbg/directed_sbg.cpp index 633313fe..c5ba4f74 100644 --- a/sbg/directed_sbg.cpp +++ b/sbg/directed_sbg.cpp @@ -17,7 +17,11 @@ ******************************************************************************/ +#include "sbg/natural.hpp" #include "sbg/directed_sbg.hpp" +#include "util/debug.hpp" + +#include namespace SBG { @@ -27,123 +31,105 @@ namespace LIB { // Directed SBG ---------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -member_imp(DSBG, Set, V); -member_imp(DSBG, PWMap, Vmap); -member_imp(DSBG, Set, E); -member_imp(DSBG, PWMap, mapB); -member_imp(DSBG, PWMap, mapD); -member_imp(DSBG, PWMap, Emap); -member_imp(DSBG, PWMap, subEmap); - -DSBG::DSBG() - : V_(SET_FACT.createSet()), Vmap_(PW_FACT.createPWMap()) - , E_(SET_FACT.createSet()), mapB_(PW_FACT.createPWMap()) - , mapD_(PW_FACT.createPWMap()), Emap_(PW_FACT.createPWMap()) - , subEmap_(PW_FACT.createPWMap()) {} -DSBG::DSBG(const Set &V, const PWMap &Vmap - , const PWMap &mapB, const PWMap &mapD - , const PWMap &Emap, const PWMap &subEmap) - : V_(V), Vmap_(Vmap) - , E_(mapB.dom().intersection(mapD.dom())) - , mapB_(mapB), mapD_(mapD), Emap_(Emap), subEmap_(subEmap) {} - -DSBG &DSBG::operator=(const DSBG &other) -{ - V_ = other.V_; - Vmap_ = other.Vmap_; - E_ = other.E_; - mapB_ = other.mapB_; - mapD_ = other.mapD_; - Emap_ = other.Emap_; - subEmap_ = other.subEmap_; - - return *this; -} +// Constructors/Destructors ---------------------------------------------------- -std::ostream &operator<<(std::ostream &out, const DSBG &dg) -{ - out << "V: " << dg.V() << "\n"; - out << "Vmap: " << dg.Vmap() << "\n\n"; - out << "E: " << dg.E() << "\n"; - out << "mapB: " << dg.mapB() << "\n"; - out << "mapD: " << dg.mapD() << "\n"; - out << "Emap: " << dg.Emap() << "\n"; - out << "subEmap: " << dg.subEmap() << "\n"; +DirectedSBG::DirectedSBG() : _V(), _Vmap(), _E(), _mapB(), _mapD(), _Emap() {} - return out; -} +DirectedSBG::DirectedSBG(const Set& V, const PWMap& Vmap + , const PWMap& mapB, const PWMap& mapD + , const PWMap& Emap) + : _V(V), _Vmap(Vmap) + , _E(mapB.domain().intersection(mapD.domain())) + , _mapB(mapB), _mapD(mapD), _Emap(Emap) {} -DSBG DSBG::addSV(const Set &vertices) const -{ - if (!vertices.isEmpty() && vertices.intersection(V_).isEmpty()) { - PWMap new_Vmap(std::move(Vmap_)); - PWMap new_mapB(std::move(mapB_)), new_mapD(std::move(mapD_)); - PWMap new_Emap(std::move(Emap_)), new_subE(std::move(subEmap_)); - - Set new_V = new_V.cup(vertices); - - Set SV = new_Vmap.image(); // Identifiers of SV - std::size_t dims = vertices.arity(); - MD_NAT max = SV.isEmpty() ? MD_NAT(dims, 0) : SV.maxElem(); - for (unsigned int j = 0; j < dims; ++j) - max[j] = max[j] + 1; - Map m(vertices, Exp(max)); - new_Vmap.emplaceBack(m); - - return DSBG(new_V, new_Vmap, new_mapB, new_mapD, new_Emap, new_subE); - } +// Getters --------------------------------------------------------------------- + +const Set& DirectedSBG::V() const { return _V; } + +const PWMap& DirectedSBG::Vmap() const { return _Vmap; } + +const Set& DirectedSBG::E() const { return _E; } + +const PWMap& DirectedSBG::mapB() const { return _mapB; } - else if (!vertices.intersection(V_).isEmpty()) - Util::ERROR("Trying to add existing vertices: ", vertices, " to DSBG\n"); +const PWMap& DirectedSBG::mapD() const { return _mapD; } - return DSBG(); +const PWMap& DirectedSBG::Emap() const { return _Emap; } + +// Setters --------------------------------------------------------------------- + +void DirectedSBG::addSetVertex(const Set& vertices) +{ + if (!vertices.intersection(_V).isEmpty()){ + Util::ERROR("Trying to add existing vertices: ", vertices + , " to DirectedSBG\n"); + } else if (!vertices.isEmpty()) { + _V = std::move(_V).cup(vertices); + Set set_vertices = _Vmap.image(); + std::size_t arity = vertices.arity(); + MD_NAT max = set_vertices.isEmpty() ? MD_NAT{arity, 0} + : set_vertices.maxElem(); + MD_NAT one_all_dims{arity, 1}; + _Vmap.emplace(vertices, max + one_all_dims); + } } -DSBG DSBG::addSE(const PWMap &pw1, const PWMap &pw2) const +void DirectedSBG::addSetEdge(const PWMap& pwB, const PWMap& pwD) { - Set edges = SET_FACT.createSet(), edges1 = pw1.dom(), edges2 = pw2.dom(); - if (edges1 == edges2) { - edges = edges1; - if (!edges.isEmpty() && edges.intersection(E_).isEmpty()) { - Set new_V(std::move(V_)); - PWMap new_Vmap(std::move(Vmap_)); - PWMap new_mapB(std::move(mapB_)), new_mapD(std::move(mapD_)); - PWMap new_Emap(std::move(Emap_)), new_subE(std::move(subEmap_)); - - Set SE = Emap_.image(); // Identifiers of SV - std::size_t dims = edges.arity(); - MD_NAT max = SE.isEmpty() ? MD_NAT(dims, 0) : SE.maxElem(); - for (unsigned int j = 0; j < dims; ++j) - max[j] = max[j] + 1; - Map m(edges, max); - new_Emap.emplaceBack(m); - - new_mapB = new_mapB.concatenation(pw1); - new_mapD = new_mapD.concatenation(pw2); - - return DSBG(new_V, new_Vmap, new_mapB, new_mapD, new_Emap, new_subE); + Set edgesB = pwB.domain(); + Set edgesD = pwD.domain(); + if (edgesB != edgesD) { + // TODO + Util::ERROR("The domain of ", edgesB, " is different from ", edgesD, "\n"); + } else if (edgesB.intersection(_E).isEmpty()) { + Set edges = edgesB; + if (!edges.isEmpty()) { + _E = std::move(_E).cup(std::move(edges)); + Set set_edges = _Emap.image(); + std::size_t arity = edges.arity(); + MD_NAT max = set_edges.isEmpty() ? MD_NAT(arity, 0) : set_edges.maxElem(); + MD_NAT one_all_dims{arity, 1}; + _mapB = std::move(_mapB).concatenation(pwB); + _mapD = std::move(_mapD).concatenation(pwD); + _Emap.emplace(edges, max + one_all_dims); } - - else if (!edges.intersection(E_).isEmpty()) - Util::ERROR("Trying to add existing edges: ", edges, " to DSBG\n"); + } else { + Util::ERROR("Trying to add existing edges: ", edgesB, " to SBG\n"); } +} - return DSBG(); +void DirectedSBG::eraseVertices(const Set& V) +{ + _V = _V.difference(V); + _Vmap = _Vmap.restrict(_V); + + Set eraseE = _mapB.preImage(V).cup(_mapD.preImage(V)); + _E = _E.difference(eraseE); + _mapB = _mapB.restrict(_E); + _mapD = _mapD.restrict(_E); + _Emap = _Emap.restrict(_E); } -DSBG DSBG::eraseVertices(const Set &vs) const +void DirectedSBG::eraseEdges(const Set& E) { - Set new_V = V_.difference(vs); - PWMap new_Vmap = Vmap_.restrict(V_); + _E = _E.difference(E); + _mapB = _mapB.restrict(_E); + _mapD = _mapD.restrict(_E); + _Emap = _Emap.restrict(_E); +} - Set eraseE = mapB_.preImage(vs).cup(mapD_.preImage(vs)); - Set new_E = E_.difference(eraseE); - PWMap new_mapB = mapB_.restrict(new_E); - PWMap new_mapD = mapD_.restrict(new_E); - PWMap new_Emap = Emap_.restrict(new_E); - PWMap new_subE = subEmap_.restrict(new_E); +// Operators ------------------------------------------------------------------- - return DSBG(new_V, new_Vmap, new_mapB, new_mapD, new_Emap, new_subE); +std::ostream& operator<<(std::ostream& out, const DirectedSBG& dg) +{ + out << "V: " << dg.V() << "\n"; + out << "Vmap: " << dg.Vmap() << "\n\n"; + out << "E: " << dg.E() << "\n"; + out << "mapB: " << dg.mapB() << "\n"; + out << "mapD: " << dg.mapD() << "\n"; + out << "Emap: " << dg.Emap() << "\n"; + + return out; } } // namespace LIB diff --git a/sbg/directed_sbg.hpp b/sbg/directed_sbg.hpp index 52324a49..9100d8d2 100644 --- a/sbg/directed_sbg.hpp +++ b/sbg/directed_sbg.hpp @@ -8,14 +8,12 @@ - A Set E_ listing elements of E(G). - A PWMap mapB_ mapping elements of E_ to V_ (start of each edge). - A PWMap mapD_ mapping elements of E_ to V_ (ending of each edge). \n - where map1_ and map_2 share the same domain. These elements all together keep + where mapB_ and mapD_ share the same domain. These elements all together keep the same information as G. Additionally, the SBG keeps: - A PWMap Vmap_ mapping elements in V_ to some constant value. Vertices that share the same image conform a *Set-Vertex*. - A PWMap Emap_ mapping elements in E_ to some constant value. Edges that share the same image conform a *Set-Edge*. - - A PWMap subEmap_ mapping elements in E_ to some constant value. Edges that - share the same image conform a *Subset-Edge*.\n These components are added to keep track of repetitve structures in G. Note that a Set-Edge might be composed by several Subset-Edges. @@ -38,11 +36,13 @@ ******************************************************************************/ -#ifndef SBG_DIRECTED_SBG_HPP -#define SBG_DIRECTED_SBG_HPP +#ifndef SBGRAPH_SBG_DIRECTED_SBG_HPP_ +#define SBGRAPH_SBG_DIRECTED_SBG_HPP_ -#include "sbg/pwmap_fact.hpp" -#include "util/debug.hpp" +#include "sbg/set.hpp" +#include "sbg/pw_map.hpp" + +#include namespace SBG { @@ -52,58 +52,93 @@ namespace LIB { // Directed SBG ---------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -class DSBG { - public: - // Vertex definitions - member_class(Set, V); - member_class(PWMap, Vmap); - - // Edge definitions - member_class(Set, E); - member_class(PWMap, mapB); - member_class(PWMap, mapD); - member_class(PWMap, Emap); - member_class(PWMap, subEmap); - +class DirectedSBG { +public: /** * @brief Empty SBG constructor. */ - DSBG(); + DirectedSBG(); /** * @brief SBG constructor that copies arguments to construct member variables. * A set of edges E is not needed, as it will be obtained from the domain of * map1_ and map2_. */ - DSBG(const Set &V, const PWMap &Vmap - , const PWMap &mapB, const PWMap &mapD - , const PWMap &Emap, const PWMap &subEmap); + DirectedSBG(const Set& V, const PWMap& Vmap + , const PWMap& mapB, const PWMap& mapD + , const PWMap& Emap); - DSBG &operator=(const DSBG &other); + const Set& V() const; + const PWMap& Vmap() const; + const Set& E() const; + const PWMap& mapB() const; + const PWMap& mapD() const; + const PWMap& Emap() const; /** * @brief Adds a new set-vertex composed by \p vertices. * Precondition: V_.intersection(vertices) = {} */ - DSBG addSV(const Set &vertices) const; + void addSetVertex(const Set& vertices); /** * @brief Adds a new set-edge described by \p pw1 and \p pw2. * Precondition: dom(pw1) = dom(pw2) and * E_.intersection(pw1.dom()) = {} and E_.intersection(pw2.dom()) = {} */ - DSBG addSE(const PWMap &pw1, const PWMap &pw2) const; + void addSetEdge(const PWMap& pw1, const PWMap& pw2); /** - * @brief Erase vertices \p vs from the DSBG, together with associated edges - * with \p vs. + * @brief Erase vertices \p vs from the DirectedSBG, together with adjacent + * edges of \p vs. */ - DSBG eraseVertices(const Set &vs) const; + void eraseVertices(const Set& V); + + void eraseEdges(const Set& E); + + template + void foreachSetVertex(FuncT&& f) const; + + template + void foreachSetEdge(FuncT&& f) const; + +private: + Set _V; ///< Vertices definitions + PWMap _Vmap; + Set _E; ///< Edges definitions + PWMap _mapB; + PWMap _mapD; + PWMap _Emap; }; -std::ostream &operator<<(std::ostream &out, const DSBG &dg); + +std::ostream& operator<<(std::ostream& out, const DirectedSBG& dg); + +// Template definitions -------------------------------------------------------- + +template +inline void DirectedSBG::foreachSetVertex(FuncT&& f) const +{ + Set remaining = _Vmap.image(); + while (!remaining.isEmpty()) { + const MD_NAT& x = remaining.minElem(); + f(x); + remaining = remaining.difference(Set{x}); + } +} + +template +inline void DirectedSBG::foreachSetEdge(FuncT&& f) const +{ + Set remaining = _Emap.image(); + while (!remaining.isEmpty()) { + const MD_NAT& x = remaining.minElem(); + f(x); + remaining = remaining.difference(Set{x}); + } +} } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_DIRECTED_SBG_HPP_ diff --git a/sbg/dom_ord_pwmap.cpp b/sbg/dom_ord_pwmap.cpp index c03ae513..d0444fea 100644 --- a/sbg/dom_ord_pwmap.cpp +++ b/sbg/dom_ord_pwmap.cpp @@ -17,159 +17,201 @@ ******************************************************************************/ -#include +#include "sbg/dom_ord_pwmap.hpp" +#include "sbg/interval.hpp" +#include "sbg/ord_set.hpp" +#include "sbg/ord_unidim_dense_set.hpp" +#include "sbg/perimeter.hpp" +#include "sbg/pwmap_detail.hpp" +#include "sbg/set_detail.hpp" +#include "sbg/set_impl.hpp" +#include "util/defs.hpp" +#include "util/debug.hpp" + #include #include - -#include "sbg/map_entry.hpp" -#include "sbg/dom_ord_pwmap.hpp" +#include namespace SBG { namespace LIB { -using Internal::calculatePerimeter; -using Internal::doInt; -using Internal::createMapEntry; -using Internal::operator<; -using Internal::emplaceHint; -using Internal::advanceHint; +namespace detail { //////////////////////////////////////////////////////////////////////////////// // Domain Ordered PWMap Implementation ----------------------------------------- //////////////////////////////////////////////////////////////////////////////// -// Member functions - Domain Ordered Piecewise maps ---------------------------- +// Auxiliary definitions ------------------------------------------------------- + +class MapLess { +public: + bool operator()(const Map& a, const Map& b) const { + return a.domain().minElem() < b.domain().minElem(); + } +}; + +// Constructors/Destructors ---------------------------------------------------- -member_imp(DomOrdPWMap, DomOrdPWMap::OrdMapCollection, pieces); +DomOrdPWMap::DomOrdPWMap() : _pieces() {} -DomOrdPWMap::DomOrdPWMap() : pieces_() {} -DomOrdPWMap::DomOrdPWMap(const Set& s) : pieces_() { +DomOrdPWMap::DomOrdPWMap(const Set& s) : _pieces() { if (!s.isEmpty()) { - SetPiece first = s.begin().operator*(); - pieces_.push_back(createMapEntry(Map(s, Exp(first.arity() - , LExp())))); + _pieces.emplace_back(Map{s, Expression{s.arity(), 1, 0}}); } } -DomOrdPWMap::DomOrdPWMap(const Map& m) : pieces_() { - if (!m.isEmpty()) { - pieces_.push_back(createMapEntry(m)); + +DomOrdPWMap::DomOrdPWMap(const Map& m) : _pieces() { + if (!m.domain().isEmpty()) { + _pieces.emplace_back(m); + } +} + +DomOrdPWMap::DomOrdPWMap(const std::vector& pieces) : _pieces() { + for (const Map& m : pieces) { + insert(m); } } -DomOrdPWMap::DomOrdPWMap(OrdMapCollection pieces) - : pieces_(std::move(pieces)) {} -member_imp(DomOrdPWMap::Iterator, DomOrdPWMap::OrdMapCollection::const_iterator - , it); +DomOrdPWMap::DomOrdPWMap(const DomOrdPWMap::OrdMapCollection& pieces) + : _pieces(pieces) {} + +DomOrdPWMap::DomOrdPWMap(DomOrdPWMap::OrdMapCollection&& pieces) + : _pieces(std::move(pieces)) {} + +// Getters --------------------------------------------------------------------- + +DomOrdPWMap::ConstIt DomOrdPWMap::begin() const { return _pieces.begin(); } -DomOrdPWMap::Iterator::Iterator(OrdMapCollection::const_iterator it) - : it_(it) {} +DomOrdPWMap::ConstIt DomOrdPWMap::end() const { return _pieces.end(); } -void DomOrdPWMap::Iterator::operator++() +// Setters --------------------------------------------------------------------- + +void DomOrdPWMap::insert(const Map& m) { - ++it_; - return; + insert(Map{m}); } -bool DomOrdPWMap::Iterator::operator!=(const PWMapStrategy::Iterator& other) - const +void DomOrdPWMap::insert(Map&& m) { - return it_ != static_cast(&other)->it_; + if (!m.isEmpty()) { + MapEntry entry{m}; + if (isEmpty() || _pieces.back() < entry) { + _pieces.push_back(entry); + } else { + insertHint(0, std::move(m)); + } + } } -const Map& DomOrdPWMap::Iterator::operator*() const { return it_->first; } +void DomOrdPWMap::pushBack(const Map& m) +{ + pushBack(Map{m}); +} -std::shared_ptr DomOrdPWMap::begin() const -{ - return std::make_shared(pieces_.begin()); +void DomOrdPWMap::pushBack(Map&& m) +{ + if (!m.isEmpty()) { + _pieces.emplace_back(std::move(m)); + } } -std::shared_ptr DomOrdPWMap::end() const +void DomOrdPWMap::pushBack(const MapEntry& entry) { - return std::make_shared(pieces_.end()); + pushBack(MapEntry{entry}); } -void DomOrdPWMap::emplaceBack(const Map& m) -{ - if (!m.isEmpty()) { - MapEntry mpe = createMapEntry(m); - if (pieces_.empty() || pieces_.back().second.first < mpe.second.first) { - pieces_.emplace_back(mpe); - } - else { - emplaceHint(pieces_, m, 0); - } +void DomOrdPWMap::pushBack(MapEntry&& entry) +{ + if (!entry.map().isEmpty()) { + _pieces.push_back(std::move(entry)); } } -bool DomOrdPWMap::operator==(const PWMapStrategy& other) const -{ - DomOrdPWMapCRef othr = static_cast(other); +void DomOrdPWMap::insertHint(std::size_t hint, const Map& m) +{ + insertHint(hint, Map{m}); +} - if (dom() != othr.dom()) { - return false; +void DomOrdPWMap::insertHint(std::size_t hint, Map&& m) +{ + if (!m.isEmpty()) { + auto it = _pieces.begin(); + std::advance(it, hint); + auto end = _pieces.end(); + MapEntry map_entry{m}; + while (it != end) { + if (*it < map_entry) { + ++it; + } else { + break; + } + } + _pieces.insert(it, map_entry); } +} - if (pieces_ == othr.pieces_) { - return true; +std::size_t DomOrdPWMap::advanceHint(std::size_t hint, const MapEntry& jth_entry) +{ + auto it = _pieces.begin(); + std::advance(it, hint); + auto end = _pieces.end(); + while (it != end) { + if (*it < jth_entry) { + ++it; + ++hint; + } else { + break; + } } - OrdMapCollection short_pw = pieces_; - OrdMapCollection long_pw = othr.pieces_; - if (othr.pieces_.size() < pieces_.size()) { - short_pw = othr.pieces_; - long_pw = pieces_; - } + return hint; +} + +// Traverse -------------------------------------------------------------------- - // Indexes list corresponding to remaining maps in short_pw +template +Core traverse(const OrdCollection1& lhs, const OrdCollection2& rhs + , Core core_op) +{ + OrdCollection1 short_collection = lhs; + OrdCollection2 long_collection = rhs; + + // Indexes list corresponding to remaining maps in short_collection std::forward_list indexes; - int short_size = short_pw.size(); + int short_size = short_collection.size(); for (int i = short_size - 1; i >= 0; --i) { indexes.push_front(i); } - auto short_begin = short_pw.begin(); - for (const MapEntry& long_mpe : long_pw) { - const Map& long_map = long_mpe.first; - const SetPerimeter& long_sp = long_mpe.second; + auto short_begin = short_collection.begin(); + for (const auto& long_elem : long_collection) { + const Perimeter& long_perimeter = long_elem.perimeter(); auto prev_index = indexes.before_begin(); auto curr_index = indexes.begin(); while (curr_index != indexes.end()) { - const size_t idx = *curr_index; - const MapEntry& short_mpe = *(short_begin + idx); - const Map& short_map = short_mpe.first; - const SetPerimeter& short_sp = short_mpe.second; - - // Here short_map is "before" long_map, so it is also "before" all the - // remaining maps in long_pw, thus it can be discarded. - if (short_sp.second < long_sp.first) { + size_t idx = *curr_index; + const auto& short_elem = *(short_begin + idx); + const Perimeter& short_perimeter = short_elem.perimeter(); + + // Here short_elem is "before" long_elem, so it is also "before" all the + // remaining elements in long_collection, thus it can be discarded. + if (short_perimeter.max() < long_perimeter.min()) { curr_index = indexes.erase_after(prev_index); continue; } - // Here short_map is "after" long_map, so no comparison is needed, and - // the loop of long_pw continues to check if this short_map interacts - // with the following elements of long_pw. - if (long_sp.second < short_sp.first) { + // Here short_elem is "after" long_elem, so no comparison is needed, and + // the loop of long_collection continues to check if this short_map interacts + // with the following elements of long_collection. + if (long_perimeter.max() < short_perimeter.min()) { break; } - // Comparison between short_map and long_map needed. - if (doInt(short_sp, long_sp)) { - Set cap_dom = short_map.dom().intersection(long_map.dom()); - if (!cap_dom.isEmpty()) { - Exp short_exp = short_map.exp(); - Exp long_exp = long_map.exp(); - if (short_exp != long_exp) { - return false; - } - - Map short_cap_map(cap_dom, short_exp); - Map long_cap_map(cap_dom, long_exp); - if (short_cap_map != long_cap_map) { - return false; - } + if (short_perimeter.overlap(long_perimeter)) { + if (!core_op(short_elem, long_elem)) { + return core_op; } } @@ -181,64 +223,108 @@ bool DomOrdPWMap::operator==(const PWMapStrategy& other) const break; } } - - return true; + + return core_op; +} + +// Operators ------------------------------------------------------------------- + +class EqualCore { +public: + bool operator()(const MapEntry& entry1, const MapEntry& entry2) { + Map m1 = entry1.map(); + Map m2 = entry2.map(); + Set cap_domain = m1.domain().intersection(m2.domain()); + if (!cap_domain.isEmpty()) { + Expression expr1 = m1.law(); + Expression expr2 = m2.law(); + if (expr1 != expr2) { + _are_equal = false; + return false; + } + + Map cap_m1{cap_domain, expr1}; + Map cap_m2{cap_domain, expr2}; + if (cap_m1 != cap_m2) { + _are_equal = false; + return false; + } + } + + _are_equal = true; + return true; + } + + bool orderMatters() const { return false; } + + bool result() const { return _are_equal; } + +private: + bool _are_equal = true; +}; + +bool DomOrdPWMap::operator==(const DomOrdPWMap& other) const +{ + if (domain() != other.domain()) { + return false; + } + + if (_pieces == other._pieces) { + return true; + } + + return traverse(_pieces, other._pieces, EqualCore{}).result(); } -bool DomOrdPWMap::operator!=(const PWMapStrategy& other) const +bool DomOrdPWMap::operator!=(const DomOrdPWMap& other) const { return !(*this == other); } -DomOrdPWMap& DomOrdPWMap::operator=(DomOrdPWMap&& other) -{ - pieces_ = std::move(other.pieces_); - - return *this; -} +class AddCore { +public: + bool operator()(const MapEntry& entry1, const MapEntry& entry2) { + Map added = entry1.map() + entry2.map(); + _global_pos = _result.advanceHint(_global_pos, entry2); + _result.insertHint(_global_pos, added); + return true; + } + + bool orderMatters() const { return false; } + + DomOrdPWMap result() const { return _result; } -PWMapStratPtr DomOrdPWMap::operator+(const PWMapStrategy& other) const +private: + DomOrdPWMap _result; + std::size_t _global_pos = 0; +}; + +DomOrdPWMap DomOrdPWMap::operator+(const DomOrdPWMap& other) const { - Set set_in = SET_FACT.createSet(); - Set set_out = SET_FACT.createSet(); - OrdMapCollection result; - processMapsOrd(other, set_in, set_out, result, &DomOrdPWMap::processAdd - , false); - return std::make_unique(std::move(result)); -} + if (isEmpty() || other.isEmpty()) { + return DomOrdPWMap{}; + } -void DomOrdPWMap::processAdd(const Map& m1, const Map& m2, - Set& set_in, Set& set_out, - OrdMapCollection& ord_pwmap, - NAT& global_pos) const -{ - Map res_add = m1 + m2; - advanceHint(ord_pwmap, calculatePerimeter(m2.dom()).first, global_pos); - emplaceHint(ord_pwmap, res_add, global_pos); + return traverse(_pieces, other._pieces, AddCore{}).result(); } std::ostream& DomOrdPWMap::print(std::ostream& out) const { - int sz = pieces_.size(); + int sz = _pieces.size(); out << "<<"; if (sz > 0) { int i = 0; for (; i < sz - 1; ++i) { - out << pieces_[i].first << ", "; + out << _pieces[i].map() << ", "; } - out << pieces_[i].first; + out << _pieces[i].map(); } out << ">>"; return out; } -PWMapStratPtr DomOrdPWMap::clone() const -{ - return std::make_unique(pieces_); -} - // PWMap functions ------------------------------------------------------------- std::size_t DomOrdPWMap::arity() const @@ -247,90 +333,87 @@ std::size_t DomOrdPWMap::arity() const return 0; } - return pieces_.begin()->first.dom().arity(); + return _pieces.begin()->map().domain().arity(); } -bool DomOrdPWMap::isEmpty() const -{ - return pieces_.empty(); -} +bool DomOrdPWMap::isEmpty() const { return _pieces.empty(); } -Set DomOrdPWMap::dom() const +Set DomOrdPWMap::domain() const & { - Set result = SET_FACT.createSet(); - for (const MapEntry& mpe : pieces_) { - Set ith_dom = mpe.first.dom(); - result = std::move(result).disjointCup(std::move(ith_dom)); + Set result; + + for (const MapEntry& entry : _pieces) { + result = std::move(result).disjointCup(entry.map().domain()); } return result; } -PWMapStratPtr DomOrdPWMap::restrict(const Set& subdom) const +Set DomOrdPWMap::domain() && { - OrdMapCollection result; - - if (subdom.isEmpty() || isEmpty()) { - return std::make_unique(); - } + Set result; - // Indexes list corresponding to remaining maps in the pw - std::forward_list indexes; - int sz = pieces_.size(); - for (int i = sz - 1; i >= 0; --i) { - indexes.push_front(i); + for (MapEntry& entry : _pieces) { + result = std::move(result).disjointCup(std::move(entry.map()).domain()); } - auto begin = pieces_.begin(); - for (const SetPiece& mdi : subdom) { - auto prev_index = indexes.before_begin(); - auto curr_index = indexes.begin(); - while (curr_index != indexes.end()) { - size_t idx = *curr_index; - const MapEntry& mpe = *(begin + idx); - const Map& map = mpe.first; - const SetPerimeter& map_sp = mpe.second; - - // Here map is "before" mdi, so it is also "before" all the - // remaining set pieces in subdom, thus it can be discarded. - if (map_sp.second < mdi.minElem()) { - curr_index = indexes.erase_after(prev_index); - continue; - } + return result; +} - // Here map is "after" mdi, so no comparison is needed, and - // the loop of subdom continues to check if this map interacts - // with the following elements of subdom. - if (mdi.maxElem() < map_sp.first) { - break; - } +template +class RestrictCore { +public: + bool operator()(const MapEntry& entry, const T& subdom) { + SetAccessKey key = SetAccess::key(); + Set set_subdom = key.createSet(SetImplT{subdom}); + _result.insert(entry.map().restrict(set_subdom)); - // Comparison between map and mdi needed. - Set mdi_set = SET_FACT.createSet(mdi); - SetPerimeter mdi_sp = calculatePerimeter(mdi_set); - if (doInt(map_sp, mdi_sp)) { - Internal::emplaceBack(result, map.restrict(mdi_set)); - } + return true; + } - ++prev_index; - ++curr_index; - } + bool orderMatters() const { return true; } - if (indexes.empty()) { - break; + DomOrdPWMap result() const { return DomOrdPWMap(std::move(_result)); } + +private: + DomOrdPWMap _result; +}; + +DomOrdPWMap DomOrdPWMap::restrict(const Set& subdom) const +{ + if (isEmpty() || subdom.isEmpty()) { + return DomOrdPWMap{}; + } + + SetAccessKey key = SetAccess::key(); + auto restrict_evaluator = Util::Overload { + [&](const OrderedSet& impl) + { + return traverse(_pieces, key.pieces(impl) + , RestrictCore{}).result(); + }, + [&](const OrdUnidimDenseSet& impl) + { + return traverse(_pieces, key.pieces(impl) + , RestrictCore{}).result(); + }, + [&](const auto& impl) + { + Util::ERROR("DomOrdPWMap::restrict: unsupported ", SET_IMPL.kind() + , " set implementation"); + return DomOrdPWMap{}; } - } + }; - return std::make_unique(std::move(result)); + return std::visit(restrict_evaluator, key.impl(subdom)); } Set DomOrdPWMap::image() const { - Set result = SET_FACT.createSet(); + Set result; - for (const MapEntry& mpe : pieces_) { - Set ith_img = mpe.first.image(); - result = std::move(result).cup(std::move(ith_img)); + for (const MapEntry& entry : _pieces) { + result = std::move(result).cup(entry.map().image()); } return result; @@ -338,101 +421,92 @@ Set DomOrdPWMap::image() const Set DomOrdPWMap::image(const Set& subdom) const { - return restrict(subdom)->image(); + return restrict(subdom).image(); } Set DomOrdPWMap::preImage(const Set& subcodom) const { - Set result = SET_FACT.createSet(); - for (const MapEntry& mpe : pieces_) { - Set ith_pre = mpe.first.preImage(subcodom); - result = std::move(result).disjointCup(std::move(ith_pre)); + Set result; + + for (const MapEntry& entry : _pieces) { + result = std::move(result).disjointCup(entry.map().preImage(subcodom)); } return result; } -PWMapStratPtr DomOrdPWMap::inverse() const -{ - OrdMapCollection result; +DomOrdPWMap DomOrdPWMap::inverse() const +{ + DomOrdPWMap result; - for (const MapEntry& mpe : pieces_) { - Internal::emplaceBack(result, mpe.first.minInv()); + for (const MapEntry& entry : _pieces) { + result.emplace(entry.map().inverse()); } - std::sort(result.begin(), result.end(), operator<); - return std::make_unique(result); + return result; } -PWMapStratPtr DomOrdPWMap::composition(const PWMapStrategy& other) const +DomOrdPWMap DomOrdPWMap::composition(const DomOrdPWMap& other) const { - OrdMapCollection result; - DomOrdPWMapCRef othr = static_cast(other); + DomOrdPWMap result; NAT global_pos = 0; - for (const MapEntry& other_mpe : othr.pieces_) { - const Map& other_map = other_mpe.first; + for (const MapEntry& other_entry : other._pieces) { + Map other_map = other_entry.map(); Set img = other_map.image(); - SetPerimeter image_sp = calculatePerimeter(img); - MD_NAT image_max = image_sp.second; - advanceHint(result, other_mpe.second.first, global_pos); - - for (const MapEntry& this_mpe : pieces_) { - const Map& this_map = this_mpe.first; - const SetPerimeter& this_sp = this_mpe.second; - MD_NAT this_min = this_sp.first; - - if (doInt(this_sp, image_sp)) { - Map composition = this_map.composition(other_map); - if (!composition.isEmpty()) { - emplaceHint(result, composition, global_pos); - } + Perimeter img_perimeter = img.perimeter(); + result.advanceHint(global_pos, other_entry); + MD_NAT img_max_perimeter = img_perimeter.max(); + + for (const MapEntry& entry : _pieces) { + const Perimeter& entry_perimeter = entry.perimeter(); + if (entry_perimeter.overlap(img_perimeter)) { + Map composed = entry.map().composition(other_map); + result.insertHint(global_pos, composed); continue; } - if (image_max < this_min) { + // No possible intersection between the current image and the remaining + // elements of _pieces. + if (img_max_perimeter < entry_perimeter.min()) { break; } } } - return std::make_unique(std::move(result)); + return result; } -PWMapStratPtr DomOrdPWMap::mapInf(unsigned int n) const +DomOrdPWMap DomOrdPWMap::mapInf(unsigned int n) const { - PWMapStratPtr result = std::make_unique(pieces_); + DomOrdPWMap result{_pieces}; - if (!dom().isEmpty()) { + if (!domain().isEmpty()) { for (unsigned int j = 0; j < n; ++j) { - PWMapStratPtr new_res = result->composition(*this); - result = std::move(new_res); + result = composition(result); } - PWMapStratPtr reduced = result->reduce(); - result = std::move(reduced); - PWMapStratPtr old_res = result->clone(); + result = result.reduce(); + DomOrdPWMap old_result{result}; do { - old_res = result->clone(); - - PWMapStratPtr new_res = result->composition(*result); - new_res = new_res->reduce(); - result = std::move(new_res); - } while (*old_res != *result); + old_result = result; + + result = result.composition(result).reduce(); + } while (old_result != result); } - + return result; } -PWMapStratPtr DomOrdPWMap::mapInf() const { return mapInf(0); } +DomOrdPWMap DomOrdPWMap::mapInf() const { return mapInf(0); } Set DomOrdPWMap::fixedPoints() const { - Set result = SET_FACT.createSet(); - for (const MapEntry& mpe : pieces_) { - Set ith_fixed = mpe.first.fixedPoints(); - result = std::move(result).disjointCup(std::move(ith_fixed)); + Set result; + + for (const MapEntry& entry : _pieces) { + result = std::move(result).disjointCup(entry.map().fixedPoints()); } return result; @@ -440,441 +514,333 @@ Set DomOrdPWMap::fixedPoints() const // Extra operations ------------------------------------------------------------ -PWMapStratPtr DomOrdPWMap::concatenation(const PWMapStrategy& other) const +DomOrdPWMap DomOrdPWMap::concatenation(const DomOrdPWMap& other) const & { - OrdMapCollection res; - DomOrdPWMapCRef othr = static_cast(other); - res.reserve(pieces_.size() + othr.pieces_.size()); - - if (isEmpty()) { - return std::make_unique(othr.pieces_); - } - - if (other.isEmpty()) { - return std::make_unique(pieces_); - } - - if (pieces_.back().second.second < othr.pieces_.front().second.first) { - res.insert(res.end(), pieces_.begin(), pieces_.end()); - res.insert(res.end(), othr.pieces_.begin(), othr.pieces_.end()); - return std::make_unique(std::move(res)); - } - - if (othr.pieces_.back().second.second < pieces_.front().second.first) { - res.insert(res.end(), othr.pieces_.begin(), othr.pieces_.end()); - res.insert(res.end(), pieces_.begin(), pieces_.end()); - return std::make_unique(std::move(res)); - } - - auto it1 = pieces_.begin(), it2 = othr.pieces_.begin(); - auto end1 = pieces_.end(), end2 = othr.pieces_.end(); - - for (; it1 != end1 && it2 != end2;) { - auto min_per_m1 = it1->second.first; - auto min_per_m2 = it2->second.first; - - if (min_per_m1 < min_per_m2) { - Internal::emplaceBack(res, *it1); - ++it1; - } else { - Internal::emplaceBack(res, *it2); - ++it2; - } - } - - res.insert(res.end(), it1, end1); - res.insert(res.end(), it2, end2); - return std::make_unique(std::move(res)); + return DomOrdPWMap{*this}.concatenation(other); } -PWMapStratPtr DomOrdPWMap::combine(const PWMapStrategy& other) const +DomOrdPWMap DomOrdPWMap::concatenation(const DomOrdPWMap& other) && { - DomOrdPWMapCRef othr = static_cast(other); - if (isEmpty()) - return std::make_unique(othr.pieces_); - - if (other.isEmpty()) - return std::make_unique(pieces_); + return std::move(*this).concatenation(DomOrdPWMap{other}); +} - if (pieces_ == othr.pieces_) - return std::make_unique(pieces_); +DomOrdPWMap DomOrdPWMap::concatenation(DomOrdPWMap&& other) const & +{ + return DomOrdPWMap{*this}.concatenation(std::move(other)); +} - Set exclusive_other = other.dom().difference(dom()); +DomOrdPWMap DomOrdPWMap::concatenation(DomOrdPWMap&& other) && +{ + // Special cases + if (isEmpty()) { + return std::move(other); + } - return concatenation(*other.restrict(exclusive_other)); -} + if (other.isEmpty()) { + return std::move(*this); + } -PWMapStratPtr DomOrdPWMap::reduce() const -{ OrdMapCollection result; - for (const MapEntry& mpe : pieces_) { - std::vector reduced = mpe.first.reduce(); - for (const Map& reduced_map : reduced) { - Internal::emplaceBack(result, reduced_map); + if (_pieces.back() < other._pieces.front()) { + result.insert(result.end(), std::make_move_iterator(_pieces.begin()) + , std::make_move_iterator(_pieces.end())); + result.insert(result.end(), std::make_move_iterator(other._pieces.begin()) + , std::make_move_iterator(other._pieces.end())); + } else if (other._pieces.back() < _pieces.front()) { + result.insert(result.end(), std::make_move_iterator(other._pieces.begin()) + , std::make_move_iterator(other._pieces.end())); + result.insert(result.end(), std::make_move_iterator(_pieces.begin()) + , std::make_move_iterator(_pieces.end())); + } else { + // General case + auto it1 = _pieces.begin(); + auto end1 = _pieces.end(); + auto it2 = other._pieces.begin(); + auto end2 = other._pieces.end(); + while (it1 != end1 && it2 != end2) { + if (*it1 < *it2) { + result.push_back(*it1); + ++it1; + } else { + result.push_back(*it2); + ++it2; + } } - } + result.insert(result.end(), std::make_move_iterator(it1) + , std::make_move_iterator(end1)); + result.insert(result.end(), std::make_move_iterator(it2) + , std::make_move_iterator(end2)); + } - std::sort(result.begin(), result.end(), operator<); - return std::make_unique(std::move(result)); + return DomOrdPWMap{std::move(result)}; } -PWMapStratPtr DomOrdPWMap::minMap(const PWMapStrategy& other) const +DomOrdPWMap DomOrdPWMap::combine(const DomOrdPWMap& other) const & { - if (isEmpty() || other.isEmpty()) - return std::make_unique(); - - Set min_in_pw1 = lessImage(other); - return restrict(min_in_pw1)->combine(*other.restrict(dom())); + return DomOrdPWMap{*this}.combine(other); } -PWMapStratPtr DomOrdPWMap::minAdjMap(const PWMapStrategy& other) const +DomOrdPWMap DomOrdPWMap::combine(const DomOrdPWMap& other) && { - Set set_in = SET_FACT.createSet(); - Set set_out = SET_FACT.createSet(); - OrdMapCollection res; - processMapsOrd(other, set_in, set_out, res, &DomOrdPWMap::processMinAdjMap, true); - std::sort(res.begin(), res.end(), operator<); - return std::make_unique(res); + return std::move(*this).combine(DomOrdPWMap{other}); } -void DomOrdPWMap::processMinAdjMap(const Map& m1, const Map& m2, - Set& set_in, Set& set_out, - OrdMapCollection& ord_pwmap, - NAT& global_pos) const -{ - Set dom_res = SET_FACT.createSet(); - Set ith_dom = m1.dom().intersection(m2.dom()); - if (!ith_dom.isEmpty()) { - Exp e_res, e1; - - dom_res = m1.image(ith_dom); - e1 = m1.exp(); - - Set im2 = m2.image(ith_dom); - if (!e1.isConstant()) - e_res = m2.exp().composition(e1.inverse()); - else - e_res = MDLExp(im2.minElem()); - - if (!dom_res.isEmpty()) { - Map ith(dom_res, e_res); - DomOrdPWMap ith_pw(ith); - Set again = dom_res.intersection(set_in); - if (!again.isEmpty()) { - DomOrdPWMap ord_pwmap_aux(ord_pwmap); - std::sort(ord_pwmap_aux.pieces_.begin(), ord_pwmap_aux.pieces_.end(), operator<); - PWMapStratPtr aux_res = ord_pwmap_aux.restrict(dom_res); - PWMapStratPtr min_map = aux_res->minMap(ith_pw); - PWMapStratPtr new_resPtr = min_map->combine(ith_pw)->combine(ord_pwmap_aux); - DomOrdPWMapCRef new_res_c = static_cast(*new_resPtr); - ord_pwmap = std::move(new_res_c.pieces_); - Set ith_dom = ith_pw.dom(); - set_in = std::move(set_in).cup(std::move(ith_dom)); - } - else { - Internal::emplaceBack(ord_pwmap, ith); - set_in = std::move(set_in).disjointCup(std::move(dom_res)); - } - } - } +DomOrdPWMap DomOrdPWMap::combine(DomOrdPWMap&& other) const & +{ + return DomOrdPWMap{*this}.combine(std::move(other)); } -PWMapStratPtr DomOrdPWMap::firstInv(const Set& subdom) const +DomOrdPWMap DomOrdPWMap::combine(DomOrdPWMap&& other) && { - OrdMapCollection res; - if (isEmpty() || subdom.isEmpty() ) - return std::make_unique(res); - - SetPerimeter short_sp = calculatePerimeter(subdom); - auto s_max_per = short_sp.second; - Set visited = SET_FACT.createSet(); - - for (const MapEntry& t_mpe : pieces_) { - const Map& t_m = t_mpe.first; - const SetPerimeter& t_sp = t_mpe.second; - auto t_min_per = t_sp.first; - - if (doInt(t_sp, short_sp)) { - Set img = t_m.image(subdom); - - if (!img.isEmpty()) { - if (!visited.isEmpty()) { - SetPerimeter i_sp = calculatePerimeter(img); - SetPerimeter v_sp = calculatePerimeter(visited); - - if (doInt(i_sp, v_sp)) { - Set res_dom = img.difference(visited); - if (!res_dom.isEmpty()) - img = res_dom; - else - continue; - } - } - Map new_map(t_m.preImage(img), t_m.exp()); - Internal::emplaceBack(res, new_map.minInv()); - visited = std::move(visited).disjointCup(std::move(img)); - continue; - } - } - if (s_max_per < t_min_per) { - break; - } + if (isEmpty()) { + return std::move(other); } - std::sort(res.begin(), res.end(), operator<); - - return std::make_unique(res); -} - -PWMapStratPtr DomOrdPWMap::firstInv() const { return firstInv(dom()); } - -PWMapStratPtr DomOrdPWMap::filterMap(bool (*f)(const Map&)) const -{ - OrdMapCollection res; - for (const MapEntry& mpe : pieces_){ - Internal::emplaceBack(res, mpe); + if (other.isEmpty()) { + return std::move(*this); } - - return std::make_unique(res); -} -Set DomOrdPWMap::equalImage(const PWMapStrategy& other) const -{ - if (isEmpty() || other.isEmpty()) - return SET_FACT.createSet(); + if (_pieces == other._pieces) { + return std::move(*this); + } - Set set_in = SET_FACT.createSet(); - Set set_out = SET_FACT.createSet(); - OrdMapCollection unused; - processMapsOrd(other, set_in, set_out, unused, &DomOrdPWMap::processEqualImage - , false); - return set_out; + Set exclusive_other = other.domain().difference(domain()); + return std::move(*this).concatenation(other.restrict(exclusive_other)); } -void DomOrdPWMap::processEqualImage(const Map& m1, const Map& m2, - Set& set_in, Set& set_out, - OrdMapCollection& ord_pwmap, - NAT& global_pos) const -{ - Set cap_dom = m1.dom().intersection(m2.dom()); - if (!cap_dom.isEmpty()) { - Map m1_cap(cap_dom, m1.exp()); - Map m2_cap(cap_dom, m2.exp()); - if (m1_cap == m2_cap) { - set_out = std::move(set_out).disjointCup(std::move(cap_dom)); +DomOrdPWMap DomOrdPWMap::reduce() const +{ + DomOrdPWMap result; + + for (const MapEntry& entry : _pieces) { + std::vector reduced = entry.map().reduce(); + for (Map& reduced_map : reduced) { + result.insert(std::move(reduced_map)); } } -} -Set DomOrdPWMap::lessImage(const PWMapStrategy& other) const -{ - Set set_in = SET_FACT.createSet(); - Set set_out = SET_FACT.createSet(); - OrdMapCollection unused; - processMapsOrd(other, set_in, set_out, unused, &DomOrdPWMap::processLessImage - , true); - return set_out; -} - -void DomOrdPWMap::processLessImage(const Map& m1, const Map& m2, - Set& set_in, Set& set_out, - OrdMapCollection& ord_pwmap, - NAT& global_pos) const -{ - Set ith_less = m1.lessImage(m2); - set_out = std::move(set_out).disjointCup(std::move(ith_less)); + return result; } -void DomOrdPWMap::processMapsOrd( - const PWMapStrategy& other, - Set& set_in, - Set& set_out, - OrdMapCollection& ord_map, - ProcessFunc process, - bool order_mts - ) const +DomOrdPWMap DomOrdPWMap::min(const DomOrdPWMap& other) const { - DomOrdPWMapCRef othr = static_cast(other); + if (isEmpty() || other.isEmpty()) { + return DomOrdPWMap{}; + } - int sz = pieces_.size(); - int othr_sz = othr.pieces_.size(); - ord_map.reserve(2*(sz + othr_sz)); + Set min_in_pw1 = lessImage(other); + return restrict(min_in_pw1).combine(other.restrict(domain())); +} + +class MinAdjCore { +public: + bool operator()(const MapEntry& entry1, const MapEntry& entry2) { + Map min_adj = entry1.map().minAdj(entry2.map()); + if (!min_adj.isEmpty()) { + Set min_adj_domain = min_adj.domain(); + Set repeated = min_adj_domain.intersection(_visited); + if (!repeated.isEmpty()) { + DomOrdPWMap min_adj_pw{std::move(min_adj)}; + DomOrdPWMap min_adj_repeated = min_adj_pw.restrict(repeated); + DomOrdPWMap result_repeated = _result.restrict(repeated); + DomOrdPWMap min_map = min_adj_repeated.min(result_repeated); + DomOrdPWMap min_adj_result = std::move(min_map).combine( + std::move(min_adj_pw)); + _result = std::move(min_adj_result).combine(std::move(_result)); + _visited = std::move(_visited).cup(std::move(min_adj_domain)); + } else { + _result.insert(std::move(min_adj)); + _visited = std::move(_visited).disjointCup(std::move(min_adj_domain)); + } + } - const DomOrdPWMap *short_pw = this; - const DomOrdPWMap *long_pw = &othr; - if (!order_mts && othr_sz < sz) { - short_pw = &othr; - long_pw = this; + return true; } - std::forward_list indexes; - auto si_it = indexes.before_begin(); + bool orderMatters() const { return true; } + + DomOrdPWMap result() const { return _result; } - const size_t short_size = short_pw->pieces_.size(); - for (size_t i = 0; i < short_size; ++i) { - si_it = indexes.insert_after(si_it, i); +private: + DomOrdPWMap _result; + Set _visited; +}; + +DomOrdPWMap DomOrdPWMap::minAdj(const DomOrdPWMap& other) const +{ + if (isEmpty() || other.isEmpty()) { + return DomOrdPWMap{}; } - auto short_begin = short_pw->pieces_.begin(); - NAT global_pos = 0; - for (const MapEntry& long_mpe : long_pw->pieces_ ) { - const Map& long_map = long_mpe.first; - const SetPerimeter& long_sp = long_mpe.second; - - auto prev_index = indexes.before_begin(); - auto curr_index = indexes.begin(); - while (curr_index != indexes.end()) { - size_t idx = *curr_index; - const MapEntry& short_mpe = *(short_begin + idx); - const Map& short_map = short_mpe.first; - const SetPerimeter& short_sp = short_mpe.second; + return traverse(_pieces, other._pieces, MinAdjCore{}).result(); +} - // Here short_map is "before" long_map, so it is also "before" all the - // remaining maps in long_pw, thus it can be discarded. - if (short_sp.second < long_sp.first) { - curr_index = indexes.erase_after(prev_index); - continue; - } +Set DomOrdPWMap::sharedImage() const +{ + Set repeated_image; + Set visited; + for (const MapEntry& entry : _pieces) { + Set m_image = entry.map().image(); + Set image_in_visited = m_image.intersection(visited); + if (!image_in_visited.isEmpty()) { + repeated_image = std::move(repeated_image).cup(std::move( + image_in_visited)); + } + visited = std::move(visited).cup(m_image); + } - // Here short_map is "after" long_map, so no comparison is needed, and - // the loop of long_pw continues to check if this short_map interacts - // with the following elements of long_pw. - if (long_sp.second < short_sp.first) { - break; - } + return preImage(repeated_image); +} - // Comparison between short_map and long_map needed. - if (doInt(short_sp, long_sp)) { - (this->*process)(short_map, long_map, set_in, set_out, ord_map - , global_pos); +class EqualImageCore { +public: + bool operator()(const MapEntry& entry1, const MapEntry& entry2) { + Map m1 = entry1.map(); + Map m2 = entry2.map(); + Set cap_dom = m1.domain().intersection(m2.domain()); + if (!cap_dom.isEmpty()) { + Map m1_cap{cap_dom, m1.law()}; + Map m2_cap{cap_dom, m2.law()}; + if (m1_cap == m2_cap) { + _result = std::move(_result).disjointCup(std::move(cap_dom)); } - - ++prev_index; - ++curr_index; } - if (indexes.empty()) { - break; - } + return true; } -} -Set DomOrdPWMap::sharedImage() const -{ - Set not_present = dom().difference(firstInv()->image()); - Set res = preImage(image(not_present)); + bool orderMatters() const { return false; } - return res; -} + Set result() const { return _result; } -PWMapStratPtr DomOrdPWMap::offsetDom(const MD_NAT& off) const +private: + Set _result; +}; + +Set DomOrdPWMap::equalImage(const DomOrdPWMap& other) const { - OrdMapCollection res; + if (isEmpty() || other.isEmpty()) { + return Set{}; + } - for (const MapEntry& mpe : pieces_){ - Map map(mpe.first.dom().offset(off), mpe.first.exp()); - Internal::emplaceBack(res, map); + if (_pieces == other._pieces) { + return domain(); } - return std::make_unique(res); + return traverse(_pieces, other._pieces, EqualImageCore{}).result(); } -PWMapStratPtr DomOrdPWMap::offsetDom(const PWMapStrategy& off) const -{ - OrdMapCollection res; - const SetPerimeter o_sp = calculatePerimeter(off.dom()); - const auto o_max_per = o_sp.second; - for (const MapEntry& t_mpe : pieces_) { - const Map& t_m = t_mpe.first; - const SetPerimeter& t_sp = t_mpe.second; - const auto m_min_per = t_sp.first; - - if (doInt(t_sp, o_sp)) { - Set ith_dom = off.image(t_m.dom()); - - if (!ith_dom.isEmpty()){ - Map res_map(ith_dom, t_m.exp()); - Internal::emplaceBack(res, res_map); - } - continue; - } - - if (o_max_per < m_min_per) - break; +class LessImageCore { +public: + bool operator()(const MapEntry& entry1, const MapEntry& entry2) { + Set less_map = entry1.map().lessImage(entry2.map()); + _result = std::move(_result).disjointCup(std::move(less_map)); + + return true; } - std::sort(res.begin(),res.end(), operator<); - - return std::make_unique(res); + bool orderMatters() const { return true; } -} + Set result() const { return _result; } -PWMapStratPtr DomOrdPWMap::offsetImage(const MD_NAT& off) const -{ - OrdMapCollection res; +private: + Set _result; +}; - for (const MapEntry& mpe : pieces_) { - Exp e = mpe.first.exp(), res_e; - for (unsigned int j = 0; j < e.arity(); ++j) { - LExp res_lexp(e[j].slope(), e[j].offset() + (RATIONAL) off[j]); - res_e.emplaceBack(res_lexp); - } +Set DomOrdPWMap::lessImage(const DomOrdPWMap& other) const +{ + if (isEmpty() || other.isEmpty()) { + return Set{}; + } - Internal::emplaceBack(res, Map(mpe.first.dom(), res_e)); + if (_pieces == other._pieces) { + return Set{}; } - return std::make_unique(res); -} + return traverse(_pieces, other._pieces, LessImageCore{}).result(); +} -PWMapStratPtr DomOrdPWMap::offsetImage(const Exp& off) const +DomOrdPWMap DomOrdPWMap::imageMultiplicity() const { - OrdMapCollection res; + Map initial_result{image(), Expression{arity(), 0, 0}}; + DomOrdPWMap result{initial_result}; - for (const MapEntry& mpe : pieces_) - Internal::emplaceBack(res, Map(mpe.first.dom(), off + mpe.first.exp())); + for (const MapEntry& entry : _pieces) { + DomOrdPWMap jth_mult{entry.map().imageMultiplicity()}; + DomOrdPWMap sum_mult = jth_mult + result; + result = std::move(sum_mult).combine(std::move(result)); + } - return std::make_unique(res); -} + return result; +} -PWMapStratPtr DomOrdPWMap::compact() const +void DomOrdPWMap::compact() { - OrdMapCollection result; + using MapSet = std::set; + + DomOrdPWMap result; if (!isEmpty()) { - std::set prev(pieces_.begin(), pieces_.end()); - std::set actual = prev; + MapSet set_result; + for (const MapEntry& entry : _pieces) { + const Map& m = entry.map(); + Set new_domain = m.domain(); + new_domain.compact(); + set_result.emplace(new_domain, m.law()); + } + + MapSet to_erase; do { - prev = actual; - actual = std::set(); + MapSet new_set_result; + to_erase.clear(); - std::set::iterator ith = prev.begin(); - std::set::iterator last = prev.end(); - std::set to_erase; + MapSet::iterator ith = set_result.begin(); + MapSet::iterator last = set_result.end(); for (; ith != last; ++ith) { - Map ith_compact = ith->first; - std::set::iterator next = ith; + Map ith_compact = *ith; + MapSet::iterator next = ith; ++next; for (; next != last; ++next) { - MaybeMap new_compact = ith_compact.compact(next->first); + MaybeMap new_compact = ith_compact.compact(*next); if (new_compact) { ith_compact = new_compact.value(); to_erase.insert(*next); } } - if (to_erase.find(*ith) == to_erase.end()) - actual.insert(createMapEntry(ith_compact)); + if (to_erase.find(ith_compact) == to_erase.end()) { + new_set_result.insert(ith_compact); + } } - } while (actual != prev); - for (const MapEntry& mdi : actual) { - result.emplace_back(mdi); + std::swap(set_result, new_set_result); + } while (!to_erase.empty()); + + for (const Map& m : set_result) { + result.insert(m); } } - return std::make_unique(result); + _pieces = std::move(result._pieces); +} + +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(DomOrdPWMap pw + , rapidjson::Document::AllocatorType& alloc) +{ + rapidjson::Value result{rapidjson::kArrayType}; + + for (const MapEntry& entry : pw) { + rapidjson::Value jth = toJSON(entry.map(), alloc); + result.PushBack(jth, alloc); + } + + return result; } +} // namespace detail + } // namespace LIB } // namespace SBG; diff --git a/sbg/dom_ord_pwmap.hpp b/sbg/dom_ord_pwmap.hpp index f713659c..be6eefd7 100644 --- a/sbg/dom_ord_pwmap.hpp +++ b/sbg/dom_ord_pwmap.hpp @@ -2,9 +2,9 @@ @brief Domain Ordered PWMap Implementation - Domain ordered and map ordered piecewise map implementation. The evaluator will - be in charge of checking that the choosen set implementation is ordered when - this structure is used. + Ordered piecewise implementation, that assumes an ordered set implementation. + The evaluator will be in charge of checking that the choosen set + implementation is ordered when this structure is used.
@@ -25,187 +25,164 @@ ******************************************************************************/ -#ifndef SBG_DOM_ORD_PWMAP_HPP -#define SBG_DOM_ORD_PWMAP_HPP +#ifndef SBGRAPH_SBG_DOM_ORD_PWMAP_HPP_ +#define SBGRAPH_SBG_DOM_ORD_PWMAP_HPP_ -#include "sbg/ord_pwmap.hpp" +#include "sbg/map.hpp" +#include "sbg/map_entry.hpp" +#include "sbg/set.hpp" + +#include "rapidjson/document.h" + +#include +#include namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// -// Domain Ordered PWMap Implementation (concrete strategy) --------------------- +// Domain ordered PWMap Implementation ----------------------------------------- //////////////////////////////////////////////////////////////////////////////// -struct DomOrdPWMap : public OrdPWMap { - using SetPerimeter = OrdPWMap::SetPerimeter; - using MapEntry = OrdPWMap::MapEntry; - using OrdMapCollection = OrdPWMap::OrdMapCollection; - - member_class(OrdMapCollection, pieces); +class DomOrdPWMap { +public: + using OrdMapCollection = std::vector; + using ConstIt = OrdMapCollection::const_iterator; - ~DomOrdPWMap() = default; DomOrdPWMap(); DomOrdPWMap(const Set& s); DomOrdPWMap(const Map& m); - DomOrdPWMap(OrdMapCollection pieces); - - struct Iterator : public PWMapStrategy::Iterator { - member_class(OrdMapCollection::const_iterator, it); - - Iterator(OrdMapCollection::const_iterator it); - void operator++() override; - bool operator!=(const PWMapStrategy::Iterator& other) const override; - const Map& operator*() const override; - }; - - std::shared_ptr begin() const override; - std::shared_ptr end() const override; + DomOrdPWMap(const std::vector& pieces); + DomOrdPWMap(const OrdMapCollection& pieces); + DomOrdPWMap(OrdMapCollection&& pieces); - void emplaceBack(const Map& m) override; + ConstIt begin() const; + ConstIt end() const; - bool operator==(const PWMapStrategy& other) const override; - bool operator!=(const PWMapStrategy& other) const override; - DomOrdPWMap& operator=(DomOrdPWMap&& other); - std::ostream& print(std::ostream& out) const override; + template + void emplace(Args&&... args); + void insert(const Map& m); + void insert(Map&& m); - PWMapStratPtr operator+(const PWMapStrategy& other) const override; - - PWMapStratPtr clone() const override; + bool operator==(const DomOrdPWMap& other) const; + bool operator!=(const DomOrdPWMap& other) const; + DomOrdPWMap operator+(const DomOrdPWMap& other) const; + std::ostream& print(std::ostream& out) const; // Traditional map operations ------------------------------------------------ - std::size_t arity() const override; - bool isEmpty() const override; - Set dom() const override; - PWMapStratPtr restrict(const Set& subdom) const override; - Set image() const override; - Set image(const Set& subdom) const override; - Set preImage(const Set& subcodom) const override; - PWMapStratPtr inverse() const override; - PWMapStratPtr composition(const PWMapStrategy& pw2) const override; + std::size_t arity() const; + bool isEmpty() const; + Set domain() const &; + Set domain() &&; + DomOrdPWMap restrict(const Set& subdom) const; + Set image() const; + Set image(const Set& subdom) const; + Set preImage(const Set& subcodom) const; + DomOrdPWMap inverse() const; + DomOrdPWMap composition(const DomOrdPWMap& other) const; - PWMapStratPtr mapInf(unsigned int n) const override; - PWMapStratPtr mapInf() const override; - Set fixedPoints() const override; + DomOrdPWMap mapInf() const; + Set fixedPoints() const; // Extra operations ---------------------------------------------------------- - PWMapStratPtr concatenation(const PWMapStrategy& other) const override; - PWMapStratPtr combine(const PWMapStrategy& other) const override; - PWMapStratPtr reduce() const override; + DomOrdPWMap concatenation(const DomOrdPWMap& other) const &; + DomOrdPWMap concatenation(const DomOrdPWMap& other) &&; + DomOrdPWMap concatenation(DomOrdPWMap&& other) const &; + DomOrdPWMap concatenation(DomOrdPWMap&& other) &&; + DomOrdPWMap combine(const DomOrdPWMap& other) const &; + DomOrdPWMap combine(const DomOrdPWMap& other) &&; + DomOrdPWMap combine(DomOrdPWMap&& other) const &; + DomOrdPWMap combine(DomOrdPWMap&& other) &&; - PWMapStratPtr minMap(const PWMapStrategy& other) const override; - PWMapStratPtr minAdjMap(const PWMapStrategy& other) const override; + DomOrdPWMap min(const DomOrdPWMap& other) const; + DomOrdPWMap minAdj(const DomOrdPWMap& other) const; - PWMapStratPtr firstInv(const Set& subdom) const override; - PWMapStratPtr firstInv() const override; + Set sharedImage() const; + Set equalImage(const DomOrdPWMap& other) const; + Set lessImage(const DomOrdPWMap& other) const; - PWMapStratPtr filterMap(bool (*f)(const Map& )) const override; + DomOrdPWMap imageMultiplicity() const; - Set equalImage(const PWMapStrategy& other) const override; - Set lessImage(const PWMapStrategy& other) const override; - Set sharedImage() const override; + void compact(); - PWMapStratPtr offsetDom(const MD_NAT& off) const override; - PWMapStratPtr offsetDom(const PWMapStrategy& off) const override; - PWMapStratPtr offsetImage(const MD_NAT& off) const override; - PWMapStratPtr offsetImage(const Exp& off) const override; +private: + template + void emplaceBack(Args&&... args); + void pushBack(const Map& m); + void pushBack(Map&& m); + void pushBack(const MapEntry& entry); + void pushBack(MapEntry&& entry); - PWMapStratPtr compact() const override; - - private: - /** - * @brief Calculates the minAdjMap core, which contains the entire main process - * of the function. - */ - void processMinAdjMap( - const Map& m1, - const Map& m2, - Set& set_in, - Set& set_out, - OrdMapCollection& ord_pwmap, - NAT& global_pos) const; - - /** - * @brief Calculates the minus core, which contains the entire main process of - * the function. - */ - void processMinus( - const Map& m1, - const Map& m2, - Set& set_in, - Set& set_out, - OrdMapCollection& ord_pwmap, - NAT& global_pos) const; - - /** - * @brief Calculates the add core, which contains the entire main process of - * the function. - */ - void processAdd( - const Map& m1, - const Map& m2, - Set& set_in, - Set& set_out, - OrdMapCollection& ord_pwmap, - NAT& global_pos) const; + void insertHint(std::size_t hint, const Map& m); + void insertHint(std::size_t hint, Map&& m); /** - * @brief Calculates the lessImage core, which contains the entire main - * process of the function. + * @brief Advances the hint to point the next element that has jth_entry as + * its minimum in its perimeter. */ - void processLessImage( - const Map& m1, - const Map& m2, - Set& set_in, - Set& set_out, - OrdMapCollection& ord_pwmap, - NAT& global_pos) const; - - /** - * @brief Calculates the equalImage core, which contains the entire main - * process of the function. - */ - void processEqualImage( - const Map& m1, - const Map& m2, - Set& set_in, - Set& set_out, - OrdMapCollection& ord_pwmap, - NAT& global_pos) const; - + std::size_t advanceHint(std::size_t hint, const MapEntry& jth_entry); + /** - * @brief Type used in the 'processMapsOrd' declaration to reduce its size. - * This type is the same as the process functions above. + * @brief Calculates (if possible) compactly the result of mapInf.\n + * + * Currently, the only expressions that can be efficiently reduced are: + * - x+h + * - x-h */ - using ProcessFunc = void (DomOrdPWMap::*)( - const Map& , const Map& , - Set& , Set& , OrdMapCollection&, - NAT& - ) const; - - /** - * @brief Provides an efficient method for processing two ordered piecewise - * maps. + DomOrdPWMap reduce() const; + + /* + * @brief First compose the pw with itself \p n times, obtaining pw'. Then, + * compose pw' with itself up to convergence. */ - void processMapsOrd( - const PWMapStrategy& other, - Set& set_in, - Set& set_out, - OrdMapCollection& ord_pwmap, - ProcessFunc process, - bool order_mts - ) const; + DomOrdPWMap mapInf(unsigned int n) const; + + OrdMapCollection _pieces; + + friend class AddCore; + friend class MinAdjCore; + template + friend class RestrictCore; + friend class PWMapAccessKey; }; -typedef const DomOrdPWMap& DomOrdPWMapCRef; -typedef DomOrdPWMap& DomOrdPWMapRef; -typedef std::unique_ptr DomOrdPWMapPtr; +// Template definitions -------------------------------------------------------- + +template +inline void DomOrdPWMap::emplace(Args&&... args) +{ + auto&& domain = std::get<0>(std::forward_as_tuple(args...)); + if (!domain.isEmpty()) { + insert(Map{std::forward(args)...}); + } +} + +template +inline void DomOrdPWMap::emplaceBack(Args&&... args) +{ + auto&& domain = std::get<0>(std::forward_as_tuple(args...)); + if (!domain.isEmpty()) { + _pieces.emplace_back(std::forward(args)...); + } +} + +template +Core traverse(const OrdCollection1& lhs, const OrdCollection2& rhs, Core op); + +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(DomOrdPWMap pw + , rapidjson::Document::AllocatorType& alloc); + +} // namespace detail } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_DOM_ORD_PWMAP_HPP_ diff --git a/sbg/expression.cpp b/sbg/expression.cpp new file mode 100755 index 00000000..dcabdd2f --- /dev/null +++ b/sbg/expression.cpp @@ -0,0 +1,243 @@ +/******************************************************************************* + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "sbg/expression.hpp" + +namespace SBG { + +namespace LIB { + +// Constructors/Destructors ---------------------------------------------------- + +Expression::Expression() : _impl() {} + +Expression::Expression(const MD_NAT& x) +{ + for (const NAT xj : x) { + _impl.emplace_back(detail::LinearExpr{0, RATIONAL{static_cast(xj)}}); + } +} + +Expression::Expression(const RATIONAL& slope, const RATIONAL& offset) : _impl() +{ + _impl.emplace_back(detail::LinearExpr{slope, offset}); +} + +Expression::Expression(std::size_t n, const RATIONAL& slope + , const RATIONAL& offset) + : _impl() +{ + detail::LinearExpr linear_expr{slope, offset}; + for (unsigned int k = 0; k < n; ++k) { + _impl.emplace_back(linear_expr); + } +} + +Expression::Expression(const MD_NAT& from, const MD_NAT& to) +{ + for (unsigned int k = 0; k < from.arity(); ++k) { + _impl.emplace_back(1, to[k] - from[k]); + } +} + +Expression::Expression(const detail::ExpressionImpl& impl) : _impl(impl) {} + +Expression::Expression(detail::ExpressionImpl&& impl) + : _impl(std::move(impl)) {} + +// Setters (private) ----------------------------------------------------------- + +detail::LinearExpr& Expression::operator[](std::size_t n) { return _impl[n]; } + +const detail::LinearExpr &Expression::operator[](std::size_t n) const +{ + return _impl[n]; +} + +// Operators ------------------------------------------------------------------- + +bool Expression::operator==(const Expression& other) const +{ + return _impl == other._impl; +} + +bool Expression::operator!=(const Expression& other) const +{ + return !(*this == other); +} + +Expression Expression::operator+(const Expression& other) const +{ + Expression result; + + for (unsigned int k = 0; k < arity(); ++k) { + result._impl.emplace_back(operator[](k) + other[k]); + } + + return result; +} + +Expression Expression::operator-(const Expression& other) const +{ + Expression result; + + for (unsigned int k = 0; k < arity(); ++k) { + result._impl.emplace_back(operator[](k) - other[k]); + } + + return result; +} + +std::ostream& Expression::print(std::ostream& out) const +{ + unsigned int sz = arity(); + + out << "|"; + if (sz > 0) { + for (unsigned int k = 0; k < sz-1; ++k) { + out << _impl[k] << "|"; + } + out << _impl[sz-1]; + } + out << "|"; + + return out; +} + +std::ostream& operator<<(std::ostream& out, const Expression& expr) +{ + expr.print(out); + return out; +} + +// Linear expression functions ------------------------------------------------- + +std::size_t Expression::arity() const { return _impl.size(); } + +MD_NAT Expression::apply(const MD_NAT& x) const +{ + MD_NAT result; + + for (unsigned int k = 0; k < _impl.size(); ++k) { + result.pushBack(_impl[k].apply(x[k])); + } + + return result; +} + +Expression Expression::composition(const Expression& other) const +{ + Expression result; + + for (unsigned int k = 0; k < arity(); ++k) { + result._impl.emplace_back(operator[](k).composition(other[k])); + } + + return result; +} + +Expression Expression::inverse() const +{ + Expression result; + + for (const detail::LinearExpr& le : _impl) { + result._impl.emplace_back(le.inverse()); + } + + return result; +} + +bool Expression::isId() const +{ + for (const detail::LinearExpr& le : _impl) { + if (!le.isId()) { + return false; + } + } + + return true; +} + +bool Expression::isConstant() const +{ + for (const detail::LinearExpr& le : _impl) { + if (!le.isConstant()) { + return false; + } + } + + return true; +} + +bool Expression::isInjective() const +{ + for (const detail::LinearExpr& linear_expr : _impl) { + if (!linear_expr.isInjective()) { + return false; + } + } + + return true; +} + +FixedPointsInfo Expression::fixedPoints() const +{ + std::vector result; + + for (unsigned int k = 0; k < arity(); ++k) { + detail::LinearExpr kth = _impl[k]; + if (kth.isId()) { + result.emplace_back(Solution{SolutionKind::kFree}); + } else if (kth.isConstant()) { + result.emplace_back(Solution{SolutionKind::kFixed, kth.offset().toNat()}); + } else { + return {}; + } + } + + return FixedPointsInfo{result}; +} + +Expression Expression::cartesianProduct(const Expression& other) const +{ + Expression result; + + result._impl.insert(result._impl.end(), _impl.begin(), _impl.end()); + result._impl.insert(result._impl.end(), other._impl.begin() + , other._impl.end()); + + return result; +} + +rapidjson::Value Expression::toJSON(rapidjson::Document::AllocatorType& alloc) + const +{ + rapidjson::Value result{rapidjson::kArrayType}; + + for (const detail::LinearExpr& le : _impl) { + rapidjson::Value jth = detail::toJSON(le, alloc); + result.PushBack(jth, alloc); + } + + return result; +} + +} // namespace LIB + +} // namespace SBG diff --git a/sbg/expression.hpp b/sbg/expression.hpp new file mode 100755 index 00000000..40feee5c --- /dev/null +++ b/sbg/expression.hpp @@ -0,0 +1,149 @@ +/** @file expression.hpp + + @brief Multi-dimensional Expression implementation + + The current implementation for expressions that will be used as laws to define + maps is an ordered collection of linear expressions. + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_SBG_EXPRESSION_HPP_ +#define SBGRAPH_SBG_EXPRESSION_HPP_ + +#include "sbg/expression_impl.hpp" +#include "sbg/fixed_points.hpp" +#include "sbg/linear_expr.hpp" +#include "sbg/multidim_inter.hpp" + +#include "rapidjson/document.h" + +#include + +namespace SBG { + +namespace LIB { + +namespace detail { + +class MapDetail; + +} // namespace detail + +class Expression { +public: + /** + * @brief Empty multi-dimensional expression constructor. + */ + Expression(); + + /** + * @brief Constructs a constant mdle in all dimensions that maps to \p x. + */ + Expression(const MD_NAT& x); + + /** + * @brief Constructs a one-dimensional linear expression. + */ + Expression(const RATIONAL& slope, const RATIONAL& offset); + + /** + * @brief Constructs a multi-dimensional expression of arity \p nmbr_copies + * with \p the same linear expression in each dimension. + */ + Expression(std::size_t n, const RATIONAL& slope, const RATIONAL& offset); + + /** + * @brief Creates an injective expression that maps the first argument to the + * second one. + */ + Expression(const MD_NAT& from, const MD_NAT& to); + + bool operator==(const Expression& other) const; + bool operator!=(const Expression& other) const; + Expression operator+(const Expression& other) const; + Expression operator-(const Expression& other) const; + std::ostream& print(std::ostream& out) const; + + // Traditional expression operations ----------------------------------------- + + /** + * @brief Number of dimensions of the mdle, i.e. arity(1*x+0 | 1*x+0) = 2. + */ + std::size_t arity() const; + + MD_NAT apply(const MD_NAT& x) const; + + /** + * @brief Calculate the composition of \p this with \p other, i.e. + * \p this(\p other). + */ + Expression composition(const Expression& other) const; + + /** + * @brief Calculates the inverse dimension by dimension. + * Precondition: the expression in each dimension should be bijective for all + * naturals. + */ + Expression inverse() const; + + // Extra operations ---------------------------------------------------------- + + bool isId() const; + bool isConstant() const; + + /** + * @brief Checks if the expression is injective for all multi-dimensional + * naturals. + */ + bool isInjective() const; + + /** + * @brief Calculates all the elements x ∈ [0:1:Inf]^k such that replacing x + * in the current expression returns x as result. + */ + FixedPointsInfo fixedPoints() const; + + /** + * @brief Given two expressions f and g such that arity(f) = n and + * arity(g) = m it returns an expression h such that arity(h) = n+m and + * g(x1, ..., x(n+m)) = (f(x1, ..., xn), g(x(n+1), ..., x(n+m))) flattened. + */ + Expression cartesianProduct(const Expression& other) const; + + rapidjson::Value toJSON(rapidjson::Document::AllocatorType& alloc) const; + +private: + detail::ExpressionImpl _impl; + + Expression(const detail::ExpressionImpl& impl); + Expression(detail::ExpressionImpl&& impl); + + detail::LinearExpr& operator[](std::size_t n); + const detail::LinearExpr& operator[](std::size_t n) const; + + friend class detail::MapDetail; +}; +std::ostream& operator<<(std::ostream& out, const Expression& mdle); + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_SBG_EXPRESSION_HPP_ diff --git a/sbg/expression_impl.hpp b/sbg/expression_impl.hpp new file mode 100755 index 00000000..b0f72fc5 --- /dev/null +++ b/sbg/expression_impl.hpp @@ -0,0 +1,44 @@ +/** @file expression_impl.hpp + + @brief Multi-dimensional Expression implementation + + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_SBG_EXPRESSION_IMPL_HPP_ +#define SBGRAPH_SBG_EXPRESSION_IMPL_HPP_ + +#include "sbg/linear_expr.hpp" + +namespace SBG { + +namespace LIB { + +namespace detail { + +using ExpressionImpl = std::vector; + +} // namespace detail + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_SBG_EXPRESSION_IMPL_HPP_ diff --git a/sbg/fixed_points.cpp b/sbg/fixed_points.cpp new file mode 100755 index 00000000..cbd07d08 --- /dev/null +++ b/sbg/fixed_points.cpp @@ -0,0 +1,37 @@ +/******************************************************************************* + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "sbg/fixed_points.hpp" + +namespace SBG { + +namespace LIB { + +Solution::Solution(const SolutionKind kind) : _kind(kind), _value() {} + +Solution::Solution(const SolutionKind kind, const NAT value) + : _kind(kind), _value(value) {} + +const SolutionKind& Solution::kind() const { return _kind; } + +const std::optional& Solution::value() const { return _value; } + +} // namespace LIB + +} // namespace SBG diff --git a/sbg/fixed_points.hpp b/sbg/fixed_points.hpp new file mode 100755 index 00000000..7ad2524b --- /dev/null +++ b/sbg/fixed_points.hpp @@ -0,0 +1,59 @@ +/** @file fixed_points.hpp + + @brief Fixed Points Information + + Interface for fixed points information that will be interchanged between sets + and expressions. + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_SBG_FIXED_POINTS_HPP_ +#define SBGRAPH_SBG_FIXED_POINTS_HPP_ + +#include "sbg/natural.hpp" + +#include + +namespace SBG { + +namespace LIB { + +enum class SolutionKind { kFree, kFixed }; + +class Solution { +public: + Solution(const SolutionKind kind); + Solution(const SolutionKind kind, const NAT value); + + const SolutionKind& kind() const; + const std::optional& value() const; + +private: + std::optional _value; + SolutionKind _kind; +}; + +using FixedPointsInfo = std::optional>; + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_SBG_FIXED_POINTS_HPP_ diff --git a/sbg/interval.cpp b/sbg/interval.cpp index 3a878389..75def842 100755 --- a/sbg/interval.cpp +++ b/sbg/interval.cpp @@ -19,58 +19,101 @@ #include "sbg/interval.hpp" +#include +#include +#include + namespace SBG { namespace LIB { -member_imp(Interval, NAT, begin); -member_imp(Interval, NAT, step); -member_imp(Interval, NAT, end); +namespace detail { + +// Auxiliary functions --------------------------------------------------------- + +bool isMember(const SBG::LIB::NAT x, const SBG::LIB::detail::Interval& i) +{ + if (x < i.begin() || x > i.end()) { + return false; + } + + int rem = fmod(x - i.begin(), i.step()); + return rem == 0; +} + +// Constructors/Destructors ---------------------------------------------------- + +Interval::Interval() : _begin(1), _step(1), _end(0) {} -Interval::Interval() : begin_(1), step_(1), end_(0) {} -Interval::Interval(NAT x) : begin_(x), step_(1), end_(x) {} -Interval::Interval(NAT begin, NAT step, NAT end) - : begin_(begin), step_(step), end_(end) +Interval::Interval(const NAT x) : _begin(x), _step(1), _end(x) {} + +Interval::Interval(const NAT begin, const NAT step, const NAT end) + : _begin(begin), _step(step), _end(end) { if (end >= begin) { int rem = fmod(end - begin, step); - end_ = end - rem; - - if (begin_ == end_) - step_ = 1; + _end = end - rem; + _step = _begin == _end ? 1 : _step; + } else { + _begin = 1; + _step = 1; + _end = 0; } +} - else { - begin_ = 1; - step_ = 1; - end_ = 0; - } +// Getters --------------------------------------------------------------------- + +const NAT& Interval::begin() const +{ + return _begin; +} + +const NAT& Interval::step() const +{ + return _step; +} + +const NAT& Interval::end() const +{ + return _end; } // Operators ------------------------------------------------------------------- -bool Interval::operator==(const Interval &other) const +bool operator==(const Interval& lhs, const Interval& rhs) { - return (begin_ == other.begin_) - && (step_ == other.step_) - && (end_ == other.end_); + return (lhs.begin() == rhs.begin()) && (lhs.step() == rhs.step()) + && (lhs.end() == rhs.end()); } -bool Interval::operator!=(const Interval &other) const +bool operator!=(const Interval& lhs, const Interval& rhs) { - return !(*this == other); + if (lhs.begin() != rhs.begin()) { + return true; + } + + if (lhs.step() != rhs.step()) { + return true; + } + + if (lhs.end() != rhs.end()) { + return true; + } + + return false; } -bool Interval::operator<(const Interval &other) const +bool Interval::operator<(const Interval& other) const { - return begin_ < other.begin_; + return _begin < other._begin; } -std::ostream &operator<<(std::ostream &out, const Interval &i) +std::ostream& operator<<(std::ostream& out, const Interval& i) { out << "[" << i.begin(); - if (i.step() != 1) + if (i.step() != 1) { out << ":" << i.step(); + } out << ":" << i.end() << "]"; return out; @@ -80,85 +123,93 @@ std::ostream &operator<<(std::ostream &out, const Interval &i) unsigned int Interval::cardinal() const { - return (end_ - begin_) / step_ + 1; + return (_end - _begin) / _step + 1; } -bool Interval::isEmpty() const { return end_ < begin_; } +bool Interval::isEmpty() const { return _end < _begin; } -bool Interval::isMember(NAT x) const -{ - if (x < begin_ || x > end_) - return false; +NAT Interval::minElem() const { return _begin; } - int rem = fmod(x - begin_, step_); +NAT Interval::maxElem() const { return _end; } - return rem == 0; -} - -Interval Interval::intersection(const Interval &other)const +Interval Interval::intersection(const Interval& other) const { - if (isEmpty() || other.isEmpty()) - return Interval(); + if (isEmpty() || other.isEmpty()) { + return Interval{}; + } - if ((end_ < other.begin_) || (other.end_ < begin_)) - return Interval(); + if ((_end < other._begin) || (other._end < _begin)) { + return Interval{}; + } // Two non overlapping intervals with the same step - if (step_ == other.step_ - && !other.isMember(begin_) - && !isMember(other.begin_)) - return Interval(); - - NAT max_begin = std::max(begin_, other.begin_); - NAT new_step = std::lcm(step_, other.step_) - , new_begin = max_begin - , new_end = std::min(end_, other.end_); + if (_step == other._step && !isMember(_begin, other) + && !isMember(other._begin, *this)) { + return Interval{}; + } + + NAT max_begin = std::max(_begin, other._begin); + NAT new_step = std::lcm(_step, other._step); + NAT new_begin = max_begin; + NAT new_end = std::min(_end, other._end); bool found_member = false; - for (NAT x = max_begin; x < max_begin + new_step; ++x) - if (isMember(x) && other.isMember(x)) { + for (NAT x = max_begin; x < max_begin + new_step; ++x) { + if (isMember(x, *this) && isMember(x, other)) { new_begin = x; found_member = true; } + } - if (found_member) - return Interval(new_begin, new_step, new_end); + if (found_member) { + return Interval{new_begin, new_step, new_end}; + } - return Interval(1, 1, 0); + return Interval{}; } // Extra operations ------------------------------------------------------------ -Interval Interval::offset(NAT off) const +Interval Interval::offset(const NAT off) const { - NAT new_b = begin_ + off, new_e = end_ + off; - - return Interval(new_b, step_, new_e); + return Interval{_begin + off, _step, _end + off}; } -Interval Interval::least(const Interval &other) const -{ - return std::min(*this, other); -} +Perimeter Interval::perimeter() const { return Perimeter(_begin, _end); } -MaybeInterval Interval::compact(const Interval &other) const +MaybeInterval Interval::compact(const Interval& other) const { - if (step_ == other.step_) { - if (end_+step_ == other.begin_) - return Interval(begin_, step_, other.end_); - - else if (other.end_+step_ == begin_) - return Interval(other.begin_, step_, end_); - - else if (!intersection(other).isEmpty()) { - NAT new_b = std::min(begin_, other.begin_); - NAT new_e = std::max(end_, other.end_); - return Interval(new_b, step_, new_e); + if (_step == other._step) { + if (_end + _step == other._begin) { + return Interval{_begin, _step, other._end}; + } else if (other._end + _step == _begin) { + return Interval{other._begin, _step, _end}; + } else if (!intersection(other).isEmpty()) { + return Interval{std::min(_begin, other._begin), _step + , std::max(_end, other._end)}; } } return {}; } +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(Interval i, rapidjson::Document::AllocatorType& alloc) +{ + rapidjson::Value result{rapidjson::kArrayType}; + + rapidjson::Value begin{static_cast(i.begin())}; + result.PushBack(begin, alloc); + rapidjson::Value step{static_cast(i.step())}; + result.PushBack(step, alloc); + rapidjson::Value end{static_cast(i.end())}; + result.PushBack(end, alloc); + + return result; +} + +} // namespace detail + } // namespace LIB } // namespace SBG diff --git a/sbg/interval.hpp b/sbg/interval.hpp index 59415708..1ed623b5 100755 --- a/sbg/interval.hpp +++ b/sbg/interval.hpp @@ -28,26 +28,29 @@ ******************************************************************************/ -#ifndef SBG_INTERVAL_HPP -#define SBG_INTERVAL_HPP - -#include +#ifndef SBGRAPH_SBG_INTERVAL_HPP_ +#define SBGRAPH_SBG_INTERVAL_HPP_ #include "sbg/natural.hpp" +#include "sbg/perimeter.hpp" + +#include "rapidjson/document.h" + +#include +#include namespace SBG { namespace LIB { +namespace detail { + class Interval; -typedef std::optional MaybeInterval; +using MaybeInterval = std::optional; class Interval { - member_class(NAT, begin); - member_class(NAT, step); - member_class(NAT, end); - +public: /** * @brief Construct an empty interval. */ @@ -56,24 +59,18 @@ class Interval { /** * @brief Construct an interval only containing \p x. */ - Interval(NAT x); + Interval(const NAT x); /** * @brief Construct an interval with \p begin, \p step and \p end. */ - Interval(NAT begin, NAT step, NAT end); + Interval(const NAT begin, const NAT step, const NAT end); - bool operator==(const Interval &i) const; - bool operator!=(const Interval &i) const; + const NAT& begin() const; + const NAT& step() const; + const NAT& end() const; - /** - * @brief An interval i1 is less than another interval i2 iff - * min(i1) < min(i2). This operation is later needed to implement ordered - * sets. - */ - bool operator<(const Interval &i) const; - - // Traditional set operations ------------------------------------------------ + bool operator<(const Interval& other) const; /** * @brief Number of elements contained in the interval, i.e. @@ -81,32 +78,43 @@ class Interval { */ unsigned int cardinal() const; bool isEmpty() const; - bool isMember(NAT x) const; - Interval intersection(const Interval &i2) const; - - // Extra operations ---------------------------------------------------------- + NAT minElem() const; + NAT maxElem() const; + Interval intersection(const Interval& other) const; /** * @brief Sum a constant value to every element of the interval. */ - Interval offset(NAT off) const; + Interval offset(const NAT off) const; - /** - * @brief Operation that given two disjoint intervals returns the lesser one. - * It will be used by ordered sets operations. - */ - Interval least(const Interval &i2) const; + Perimeter perimeter() const; /** * @brief Merge two contiguous intervals if possible. If not, then the result * is not an interval, so no value is returned. */ - MaybeInterval compact(const Interval &i2) const; + MaybeInterval compact(const Interval& other) const; + +private: + NAT _begin; + NAT _step; + NAT _end; }; -std::ostream &operator<<(std::ostream &out, const Interval &i); + +bool operator==(const Interval& lhs, const Interval& rhs); + +bool operator!=(const Interval& lhs, const Interval& rhs); + +std::ostream& operator<<(std::ostream& out, const Interval& i); + +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(Interval i, rapidjson::Document::AllocatorType& alloc); + +} // namespace detail } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_INTERVAL_HPP_ diff --git a/sbg/lexp.cpp b/sbg/lexp.cpp deleted file mode 100755 index 1555e42d..00000000 --- a/sbg/lexp.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/******************************************************************************* - - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -#include "sbg/lexp.hpp" - -namespace SBG { - -namespace LIB { - -LExp::LExp() : slope_(1), offset_(0) {} -LExp::LExp(RATIONAL slope, RATIONAL offset) : slope_(slope), offset_(offset) {} - -member_imp(LExp, RATIONAL, slope); -member_imp(LExp, RATIONAL, offset); - -bool LExp::operator==(const LExp &other) const -{ - return slope_ == other.slope_ && offset_ == other.offset_; -} - -bool LExp::operator!=(const LExp &other) const { return !(*this == other); } - -LExp LExp::operator+(const LExp &other) const -{ - return LExp(slope_ + other.slope_, offset_ + other.offset_); -} - -LExp LExp::operator-(const LExp &other) const -{ - return LExp(slope_ - other.slope_, offset_ - other.offset_); -} - -std::ostream &operator<<(std::ostream &out, const LExp &le) -{ - RATIONAL slo = le.slope(), off = le.offset(); - - if (slo != 0 && slo != 1) { - if (slo.numerator() != 1) - out << slo.numerator(); - - if (slo.denominator() != 1) - out << "x/" << slo.denominator(); - - else - out << "x"; - } - - if (slo == 1) - out << "x"; - - if (off != 0) { - if (off > 0 && slo != 0) - out << "+" << off; - - else - out << off; - } - - if (slo == 0 && off == 0) - out << "0"; - - return out; -} - -// Linear expression functions ------------------------------------------------- - -LExp LExp::composition(const LExp &other)const -{ - RATIONAL new_slope = other.slope_ * slope_; - RATIONAL new_offset = slope_ * other.offset_ + offset_; - - return LExp(new_slope, new_offset); -} - -LExp LExp::inverse() const -{ - RATIONAL zero, one(1); - RATIONAL new_slope(0, 1), new_offset(0, 1); - - // Non constant map - if (slope_ != 0) { - new_slope = RATIONAL(slope_.denominator(), slope_.numerator()); - new_offset = (-offset_)/slope_; - } - - // Constant map - else { - new_slope = RATIONAL(INT_Inf, 1); - new_offset = RATIONAL(-INT_Inf, 1); - } - - return LExp(new_slope, new_offset); -} - -bool LExp::isId() const { return slope_ == 1 && offset_ == 0; } - -bool LExp::isConstant() const { return slope_ == 0; } - -bool LExp::isIncreasing() const { return slope_ > 0; } - -RATIONAL LExp::intersectionPoint(const LExp& other) const -{ - return (other.offset_ - offset_)/(slope_ - other.slope_); -} - -} // namespace LIB - -} // namespace SBG diff --git a/sbg/lexp.hpp b/sbg/lexp.hpp deleted file mode 100755 index de565c7d..00000000 --- a/sbg/lexp.hpp +++ /dev/null @@ -1,83 +0,0 @@ -/** @file lexp.hpp - - @brief Linear expressions implementation - - A linear expression m*x+h is determined by its slope and offset. It will be - used as the law of maps. - -
- - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -#ifndef SBG_LEXP_HPP -#define SBG_LEXP_HPP - -#include "sbg/rational.hpp" - -namespace SBG { - -namespace LIB { - -class LExp { - member_class(RATIONAL, slope); - member_class(RATIONAL, offset); - - /** - * @brief Identity constructor. - */ - LExp(); - - /** - * @brief Construct a linear expression defining the \p slope and \p offset. - */ - LExp(RATIONAL slope, RATIONAL offset); - - bool operator==(const LExp &other) const; - bool operator!=(const LExp &other) const; - - LExp operator+(const LExp &other) const; - LExp operator-(const LExp &other) const; - - // Tradiotional le operations ------------------------------------------------ - - /** - * @brief Calculate the composition of \p this with \p other, i.e. - * \p this(\p other). - */ - LExp composition(const LExp &other) const; - - /** - * @brief Calculates the inverse of a linear expression. If it is not bijective - * , i.e. it is constant, then it returns inf*x-inf. - */ - LExp inverse() const; - - // Extra operations ---------------------------------------------------------- - - bool isId() const; - bool isConstant() const; - bool isIncreasing() const; - RATIONAL intersectionPoint(const LExp& other) const; -}; -std::ostream &operator<<(std::ostream &out, const LExp &le); - -} // namespace LIB - -} // namespace SBG - -#endif diff --git a/sbg/linear_expr.cpp b/sbg/linear_expr.cpp new file mode 100755 index 00000000..c361747e --- /dev/null +++ b/sbg/linear_expr.cpp @@ -0,0 +1,164 @@ +/******************************************************************************* + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "sbg/linear_expr.hpp" + +#include +#include + +namespace SBG { + +namespace LIB { + +namespace detail { + +// Constructors/Destructors ---------------------------------------------------- + +LinearExpr::LinearExpr() : _slope(1), _offset(0) {} + +LinearExpr::LinearExpr(RATIONAL slope, RATIONAL offset) + : _slope(slope), _offset(offset) {} + +// Getters --------------------------------------------------------------------- + +const RATIONAL& LinearExpr::slope() const { return _slope; } + +const RATIONAL& LinearExpr::offset() const { return _offset; } + +// Operators ------------------------------------------------------------------- + +bool LinearExpr::operator==(const LinearExpr& other) const +{ + return _slope == other._slope && _offset == other._offset; +} + +bool LinearExpr::operator!=(const LinearExpr& other) const +{ + return !(*this == other); +} + +LinearExpr LinearExpr::operator+(const LinearExpr& other) const +{ + return LinearExpr{_slope + other._slope, _offset + other._offset}; +} + +LinearExpr LinearExpr::operator-(const LinearExpr& other) const +{ + return LinearExpr{_slope - other._slope, _offset - other._offset}; +} + +std::ostream& operator<<(std::ostream& out, const LinearExpr& le) +{ + RATIONAL slo = le.slope(), off = le.offset(); + + if (slo != 0 && slo != 1) { + if (slo.numerator() != 1) { + out << slo.numerator(); + } + + if (slo.denominator() != 1) { + out << "x/" << slo.denominator(); + } else { + out << "x"; + } + } + + if (slo == 1) { + out << "x"; + } + + if (off != 0) { + if (off > 0 && slo != 0) { + out << "+" << off; + } else { + out << off; + } + } + + if (slo == 0 && off == 0) { + out << "0"; + } + + return out; +} + +// Linear expression functions ------------------------------------------------- + +NAT LinearExpr::apply(const NAT& x) const +{ + return (_slope*x + _offset).toNat(); +} + +LinearExpr LinearExpr::composition(const LinearExpr& other) const +{ + RATIONAL new_slope = other._slope*_slope; + RATIONAL new_offset = _slope*other._offset + _offset; + + return LinearExpr{new_slope, new_offset}; +} + +LinearExpr LinearExpr::inverse() const +{ + RATIONAL zero; + RATIONAL one{1}; + + RATIONAL new_slope{0, 1}; + RATIONAL new_offset{0, 1}; + new_slope = RATIONAL{_slope.denominator(), _slope.numerator()}; + new_offset = (-_offset)/_slope; + + return LinearExpr{new_slope, new_offset}; +} + +bool LinearExpr::isId() const { return _slope == 1 && _offset == 0; } + +bool LinearExpr::isConstant() const { return _slope == 0; } + +bool LinearExpr::isInjective() const { return _slope != 0; } + +RATIONAL LinearExpr::intersectionPoint(const LinearExpr& other) const +{ + return (other._offset - _offset)/(_slope - other._slope); +} + +rapidjson::Value toJSON(LinearExpr le + , rapidjson::Document::AllocatorType& alloc) +{ + rapidjson::Value result{rapidjson::kArrayType}; + + std::stringstream ssm; + ssm << le.slope(); + rapidjson::Value m; + m.SetString(ssm.str().c_str(), strlen(ssm.str().c_str()), alloc); + result.PushBack(m, alloc); + + std::stringstream ssh; + ssh << le.offset(); + rapidjson::Value h; + h.SetString(ssh.str().c_str(), strlen(ssh.str().c_str()), alloc); + result.PushBack(h, alloc); + + return result; +} + +} // namespace detail + +} // namespace LIB + +} // namespace SBG diff --git a/sbg/linear_expr.hpp b/sbg/linear_expr.hpp new file mode 100755 index 00000000..a61a5b65 --- /dev/null +++ b/sbg/linear_expr.hpp @@ -0,0 +1,114 @@ +/** @file linear_expr.hpp + + @brief Linear expressions implementation + + A linear expression m*x+h is determined by its slope and offset. It will be + used as the law of maps. + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_SBG_LINEAR_EXPR_HPP_ +#define SBGRAPH_SBG_LINEAR_EXPR_HPP_ + +#include "sbg/rational.hpp" + +#include "rapidjson/document.h" + +#include + +namespace SBG { + +namespace LIB { + +namespace detail { + +class LinearExpr { +public: + /** + * @brief Identity constructor. + */ + LinearExpr(); + + /** + * @brief Construct a linear expression defining the \p slope and \p offset. + */ + LinearExpr(RATIONAL slope, RATIONAL offset); + + const RATIONAL& slope() const; + const RATIONAL& offset() const; + + bool operator==(const LinearExpr &other) const; + bool operator!=(const LinearExpr &other) const; + LinearExpr operator+(const LinearExpr &other) const; + LinearExpr operator-(const LinearExpr &other) const; + + // Traditional linear expression operations ---------------------------------- + + /** + * @brief Calculates the result of applying the linear expression to \p x. + * Precondition: result is >= 0. + */ + NAT apply(const NAT& x) const; + + /** + * @brief Calculate the composition of \p this with \p other, i.e. + * \p this(\p other). + */ + LinearExpr composition(const LinearExpr &other) const; + + /** + * @brief Calculates the inverse of a linear expression. + * Precondition: slope should be non-zero. + */ + LinearExpr inverse() const; + + // Extra operations ---------------------------------------------------------- + + bool isId() const; + bool isConstant() const; + + /** + * @brief Checks if the expression is injective for all naturals. + */ + bool isInjective() const; + + /** + * Precondition: both slopes should be different. + */ + RATIONAL intersectionPoint(const LinearExpr& other) const; + +private: + RATIONAL _slope; + RATIONAL _offset; +}; +std::ostream &operator<<(std::ostream &out, const LinearExpr& le); + +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(LinearExpr le + , rapidjson::Document::AllocatorType& alloc); + +} // namespace detail + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_SBG_LINEAR_EXPR_HPP_ diff --git a/sbg/map.cpp b/sbg/map.cpp index dfe54653..4ae864ec 100755 --- a/sbg/map.cpp +++ b/sbg/map.cpp @@ -18,176 +18,48 @@ ******************************************************************************/ #include "sbg/map.hpp" +#include "sbg/map_detail.hpp" + +#include namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Auxiliary functions --------------------------------------------------------- +// Map Implementation ---------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -// Image ----------------------------------------------------------------------- - -Interval image(Interval i, LExp le) { - RATIONAL m = le.slope(), h = le.offset(); - NAT new_begin = 0, new_step = 0, new_end = 0; +// Constructors/Destructors ---------------------------------------------------- - RATIONAL rat_inf(INT_Inf, 1); - if (m == rat_inf || m > rat_inf) - return Interval(0, 1, Inf); +Map::Map() : _domain() {} - if (le.isId()) { - return i; - } - - if (le.isConstant()) { - NAT off = le.offset().toNat(); - return Interval(off, 1, off); - } +Map::Map(const MD_NAT& x, const Expression& expr) + : _domain(x), _law(expr) {} - if (i.begin() == i.end()) { - NAT x = (m * i.begin() + h).toNat(); - return Interval(x, 1, x); - } +Map::Map(const Set& s, const Expression& expr) : _domain(s), _law(expr) {} - // Increasing expression - if (m > 0) { - new_begin = (m * i.begin() + h).toNat(); - new_step = (m * i.step()).toNat(); - new_end = (m * i.end() + h).toNat(); - } +Map::Map(Set&& s, Expression&& expr) + : _domain(std::move(s)), _law(std::move(expr)) {} - // Decreasing expression - else if (m < 0) { - new_begin = (m * i.end() + h).toNat(); - new_step = (-m * i.step()).toNat(); - new_end = (m * i.begin() + h).toNat(); - } +// Getters --------------------------------------------------------------------- - return Interval(new_begin, new_step, new_end); -} +const Set& Map::domain() const & { return _domain; } -SetPiece image(SetPiece mdi, Exp mdle) -{ - if (mdi.isEmpty()) - return mdi; +Set Map::domain() && { return std::move(_domain); } - SetPiece res; - for (unsigned int j = 0; j < mdi.arity(); ++j) - res.emplaceBack(image(mdi[j], mdle[j])); +const Expression& Map::law() const { return _law; } - return res; -} - -// Reduction ------------------------------------------------------------------- - -bool reductionIsEfficient(const Map& m) -{ - int count = 0; - for (const LExp& le : m.exp()) { - if (le.slope() != 1 && le.slope() != 0) { - return false; - } - - if (le.slope() == 1 && le.offset() != 0) { - ++count; - } - } - - return count == 1; -} - -std::vector reduce(int k, const SetPiece& mdi, const Exp& e) -{ - std::vector result; - - // Special cases - if (mdi.cardinal() == 1) { - result.emplace_back(Map(mdi, e)); - return result; - } - - // No partition of the piece is needed - RATIONAL zero(0, 1); - INT h = e[k].offset().toInt(); - Interval i = mdi[k]; - NAT st = i.step(); - Exp e_copy = e; - if (h == (INT) st) { - NAT hi = i.end(); - if (st < Inf - hi) { - e_copy[k] = LExp(zero, hi + st); - result.emplace_back(Map(mdi, e_copy)); - return result; - } - } else if (h == (INT) -st) { - NAT lo = i.begin(); - if (lo >= st) { - e_copy[k] = LExp(zero, lo - st); - result.emplace_back(Map(mdi, e_copy)); - return result; - } - } - - // Partition of the piece needed - if (h % (INT) st == 0) { - SetPiece mdi_copy = mdi; - // Is convenient the partition of the piece? - if ((INT) i.cardinal() > h*h) { - INT absh = std::abs(h); - for (int j = 1; j <= absh; ++j) { - NAT new_begin = i.begin() + j - 1; - Interval jth_piece(new_begin, (NAT) absh, i.end()); - mdi_copy[k] = jth_piece; - - RATIONAL jth_off; - if (h > 0) { - jth_off = jth_piece.end() + h; - } - else { - jth_off = jth_piece.begin() + h; - } - - e_copy[k] = LExp(0, jth_off); - result.emplace_back(Map(mdi_copy, e_copy)); - } - } else { - result.emplace_back(Map(mdi, e)); - } - } else { - result.emplace_back(Map(mdi, e)); - } - - return result; -} - -//////////////////////////////////////////////////////////////////////////////// -// Map Implementation ---------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -member_imp(Map, Set, dom); -member_imp(Map, Exp, exp); - -Map::~Map() {} -Map::Map() : dom_(SET_FACT.createSet()) {} -Map::Map(MD_NAT x, Exp exp) - : dom_(SET_FACT.createSet(x)), exp_(exp) {} -Map::Map(Interval i, LExp le) - : dom_(SET_FACT.createSet(i)), exp_(Exp(le)) {} -Map::Map(SetPiece mdi, Exp exp) - : dom_(SET_FACT.createSet(mdi)), exp_(exp) {} -Map::Map(Set s, Exp exp) - : dom_(std::move(s)), exp_(exp) {} +// Operators ------------------------------------------------------------------- bool Map::operator==(const Map& other) const { - if (dom_ == other.dom()) { - if (dom_.cardinal() == 1) { + if (_domain == other._domain) { + if (_domain.cardinal() == 1) { return image() == other.image(); + } else { + return _law == other._law; } - else - return exp_ == other.exp(); } return false; @@ -198,247 +70,166 @@ bool Map::operator!=(const Map& other) const return !(*this == other); } -Map& Map::operator=(const Map& other) -{ - dom_ = other.dom_; - exp_ = other.exp_; - - return *this; -} - Map Map::operator+(const Map& other) const { - Set res_dom = dom_.intersection(other.dom()); - Exp res_exp = exp_ + other.exp(); + Set result_domain = _domain.intersection(other._domain); + Expression result_law = _law + other._law; - return Map(res_dom, res_exp); + return Map{std::move(result_domain), std::move(result_law)}; } std::ostream& operator<<(std::ostream& out, const Map& m) { - out << m.dom() << " -> " << m.exp(); - + out << m.domain() << " -> " << m.law(); return out; } // Map operations -------------------------------------------------------------- -std::size_t Map::arity() const { return exp_.arity(); } +std::size_t Map::arity() const { return _law.arity(); } -bool Map::isEmpty() const { return dom_.isEmpty(); } +bool Map::isEmpty() const { return _domain.isEmpty(); } -Map Map::restrict(const Set& subdom) const +Map Map::restrict(const Set& subdom) const & { - return Map(dom_.intersection(subdom), exp_); + return Map{_domain.intersection(subdom), _law}; } -Set Map::image() const { return image(dom_); } +Map Map::restrict(const Set& subdom) && +{ + return Map{std::move(_domain).intersection(subdom), _law}; +} -Set Map::image(const Set& subdom) const +Map Map::restrict(Set&& subdom) const & { - Set res = SET_FACT.createSet(); + return Map{_domain.intersection(std::move(subdom)), _law}; +} - if (subdom.isEmpty()) - return res; +Set Map::image() const { return image(_domain); } - Set capdom = dom_.intersection(subdom); - if (capdom.isEmpty()) { - return res; - } else { - // Check if all expressions are bijective; if so all partial images can be - // added without further checks - bool cond = true; - for (const LExp& le : exp_) { - if (le.isConstant()) { - cond = false; - } - } +Set Map::image(const Set& subdom) const +{ + if (isEmpty() || subdom.isEmpty()) { + return Set{}; + } - if (cond) { - for (const SetPiece& mdi : capdom) { - res.emplaceBack(SBG::LIB::image(mdi, exp_)); - } - } - else { - for (const SetPiece& mdi : capdom) { - Set ith_img = SET_FACT.createSet(SBG::LIB::image(mdi, exp_)); - res = std::move(res).cup(std::move(ith_img)); - } - } + Set domain_subdom = _domain.intersection(subdom); + if (domain_subdom.isEmpty()) { + return Set{}; } - return res; + return detail::MapDetail::image(domain_subdom, _law); } Set Map::preImage(const Set& subcodom) const { - Set im = image(); - Set cap_subcodom = im.intersection(subcodom); - if (cap_subcodom.isEmpty()) - return SET_FACT.createSet(); - - RATIONAL rat_inf(INT_Inf, 1); - Set inv_dom = cap_subcodom; - Exp inv_exp = exp_.inverse(); - for (unsigned int j = 0; j < inv_exp.arity(); ++j) { - RATIONAL m = exp_[j].slope(), h = exp_[j].offset(); - if (m == rat_inf && h == -rat_inf) { - for (SetPiece mdi : cap_subcodom) - mdi[j] = Interval(0, 1, Inf); - inv_exp[j] = LExp(1, 0); - } + Set image_subcodom = image().intersection(subcodom); + return detail::MapDetail::preImage(image_subcodom, _law) + .intersection(_domain); +} + +Map Map::inverse() const +{ + if (_domain.cardinal() == 1) { + return Map{image(), _domain.minElem()}; } - Map inv(cap_subcodom, inv_exp); - Set inv_im = inv.image(); - return dom_.intersection(inv_im); + return Map{image(), _law.inverse()}; } Map Map::composition(const Map& other) const { - Set res_dom = dom_.intersection(other.image()); - if (!res_dom.isEmpty()) { - res_dom = other.preImage(res_dom); + Set result_domain = _domain.intersection(other.image()); + if (!result_domain.isEmpty()) { + result_domain = other.preImage(result_domain); } - Exp res_exp = exp_.composition(other.exp_); + Expression result_law = _law.composition(other._law); - return Map(res_dom, res_exp); + return Map{std::move(result_domain), std::move(result_law)}; } Set Map::fixedPoints() const { - Interval univ_one_dim(0, 1, Inf); - SetPiece allowed; - for (unsigned int j = 0; j < arity(); ++j) { - LExp jth = exp_[j]; - - if (jth.isId()) - allowed.emplaceBack(univ_one_dim); - - else if (jth.isConstant()) - allowed.emplaceBack(Interval(jth.offset().toNat())); - - else - return SET_FACT.createSet(); - } - - return dom_.intersection(SET_FACT.createSet(allowed)); + FixedPointsInfo fixed_points_info = _law.fixedPoints(); + Set universal_fixed{fixed_points_info}; + return _domain.intersection(std::move(universal_fixed)); } // Extra operations ------------------------------------------------------------ -Map Map::minInv() const -{ - Set res_dom = image(); - Exp res_exp; - - if (dom_.cardinal() == 1 || exp_.isConstant()) - res_exp = Exp(dom_.minElem()); - else - res_exp = exp_.inverse(); - - return Map(res_dom, res_exp); -} - bool Map::isId() const { - if (dom_.cardinal() == 1) - return dom_ == image(); + if (_domain.cardinal() == 1) { + return _domain == image(); + } - return exp_.isId(); + return _law.isId(); } Set Map::lessImage(const Map& other) const { - Set result = SET_FACT.createSet(); - - int ar = arity(); - SetPiece min_in_m1(ar, Interval(0, 1, Inf)); - Exp exp1 = exp_; - Exp exp2 = other.exp_; - - Set cap_dom = dom_.intersection(other.dom_); - if (cap_dom.isEmpty()) - return cap_dom; - - for (int k = 0; k < ar; ++k) { - LExp linear_exp1 = exp1[k]; - LExp linear_exp2 = exp2[k]; - - RATIONAL m1 = linear_exp1.slope(); - RATIONAL m2 = linear_exp2.slope(); - if (m1 == m2) { - RATIONAL h1 = linear_exp1.offset(); - RATIONAL h2 = linear_exp2.offset(); - if (h1 < h2) { - result.emplaceBack(min_in_m1); - } - break; - } - else { - RATIONAL point = linear_exp1.intersectionPoint(linear_exp2); - if (point >= 0) { - NAT floor = point.floor(); - NAT ceil = point.ceiling(); - if (ceil == floor) { - NAT floor_minus = floor == 0 ? 0 : floor - 1; - NAT ceil_plus = ceil == Inf ? Inf : ceil + 1; - Interval kth = m1 < m2 ? Interval(ceil_plus, 1, Inf) - : Interval (0, 1, floor_minus); - min_in_m1[k] = kth; - result.emplaceBack(min_in_m1); - min_in_m1[k] = Interval(ceil, 1, floor); - } - else { - break; - } - } - else { - if (m1 < m2) { - result.emplaceBack(min_in_m1); - } - break; - } - } + Set cap_dom = _domain.intersection(other._domain); + if (cap_dom.isEmpty()) { + return cap_dom; } - result = result.intersection(cap_dom); - return result; + Set result = detail::MapDetail::lessImage(_law, other._law); + return result.intersection(cap_dom); } -std::vector Map::reduce() const +Map Map::minAdj(const Map& other) const { - std::vector result; + Set this_other_dom = _domain.intersection(other._domain); + if (this_other_dom.isEmpty()) { + return Map{}; + } - Map m = *this; - if (!reductionIsEfficient(m)) { - result.emplace_back(m); + Set result_domain = image(this_other_dom); + Expression result_expr; + if (_law.isInjective()) { + result_expr = other._law.composition(_law.inverse()); } else { - Exp e = m.exp(); - for (auto k = 0; k < m.arity(); ++k) { - LExp le = e[k]; - if (le.slope() == 1 && le.offset() != 0) { - for (const SetPiece& mdi : m.dom()) { - std::vector reduced = SBG::LIB::reduce(k, mdi, e); - result.insert(result.end(), reduced.begin(), reduced.end()); - } - } - } + Set image2 = other.image(this_other_dom); + result_expr = Expression{image2.minElem()}; } - return result; + return Map{result_domain, result_expr}; +} + +std::vector Map::reduce() const +{ + return detail::MapDetail::reduce(*this); +} + +std::vector Map::imageMultiplicity() const +{ + return detail::MapDetail::imageMultiplicity(*this); } MaybeMap Map::compact(const Map& other) const { - Set res_dom = SET_FACT.createSet(); - if (exp_ == other.exp()) { - return Map(dom_.cup(other.dom()).compact(), exp_); + Set result_domain; + if (_law == other.law()) { + Set result_dom = _domain.disjointCup(other.domain()); + result_dom.compact(); + return Map{std::move(result_dom), Expression{_law}}; } return {}; } +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(Map m, rapidjson::Document::AllocatorType& alloc) +{ + rapidjson::Value result{rapidjson::kObjectType}; + + result.AddMember("domain", m.domain().toJSON(alloc), alloc); + result.AddMember("law", m.law().toJSON(alloc), alloc); + + return result; +} + } // namespace LIB } // namespace SBG diff --git a/sbg/map.hpp b/sbg/map.hpp index 8a034fbc..8de564ab 100755 --- a/sbg/map.hpp +++ b/sbg/map.hpp @@ -26,11 +26,18 @@ ******************************************************************************/ -#ifndef SBG_MAP_HPP -#define SBG_MAP_HPP +#ifndef SBGRAPH_SBG_MAP_HPP_ +#define SBGRAPH_SBG_MAP_HPP_ -#include "sbg/set_fact.hpp" -#include "sbg/multidim_lexp.hpp" +#include "sbg/natural.hpp" +#include "sbg/expression.hpp" +#include "sbg/set.hpp" + +#include "rapidjson/document.h" + +#include +#include +#include namespace SBG { @@ -38,19 +45,10 @@ namespace LIB { class Map; -typedef std::optional MaybeMap; +using MaybeMap = std::optional; -/** - * @brief Implementation of maps. Every map has as member a SetFact that keeps - * track of the chosen implementation for Sets. - */ class Map { - public: - member_class(Set, dom); - member_class(Exp, exp); - - ~Map(); - +public: /** * @brief Construct a map with empty domain and expression. */ @@ -60,28 +58,21 @@ class Map { * @brief Construct a map with a single element \p x in its domain, and with * \p exp as its law. */ - Map(MD_NAT x, Exp exp); - - /** - * @brief Construct a map with all the elements of \p i in its domain, and law - * \p le. - */ - Map(Interval i, LExp le); - - /** - * @brief Construct a map with all the elements of \p mdi in its domain, and - * law \p exp. - */ - Map(SetPiece mdi, Exp exp); + Map(const MD_NAT& x, const Expression& expr); + Map(MD_NAT&& x, Expression&& expr); /** * @brief Construct a map defining its domain as \p s and law as \p exp. */ - Map(Set s, Exp exp); + Map(const Set& s, const Expression& expr); + Map(Set&& s, Expression&& expr); + + const Set& domain() const &; + Set domain() &&; + const Expression& law() const; bool operator==(const Map& other) const; bool operator!=(const Map& other) const; - Map& operator=(const Map& other); /** * @brief Calculates the sum of both maps for elements that belong to both @@ -92,8 +83,8 @@ class Map { // Traditional map operations ------------------------------------------------ /** - * @brief Number of dimensions of the elements that compose the mdi. For - * example, arity([1:1:10]x[1:1:10]) = 2. + * @brief Number of dimensions of the elements that compose the domain of the + * map. For example, arity([1:1:10]x[1:1:10]) = 2. */ std::size_t arity() const; @@ -102,7 +93,9 @@ class Map { /** * @brief Restrict the domain of the map to \p subdom. */ - Map restrict(const Set& subdom) const; + Map restrict(const Set& subdom) const &; + Map restrict(const Set& subdom) &&; + Map restrict(Set&& subdom) const &; /** * @brief Return all the elements that are the image of a value in the domain. @@ -122,6 +115,12 @@ class Map { */ Set preImage(const Set& subcodom) const; + /** + * @brief Calculates the inverse of a map. + * Precondition: map should be bijective. + */ + Map inverse() const; + /** * @brief Calculate the composition of \p this with \p other, i.e. * \p this(\p other). @@ -135,14 +134,6 @@ class Map { // Extra operations ---------------------------------------------------------- - /** - * @brief Calculate pseudo-inverse of a map. If the map is bijective, it - * returns its inverse. If it's constant, i.e. s -> 0*x+h it returns a new map - * {h} -> min(s), that is a map from the image to the minimum element of the - * domain. - */ - Map minInv() const; - bool isId() const; /** @@ -152,24 +143,44 @@ class Map { */ Set lessImage(const Map& other) const; + /** + * @brief Given two maps m1 (\p this) and m2 (\p other), for every element + * y in the image of m1 returns a map result such that + * result(y) = {min(m2(x)) : m1(x) = y}. + */ + Map minAdj(const Map& other) const; + /** * @brief If it is convenient calculates the result of composing the map with - * itself until the image is out of the domain. For example, - * reduce({[1:1:100]} -> x+1) = {[1:1:100]} -> 101. + * itself until the image is out of the domain (without actually composing the + * map). For example, reduce({[1:1:100]} -> x+1) = {[1:1:100]} -> 101. */ std::vector reduce() const; /** - * @brief Compact the domain of two maps if both share the same expression. If - * not, the result isn't a map, so no value is returned. + * @brief Calculates the multiplicity for each element of the image, i.e. the + * number of pre-images of each one. + */ + std::vector imageMultiplicity() const; + + /** + * @brief Minimize internal representation cost. Heuristic guided. + * Precondition: maps should domain disjoint. */ MaybeMap compact(const Map& other) const; - + +private: + Set _domain; + Expression _law; }; std::ostream& operator<<(std::ostream& out, const Map& s); +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(Map m, rapidjson::Document::AllocatorType& alloc); + } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_MAP_HPP_ diff --git a/sbg/map_detail.cpp b/sbg/map_detail.cpp new file mode 100755 index 00000000..7d6256d0 --- /dev/null +++ b/sbg/map_detail.cpp @@ -0,0 +1,603 @@ +/******************************************************************************* + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "sbg/map_detail.hpp" +#include "sbg/natural.hpp" +#include "sbg/ord_unidim_dense_set.hpp" +#include "sbg/rational.hpp" +#include "sbg/set_detail.hpp" +#include "sbg/set_impl.hpp" +#include "sbg/unord_set.hpp" +#include "util/debug.hpp" + +#include +#include + +namespace SBG { + +namespace LIB { + +namespace detail { + +// Image ----------------------------------------------------------------------- + +Interval image(const Interval& i, const LinearExpr& linear_expr) +{ + if (i.isEmpty()) { + return Interval{}; + } + + if (linear_expr.isId()) { + return i; + } + + if (linear_expr.isConstant()) { + NAT value = linear_expr.apply(i.begin()); + return Interval{value, 1, value}; + } + + NAT new_begin = linear_expr.apply(i.begin()); + RATIONAL m = linear_expr.slope(); + NAT step = i.step(); + NAT new_step = m >= 0 ? (m*step).toNat() : (-m*step).toNat(); + NAT new_end = linear_expr.apply(i.end()); + + return Interval{new_begin, new_step, new_end}; +} + +MultiDimInter image(const MultiDimInter& mdi, const ExpressionImpl& expr) +{ + if (mdi.isEmpty()) { + return MultiDimInter{}; + } + + MultiDimInter result; + for (unsigned int k = 0; k < mdi.arity(); ++k) { + result.pushBack(image(mdi[k], expr[k])); + } + return result; +} + +template +CompactSetImpl compactImage(const CompactSetImpl& s, const Expr& expr + , bool is_injective) +{ + CompactSetImpl result; + + if (is_injective) { + for (const Piece& p : s) { + result.pushBack(detail::image(p, expr)); + } + } else { + for (const Piece& p : s) { + CompactSetImpl jth_image{detail::image(p, expr)}; + result = std::move(result).cup(std::move(jth_image)); + } + } + + return result; +} + +Set MapDetail::image(const Set& s, const Expression& expr) +{ + SetAccessKey key = SetAccess::key(); + auto image_evaluator = Util::Overload { + [&](const UnorderedSet& a) + { + return key.createSet(detail::compactImage(a, expr._impl, expr.isInjective())); + }, + [&](const OrdUnidimDenseSet& a) + { + return key.createSet(detail::compactImage(a, expr._impl[0], expr.isInjective())); + }, + [&](const OrderedSet& a) + { + return key.createSet(detail::compactImage(a, expr._impl, expr.isInjective())); + }, + [&](const auto& a) + { + Util::ERROR("MapDetail::image: unsupported Set implementation"); + return Set{SetKind::kUnordered}; + } + }; + return std::visit(image_evaluator, key.impl(s)); +} + +// Pre-image ------------------------------------------------------------------- + +Interval preImage(const Interval& i, const LinearExpr& linear_expr) +{ + if (i.isEmpty()) { + return Interval{}; + } + + if (linear_expr.isConstant()) { + return Interval{0, 1, Inf}; + } + + return image(i, linear_expr.inverse()); +} + +MultiDimInter preImage(const MultiDimInter& mdi, const ExpressionImpl& expr) +{ + if (mdi.isEmpty()) { + return MultiDimInter{}; + } + + MultiDimInter result; + for (unsigned int k = 0; k < mdi.arity(); ++k) { + result.pushBack(preImage(mdi[k], expr[k])); + } + return result; +} + +template +CompactSetImpl compactPreImage(const CompactSetImpl& s, const Expr& expr) +{ + CompactSetImpl result; + + for (const Piece& p : s) { + result.pushBack(detail::preImage(p, expr)); + } + + return result; +} + +Set MapDetail::preImage(const Set& s, const Expression& expr) +{ + SetAccessKey key = SetAccess::key(); + auto pre_image_evaluator = Util::Overload { + [&](const UnorderedSet& a) + { + return key.createSet(detail::compactPreImage(a, expr._impl)); + }, + [&](const OrdUnidimDenseSet& a) + { + return key.createSet(detail::compactPreImage(a, expr._impl[0])); + }, + [&](const OrderedSet& a) + { + return key.createSet(detail::compactPreImage(a, expr._impl)); + }, + [&](const auto& a) + { + Util::ERROR("MapDetail::preImage: unsupported Set implementation"); + return Set{SetKind::kUnordered}; + } + }; + return std::visit(pre_image_evaluator, key.impl(s)); +} + +// Less image ------------------------------------------------------------------ + +Interval lessImage(const LinearExpr& linear_expr1 + , const LinearExpr& linear_expr2) +{ + RATIONAL m1 = linear_expr1.slope(); + RATIONAL m2 = linear_expr2.slope(); + if (m1 == m2) { + RATIONAL h1 = linear_expr1.offset(); + RATIONAL h2 = linear_expr2.offset(); + if (h1 < h2) { + return Interval{0, 1, Inf}; + } + } else { + RATIONAL point = linear_expr1.intersectionPoint(linear_expr2); + if (point >= 0) { + NAT floor = point.floor(); + NAT ceil = point.ceiling(); + if (ceil == floor) { + NAT floor_minus = floor == 0 ? 0 : floor - 1; + NAT ceil_plus = ceil == Inf ? Inf : ceil + 1; + Interval kth = m1 < m2 ? Interval{ceil_plus, 1, Inf} + : Interval {0, 1, floor_minus}; + return kth; + } else { + Interval kth = m1 < m2 ? Interval{ceil, 1, Inf} + : Interval {0, 1, floor}; + return kth; + } + } else { + if (m1 < m2) { + return Interval{0, 1, Inf}; + } + } + } + + return Interval{}; +} + +std::vector lessImage(const ExpressionImpl& expr1 + , const ExpressionImpl& expr2) +{ + std::vector result; + + unsigned int arity = expr1.size(); + Interval universe_one_dim{0, 1, Inf}; + MultiDimInter less_image{arity, universe_one_dim}; + for (unsigned int k = 0; k < arity; ++k) { + LinearExpr linear_expr1 = expr1[k]; + LinearExpr linear_expr2 = expr2[k]; + Interval kth_less = lessImage(linear_expr1, linear_expr2); + if (!kth_less.isEmpty()) { + less_image[k] = kth_less; + result.push_back(less_image); + if (linear_expr1.slope() == linear_expr2.slope()) { + if (linear_expr1.offset() < linear_expr2.offset()) { + break; + } + } + + RATIONAL cross = linear_expr1.intersectionPoint(linear_expr2); + if (cross.floor() == cross.ceiling()) { + less_image[k] = Interval{cross.toNat(), 1, cross.toNat()}; + } else { + break; + } + } else { + break; + } + } + + return result; +} + +template +void lessImage(const Expr& expr1 + , const Expr& expr2, CompactSetImpl& result) +{ + std::vector less_image = detail::lessImage(expr1, expr2); + + for (const Piece& p : less_image) { + result.pushBack(p); + } +} + +Set MapDetail::lessImage(const Expression& expr1, const Expression& expr2) +{ + Set result; + + SetAccessKey key = SetAccess::key(); + auto less_image_evaluator = Util::Overload { + [&](UnorderedSet&& a) + { + detail::lessImage( + expr1._impl, expr2._impl, a); + return key.createSet(a); + }, + [&](OrdUnidimDenseSet&& a) + { + a.pushBack(detail::lessImage(expr1._impl[0], expr2._impl[0])); + return key.createSet(a); + }, + [&](OrderedSet&& a) + { + detail::lessImage( + expr1._impl, expr2._impl, a); + return key.createSet(a); + }, + [&](auto&& a) + { + Util::ERROR("MapDetail::lessImage: unsupported Set implementation"); + return Set{SetKind::kUnordered}; + } + }; + return std::visit(less_image_evaluator, key.impl(result)); + + return result; +} + +// Reduction ------------------------------------------------------------------- + +void partition(const Interval& i, const LinearExpr& linear_expr + , AtomicMapVector& result) +{ + INT h = linear_expr.offset().toInt(); + INT absh = std::abs(h); + for (int j = 1; j <= absh; ++j) { + NAT new_begin = i.begin() + j - 1; + Interval jth_piece{new_begin, (NAT) absh, i.end()}; + RATIONAL jth_off; + if (h > 0) { + jth_off = jth_piece.end() + h; + } else { + jth_off = jth_piece.begin() + h; + } + LinearExpr jth_linear_expr{0, jth_off}; + result.emplace_back(jth_piece, jth_linear_expr); + } +} + +AtomicMapVector reduce(const Interval& i, const LinearExpr& linear_expr) +{ + AtomicMapVector result; + + // No partition of the piece is needed + RATIONAL zero(0, 1); + INT h = linear_expr.offset().toInt(); + NAT st = i.step(); + if (h == (INT) st) { + NAT hi = i.end(); + if (st < Inf - hi) { + LinearExpr convergence_value{zero, static_cast(hi + st)}; + result.emplace_back(i, convergence_value); + return result; + } + } else if (h == (INT) -st) { + NAT lo = i.begin(); + if (lo >= st) { + LinearExpr convergence_value{zero, static_cast(lo - st)}; + result.emplace_back(i, convergence_value); + return result; + } + } + + // Partition of the piece needed + if (h % (INT) st == 0) { + // Is convenient the partition of the piece? + if ((INT) i.cardinal() > h*h) { + partition(i, linear_expr, result); + } else { + result.emplace_back(i, linear_expr); + } + } else { + result.emplace_back(i, linear_expr); + } + + return result; +} + +bool isReductionEfficient(const ExpressionImpl& expr) +{ + int count = 0; + for (const LinearExpr& linear_expr : expr) { + if (linear_expr.slope() != 1 && linear_expr.slope() != 0) { + return false; + } + + if (linear_expr.slope() == 1 && linear_expr.offset() != 0) { + ++count; + } + } + + return count == 1; +} + +AtomicMapVector reduce(const MultiDimInter& mdi, const ExpressionImpl& expr + , unsigned int& k_reduce) +{ + // Identify reducible dimension k_reduce + std::size_t arity = mdi.arity(); + Interval reducible_interval; + LinearExpr reducible_expr; + for (std::size_t k = 0; k < arity; ++k) { + LinearExpr linear_expr = expr[k]; + if (linear_expr.slope() == 1 && linear_expr.offset() != 0) { + k_reduce = k; + reducible_interval = mdi[k]; + reducible_expr = linear_expr; + break; + } + } + + return reduce(reducible_interval, reducible_expr); +} + +template +MapVector MapDetail::MDICollectionReduce(const CompactSetImpl& s + , const ExpressionImpl& expr) +{ + MapVector result; + + SetAccessKey key = SetAccess::key(); + for (const MultiDimInter& mdi : s) { + unsigned int k_reduce = 0; + AtomicMapVector reduced = detail::reduce(mdi, expr, k_reduce); + MultiDimInter mdi_copy = mdi; + ExpressionImpl expr_copy = expr; + for (const AtomicMap& r : reduced) { + CompactSetImpl domain; + mdi_copy[k_reduce] = r.first; + domain.pushBack(mdi_copy); + expr_copy[k_reduce] = r.second; + result.emplace_back(key.createSet(domain), Expression{expr_copy}); + } + } + + return result; +} + +MapVector MapDetail::reduce(const OrdUnidimDenseSet& s + , const ExpressionImpl& expr) +{ + MapVector result; + + SetAccessKey key = SetAccess::key(); + for (const Interval& i : s) { + AtomicMapVector reduced = detail::reduce(i, expr[0]); + for (const AtomicMap& r : reduced) { + OrdUnidimDenseSet domain; + domain.pushBack(r.first); + result.emplace_back(key.createSet(domain) + , Expression{ExpressionImpl{r.second}}); + } + } + + return result; +} + +MapVector MapDetail::reduce(const Map& m) +{ + MapVector result; + + Set domain = m.domain(); + Expression law = m.law(); + if (domain.cardinal() == 1 || !isReductionEfficient(law._impl)) { + result.push_back(m); + return result; + } + + SetAccessKey key = SetAccess::key(); + auto reduce_evaluator = Util::Overload { + [&](const UnorderedSet& a) + { + return MDICollectionReduce(a, law._impl); + }, + [&](const OrdUnidimDenseSet& a) + { + return reduce(a, law._impl); + }, + [&](const OrderedSet& a) + { + return MDICollectionReduce(a, law._impl); + }, + [&](const auto& a) + { + Util::ERROR("MapDetail::reduce: unsupported Set implementation"); + return Set{SetKind::kUnordered}; + } + }; + return std::visit(reduce_evaluator, key.impl(m.domain())); +} + +// Image multiplicity ---------------------------------------------------------- + +AtomicMap imageMultiplicity(const Interval& i, const LinearExpr& linear_expr) +{ + Interval image = detail::image(i, linear_expr); + if (linear_expr.isConstant()) { + return AtomicMap{image, LinearExpr{0, i.cardinal()}}; + } + + return AtomicMap{image, LinearExpr{0, 1}}; +} + +AtomicMDMap imageMultiplicity(const MultiDimInter& mdi + , const ExpressionImpl& expr) +{ + MultiDimInter result_mdi; + ExpressionImpl result_expr; + + std::size_t arity = mdi.arity(); + for (std::size_t j = 0; j < arity; ++j) { + AtomicMap jth = imageMultiplicity(mdi[j], expr[j]); + result_mdi.pushBack(std::get<0>(jth)); + result_expr.push_back(std::get<1>(jth)); + } + + return AtomicMDMap{result_mdi, result_expr}; +} + +template +MapVector MapDetail::imageMultiplicity(const CompactSetImplT& s + , const ExprT& expr) +{ + MapVector result; + + SetAccessKey key = SetAccess::key(); + for (const PieceT& p : s) { + MapVector jth_result; + + bool repeated = false; + AtomicMDMap jth = detail::imageMultiplicity(p, expr); + Map p_multiplicity{key.createSet(CompactSetImplT{std::get<0>(jth)}) + , std::get<1>(jth)}; + for (const Map& m : result) { + Set m_domain = m.domain(); + Set cap = m_domain.intersection(p_multiplicity.domain()); + if (!cap.isEmpty()) { + jth_result.push_back(p_multiplicity + m); + jth_result.push_back(m.restrict(m_domain.difference(cap))); + repeated = true; + } + } + + if (!repeated) { + jth_result.push_back(p_multiplicity); + } + + std::swap(result, jth_result); + } + + return result; +} + +MapVector MapDetail::imageMultiplicity(const Map& m) +{ + MapVector result; + + Set domain = m.domain(); + Expression law = m.law(); + + if (m.isEmpty()) { + return result; + } + + if (law.isInjective()) { + Set result_domain = m.image(); + Expression result_expr{MD_NAT{domain.arity(), 1}}; + result.emplace_back(result_domain, result_expr); + return result; + } + + if (law.isConstant()) { + Set result_domain = m.image(); + Expression result_expr{MD_NAT{domain.arity(), domain.cardinal()}}; + result.emplace_back(result_domain, result_expr); + return result; + } + + SetAccessKey key = SetAccess::key(); + auto img_mult_evaluator = Util::Overload { + [&](const UnorderedSet& a) + { + return imageMultiplicity( + a, law._impl); + }, + [&](const OrdUnidimDenseSet& a) + { + Util::ERROR("MapDetail::imageMultiplicity: uni-dimensional already " + , "solved"); + return MapVector{}; + }, + [&](const OrderedSet& a) + { + return imageMultiplicity( + a, law._impl); + }, + [&](const auto& a) + { + Util::ERROR("MapDetail::imageMultiplicity: unsupported Set implementation"); + return MapVector{}; + } + }; + return std::visit(img_mult_evaluator, key.impl(m.domain())); +} + +} // namespace detail + +} // namespace LIB + +} // namespace SBG diff --git a/sbg/map_detail.hpp b/sbg/map_detail.hpp new file mode 100755 index 00000000..b0a410a1 --- /dev/null +++ b/sbg/map_detail.hpp @@ -0,0 +1,78 @@ +/** @file map_detail.hpp + + @brief Map implementation details + + This module defines some functions that work both with the implementation of + Interval, SetPiece, LinearExpr (that don't belong to the public interface), + and also Expression, which belongs to the public interface, but exposes its + implementations details only to these functions. + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_SBG_MAP_DETAIL_HPP_ +#define SBGRAPH_SBG_MAP_DETAIL_HPP_ + +#include "sbg/expression_impl.hpp" +#include "sbg/interval.hpp" +#include "sbg/linear_expr.hpp" +#include "sbg/map.hpp" +#include "sbg/multidim_inter.hpp" +#include "util/defs.hpp" + +#include + +namespace SBG { + +namespace LIB { + +namespace detail { + +using AtomicMap = std::pair; +using AtomicMapVector = std::vector; +using AtomicMDMap = std::pair; +using MapVector = std::vector; + +class MapDetail { +public: + static Set image(const Set& s, const Expression& expr); + static Set preImage(const Set& s, const Expression& expr); + static Set lessImage(const Expression& expr1, const Expression& expr2); + static MapVector reduce(const Map& m); + static MapVector imageMultiplicity(const Map& m); + +private: + template + static MapVector MDICollectionReduce(const SetMDIImpl& s + , const ExpressionImpl& expr); + static MapVector reduce(const OrdUnidimDenseSet& s + , const ExpressionImpl& expr); + + template + static MapVector imageMultiplicity(const CompactSetImplT& s + , const ExprT& expr); +}; + +} // namespace detail + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_SBG_MAP_DETAIL_HPP_ diff --git a/sbg/map_entry.cpp b/sbg/map_entry.cpp index 5e51f2f0..76768bdf 100755 --- a/sbg/map_entry.cpp +++ b/sbg/map_entry.cpp @@ -23,101 +23,43 @@ namespace SBG { namespace LIB { -namespace Internal { +namespace detail { -SetPerimeter calculatePerimeter(const Set& s) -{ - std::size_t ar = s.arity(); - MD_NAT min_per(ar, Inf); - MD_NAT max_per(ar, 0); - - for (const SetPiece& mdi : s) { - MD_NAT candidate_min = mdi.minElem(); - MD_NAT candidate_max = mdi.maxElem(); - for (size_t i = 0; i < ar; ++i) { - min_per[i] = std::min(min_per[i], candidate_min[i]); - max_per[i] = std::max(max_per[i], candidate_max[i]); - } - } - - return {min_per, max_per}; -} +//////////////////////////////////////////////////////////////////////////////// +// Map entry ------------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// -bool doInt(const SetPerimeter& p1, const SetPerimeter& p2) -{ - const auto min_per_p1 = p1.first; - const auto max_per_p1 = p1.second; - const auto min_per_p2 = p2.first; - const auto max_per_p2 = p2.second; - const unsigned int arity = max_per_p1.arity(); - - for (unsigned int j = 0; j < arity; ++j) { - if (max_per_p1[j] < min_per_p2[j] || max_per_p2[j] < min_per_p1[j]) { - return false; // No intersection - } - } - - return true; // Intersection detected -} +MapEntry::MapEntry(const Set& s, const Expression& expr) + : _map(s, expr), _perimeter(s.perimeter()) {} -MapEntry createMapEntry(const Map& m) -{ - return {m, calculatePerimeter(m.dom())}; -} +MapEntry::MapEntry(const Map& m) + : _map(m), _perimeter(m.domain().perimeter()) {} -bool operator<(const MapEntry& mpe1, const MapEntry& mpe2) -{ - return mpe1.second.first < mpe2.second.first; -} +const Map& MapEntry::map() const { return _map; } -void emplaceBack(OrdMapCollection& ord_pw, const MapEntry& entry) +const Perimeter& MapEntry::perimeter() const { return _perimeter; } + +bool MapEntry::operator==(const MapEntry& other) const { - if (!entry.first.isEmpty()) { - ord_pw.emplace_back(entry); - } + return _map == other._map; } -void emplaceBack(OrdMapCollection& ord_pw, const Map& m) +bool MapEntry::operator<(const MapEntry& other) const { - if (!m.isEmpty()) { - ord_pw.emplace_back(createMapEntry(m)); - } + return _perimeter.min() < other._perimeter.min(); } -void emplaceHint(OrdMapCollection& ord_pw, const Map& m, NAT hint) +MaybeMapEntry MapEntry::compact(const MapEntry& other) const { - if (!m.isEmpty()) { - auto it = ord_pw.begin(); - std::advance(it, hint); - auto end = ord_pw.end(); - MapEntry mpe = createMapEntry(m); - while (it != end) { - if (it->second.first < mpe.second.first) { - ++it; - } else { - break; - } - } - ord_pw.emplace(it, mpe); + MaybeMap compacted = _map.compact(other._map); + if (compacted) { + return MaybeMapEntry{compacted.value()}; } -} -void advanceHint(OrdMapCollection& ord_pw, const MD_NAT crit, NAT& hint) -{ - auto it = ord_pw.begin(); - std::advance(it, hint); - auto end = ord_pw.end(); - while (it != end) { - if (it->second.first < crit) { - ++it; - ++hint; - } else { - break; - } - } + return {}; } - -} // namespace Internal + +} // namespace detail } // namespace LIB diff --git a/sbg/map_entry.hpp b/sbg/map_entry.hpp index f63433a3..282d7d46 100755 --- a/sbg/map_entry.hpp +++ b/sbg/map_entry.hpp @@ -23,34 +23,48 @@ ******************************************************************************/ -#ifndef SBG_MAP_ENTRY_HPP -#define SBG_MAP_ENTRY_HPP +#ifndef SBGRAPH_SBG_MAP_ENTRY_HPP_ +#define SBGRAPH_SBG_MAP_ENTRY_HPP_ +#include "sbg/expression.hpp" #include "sbg/map.hpp" +#include "sbg/set.hpp" +#include "sbg/perimeter.hpp" + +#include namespace SBG { namespace LIB { -namespace Internal { +namespace detail { + +class MapEntry; + +using MaybeMapEntry = std::optional; + +class MapEntry { +public: + MapEntry(const Set& s, const Expression& expr); + MapEntry(const Map& m); + + const Map& map() const; + const Perimeter& perimeter() const; + + bool operator==(const MapEntry& other) const; + bool operator<(const MapEntry& other) const; -using SetPerimeter = std::pair; -using MapEntry = std::pair; -using OrdMapCollection = std::vector; + MaybeMapEntry compact(const MapEntry& other) const; -SetPerimeter calculatePerimeter(const Set &s); -bool doInt(const SetPerimeter& p1, const SetPerimeter& p2); -MapEntry createMapEntry(const Map& m); -bool operator<(const MapEntry& mpe1, const MapEntry& mpe2); -void emplaceBack(OrdMapCollection& ord_pw, const MapEntry& entry); -void emplaceBack(OrdMapCollection& ord_pw, const Map& m); -void emplaceHint(OrdMapCollection& ord_pw, const Map& m, NAT hint); -void advanceHint(OrdMapCollection& ord_pw, const MD_NAT crit, NAT& hint); +private: + Map _map; + Perimeter _perimeter; +}; -} // namespace Internal +} // namespace detail } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_MAP_ENTRY_HPP_ diff --git a/sbg/multidim_inter.cpp b/sbg/multidim_inter.cpp index 16b6e6ad..a788f8d8 100755 --- a/sbg/multidim_inter.cpp +++ b/sbg/multidim_inter.cpp @@ -19,76 +19,92 @@ #include "sbg/multidim_inter.hpp" +#include + namespace SBG { namespace LIB { -member_imp(MultiDimInter, InterVector, intervals); +namespace detail { + +// Constructors/Destructors ---------------------------------------------------- + +MultiDimInter::MultiDimInter() : _intervals() {} -MultiDimInter::MultiDimInter() : intervals_() {} -MultiDimInter::MultiDimInter(const MD_NAT &x) : intervals_() { - for (NAT xi : x) - intervals_.push_back(Interval(xi, 1, xi)); +MultiDimInter::MultiDimInter(const MD_NAT& x) : _intervals() +{ + for (const NAT xi : x) { + _intervals.emplace_back(Interval{xi, 1, xi}); + } } -MultiDimInter::MultiDimInter(const Interval &i) : intervals_() + +MultiDimInter::MultiDimInter(const Interval& i) : _intervals() { - intervals_.push_back(i); + _intervals.push_back(i); } -MultiDimInter::MultiDimInter(const unsigned int &nmbr_copies - , const Interval &i) : intervals_() { - for (unsigned int j = 0; j < nmbr_copies; ++j) - intervals_.push_back(i); + +MultiDimInter::MultiDimInter(const std::size_t k, const Interval& i) + : _intervals() +{ + for (unsigned int j = 0; j < k; ++j) { + _intervals.push_back(i); + } } -MultiDimInter::MultiDimInter(const InterVector &iv) - : intervals_(std::move(iv)) {} -MultiDimInter::iterator MultiDimInter::begin() { return intervals_.begin(); } -MultiDimInter::iterator MultiDimInter::end() { return intervals_.end(); } -MultiDimInter::const_iterator MultiDimInter::begin() const +MultiDimInter::MultiDimInter(InterVector iv) : _intervals(std::move(iv)) {} + +// Getters --------------------------------------------------------------------- + +MultiDimInter::ConstIt MultiDimInter::begin() const { - return intervals_.begin(); + return _intervals.begin(); } -MultiDimInter::const_iterator MultiDimInter::end() const + +MultiDimInter::ConstIt MultiDimInter::end() const { - return intervals_.end(); + return _intervals.end(); } -void MultiDimInter::emplaceBack(Interval i) +// Setters --------------------------------------------------------------------- + +void MultiDimInter::pushBack(const Interval& i) { - if (i.isEmpty()){ - intervals_ = InterVector();} - else - intervals_.push_back(i); - return; + if (!i.isEmpty()) { + _intervals.push_back(i); + } } -Interval &MultiDimInter::operator[](std::size_t n) +// Operators ------------------------------------------------------------------- + +Interval& MultiDimInter::operator[](std::size_t n) { - return intervals_[n]; + return _intervals[n]; } -const Interval &MultiDimInter::operator[](std::size_t n) const +const Interval& MultiDimInter::operator[](std::size_t n) const { - return intervals_[n]; + return _intervals[n]; } -bool MultiDimInter::operator==(const MultiDimInter &other) const +bool MultiDimInter::operator==(const MultiDimInter& other) const { - return intervals_ == other.intervals_; + return _intervals == other._intervals; } -bool MultiDimInter::operator!=(const MultiDimInter &other) const +bool MultiDimInter::operator!=(const MultiDimInter& other) const { return !(*this == other); } -bool MultiDimInter::operator<(const MultiDimInter &other) const +bool MultiDimInter::operator<(const MultiDimInter& other) const { - if (other.isEmpty()) + if (other.isEmpty()) { return false; + } - if (isEmpty()) + if (isEmpty()) { return true; + } return minElem() < other.minElem(); } @@ -98,13 +114,14 @@ bool MultiDimInter::operator>(const MultiDimInter& other) const return !(*this == other && *this < other); } -std::ostream &operator<<(std::ostream &out, const MultiDimInter &mdi) +std::ostream& operator<<(std::ostream& out, const MultiDimInter& mdi) { std::size_t sz = mdi.arity(); if (sz > 0) { - for (std::size_t j = 0; j < sz - 1; ++j) + for (std::size_t j = 0; j < sz - 1; ++j) { out << mdi[j] << "x"; + } out << mdi[sz-1]; } @@ -115,107 +132,146 @@ std::ostream &operator<<(std::ostream &out, const MultiDimInter &mdi) unsigned int MultiDimInter::cardinal() const { - unsigned int res = 1; + unsigned int result = 1; - for (const Interval &i : intervals_) - res *= i.cardinal(); + for (const Interval& i : _intervals) { + result *= i.cardinal(); + } - return res; + return result; } -bool MultiDimInter::isEmpty() const { return intervals_.empty(); } +bool MultiDimInter::isEmpty() const { return _intervals.empty(); } MD_NAT MultiDimInter::minElem() const { - MD_NAT res; + MD_NAT result; - for (const Interval &i : intervals_) - res.emplaceBack(i.begin()); + for (const Interval& i : _intervals) { + result.pushBack(i.begin()); + } - return res; + return result; } MD_NAT MultiDimInter::maxElem() const { - MD_NAT res; + MD_NAT result; - for (const Interval &i : intervals_) - res.emplaceBack(i.end()); + for (const Interval& i : _intervals) { + result.pushBack(i.end()); + } - return res; + return result; } -MultiDimInter MultiDimInter::intersection(const MultiDimInter &other) const +MultiDimInter MultiDimInter::intersection(const MultiDimInter& other) const { - if (isEmpty() || other.isEmpty()) - return MultiDimInter(); + if (isEmpty() || other.isEmpty()) { + return MultiDimInter{}; + } - MultiDimInter res; + MultiDimInter result; for (unsigned int j = 0; j < arity(); ++j) { - Interval ith = operator[](j).intersection(other[j]); - if (!ith.isEmpty()) - res.emplaceBack(ith); + Interval jth_intersection = operator[](j).intersection(other[j]); + if (jth_intersection.isEmpty()) { + return MultiDimInter{}; + } else { + result.pushBack(jth_intersection); + } + } + + return result; +} + +MultiDimInter MultiDimInter::cartesianProduct(const MultiDimInter& other) const +{ + MultiDimInter result = *this; - else - return MultiDimInter(); + for (const Interval& other_i : other._intervals) { + result.pushBack(other_i); } - return res; + return result; } // Extra operations ------------------------------------------------------------ -std::size_t MultiDimInter::arity() const { return intervals_.size(); } +std::size_t MultiDimInter::arity() const { return _intervals.size(); } -MultiDimInter MultiDimInter::offset(const MD_NAT &off) const +MultiDimInter MultiDimInter::offset(const MD_NAT& off) const { - MultiDimInter res; + MultiDimInter result; - for (unsigned int j = 0; j < arity(); ++j) - res.emplaceBack(operator[](j).offset(off[j])); + for (unsigned int j = 0; j < arity(); ++j) { + result.pushBack(operator[](j).offset(off[j])); + } - return res; + return result; } -MultiDimInter MultiDimInter::least(const MultiDimInter &other) const +MultiDimInter MultiDimInter::least(const MultiDimInter& other) const { return std::min(*this, other); } -MaybeMDI MultiDimInter::compact(const MultiDimInter &other) const +Perimeter MultiDimInter::perimeter() const +{ + return Perimeter{minElem(), maxElem()}; +} + +MaybeMDI MultiDimInter::compact(const MultiDimInter& other) const { - MultiDimInter res; + MultiDimInter result; unsigned int j = 0; for (; j < arity(); ++j) { - auto ith = operator[](j).compact(other[j]); - if (operator[](j) == other[j]) - res.emplaceBack(operator[](j)); - - else { - if (ith) { - res.emplaceBack(ith.value()); + Interval jth_this = operator[](j); + Interval jth_other = other[j]; + if (jth_this == jth_other) { + result.pushBack(jth_this); + } else { + MaybeInterval jth_compact = jth_this.compact(jth_other); + if (jth_compact) { + result.pushBack(jth_compact.value()); ++j; break; - } - - else + } else { return {}; + } } } for (; j < arity(); ++j) { - if (operator[](j) != other[j]) + if (operator[](j) != other[j]) { return {}; + } else { + result.pushBack(operator[](j)); + } + } - else - res.emplaceBack(operator[](j)); + return result; +} + +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(MultiDimInter mdi + , rapidjson::Document::AllocatorType& alloc) +{ + rapidjson::Value interval_array{rapidjson::kArrayType}; + for (const Interval& i : mdi) { + rapidjson::Value jth = toJSON(i, alloc); + interval_array.PushBack(jth, alloc); } + rapidjson::Value result{rapidjson::kObjectType}; + result.AddMember("bounds", interval_array, alloc); - return res; + return result; } +} // namespace detail + } // namespace LIB } // namespace SBG diff --git a/sbg/multidim_inter.hpp b/sbg/multidim_inter.hpp index 6c6dc120..c90a5182 100755 --- a/sbg/multidim_inter.hpp +++ b/sbg/multidim_inter.hpp @@ -3,8 +3,8 @@ @brief Multi-dimensional interval implementation A Multi-dimensional interval (mdi) i1 x ... x ik is the resulting set of the - cartesian product of intervals. As such the implementations an ordered - collection of intervals. + cartesian product of intervals. Thus, the implementation consists of an + ordered collection of intervals.
@@ -25,25 +25,32 @@ ******************************************************************************/ -#ifndef SBG_MULTIDIM_INTERVAL_HPP -#define SBG_MULTIDIM_INTERVAL_HPP +#ifndef SBGRAPH_SBG_MULTIDIM_INTER_HPP_ +#define SBGRAPH_SBG_MULTIDIM_INTER_HPP_ #include "sbg/interval.hpp" +#include "sbg/natural.hpp" +#include "sbg/perimeter.hpp" + +#include "rapidjson/document.h" + +#include +#include namespace SBG { namespace LIB { -typedef std::vector InterVector; -typedef InterVector::iterator InterVectorIt; -typedef InterVector::const_iterator InterVectorConstIt; +namespace detail { class MultiDimInter; -typedef std::optional MaybeMDI; +using MaybeMDI = std::optional; class MultiDimInter { - member_class(InterVector, intervals); +public: + using InterVector = std::vector; + using ConstIt = InterVector::const_iterator; /** * @brief Construct zero-dimensional mdi. @@ -53,42 +60,38 @@ class MultiDimInter { /** * @brief Construct a mdi with a single element \p x. */ - MultiDimInter(const MD_NAT &x); + MultiDimInter(const MD_NAT& x); /** * @brief Construct a one-dimensional mdi with the same elements as \p i. */ - MultiDimInter(const Interval &i); + MultiDimInter(const Interval& i); /** - * @brief Construct a mdi that is the result of \p i ^ \p nmbr_copies. + * @brief Construct a mdi that is the result of \p i ^ \p n. */ - MultiDimInter(const unsigned int &nmbr_copies, const Interval &i); + MultiDimInter(const std::size_t k, const Interval& i); - /** - * @brief Collection move constructor. - */ - MultiDimInter(const InterVector &iv); + MultiDimInter(InterVector iv); + + ConstIt begin() const; + ConstIt end() const; - typedef InterVectorIt iterator; - typedef InterVectorConstIt const_iterator; - iterator begin(); - iterator end(); - const_iterator begin() const; - const_iterator end() const; - void emplaceBack(Interval i); - Interval &operator[](std::size_t n); - const Interval &operator[](std::size_t n) const; + template + void emplaceBack(Args&&... args); + void pushBack(const Interval& i); - bool operator==(const MultiDimInter &other) const; - bool operator!=(const MultiDimInter &other) const; + Interval& operator[](std::size_t n); + const Interval& operator[](std::size_t n) const; + bool operator==(const MultiDimInter& other) const; + bool operator!=(const MultiDimInter& other) const; /** * @brief A mdi mdi1 is less than another mdi2 iff min(mdi1) < min(mdi2). * This operation is later needed to implement ordered sets. */ - bool operator<(const MultiDimInter &other) const; - bool operator>(const MultiDimInter &other) const; + bool operator<(const MultiDimInter& other) const; + bool operator>(const MultiDimInter& other) const; // Traditional set operations ------------------------------------------------ @@ -100,7 +103,8 @@ class MultiDimInter { bool isEmpty() const; MD_NAT minElem() const; MD_NAT maxElem() const; - MultiDimInter intersection(const MultiDimInter &other) const; + MultiDimInter intersection(const MultiDimInter& other) const; + MultiDimInter cartesianProduct(const MultiDimInter& other) const; // Extra operations ---------------------------------------------------------- @@ -113,27 +117,44 @@ class MultiDimInter { /** * @brief Sum a constant value to every element of the mdi. */ - MultiDimInter offset(const MD_NAT &off) const; + MultiDimInter offset(const MD_NAT& off) const; /** * @brief Operation that given two disjoint mdis returns the lesser one. * It will be used by ordered sets operations. */ - MultiDimInter least(const MultiDimInter &other) const; + MultiDimInter least(const MultiDimInter& other) const; + + Perimeter perimeter() const; /** * @brief Merge two contiguous mdis if possible. If not, then the result is * not an mdi, so no value is returned. */ - MaybeMDI compact(const MultiDimInter &other) const; - + MaybeMDI compact(const MultiDimInter& other) const; + +private: + InterVector _intervals; }; -std::ostream &operator<<(std::ostream &out, const MultiDimInter &mi); +std::ostream& operator<<(std::ostream& out, const MultiDimInter& mdi); + +// Template definitions -------------------------------------------------------- + +template +inline void MultiDimInter::emplaceBack(Args&&... args) +{ + _intervals.emplace_back(std::forward(args)...); +} + +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(MultiDimInter mdi + , rapidjson::Document::AllocatorType& alloc); -typedef MultiDimInter SetPiece; +} // namespace detail } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_MULTIDIM_INTER_HPP_ diff --git a/sbg/multidim_lexp.cpp b/sbg/multidim_lexp.cpp deleted file mode 100755 index 4d5dc7cc..00000000 --- a/sbg/multidim_lexp.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/******************************************************************************* - - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -#include "sbg/multidim_lexp.hpp" - -namespace SBG { - -namespace LIB { - -MDLExp::MDLExp() : exps_() {} -MDLExp::MDLExp(const MD_NAT &x) -{ - for (NAT xi : x) - exps_.push_back(LExp(0, RATIONAL(xi))); -} -MDLExp::MDLExp(const LExp &le) : exps_() { exps_.push_back(le); } -MDLExp::MDLExp(unsigned int nmbr_copies, const LExp &le) : exps_() -{ - for (unsigned int j = 0; j < nmbr_copies; ++j) - exps_.push_back(le); -} -MDLExp::MDLExp(const LExpVector &v) : exps_(std::move(v)) {} - -member_imp(MDLExp, LExpVector, exps); - -MDLExp::iterator MDLExp::begin() { return exps_.begin(); } -MDLExp::iterator MDLExp::end() { return exps_.end(); } -MDLExp::const_iterator MDLExp::begin() const { return exps_.begin(); } -MDLExp::const_iterator MDLExp::end() const { return exps_.end(); } - -void MDLExp::emplaceBack(LExp le) { exps_.emplace_back(le); } - -LExp &MDLExp::operator[](std::size_t n) { return exps_[n]; } -const LExp &MDLExp::operator[](std::size_t n) const { return exps_[n]; } - -bool MDLExp::operator==(const MDLExp &other) const -{ - return exps_ == other.exps_; -} - -bool MDLExp::operator!=(const MDLExp &other) const -{ - return !(*this == other); -} - -MDLExp MDLExp::operator+(const MDLExp &other) const -{ - MDLExp res; - for (unsigned int j = 0; j < arity(); ++j) - res.emplaceBack(operator[](j) + other[j]); - - return res; -} - -MDLExp MDLExp::operator-(const MDLExp &other) const -{ - MDLExp res; - for (unsigned int j = 0; j < arity(); ++j) - res.emplaceBack(operator[](j) - other[j]); - - return res; -} - -std::ostream &operator<<(std::ostream &out, const MDLExp &mdle) -{ - unsigned int sz = mdle.arity(); - - out << "|"; - if (sz > 0) { - for (unsigned int j = 0; j < sz-1; ++j) - out << mdle[j] << "|"; - out << mdle[sz-1]; - } - out << "|"; - - return out; -} - -// Linear expression functions ------------------------------------------------- - -std::size_t MDLExp::arity() const { return exps_.size(); } - -MDLExp MDLExp::composition(const MDLExp &other) const -{ - MDLExp res; - - for (unsigned int j = 0; j < arity(); ++j) - res.emplaceBack(operator[](j).composition(other[j])); - - return res; -} - -MDLExp MDLExp::inverse() const -{ - MDLExp res; - - for (const LExp &le : exps_) - res.emplaceBack(le.inverse()); - - return res; -} - -bool MDLExp::isId() const -{ - for (const LExp &le : exps_) - if (!le.isId()) - return false; - - return true; -} - -bool MDLExp::isConstant() const -{ - for (const LExp &le : exps_) - if (!le.isConstant()) - return false; - - return true; -} - -} // namespace LIB - -} // namespace SBG diff --git a/sbg/multidim_lexp.hpp b/sbg/multidim_lexp.hpp deleted file mode 100755 index 24b363ef..00000000 --- a/sbg/multidim_lexp.hpp +++ /dev/null @@ -1,116 +0,0 @@ -/** @file multidim_lexp.hpp - - @brief Multi-dimensional linear expressions implementation - - A Multi-dimensional linear expression (mdle) le1 | ... | lek is an ordered - collection of linear expressions. - -
- - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -#ifndef SBG_MULTIDIM_LEXP_HPP -#define SBG_MULTIDIM_LEXP_HPP - -#include "lexp.hpp" - -namespace SBG { - -namespace LIB { - -typedef std::vector LExpVector; -typedef LExpVector::iterator LExpVectorIt; -typedef LExpVector::const_iterator LExpVectorConstIt; - -class MDLExp { - member_class(LExpVector, exps); - - /** - * @brief Empty multi-dimensional expression constructor. - */ - MDLExp(); - - /** - * @brief Constructs a constant mdle in all dimensions that maps to \p x. - */ - MDLExp(const MD_NAT &x); - - /** - * @brief Constructs a one-dimensional mdle composed only by \p le. - */ - MDLExp(const LExp &le); - - /** - * @brief Constructs a mdle of dimension \p nmbr_copies with \p le as linear - * expression in each dimensions. - */ - MDLExp(unsigned int nmbr_copies, const LExp &le); - - /** - * @brief Collection move constructor. - */ - MDLExp(const LExpVector &v); - - typedef LExpVectorIt iterator; - typedef LExpVectorConstIt const_iterator; - iterator begin(); - iterator end(); - const_iterator begin() const; - const_iterator end() const; - void emplaceBack(LExp le); - LExp &operator[](std::size_t n); - const LExp &operator[](std::size_t n) const; - - bool operator==(const MDLExp &other) const; - bool operator!=(const MDLExp &other) const; - - MDLExp operator+(const MDLExp &other) const; - MDLExp operator-(const MDLExp &other) const; - - // Traditional expression operations ----------------------------------------- - - /** - * @brief Number of dimensions of the mdle, i.e. arity(1*x+0 | 1*x+0) = 2. - */ - std::size_t arity() const; - - /** - * @brief Calculate the composition of \p this with \p other, i.e. - * \p this(\p other). - */ - MDLExp composition(const MDLExp &other) const; - - /** - * @brief Calculates the inverse dimension by dimension. - */ - MDLExp inverse() const; - - // Extra operations ---------------------------------------------------------- - - bool isId() const; - bool isConstant() const; -}; -std::ostream &operator<<(std::ostream &out, const MDLExp &mdle); - -typedef MDLExp Exp; - -} // namespace LIB - -} // namespace SBG - -#endif diff --git a/sbg/natural.cpp b/sbg/natural.cpp index e020af5f..4d2445d3 100755 --- a/sbg/natural.cpp +++ b/sbg/natural.cpp @@ -19,81 +19,96 @@ #include "sbg/natural.hpp" +#include + namespace SBG { namespace LIB { -member_imp(MD_NAT, VNAT, value); +// Constructors/Destructors ---------------------------------------------------- + +MD_NAT::MD_NAT() : _value() {} + +MD_NAT::MD_NAT(const NAT x) : _value() { _value.emplace_back(x); } -MD_NAT::MD_NAT() : value_() {} -MD_NAT::MD_NAT(NAT x) : value_() { value_.push_back(x); } -MD_NAT::MD_NAT(unsigned int nmbr_copies, NAT x) : value_() { - for (unsigned int j = 0; j < nmbr_copies; ++j) - value_.push_back(x); +MD_NAT::MD_NAT(const std::size_t k, const NAT x) : _value() +{ + for (unsigned int j = 0; j < k; ++j) { + _value.emplace_back(x); + } } -MD_NAT::MD_NAT(MD_NAT::iterator b, MD_NAT::iterator e) : value_(b, e) {} -MD_NAT::iterator MD_NAT::begin() { return value_.begin(); } -MD_NAT::iterator MD_NAT::end() { return value_.end(); } -MD_NAT::const_iterator MD_NAT::begin() const { return value_.begin(); } -MD_NAT::const_iterator MD_NAT::end() const { return value_.end(); } +MD_NAT::MD_NAT(MD_NAT::Iterator b, MD_NAT::Iterator e) : _value(b, e) {} + +// Getters --------------------------------------------------------------------- + +MD_NAT::Iterator MD_NAT::begin() { return _value.begin(); } + +MD_NAT::Iterator MD_NAT::end() { return _value.end(); } + +MD_NAT::ConstIterator MD_NAT::begin() const { return _value.begin(); } + +MD_NAT::ConstIterator MD_NAT::end() const { return _value.end(); } -void MD_NAT::emplaceBack(NAT x) { value_.push_back(x); } +// Setters --------------------------------------------------------------------- -NAT &MD_NAT::operator[](std::size_t n) { return value_[n]; } -const NAT &MD_NAT::operator[](std::size_t n) const { return value_[n]; } +void MD_NAT::pushBack(const NAT x) { _value.push_back(x); } -bool MD_NAT::operator==(const MD_NAT &other) const +// Operators ------------------------------------------------------------------- + +NAT& MD_NAT::operator[](std::size_t n) { return _value[n]; } + +const NAT& MD_NAT::operator[](std::size_t n) const { return _value[n]; } + +bool MD_NAT::operator==(const MD_NAT& other) const { - return value_ == other.value_; + return _value == other._value; } -bool MD_NAT::operator!=(const MD_NAT &other) const { return !(*this == other); } +bool MD_NAT::operator!=(const MD_NAT& other) const { return !(*this == other); } -bool MD_NAT::operator<(const MD_NAT &other) const +bool MD_NAT::operator<(const MD_NAT& other) const { for (unsigned int j = 0; j < arity(); ++j) { - if (operator[](j) < other[j]) + if (operator[](j) < other[j]) { return true; - - if (operator[](j) > other[j]) + } else if (operator[](j) > other[j]) { return false; + } } return false; } -bool MD_NAT::operator<=(const MD_NAT &other) const +bool MD_NAT::operator<=(const MD_NAT& other) const { return *this == other || *this < other; } -MD_NAT MD_NAT::operator+=(const MD_NAT &other) const +MD_NAT MD_NAT::operator+(const MD_NAT& other) const { - MD_NAT res = *this; - for (unsigned int j = 0; j < arity(); ++j) - res[j] += other[j]; + MD_NAT result; - return res; -} + for (auto j = 0; j < _value.size(); ++j) { + result.pushBack(operator[](j) + other[j]); + } -MD_NAT MD_NAT::operator+(const MD_NAT &other) const -{ - return *this += other; + return result; } -std::size_t MD_NAT::arity() const { return value_.size(); } +// Extra operations ------------------------------------------------------------ -std::ostream &operator<<(std::ostream &out, const MD_NAT &md) +std::size_t MD_NAT::arity() const { return _value.size(); } + +std::ostream& operator<<(std::ostream& out, const MD_NAT& md) { MD_NAT aux = md; unsigned int sz = aux.arity(); - if (sz == 1) + if (sz == 1) { out << aux[0]; - - if (sz > 1) { + } else if (sz > 1) { out << "("; for (unsigned int j = 0; j < sz - 1; ++j) out << aux[j] << ", "; diff --git a/sbg/natural.hpp b/sbg/natural.hpp index 0d841a47..5d2023b5 100755 --- a/sbg/natural.hpp +++ b/sbg/natural.hpp @@ -21,31 +21,33 @@ ******************************************************************************/ -#ifndef SBG_NAT_HPP -#define SBG_NAT_HPP +#ifndef SBGRAPH_SBG_NATURAL_HPP_ +#define SBGRAPH_SBG_NATURAL_HPP_ -#include +#include #include -#include -#include #include -#include "util/defs.hpp" - namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Naturals implementation ------------------------------------------------------ +// Naturals implementation ----------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -typedef long long unsigned int NAT; -const NAT Inf = std::numeric_limits::max(); +using NAT = long long unsigned int; +constexpr NAT Inf = std::numeric_limits::max(); + +//////////////////////////////////////////////////////////////////////////////// +// Naturals implementation ----------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// -typedef std::vector VNAT; class MD_NAT { - member_class(VNAT, value); +public: + using VNAT = std::vector; + using Iterator = VNAT::iterator; + using ConstIterator = VNAT::const_iterator; /** * @brief Constructs a zero-dimensional mdnat. @@ -55,57 +57,57 @@ class MD_NAT { /** * @brief Constructs a one-dimensional mdnat with value x. */ - MD_NAT(NAT x); + MD_NAT(const NAT x); /** * @brief Constructs a nmbr_copies-dimensional mdnat with value x in every * dimension. */ - MD_NAT(unsigned int nmbr_copies, NAT x); + MD_NAT(const std::size_t k, NAT x); /** * @brief Range constructor. */ - MD_NAT(VNAT::iterator b, VNAT::iterator e); + MD_NAT(Iterator b, Iterator e); - typedef VNAT::iterator iterator; - typedef VNAT::const_iterator const_iterator; - iterator begin(); - iterator end(); - const_iterator begin() const; - const_iterator end() const; + Iterator begin(); + Iterator end(); + ConstIterator begin() const; + ConstIterator end() const; /** * @brief Add a dimension to the mdnat, and assign to it the value of x. */ - void emplaceBack(NAT x); + void pushBack(const NAT x); - NAT &operator[](std::size_t n); - const NAT &operator[](std::size_t n) const; + NAT& operator[](std::size_t n); + const NAT& operator[](std::size_t n) const; - bool operator==(const MD_NAT &other) const; - bool operator!=(const MD_NAT &other) const; + bool operator==(const MD_NAT& other) const; + bool operator!=(const MD_NAT& other) const; /** * @brief A mdnat x1 is less than other mdnat x2 iff there is some dimension * i for which x1[i] < x2[i] and for every j < i, x1[j] == x2[j]. */ - bool operator<(const MD_NAT &other) const; + bool operator<(const MD_NAT& other) const; - bool operator<=(const MD_NAT &other) const; + bool operator<=(const MD_NAT& other) const; - MD_NAT operator+=(const MD_NAT &other) const; - MD_NAT operator+(const MD_NAT &other) const; + MD_NAT operator+(const MD_NAT& other) const; /** * @brief Number of dimensions of the mdnat, i.e. arity(1, 1, 1) = 3. */ std::size_t arity() const; + +private: + VNAT _value; }; -std::ostream &operator<<(std::ostream &out, const MD_NAT &md); +std::ostream& operator<<(std::ostream& out, const MD_NAT& md); } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_NATURAL_HPP_ diff --git a/sbg/ord_pwmap.cpp b/sbg/ord_pwmap.cpp index 4aa766e0..5122c6cc 100644 --- a/sbg/ord_pwmap.cpp +++ b/sbg/ord_pwmap.cpp @@ -17,103 +17,159 @@ ******************************************************************************/ -#include - -#include "sbg/map_entry.hpp" #include "sbg/ord_pwmap.hpp" +#include "sbg/perimeter.hpp" + +#include +#include +#include namespace SBG { namespace LIB { -using Internal::calculatePerimeter; -using Internal::doInt; -using Internal::createMapEntry; -using Internal::operator<; -using Internal::emplaceHint; -using Internal::advanceHint; +namespace detail { //////////////////////////////////////////////////////////////////////////////// // Ordered PWMap Implementation ------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// -// Member functions - Ordered Piecewise maps ----------------------------------- +// Auxiliary definitions ------------------------------------------------------- -member_imp(OrdPWMap, OrdPWMap::OrdMapCollection, pieces); +class MapLess { +public: + bool operator()(const Map& a, const Map& b) const { + return a.domain().minElem() < b.domain().minElem(); + } +}; -OrdPWMap::OrdPWMap() : pieces_() {} -OrdPWMap::OrdPWMap(const Set& s) : pieces_() { +// Constructors/Destructors ---------------------------------------------------- + +OrdPWMap::OrdPWMap() : _pieces() {} + +OrdPWMap::OrdPWMap(const Set& s) : _pieces() { if (!s.isEmpty()) { - SetPiece first = s.begin().operator*(); - pieces_.push_back(createMapEntry(Map(s, Exp(first.arity() - , LExp())))); + _pieces.emplace_back(Map{s, Expression{s.arity(), 1, 0}}); } } -OrdPWMap::OrdPWMap(const Map& m) : pieces_() { - if (!m.isEmpty()){ - pieces_.push_back(createMapEntry(m)); + +OrdPWMap::OrdPWMap(const Map& m) : _pieces() { + if (!m.domain().isEmpty()) { + _pieces.emplace_back(m); } } -OrdPWMap::OrdPWMap(const OrdMapCollection& pieces) - : pieces_(std::move(pieces)) {} -member_imp(OrdPWMap::Iterator, OrdPWMap::OrdMapCollection::const_iterator, it); +OrdPWMap::OrdPWMap(const std::vector& pieces) : _pieces() { + for (const Map& m : pieces) { + insert(m); + } +} + +OrdPWMap::OrdPWMap(const OrdPWMap::OrdMapCollection& pieces) + : _pieces(pieces) {} + +OrdPWMap::OrdPWMap(OrdPWMap::OrdMapCollection&& pieces) + : _pieces(std::move(pieces)) {} + +// Getters --------------------------------------------------------------------- -OrdPWMap::Iterator::Iterator(OrdMapCollection::const_iterator it) - : it_(it) {} +OrdPWMap::ConstIt OrdPWMap::begin() const { return _pieces.begin(); } -void OrdPWMap::Iterator::operator++() +OrdPWMap::ConstIt OrdPWMap::end() const { return _pieces.end(); } + +// Setters --------------------------------------------------------------------- + +void OrdPWMap::insert(const Map& m) { - ++it_; - return; + insert(Map{m}); } -bool OrdPWMap::Iterator::operator!=(const PWMapStrategy::Iterator& other) - const +void OrdPWMap::insert(Map&& m) { - return it_ != static_cast(&other)->it_; + if (!m.isEmpty()) { + MapEntry entry{m}; + if (isEmpty() || _pieces.back() < entry) { + _pieces.push_back(entry); + } else { + insertHint(0, std::move(m)); + } + } } -const Map& OrdPWMap::Iterator::operator*() const { return it_->first; } +void OrdPWMap::pushBack(const Map& m) +{ + pushBack(Map{m}); +} -std::shared_ptr OrdPWMap::begin() const -{ - return std::make_shared(pieces_.begin()); +void OrdPWMap::pushBack(Map&& m) +{ + if (!m.isEmpty()) { + _pieces.emplace_back(std::move(m)); + } } -std::shared_ptr OrdPWMap::end() const +void OrdPWMap::pushBack(const MapEntry& entry) { - return std::make_shared(pieces_.end()); + pushBack(MapEntry{entry}); } -void OrdPWMap::emplaceBack(const Map& m) -{ - if (!m.isEmpty()){ - MapEntry mpe = createMapEntry(m); - if (pieces_.empty() || pieces_.back().second.first < mpe.second.first) - pieces_.push_back(mpe); - else - emplaceHint(pieces_, m, 0); +void OrdPWMap::pushBack(MapEntry&& entry) +{ + if (!entry.map().isEmpty()) { + _pieces.push_back(std::move(entry)); } } -bool OrdPWMap::operator==(const PWMapStrategy& other) const -{ - OrdPWMapCRef othr = static_cast(other); +void OrdPWMap::insertHint(std::size_t hint, const Map& m) +{ + insertHint(hint, Map{m}); +} - if (dom() != othr.dom()) { - return false; +void OrdPWMap::insertHint(std::size_t hint, Map&& m) +{ + if (!m.isEmpty()) { + auto it = _pieces.begin(); + std::advance(it, hint); + auto end = _pieces.end(); + MapEntry map_entry{m}; + while (it != end) { + if (*it < map_entry) { + ++it; + } else { + break; + } + } + _pieces.insert(it, map_entry); } +} - if (pieces_ == othr.pieces_) { - return true; +std::size_t OrdPWMap::advanceHint(std::size_t hint, const MapEntry& jth_entry) +{ + auto it = _pieces.begin(); + std::advance(it, hint); + auto end = _pieces.end(); + while (it != end) { + if (*it < jth_entry) { + ++it; + ++hint; + } else { + break; + } } - - OrdMapCollection short_pw = pieces_; - OrdMapCollection long_pw = othr.pieces_; - if (othr.pieces_.size() < pieces_.size()) { - short_pw = othr.pieces_; - long_pw = pieces_; + + return hint; +} + +// Traverse -------------------------------------------------------------------- + +template +Core OrdPWMap::traverse(const OrdPWMap& other, Core core_op) const +{ + OrdMapCollection short_pw = _pieces; + OrdMapCollection long_pw = other._pieces; + if (!core_op.orderMatters() && long_pw.size() < short_pw.size()) { + short_pw = other._pieces; + long_pw = _pieces; } // Indexes list corresponding to remaining maps in short_pw @@ -125,39 +181,32 @@ bool OrdPWMap::operator==(const PWMapStrategy& other) const auto short_begin = short_pw.begin(); for (const MapEntry& long_mpe : long_pw) { - const Map& long_map = long_mpe.first; - const SetPerimeter& long_sp = long_mpe.second; + const Perimeter& long_perimeter = long_mpe.perimeter(); auto prev_index = indexes.before_begin(); auto curr_index = indexes.begin(); while (curr_index != indexes.end()) { size_t idx = *curr_index; const MapEntry& short_mpe = *(short_begin + idx); - const Map& short_map = short_mpe.first; - const SetPerimeter& short_sp = short_mpe.second; + const Perimeter& short_perimeter = short_mpe.perimeter(); - if (short_sp.second < long_sp.first) { + // Here short_map is "before" long_map, so it is also "before" all the + // remaining sets in long_pw, thus it can be discarded. + if (short_perimeter.max() < long_perimeter.min()) { curr_index = indexes.erase_after(prev_index); continue; } - if (long_sp.second < short_sp.first) + // Here short_map is "after" long_map, so no comparison is needed, and + // the loop of long_pw continues to check if this short_map interacts + // with the following elements of long_pw. + if (long_perimeter.max() < short_perimeter.min()) { break; + } - if (doInt(short_sp, long_sp)) { - Set cap_dom = short_map.dom().intersection(long_map.dom()); - if (!cap_dom.isEmpty()) { - Exp short_exp = short_map.exp(); - Exp long_exp = long_map.exp(); - if (short_exp != long_exp) { - return false; - } - - Map short_cap_map(cap_dom, short_exp); - Map long_cap_map(cap_dom, long_exp); - if (short_cap_map != long_cap_map) { - return false; - } + if (short_perimeter.overlap(long_perimeter)) { + if (!core_op(short_mpe, long_mpe)) { + return core_op; } } @@ -169,242 +218,271 @@ bool OrdPWMap::operator==(const PWMapStrategy& other) const break; } } - - return true; + + return core_op; } -bool OrdPWMap::operator!=(const PWMapStrategy& other) const +// Operators ------------------------------------------------------------------- + +class EqualCore { +public: + bool operator()(const MapEntry& entry1, const MapEntry& entry2) { + Map m1 = entry1.map(); + Map m2 = entry2.map(); + Set cap_domain = m1.domain().intersection(m2.domain()); + if (!cap_domain.isEmpty()) { + Expression expr1 = m1.law(); + Expression expr2 = m2.law(); + if (expr1 != expr2) { + _are_equal = false; + return false; + } + + Map cap_m1{cap_domain, expr1}; + Map cap_m2{cap_domain, expr2}; + if (cap_m1 != cap_m2) { + _are_equal = false; + return false; + } + } + + _are_equal = true; + return true; + } + + bool orderMatters() const { return false; } + + bool result() const { return _are_equal; } + +private: + bool _are_equal = true; +}; + +bool OrdPWMap::operator==(const OrdPWMap& other) const +{ + if (domain() != other.domain()) { + return false; + } + + if (_pieces == other._pieces) { + return true; + } + + return traverse(other, EqualCore{}).result(); +} + +bool OrdPWMap::operator!=(const OrdPWMap& other) const { return !(*this == other); } -OrdPWMap& OrdPWMap::operator=(OrdPWMap&& other) +class AddCore { +public: + bool operator()(const MapEntry& entry1, const MapEntry& entry2) { + Map added = entry1.map() + entry2.map(); + _global_pos = _result.advanceHint(_global_pos, entry2); + _result.insertHint(_global_pos, added); + return true; + } + + bool orderMatters() const { return false; } + + OrdPWMap result() const { return _result; } + +private: + OrdPWMap _result; + std::size_t _global_pos = 0; +}; + +OrdPWMap OrdPWMap::operator+(const OrdPWMap& other) const { - if (this != &other) - pieces_ = std::move(other.pieces_); - - return *this; + if (isEmpty() || other.isEmpty()) { + return OrdPWMap{}; + } + + return traverse(other, AddCore{}).result(); } std::ostream& OrdPWMap::print(std::ostream& out) const { - int sz = pieces_.size(); + int sz = _pieces.size(); out << "<<"; if (sz > 0) { int i = 0; for (; i < sz - 1; ++i) { - out << pieces_[i].first << ", "; + out << _pieces[i].map() << ", "; } - out << pieces_[i].first; + out << _pieces[i].map(); } out << ">>"; return out; } -PWMapStratPtr OrdPWMap::operator+(const PWMapStrategy& other) const -{ - Set set_in = SET_FACT.createSet(); - Set set_out = SET_FACT.createSet(); - OrdMapCollection res; - processMapsOrd(other,set_in, set_out, res, &OrdPWMap::processAdd, false); - return std::make_unique(std::move(res)); -} - -void OrdPWMap::processAdd(const Map& m1, const Map& m2, - Set& set_in, Set& set_out, - OrdMapCollection& ord_pwmap, - NAT& global_pos) const -{ - Map res_add = m1 + m2; - if (!res_add.dom().isEmpty()){ - advanceHint(ord_pwmap, calculatePerimeter(m2.dom()).first, global_pos); - emplaceHint(ord_pwmap, res_add, global_pos); - } -} - -PWMapStratPtr OrdPWMap::clone() const -{ - return std::make_unique(pieces_); -} - // PWMap functions ------------------------------------------------------------- std::size_t OrdPWMap::arity() const { - if (isEmpty()) + if (isEmpty()) { return 0; + } - return pieces_.begin()->first.dom().arity(); + return _pieces.begin()->map().domain().arity(); } -bool OrdPWMap::isEmpty() const -{ - return pieces_.empty(); +bool OrdPWMap::isEmpty() const { return _pieces.empty(); } + +Set OrdPWMap::domain() const & +{ + Set result; + + for (const MapEntry& entry : _pieces) { + result = std::move(result).disjointCup(entry.map().domain()); + } + + return result; } -Set OrdPWMap::dom() const +Set OrdPWMap::domain() && { - Set result = SET_FACT.createSet(); - for (const MapEntry& mpe : pieces_) { - Set dom = mpe.first.dom(); - for (const SetPiece& mdi : dom) { - result.emplaceBack(mdi); - } + Set result; + + for (MapEntry& entry : _pieces) { + result = std::move(result).disjointCup(std::move(entry.map()).domain()); } return result; } -PWMapStratPtr OrdPWMap::restrict(const Set& subdom) const +OrdPWMap OrdPWMap::restrict(const Set& subdom) const { - OrdMapCollection res; - if (subdom.isEmpty()) { - return std::make_unique(res); + if (subdom.isEmpty() || isEmpty()) { + return OrdPWMap{}; } + OrdPWMap result; NAT global_pos = 0; - - SetPerimeter s_sp = calculatePerimeter(subdom); - auto s_max_per = s_sp.second; - - for (const MapEntry& mpe : pieces_) { - const Map& m = mpe.first; - const SetPerimeter& m_sp = mpe.second; - auto m_min_per = m_sp.first; - - if (doInt(m_sp, s_sp)) { - Map res_rest = m.restrict(subdom); - if (!res_rest.isEmpty()) { - advanceHint(res, m_min_per, global_pos); - emplaceHint(res, res_rest, global_pos); - } + Perimeter subdom_perimeter = subdom.perimeter(); + const MD_NAT subdom_max_perimeter = subdom_perimeter.max(); + for (const MapEntry& entry : _pieces) { + const Perimeter& entry_perimeter = entry.perimeter(); + if (subdom_perimeter.overlap(entry_perimeter)) { + result.advanceHint(global_pos, entry); + result.insertHint(global_pos, entry.map().restrict(subdom)); continue; } - - if (s_max_per < m_min_per) + + // No possible intersection between the subdom and the remaining elements + // of _pieces. + if (subdom_max_perimeter < entry_perimeter.min()) { break; + } } - return std::make_unique(std::move(res)); + return result; } Set OrdPWMap::image() const { - Set res = SET_FACT.createSet(); + Set result; - for (const MapEntry& mpe : pieces_) { - Set ith_img = mpe.first.image(); - res = std::move(res).cup(std::move(ith_img)); + for (const MapEntry& entry : _pieces) { + result = std::move(result).cup(entry.map().image()); } - return res; + return result; } Set OrdPWMap::image(const Set& subdom) const { - return restrict(subdom)->image(); + return restrict(subdom).image(); } Set OrdPWMap::preImage(const Set& subcodom) const { - Set result = SET_FACT.createSet(); + Set result; - for (const MapEntry& mpe : pieces_) { - Set ith_pre = mpe.first.preImage(subcodom); - result = std::move(result).disjointCup(std::move(ith_pre)); + for (const MapEntry& entry : _pieces) { + result = std::move(result).disjointCup(entry.map().preImage(subcodom)); } return result; } -PWMapStratPtr OrdPWMap::inverse() const -{ - OrdMapCollection res; +OrdPWMap OrdPWMap::inverse() const +{ + OrdPWMap result; - for (const MapEntry& mpe : pieces_){ - const Map& inv = mpe.first.minInv(); - if(!inv.isEmpty()) - Internal::emplaceBack(res, inv); + for (const MapEntry& entry : _pieces) { + result.emplace(entry.map().inverse()); } - - std::sort(res.begin(),res.end(), operator<); - return std::make_unique(std::move(res)); + return result; } -PWMapStratPtr OrdPWMap::composition(const PWMapStrategy& other) const +OrdPWMap OrdPWMap::composition(const OrdPWMap& other) const { - OrdMapCollection res; - OrdPWMapCRef othr = static_cast(other); + OrdPWMap result; NAT global_pos = 0; - - for (const MapEntry& o_mpe : othr.pieces_) { - const auto& o_m = o_mpe.first; - auto img = o_m.image(); + for (const MapEntry& other_entry : other._pieces) { + Map other_map = other_entry.map(); + Set img = other_map.image(); - SetPerimeter i_sp = calculatePerimeter(img); - auto i_max_per = i_sp.second; - - advanceHint(res, o_mpe.second.first, global_pos); - - for (const MapEntry& t_mpe : pieces_) { - const auto& t_m = t_mpe.first; - const SetPerimeter& t_sp = t_mpe.second; - auto t_min_per = t_sp.first; - - if (doInt(t_sp, i_sp)) { - auto res_com = t_m.composition(o_m); - if (!res_com.isEmpty()) - emplaceHint(res, res_com, global_pos); + Perimeter img_perimeter = img.perimeter(); + result.advanceHint(global_pos, other_entry); + MD_NAT img_max_perimeter = img_perimeter.max(); + + for (const MapEntry& entry : _pieces) { + const Perimeter& entry_perimeter = entry.perimeter(); + if (entry_perimeter.overlap(img_perimeter)) { + Map composed = entry.map().composition(other_map); + result.insertHint(global_pos, composed); continue; } - if (i_max_per < t_min_per) + // No possible intersection between the current image and the remaining + // elements of _pieces. + if (img_max_perimeter < entry_perimeter.min()) { break; + } } } - return std::make_unique(std::move(res)); + return result; } -PWMapStratPtr OrdPWMap::mapInf(unsigned int n) const +OrdPWMap OrdPWMap::mapInf(unsigned int n) const { - PWMapStratPtr result = std::make_unique(pieces_); + OrdPWMap result{_pieces}; - if (!dom().isEmpty()) { + if (!domain().isEmpty()) { for (unsigned int j = 0; j < n; ++j) { - PWMapStratPtr new_res = result->composition(*this); - result = std::move(new_res); + result = composition(result); } - - PWMapStratPtr reduced = result->reduce(); - result = std::move(reduced); - PWMapStratPtr old_res = result->clone(); + + result = result.reduce(); + OrdPWMap old_result{result}; do { - old_res = result->clone(); - - PWMapStratPtr new_res = result->composition(*result); - new_res = new_res->reduce(); - result = std::move(new_res); - } while (*old_res != *result); + old_result = result; + + result = result.composition(result).reduce(); + } while (old_result != result); } - + return result; } -PWMapStratPtr OrdPWMap::mapInf() const { return mapInf(0); } +OrdPWMap OrdPWMap::mapInf() const { return mapInf(0); } Set OrdPWMap::fixedPoints() const { - Set result = SET_FACT.createSet(); + Set result; - for (const MapEntry& entry : pieces_) { - Set ith_fixed = entry.first.fixedPoints(); - result = std::move(result).disjointCup(std::move(ith_fixed)); + for (const MapEntry& entry : _pieces) { + result = std::move(result).disjointCup(entry.map().fixedPoints()); } return result; @@ -412,453 +490,332 @@ Set OrdPWMap::fixedPoints() const // Extra operations ------------------------------------------------------------ -PWMapStratPtr OrdPWMap::concatenation(const PWMapStrategy& other) const +OrdPWMap OrdPWMap::concatenation(const OrdPWMap& other) const & { - OrdMapCollection res; - OrdPWMapCRef othr = static_cast(other); - res.reserve(pieces_.size() + othr.pieces_.size()); - - if (isEmpty()) { - return std::make_unique(othr.pieces_); + return OrdPWMap{*this}.concatenation(other); +} + +OrdPWMap OrdPWMap::concatenation(const OrdPWMap& other) && +{ + return std::move(*this).concatenation(OrdPWMap{other}); +} + +OrdPWMap OrdPWMap::concatenation(OrdPWMap&& other) const & +{ + return OrdPWMap{*this}.concatenation(std::move(other)); +} + +OrdPWMap OrdPWMap::concatenation(OrdPWMap&& other) && +{ + // Special cases + if (isEmpty()) { + return std::move(other); } if (other.isEmpty()) { - return std::make_unique(pieces_); - } - - if (pieces_.back().second.first < othr.pieces_.front().second.first) { - res.insert(res.end(), pieces_.begin(), pieces_.end()); - res.insert(res.end(), othr.pieces_.begin(), othr.pieces_.end()); - return std::make_unique(std::move(res)); - } - - if (othr.pieces_.back().second.first < pieces_.front().second.first) { - res.insert(res.end(), othr.pieces_.begin(), othr.pieces_.end()); - res.insert(res.end(), pieces_.begin(), pieces_.end()); - return std::make_unique(std::move(res)); + return std::move(*this); } - - auto it1 = pieces_.begin(), it2 = othr.pieces_.begin(); - auto end1 = pieces_.end(), end2 = othr.pieces_.end(); - - for (; it1 != end1 && it2 != end2;) { - auto min_per_m1 = it1->second.first; - auto min_per_m2 = it2->second.first; - if (min_per_m1 < min_per_m2) { - Internal::emplaceBack(res, *it1); - ++it1; - } else { - Internal::emplaceBack(res, *it2); - ++it2; + OrdMapCollection result; + if (_pieces.back() < other._pieces.front()) { + result.insert(result.end(), std::make_move_iterator(_pieces.begin()) + , std::make_move_iterator(_pieces.end())); + result.insert(result.end(), std::make_move_iterator(other._pieces.begin()) + , std::make_move_iterator(other._pieces.end())); + } else if (other._pieces.back() < _pieces.front()) { + result.insert(result.end(), std::make_move_iterator(other._pieces.begin()) + , std::make_move_iterator(other._pieces.end())); + result.insert(result.end(), std::make_move_iterator(_pieces.begin()) + , std::make_move_iterator(_pieces.end())); + } else { + // General case + auto it1 = _pieces.begin(); + auto end1 = _pieces.end(); + auto it2 = other._pieces.begin(); + auto end2 = other._pieces.end(); + while (it1 != end1 && it2 != end2) { + if (*it1 < *it2) { + result.push_back(*it1); + ++it1; + } else { + result.push_back(*it2); + ++it2; + } } + result.insert(result.end(), std::make_move_iterator(it1) + , std::make_move_iterator(end1)); + result.insert(result.end(), std::make_move_iterator(it2) + , std::make_move_iterator(end2)); } - res.insert(res.end(), it1, end1); - res.insert(res.end(), it2, end2); + return OrdPWMap{std::move(result)}; +} - return std::make_unique(std::move(res)); +OrdPWMap OrdPWMap::combine(const OrdPWMap& other) const & +{ + return OrdPWMap{*this}.combine(other); } -PWMapStratPtr OrdPWMap::combine(const PWMapStrategy& other) const +OrdPWMap OrdPWMap::combine(const OrdPWMap& other) && +{ + return std::move(*this).combine(OrdPWMap{other}); +} + +OrdPWMap OrdPWMap::combine(OrdPWMap&& other) const & +{ + return OrdPWMap{*this}.combine(std::move(other)); +} + +OrdPWMap OrdPWMap::combine(OrdPWMap&& other) && { - OrdPWMapCRef othr = static_cast(other); if (isEmpty()) { - return std::make_unique(othr.pieces_); + return std::move(other); } if (other.isEmpty()) { - return std::make_unique(pieces_); + return std::move(*this); } - if (pieces_ == othr.pieces_) { - return std::make_unique(pieces_); + if (_pieces == other._pieces) { + return std::move(*this); } - Set exclusive_other = other.dom().difference(dom()); - - return concatenation(*other.restrict(exclusive_other)); + Set exclusive_other = other.domain().difference(domain()); + return std::move(*this).concatenation(other.restrict(exclusive_other)); } -PWMapStratPtr OrdPWMap::reduce() const -{ - OrdMapCollection result; - for (const MapEntry& mpe : pieces_) { - std::vector reduced = mpe.first.reduce(); - for (const Map& reduced_map : reduced) { - Internal::emplaceBack(result, reduced_map); +OrdPWMap OrdPWMap::reduce() const +{ + OrdPWMap result; + + for (const MapEntry& entry : _pieces) { + std::vector reduced = entry.map().reduce(); + for (Map& reduced_map : reduced) { + result.insert(std::move(reduced_map)); } - } + } - std::sort(result.begin(), result.end(), operator<); - return std::make_unique(std::move(result)); + return result; } -PWMapStratPtr OrdPWMap::minMap(const PWMapStrategy& other) const +OrdPWMap OrdPWMap::min(const OrdPWMap& other) const { if (isEmpty() || other.isEmpty()) { - return std::make_unique(); + return OrdPWMap{}; } Set min_in_pw1 = lessImage(other); - return restrict(min_in_pw1)->combine(*other.restrict(dom())); -} - -PWMapStratPtr OrdPWMap::minAdjMap(const PWMapStrategy& other) const -{ - Set set_in = SET_FACT.createSet(); - Set set_out = SET_FACT.createSet(); - OrdMapCollection res; - processMapsOrd(other, set_in, set_out, res, &OrdPWMap::processMinAdjMap, true); - std::sort(res.begin(), res.end(), operator<); - return std::make_unique(std::move(res)); -} - -void OrdPWMap::processMinAdjMap(const Map& m1, const Map& m2, - Set& set_in, Set& set_out, - OrdMapCollection& ord_pwmap, - NAT& global_pos) const -{ - Set dom_res = SET_FACT.createSet(); - Set ith_dom = m1.dom().intersection(m2.dom()); - if (!ith_dom.isEmpty()) { - Exp e_res, e1; - - dom_res = m1.image(ith_dom); - e1 = m1.exp(); - - Set im2 = m2.image(ith_dom); - if (!e1.isConstant()) - e_res = m2.exp().composition(e1.inverse()); - else - e_res = MDLExp(im2.minElem()); - - if (!dom_res.isEmpty()) { - Map ith(dom_res, e_res); - OrdPWMap ith_pw(ith); - Set again = dom_res.intersection(set_in); - if (!again.isEmpty()) { - OrdPWMap ord_pwmap_aux(ord_pwmap); - std::sort(ord_pwmap_aux.pieces_.begin(), ord_pwmap_aux.pieces_.end() - , operator<); - PWMapStratPtr aux_res = ord_pwmap_aux.restrict(dom_res); - PWMapStratPtr min_map = aux_res->minMap(ith_pw); - PWMapStratPtr new_resPtr = min_map->combine(ith_pw)->combine(ord_pwmap_aux); - OrdPWMapCRef new_res_c = static_cast(*new_resPtr); - ord_pwmap = std::move(new_res_c.pieces_); - Set ith_dom = ith_pw.dom(); - set_in = std::move(set_in).cup(std::move(ith_dom)); - } - else { - Internal::emplaceBack(ord_pwmap, ith); - set_in = std::move(set_in).disjointCup(std::move(dom_res)); + return restrict(min_in_pw1).combine(other.restrict(domain())); +} + +class MinAdjCore { +public: + bool operator()(const MapEntry& entry1, const MapEntry& entry2) { + Map min_adj = entry1.map().minAdj(entry2.map()); + if (!min_adj.isEmpty()) { + Set min_adj_domain = min_adj.domain(); + Set repeated = min_adj_domain.intersection(_visited); + if (!repeated.isEmpty()) { + OrdPWMap min_adj_pw{std::move(min_adj)}; + OrdPWMap min_adj_repeated = min_adj_pw.restrict(repeated); + OrdPWMap result_repeated = _result.restrict(repeated); + OrdPWMap min_map = min_adj_repeated.min(result_repeated); + OrdPWMap min_adj_result = std::move(min_map).combine( + std::move(min_adj_pw)); + _result = std::move(min_adj_result).combine(std::move(_result)); + _visited = std::move(_visited).cup(std::move(min_adj_domain)); + } else { + _result.insert(std::move(min_adj)); + _visited = std::move(_visited).disjointCup(std::move(min_adj_domain)); } } - } -} -PWMapStratPtr OrdPWMap::firstInv(const Set& subdom) const -{ - OrdMapCollection res; - if (isEmpty() || subdom.isEmpty()) { - return std::make_unique(res); + return true; } - SetPerimeter s_sp = calculatePerimeter(subdom); - auto s_max_per = s_sp.second; - Set visited = SET_FACT.createSet(); - - for (const MapEntry& t_mpe : pieces_) { - const Map& t_m = t_mpe.first; - const SetPerimeter& t_sp = t_mpe.second; - auto t_min_per = t_sp.first; + bool orderMatters() const { return true; } - - if (doInt(t_sp, s_sp)) { - Set img = t_m.image(subdom); - - if (!img.isEmpty()) { - - if (!visited.isEmpty()) { - SetPerimeter i_sp = calculatePerimeter(img); - SetPerimeter v_sp = calculatePerimeter(visited); - - if (doInt(i_sp, v_sp)) { - Set res_dom = img.difference(visited); - if (!res_dom.isEmpty()) - img = res_dom; - else - continue; - } - } - Map new_map(t_m.preImage(img), t_m.exp()); - Internal::emplaceBack(res, new_map.minInv()); - visited = std::move(visited).disjointCup(std::move(img)); - continue; - } - } - if (s_max_per < t_min_per) break; + OrdPWMap result() const { return _result; } + +private: + OrdPWMap _result; + Set _visited; +}; + +OrdPWMap OrdPWMap::minAdj(const OrdPWMap& other) const +{ + if (isEmpty() || other.isEmpty()) { + return OrdPWMap{}; } - std::sort(res.begin(), res.end(), operator<); - return std::make_unique(std::move(res)); + return traverse(other, MinAdjCore{}).result(); } -PWMapStratPtr OrdPWMap::firstInv() const { return firstInv(dom()); } - -PWMapStratPtr OrdPWMap::filterMap(bool (*f)(const Map& )) const -{ - OrdMapCollection res; - for (const MapEntry& mpe : pieces_) { - if (f(mpe.first)) { - Internal::emplaceBack(res, mpe); +Set OrdPWMap::sharedImage() const +{ + Set repeated_image; + Set visited; + for (const MapEntry& entry : _pieces) { + Set m_image = entry.map().image(); + Set image_in_visited = m_image.intersection(visited); + if (!image_in_visited.isEmpty()) { + repeated_image = std::move(repeated_image).cup(std::move( + image_in_visited)); } + visited = std::move(visited).cup(m_image); } - - return std::make_unique(std::move(res)); + + return preImage(repeated_image); } -Set OrdPWMap::equalImage(const PWMapStrategy& other) const -{ - Set set_in = SET_FACT.createSet(); - Set set_out = SET_FACT.createSet(); - OrdMapCollection unused; - processMapsOrd(other, set_in, set_out, unused, &OrdPWMap::processEqualImage - , false); - return set_out; -} - -void OrdPWMap::processEqualImage(const Map& m1, const Map& m2, - Set& set_in, Set& set_out, - OrdMapCollection& ord_pwmap, - NAT& global_pos) const -{ - Set cap_dom = m1.dom().intersection(m2.dom()); - if (!cap_dom.isEmpty()) { - Map m1_cap(cap_dom, m1.exp()); - Map m2_cap(cap_dom, m2.exp()); - if (m1_cap == m2_cap) { - set_out = std::move(set_out).disjointCup(std::move(cap_dom)); +class EqualImageCore { +public: + bool operator()(const MapEntry& entry1, const MapEntry& entry2) { + Map m1 = entry1.map(); + Map m2 = entry2.map(); + Set cap_dom = m1.domain().intersection(m2.domain()); + if (!cap_dom.isEmpty()) { + Map m1_cap{cap_dom, m1.law()}; + Map m2_cap{cap_dom, m2.law()}; + if (m1_cap == m2_cap) { + _result = std::move(_result).disjointCup(std::move(cap_dom)); + } } + + return true; } -} -Set OrdPWMap::lessImage(const PWMapStrategy& other) const -{ - Set set_in = SET_FACT.createSet(); - Set set_out = SET_FACT.createSet(); - OrdMapCollection unused; - processMapsOrd(other, set_in, set_out, unused, &OrdPWMap::processLessImage - , true); - return set_out; -} - -void OrdPWMap::processLessImage(const Map& m1, const Map& m2, - Set& set_in, Set& set_out, - OrdMapCollection& ord_pwmap, - NAT& global_pos) const -{ - Set ith_less = m1.lessImage(m2); - set_out = std::move(set_out).disjointCup(std::move(ith_less)); -} + bool orderMatters() const { return false; } -void OrdPWMap::processMapsOrd( - const PWMapStrategy& other, - Set& set_in, - Set& set_out, - OrdMapCollection& ord_map, - ProcessFunc process, - bool order_mts -) const -{ - OrdPWMapCRef othr = static_cast(other); + Set result() const { return _result; } - int sz = pieces_.size(); - int othr_sz = othr.pieces_.size(); - ord_map.reserve(2*(sz + othr_sz)); +private: + Set _result; +}; - const OrdPWMap *short_pw = this; - const OrdPWMap *long_pw = &othr; - if (!order_mts && othr.pieces_.size() < pieces_.size()) { - short_pw = &othr; - long_pw = this; +Set OrdPWMap::equalImage(const OrdPWMap& other) const +{ + if (isEmpty() || other.isEmpty()) { + return Set{}; } - std::forward_list indexes; - auto si_it = indexes.before_begin(); - - const size_t short_size = short_pw->pieces_.size(); - for (size_t i = 0; i < short_size; ++i) { - si_it = indexes.insert_after(si_it, i); + if (_pieces == other._pieces) { + return domain(); } - auto short_begin = short_pw->pieces_.begin(); - NAT global_pos = 0; - - for (const MapEntry& long_mpe : long_pw->pieces_) { - const Map& long_map = long_mpe.first; - const SetPerimeter& long_sp = long_mpe.second; - - auto si_prev = indexes.before_begin(); - auto si_curr = indexes.begin(); - - while (si_curr != indexes.end()) { - size_t idx = *si_curr; - const MapEntry& s_mpe = *(short_begin + idx); - const Map& s_m = s_mpe.first; - const SetPerimeter& s_sp = s_mpe.second; - - if (s_sp.second < long_sp.first) { - si_curr = indexes.erase_after(si_prev); - continue; - } - - if (long_sp.second < s_sp.first) - break; + return traverse(other, EqualImageCore{}).result(); +} - // Process overlapping perimeters - if (doInt(s_sp, long_sp)) { - (this->*process)(s_m, long_map, set_in, set_out, ord_map, global_pos); - } +class LessImageCore { +public: + bool operator()(const MapEntry& entry1, const MapEntry& entry2) { + Set less_map = entry1.map().lessImage(entry2.map()); + _result = std::move(_result).disjointCup(std::move(less_map)); - ++si_prev; - ++si_curr; - } - - if (indexes.empty()) { - break; - } + return true; } -} + bool orderMatters() const { return true; } -Set OrdPWMap::sharedImage() const -{ - Set not_present = dom().difference(firstInv()->image()); - Set res = preImage(image(not_present)); + Set result() const { return _result; } - return res; -} +private: + Set _result; +}; -PWMapStratPtr OrdPWMap::offsetDom(const MD_NAT& off) const +Set OrdPWMap::lessImage(const OrdPWMap& other) const { - OrdMapCollection res; + if (isEmpty() || other.isEmpty()) { + return Set{}; + } - for (const MapEntry& mpe : pieces_) { - Map map(mpe.first.dom().offset(off), mpe.first.exp()); - if(!map.isEmpty()) - Internal::emplaceBack(res, map); + if (_pieces == other._pieces) { + return Set{}; } - return std::make_unique(std::move(res)); -} + return traverse(other, LessImageCore{}).result(); +} -PWMapStratPtr OrdPWMap::offsetDom(const PWMapStrategy& off) const +OrdPWMap OrdPWMap::imageMultiplicity() const { - OrdMapCollection res; - const SetPerimeter o_sp = calculatePerimeter(off.dom()); - const auto o_max_per = o_sp.second; - for (const MapEntry& t_mpe : pieces_) { - const Map& t_m = t_mpe.first; - const SetPerimeter& t_sp = t_mpe.second; - const auto m_min_per = t_sp.first; - - if (doInt(t_sp, o_sp)) { - Set ith_dom = off.image(t_m.dom()); - - if (!ith_dom.isEmpty()){ - Map res_map(ith_dom, t_m.exp()); - Internal::emplaceBack(res, res_map); - } - continue; - } - - if (o_max_per < m_min_per) - break; + Map initial_result{image(), Expression{arity(), 0, 0}}; + OrdPWMap result{initial_result}; + + for (const MapEntry& entry : _pieces) { + OrdPWMap jth_mult{entry.map().imageMultiplicity()}; + OrdPWMap sum_mult = jth_mult + result; + result = std::move(sum_mult).combine(std::move(result)); } - std::sort(res.begin(),res.end(), operator<); - - return std::make_unique(std::move(res)); -} + return result; +} -PWMapStratPtr OrdPWMap::offsetImage(const MD_NAT& off) const +void OrdPWMap::compact() { - OrdMapCollection res; + using MapSet = std::set; + + OrdPWMap result; - for (const MapEntry& mpe : pieces_) { - Exp e = mpe.first.exp(), res_e; - for (unsigned int j = 0; j < e.arity(); ++j) { - LExp res_lexp(e[j].slope(), e[j].offset() + (RATIONAL) off[j]); - res_e.emplaceBack(res_lexp); + if (!isEmpty()) { + MapSet set_result; + for (const MapEntry& entry : _pieces) { + const Map& m = entry.map(); + Set new_domain = m.domain(); + new_domain.compact(); + set_result.emplace(new_domain, m.law()); } - Internal::emplaceBack(res, Map(mpe.first.dom(), res_e)); - } + MapSet to_erase; + do { + MapSet new_set_result; + to_erase.clear(); + + MapSet::iterator ith = set_result.begin(); + MapSet::iterator last = set_result.end(); + for (; ith != last; ++ith) { + Map ith_compact = *ith; + MapSet::iterator next = ith; + ++next; + for (; next != last; ++next) { + MaybeMap new_compact = ith_compact.compact(*next); + if (new_compact) { + ith_compact = new_compact.value(); + to_erase.insert(*next); + } + } - return std::make_unique(std::move(res)); -} + if (to_erase.find(ith_compact) == to_erase.end()) { + new_set_result.insert(ith_compact); + } + } -PWMapStratPtr OrdPWMap::offsetImage(const Exp& off) const -{ - OrdMapCollection res; + std::swap(set_result, new_set_result); + } while (!to_erase.empty()); - for (const MapEntry& mpe : pieces_) - Internal::emplaceBack(res, Map(mpe.first.dom(), off + mpe.first.exp())); + for (const Map& m : set_result) { + result.insert(m); + } + } - return std::make_unique(std::move(res)); + _pieces = std::move(result._pieces); } -PWMapStratPtr OrdPWMap::compact() const -{ - OrdMapCollection res; - if (dom().isEmpty()) { - return std::make_unique(res); - } - - std::forward_list indexes; - auto li_it = indexes.before_begin(); - - const size_t size = pieces_.size(); - for (size_t i = 0; i < size; ++i) - li_it = indexes.insert_after(li_it, i); +// Non-member functions -------------------------------------------------------- - auto begin = pieces_.begin(); - auto li_prev = indexes.before_begin(); - auto li_curr = indexes.begin(); - - while (li_curr != indexes.end()) { - size_t id = *li_curr; - const MapEntry& mpe = *(begin + id); - const Map& m = mpe.first; - Map new_m(m.dom().compact(), m.exp()); +rapidjson::Value toJSON(OrdPWMap pw, rapidjson::Document::AllocatorType& alloc) +{ + rapidjson::Value result{rapidjson::kArrayType}; - li_curr = indexes.erase_after(li_prev); - - while (li_curr != indexes.end()) { - size_t idx = *li_curr; - const MapEntry& next_mpe = *(begin + idx); - const Map& next_map = next_mpe.first; - - auto comp = new_m.compact(next_map); - if (comp) { - new_m = comp.value(); - li_curr = indexes.erase_after(li_prev); - continue; - } - - ++li_prev; - ++li_curr; - } - - Internal::emplaceBack(res, new_m); - li_prev = indexes.before_begin(); - li_curr = indexes.begin(); + for (const MapEntry& entry : pw) { + rapidjson::Value jth = toJSON(entry.map(), alloc); + result.PushBack(jth, alloc); } - return std::make_unique(std::move(res)); + return result; } +} // namespace detail + } // namespace LIB } // namespace SBG; diff --git a/sbg/ord_pwmap.hpp b/sbg/ord_pwmap.hpp index 78b46308..088a59b9 100644 --- a/sbg/ord_pwmap.hpp +++ b/sbg/ord_pwmap.hpp @@ -21,183 +21,161 @@ ******************************************************************************/ -#ifndef SBG_ORD_PWMAP_HPP -#define SBG_ORD_PWMAP_HPP +#ifndef SBGRAPH_SBG_ORD_PWMAP_HPP_ +#define SBGRAPH_SBG_ORD_PWMAP_HPP_ +#include "sbg/map.hpp" #include "sbg/map_entry.hpp" -#include "sbg/pw_map.hpp" +#include "sbg/set.hpp" + +#include "rapidjson/document.h" + +#include +#include namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// -// Ordered PWMap Implementation (concrete strategy) ---------------------------- +// Ordered PWMap Implementation ---------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -class OrdPWMap : public PWMapStrategy { - public: - using SetPerimeter = Internal::SetPerimeter; - using MapEntry = Internal::MapEntry; - using OrdMapCollection = Internal::OrdMapCollection; - - member_class(OrdMapCollection, pieces); +class OrdPWMap { +public: + using OrdMapCollection = std::vector; + using ConstIt = OrdMapCollection::const_iterator; - ~OrdPWMap() = default; OrdPWMap(); OrdPWMap(const Set& s); OrdPWMap(const Map& m); + OrdPWMap(const std::vector& pieces); OrdPWMap(const OrdMapCollection& pieces); + OrdPWMap(OrdMapCollection&& pieces); - class Iterator : public PWMapStrategy::Iterator { - member_class(OrdMapCollection::const_iterator, it); - - Iterator(OrdMapCollection::const_iterator it); - void operator++() override; - bool operator!=(const PWMapStrategy::Iterator& other) const override; - const Map& operator*() const override; - }; - - std::shared_ptr begin() const override; - std::shared_ptr end() const override; - - void emplaceBack(const Map& m) override; + ConstIt begin() const; + ConstIt end() const; - bool operator==(const PWMapStrategy& other) const override; - bool operator!=(const PWMapStrategy& other) const override; - OrdPWMap& operator=(OrdPWMap&& other); - std::ostream& print(std::ostream& out) const override; + template + void emplace(Args&&... args); + void insert(const Map& m); + void insert(Map&& m); - PWMapStratPtr operator+(const PWMapStrategy& other) const override; - - PWMapStratPtr clone() const override; + bool operator==(const OrdPWMap& other) const; + bool operator!=(const OrdPWMap& other) const; + OrdPWMap operator+(const OrdPWMap& other) const; + std::ostream& print(std::ostream& out) const; // Traditional map operations ------------------------------------------------ - std::size_t arity() const override; - bool isEmpty() const override; - Set dom() const override; - PWMapStratPtr restrict(const Set& subdom) const override; - Set image() const override; - Set image(const Set& subdom) const override; - Set preImage(const Set& subcodom) const override; - PWMapStratPtr inverse() const override; - PWMapStratPtr composition(const PWMapStrategy& pw2) const override; + std::size_t arity() const; + bool isEmpty() const; + Set domain() const &; + Set domain() &&; + OrdPWMap restrict(const Set& subdom) const; + Set image() const; + Set image(const Set& subdom) const; + Set preImage(const Set& subcodom) const; + OrdPWMap inverse() const; + OrdPWMap composition(const OrdPWMap& other) const; - PWMapStratPtr mapInf(unsigned int n) const override; - PWMapStratPtr mapInf() const override; - Set fixedPoints() const override; + OrdPWMap mapInf() const; + Set fixedPoints() const; // Extra operations ---------------------------------------------------------- - PWMapStratPtr concatenation(const PWMapStrategy& other) const override; - PWMapStratPtr combine(const PWMapStrategy& other) const override; - PWMapStratPtr reduce() const override; + OrdPWMap concatenation(const OrdPWMap& other) const &; + OrdPWMap concatenation(const OrdPWMap& other) &&; + OrdPWMap concatenation(OrdPWMap&& other) const &; + OrdPWMap concatenation(OrdPWMap&& other) &&; + OrdPWMap combine(const OrdPWMap& other) const &; + OrdPWMap combine(const OrdPWMap& other) &&; + OrdPWMap combine(OrdPWMap&& other) const &; + OrdPWMap combine(OrdPWMap&& other) &&; - PWMapStratPtr minMap(const PWMapStrategy& other) const override; - PWMapStratPtr minAdjMap(const PWMapStrategy& other) const override; + OrdPWMap min(const OrdPWMap& other) const; + OrdPWMap minAdj(const OrdPWMap& other) const; - PWMapStratPtr firstInv(const Set& subdom) const override; - PWMapStratPtr firstInv() const override; + Set sharedImage() const; + Set equalImage(const OrdPWMap& other) const; + Set lessImage(const OrdPWMap& other) const; - PWMapStratPtr filterMap(bool (*f)(const Map&)) const override; + OrdPWMap imageMultiplicity() const; - Set equalImage(const PWMapStrategy& other) const override; - Set lessImage(const PWMapStrategy& other) const override; - Set sharedImage() const override; + void compact(); - PWMapStratPtr offsetDom(const MD_NAT& off) const override; - PWMapStratPtr offsetDom(const PWMapStrategy& off) const override; - PWMapStratPtr offsetImage(const MD_NAT& off) const override; - PWMapStratPtr offsetImage(const Exp& off) const override; +private: + template + void emplaceBack(Args&&... args); + void pushBack(const Map& m); + void pushBack(Map&& m); + void pushBack(const MapEntry& entry); + void pushBack(MapEntry&& entry); - PWMapStratPtr compact() const override; - - private: - /** - * @brief Calculates the minAdjMap core, which contains the entire main process of the function. - */ - void processMinAdjMap( - const Map& m1, - const Map& m2, - Set& set_in, - Set& set_out, - OrdMapCollection& ord_pwmap, - NAT& global_pos) const; - - /** - * @brief Calculates the minus core, which contains the entire main process of the function. - */ - void processMinus( - const Map& m1, - const Map& m2, - Set& set_in, - Set& set_out, - OrdMapCollection& ord_pwmap, - NAT& global_pos) const; - - /** - * @brief Calculates the add core, which contains the entire main process of the function. - */ - void processAdd( - const Map& m1, - const Map& m2, - Set& set_in, - Set& set_out, - OrdMapCollection& ord_pwmap, - NAT& global_pos) const; - - /** - * @brief Calculates the equalImage core, which contains the entire main process of the function. - */ - void processEqualImage( - const Map& m1, - const Map& m2, - Set& set_in, - Set& set_out, - OrdMapCollection& ord_pwmap, - NAT& global_pos) const; + void insertHint(std::size_t hint, const Map& m); + void insertHint(std::size_t hint, Map&& m); /** - * @brief Calculates the lessImage core, which contains the entire main process of the function. + * @brief Advances the hint to point the next element that has jth_entry as + * its minimum in its perimeter. */ - void processLessImage( - const Map& m1, - const Map& m2, - Set& set_in, - Set& set_out, - OrdMapCollection& ord_pwmap, - NAT& global_pos) const; - + std::size_t advanceHint(std::size_t hint, const MapEntry& jth_entry); + /** - * @brief Type used in the 'processMapsOrd' declaration to reduce its size. - * This type is the same as the process functions above. + * @brief Calculates (if possible) compactly the result of mapInf.\n + * + * Currently, the only expressions that can be efficiently reduced are: + * - x+h + * - x-h */ - using ProcessFunc = void (OrdPWMap::*)( - const Map& , const Map& , - Set& , Set& , OrdMapCollection& , - NAT& - ) const; - - /** - * @brief Provides an efficient method for processing two ordered piecewise maps. + OrdPWMap reduce() const; + + /* + * @brief First compose the pw with itself \p n times, obtaining pw'. Then, + * compose pw' with itself up to convergence. */ - void processMapsOrd( - const PWMapStrategy& other, - Set& set_in, - Set& set_out, - OrdMapCollection& ord_pwmap, - ProcessFunc process, - bool order_mts - ) const; + OrdPWMap mapInf(unsigned int n) const; + + template + Core traverse(const OrdPWMap& other, Core op) const; + + OrdMapCollection _pieces; + + friend class AddCore; + friend class MinAdjCore; + friend class PWMapAccessKey; }; -typedef const OrdPWMap& OrdPWMapCRef; -typedef OrdPWMap& OrdPWMapRef; -typedef std::unique_ptr OrdPWMapPtr; +// Template definitions -------------------------------------------------------- + +template +inline void OrdPWMap::emplace(Args&&... args) +{ + auto&& domain = std::get<0>(std::forward_as_tuple(args...)); + if (!domain.isEmpty()) { + insert(Map{std::forward(args)...}); + } +} + +template +inline void OrdPWMap::emplaceBack(Args&&... args) +{ + auto&& domain = std::get<0>(std::forward_as_tuple(args...)); + if (!domain.isEmpty()) { + _pieces.emplace_back(std::forward(args)...); + } +} + +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(OrdPWMap pw, rapidjson::Document::AllocatorType& alloc); + +} // namespace detail } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_ORD_PWMAP_HPP_ diff --git a/sbg/ord_set.cpp b/sbg/ord_set.cpp index 8b3f1d5e..c41e5a9e 100644 --- a/sbg/ord_set.cpp +++ b/sbg/ord_set.cpp @@ -17,25 +17,27 @@ ******************************************************************************/ -#include -#include - #include "sbg/ord_set.hpp" +#include +#include +#include +#include + namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// -// Ordered Set Implementation -------------------------------------------------- +// Auxiliary functions --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -// Auxiliary functions - Ordered Sets ------------------------------------------ - /** * @brief Checks if the both set pieces overlap. */ -bool doInt(const SetPiece& mdi1, const SetPiece& mdi2) +bool overlap(const MultiDimInter& mdi1, const MultiDimInter& mdi2) { const auto max1 = mdi1.maxElem(); const auto min1 = mdi1.minElem(); @@ -44,198 +46,164 @@ bool doInt(const SetPiece& mdi1, const SetPiece& mdi2) const unsigned int arity = mdi1.arity(); for (unsigned int j = 0; j < arity; ++j) { - if (max1[j] < min2[j] || max2[j] < min1[j]) + if (max1[j] < min2[j] || max2[j] < min1[j]) { return false; + } } return true; } -// Member functions - Ordered Sets --------------------------------------------- - -member_imp(OrderedSet, OrderedSet::MDIOrdCollection, pieces); -OrderedSet::~OrderedSet() {} -OrderedSet::OrderedSet() : pieces_() {} -OrderedSet::OrderedSet(MD_NAT x) : pieces_() { - pieces_.push_back(SetPiece(x)); -} -OrderedSet::OrderedSet(Interval i) : pieces_() { - if (!i.isEmpty()) - pieces_.push_back(SetPiece(i)); -} -OrderedSet::OrderedSet(SetPiece mdi) : pieces_() { - if (!mdi.isEmpty()) - pieces_.push_back(mdi); -} -OrderedSet::OrderedSet(OrderedSet::MDIOrdCollection pieces) - : pieces_(std::move(pieces)) {} - -SetStratPtr OrderedSet::clone() const -{ - return std::make_unique(*this); -} +//////////////////////////////////////////////////////////////////////////////// +// Ordered Set Implementation -------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// -member_imp(OrderedSet::Iterator, OrderedSet::MDIOrdCollection::const_iterator - , it); +// Constructors/Destructors ---------------------------------------------------- -OrderedSet::Iterator::Iterator(OrderedSet::MDIOrdCollection::const_iterator it) - : it_(it) {} +OrderedSet::OrderedSet() : _pieces() {} -void OrderedSet::Iterator::operator++() +OrderedSet::OrderedSet(const MD_NAT& x) : _pieces() { - ++it_; - return; + _pieces.push_back(MultiDimInter{x}); } -bool OrderedSet::Iterator::operator!=(const SetStrategy::Iterator& other) - const +OrderedSet::OrderedSet(const Interval& i) : _pieces() { - return it_ != static_cast(&other)->it_; + if (!i.isEmpty()) { + _pieces.push_back(MultiDimInter{i}); + } } -bool OrderedSet::Iterator::operator==(const SetStrategy::Iterator& other) const +OrderedSet::OrderedSet(const MultiDimInter& mdi) : _pieces() { - return it_ == static_cast(&other)->it_; + if (!mdi.isEmpty()) { + _pieces.push_back(mdi); + } } -bool OrderedSet::Iterator::operator<(const SetStrategy::Iterator& other) const -{ - return it_ < static_cast(&other)->it_; -} +OrderedSet::OrderedSet(const OrderedSet::OrdMDICollection& pieces) + : _pieces(pieces) {} -const SetPiece& OrderedSet::Iterator::operator*() const { return *it_; } +OrderedSet::OrderedSet(OrderedSet::OrdMDICollection&& pieces) + : _pieces(std::move(pieces)) {} -std::shared_ptr OrderedSet::begin() const +OrderedSet::OrderedSet(const FixedPointsInfo& info) : _pieces() { - return std::make_shared(pieces_.begin()); + if (info) { + std::vector solutions = info.value(); + Interval universe_one_dim{0, 1, Inf}; + MultiDimInter result_mdi; + for (const Solution& jth_solution : solutions) { + if (jth_solution.kind() == SolutionKind::kFixed) { + result_mdi.pushBack(jth_solution.value().value()); + } else if (jth_solution.kind() == SolutionKind::kFree) { + result_mdi.pushBack(universe_one_dim); + } + } + pushBack(result_mdi); + } } -std::shared_ptr OrderedSet::end() const -{ - return std::make_shared(pieces_.end()); -} +// Getters --------------------------------------------------------------------- -std::size_t OrderedSet::size() const { return pieces_.size(); } +OrderedSet::ConstIt OrderedSet::begin() const { return _pieces.begin(); } -void OrderedSet::emplace(const SetPiece& mdi) -{ - if (mdi.isEmpty()) - return; +OrderedSet::ConstIt OrderedSet::end() const { return _pieces.end(); } - if (pieces_.empty() || pieces_.back() < mdi) { - pieces_.emplace_back(mdi); +// Setters --------------------------------------------------------------------- + +void OrderedSet::pushBack(const MultiDimInter& mdi) +{ + if (mdi.isEmpty()) { return; } - if (mdi < pieces_.front()) { - pieces_.emplace(pieces_.begin(), mdi); + if (_pieces.empty() || _pieces.back() < mdi) { + _pieces.push_back(mdi); return; } - auto it = pieces_.begin(); - for (; it != pieces_.end(); ++it) { - if (mdi < *it) + auto it = _pieces.rbegin(); + for (; it != _pieces.rend(); ++it) { + if (*it < mdi) { break; + } } - pieces_.emplace(it, mdi); - - return; + _pieces.insert(it.base(), mdi); } -void OrderedSet::emplaceBack(const SetPiece& mdi) -{ - if (mdi.isEmpty()) - return; - - if (pieces_.empty() || pieces_.back() < mdi) { - pieces_.emplace_back(mdi); - return; - } - - if (mdi < pieces_.front()) { - pieces_.emplace(pieces_.begin(), mdi); - return; - } - - auto it = pieces_.rbegin(); - for (; it != pieces_.rend(); ++it) { - if (*it < mdi) +NAT OrderedSet::advanceHint(NAT hint, const MultiDimInter& mdi) +{ + auto it = _pieces.begin(); + auto end = _pieces.end(); + std::advance(it, hint); + for (; it != end; ++it) { + if (mdi < *it) { break; + } + ++hint; } - pieces_.emplace(it.base(), mdi); - - return; + + return hint; } -void OrderedSet::emplaceHint(NAT hint, const SetPiece& mdi) +void OrderedSet::insertHint(const NAT hint, const MultiDimInter& mdi) { - if (mdi.isEmpty()) - return; - - if (pieces_.empty() || pieces_.back() < mdi) { - pieces_.emplace_back(mdi); + if (mdi.isEmpty()) { return; } - if (mdi < pieces_.front()) { - pieces_.emplace(pieces_.begin(), mdi); + if (_pieces.empty() || _pieces.back() < mdi) { + _pieces.emplace_back(mdi); return; } - auto it = pieces_.begin(); - auto end = pieces_.end(); + auto it = _pieces.begin(); + auto end = _pieces.end(); std::advance(it, hint); for (; it != end; ++it) { - if (mdi < *it) + if (mdi < *it) { break; + } } - pieces_.emplace(it, mdi); - - return; + _pieces.emplace(it, mdi); } -NAT OrderedSet::advanceHint(NAT hint, const SetPiece& mdi) -{ - auto it = pieces_.begin(); - auto end = pieces_.end(); - std::advance(it, hint); - for (; it != end; ++it) { - if (mdi < *it) - break; - ++hint; +// Operators ------------------------------------------------------------------- + +bool OrderedSet::operator==(const OrderedSet& other) const +{ + if (isEmpty() && other.isEmpty()) { + return true; } - - return hint; -} -bool OrderedSet::operator==(const SetStrategy& other) const -{ - OrdSetCRef othr = static_cast(other); - - if (pieces_ == othr.pieces_) { + if (isEmpty() != other.isEmpty()) { + return false; + } + + if (_pieces == other._pieces) { return true; } - return (this->difference(othr))->isEmpty() - && (othr.difference(*this))->isEmpty(); + return difference(other).isEmpty() && other.difference(*this).isEmpty(); } -bool OrderedSet::operator!=(const SetStrategy& other) const +bool OrderedSet::operator!=(const OrderedSet& other) const { return !(*this == other); } std::ostream& OrderedSet::print(std::ostream& out) const { - std::size_t sz = size(); + std::size_t sz = _pieces.size(); out << "{"; if (sz > 0) { unsigned int j = 0; - for (const SetPiece& mdi : pieces_) { + for (const MultiDimInter& mdi : _pieces) { if (j < sz - 1) { - out << mdi << ", "; + out << mdi << ", "; } else { out << mdi; } @@ -254,70 +222,42 @@ unsigned int OrderedSet::cardinal() const { unsigned int result = 0; - for (const SetPiece& mdi : pieces_) { + for (const MultiDimInter& mdi : _pieces) { result += mdi.cardinal(); } return result; } -bool OrderedSet::isEmpty() const { return pieces_.empty(); } +bool OrderedSet::isEmpty() const { return _pieces.empty(); } MD_NAT OrderedSet::minElem() const { - return pieces_.begin()->minElem(); + return _pieces.begin()->minElem(); } MD_NAT OrderedSet::maxElem() const -{ - MD_NAT res = pieces_.begin()->maxElem(); - for (const SetPiece& mdi : pieces_) { - MD_NAT ith = mdi.maxElem(); - if (res < ith) { - res = ith; - } +{ + MD_NAT result = _pieces.begin()->maxElem(); + + for (const MultiDimInter& mdi : _pieces) { + result = std::max(result, mdi.maxElem()); } - return res; + return result; } -SetStratPtr OrderedSet::intersection(const SetStrategy& other) const -{ - // Special cases - if (isEmpty() || other.isEmpty()) { - return std::make_unique(); - } - - const MD_NAT min_elem = minElem(); - const MD_NAT max_elem = maxElem(); - const MD_NAT other_min = other.minElem(); - const MD_NAT other_max = other.maxElem(); - if (max_elem < other_min || other_max < min_elem) { - return std::make_unique(); - } - +OrderedSet OrderedSet::intersectionEpilogue(const OrderedSet& lhs + , const OrderedSet& rhs) const +{ OrderedSet result; - if (max_elem == other_min) { - result.emplaceBack(SetPiece(max_elem)); - return std::make_unique(result); - } - - if (min_elem == other_max) { - result.emplaceBack(SetPiece(min_elem)); - return std::make_unique(result); - } - const OrdSetCRef othr = static_cast(other); - if (pieces_ == othr.pieces_) { - return std::make_unique(pieces_); - } - // General case - MDIOrdCollection short_set = pieces_; - MDIOrdCollection long_set = othr.pieces_; - if (othr.pieces_.size() < pieces_.size()) { - short_set = othr.pieces_; - long_set = pieces_; + OrderedSet::OrdMDICollection short_set = lhs._pieces; + OrderedSet::OrdMDICollection long_set = rhs._pieces; + if (rhs._pieces.size() < lhs._pieces.size()) { + short_set = rhs._pieces; + long_set = lhs._pieces; } // Indexes list corresponding to remaining pieces in short_set @@ -327,18 +267,18 @@ SetStratPtr OrderedSet::intersection(const SetStrategy& other) const indexes.push_front(i); } - NAT global_pos = 0; + NAT global_position = 0; auto short_begin = short_set.begin(); - for (const SetPiece& long_elem : long_set) { + for (const MultiDimInter& long_elem : long_set) { const MD_NAT long_min = long_elem.minElem(); const MD_NAT long_max = long_elem.maxElem(); auto prev_index = indexes.before_begin(); auto curr_index = indexes.begin(); - global_pos = result.advanceHint(global_pos, long_elem); + global_position = result.advanceHint(global_position, long_elem); while (curr_index != indexes.end()) { const size_t idx = *curr_index; - const SetPiece short_elem = *(short_begin + idx); + const MultiDimInter short_elem = *(short_begin + idx); const auto short_min = short_elem.minElem(); const auto short_max = short_elem.maxElem(); @@ -349,391 +289,369 @@ SetStratPtr OrderedSet::intersection(const SetStrategy& other) const continue; } - // Here short_elem is "after" long_elm, so no comparison is needed, and + // Here short_elem is "after" long_elem, so no comparison is needed, and // the loop of long_set continues to check if this short_elem interacts // with the following elements of long_set. - if (long_max < short_min) + if (long_max < short_min) { break; + } - if (doInt(short_elem, long_elem)) { - const SetPiece inter = long_elem.intersection(short_elem); - result.emplaceHint(global_pos, inter); + if (overlap(short_elem, long_elem)) { + const MultiDimInter inter = long_elem.intersection(short_elem); + result.insertHint(global_position, inter); } ++prev_index; ++curr_index; } - if (indexes.empty()) - break; + if (indexes.empty()) { + break; + } } - return std::make_unique(std::move(result)); + return result; } -SetStratPtr OrderedSet::cup(const SetStrategy& other) const & -{ - // Special cases - OrdSetCRef othr = static_cast(other); - if (isEmpty()) { - return std::make_unique(othr.pieces_); +OrderedSet OrderedSet::intersection(const OrderedSet& other) const +{ + if (isEmpty() || other.isEmpty()) { + return OrderedSet{}; } - if (other.isEmpty() || pieces_ == othr.pieces_) { - return std::make_unique(pieces_); + if (_pieces == other._pieces) { + return OrderedSet{_pieces}; } - MDIOrdCollection result; - if (maxElem() < othr.minElem()) { - result.insert(result.end(), pieces_.begin(), pieces_.end()); - result.insert(result.end(), othr.pieces_.begin(), othr.pieces_.end()); - return std::make_unique(std::move(result)); - } + return intersectionEpilogue(*this, other); +} - if (othr.maxElem() < minElem()) { - result.insert(result.end(), othr.pieces_.begin(), othr.pieces_.end()); - result.insert(result.end(), pieces_.begin(), pieces_.end()); - return std::make_unique(std::move(result)); - } +OrderedSet OrderedSet::cup(const OrderedSet& other) const & +{ + return OrderedSet{*this}.cup(other); +} - // General case - SetStratPtr diff = difference(other); - return othr.disjointCup(*diff); +OrderedSet OrderedSet::cup(const OrderedSet& other) && +{ + return std::move(*this).cup(OrderedSet{other}); } -SetStratPtr OrderedSet::cup(SetStrategy&& other) && -{ - // Special cases - OrdSetRef othr = static_cast(other); - if (other.isEmpty() || pieces_ == othr.pieces_) { - return std::make_unique(std::move(pieces_)); - } +OrderedSet OrderedSet::cup(OrderedSet&& other) const & +{ + return OrderedSet{*this}.cup(std::move(other)); +} +OrderedSet OrderedSet::cup(OrderedSet&& other) && +{ if (isEmpty()) { - return std::make_unique(std::move(othr.pieces_)); + return std::move(other); } - MDIOrdCollection result; - if (maxElem() < othr.minElem()) { - result = std::move(pieces_); - result.insert(result.end(), othr.pieces_.begin(), othr.pieces_.end()); - return std::make_unique(std::move(result)); + if (other.isEmpty() || _pieces == other._pieces) { + return std::move(*this); } - if (othr.maxElem() < minElem()) { - result = std::move(othr.pieces_); - result.insert(result.end(), pieces_.begin(), pieces_.end()); - return std::make_unique(std::move(result)); + if (maxElem() < other.minElem()) { + OrdMDICollection result = std::move(_pieces); + result.insert(result.end(), std::make_move_iterator(other._pieces.begin()) + , std::make_move_iterator(other._pieces.end())); + return OrderedSet{std::move(result)}; + } + + if (other.maxElem() < minElem()) { + OrdMDICollection result = std::move(other._pieces); + result.insert(result.end(), std::make_move_iterator(_pieces.begin()) + , std::make_move_iterator(_pieces.end())); + return OrderedSet{std::move(result)}; } // General case - SetStratPtr diff = difference(other); - return othr.disjointCup(*diff); + return std::move(other).disjointCup(difference(other)); } -SetStratPtr OrderedSet::complementAtom() const +OrderedSet OrderedSet::complementAtom() const { - MDIOrdCollection res; - - const SetPiece& mdi = *pieces_.begin(); - SetPiece dense_mdi; - - for (const Interval& i : mdi) - dense_mdi.emplaceBack(Interval(i.begin(), 1, i.end())); - - SetPiece during_mdi = dense_mdi; + OrdMDICollection result; - const Interval univ_one_dim(0, 1, Inf); - SetPiece univ(mdi.arity(), univ_one_dim); + MultiDimInter mdi = *_pieces.begin(); + MultiDimInter dense_mdi; + for (const Interval& i : mdi) { + dense_mdi.emplaceBack(i.begin(), 1, i.end()); + } + MultiDimInter during_mdi = dense_mdi; - unsigned int dim = 0; - int global_pos = 0; + Interval universe_one_dim{0, 1, Inf}; + MultiDimInter univ{mdi.arity(), universe_one_dim}; + std::size_t dim = 0; + std::size_t global_position = 0; for (const Interval& i : mdi) { - int local_pos = global_pos; - + std::size_t local_pos = global_position; + // Before interval if (i.begin() != 0) { - Interval i_res(0, 1, i.begin() - 1); + Interval i_res{0, 1, i.begin() - 1}; if (!i_res.isEmpty()) { univ[dim] = i_res; - res.insert(res.begin() + local_pos, univ); + result.insert(result.begin() + local_pos, univ); ++local_pos; - ++global_pos; - univ[dim] = univ_one_dim; + ++global_position; + univ[dim] = universe_one_dim; } } + // "During" interval if (i.begin() < Inf && i.step() > 1) { for (unsigned int j = 0; j < i.step() - 1; ++j) { - Interval i_res(i.begin() + j + 1, i.step(), i.end()); + Interval i_res{i.begin() + j + 1, i.step(), i.end()}; if (!i_res.isEmpty()) { during_mdi[dim] = i_res; - res.insert(res.begin() + local_pos, during_mdi); + result.insert(result.begin() + local_pos, during_mdi); ++local_pos; } } } - + + // After interval if (i.end() < Inf) { - Interval i_res(i.end() + 1, 1, Inf); + Interval i_res{i.end() + 1, 1, Inf}; if (!i_res.isEmpty()) { univ[dim] = i_res; - res.insert(res.begin() + local_pos, univ); + result.insert(result.begin() + local_pos, univ); ++local_pos; - univ[dim] = univ_one_dim; + univ[dim] = universe_one_dim; } } - univ[dim] = dense_mdi[dim]; during_mdi[dim] = i; ++dim; } - - return std::make_unique(std::move(res)); + + return OrderedSet{std::move(result)}; } -void OrderedSet::intersectionComp(const SetStrategy& other - , const SetPiece& mdi, SetStrategy& rem) +void OrderedSet::intersectionComplement(const OrderedSet& + local_complement, const MultiDimInter& mdi) { // Special cases - if (isEmpty() || other.isEmpty()) - return; - - OrderedSet result; - const MD_NAT min_elem = minElem(); - const MD_NAT max_elem = maxElem(); - const MD_NAT other_min = other.minElem(); - const MD_NAT other_max = other.maxElem(); - if (max_elem < other_min || other_max < min_elem) { - pieces_ = std::move(result.pieces_); - return; - } - - if (max_elem == other_min) { - result.emplaceBack(SetPiece(max_elem)); - pieces_ = std::move(result.pieces_); - return; - } - - if (min_elem == other_max) { - result.emplaceBack(SetPiece(min_elem)); - pieces_ = std::move(result.pieces_); - return; - } - - OrdSetCRef othr = static_cast(other); - if (pieces_ == othr.pieces_) { - pieces_ = std::move(result.pieces_); + if (isEmpty()) { return; } // General case - size_t i = 0; - for (const SetPiece& elem : pieces_) { - if (!(elem.maxElem() < mdi.minElem())) + + // Values in the partial result "before" the current MDI all belong to the + // complement of the processed MDIs, the current MDI and also to the remaining + // MDIs, so there's no need to keep calculating with them. + OrderedSet result; + auto it = _pieces.begin(); + for (const MultiDimInter& elem : _pieces) { + if (!(elem.maxElem() < mdi.minElem())) { break; - rem.emplaceBack(elem); - ++i; + } + ++it; } - - NAT global_pos = 0; - for (auto it = pieces_.begin() + i; it != pieces_.end(); ++it) { - const SetPiece& elem = *it; - - global_pos = result.advanceHint(global_pos, elem); - if (doInt(elem, mdi)) { - for (const SetPiece& othr_elem : othr.pieces_) { - if (doInt(othr_elem, elem)) { - auto inter = elem.intersection(othr_elem); - result.emplaceHint(global_pos, inter); + result._pieces.insert(result.end(), std::make_move_iterator(_pieces.begin()) + , std::make_move_iterator(it)); + + NAT global_position = 0; + for (; it != _pieces.end(); ++it) { + const MultiDimInter& elem = *it; + global_position = result.advanceHint(global_position, elem); + // Discard elements in the complement of processed MDIs that belong to the + // current MDI. + if (overlap(elem, mdi)) { + for (const MultiDimInter& local_elem : local_complement._pieces) { + if (overlap(elem, local_elem)) { + result.insertHint(global_position, elem.intersection(local_elem)); } } } else { - result.emplaceHint(global_pos, elem); + // Values in the partial result "after" the current MDI all belong to the + // complement of the processed MDIs and the current MDI, but might not be + // in the complement of the remaining MDIs, so they are kept for + // subsequent calculations. + result.insertHint(global_position, elem); } } - - pieces_ = std::move(result.pieces_); - return; + _pieces = std::move(result._pieces); } -SetStratPtr OrderedSet::complement() const -{ - if (isEmpty()) - return std::make_unique(); - - - auto first_it = pieces_.begin(); - SetPiece first = *first_it; - OrderedSet result = static_cast( - *(OrderedSet(first).complementAtom())); - - ++first_it; - MDIOrdCollection second(first_it, pieces_.end()); - OrderedSet remnant; - for (const SetPiece& mdi : second) { - SetStratPtr c = OrderedSet(mdi).complementAtom(); - result.intersectionComp(*c, mdi, remnant); +OrderedSet OrderedSet::complement() const +{ + if (isEmpty()) { + return OrderedSet{}; } - - return remnant.disjointCup(result); -} - -SetStratPtr OrderedSet::difference(const SetStrategy& other) const -{ - // Special cases - if (isEmpty() || other.isEmpty()) - return std::make_unique(pieces_); - - if (maxElem() < other.minElem() || other.maxElem() < minElem()) - return std::make_unique(pieces_); - - // General case - return intersection(*other.complement()); -} - -// Extra operations ------------------------------------------------------------ -std::size_t OrderedSet::arity() const -{ - if (isEmpty()) - return 0; + OrderedSet result = OrderedSet{_pieces.front()}.complementAtom(); + std::size_t j = 0; + for (const MultiDimInter& mdi : _pieces) { + if (j > 0) { + OrderedSet c = OrderedSet{mdi}.complementAtom(); + result.intersectionComplement(c, mdi); + } + ++j; + } - return pieces_.begin()->arity(); + return result; } -SetStratPtr OrderedSet::disjointCup(const SetStrategy& other) const & +OrderedSet OrderedSet::difference(const OrderedSet& other) const { - OrdSetCRef othr = static_cast(other); - // Special cases - if (isEmpty()) { - return std::make_unique(othr.pieces_); + if (isEmpty() || other.isEmpty()) { + return OrderedSet{_pieces}; } - if (othr.isEmpty() || pieces_ == othr.pieces_) { - return std::make_unique(pieces_); + if (_pieces == other._pieces) { + return OrderedSet{}; } - MDIOrdCollection result; - if (pieces_.back() < othr.pieces_.front()) { - result.insert(result.end(), pieces_.begin(), pieces_.end()); - result.insert(result.end(), othr.pieces_.begin(), othr.pieces_.end()); - return std::make_unique(std::move(result)); - } + // General case + return intersection(other.complement()); +} + +OrderedSet OrderedSet::cartesianProduct(const OrderedSet& other) const +{ + OrderedSet result; - if (othr.pieces_.back() < pieces_.front()) { - result.insert(result.end(), othr.pieces_.begin(), othr.pieces_.end()); - result.insert(result.end(), pieces_.begin(), pieces_.end()); - return std::make_unique(std::move(result)); + if (isEmpty() || other.isEmpty()) { + return result; } - // General case - auto it1 = pieces_.begin(); - auto end1 = pieces_.end(); - auto it2 = othr.pieces_.begin(); - auto end2 = othr.pieces_.end(); - while (it1 != end1 && it2 != end2) { - if (*it1 < *it2) { - result.emplace_back(*it1); - ++it1; - } else { - result.emplace_back(*it2); - ++it2; + for (const MultiDimInter& mdi : _pieces) { + MultiDimInter mdi_copy = mdi; + for (const MultiDimInter& other_mdi : other._pieces) { + result.pushBack(mdi.cartesianProduct(other_mdi)); } } - result.insert(result.end(), it1, end1); - result.insert(result.end(), it2, end2); - - return std::make_unique(std::move(result)); + + return result; } -SetStratPtr OrderedSet::disjointCup(SetStrategy&& other) && -{ - // Special cases - OrdSetRef othr = static_cast(other); - if (other.isEmpty() || pieces_ == othr.pieces_) { - return std::make_unique(std::move(pieces_)); - } +// Extra operations ------------------------------------------------------------ - if (isEmpty()) { - return std::make_unique(std::move(othr.pieces_)); +std::size_t OrderedSet::arity() const +{ + if (isEmpty()) { + return 0; } - MDIOrdCollection result; - if (pieces_.back() < othr.pieces_.front()) { - result = std::move(pieces_); - result.insert(result.end(), othr.pieces_.begin(), othr.pieces_.end()); - return std::make_unique(std::move(result)); - } + return _pieces.begin()->arity(); +} - if (othr.pieces_.back() < pieces_.front()) { - result = std::move(othr.pieces_); - result.insert(result.end(), pieces_.begin(), pieces_.end()); - return std::make_unique(std::move(result)); - } +OrderedSet OrderedSet::disjointCup(const OrderedSet& other) const & +{ + return OrderedSet{*this}.disjointCup(other); +} - // General case - auto it1 = pieces_.begin(); - auto end1 = pieces_.end(); - auto it2 = othr.pieces_.begin(); - auto end2 = othr.pieces_.end(); - while (it1 != end1 && it2 != end2) { - if (*it1 < *it2) { - result.emplace_back(*it1); - ++it1; - } else { - result.emplace_back(*it2); - ++it2; +OrderedSet OrderedSet::disjointCup(const OrderedSet& other) && +{ + return std::move(*this).disjointCup(OrderedSet{other}); +} + +OrderedSet OrderedSet::disjointCup(OrderedSet&& other) const & +{ + return OrderedSet{*this}.disjointCup(std::move(other)); +} + +OrderedSet OrderedSet::disjointCup(OrderedSet&& other) && +{ + // Special cases + if (isEmpty()) { + return std::move(other); + } + + if (other.isEmpty()) { + return std::move(*this); + } + + OrdMDICollection result; + if (_pieces.back() < other._pieces.front()) { + result.insert(result.end(), std::make_move_iterator(_pieces.begin()) + , std::make_move_iterator(_pieces.end())); + result.insert(result.end(), std::make_move_iterator(other._pieces.begin()) + , std::make_move_iterator(other._pieces.end())); + } else if (other._pieces.back() < _pieces.front()) { + result.insert(result.end(), std::make_move_iterator(other._pieces.begin()) + , std::make_move_iterator(other._pieces.end())); + result.insert(result.end(), std::make_move_iterator(_pieces.begin()) + , std::make_move_iterator(_pieces.end())); + } else { + // General case + auto it1 = _pieces.begin(); + auto end1 = _pieces.end(); + auto it2 = other._pieces.begin(); + auto end2 = other._pieces.end(); + while (it1 != end1 && it2 != end2) { + if (*it1 < *it2) { + result.push_back(*it1); + ++it1; + } else { + result.push_back(*it2); + ++it2; + } } + result.insert(result.end(), std::make_move_iterator(it1) + , std::make_move_iterator(end1)); + result.insert(result.end(), std::make_move_iterator(it2) + , std::make_move_iterator(end2)); } - result.insert(result.end(), it1, end1); - result.insert(result.end(), it2, end2); - - return std::make_unique(std::move(result)); + + return OrderedSet{std::move(result)}; } -SetStratPtr OrderedSet::filterSet(bool (*f)(const SetPiece& mdi)) const +OrderedSet OrderedSet::offset(const MD_NAT& off) const { - MDIOrdCollection res; + OrderedSet result; - for (const SetPiece& mdi : pieces_) { - if (f(mdi)) { - res.push_back(mdi); - } + for (const MultiDimInter& mdi : _pieces) { + result.pushBack(mdi.offset(off)); } - return std::make_unique(std::move(res)); + return result; } -SetStratPtr OrderedSet::offset(const MD_NAT& off) const +Perimeter OrderedSet::perimeter() const { - MDIOrdCollection res; + MD_NAT min; + MD_NAT max; - for (const SetPiece& mdi : pieces_) { - res.emplace_back(mdi.offset(off)); + if (!isEmpty()) { + std::size_t arity = this->arity(); + min = MD_NAT{arity, Inf}; + max = MD_NAT{arity, 0}; + for (const MultiDimInter& mdi : _pieces) { + MD_NAT candidate_min = mdi.minElem(); + MD_NAT candidate_max = mdi.maxElem(); + for (size_t i = 0; i < arity; ++i) { + min[i] = std::min(min[i], candidate_min[i]); + max[i] = std::max(max[i], candidate_max[i]); + } + } } - return std::make_unique(std::move(res)); + return Perimeter{min, max}; } -SetStratPtr OrderedSet::compact() const +void OrderedSet::compact() { - MDIOrdCollection result; + using MDISet = std::set; + + OrdMDICollection result; if (!isEmpty()) { - std::set prev(pieces_.begin(), pieces_.end()); - std::set actual = prev; + MDISet set_result{std::make_move_iterator(_pieces.begin()) + , std::make_move_iterator(_pieces.end())}; + MDISet to_erase; do { - prev = actual; - actual = std::set(); + MDISet new_set_result; + to_erase.clear(); - std::set::iterator ith = prev.begin(); - std::set::iterator last = prev.end(); - std::set to_erase; + MDISet::iterator ith = set_result.begin(); + MDISet::iterator last = set_result.end(); for (; ith != last; ++ith) { - SetPiece ith_compact = *ith; - std::set::iterator next = ith; + MultiDimInter ith_compact = *ith; + MDISet::iterator next = ith; ++next; for (; next != last; ++next) { MaybeMDI new_compact = ith_compact.compact(*next); @@ -743,19 +661,39 @@ SetStratPtr OrderedSet::compact() const } } - if (to_erase.find(ith_compact) == to_erase.end()) - actual.insert(ith_compact); + if (to_erase.find(ith_compact) == to_erase.end()) { + new_set_result.insert(ith_compact); + } } - } while (actual != prev); - for (const SetPiece& mdi : actual) { - result.emplace_back(mdi); + std::swap(set_result, new_set_result); + } while (!to_erase.empty()); + + for (const MultiDimInter& m : set_result) { + result.push_back(m); } } - return std::make_unique(std::move(result)); + _pieces = std::move(result); } +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(OrderedSet s, rapidjson::Document::AllocatorType& alloc) +{ + rapidjson::Value mdi_array{rapidjson::kArrayType}; + for (const MultiDimInter& mdi : s) { + rapidjson::Value jth = detail::toJSON(mdi, alloc); + mdi_array.PushBack(jth, alloc); + } + rapidjson::Value result{rapidjson::kObjectType}; + result.AddMember("pieces", mdi_array, alloc); + + return result; +} + +} // namespace detail + } // namespace LIB } // namespace SBG diff --git a/sbg/ord_set.hpp b/sbg/ord_set.hpp index 014f544b..cd0d2a0f 100644 --- a/sbg/ord_set.hpp +++ b/sbg/ord_set.hpp @@ -21,101 +21,114 @@ ******************************************************************************/ -#ifndef SBG_ORD_SET_HPP -#define SBG_ORD_SET_HPP +#ifndef SBGRAPH_SBG_ORD_SET_HPP_ +#define SBGRAPH_SBG_ORD_SET_HPP_ +#include "sbg/expression.hpp" +#include "sbg/fixed_points.hpp" +#include "sbg/interval.hpp" #include "sbg/multidim_inter.hpp" -#include "sbg/set.hpp" +#include "sbg/natural.hpp" +#include "sbg/perimeter.hpp" + +#include "rapidjson/document.h" + +#include +#include +#include namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// -// Ordered Set Implementation (concrete strategy) ------------------------------ +// Ordered Set Implementation -------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -class OrderedSet : public SetStrategy { - using MDIOrdCollection = std::vector; - - member_class(MDIOrdCollection, pieces); +class OrderedSet { +public: + using OrdMDICollection = std::vector; + using ConstIt = OrdMDICollection::const_iterator; - ~OrderedSet(); OrderedSet(); - OrderedSet(MD_NAT x); - OrderedSet(Interval i); - OrderedSet(SetPiece mdi); - OrderedSet(MDIOrdCollection pieces); + OrderedSet(const MD_NAT& x); + OrderedSet(const detail::Interval& i); + OrderedSet(const detail::MultiDimInter& mdi); + OrderedSet(const OrdMDICollection& pieces); + OrderedSet(OrdMDICollection&& pieces); + OrderedSet(const FixedPointsInfo& info); - SetStratPtr clone() const override; + ConstIt begin() const; + ConstIt end() const; - class Iterator : public SetStrategy::Iterator { - member_class(MDIOrdCollection::const_iterator, it); + void pushBack(const MultiDimInter& mdi); - Iterator(MDIOrdCollection::const_iterator it); - void operator++() override; - bool operator!=(const SetStrategy::Iterator& other) const override; - bool operator==(const SetStrategy::Iterator& other) const override; - bool operator<(const SetStrategy::Iterator& other) const override; - const SetPiece& operator*() const override; - }; - - std::shared_ptr begin() const override; - std::shared_ptr end() const override; - - std::size_t size() const override; - void emplace(const SetPiece& mdi) override; - void emplaceBack(const SetPiece& mdi) override; - - bool operator==(const SetStrategy& other) const override; - bool operator!=(const SetStrategy& other) const override; - std::ostream& print(std::ostream& out) const override; + bool operator==(const OrderedSet& other) const; + bool operator!=(const OrderedSet& other) const; + std::ostream& print(std::ostream& out) const; // Traditional set operations ------------------------------------------------ - unsigned int cardinal() const override; - bool isEmpty() const override; - MD_NAT minElem() const override; - MD_NAT maxElem() const override; - SetStratPtr intersection(const SetStrategy& other) const override; - SetStratPtr cup(const SetStrategy& other) const & override; - SetStratPtr cup(SetStrategy&& other) && override; - SetStratPtr complement() const; - SetStratPtr difference(const SetStrategy& other) const override; + unsigned int cardinal() const; + bool isEmpty() const; + MD_NAT minElem() const; + MD_NAT maxElem() const; + OrderedSet intersection(const OrderedSet& other) const; + OrderedSet cup(const OrderedSet& other) const &; + OrderedSet cup(OrderedSet&& other) const &; + OrderedSet cup(const OrderedSet& other) &&; + OrderedSet cup(OrderedSet&& other) &&; + OrderedSet complement() const; + OrderedSet difference(const OrderedSet& other) const; + OrderedSet cartesianProduct(const OrderedSet& other) const; // Extra operations ---------------------------------------------------------- - std::size_t arity() const override; - SetStratPtr disjointCup(const SetStrategy& other) const & override; - SetStratPtr disjointCup(SetStrategy&& other) && override; - SetStratPtr filterSet(bool (*f)(const SetPiece& mdi)) const override; - SetStratPtr offset(const MD_NAT& off) const override; - SetStratPtr compact() const override; + std::size_t arity() const; + OrderedSet disjointCup(const OrderedSet& other) const &; + OrderedSet disjointCup(const OrderedSet& other) &&; + OrderedSet disjointCup(OrderedSet&& other) const &; + OrderedSet disjointCup(OrderedSet&& other) &&; + OrderedSet offset(const MD_NAT& off) const; + Perimeter perimeter() const; + void compact(); - private: - void emplaceHint(NAT hint, const SetPiece& mdi); +private: + NAT advanceHint(NAT hint, const MultiDimInter& mdi); + void insertHint(const NAT hint, const MultiDimInter& mdi); - NAT advanceHint(NAT hint, const SetPiece& mdi); + OrderedSet intersectionEpilogue(const OrderedSet& lhs, const OrderedSet& rhs) + const; - /** - * @brief Calculates the complement of an ordered set with a single piece. - */ - SetStratPtr complementAtom() const; - /** * @brief Computes the accumulated complement between an ordered set (this), * which represents the complement of an ordered set, and an ordered set * (other), which represents the complement of an atomic ordered set. */ - void intersectionComp(const SetStrategy& other, const SetPiece& mdi - , SetStrategy& rem); + void intersectionComplement(const OrderedSet& other + , const MultiDimInter& mdi); + + /** + * @brief Calculate the complement of an unordered set with a single piece. + */ + OrderedSet complementAtom() const; + + OrdMDICollection _pieces; + + friend class SetAccessKey; }; -typedef const OrderedSet& OrdSetCRef; -typedef OrderedSet& OrdSetRef; +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(OrderedSet s + , rapidjson::Document::AllocatorType& alloc); + +} // namespace detail } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_ORD_SET_HPP_ diff --git a/sbg/ord_unidim_dense_set.cpp b/sbg/ord_unidim_dense_set.cpp index 6d4ab9e8..c04e9122 100644 --- a/sbg/ord_unidim_dense_set.cpp +++ b/sbg/ord_unidim_dense_set.cpp @@ -18,163 +18,183 @@ ******************************************************************************/ #include "sbg/ord_unidim_dense_set.hpp" +#include "util/debug.hpp" + +#include namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// -// Ordered Unidimensional Dense Set Implementation ----------------------------- +// Auxiliary functions --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -member_imp(OrdUnidimDenseSet, OrdUnidimDenseSet::MDIOrdCollection, pieces); - -OrdUnidimDenseSet::~OrdUnidimDenseSet() {} -OrdUnidimDenseSet::OrdUnidimDenseSet() : pieces_() {} -OrdUnidimDenseSet::OrdUnidimDenseSet(MD_NAT x) : pieces_() { - pieces_.emplace_back(SetPiece(x)); -} -OrdUnidimDenseSet::OrdUnidimDenseSet(Interval i) : pieces_() { - if (!i.isEmpty()) - pieces_.emplace_back(SetPiece(i)); +Interval least(const Interval& lhs, const Interval& rhs) +{ + return lhs < rhs ? lhs : rhs; } -OrdUnidimDenseSet::OrdUnidimDenseSet(SetPiece mdi) : pieces_() { - if (!mdi.isEmpty()) - pieces_.emplace_back(mdi); + +bool overlap(const OrdUnidimDenseSet::OrdIntervalCollection& lhs, + const OrdUnidimDenseSet::OrdIntervalCollection& rhs) +{ + return lhs.back().end() >= rhs.front().begin() + || rhs.back().end() >= lhs.front().begin(); } -OrdUnidimDenseSet::OrdUnidimDenseSet(OrdUnidimDenseSet::MDIOrdCollection pieces) - : pieces_(std::move(pieces)) {} -SetStratPtr OrdUnidimDenseSet::clone() const +Interval intersection(const Interval& lhs, const Interval& rhs) { - return std::make_unique(pieces_); + return lhs.intersection(rhs); } -member_imp(OrdUnidimDenseSet::Iterator - , OrdUnidimDenseSet::MDIOrdCollection::const_iterator, it); +OrdUnidimDenseSet::OrdIntervalCollection + compact(const OrdUnidimDenseSet::OrdIntervalCollection& c) +{ + OrdUnidimDenseSet::OrdIntervalCollection result; -OrdUnidimDenseSet::Iterator::Iterator( - OrdUnidimDenseSet::MDIOrdCollection::const_iterator it) : it_(it) {} + if (c.empty()) { + return result; + } -void OrdUnidimDenseSet::Iterator::operator++() -{ - ++it_; - return; + auto next_it = c.begin(); + ++next_it; + Interval compacted = c.front(); + for (auto it = c.begin(); next_it != c.end(); ++it) { + MaybeInterval ith = compacted.compact(*next_it); + if (!ith) { + result.push_back(compacted); + compacted = *next_it; + } else { + compacted = ith.value(); + } + + ++next_it; + } + result.push_back(compacted); + + return result; } -bool OrdUnidimDenseSet::Iterator::operator!=(const SetStrategy::Iterator& other) - const +//////////////////////////////////////////////////////////////////////////////// +// Ordered Unidimensional Dense Set Implementation ----------------------------- +//////////////////////////////////////////////////////////////////////////////// + +// Constructors/Destructors ---------------------------------------------------- + +OrdUnidimDenseSet::OrdUnidimDenseSet() : _pieces() {} + +OrdUnidimDenseSet::OrdUnidimDenseSet(const NAT x) : _pieces() { - return it_ != static_cast(&other)->it_; + _pieces.emplace_back(x); } -bool OrdUnidimDenseSet::Iterator::operator==(const SetStrategy::Iterator& other) - const +OrdUnidimDenseSet::OrdUnidimDenseSet(const Interval& i) : _pieces() { - return it_ == static_cast(&other)->it_; + if (!i.isEmpty()) { + _pieces.push_back(i); + } } -bool OrdUnidimDenseSet::Iterator::operator<(const SetStrategy::Iterator& other) - const +OrdUnidimDenseSet::OrdUnidimDenseSet( + const OrdUnidimDenseSet::OrdIntervalCollection& pieces) + : _pieces(pieces) {} + +OrdUnidimDenseSet::OrdUnidimDenseSet( + OrdUnidimDenseSet::OrdIntervalCollection&& pieces) + : _pieces(std::move(pieces)) {} + +OrdUnidimDenseSet::OrdUnidimDenseSet(const FixedPointsInfo& info) { - return it_ < static_cast(&other)->it_; + if (info) { + std::vector solutions = info.value(); + for (const Solution& jth_solution : solutions) { + if (jth_solution.kind() == SolutionKind::kFixed) { + _pieces.emplace_back(jth_solution.value().value()); + } else { + _pieces.emplace_back(0, 1, Inf); + } + } + } } -const SetPiece& OrdUnidimDenseSet::Iterator::operator*() const { return *it_; } +// Getters --------------------------------------------------------------------- -std::shared_ptr OrdUnidimDenseSet::begin() const +OrdUnidimDenseSet::ConstIt OrdUnidimDenseSet::begin() const { - return std::make_shared(pieces_.begin()); + return _pieces.begin(); } -std::shared_ptr OrdUnidimDenseSet::end() const +OrdUnidimDenseSet::ConstIt OrdUnidimDenseSet::end() const { - return std::make_shared(pieces_.end()); + return _pieces.end(); } -std::size_t OrdUnidimDenseSet::size() const { return pieces_.size(); } +// Setters --------------------------------------------------------------------- -void OrdUnidimDenseSet::emplace(const SetPiece& mdi) +void OrdUnidimDenseSet::pushBack(const Interval& i) { - if (mdi.isEmpty()) + if (i.isEmpty()) { return; + } - if (pieces_.empty() || pieces_.back() < mdi) { - pieces_.emplace_back(mdi); + if (_pieces.empty() || _pieces.back() < i) { + _pieces.push_back(i); return; } - if (mdi < pieces_.front()) { - pieces_.emplace(pieces_.begin(), mdi); + if (i < _pieces.front()) { + _pieces.insert(_pieces.begin(), i); return; } - auto it = pieces_.begin(); - auto end = pieces_.end(); - for (; it != end; ++it) { - if (mdi < *it) + auto it = _pieces.rbegin(); + auto rend = _pieces.rend(); + for (; it != rend; ++it) { + if (*it < i) { break; + } } - pieces_.emplace(it, mdi); - - return; + _pieces.insert(it.base(), i); } -void OrdUnidimDenseSet::emplaceBack(const SetPiece& mdi) -{ - if (mdi.isEmpty()) { - return; - } +// Operators ------------------------------------------------------------------- - if (pieces_.empty() || pieces_.back() < mdi) { - pieces_.emplace_back(mdi); - return; +bool OrdUnidimDenseSet::operator==(const OrdUnidimDenseSet& other) const +{ + if (isEmpty() && other.isEmpty()) { + return true; } - if (mdi < pieces_.front()) { - pieces_.emplace(pieces_.begin(), mdi); - return; + if (isEmpty() != other.isEmpty()) { + return false; } - auto it = pieces_.rbegin(); - auto rend = pieces_.rend(); - for (; it != rend; ++it) { - if (*it < mdi) { - break; - } + if (_pieces == other._pieces) { + return true; } - pieces_.emplace(it.base(), mdi); - return; + return detail::compact(_pieces) == detail::compact(other._pieces); } -bool OrdUnidimDenseSet::operator==(const SetStrategy& other) const -{ - SetStratPtr this_comp = compact(); - OrdUnidimDenseSetCRef ths = static_cast(*this_comp); - SetStratPtr other_comp = other.compact(); - OrdUnidimDenseSetCRef othr = static_cast(*other_comp); - - return ths.pieces_ == othr.pieces_; -} - -bool OrdUnidimDenseSet::operator!=(const SetStrategy& other) const +bool OrdUnidimDenseSet::operator!=(const OrdUnidimDenseSet& other) const { return !(*this == other); } std::ostream& OrdUnidimDenseSet::print(std::ostream& out) const { - std::size_t sz = size(); + std::size_t sz = _pieces.size(); out << "{"; if (sz > 0) { unsigned int j = 0; - for (const SetPiece& mdi : pieces_) { + for (const Interval& i : _pieces) { if (j < sz - 1) { - out << mdi << ", "; + out << i << ", "; } else { - out << mdi; + out << i; } ++j; @@ -191,272 +211,219 @@ unsigned int OrdUnidimDenseSet::cardinal() const { unsigned int result = 0; - for (const SetPiece& mdi : pieces_) { - result += mdi.cardinal(); + for (const Interval& i : _pieces) { + result += i.cardinal(); } return result; } -bool OrdUnidimDenseSet::isEmpty() const { return pieces_.empty(); } +bool OrdUnidimDenseSet::isEmpty() const { return _pieces.empty(); } MD_NAT OrdUnidimDenseSet::minElem() const { - return pieces_.begin()->minElem(); + return MD_NAT(_pieces.front().begin()); } MD_NAT OrdUnidimDenseSet::maxElem() const { - auto it = pieces_.end(); - --it; - return it->maxElem(); + return MD_NAT(_pieces.back().end()); } -SetStratPtr OrdUnidimDenseSet::intersection(const SetStrategy& other) const +OrdUnidimDenseSet OrdUnidimDenseSet::intersection(const OrdUnidimDenseSet& + other) const { // Special cases to enhance performance if (isEmpty() || other.isEmpty()) { - return std::make_unique(); - } - - const MD_NAT min_elem = minElem(); - const MD_NAT max_elem = maxElem(); - const MD_NAT other_min = other.minElem(); - const MD_NAT other_max = other.maxElem(); - if (max_elem < other_min || other_max < min_elem) { - return std::make_unique(); - } - - OrdUnidimDenseSet result; - if (max_elem == other_min) { - result.emplaceBack(SetPiece(max_elem)); - return std::make_unique(result); + return OrdUnidimDenseSet{}; } - if (min_elem == other_max) { - result.emplaceBack(SetPiece(min_elem)); - return std::make_unique(result); + if (!overlap(_pieces, other._pieces)) { + return OrdUnidimDenseSet{}; } - const OrdUnidimDenseSetCRef othr = static_cast(other); - if (pieces_ == othr.pieces_) { - return std::make_unique(pieces_); + if (_pieces == other._pieces) { + return OrdUnidimDenseSet{_pieces}; } - // General case - MDIOrdCollection cap = boundedTraverse(&SetPiece::intersection, othr.pieces_); - - return std::make_unique(std::move(cap)); + return boundedTraverse(detail::intersection, other); } -SetStratPtr OrdUnidimDenseSet::cup(const SetStrategy& other) const & +OrdUnidimDenseSet OrdUnidimDenseSet::cup(const OrdUnidimDenseSet& other) const & { - // Special cases - OrdUnidimDenseSetCRef othr = static_cast(other); - if (isEmpty()) { - return std::make_unique(othr.pieces_); - } - - if (other.isEmpty() || pieces_ == othr.pieces_) { - return std::make_unique(pieces_); - } - - MDIOrdCollection result; - if (maxElem() < othr.minElem()) { - result.insert(result.end(), pieces_.begin(), pieces_.end()); - result.insert(result.end(), othr.pieces_.begin(), othr.pieces_.end()); - return std::make_unique(std::move(result)); - } - - if (othr.maxElem() < minElem()) { - result.insert(result.end(), othr.pieces_.begin(), othr.pieces_.end()); - result.insert(result.end(), pieces_.begin(), pieces_.end()); - return std::make_unique(std::move(result)); - } + return OrdUnidimDenseSet{*this}.cup(other); +} - // General case - SetStratPtr diff = difference(other); +OrdUnidimDenseSet OrdUnidimDenseSet::cup(const OrdUnidimDenseSet& other) && +{ + return std::move(*this).cup(OrdUnidimDenseSet{other}); +} - return othr.disjointCup(*diff); +OrdUnidimDenseSet OrdUnidimDenseSet::cup(OrdUnidimDenseSet&& other) const & +{ + return OrdUnidimDenseSet{*this}.cup(std::move(other)); } -SetStratPtr OrdUnidimDenseSet::cup(SetStrategy&& other) && +OrdUnidimDenseSet OrdUnidimDenseSet::cup(OrdUnidimDenseSet&& other) && { // Special cases - OrdUnidimDenseSetRef othr = static_cast(other); - if (other.isEmpty() || pieces_ == othr.pieces_) { - return std::make_unique(std::move(pieces_)); + if (other.isEmpty() || _pieces == other._pieces) { + return OrdUnidimDenseSet{std::move(_pieces)}; } if (isEmpty()) { - return std::make_unique(std::move(othr.pieces_)); + return OrdUnidimDenseSet{std::move(other._pieces)}; } - MDIOrdCollection result; - if (maxElem() < othr.minElem()) { - result = std::move(pieces_); - result.insert(result.end(), othr.pieces_.begin(), othr.pieces_.end()); - return std::make_unique(std::move(result)); - } - - if (othr.maxElem() < minElem()) { - result = std::move(othr.pieces_); - result.insert(result.end(), pieces_.begin(), pieces_.end()); - return std::make_unique(std::move(result)); + OrdIntervalCollection result; + if (!overlap(_pieces, other._pieces)) { + return std::move(*this).disjointCup(std::move(other)); } // General case - SetStratPtr diff = difference(other); - return othr.disjointCup(*diff); + OrdUnidimDenseSet exclusive_this = difference(other); + return std::move(other).disjointCup(std::move(exclusive_this)); } -SetStratPtr OrdUnidimDenseSet::complement() const +OrdUnidimDenseSet OrdUnidimDenseSet::complement() const { - OrdUnidimDenseSet res; + OrdUnidimDenseSet result; if (isEmpty()) { - res.emplaceBack(SetPiece(Interval(0, 1, Inf))); - return std::make_unique(res); + result._pieces.emplace_back(0, 1, Inf); + return result; } - auto first_it = pieces_.begin(); - Interval first(0, 1, first_it->operator[](0).begin() - 1); - if (!first.isEmpty()) - res.emplaceBack(SetPiece(first)); - NAT last = first_it->maxElem()[0]; + // Complement before minimum element of the set + result._pieces.emplace_back(0, 1, _pieces.front().minElem() - 1); - ++first_it; - MDIOrdCollection second(first_it, pieces_.end()); - for (const SetPiece& mdi : second) { - Interval ith(last + 1, 1, mdi[0].begin() - 1); - if (!ith.isEmpty()) - res.emplaceBack(SetPiece(ith)); - last = mdi.maxElem()[0]; + // Complement between pieces of the set + NAT last_interval_end = _pieces.front().maxElem(); + unsigned int j = 0; + for (const Interval& i : _pieces) { + if (j != 0) { + if (i.begin() - 1 >= last_interval_end + 1) { + result._pieces.emplace_back(last_interval_end + 1, 1, i.begin() - 1); + } + last_interval_end = i.maxElem(); + } + ++j; } - Interval end(last + 1, 1, Inf); - res.emplaceBack(SetPiece(end)); - return std::make_unique(std::move(res)); + // Complement after maximum element of the set + result._pieces.emplace_back(last_interval_end + 1, 1, Inf); + + return result; } -SetStratPtr OrdUnidimDenseSet::difference(const SetStrategy& other) const +OrdUnidimDenseSet OrdUnidimDenseSet::difference(const OrdUnidimDenseSet& other) + const { if (isEmpty() || other.isEmpty()) { - return std::make_unique(pieces_); + return OrdUnidimDenseSet{_pieces}; } - if (maxElem() < other.minElem() || other.maxElem() < minElem()) { - return std::make_unique(pieces_); + if (!overlap(_pieces, other._pieces)) { + return OrdUnidimDenseSet{_pieces}; } - return intersection(*other.complement()); -} + if (_pieces == other._pieces) { + return OrdUnidimDenseSet{}; + } -// Extra operations ------------------------------------------------------------ + return intersection(other.complement()); +} -std::size_t OrdUnidimDenseSet::arity() const +OrdUnidimDenseSet OrdUnidimDenseSet::cartesianProduct(const OrdUnidimDenseSet& + other) const { - if (isEmpty()) - return 0; + Util::ERROR("OrdUnidimDenseSet::cartesianProduct: operation not supported\n"); - return pieces_.begin()->arity(); + return OrdUnidimDenseSet{}; } -SetStratPtr OrdUnidimDenseSet::disjointCup(const SetStrategy& other) const & +// Extra operations ------------------------------------------------------------ + +std::size_t OrdUnidimDenseSet::arity() const { - OrdUnidimDenseSetCRef othr = static_cast(other); - - // Special cases if (isEmpty()) { - return std::make_unique(othr.pieces_); + return 0; } - if (othr.isEmpty() || pieces_ == othr.pieces_) { - return std::make_unique(pieces_); - } + return 1; +} - MDIOrdCollection result; - if (pieces_.back() < othr.pieces_.front()) { - result.insert(result.end(), pieces_.begin(), pieces_.end()); - result.insert(result.end(), othr.pieces_.begin(), othr.pieces_.end()); - return std::make_unique(std::move(result)); - } +OrdUnidimDenseSet OrdUnidimDenseSet::disjointCup(const OrdUnidimDenseSet& other) + const & +{ + return OrdUnidimDenseSet{*this}.disjointCup(other); +} - if (othr.pieces_.back() < pieces_.front()) { - result.insert(result.end(), othr.pieces_.begin(), othr.pieces_.end()); - result.insert(result.end(), pieces_.begin(), pieces_.end()); - return std::make_unique(std::move(result)); - } - - MDIOrdCollection cup = traverse(&SetPiece::least, othr.pieces_); - return std::make_unique(std::move(cup)); +OrdUnidimDenseSet OrdUnidimDenseSet::disjointCup(const OrdUnidimDenseSet& other) + && +{ + return std::move(*this).disjointCup(OrdUnidimDenseSet{other}); } -SetStratPtr OrdUnidimDenseSet::disjointCup(SetStrategy&& other) && +OrdUnidimDenseSet OrdUnidimDenseSet::disjointCup(OrdUnidimDenseSet&& other) + const & { - OrdUnidimDenseSetCRef othr = static_cast(other); + return OrdUnidimDenseSet{*this}.disjointCup(std::move(other)); +} +OrdUnidimDenseSet OrdUnidimDenseSet::disjointCup(OrdUnidimDenseSet&& other) && +{ // Special cases if (isEmpty()) { - return std::make_unique(std::move(othr.pieces_)); + return OrdUnidimDenseSet{std::move(other._pieces)}; } - if (othr.isEmpty() || pieces_ == othr.pieces_) { - return std::make_unique(std::move(pieces_)); + if (other.isEmpty() || _pieces == other._pieces) { + return OrdUnidimDenseSet{std::move(_pieces)}; } - MDIOrdCollection result; - if (pieces_.back() < othr.pieces_.front()) { - result = std::move(pieces_); - result.insert(result.end(), othr.pieces_.begin(), othr.pieces_.end()); - return std::make_unique(std::move(result)); - } - - if (othr.pieces_.back() < pieces_.front()) { - result = std::move(othr.pieces_); - result.insert(result.end(), pieces_.begin(), pieces_.end()); - return std::make_unique(std::move(result)); + if (!overlap(_pieces, other._pieces)) { + OrdIntervalCollection result; + result.insert(result.end(), std::make_move_iterator(_pieces.begin()) + , std::make_move_iterator(_pieces.end())); + result.insert(result.end(), std::make_move_iterator(other._pieces.begin()) + , std::make_move_iterator(other._pieces.end())); + return result; } - MDIOrdCollection cup = traverse(&SetPiece::least, othr.pieces_); - return std::make_unique(std::move(cup)); + return traverse(least, other); } -SetStratPtr OrdUnidimDenseSet::filterSet(bool (*f)(const SetPiece& mdi)) const +OrdUnidimDenseSet OrdUnidimDenseSet::offset(const MD_NAT& offset) const { - MDIOrdCollection res; + OrdUnidimDenseSet result; - for (const SetPiece& mdi : pieces_) - if (f(mdi)) - res.emplace_back(mdi); + for (const Interval& i : _pieces) { + result.pushBack(i.offset(offset[0])); + } - return std::make_unique(std::move(res)); + return result; } -SetStratPtr OrdUnidimDenseSet::offset(const MD_NAT& off) const +Perimeter OrdUnidimDenseSet::perimeter() const { - MDIOrdCollection res; - - for (const SetPiece& mdi : pieces_) - res.emplace_back(mdi.offset(off)); - - return std::make_unique(std::move(res)); + return Perimeter{minElem(), maxElem()}; } -SetStratPtr OrdUnidimDenseSet::compact() const +void OrdUnidimDenseSet::compact() { - MDIOrdCollection res; - - if (isEmpty()) - return std::make_unique(std::move(res)); + if (isEmpty()) { + return; + } - auto next_it = pieces_.begin(); + OrdIntervalCollection result; + auto next_it = _pieces.begin(); ++next_it; - SetPiece compacted = *pieces_.begin(); - for (auto it = pieces_.begin(); next_it != pieces_.end(); ++it) { - MaybeMDI ith = compacted.compact(*next_it); + Interval compacted = _pieces.front(); + for (auto it = _pieces.begin(); next_it != _pieces.end(); ++it) { + MaybeInterval ith = compacted.compact(*next_it); if (!ith) { - res.emplace_back(compacted); + result.push_back(compacted); compacted = *next_it; } else { compacted = ith.value(); @@ -464,90 +431,83 @@ SetStratPtr OrdUnidimDenseSet::compact() const ++next_it; } - res.emplace_back(compacted); + result.push_back(compacted); - return std::make_unique(std::move(res)); + _pieces = std::move(result); } -OrdUnidimDenseSet::MDIOrdCollection OrdUnidimDenseSet::boundedTraverse( - SetPiece (SetPiece::*f)(const SetPiece&) const, const MDIOrdCollection& other +OrdUnidimDenseSet OrdUnidimDenseSet::boundedTraverse( + Interval f(const Interval&, const Interval&), const OrdUnidimDenseSet& other ) const { - MDIOrdCollection res; - - if (isEmpty() || other.empty()) - return res; - - auto it1 = pieces_.begin(); - auto end1 = pieces_.end(); - auto it2 = other.begin(); - auto end2 = other.end(); - SetPiece mdi1; - SetPiece mdi2; + OrdUnidimDenseSet result; + auto it1 = _pieces.begin(); + auto end1 = _pieces.end(); + auto it2 = other._pieces.begin(); + auto end2 = other._pieces.end(); for (int j = 0; it1 != end1 && it2 != end2; ++j) { - mdi1 = *it1; - mdi2 = *it2; - - SetPiece funci = (mdi1.*f)(mdi2); - if (!funci.isEmpty()) - res.emplace_back(funci); + const Interval i1 = *it1; + const Interval i2 = *it2; + result.pushBack(f(i1, i2)); - if (mdi1.maxElem() < mdi2.maxElem()) { + if (i1.maxElem() < i2.maxElem()) { ++it1; } else { ++it2; } } - return res; + return result; } -OrdUnidimDenseSet::MDIOrdCollection OrdUnidimDenseSet::traverse( - SetPiece (SetPiece::*f)(const SetPiece&) const, const MDIOrdCollection& other -) const +OrdUnidimDenseSet OrdUnidimDenseSet::traverse( + Interval f(const Interval&, const Interval&) , const OrdUnidimDenseSet& other) + const { - MDIOrdCollection res; - - if (isEmpty()) - return other; + OrdUnidimDenseSet result; - if (other.empty()) - return pieces_; - - auto it1 = pieces_.begin(); - auto end1 = pieces_.end(); - auto it2 = other.begin(); - auto end2 = other.end(); - SetPiece mdi1; - SetPiece mdi2; + auto it1 = _pieces.begin(); + auto end1 = _pieces.end(); + auto it2 = other._pieces.begin(); + auto end2 = other._pieces.end(); for (; it1 != end1 && it2 != end2;) { - mdi1 = *it1; - mdi2 = *it2; + const Interval i1 = *it1; + const Interval i2 = *it2; + result.pushBack(f(i1, i2)); - SetPiece funci = (mdi1.*f)(mdi2); - if (!funci.isEmpty()) - res.emplace_back(funci); - - if (mdi1.maxElem() < mdi2.maxElem()) { + if (i1.maxElem() < i2.maxElem()) { ++it1; } else { ++it2; } } + result._pieces.insert(result.end(), it1, end1); + result._pieces.insert(result.end(), it2, end2); - for (; it1 != end1; ++it1) { - mdi1 = *it1; - res.emplace_back(mdi1); - } + return result; +} - for (; it2 != end2; ++it2) { - mdi2 = *it2; - res.emplace_back(mdi2); +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(OrdUnidimDenseSet s + , rapidjson::Document::AllocatorType& alloc) +{ + rapidjson::Value interval_array{rapidjson::kArrayType}; + for (const Interval& i : s) { + rapidjson::Value jth_array{rapidjson::kArrayType}; + jth_array.PushBack(detail::toJSON(i, alloc), alloc); + rapidjson::Value jth{rapidjson::kObjectType}; + jth.AddMember("bounds", jth_array, alloc); + interval_array.PushBack(jth, alloc); } + rapidjson::Value result{rapidjson::kObjectType}; + result.AddMember("pieces", interval_array, alloc); - return res; + return result; } +} // namespace detail + } // namespace LIB } // namespace SBG diff --git a/sbg/ord_unidim_dense_set.hpp b/sbg/ord_unidim_dense_set.hpp index f5ac1b1d..30ac1b23 100644 --- a/sbg/ord_unidim_dense_set.hpp +++ b/sbg/ord_unidim_dense_set.hpp @@ -24,102 +24,113 @@ ******************************************************************************/ -#ifndef SBG_ORD_UNIDIM_DENSE_SET_HPP -#define SBG_ORD_UNIDIM_DENSE_SET_HPP +#ifndef SBGRAPH_SBG_ORD_UNIDIM_DENSE_SET_HPP_ +#define SBGRAPH_SBG_ORD_UNIDIM_DENSE_SET_HPP_ -#include "sbg/set.hpp" +#include "sbg/expression.hpp" +#include "sbg/fixed_points.hpp" +#include "sbg/interval.hpp" +#include "sbg/multidim_inter.hpp" +#include "sbg/natural.hpp" +#include "sbg/perimeter.hpp" + +#include "rapidjson/document.h" + +#include +#include +#include namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// -// Ordered Unidimensional Dense Set Implementation (concrete strategy) --------- +// Ordered Unidimensional Dense Set Implementation ----------------------------- //////////////////////////////////////////////////////////////////////////////// -class OrdUnidimDenseSet : public SetStrategy { - using MDIOrdCollection = std::vector; +class OrdUnidimDenseSet { +public: + using OrdIntervalCollection = std::vector; + using ConstIt = OrdIntervalCollection::const_iterator; - member_class(MDIOrdCollection, pieces); - - ~OrdUnidimDenseSet(); OrdUnidimDenseSet(); - OrdUnidimDenseSet(MD_NAT x); - OrdUnidimDenseSet(Interval i); - OrdUnidimDenseSet(SetPiece mdi); - OrdUnidimDenseSet(MDIOrdCollection pieces); - - SetStratPtr clone() const override; - - class Iterator : public SetStrategy::Iterator { - member_class(MDIOrdCollection::const_iterator, it); + OrdUnidimDenseSet(const NAT x); + OrdUnidimDenseSet(const detail::Interval& i); + OrdUnidimDenseSet(const OrdIntervalCollection& pieces); + OrdUnidimDenseSet(OrdIntervalCollection&& pieces); + OrdUnidimDenseSet(const FixedPointsInfo& info); - Iterator(MDIOrdCollection::const_iterator it); - void operator++() override; - bool operator!=(const SetStrategy::Iterator& other) const override; - bool operator==(const SetStrategy::Iterator& other) const override; - bool operator<(const SetStrategy::Iterator& other) const override; - const SetPiece& operator*() const override; - }; + ConstIt begin() const; + ConstIt end() const; - std::shared_ptr begin() const override; - std::shared_ptr end() const override; + void pushBack(const Interval& mdi); - std::size_t size() const override; - void emplace(const SetPiece& mdi) override; - void emplaceBack(const SetPiece& mdi) override; - - bool operator==(const SetStrategy& other) const override; - bool operator!=(const SetStrategy& other) const override; - std::ostream& print(std::ostream& out) const override; + bool operator==(const OrdUnidimDenseSet& other) const; + bool operator!=(const OrdUnidimDenseSet& other) const; + std::ostream& print(std::ostream& out) const; // Traditional set operations ------------------------------------------------ - unsigned int cardinal() const override; - bool isEmpty() const override; - MD_NAT minElem() const override; - MD_NAT maxElem() const override; - SetStratPtr intersection(const SetStrategy& other) const override; - SetStratPtr cup(const SetStrategy& other) const & override; - SetStratPtr cup(SetStrategy&& other) && override; - SetStratPtr complement() const; - SetStratPtr difference(const SetStrategy& other) const override; + unsigned int cardinal() const; + bool isEmpty() const; + MD_NAT minElem() const; + MD_NAT maxElem() const; + OrdUnidimDenseSet intersection(const OrdUnidimDenseSet& other) const; + OrdUnidimDenseSet cup(const OrdUnidimDenseSet& other) const &; + OrdUnidimDenseSet cup(const OrdUnidimDenseSet& other) &&; + OrdUnidimDenseSet cup(OrdUnidimDenseSet&& other) const &; + OrdUnidimDenseSet cup(OrdUnidimDenseSet&& other) &&; + OrdUnidimDenseSet complement() const; + OrdUnidimDenseSet difference(const OrdUnidimDenseSet& other) const; + OrdUnidimDenseSet cartesianProduct(const OrdUnidimDenseSet& other) const; // Extra operations ---------------------------------------------------------- - std::size_t arity() const override; - SetStratPtr disjointCup(const SetStrategy& other) const & override; - SetStratPtr disjointCup(SetStrategy&& other) && override; - SetStratPtr filterSet(bool (*f)(const SetPiece& mdi)) const override; - SetStratPtr offset(const MD_NAT& off) const override; - SetStratPtr compact() const override; + std::size_t arity() const; + OrdUnidimDenseSet disjointCup(const OrdUnidimDenseSet& other) const &; + OrdUnidimDenseSet disjointCup(const OrdUnidimDenseSet& other) &&; + OrdUnidimDenseSet disjointCup(OrdUnidimDenseSet&& other) const &; + OrdUnidimDenseSet disjointCup(OrdUnidimDenseSet&& other) &&; + OrdUnidimDenseSet offset(const MD_NAT& offset) const; + Perimeter perimeter() const; + void compact(); - private: +private: /** * @brief Performs operation f between a piece of s1 and a piece of s2. At the - * start begins with both minimum elements, and advances the iterator of the - * set with the piece that has the minimum end. This is repeated until one of - * the two collections is consumed. + * start it begins with both minimum elements, and advances the iterator of + * the set with the piece that has the minimum end. This is repeated until one + * of the two collections is consumed. */ - MDIOrdCollection boundedTraverse(SetPiece (SetPiece::*f)(const SetPiece&) const - , const MDIOrdCollection& other) const; + OrdUnidimDenseSet boundedTraverse(Interval f(const Interval&, const Interval&) + , const OrdUnidimDenseSet& other) const; /** * @brief Performs operation f between a piece of s1 and a piece of s2. At the - * start begins with both minimum elements, and advances the iterator of the - * set with the piece that has the minimum end. This is repeated until one of - * the two collections is consumed. Then, all the remaining pieces of the + * start it begins with both minimum elements, and advances the iterator of + * the set with the piece that has the minimum end. This is repeated until one + * of the two collections is consumed. Then, all the remaining pieces of the * other set are also inserted. */ - MDIOrdCollection traverse(SetPiece (SetPiece::*f)(const SetPiece&) const - , const MDIOrdCollection& other) const; + OrdUnidimDenseSet traverse(Interval f(const Interval&, const Interval&) + , const OrdUnidimDenseSet& other) const; + + OrdIntervalCollection _pieces; + + friend class SetAccessKey; }; -typedef const OrdUnidimDenseSet& OrdUnidimDenseSetCRef; -typedef OrdUnidimDenseSet& OrdUnidimDenseSetRef; +// Non-member definitions ------------------------------------------------------ + +rapidjson::Value toJSON(OrdUnidimDenseSet s + , rapidjson::Document::AllocatorType& alloc); + +} // namespace detail } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_ORD_UNIDIM_DENSE_SET_HPP_ diff --git a/algorithms/toposort/topo_sort.cpp b/sbg/perimeter.cpp old mode 100644 new mode 100755 similarity index 65% rename from algorithms/toposort/topo_sort.cpp rename to sbg/perimeter.cpp index ee63501a..9dac1e0d --- a/algorithms/toposort/topo_sort.cpp +++ b/sbg/perimeter.cpp @@ -17,30 +17,33 @@ ******************************************************************************/ -#include - -#include "algorithms/toposort/topo_sort.hpp" -#include "util/logger.hpp" +#include "sbg/perimeter.hpp" namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Topological Sort Algorithm Abstract Strategy Constructors ------------------- +// Set perimeter --------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -TSStrategy::TSStrategy() {} +Perimeter::Perimeter(const MD_NAT& min, const MD_NAT& max) + : _min(min), _max(max) {} -//////////////////////////////////////////////////////////////////////////////// -// Topological Sort Algorithm Interface ---------------------------------------- -//////////////////////////////////////////////////////////////////////////////// +const MD_NAT& Perimeter::min() const { return _min; } -TopoSort::TopoSort(TSStratPtr strat) : strategy_(std::move(strat)) {} +const MD_NAT& Perimeter::max() const { return _max; } -PWMap TopoSort::calculate(const DSBG& dsbg) const +bool Perimeter::overlap(const Perimeter& other) const { - return strategy_->calculate(dsbg); + std::size_t arity = _min.arity(); + for (std::size_t j = 0; j < arity; ++j) { + if (_max[j] < other._min[j] || other._max[j] < _min[j]) { + return false; + } + } + + return true; } } // namespace LIB diff --git a/sbg/perimeter.hpp b/sbg/perimeter.hpp new file mode 100755 index 00000000..cbf95340 --- /dev/null +++ b/sbg/perimeter.hpp @@ -0,0 +1,55 @@ +/** @file perimeter.pp + + @brief Perimeter + + The perimeter is the smallest dense MultiDimInter that contains all of the + elements of a collection of multi-dimensional values. Thus, is can be defined + using only two multi-dimensional values. + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_SBG_PERIMETER_HPP_ +#define SBGRAPH_SBG_PERIMETER_HPP_ + +#include "sbg/natural.hpp" + +namespace SBG { + +namespace LIB { + +class Perimeter { +public: + Perimeter(const MD_NAT& min, const MD_NAT& max); + + const MD_NAT& min() const; + const MD_NAT& max() const; + + bool overlap(const Perimeter& other) const; + +private: + MD_NAT _min; + MD_NAT _max; +}; + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_SBG_PERIMETER_HPP_ diff --git a/sbg/pw_map.cpp b/sbg/pw_map.cpp index 958dafd2..51efd902 100644 --- a/sbg/pw_map.cpp +++ b/sbg/pw_map.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - This file is part of Set--Based Graph Library. + This file is part of PWMap--Based Graph Library. SBG Library is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -8,7 +8,7 @@ (at your option) any later version. SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of + but WITHOUT ANY WARRANTY; without even the stratied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -18,193 +18,436 @@ ******************************************************************************/ #include "sbg/pw_map.hpp" +#include "sbg/pwmap_impl.hpp" +#include "util/debug.hpp" +#include "util/defs.hpp" + +#include namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// PWMap Abstract Strategy Constructors ---------------------------------------- +// PWMap Iterator -------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -PWMapStrategy::PWMapStrategy() {} +PWMap::ConstIt::ConstIt(detail::UnordPWMap::ConstIt it) : _it(it) {} -//////////////////////////////////////////////////////////////////////////////// -// PWMap Interface ------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// +PWMap::ConstIt::ConstIt(detail::OrdPWMap::ConstIt it) : _it(it) {} -PWMap::PWMap(PWMapStratPtr strat) : strategy_(std::move(strat)) {} +const Map& PWMap::ConstIt::operator*() +{ + auto it_visitor = SBG::Util::Overload { + [](const detail::UnordPWMap::ConstIt& i) -> const Map& { return *i; }, + [](const detail::OrdPWMap::ConstIt& i) -> const Map& { return i->map(); } + }; + return std::visit(it_visitor, _it); +} -PWMap::PWMap(const PWMap& other) - : strategy_(other.strategy_ ? other.strategy_->clone() : nullptr) {} +PWMap::ConstIt PWMap::ConstIt::operator++() +{ + std::visit([](auto& i) { ++i; }, _it); + return *this; +} -PWMap::Iterator::Iterator(std::shared_ptr it) - : it_(std::move(it)) {} +bool PWMap::ConstIt::operator==(const ConstIt& other) +{ + return _it == other._it; +} -void PWMap::Iterator::operator++() +bool PWMap::ConstIt::operator!=(const ConstIt& other) { - ++(*it_); - return; + return _it != other._it; } -Map PWMap::Iterator::operator*() const { return **it_; } +//////////////////////////////////////////////////////////////////////////////// +// PWMap ---------------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +// Constructors ---------------------------------------------------------------- -bool PWMap::Iterator::operator!=(const Iterator& other) const +PWMap::PWMap() : _impl() { - return *it_ != *other.it_; + PWMapKind kind = PWMAP_IMPL.kind(); + switch (kind) { + case PWMapKind::kUnordered: { + _impl = detail::UnordPWMap{}; + break; + } + + case PWMapKind::kOrdered: { + _impl = detail::OrdPWMap{}; + break; + } + + case PWMapKind::kDomOrdered: { + _impl = detail::DomOrdPWMap{}; + break; + } + + default: { + Util::ERROR("Unsupported ", kind, " PWMap implementation\n"); + break; + } + } } -PWMap::Iterator PWMap::begin() const { return strategy_->begin(); } -PWMap::Iterator PWMap::end() const { return strategy_->end(); } +PWMap::PWMap(Set s) : _impl() +{ + PWMapKind kind = PWMAP_IMPL.kind(); + switch (kind) { + case PWMapKind::kUnordered: { + _impl = detail::UnordPWMap{s}; + break; + } + + case PWMapKind::kOrdered: { + _impl = detail::OrdPWMap{s}; + break; + } + + case PWMapKind::kDomOrdered: { + _impl = detail::DomOrdPWMap{s}; + break; + } + + default: { + Util::ERROR("Unsupported ", kind, " PWMap implementation\n"); + break; + } + } +} + +PWMap::PWMap(Map m) : _impl() +{ + PWMapKind kind = PWMAP_IMPL.kind(); + switch (kind) { + case PWMapKind::kUnordered: { + _impl = detail::UnordPWMap{m}; + break; + } + + case PWMapKind::kOrdered: { + _impl = detail::OrdPWMap{m}; + break; + } + + case PWMapKind::kDomOrdered: { + _impl = detail::DomOrdPWMap{m}; + break; + } + + default: { + Util::ERROR("Unsupported ", kind, " PWMap implementation\n"); + break; + } + } +} -void PWMap::emplaceBack(const Map& m) +PWMap::PWMap(const detail::PWMapImpl& impl) : _impl(impl) {} + +PWMap::PWMap(detail::PWMapImpl&& impl) : _impl(std::move(impl)) {} + +// Getters --------------------------------------------------------------------- + +PWMap::ConstIt PWMap::begin() { - strategy_->emplaceBack(m); - return; + return std::visit([](const auto& a) { return PWMap::ConstIt(a.begin()); } + , _impl); } -bool PWMap::operator==(const PWMap& other) const +PWMap::ConstIt PWMap::end() { - return *strategy_ == *other.strategy_; + return std::visit([](const auto& a) { return PWMap::ConstIt(a.end()); } + , _impl); } -bool PWMap::operator!=(const PWMap& other) const { return !(*this == other); } +// Setters --------------------------------------------------------------------- -PWMap& PWMap::operator=(const PWMap& other) +void PWMap::insert(const Map& m) { - if (this !=& other) - strategy_ = other.strategy_->clone(); + std::visit([&m](auto& a) -> void { a.insert(m); } , _impl); +} - return *this; +void PWMap::insert(Map&& m) +{ + std::visit([move_m = std::move(m)](auto& a) { a.insert(move_m); } + , _impl); +} + +// Operators ------------------------------------------------------------------- + +bool PWMap::operator==(const PWMap& other) const +{ + return _impl == other._impl; } -PWMap& PWMap::operator=(PWMap&& other) +bool PWMap::operator!=(const PWMap& other) const { - if (this !=& other) - strategy_ = std::move(other.strategy_); + return !(*this == other); +} - return *this; +PWMap PWMap::operator+(const PWMap& other) const +{ + return std::visit([](const auto& a, const auto& b) + { + using A = std::decay_t; + using B = std::decay_t; + if constexpr (std::is_same_v) { + return PWMap{a + b}; + } else { + Util::ERROR("PWMap::operator+: mismatched implementations\n"); + return PWMap{}; + } + } + , _impl, other._impl); } std::ostream& PWMap::print(std::ostream& out) const { - strategy_->print(out); + std::visit([&out](const auto& a) -> void { a.print(out); } , _impl); return out; } -std::ostream& operator<<(std::ostream& out, const PWMap& pw) +std::ostream& operator<<(std::ostream& out, const PWMap& s) { - pw.print(out); + s.print(out); return out; } -PWMap PWMap::operator+(const PWMap& other) const +// PWMap operations -------------------------------------------------------------- + +std::size_t PWMap::arity() const { - return strategy_->operator+(*other.strategy_); + return std::visit([](const auto& a) { return a.arity(); }, _impl); } -std::size_t PWMap::arity() const { return strategy_->arity(); } +bool PWMap::isEmpty() const +{ + return std::visit([](const auto& a) { return a.isEmpty(); }, _impl); +} -bool PWMap::isEmpty() const { return strategy_->isEmpty(); } +Set PWMap::domain() const & +{ + return std::visit([](const auto& a) { return a.domain(); }, _impl); +} -Set PWMap::dom() const { return strategy_->dom(); } +Set PWMap::domain() && +{ + return std::visit([](auto&& a) { return std::move(a).domain(); }, _impl); +} PWMap PWMap::restrict(const Set& subdom) const { - return strategy_->restrict(subdom); + return std::visit([&](const auto& a) -> PWMap + { + return PWMap{a.restrict(subdom)}; + } + , _impl); } -Set PWMap::image() const { return strategy_->image(); } -Set PWMap::image(const Set& subdom) const { return strategy_->image(subdom); } +Set PWMap::image() const +{ + return std::visit([](const auto& a) { return a.image(); }, _impl); +} + +Set PWMap::image(const Set& subdom) const +{ + return std::visit([&subdom](const auto& a) { return a.image(subdom); } + , _impl); +} Set PWMap::preImage(const Set& subcodom) const { - return strategy_->preImage(subcodom); + return std::visit([&subcodom](const auto& a) { return a.preImage(subcodom); } + , _impl); } -PWMap PWMap::inverse() const { return strategy_->inverse(); } +PWMap PWMap::inverse() const +{ + return std::visit([](const auto& a) { return PWMap{a.inverse()}; } + , _impl); +} PWMap PWMap::composition(const PWMap& other) const { - return strategy_->composition(*other.strategy_); + return std::visit([](const auto& a, const auto& b) + { + using A = std::decay_t; + using B = std::decay_t; + if constexpr (std::is_same_v) { + return PWMap{a.composition(b)}; + } else { + Util::ERROR("PWMap::composition: mismatched implementations\n"); + return PWMap{}; + } + } + , _impl, other._impl); } -PWMap PWMap::mapInf(unsigned int n) const { return strategy_->mapInf(n); } +PWMap PWMap::mapInf() const +{ + return std::visit([](const auto& a) { return PWMap{a.mapInf()}; } + , _impl); +} -PWMap PWMap::mapInf() const { return strategy_->mapInf(); } +Set PWMap::fixedPoints() const +{ + return std::visit([](const auto& a) { return a.fixedPoints(); }, _impl); +} -Set PWMap::fixedPoints() const { return strategy_->fixedPoints(); } +// Extra operations ------------------------------------------------------------ -PWMap PWMap::concatenation(const PWMap& other) const +PWMap PWMap::concatenation(const PWMap& other) const & { - return strategy_->concatenation(*other.strategy_); + return PWMap{*this}.concatenation(other); } -PWMap PWMap::combine(const PWMap& other) const +PWMap PWMap::concatenation(const PWMap& other) && { - return strategy_->combine(*other.strategy_); + return std::move(*this).concatenation(PWMap{other}); } -PWMap PWMap::reduce() const { return strategy_->reduce(); } - -PWMap PWMap::minMap(const PWMap& other) const +PWMap PWMap::concatenation(PWMap&& other) const & { - return strategy_->minMap(*other.strategy_); + return PWMap{*this}.concatenation(std::move(other)); } -PWMap PWMap::minAdjMap(const PWMap& other) const +PWMap PWMap::concatenation(PWMap&& other) && { - return strategy_->minAdjMap(*other.strategy_); + return std::visit([](auto&& a, auto&& b) + { + using A = std::decay_t; + using B = std::decay_t; + if constexpr (std::is_same_v) { + return PWMap{std::move(a).concatenation(std::move(b))}; + } else { + Util::ERROR("PWMap::concatenation: mismatched implementations\n"); + return PWMap{}; + } + } + , std::move(_impl), std::move(other._impl)); } -PWMap PWMap::firstInv(const Set& subdom) const +PWMap PWMap::combine(const PWMap& other) const & { - return strategy_->firstInv(subdom); + return PWMap{*this}.combine(other); } -PWMap PWMap::firstInv() const { return strategy_->firstInv(); } +PWMap PWMap::combine(const PWMap& other) && +{ + return std::move(*this).combine(PWMap{other}); +} -PWMap PWMap::filterMap(bool (*f)(const Map&)) const +PWMap PWMap::combine(PWMap&& other) const & { - return strategy_->filterMap(f); + return PWMap{*this}.combine(std::move(other)); } -Set PWMap::equalImage(const PWMap& other) const +PWMap PWMap::combine(PWMap&& other) && { - return strategy_->equalImage(*other.strategy_); + return std::visit([](auto&& a, auto&& b) + { + using A = std::decay_t; + using B = std::decay_t; + if constexpr (std::is_same_v) { + return PWMap{std::move(a).combine(std::move(b))}; + } else { + Util::ERROR("PWMap::combine: mismatched implementations\n"); + return PWMap{}; + } + } + , std::move(_impl), std::move(other._impl)); } -Set PWMap::lessImage(const PWMap& other) const +PWMap PWMap::min(const PWMap& other) const { - return strategy_->lessImage(*other.strategy_); + return std::visit([](const auto& a, const auto& b) + { + using A = std::decay_t; + using B = std::decay_t; + if constexpr (std::is_same_v) { + return PWMap{a.min(b)}; + } else { + Util::ERROR("PWMap::min: mismatched implementations\n"); + return PWMap{}; + } + } + , _impl, other._impl); } -Set PWMap::sharedImage() const { return strategy_->sharedImage(); } +PWMap PWMap::minAdj(const PWMap& other) const +{ + return std::visit([](const auto& a, const auto& b) + { + using A = std::decay_t; + using B = std::decay_t; + if constexpr (std::is_same_v) { + return PWMap{a.minAdj(b)}; + } else { + Util::ERROR("PWMap::minAdj: mismatched implementations\n"); + return PWMap{}; + } + } + , _impl, other._impl); +} -PWMap PWMap::offsetDom(const MD_NAT& off) const +Set PWMap::sharedImage() const { - return strategy_->offsetDom(off); + return std::visit([](const auto& a) { return a.sharedImage(); }, _impl); } -PWMap PWMap::offsetDom(const PWMap& off) const +Set PWMap::equalImage(const PWMap& other) const { - return strategy_->offsetDom(*off.strategy_); + return std::visit([](const auto& a, const auto& b) + { + using A = std::decay_t; + using B = std::decay_t; + if constexpr (std::is_same_v) { + return a.equalImage(b); + } else { + Util::ERROR("PWMap::equalImage: mismatched implementations\n"); + return Set{}; + } + } + , _impl, other._impl); } -PWMap PWMap::offsetImage(const MD_NAT& off) const +Set PWMap::lessImage(const PWMap& other) const { - return strategy_->offsetImage(off); + return std::visit([](const auto& a, const auto& b) + { + using A = std::decay_t; + using B = std::decay_t; + if constexpr (std::is_same_v) { + return a.lessImage(b); + } else { + Util::ERROR("PWMap::lessImage: mismatched implementations\n"); + return Set{}; + } + } + , _impl, other._impl); } -PWMap PWMap::offsetImage(const Exp& off) const +PWMap PWMap::imageMultiplicity() const { - return strategy_->offsetImage(off); + return std::visit([](const auto& a) { return PWMap{a.imageMultiplicity()}; } + , _impl); } -PWMap PWMap::compact() const { return strategy_->compact(); } +void PWMap::compact() +{ + std::visit([](auto& a) { a.compact(); }, _impl); +} -} // namespace LIB +rapidjson::Value PWMap::toJSON(rapidjson::Document::AllocatorType& alloc) const +{ + return std::visit([&alloc](auto a) { return detail::toJSON(a, alloc); } + , _impl); +} -} // namespace SBG; +} // namespace LIB +} // namespace SBG diff --git a/sbg/pw_map.hpp b/sbg/pw_map.hpp index 10bf6663..6e929da9 100644 --- a/sbg/pw_map.hpp +++ b/sbg/pw_map.hpp @@ -5,10 +5,12 @@ A piecewise map (pw) <> is a representation for functions using collections of domain-disjoint Maps, all sharing the same arity. Maps of the collection will be named "pieces" (i.e. m1, ..., mj). The domain of the - function is the union of all domains of every map. Currently two + function is the union of all domains of every map. Currently three implementations are supported: - Unordered PWMaps. - - Ordered PWMaps, allowing different optimizations. + - Ordered PWMaps, that saves comparisons between maps in some operations. + - Domain ordered PWMaps, that have an ordered set implementation as domain, + and also order their collection of maps accordingly.
@@ -29,67 +31,84 @@ ******************************************************************************/ -#ifndef SBG_PWMAP_HPP -#define SBG_PWMAP_HPP - -#include +#ifndef SBGRAPH_SBG_PW_MAP_HPP_ +#define SBGRAPH_SBG_PW_MAP_HPP_ +#include "sbg/dom_ord_pwmap.hpp" #include "sbg/map.hpp" +#include "sbg/ord_pwmap.hpp" +#include "sbg/set.hpp" +#include "sbg/unord_pwmap.hpp" + +#include "rapidjson/document.h" namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// -// PWMap Abstract Strategy ----------------------------------------------------- +// PWMaps implementations ------------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// -class PWMapStrategy; +using PWMapImpl = std::variant; -typedef std::unique_ptr PWMapStratPtr; +class PWMapAccessKey; -class PWMapStrategy { - public: - virtual ~PWMapStrategy() = default; +} // namespace detail - /** - * @brief Constructs an empty pw. - */ - PWMapStrategy(); +//////////////////////////////////////////////////////////////////////////////// +// PWMap ----------------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +class PWMap { +public: + class ConstIt { + public: + const Map& operator*(); + ConstIt operator++(); + bool operator==(const ConstIt& other); + bool operator!=(const ConstIt& other); + + private: + ConstIt(detail::UnordPWMap::ConstIt it); + ConstIt(detail::OrdPWMap::ConstIt it); + + std::variant _it; + + friend class PWMap; + }; /** - * @brief Auxiliary function for defining the copy constructor of PWMap. + * @brief Constructs an empty domain pw. */ - virtual PWMapStratPtr clone() const = 0; - - class Iterator { - public: - virtual ~Iterator() = default; - virtual void operator++() = 0; - virtual bool operator!=(const Iterator& other) const = 0; - virtual const Map& operator*() const = 0; - }; + PWMap(); + PWMap(Set s); + PWMap(Map m); - virtual std::shared_ptr begin() const = 0; - virtual std::shared_ptr end() const = 0; + ConstIt begin(); + ConstIt end(); + template + void emplace(Args&&... args); /** * @brief Adds a piece to the pw. + * Precondition: \p m domain should not be empty, and should have no + * intersection with the current domain of the PWMap. */ - virtual void emplaceBack(const Map& m) = 0; + void insert(const Map& m); + void insert(Map&& m); /** * @brief Two pws are equal if they satisfy the function extensionality * principle. */ - virtual bool operator==(const PWMapStrategy& other) const = 0; - virtual bool operator!=(const PWMapStrategy& other) const = 0; - virtual std::ostream& print(std::ostream& out) const = 0; - - /** - * @brief Sum of two pws. - */ - virtual PWMapStratPtr operator+(const PWMapStrategy& other) const = 0; + bool operator==(const PWMap& other) const; + bool operator!=(const PWMap& other) const; + PWMap operator+(const PWMap& other) const; + std::ostream& print(std::ostream& out) const; // Traditional maps operations ----------------------------------------------- @@ -97,35 +116,36 @@ class PWMapStrategy { * @brief Number of dimensions of the elements that compose the pw. For * example, arity(<<{[1:1:10] x [1:1:10]} -> 1*x+0|1*x+0>>) = 2. */ - virtual std::size_t arity() const = 0; + std::size_t arity() const; /** * @brief Determines if the collection is empty or not. */ - virtual bool isEmpty() const = 0; + bool isEmpty() const; /** * @brief Domain of the pw, i.e. the union of all domains of every map in the * collection. */ - virtual Set dom() const = 0; + Set domain() const &; + Set domain() &&; /** * @brief Restrict the domain of the pw to \p subdom. */ - virtual PWMapStratPtr restrict(const Set& subdom) const = 0; + PWMap restrict(const Set& subdom) const; /** * @brief Calculates all possible images for all elements in the domain of * the pw. */ - virtual Set image() const = 0; + Set image() const; /** * @brief Calculates all possible images for all elements in the domain of * the pw restricted to \p subdom. */ - virtual Set image(const Set& subdom) const = 0; + Set image(const Set& subdom) const; /** * @brief Calculates the pre image of certain elements of the image. @@ -133,35 +153,29 @@ class PWMapStrategy { * @param subcodom Set of elements in the image of the map for which the pre * image will be calculated. */ - virtual Set preImage(const Set& subcodom) const = 0; + Set preImage(const Set& subcodom) const; /** * @brief Calculate the inverse of a bijective pw.\n * Precondition: the pw must be bijective. */ - virtual PWMapStratPtr inverse() const = 0; + PWMap inverse() const; /** * @brief Calculate the composition of \p this with \p other, i.e. * \p this(\p other). */ - virtual PWMapStratPtr composition(const PWMapStrategy& pw2) const = 0; - - /** - * @brief First compose the pw with itself \p n times, obtaining pw'. Then, - * compose pw' with itself up to convergence. - */ - virtual PWMapStratPtr mapInf(unsigned int n) const = 0; + PWMap composition(const PWMap& pw2) const; /** * @brief Compose a map with itself up to convergence. */ - virtual PWMapStratPtr mapInf() const = 0; + PWMap mapInf() const; /** * @brief Calculates the set of elements in the domain such that f(x) = x. */ - virtual Set fixedPoints() const = 0; + Set fixedPoints() const; // Extra operations ---------------------------------------------------------- @@ -169,185 +183,83 @@ class PWMapStrategy { * @brief Concatenation of two pws.\n * Precondition: pws should domain-disjoint. */ - virtual PWMapStratPtr concatenation(const PWMapStrategy& other) const = 0; + PWMap concatenation(const PWMap& other) const &; + PWMap concatenation(const PWMap& other) &&; + PWMap concatenation(PWMap&& other) const &; + PWMap concatenation(PWMap&& other) &&; /** * @brief Extend the pw with exclusive elements in the domain of \p other. */ - virtual PWMapStratPtr combine(const PWMapStrategy& other) const = 0; - - /** - * @brief Calculates (if possible) compactly the result of mapInf.\n - * - * Currently, the only expressions that can be efficiently reduced are: - * - x+h - * - x-h - */ - virtual PWMapStratPtr reduce() const = 0; + PWMap combine(const PWMap& other) const &; + PWMap combine(const PWMap& other) &&; + PWMap combine(PWMap&& other) const &; + PWMap combine(PWMap&& other) &&; /** * @brief For every element in both domains assign the law that returns the * minimum value. */ - virtual PWMapStratPtr minMap(const PWMapStrategy& other) const = 0; + PWMap min(const PWMap& other) const; /** * @brief Given two maps pw1 (\p this) and pw2 (\p other), for every element y1 * in the image of pw1 returns a pw res such that * res(y1) = {min(pw2(x)) : pw1(x) = y1}. In SBG algorithms it is used to * calculate for every vertex which of its adjacent vertices returns the - * minimum value according to pw other. + * minimum value according to pw \p other. */ - virtual PWMapStratPtr minAdjMap(const PWMapStrategy& other) const = 0; + PWMap minAdj(const PWMap& other) const; /** - * @brief Pseudo-inverse of a pw restricted to \p subdom. If a value is the - * image of several elements of the original domain, it will mapped to any - * of the possible candidates. - */ - virtual PWMapStratPtr firstInv(const Set& subdom) const = 0; - - /** - * @brief Pseudo-inverse of a pw. - */ - virtual PWMapStratPtr firstInv() const = 0; - - /** - * Returns a pw that keeps pieces of the original pw that satisfy the - * predicate argument. + * @brief Given a map, return elements of the domain that share its image with + * other values of the domain. */ - virtual PWMapStratPtr filterMap(bool (*f)(const Map& )) const = 0; + Set sharedImage() const; /** * @brief Return elements in both domains, that have the same image in both * pws. */ - virtual Set equalImage(const PWMapStrategy& other) const = 0; + Set equalImage(const PWMap& other) const; /** * @brief Returns the set of elements of the domain that have a lesser * image in the first argument. * For example: lessImage({[1:100]} -> x, {[1:100]} -> -x+100) = {[1:49]}. */ - virtual Set lessImage(const PWMapStrategy& other) const = 0; + Set lessImage(const PWMap& other) const; - /** - * @brief Given a map, return elements of the domain that share its image with - * other values of the domain. - */ - virtual Set sharedImage() const = 0; + PWMap imageMultiplicity() const; /** - * @brief Sum a constant value to every element in the domain of the pw. The - * law remains unchanged. + * @brief Minimize internal representation cost. Heuristic guided. */ - virtual PWMapStratPtr offsetDom(const MD_NAT& off) const = 0; + void compact(); - /** - * @brief Sum the value indicated by pw \p off for every value in the domain - * of the pw \p this. The law remains unchanged. - */ - virtual PWMapStratPtr offsetDom(const PWMapStrategy& off) const = 0; + rapidjson::Value toJSON(rapidjson::Document::AllocatorType& alloc) const; - /** - * @brief Sum a constant value to every element in the image of the pw, that - * is, the law of the pw is modified without altering its domain. - */ - virtual PWMapStratPtr offsetImage(const MD_NAT& off) const = 0; +private: + PWMap(const detail::PWMapImpl& impl); + PWMap(detail::PWMapImpl&& impl); - /** - * @brief Sum the expression \p off to every element in the image of the pw, - * that is, the law is modified without altering its domain. - */ - virtual PWMapStratPtr offsetImage(const Exp& off) const = 0; + detail::PWMapImpl _impl; - /** - * @brief Compact in the same piece all maps that have the same expression. - */ - virtual PWMapStratPtr compact() const = 0; + friend class detail::PWMapAccessKey; }; -//////////////////////////////////////////////////////////////////////////////// -// PWMap Interface (context) --------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -class PWMap { - public: - PWMap(PWMapStratPtr strat); - PWMap(const PWMap& other); - - class Iterator { - public: - Iterator(std::shared_ptr it); - void operator++(); - bool operator!=(const PWMap::Iterator& other) const; - Map operator*() const; - - private: - std::shared_ptr it_; - }; - - Iterator begin() const; - Iterator end() const; - - void emplaceBack(const Map& m); - - bool operator==(const PWMap& other) const; - bool operator!=(const PWMap& other) const; - PWMap& operator=(const PWMap& other); - PWMap& operator=(PWMap&& other); - std::ostream& print(std::ostream& out) const; - - PWMap operator+(const PWMap& other) const; - - // Traditional map operations ------------------------------------------------ - - std::size_t arity() const; - bool isEmpty() const; - Set dom() const; - PWMap restrict(const Set& subdom) const; - Set image() const; - Set image(const Set& subdom) const; - Set preImage(const Set& subcodom) const; - PWMap inverse() const; - PWMap composition(const PWMap& other) const; - - PWMap mapInf(unsigned int n) const; - PWMap mapInf() const; - Set fixedPoints() const; - - // Extra operations ---------------------------------------------------------- - - PWMap concatenation(const PWMap& other) const; - PWMap combine(const PWMap& other) const; - PWMap reduce() const; - - PWMap minMap(const PWMap& other) const; - PWMap minAdjMap(const PWMap& other) const; - - PWMap firstInv(const Set& subdom) const; - PWMap firstInv() const; - - PWMap filterMap(bool (*f)(const Map& )) const; - - Set equalImage(const PWMap& other) const; - Set lessImage(const PWMap& other) const; - Set sharedImage() const; - - PWMap offsetDom(const MD_NAT& off) const; - PWMap offsetDom(const PWMap& off) const; - PWMap offsetImage(const MD_NAT& off) const; - PWMap offsetImage(const Exp& off) const; +std::ostream& operator<<(std::ostream& out, const PWMap& pw); - PWMap compact() const; +// Template definitions -------------------------------------------------------- - private: - PWMapStratPtr strategy_; -}; -std::ostream& operator<<(std::ostream& out, const PWMap& pw); +template +inline void PWMap::emplace(Args&&... args) +{ + std::visit([&](auto& a) { a.emplace(std::forward(args)...); } , _impl); +} } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_PW_MAP_HPP_ diff --git a/sbg/pwmap_detail.cpp b/sbg/pwmap_detail.cpp new file mode 100755 index 00000000..dcd2f454 --- /dev/null +++ b/sbg/pwmap_detail.cpp @@ -0,0 +1,43 @@ +/******************************************************************************* + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "sbg/pwmap_detail.hpp" + +namespace SBG { + +namespace LIB { + +namespace detail { + +PWMap PWMapAccessKey::reduce(PWMap pw) const +{ + auto& impl = pw._impl; + return std::visit( + [](auto&& impl) -> PWMap { + return PWMap{impl.reduce()}; + }, impl); +} + +PWMapAccessKey PWMapAccess::key() { return PWMapAccessKey{}; }; + +} // namespace detail + +} // namespace LIB + +} // namespace SBG diff --git a/sbg/pwmap_detail.hpp b/sbg/pwmap_detail.hpp new file mode 100755 index 00000000..a3d3e451 --- /dev/null +++ b/sbg/pwmap_detail.hpp @@ -0,0 +1,59 @@ +/** @file pwmap_detail.hpp + + @brief PWMap implementation access + + This module is intended for internal use to access the implementation of + PWMaps, for example to benchmark private methods. + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_SBG_PWMAP_DETAIL_HPP_ +#define SBGRAPH_SBG_PWMAP_DETAIL_HPP_ + +#include "sbg/pw_map.hpp" + +namespace SBG { + +namespace LIB { + +namespace detail { + +class PWMapAccessKey { +public: + PWMap reduce(PWMap pw) const; + +private: + PWMapAccessKey() = default; + + friend class PWMapAccess; +}; + +class PWMapAccess { +public: + static PWMapAccessKey key(); +}; + +} // namespace detail + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_SBG_PWMAP_DETAIL_HPP_ diff --git a/sbg/pwmap_fact.cpp b/sbg/pwmap_fact.cpp deleted file mode 100644 index 292fc00b..00000000 --- a/sbg/pwmap_fact.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/******************************************************************************* - - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -#include "sbg/dom_ord_pwmap.hpp" -#include "sbg/pwmap_fact.hpp" -#include "sbg/ord_pwmap.hpp" -#include "sbg/unord_pwmap.hpp" - -namespace SBG { - -namespace LIB { - -//////////////////////////////////////////////////////////////////////////////// -// PWMap Factory --------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -PWMapFact::PWMapFact() {} - -//////////////////////////////////////////////////////////////////////////////// -// UnordPWMap Factory ---------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -UnordPWMapFact::UnordPWMapFact() {} - -PWMap UnordPWMapFact::createPWMap() const -{ - return PWMap(std::make_unique()); -} - -PWMap UnordPWMapFact::createPWMap(const Set &s) const -{ - return PWMap(std::make_unique(s)); -} - -PWMap UnordPWMapFact::createPWMap(const Map &m) const -{ - return PWMap(std::make_unique(m)); -} - -std::string UnordPWMapFact::prettyPrint() const -{ - return "unordered"; -} - -//////////////////////////////////////////////////////////////////////////////// -// OrdPWMap Factory ------------------------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -OrdPWMapFact::OrdPWMapFact() {} - -PWMap OrdPWMapFact::createPWMap() const -{ - return PWMap(std::make_unique()); -} - -PWMap OrdPWMapFact::createPWMap(const Set &s) const -{ - return PWMap(std::make_unique(s)); -} - -PWMap OrdPWMapFact::createPWMap(const Map &m) const -{ - return PWMap(std::make_unique(m)); -} - -std::string OrdPWMapFact::prettyPrint() const -{ - return "ordered"; -} - -//////////////////////////////////////////////////////////////////////////////// -// DomOrdPWMap Factory ------------------------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -DomOrdPWMapFact::DomOrdPWMapFact() {} - -PWMap DomOrdPWMapFact::createPWMap() const -{ - return PWMap(std::make_unique()); -} - -PWMap DomOrdPWMapFact::createPWMap(const Set &s) const -{ - return PWMap(std::make_unique(s)); -} - -PWMap DomOrdPWMapFact::createPWMap(const Map &m) const -{ - return PWMap(std::make_unique(m)); -} - -std::string DomOrdPWMapFact::prettyPrint() const -{ - return "domain ordered"; -} - -//////////////////////////////////////////////////////////////////////////////// -// Factory for clients --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -PWFactory::PWFactory() : pw_fact_(std::make_unique()) {} - -PWMapFact& PWFactory::pw_fact() -{ - return *pw_fact_; -} - -void PWFactory::set_pw_fact(PWMapFactPtr pw_fact) -{ - pw_fact_ = std::move(pw_fact); -} - -} // namespace LIB - -} // namespace SBG diff --git a/sbg/pwmap_fact.hpp b/sbg/pwmap_fact.hpp deleted file mode 100644 index d111f566..00000000 --- a/sbg/pwmap_fact.hpp +++ /dev/null @@ -1,105 +0,0 @@ -/** @file pwmap_fact.hpp - - @brief PWMap Factory - -
- - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -#ifndef SBG_PWMAP_FACT_HPP -#define SBG_PWMAP_FACT_HPP - -#include "pw_map.hpp" - -namespace SBG { - -namespace LIB { - -#define PW_FACT PWFactory::instance().pw_fact() - -class PWMapFact { - public: - virtual ~PWMapFact() = default; - PWMapFact(); - - virtual PWMap createPWMap() const = 0; - virtual PWMap createPWMap(const Set &s) const = 0; - virtual PWMap createPWMap(const Map &m) const = 0; - virtual std::string prettyPrint() const = 0; -}; - -class UnordPWMapFact : public PWMapFact { - public: - UnordPWMapFact(); - - PWMap createPWMap() const override; - PWMap createPWMap(const Set &s) const override; - PWMap createPWMap(const Map &m) const override; - std::string prettyPrint() const override; -}; - -class OrdPWMapFact : public PWMapFact { - public: - OrdPWMapFact(); - - PWMap createPWMap() const override; - PWMap createPWMap(const Set &s) const override; - PWMap createPWMap(const Map &m) const override; - std::string prettyPrint() const override; -}; - -class DomOrdPWMapFact : public PWMapFact { - public: - DomOrdPWMapFact(); - - PWMap createPWMap() const override; - PWMap createPWMap(const Set &s) const override; - PWMap createPWMap(const Map &m) const override; - std::string prettyPrint() const override; -}; - -using PWMapFactPtr = std::unique_ptr; - -/** - * @brief Single instance of pw factory to be used by clients in need of - * creating pws. A client includes this file and calls - * PW_FACT.createPWMap(args). - */ -class PWFactory { - public: - ~PWFactory() = default; - static PWFactory& instance() { - static PWFactory instance_; - return instance_; - } - - PWMapFact& pw_fact(); - void set_pw_fact(PWMapFactPtr pw_fact); - - private: - PWFactory(); - PWMapFactPtr pw_fact_; -}; - - - -} // namespace LIB - -} // namespace SBG - -#endif diff --git a/sbg/pwmap_impl.cpp b/sbg/pwmap_impl.cpp new file mode 100644 index 00000000..3a7f860d --- /dev/null +++ b/sbg/pwmap_impl.cpp @@ -0,0 +1,75 @@ +/******************************************************************************* + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "sbg/pwmap_impl.hpp" +#include "util/debug.hpp" + +namespace SBG { + +namespace LIB { + +//////////////////////////////////////////////////////////////////////////////// +// PWMap implementations ------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +std::ostream& operator<<(std::ostream& out, PWMapKind kind) +{ + switch (kind) { + case PWMapKind::kUnordered: { + out << "unordered"; + break; + } + + case PWMapKind::kOrdered: { + out << "ordered"; + break; + } + + case PWMapKind::kDomOrdered: { + out << "domain ordered"; + break; + } + + default: { + Util::ERROR("Unsupported ", kind, " implementation\n"); + break; + } + } + + return out; +} + +PWMapImplementation::PWMapImplementation() : _kind(PWMapKind::kUnordered) {} + +PWMapImplementation& PWMapImplementation::instance() +{ + static PWMapImplementation _instance; + return _instance; +} + +const PWMapKind& PWMapImplementation::kind() const { return _kind; } + +void PWMapImplementation::set_pwmap_fact(PWMapKind kind) +{ + _kind = kind; +} + +} // namespace LIB + +} // namespace SBG diff --git a/sbg/pwmap_impl.hpp b/sbg/pwmap_impl.hpp new file mode 100644 index 00000000..5d18c687 --- /dev/null +++ b/sbg/pwmap_impl.hpp @@ -0,0 +1,65 @@ +/** @file pwmap_impl.hpp + + @brief PWMap Implementation + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_SBG_PWMAP_IMPL_HPP_ +#define SBGRAPH_SBG_PWMAP_IMPL_HPP_ + +#include + +namespace SBG { + +namespace LIB { + +//////////////////////////////////////////////////////////////////////////////// +// PWMap implementations ------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +enum class PWMapKind { kUnordered, kOrdered, kDomOrdered }; + +std::ostream& operator<<(std::ostream& out, PWMapKind kind); + +#define PWMAP_IMPL PWMapImplementation::instance() + +/** + * @brief Singleton that keeps record of the chosen PWMap implementation. + */ +class PWMapImplementation { +public: + ~PWMapImplementation() = default; + + static PWMapImplementation& instance(); + + const PWMapKind& kind() const; + void set_pwmap_fact(PWMapKind kind); + +private: + PWMapImplementation(); + + PWMapKind _kind; +}; + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_SBG_PWMAP_IMPL_HPP_ diff --git a/sbg/rational.cpp b/sbg/rational.cpp index dbb1ba20..40a8b87b 100755 --- a/sbg/rational.cpp +++ b/sbg/rational.cpp @@ -19,156 +19,133 @@ #include "sbg/rational.hpp" +#include + namespace SBG { namespace LIB { -RATIONAL::RATIONAL() : value_() {} -RATIONAL::RATIONAL(NAT n) : value_(RatType(n, 1)) {} -RATIONAL::RATIONAL(const RatType &value) : value_(value) {} -RATIONAL::RATIONAL(INT n, INT d) : value_() { - boost::rational v(n, d); - value_ = v; -} +// Constructors/Destructors ---------------------------------------------------- -member_imp(RATIONAL, RatType, value); +RATIONAL::RATIONAL() : _value() {} -bool RATIONAL::operator==(const RATIONAL &r) const -{ - return value_ == r.value_; -} +RATIONAL::RATIONAL(INT n) : _value(RATIONAL::RATIONALT{n, 1}) {} -bool RATIONAL::operator!=(const RATIONAL &r) const -{ - return value_ != r.value_; -} +RATIONAL::RATIONAL(const RATIONAL::RATIONALT& value) : _value(value) {} -bool RATIONAL::operator<(const RATIONAL &r) const +RATIONAL::RATIONAL(INT n, INT d) : _value() { - return value_ < r.value_; + boost::rational v{n, d}; + _value = v; } -bool RATIONAL::operator>(const RATIONAL &r) const -{ - return value_ > r.value_; -} +// Getters --------------------------------------------------------------------- -bool RATIONAL::operator>=(const RATIONAL &r) const +const RATIONAL::RATIONALT& RATIONAL::value() const { return _value; } + +INT RATIONAL::numerator() const { return _value.numerator(); } + +INT RATIONAL::denominator() const { return _value.denominator(); } + +// Operators ------------------------------------------------------------------- + +bool RATIONAL::operator==(const RATIONAL& r) const { - return value_ >= r.value_; + return _value == r._value; } -bool RATIONAL::operator==(const INT &other) const +bool RATIONAL::operator!=(const RATIONAL& r) const { - RATIONAL aux = *this; - return aux.numerator() == other && aux.denominator() == 1; + return _value != r._value; } -RATIONAL RATIONAL::operator-() const +bool RATIONAL::operator<(const RATIONAL& r) const { - return RATIONAL(-numerator(), denominator()); + return _value < r._value; } -RATIONAL RATIONAL::operator+=(const RATIONAL &other) const +bool RATIONAL::operator>(const RATIONAL& r) const { - RatType value_res = value_; - - value_res += other.value_; - - return RATIONAL(value_res); + return _value > r._value; } -RATIONAL RATIONAL::operator+(const RATIONAL &other) const +bool RATIONAL::operator>=(const RATIONAL& r) const { - return *this += other; + return _value >= r._value; } -RATIONAL RATIONAL::operator-=(const RATIONAL &other) const +bool RATIONAL::operator==(const INT& other) const { - RatType value_res = value_; - - value_res -= other.value_; - - return RATIONAL(value_res); + return numerator() == other && denominator() == 1; } -RATIONAL RATIONAL::operator-(const RATIONAL &other) const +RATIONAL RATIONAL::operator-() const { - return *this -= other; + return RATIONAL{-_value}; } -RATIONAL RATIONAL::operator*=(const RATIONAL &other) const +RATIONAL RATIONAL::operator+(const RATIONAL& other) const { - RatType value_res = value_; - - value_res *= other.value_; - - return RATIONAL(value_res); + return RATIONAL{_value + other._value}; } -RATIONAL RATIONAL::operator*(const RATIONAL &other) const +RATIONAL RATIONAL::operator-(const RATIONAL& other) const { - return *this *= other; + return RATIONAL{_value - other._value}; } -RATIONAL RATIONAL::operator/=(const RATIONAL &other) const +RATIONAL RATIONAL::operator*(const RATIONAL& other) const { - RatType value_res = value_; - - value_res /= other.value_; - - return RATIONAL(value_res); + return RATIONAL{_value*other._value}; } -RATIONAL RATIONAL::operator/(const RATIONAL &other) const +RATIONAL RATIONAL::operator/(const RATIONAL& other) const { - return *this /= other; + return RATIONAL{_value/other._value}; } -INT RATIONAL::numerator() const { return value_.numerator(); } - -INT RATIONAL::denominator() const { return value_.denominator(); } +// Extra operations ------------------------------------------------------------ NAT RATIONAL::toNat() const { - if (denominator() == 1 && 0 <= value_) + if (denominator() == 1 && 0 <= _value) { return numerator(); - + } return 0; } INT RATIONAL::toInt() const { - if (denominator() == 1) + if (denominator() == 1) { return numerator(); - + } return 0; } INT RATIONAL::floor() const { - return boost::rational_cast(value_); + return boost::rational_cast(_value); } INT RATIONAL::ceiling() const { - INT trunc = boost::rational_cast(value_); - return value_ == trunc ? trunc : trunc + 1; + INT trunc = boost::rational_cast(_value); + return _value == trunc ? trunc : trunc + 1; } -std::ostream &operator<<(std::ostream &out, const RATIONAL &r) +std::ostream& operator<<(std::ostream& out, const RATIONAL& r) { - RatType rv = r.value(); + RATIONAL::RATIONALT rv = r.value(); INT num = rv.numerator(), den = rv.denominator(); if (num == 0) { out << "0"; return out; } - out << num; - if (den != 1) + if (den != 1) { out << "/" << den; + } return out; } diff --git a/sbg/rational.hpp b/sbg/rational.hpp index ee47a073..5e0f9314 100755 --- a/sbg/rational.hpp +++ b/sbg/rational.hpp @@ -21,12 +21,15 @@ ******************************************************************************/ -#ifndef SBG_RAT_HPP -#define SBG_RAT_HPP +#ifndef SBGRAPH_SBG_RATIONAL_HPP_ +#define SBGRAPH_SBG_RATIONAL_HPP_ + +#include "sbg/natural.hpp" #include -#include "sbg/natural.hpp" +#include +#include namespace SBG { @@ -40,16 +43,15 @@ namespace LIB { * * @brief Integers implementation, used in rationals definition. */ -typedef long long int INT; -const INT INT_Inf = std::numeric_limits::max(); - -typedef boost::rational RatType; +using INT = long long int; +constexpr INT INT_Inf = std::numeric_limits::max(); /** * @brief Used as coefficients and slopes in linear expressions. */ class RATIONAL { - member_class(RatType, value); +public: + using RATIONALT = boost::rational; /** * @brief Zero constructor. @@ -59,46 +61,52 @@ class RATIONAL { /** * @brief Construct rational r = n/1. */ - RATIONAL(NAT n); + RATIONAL(INT n); /** * @brief Copy constructor. */ - RATIONAL(const RatType &value); + RATIONAL(const RATIONALT& value); /** * @brief Construct rational r = n/d. */ RATIONAL(INT n, INT d); - bool operator==(const RATIONAL &other) const; - bool operator!=(const RATIONAL &other) const; - bool operator<(const RATIONAL &other) const; - bool operator>(const RATIONAL &other) const; + RATIONAL(const RATIONAL& r) = default; + RATIONAL(RATIONAL&& r) = default; + + const RATIONALT& value() const; + INT numerator() const; + INT denominator() const; + + RATIONAL& operator=(const RATIONAL& other) = default; + RATIONAL& operator=(RATIONAL&& other) = default; + bool operator==(const RATIONAL& other) const; + bool operator!=(const RATIONAL& other) const; + bool operator<(const RATIONAL& other) const; + bool operator>(const RATIONAL& other) const; bool operator>=(const RATIONAL& other) const; - bool operator==(const INT &other) const; + bool operator==(const INT& other) const; RATIONAL operator-() const; - RATIONAL operator+=(const RATIONAL &other) const; - RATIONAL operator+(const RATIONAL &other) const; - RATIONAL operator-=(const RATIONAL &other) const; - RATIONAL operator-(const RATIONAL &other) const; - RATIONAL operator*=(const RATIONAL &other) const; - RATIONAL operator*(const RATIONAL &other) const; - RATIONAL operator/=(const RATIONAL &other) const; - RATIONAL operator/(const RATIONAL &other) const; + RATIONAL operator+(const RATIONAL& other) const; + RATIONAL operator-(const RATIONAL& other) const; + RATIONAL operator*(const RATIONAL& other) const; + RATIONAL operator/(const RATIONAL& other) const; - INT numerator() const; - INT denominator() const; NAT toNat() const; INT toInt() const; INT floor() const; INT ceiling() const; + +private: + RATIONALT _value; }; -std::ostream &operator<<(std::ostream &out, const RATIONAL &r); +std::ostream& operator<<(std::ostream& out, const RATIONAL& r); } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_RATIONAL_HPP_ diff --git a/sbg/sbg.cpp b/sbg/sbg.cpp index 1cd89770..53950b83 100644 --- a/sbg/sbg.cpp +++ b/sbg/sbg.cpp @@ -17,7 +17,11 @@ ******************************************************************************/ +#include "sbg/natural.hpp" #include "sbg/sbg.hpp" +#include "util/debug.hpp" + +#include namespace SBG { @@ -27,16 +31,18 @@ namespace LIB { // SBG ------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// +// Constructors/Destructors ---------------------------------------------------- + SBG::SBG() - : _V(SET_FACT.createSet()), _Vmap(PW_FACT.createPWMap()) - , _E(SET_FACT.createSet()), _map1(PW_FACT.createPWMap()) - , _map2(PW_FACT.createPWMap()), _Emap(PW_FACT.createPWMap()) - , _subEmap(PW_FACT.createPWMap()) {} + : _V(), _Vmap(), _E(), _map1(), _map2(), _Emap() {} + SBG::SBG(const Set& V, const PWMap& Vmap , const PWMap& map1, const PWMap& map2 - , const PWMap& Emap, const PWMap& subEmap) - : _V(V), _Vmap(Vmap), _E(map1.dom().intersection(map2.dom())) - , _map1(map1), _map2(map2), _Emap(Emap), _subEmap(subEmap) {} + , const PWMap& Emap) + : _V(V), _Vmap(Vmap), _E(map1.domain().intersection(map2.domain())) + , _map1(map1), _map2(map2), _Emap(Emap) {} + +// Getters --------------------------------------------------------------------- const Set& SBG::V() const { return _V; } @@ -50,21 +56,51 @@ const PWMap& SBG::map2() const { return _map2; } const PWMap& SBG::Emap() const { return _Emap; } -const PWMap& SBG::subEmap() const { return _subEmap; } +// Setters --------------------------------------------------------------------- -SBG& SBG::operator=(const SBG& other) +void SBG::addSetVertex(const Set& vertices) { - _V = other._V; - _Vmap = other._Vmap; - _E = other._E; - _map1 = other._map1; - _map2 = other._map2; - _Emap = other._Emap; - _subEmap = other._subEmap; - - return *this; + if (!vertices.intersection(_V).isEmpty()) { + Util::ERROR("SBG::addSetVertex: trying to add existing vertices: ", vertices + , " to SBG\n"); + } else if (!vertices.isEmpty()) { + _V = std::move(_V).cup(vertices); + Set set_vertices = _Vmap.image(); + std::size_t arity = vertices.arity(); + MD_NAT max = set_vertices.isEmpty() ? MD_NAT{arity, 0} + : set_vertices.maxElem(); + MD_NAT one_all_dims{arity, 1}; + _Vmap.emplace(vertices, max + one_all_dims); + } } +void SBG::addSetEdge(const PWMap& pw1, const PWMap& pw2) +{ + Set edges1 = pw1.domain(); + Set edges2 = pw2.domain(); + if (edges1 != edges2) { + Util::ERROR("SBG::addSetEdge: ", edges1, " is different from ", edges2 + , "\n"); + } else if (edges1.intersection(_E).isEmpty()) { + Set edges = edges1; + if (!edges.isEmpty()) { + _E = std::move(_E).cup(std::move(edges)); + Set set_edges = _Emap.image(); + std::size_t arity = edges.arity(); + MD_NAT max = set_edges.isEmpty() ? MD_NAT(arity, 0) : set_edges.maxElem(); + MD_NAT one_all_dims{arity, 1}; + _map1 = std::move(_map1).concatenation(pw1); + _map2 = std::move(_map2).concatenation(pw2); + _Emap.emplace(edges, max + one_all_dims); + } + } else { + Util::ERROR("SBG::addSetEdge: trying to add existing edges: ", edges1 + , " to SBG\n"); + } +} + +// Operators ------------------------------------------------------------------- + std::ostream& operator<<(std::ostream& out, const SBG& g) { out << "V: " << g.V() << "\n"; @@ -73,102 +109,10 @@ std::ostream& operator<<(std::ostream& out, const SBG& g) out << "map1: " << g.map1() << "\n"; out << "map2: " << g.map2() << "\n"; out << "Emap: " << g.Emap() << "\n"; - out << "subEmap: " << g.subEmap() << "\n"; return out; } -void SBG::addSV(const Set& vertices) -{ - if (!vertices.intersection(_V).isEmpty()) { - Util::ERROR("Trying to add existing vertices: ", vertices, " to SBG\n"); - } else if (!vertices.isEmpty() && vertices.intersection(_V).isEmpty()) { - _V = _V.cup(vertices); - Set SV = _Vmap.image(); - std::size_t dims = vertices.arity(); - MD_NAT max = SV.isEmpty() ? MD_NAT(dims, 0) : SV.maxElem(); - for (unsigned int j = 0; j < dims; ++j) { - max[j] = max[j] + 1; - } - _Vmap.emplaceBack(Map(vertices, Exp(max))); - - } -} - -void SBG::addSE(const PWMap& pw1, const PWMap& pw2) -{ - Set edges = SET_FACT.createSet(), edges1 = pw1.dom(), edges2 = pw2.dom(); - if (!edges.intersection(_E).isEmpty()) { - Util::ERROR("Trying to add existing edges: ", edges, " to SBG\n"); - } - else if (edges1 == edges2) { - edges = edges1; - if (!edges.isEmpty() && edges.intersection(_E).isEmpty()) { - Set SE = _Emap.image(); - std::size_t dims = edges.arity(); - MD_NAT max = SE.isEmpty() ? MD_NAT(dims, 0) : SE.maxElem(); - for (unsigned int j = 0; j < dims; ++j) { - max[j] = max[j] + 1; - } - _map1 = _map1.concatenation(pw1); - _map2 = _map2.concatenation(pw2); - _Emap.emplaceBack(Map(edges, max)); - } - } -} - -SBG SBG::copy(unsigned int times) const -{ - Set ith_V = _V, new_V = ith_V; - PWMap ith_Vmap = _Vmap, new_Vmap = ith_Vmap; - PWMap ith_map1 = _map1, new_map1 = ith_map1; - PWMap ith_map2 = _map2, new_map2 = ith_map2; - PWMap ith_Emap = _Emap, new_Emap = ith_Emap; - PWMap ith_subE = _subEmap, new_subE = ith_subE; - - if (!ith_V.isEmpty()) { - MD_NAT maxv = ith_V.maxElem(); - auto dims = maxv.arity(); - MD_NAT maxV - = ith_Vmap.isEmpty() ? MD_NAT(dims, 0) : ith_Vmap.image().maxElem(); - MD_NAT maxe = _E.isEmpty() ? MD_NAT(dims, 0) : _E.maxElem(); - MD_NAT maxE - = ith_Emap.isEmpty() ? MD_NAT(dims, 0) : ith_Emap.image().maxElem(); - - Exp off; - for (unsigned int j = 0; j < dims; ++j) { - RATIONAL o = RATIONAL(maxv[j]) - RATIONAL(maxe[j]); - off.emplaceBack(LExp(0, o)); - } - - for (unsigned int j = 0; j < times; ++j) { - if (j > 0) { - new_V = new_V.disjointCup(ith_V); - new_Vmap = new_Vmap.concatenation(ith_Vmap); - new_map1 = new_map1.concatenation(ith_map1); - new_map2 = new_map2.concatenation(ith_map2); - new_Emap = new_Emap.concatenation(ith_Emap); - new_subE = new_subE.concatenation(ith_subE); - } - - ith_V = ith_V.offset(maxv); - ith_Vmap = ith_Vmap.offsetDom(maxv); - ith_Vmap = ith_Vmap.offsetImage(maxV); - - ith_map1 = ith_map1.offsetDom(maxe); - ith_map1 = ith_map1.offsetImage(off); - ith_map2 = ith_map2.offsetDom(maxe); - ith_map2 = ith_map2.offsetImage(off); - ith_Emap = ith_Emap.offsetDom(maxe); - ith_Emap = ith_Emap.offsetImage(maxE); - ith_subE = ith_subE.offsetDom(maxe); - ith_subE = ith_subE.offsetImage(maxE); - } - } - - return SBG(new_V, new_Vmap, new_map1, new_map2, new_Emap, new_subE); -} - } // namespace LIB } // namespace SBG diff --git a/sbg/sbg.hpp b/sbg/sbg.hpp index 73b1d010..5a149ae1 100644 --- a/sbg/sbg.hpp +++ b/sbg/sbg.hpp @@ -14,8 +14,6 @@ share the same image conform a *Set-Vertex*. - A PWMap Emap_ mapping elements in E_ to some constant value. Edges that share the same image conform a *Set-Edge*. - - A PWMap subEmap_ mapping elements in E_ to some constant value. Edges that - share the same image conform a *Subset-Edge*.\n These components are added to keep track of repetitve structures in G. Note that a Set-Edge might be composed by several Subset-Edges. @@ -38,11 +36,13 @@ ******************************************************************************/ -#ifndef SBG_SBG_HPP -#define SBG_SBG_HPP +#ifndef SBGRAPH_SBG_SBG_HPP_ +#define SBGRAPH_SBG_SBG_HPP_ -#include "sbg/pwmap_fact.hpp" -#include "util/debug.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/set.hpp" + +#include namespace SBG { @@ -53,7 +53,7 @@ namespace LIB { //////////////////////////////////////////////////////////////////////////////// class SBG { - public: +public: /** * @brief Empty SBG constructor. */ @@ -70,7 +70,7 @@ class SBG { */ SBG(const Set& V, const PWMap& Vmap , const PWMap& map1, const PWMap& map2 - , const PWMap& Emap, const PWMap& subEmap); + , const PWMap& Emap); const Set& V() const; const PWMap& Vmap() const; @@ -78,42 +78,64 @@ class SBG { const PWMap& map1() const; const PWMap& map2() const; const PWMap& Emap() const; - const PWMap& subEmap() const; - - SBG& operator=(const SBG& other); /** * @brief Adds a new set-vertex composed by \p vertices. \n * Precondition: V_.intersection(vertices) = {} */ - void addSV(const Set& vertices); + void addSetVertex(const Set& vertices); /** * @brief Adds a new set-edge described by \p pw1 and \p pw2. \n * Precondition: dom(pw1) = dom(pw2) and * E_.intersection(pw1.dom()) = {} and E_.intersection(pw2.dom()) = {} */ - void addSE(const PWMap& pw1, const PWMap& pw2); + void addSetEdge(const PWMap& pw1, const PWMap& pw2); - /** - * @brief Returns a new SBG composed by \p times copies of the original SBG, - * where each copy is isomorphic to the argument. - */ - SBG copy(unsigned int times) const; + template + void foreachSetVertex(FuncT&& f) const; - private: + template + void foreachSetEdge(FuncT&& f) const; + +private: Set _V; ///< Vertex definitions PWMap _Vmap; Set _E; ///< Edge definitions PWMap _map1; PWMap _map2; PWMap _Emap; - PWMap _subEmap; }; + std::ostream& operator<<(std::ostream& out, const SBG& g); +// Template definitions -------------------------------------------------------- + +template +inline void SBG::foreachSetVertex(FuncT&& f) const +{ + Set remaining = _Vmap.image(); + while (!remaining.isEmpty()) { + const MD_NAT& x = remaining.minElem(); + f(x); + remaining = remaining.difference(Set{x}); + } +} + +template +inline void SBG::foreachSetEdge(FuncT&& f) const +{ + Set remaining = _Emap.image(); + while (!remaining.isEmpty()) { + const MD_NAT& x = remaining.minElem(); + f(x); + remaining = remaining.difference(Set{x}); + } +} + + } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_SBG_HPP_ diff --git a/sbg/set.cpp b/sbg/set.cpp index f6e0ae2e..60ab2924 100644 --- a/sbg/set.cpp +++ b/sbg/set.cpp @@ -17,91 +17,171 @@ ******************************************************************************/ -#include - #include "sbg/set.hpp" +#include "sbg/set_impl.hpp" +#include "util/debug.hpp" + +#include namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Set Abstract Strategy Constructors ------------------------------------------ +// Set ------------------------------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// -SetStrategy::SetStrategy() {} -SetStrategy::SetStrategy(const MD_NAT& x) {} -SetStrategy::SetStrategy(const Interval& i) {} -SetStrategy::SetStrategy(const SetPiece& mdi) {} - -//////////////////////////////////////////////////////////////////////////////// -// Set Interface --------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -Set::Set(SetStratPtr strat) : strategy_(std::move(strat)) {} -Set::Set(const Set& other) - : strategy_(other.strategy_ ? other.strategy_->clone() : nullptr) {} - -Set::Iterator::Iterator(std::shared_ptr it) - : it_(std::move(it)) {} +// Constructors ---------------------------------------------------------------- -void Set::Iterator::operator++() +Set::Set() : _impl() { - ++(*it_); - return; + SetKind kind = SET_IMPL.kind(); + switch (kind) { + case SetKind::kUnordered: { + _impl = detail::UnorderedSet{}; + break; + } + + case SetKind::kOrdered: { + _impl = detail::OrderedSet{}; + break; + } + + case SetKind::kOrdUnidimDense: { + _impl = detail::OrdUnidimDenseSet{}; + break; + } + + default: { + Util::ERROR("Unsupported ", kind, " Set implementation\n"); + break; + } + } } -SetPiece Set::Iterator::operator*() const { return **it_; } - -bool Set::Iterator::operator!=(const Iterator& other) const { return *it_ != *other.it_; } - -bool Set::Iterator::operator==(const Iterator& other) const { return *it_ == *other.it_; } - -bool Set::Iterator::operator<(const Iterator& other) const { return it_ < other.it_; } - -Set::Iterator Set::begin() const { return strategy_->begin(); } -Set::Iterator Set::end() const { return strategy_->end(); } - -std::size_t Set::size() const { return strategy_->size(); } +Set::Set(const MD_NAT& x) : _impl() +{ + SetKind kind = SET_IMPL.kind(); + switch (kind) { + case SetKind::kUnordered: { + _impl = detail::UnorderedSet{x}; + break; + } + + case SetKind::kOrdered: { + _impl = detail::OrderedSet{x}; + break; + } + + case SetKind::kOrdUnidimDense: { + _impl = detail::OrdUnidimDenseSet{x[0]}; + break; + } + + default: { + Util::ERROR("Unsupported ", kind, " Set implementation\n"); + break; + } + } +} -void Set::emplace(SetPiece mdi) +Set::Set(MD_NAT&& x) : _impl() { - strategy_->emplace(mdi); - return; + SetKind kind = SET_IMPL.kind(); + switch (kind) { + case SetKind::kUnordered: { + _impl = detail::UnorderedSet{x}; + break; + } + + case SetKind::kOrdered: { + _impl = detail::OrderedSet{x}; + break; + } + + case SetKind::kOrdUnidimDense: { + _impl = detail::OrdUnidimDenseSet{x[0]}; + break; + } + + default: { + Util::ERROR("Unsupported ", kind, " Set implementation\n"); + break; + } + } } -void Set::emplaceBack(SetPiece mdi) +Set::Set(const NAT lo, const NAT step, const NAT hi) : _impl() { - strategy_->emplaceBack(mdi); - return; + SetKind kind = SET_IMPL.kind(); + switch (kind) { + case SetKind::kUnordered: { + _impl = detail::UnorderedSet{detail::Interval(lo, step, hi)}; + break; + } + + case SetKind::kOrdered: { + _impl = detail::OrderedSet{detail::Interval(lo, step, hi)}; + break; + } + + case SetKind::kOrdUnidimDense: { + _impl = detail::OrdUnidimDenseSet{detail::Interval(lo, step, hi)}; + break; + } + + default: { + Util::ERROR("Unsupported ", kind, " Set implementation\n"); + break; + } + } } -bool Set::operator==(const Set& other) const +Set::Set(const FixedPointsInfo& info) : _impl() { - return *strategy_ == *other.strategy_; + SetKind kind = SET_IMPL.kind(); + switch (kind) { + case SetKind::kUnordered: { + _impl = detail::UnorderedSet{info}; + break; + } + + case SetKind::kOrdered: { + _impl = detail::OrderedSet{info}; + break; + } + + case SetKind::kOrdUnidimDense: { + _impl = detail::OrdUnidimDenseSet{info}; + break; + } + + default: { + Util::ERROR("Unsupported ", kind, " Set implementation\n"); + break; + } + } } -bool Set::operator!=(const Set& other) const { return !(*this == other); } +Set::Set(const detail::SetImpl& impl) : _impl(impl) {} -Set& Set::operator=(const Set& other) -{ - if (this !=& other) - strategy_ = other.strategy_->clone(); +Set::Set(detail::SetImpl&& impl) : _impl(std::move(impl)) {} - return *this; -} +// Operators ------------------------------------------------------------------- -Set& Set::operator=(Set&& other) +bool Set::operator==(const Set& other) const { - if (this !=& other) - strategy_ = std::move(other.strategy_); + return _impl == other._impl; +} - return *this; +bool Set::operator!=(const Set& other) const +{ + return !(*this == other); } std::ostream& Set::print(std::ostream& out) const { - strategy_->print(out); + std::visit([&out](const auto& a) -> void { a.print(out); } , _impl); return out; } @@ -111,62 +191,171 @@ std::ostream& operator<<(std::ostream& out, const Set& s) return out; } -unsigned int Set::cardinal() const { return strategy_->cardinal(); } +// Set operations -------------------------------------------------------------- -bool Set::isEmpty() const { return strategy_->isEmpty(); } +unsigned int Set::cardinal() const +{ + return std::visit([](const auto& a) { return a.cardinal(); }, _impl); +} + +bool Set::isEmpty() const +{ + return std::visit([](const auto& a) { return a.isEmpty(); }, _impl); +} -MD_NAT Set::minElem() const { return strategy_->minElem(); } +MD_NAT Set::minElem() const +{ + return std::visit([](const auto& a) { return a.minElem(); }, _impl); +} -MD_NAT Set::maxElem() const { return strategy_->maxElem(); } +MD_NAT Set::maxElem() const +{ + return std::visit([](const auto& a) { return a.maxElem(); }, _impl); +} -Set Set::intersection(const Set& other) const +Set Set::intersection(const Set& other) const & { - return Set(strategy_->intersection(*other.strategy_)); + return std::visit([](const auto& a, const auto& b) + { + using A = std::decay_t; + using B = std::decay_t; + if constexpr (std::is_same_v) { + return Set{a.intersection(b)}; + } else { + Util::ERROR("Set::intersection: mismatched implementations\n"); + return Set{}; + } + } + , _impl, other._impl); } Set Set::cup(const Set& other) const & { - return Set(strategy_->cup(*other.strategy_)); + return Set{*this}.cup(other); +} + +Set Set::cup(const Set& other) && +{ + return std::move(*this).cup(Set{other}); +} + +Set Set::cup(Set&& other) const & +{ + return Set{*this}.cup(std::move(other)); } Set Set::cup(Set&& other) && { - return Set(std::move(*strategy_).cup(std::move(*other.strategy_))); + return std::visit([](auto&& a, auto&& b) + { + using A = std::decay_t; + using B = std::decay_t; + if constexpr (std::is_same_v) { + return Set{std::move(a).cup(std::move(b))}; + } else { + Util::ERROR("Set::cup: mismatched implementations\n"); + return Set{}; + } + } + , std::move(_impl), std::move(other._impl)); } Set Set::complement() const { - return Set(strategy_->complement()); + return std::visit( + [](const auto& a) -> Set { return Set{a.complement()}; } + , _impl); } Set Set::difference(const Set& other) const { - return Set(strategy_->difference(*other.strategy_)); + return std::visit([](const auto& a, const auto& b) + { + using A = std::decay_t; + using B = std::decay_t; + if constexpr (std::is_same_v) { + return Set{a.difference(b)}; + } else { + Util::ERROR("Set::difference: mismatched implementations\n"); + return Set{}; + } + } + , _impl, other._impl); +} + +Set Set::cartesianProduct(const Set& other) const +{ + return std::visit([](const auto& a, const auto& b) + { + using A = std::decay_t; + using B = std::decay_t; + if constexpr (std::is_same_v) { + return Set{a.cartesianProduct(b)}; + } else { + Util::ERROR("Set::cartesianProduct: mismatched implementations\n"); + return Set{}; + } + } + , _impl, other._impl); } -std::size_t Set::arity() const { return strategy_->arity(); } +// Extra operations ------------------------------------------------------------ + +std::size_t Set::arity() const +{ + return std::visit([](const auto& a) { return a.arity(); }, _impl); +} Set Set::disjointCup(const Set& other) const & { - return Set(strategy_->disjointCup(*other.strategy_)); + return Set{*this}.disjointCup(other); } -Set Set::disjointCup(Set&& other) && +Set Set::disjointCup(const Set& other) && { - return Set(std::move(*strategy_).disjointCup(std::move(*other.strategy_))); + return std::move(*this).disjointCup(Set{other}); } -Set Set::filterSet(bool (*f)(const SetPiece& mdi)) const +Set Set::disjointCup(Set&& other) const & +{ + return Set{*this}.disjointCup(std::move(other)); +} + +Set Set::disjointCup(Set&& other) && { - return strategy_->filterSet(f); + return std::visit([](auto&& a, auto&& b) + { + using A = std::decay_t; + using B = std::decay_t; + if constexpr (std::is_same_v) { + return Set{std::move(a).disjointCup(std::move(b))}; + } else { + Util::ERROR("Set::disjointCup: mismatched implementations\n"); + return Set{}; + } + } + , std::move(_impl), std::move(other._impl)); } Set Set::offset(const MD_NAT& off) const { - return strategy_->offset(off); + return std::visit( + [&off](const auto& a) -> Set { return Set{a.offset(off)}; } + , _impl); } -Set Set::compact() const { return strategy_->compact(); } +Perimeter Set::perimeter() const +{ + return std::visit([](const auto& a) { return a.perimeter(); }, _impl); +} + +void Set::compact() { std::visit([](auto& a) { a.compact(); }, _impl); } + +rapidjson::Value Set::toJSON(rapidjson::Document::AllocatorType& alloc) const +{ + return std::visit([&alloc](auto a) { return detail::toJSON(a, alloc); } + , _impl); +} } // namespace LIB diff --git a/sbg/set.hpp b/sbg/set.hpp index a4d2dcaa..2887c8d6 100644 --- a/sbg/set.hpp +++ b/sbg/set.hpp @@ -3,8 +3,8 @@ @brief SBG Set A SBG Set is a structure that represents sets of multi-dimensional naturals - (all with the same number of dimensions), using collections of disjoint MDIs. - Currently three implementations are supported: + (all with the same number of dimensions). + Currently three compact implementations are supported: - UnorderedSet that keeps no order, but supports multi-dimensional values. - OrderedSet that supports multi-dimensional values while also keeping an internal order that enhances performance. @@ -30,179 +30,58 @@ ******************************************************************************/ -#ifndef SBG_SET_HPP -#define SBG_SET_HPP - -#include +#ifndef SBGRAPH_SBG_SET_HPP_ +#define SBGRAPH_SBG_SET_HPP_ +#include "sbg/expression.hpp" +#include "sbg/fixed_points.hpp" +#include "sbg/interval.hpp" #include "sbg/multidim_inter.hpp" +#include "sbg/natural.hpp" +#include "sbg/ord_set.hpp" +#include "sbg/ord_unidim_dense_set.hpp" +#include "sbg/set.hpp" +#include "sbg/perimeter.hpp" +#include "sbg/unord_set.hpp" + +#include "rapidjson/document.h" + +#include +#include +#include namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// -// Set Abstract Strategy ------------------------------------------------------- +// Set implementations --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -class SetStrategy; - -typedef std::unique_ptr SetStratPtr; - -class SetStrategy { - public: - virtual ~SetStrategy() = default; - - /** - * @brief Constructs an empty set. - */ - SetStrategy(); - - /** - * @brief Constructs a set with an unique element \p x. - */ - SetStrategy(const MD_NAT& x); - - /** - * @brief Constructs a one-dimensional set with the same elements as \p i. - */ - SetStrategy(const Interval& i); - - /** - * @brief Constructs a set with the same elements as \p mdi. - */ - SetStrategy(const SetPiece& mdi); - - /** - * @brief Auxiliary function for defining the copy constructor of Set. - */ - virtual SetStratPtr clone() const = 0; - - class Iterator { - public: - virtual ~Iterator() = default; - virtual void operator++() = 0; - virtual bool operator!=(const Iterator& other) const = 0; - virtual bool operator==(const Iterator& other) const = 0; - virtual bool operator<(const Iterator& other) const = 0; - virtual const SetPiece& operator*() const = 0; - }; - - virtual std::shared_ptr begin() const = 0; - virtual std::shared_ptr end() const = 0; - - /** - * @brief Number of compact pieces in the set, i.e. - * size({[1:1:10], [20:3:50]}) = 2. - */ - virtual std::size_t size() const = 0; - - /** - * @brief Adds a compact piece to the set, traversing in forward order. - * Precondition: arguments should be disjoint. - */ - virtual void emplace(const SetPiece& mdi) = 0; - - /** - * @brief Adds a compact piece to the set, traversing in reverse order. - * Precondition: arguments should be disjoint. - */ - virtual void emplaceBack(const SetPiece& mdi) = 0; - - virtual bool operator==(const SetStrategy& other) const = 0; - virtual bool operator!=(const SetStrategy& other) const = 0; - virtual std::ostream& print(std::ostream& out) const = 0; - - // Traditional set operations ------------------------------------------------ - - /** - * @brief Number of elements contained in the set, i.e. - * cardinal({[1:1:10]x[1:1:10], [101:1:200]x[201:1:300]}) = 10100. - */ - virtual unsigned int cardinal() const = 0; - virtual bool isEmpty() const = 0; - virtual MD_NAT minElem() const = 0; - virtual MD_NAT maxElem() const = 0; - virtual SetStratPtr intersection(const SetStrategy& other) const = 0; - - /** - * @brief Calculates the union of two sets. - */ - virtual SetStratPtr cup(const SetStrategy& other) const & = 0; - virtual SetStratPtr cup(SetStrategy&& other) && = 0; - - /** - * @brief Calculates the complement of a set.\n - * Precondition: set must not be empty (undetermined arity). - */ - virtual SetStratPtr complement() const = 0; - virtual SetStratPtr difference(const SetStrategy& other) const = 0; +using SetImpl = std::variant; - // Extra operations ---------------------------------------------------------- +class SetAccessKey; - /** - * @brief Number of dimensions of the elements that compose the set. For - * example, arity([1:1:10]x[1:1:10]) = 2. - */ - virtual std::size_t arity() const = 0; - - /** - * @brief Calculates the union of two disjoint sets. \n - * Precondition: this->intersection(other) = {}. - */ - virtual SetStratPtr disjointCup(const SetStrategy& other) const & = 0; - virtual SetStratPtr disjointCup(SetStrategy&& other) && = 0; - - /** - * @brief Returns a set that keeps pieces of the original set that satisfy - * the predicate argument. - */ - virtual SetStratPtr filterSet(bool (*f)(const SetPiece& mdi)) const = 0; - - /** - * @brief Sum a constant value to every element of the set. - */ - virtual SetStratPtr offset(const MD_NAT& off) const = 0; - - /** - * @brief Merge as many pieces of the set as possible. Heuristic guided. - */ - virtual SetStratPtr compact() const = 0; -}; +} //////////////////////////////////////////////////////////////////////////////// -// Set Interface (context) ----------------------------------------------------- +// Set ------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// class Set { - public: - Set(SetStratPtr strat); - Set(const Set& other); - - class Iterator { - public: - Iterator(std::shared_ptr it); - void operator++(); - bool operator!=(const Iterator& other) const; - bool operator==(const Iterator& other) const; - bool operator<(const Iterator& other) const; - SetPiece operator*() const; - - private: - std::shared_ptr it_; - }; - - Iterator begin() const; - Iterator end() const; - - std::size_t size() const; - void emplace(SetPiece mdi); - void emplaceBack(SetPiece mdi); +public: + Set(); + Set(const MD_NAT& x); + Set(MD_NAT&& x); + Set(const NAT lo, const NAT st, const NAT hi); + Set(const FixedPointsInfo& info); bool operator==(const Set& other) const; bool operator!=(const Set& other) const; - Set& operator=(const Set& other); - Set& operator=(Set&& other); std::ostream& print(std::ostream& out) const; // Traditional set operations ------------------------------------------------ @@ -211,28 +90,40 @@ class Set { bool isEmpty() const; MD_NAT minElem() const; MD_NAT maxElem() const; - Set intersection(const Set& other) const; + Set intersection(const Set& other) const &; Set cup(const Set& other) const &; + Set cup(const Set& other) &&; + Set cup(Set&& other) const &; Set cup(Set&& other) &&; Set complement() const; Set difference(const Set& other) const; + Set cartesianProduct(const Set& other) const; // Extra operations ---------------------------------------------------------- std::size_t arity() const; Set disjointCup(const Set& other) const &; + Set disjointCup(const Set& other) &&; + Set disjointCup(Set&& other) const &; Set disjointCup(Set&& other) &&; - Set filterSet(bool (*f)(const SetPiece& mdi)) const; Set offset(const MD_NAT& off) const; - Set compact() const; + Perimeter perimeter() const; + void compact(); + rapidjson::Value toJSON(rapidjson::Document::AllocatorType& alloc) const; - private: - SetStratPtr strategy_; +private: + Set(const detail::SetImpl& impl); + Set(detail::SetImpl&& impl); + + detail::SetImpl _impl; + + friend class detail::SetAccessKey; }; + std::ostream& operator<<(std::ostream& out, const Set& s); -} // namespace LIB +} // namespace lib -} // namespace SBG +} // namespace sbg -#endif +#endif // SBGRAPH_SBG_SET_HPP_ diff --git a/sbg/set_detail.cpp b/sbg/set_detail.cpp new file mode 100755 index 00000000..62e84c00 --- /dev/null +++ b/sbg/set_detail.cpp @@ -0,0 +1,114 @@ +/******************************************************************************* + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "sbg/set_detail.hpp" +#include "util/defs.hpp" + +#include + +namespace SBG { + +namespace LIB { + +namespace detail { + +// SetAccessKey ---------------------------------------------------------------- + +SetImpl SetAccessKey::impl(Set s) const { return s._impl; } + +Set SetAccessKey::createSet(SetImpl s_impl) const { return Set{s_impl}; } + +template +std::vector SetAccessKey::flatten(const SetImplT& s) const +{ + std::vector result; + auto pieces = s._pieces; + result.reserve(pieces.size()); + + std::size_t arity = s.arity(); + for (const MultiDimInter& mdi : pieces) { + MD_NAT min_elem = mdi.minElem(); + MD_NAT x = min_elem; + unsigned int mdi_sz = mdi.cardinal(); + unsigned int div = mdi_sz; + for (unsigned int j = 0; j < mdi_sz; ++j) { + unsigned int rem = j; + for (std::size_t k = arity; k > 0; --k) { + Interval i = mdi[k-1]; + unsigned int kth_card = i.cardinal(); + x[k] = i.begin() + i.step()*fmod(rem, kth_card); + rem /= kth_card; + } + } + } + + return result; +} + +std::vector SetAccessKey::flatten(const OrdUnidimDenseSet& s) const +{ + std::vector result; + + for (const Interval& i : s._pieces) { + for (NAT j = i.begin(); j <= i.end(); j += i.step()) { + result.emplace_back(j); + } + } + + return result; +} + +std::vector SetAccessKey::flatten(const Set& s) const +{ + auto flatten_evaluator = Util::Overload { + [&](const UnorderedSet& a) + { + return flatten(a); + }, + [&](const OrdUnidimDenseSet& a) + { + return flatten(a); + }, + [&](const OrderedSet& a) + { + return flatten(a); + }, + [&](const auto& a) { return std::vector{}; } + }; + return std::visit(flatten_evaluator, s._impl); +} + +OrderedSet::OrdMDICollection SetAccessKey::pieces(OrderedSet s) const +{ + return s._pieces; +} + +OrdUnidimDenseSet::OrdIntervalCollection SetAccessKey::pieces( + OrdUnidimDenseSet s) const +{ + return s._pieces; +} + +SetAccessKey SetAccess::key() { return SetAccessKey{}; }; + +} // namespace detail + +} // namespace LIB + +} // namespace SBG diff --git a/sbg/set_detail.hpp b/sbg/set_detail.hpp new file mode 100755 index 00000000..e9825466 --- /dev/null +++ b/sbg/set_detail.hpp @@ -0,0 +1,74 @@ +/** @file set_detail.hpp + + @brief PWMap implementation access + + This module is intended for internal use to access the implementation of + Sets, for example for the DomOrdPWMap implementation. + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_SBG_SET_DETAIL_HPP_ +#define SBGRAPH_SBG_SET_DETAIL_HPP_ + +#include "sbg/set.hpp" +#include "sbg/ord_set.hpp" +#include "sbg/ord_unidim_dense_set.hpp" + +#include + +namespace SBG { + +namespace LIB { + +namespace detail { + +using MaybeMD_NAT = std::optional; + +class SetAccessKey { +public: + SetImpl impl(Set s) const; + Set createSet(SetImpl s_impl) const; + std::vector flatten(const Set& s) const; + + OrderedSet::OrdMDICollection pieces(OrderedSet s) const; + OrdUnidimDenseSet::OrdIntervalCollection pieces(OrdUnidimDenseSet s) const; + +private: + SetAccessKey() = default; + + template + std::vector flatten(const SetImplT& s) const; + std::vector flatten(const OrdUnidimDenseSet& s) const; + + friend class SetAccess; +}; + +class SetAccess { +public: + static SetAccessKey key(); +}; + +} // namespace detail + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_SBG_SET_DETAIL_HPP_ diff --git a/sbg/set_fact.cpp b/sbg/set_fact.cpp deleted file mode 100644 index 975eb89a..00000000 --- a/sbg/set_fact.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/******************************************************************************* - - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -#include "sbg/set_fact.hpp" -#include "sbg/ord_set.hpp" -#include "sbg/ord_unidim_dense_set.hpp" -#include "sbg/unord_set.hpp" - -namespace SBG { - -namespace LIB { - -//////////////////////////////////////////////////////////////////////////////// -// Unordered Set Factory ------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -Set UnordSetFact::createSet() const -{ - return Set(std::make_unique()); -} - -Set UnordSetFact::createSet(const MD_NAT &x) const -{ - return Set(std::make_unique(x)); -} - -Set UnordSetFact::createSet(const Interval &i) const -{ - return Set(std::make_unique(i)); -} - -Set UnordSetFact::createSet(const SetPiece &mdi) const -{ - return Set(std::make_unique(mdi)); -} - -std::string UnordSetFact::prettyPrint() const -{ - return "unordered"; -} - -//////////////////////////////////////////////////////////////////////////////// -// Ordered Unidimensional Dense Set Factory ------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -Set OrdUnidimDenseSetFact::createSet() const -{ - return Set(std::make_unique()); -} - -Set OrdUnidimDenseSetFact::createSet(const MD_NAT &x) const -{ - return Set(std::make_unique(x)); -} - -Set OrdUnidimDenseSetFact::createSet(const Interval &i) const -{ - return Set(std::make_unique(i)); -} - -Set OrdUnidimDenseSetFact::createSet(const SetPiece &mdi) const -{ - return Set(std::make_unique(mdi)); -} - -std::string OrdUnidimDenseSetFact::prettyPrint() const -{ - return "ordered unidimensional dense"; -} - -//////////////////////////////////////////////////////////////////////////////// -// Ordered Set Factory --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -Set OrdSetFact::createSet() const -{ - return Set(std::make_unique()); -} - -Set OrdSetFact::createSet(const MD_NAT &x) const -{ - return Set(std::make_unique(x)); -} - -Set OrdSetFact::createSet(const Interval &i) const -{ - return Set(std::make_unique(i)); -} - -Set OrdSetFact::createSet(const SetPiece &mdi) const -{ - return Set(std::make_unique(mdi)); -} - -std::string OrdSetFact::prettyPrint() const -{ - return "ordered"; -} - -//////////////////////////////////////////////////////////////////////////////// -// Factory for clients --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -SetFactory::SetFactory() : set_fact_(std::make_unique()) {} - -SetFact& SetFactory::set_fact() -{ - return *set_fact_; -} - -void SetFactory::set_set_fact(SetFactPtr set_fact) -{ - set_fact_ = std::move(set_fact); -} - -} // namespace LIB - -} // namespace SBG diff --git a/sbg/set_fact.hpp b/sbg/set_fact.hpp deleted file mode 100644 index b769b6ad..00000000 --- a/sbg/set_fact.hpp +++ /dev/null @@ -1,104 +0,0 @@ -/** @file set_fact.hpp - - @brief Set Factory - - As other structures will have to create SBG Sets (i.e., Maps and PWMaps), it - is necessary to have a way to create SBG Sets objects with the desired - implementation. This module provides a factory to such purpose. - -
- - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -#ifndef SBG_SET_FACT_HPP -#define SBG_SET_FACT_HPP - -#include "set.hpp" - -namespace SBG { - -namespace LIB { - -#define SET_FACT SetFactory::instance().set_fact() - -class SetFact { - public: - virtual ~SetFact() = default; - - virtual Set createSet() const = 0; - virtual Set createSet(const MD_NAT &x) const = 0; - virtual Set createSet(const Interval &i) const = 0; - virtual Set createSet(const SetPiece &mdi) const = 0; - virtual std::string prettyPrint() const = 0; -}; - -class UnordSetFact : public SetFact { - public: - Set createSet() const override; - Set createSet(const MD_NAT &x) const override; - Set createSet(const Interval &i) const override; - Set createSet(const SetPiece &mdi) const override; - std::string prettyPrint() const override; -}; - -class OrdUnidimDenseSetFact : public SetFact { - public: - Set createSet() const override; - Set createSet(const MD_NAT &x) const override; - Set createSet(const Interval &i) const override; - Set createSet(const SetPiece &mdi) const override; - std::string prettyPrint() const override; -}; - -class OrdSetFact : public SetFact { - public: - Set createSet() const override; - Set createSet(const MD_NAT &x) const override; - Set createSet(const Interval &i) const override; - Set createSet(const SetPiece &mdi) const override; - std::string prettyPrint() const override; -}; - -using SetFactPtr = std::unique_ptr; - -/** - * @brief Single instance of set factory to be used by clients in need of - * creating sets. A client includes this file and calls - * SET_FACT.createSet(args). - */ -class SetFactory { - public: - ~SetFactory() = default; - static SetFactory& instance() { - static SetFactory instance_; - return instance_; - } - - SetFact& set_fact(); - void set_set_fact(SetFactPtr set_fact); - - private: - SetFactory(); - SetFactPtr set_fact_; -}; - -} // namespace LIB - -} // namespace SBG - -#endif diff --git a/sbg/set_impl.cpp b/sbg/set_impl.cpp new file mode 100644 index 00000000..22b08683 --- /dev/null +++ b/sbg/set_impl.cpp @@ -0,0 +1,72 @@ +/******************************************************************************* + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "sbg/set_impl.hpp" +#include "util/debug.hpp" + +namespace SBG { + +namespace LIB { + +//////////////////////////////////////////////////////////////////////////////// +// Set implementations --------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +std::ostream& operator<<(std::ostream& out, const SetKind kind) +{ + switch (kind) { + case SetKind::kUnordered: { + out << "unordered"; + break; + } + + case SetKind::kOrdered: { + out << "ordered"; + break; + } + + case SetKind::kOrdUnidimDense: { + out << "uni-dimensional ordered dense"; + break; + } + + default: { + Util::ERROR("Unsupported ", kind, " Set implementation\n"); + break; + } + } + + return out; +} + +SetImplementation::SetImplementation() : _kind(SetKind::kUnordered) {} + +SetImplementation& SetImplementation::instance() +{ + static SetImplementation _instance; + return _instance; +} + +const SetKind& SetImplementation::kind() const { return _kind; } + +void SetImplementation::set_set_fact(SetKind kind) { _kind = kind; } + +} // namespace LIB + +} // namespace SBG diff --git a/sbg/set_impl.hpp b/sbg/set_impl.hpp new file mode 100644 index 00000000..4a7a8457 --- /dev/null +++ b/sbg/set_impl.hpp @@ -0,0 +1,68 @@ +/** @file set_impl.hpp + + @brief Set Implementation + + As other structures will have to create SBG Sets (i.e., Maps and PWMaps), this + structure keeps track of the desired Set implementation. + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_SBG_SET_IMPL_HPP_ +#define SBGRAPH_SBG_SET_IMPL_HPP_ + +#include + +namespace SBG { + +namespace LIB { + +//////////////////////////////////////////////////////////////////////////////// +// Set implementations --------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +enum class SetKind { kUnordered, kOrdered, kOrdUnidimDense }; + +std::ostream& operator<<(std::ostream& out, const SetKind kind); + +#define SET_IMPL SetImplementation::instance() + +/** + * @brief Singleton that keeps record of the chosen set implementation. + */ +class SetImplementation { +public: + ~SetImplementation() = default; + + static SetImplementation& instance(); + + void set_set_fact(SetKind kind); + const SetKind& kind() const; + +private: + SetImplementation(); + + SetKind _kind; +}; + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_SBG_SET_IMPL_HPP_ diff --git a/sbg/unord_pwmap.cpp b/sbg/unord_pwmap.cpp index 1a23080d..ddc61023 100644 --- a/sbg/unord_pwmap.cpp +++ b/sbg/unord_pwmap.cpp @@ -17,102 +17,114 @@ ******************************************************************************/ -#include - #include "sbg/unord_pwmap.hpp" +#include +#include +#include +#include + namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // Unordered PWMap Implementation ---------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -// Auxiliary functions - Unordered Piecewise maps ------------------------------ +// Auxiliary definitions ------------------------------------------------------- -void pushBack(UnordPWMap::UnordMapCollection& unord_pw, const Map& m) -{ - unord_pw.emplace_back(m); -} +class MapLess { +public: + bool operator()(const Map& a, const Map& b) const { + return a.domain().minElem() < b.domain().minElem(); + } +}; -// Member functions - Unordered Piecewise maps --------------------------------- +// Constructors/Destructors ---------------------------------------------------- -member_imp(UnordPWMap, UnordPWMap::UnordMapCollection, pieces); +UnordPWMap::UnordPWMap() : _pieces() {} -UnordPWMap::UnordPWMap() {} -UnordPWMap::UnordPWMap(const Set& s) : pieces_() { +UnordPWMap::UnordPWMap(const Set& s) : _pieces() { if (!s.isEmpty()) { - SetPiece first = s.begin().operator*(); - pieces_.push_back(Map(s, Exp(first.arity(), LExp()))); + _pieces.emplace_back(s, Expression{s.arity(), 1, 0}); } } -UnordPWMap::UnordPWMap(const Map& m) : pieces_() { - if (!m.dom().isEmpty()) - pieces_.push_back(m); + +UnordPWMap::UnordPWMap(const Map& m) : _pieces() { + if (!m.domain().isEmpty()) { + _pieces.push_back(m); + } } + UnordPWMap::UnordPWMap(const UnordPWMap::UnordMapCollection& pieces) - : pieces_(std::move(pieces)) {} + : _pieces(pieces) {} -member_imp(UnordPWMap::Iterator, UnordPWMap::UnordMapCollection::const_iterator - , it); +UnordPWMap::UnordPWMap(UnordPWMap::UnordMapCollection&& pieces) + : _pieces(std::move(pieces)) {} -UnordPWMap::Iterator::Iterator(UnordMapCollection::const_iterator it) - : it_(it) {} +// Getters --------------------------------------------------------------------- -void UnordPWMap::Iterator::operator++() -{ - ++it_; - return; -} +UnordPWMap::ConstIt UnordPWMap::begin() const { return _pieces.begin(); } -bool UnordPWMap::Iterator::operator!=(const PWMapStrategy::Iterator& other) - const -{ - return it_ != static_cast(&other)->it_; -} +UnordPWMap::ConstIt UnordPWMap::end() const { return _pieces.end(); } -const Map& UnordPWMap::Iterator::operator*() const { return *it_; } +// Setters --------------------------------------------------------------------- -std::shared_ptr UnordPWMap::begin() const +void UnordPWMap::insert(const Map& m) { - return std::make_shared(pieces_.begin()); + if (!m.isEmpty()) { + _pieces.push_back(m); + } } -std::shared_ptr UnordPWMap::end() const +void UnordPWMap::insert(Map&& m) { - return std::make_shared(pieces_.end()); + if (!m.isEmpty()) { + _pieces.push_back(std::move(m)); + } } -void UnordPWMap::emplaceBack(const Map& m) +void UnordPWMap::pushBack(const Map& m) { if (!m.isEmpty()) { - pieces_.emplace_back(m); + _pieces.push_back(m); } } -bool UnordPWMap::operator==(const PWMapStrategy& other) const +void UnordPWMap::pushBack(Map&& m) { - UnordPWMapCRef othr = static_cast(other); + if (!m.isEmpty()) { + _pieces.push_back(std::move(m)); + } +} + +// Operators ------------------------------------------------------------------- - if (dom() != othr.dom()) +bool UnordPWMap::operator==(const UnordPWMap& other) const +{ + if (domain() != other.domain()) { return false; + } - if (pieces_ == othr.pieces_) + if (_pieces == other._pieces) { return true; + } - for (const Map& m1 : pieces_) { - for (const Map& m2 : othr.pieces_) { - Set cap_dom = m1.dom().intersection(m2.dom()); - if (!cap_dom.isEmpty()) { - Exp exp1 = m1.exp(); - Exp exp2 = m2.exp(); - if (exp1 != exp2) { + for (const Map& m1 : _pieces) { + for (const Map& m2 : other._pieces) { + Set cap_domain = m1.domain().intersection(m2.domain()); + if (!cap_domain.isEmpty()) { + Expression expr1 = m1.law(); + Expression expr2 = m2.law(); + if (expr1 != expr2) { return false; } - Map cap_m1(cap_dom, exp1); - Map cap_m2(cap_dom, exp2); + Map cap_m1{cap_domain, expr1}; + Map cap_m2{cap_domain, expr2}; if (cap_m1 != cap_m2) { return false; } @@ -123,451 +135,431 @@ bool UnordPWMap::operator==(const PWMapStrategy& other) const return true; } -bool UnordPWMap::operator!=(const PWMapStrategy& other) const +bool UnordPWMap::operator!=(const UnordPWMap& other) const { return !(*this == other); } -UnordPWMap& UnordPWMap::operator=(UnordPWMap&& other) +UnordPWMap UnordPWMap::operator+(const UnordPWMap& other) const { - if (this != &other) - pieces_ = std::move(other.pieces_); + UnordPWMap result; + + for (const Map& m1 : _pieces) { + for (const Map& m2 : other._pieces) { + result.pushBack(m1 + m2); + } + } - return *this; + return result; } std::ostream& UnordPWMap::print(std::ostream& out) const { - int sz = pieces_.size(); + int sz = _pieces.size(); out << "<<"; if (sz > 0) { int i = 0; for (; i < sz - 1; ++i) { - out << pieces_[i] << ", "; + out << _pieces[i] << ", "; } - out << pieces_[i]; + out << _pieces[i]; } out << ">>"; return out; } -PWMapStratPtr UnordPWMap::operator+(const PWMapStrategy& other) const -{ - PWMapStratPtr res = std::make_unique(); - - UnordPWMapCRef othr = static_cast(other); - for (const Map& m1 : pieces_) - for (const Map& m2 : othr.pieces_) - res->emplaceBack(m1 + m2); - - return res; -} - -PWMapStratPtr UnordPWMap::clone() const -{ - return std::make_unique(pieces_); -} - // PWMap functions ------------------------------------------------------------- std::size_t UnordPWMap::arity() const { - if (isEmpty()) + if (isEmpty()) { return 0; + } - return pieces_.begin()->dom().arity(); + return _pieces.begin()->domain().arity(); } -bool UnordPWMap::isEmpty() const { return pieces_.empty(); } +bool UnordPWMap::isEmpty() const { return _pieces.empty(); } -Set UnordPWMap::dom() const +Set UnordPWMap::domain() const & { - Set result = SET_FACT.createSet(); - for (const Map& m : pieces_) { - Set ith_dom = m.dom(); - result = std::move(result).disjointCup(std::move(ith_dom)); + Set result; + + for (const Map& m : _pieces) { + result = std::move(result).disjointCup(m.domain()); } return result; } -PWMapStratPtr UnordPWMap::restrict(const Set& subdom) const +Set UnordPWMap::domain() && { - PWMapStratPtr res = std::make_unique(); + Set result; - for (const Map& m : pieces_) - res->emplaceBack(m.restrict(subdom)); + for (Map& m : _pieces) { + result = std::move(result).disjointCup(std::move(m).domain()); + } - return res; + return result; +} + +UnordPWMap UnordPWMap::restrict(const Set& subdom) const +{ + UnordPWMap result; + + for (const Map& m : _pieces) { + result.pushBack(m.restrict(subdom)); + } + + return result; } Set UnordPWMap::image() const { - Set res = SET_FACT.createSet(); + Set result; - for (const Map& m : pieces_) { - Set ith_img = m.image(); - res = std::move(res).cup(std::move(ith_img)); + for (const Map& m : _pieces) { + result = std::move(result).cup(m.image()); } - return res; + return result; } Set UnordPWMap::image(const Set& subdom) const { - return restrict(subdom)->image(); + return restrict(subdom).image(); } Set UnordPWMap::preImage(const Set& subcodom) const { - Set res = SET_FACT.createSet(); + Set result; - for (const Map& m : pieces_) { - res = res.disjointCup(m.preImage(subcodom)); + for (const Map& m : _pieces) { + result = std::move(result).disjointCup(m.preImage(subcodom)); } - return res; + return result; } -PWMapStratPtr UnordPWMap::inverse() const +UnordPWMap UnordPWMap::inverse() const { - PWMapStratPtr res = std::make_unique(); + UnordPWMap result; - for (const Map& m : pieces_) { - res->emplaceBack(m.minInv()); + for (const Map& m : _pieces) { + result.pushBack(m.inverse()); } - return res; + return result; } -PWMapStratPtr UnordPWMap::composition(const PWMapStrategy& other) const +UnordPWMap UnordPWMap::composition(const UnordPWMap& other) const { - PWMapStratPtr res = std::make_unique(); - - UnordPWMapCRef othr = static_cast(other); + UnordPWMap result; - for (const Map& m1 : pieces_) { - for (const Map& m2 : othr.pieces_) { - res->emplaceBack(m1.composition(m2)); + for (const Map& m1 : _pieces) { + for (const Map& m2 : other._pieces) { + result.pushBack(m1.composition(m2)); } } - return res; + + return result; } -PWMapStratPtr UnordPWMap::mapInf(unsigned int n) const +UnordPWMap UnordPWMap::mapInf(unsigned int n) const { - PWMapStratPtr result = std::make_unique(pieces_); + UnordPWMap result{_pieces}; - if (!dom().isEmpty()) { + if (!domain().isEmpty()) { for (unsigned int j = 0; j < n; ++j) { - PWMapStratPtr new_res = result->composition(*this); - result = std::move(new_res); + result = composition(result); } - PWMapStratPtr reduced = result->reduce(); - result = std::move(reduced); - PWMapStratPtr old_res = result->clone(); + result = result.reduce(); + UnordPWMap old_result{result}; do { - old_res = result->clone(); + old_result = result; - PWMapStratPtr new_res = result->composition(*result); - new_res = new_res->reduce(); - result = std::move(new_res); - } while (*old_res != *result); + result = result.composition(result).reduce(); + } while (old_result != result); } return result; } -PWMapStratPtr UnordPWMap::mapInf() const { return mapInf(0); } +UnordPWMap UnordPWMap::mapInf() const { return mapInf(0); } Set UnordPWMap::fixedPoints() const { - Set res = SET_FACT.createSet(); + Set result; - for (const Map& m : pieces_) { - res = res.disjointCup(m.fixedPoints()); + for (const Map& m : _pieces) { + result = std::move(result).disjointCup(m.fixedPoints()); } - return res; + return result; } // Extra operations ------------------------------------------------------------ -PWMapStratPtr UnordPWMap::concatenation(const PWMapStrategy& other) const +UnordPWMap UnordPWMap::concatenation(const UnordPWMap& other) const & { - PWMapStratPtr result = std::make_unique(pieces_); + return UnordPWMap{*this}.concatenation(other); +} - UnordPWMapCRef othr = static_cast(other); - for (const Map& m2 : othr.pieces_) { - result->emplaceBack(m2); - } +UnordPWMap UnordPWMap::concatenation(const UnordPWMap& other) && +{ + return std::move(*this).concatenation(UnordPWMap{other}); +} - return result; +UnordPWMap UnordPWMap::concatenation(UnordPWMap&& other) const & +{ + return UnordPWMap{*this}.concatenation(std::move(other)); } -PWMapStratPtr UnordPWMap::combine(const PWMapStrategy& other) const -{ - UnordPWMapCRef othr = static_cast(other); +UnordPWMap UnordPWMap::concatenation(UnordPWMap&& other) && +{ if (isEmpty()) { - return std::make_unique(othr.pieces_); + return std::move(other); } if (other.isEmpty()) { - return std::make_unique(pieces_); + return std::move(*this); } - if (pieces_ == othr.pieces_) { - return std::make_unique(pieces_); - } + UnordMapCollection result; + result.insert(result.end(), std::make_move_iterator(_pieces.begin()) + , std::make_move_iterator(_pieces.end())); + result.insert(result.end(), std::make_move_iterator(other._pieces.begin()) + , std::make_move_iterator(other._pieces.end())); - Set exclusive_other = other.dom().difference(dom()); - return concatenation(*other.restrict(exclusive_other)); + return UnordPWMap{std::move(result)}; } -PWMapStratPtr UnordPWMap::reduce() const +UnordPWMap UnordPWMap::combine(const UnordPWMap& other) const & { - UnordMapCollection result; - for (const Map& m : pieces_) { - std::vector reduced = m.reduce(); - for(const Map& reduced_map : reduced) { - result.emplace_back(reduced_map); - } - } - - return std::make_unique(std::move(result)); + return UnordPWMap{*this}.combine(other); } -PWMapStratPtr UnordPWMap::minMap(const PWMapStrategy& other) const +UnordPWMap UnordPWMap::combine(const UnordPWMap& other) && { - if (isEmpty() || other.isEmpty()) - return std::make_unique(); + return std::move(*this).combine(UnordPWMap{other}); +} - Set min_in_pw1 = lessImage(other); - return restrict(min_in_pw1)->combine(*other.restrict(dom())); -} +UnordPWMap UnordPWMap::combine(UnordPWMap&& other) const & +{ + return UnordPWMap{*this}.combine(std::move(other)); +} -PWMapStratPtr UnordPWMap::minAdjMap(const PWMapStrategy& other) const +UnordPWMap UnordPWMap::combine(UnordPWMap&& other) && { - PWMapStratPtr result = std::make_unique(); + if (isEmpty()) { + return std::move(other); + } - UnordPWMapCRef othr = static_cast(other); - Set visited = SET_FACT.createSet(); - for (const Map& m1 : pieces_) { - for (const Map& m2 : othr.pieces_) { - Set dom_res = SET_FACT.createSet(); - Set ith_dom = m1.dom().intersection(m2.dom()); - if (!ith_dom.isEmpty()) { - Exp e_res, e1; + if (other.isEmpty()) { + return std::move(*this); + } - dom_res = m1.image(ith_dom); - e1 = m1.exp(); + if (_pieces == other._pieces) { + return std::move(*this); + } - Set im2 = m2.image(ith_dom); - if (!e1.isConstant()) { - e_res = m2.exp().composition(e1.inverse()); - } else { - e_res = MDLExp(im2.minElem()); - } + Set exclusive_other = other.domain().difference(domain()); + return std::move(*this).concatenation(other.restrict(exclusive_other)); +} - if (!dom_res.isEmpty()) { - Map ith(dom_res, e_res); - UnordPWMap ith_pw(ith); - Set again = dom_res.intersection(visited); - if (!again.isEmpty()) { - PWMapStratPtr aux_res = result->restrict(dom_res); - PWMapStratPtr min_map = aux_res->minMap(ith_pw); - PWMapStratPtr new_res = min_map->combine(ith_pw)->combine(*result); - result = std::move(new_res); - visited = visited.cup(ith_pw.dom()); - } else { - result->emplaceBack(ith); - visited = std::move(visited).disjointCup(std::move(dom_res)); - } - } - } +UnordPWMap UnordPWMap::reduce() const +{ + UnordPWMap result; + + for (const Map& m : _pieces) { + std::vector reduced = m.reduce(); + for(Map& reduced_map : reduced) { + result._pieces.push_back(std::move(reduced_map)); } } return result; } -PWMapStratPtr UnordPWMap::firstInv(const Set& subdom) const +UnordPWMap UnordPWMap::min(const UnordPWMap& other) const { - UnordMapCollection result; - - Set visited = SET_FACT.createSet(); - for (const Map& m : pieces_) { - Set res_dom = m.image(subdom).difference(visited); - if (!res_dom.isEmpty()) { - Map new_map(m.preImage(res_dom), m.exp()); - result.emplace_back(new_map.minInv()); + if (isEmpty() || other.isEmpty()) { + return UnordPWMap{}; + } - for (const SetPiece& mdi : res_dom) - visited.emplaceBack(mdi); + Set min_in_pw1 = lessImage(other); + return restrict(min_in_pw1).combine(other.restrict(domain())); +} + +UnordPWMap UnordPWMap::minAdj(const UnordPWMap& other) const +{ + UnordPWMap result; + + Set visited; + for (const Map& m1 : _pieces) { + for (const Map& m2 : other._pieces) { + Map min_adj = m1.minAdj(m2); + if (!min_adj.isEmpty()) { + Set min_adj_domain = min_adj.domain(); + Set repeated = min_adj_domain.intersection(visited); + if (!repeated.isEmpty()) { + UnordPWMap min_adj_pw{std::move(min_adj)}; + UnordPWMap min_adj_repeated = min_adj_pw.restrict(repeated); + UnordPWMap result_repeated = result.restrict(repeated); + UnordPWMap min_map = min_adj_repeated.min(result_repeated); + UnordPWMap min_adj_result = min_map.combine(std::move(min_adj_pw)); + result = min_adj_result.combine(std::move(result)); + visited = visited.cup(min_adj_domain); + } else { + result.pushBack(std::move(min_adj)); + visited = std::move(visited).disjointCup(std::move(min_adj_domain)); + } + } } } - return std::make_unique(result); + return result; } -PWMapStratPtr UnordPWMap::firstInv() const { return firstInv(dom()); } - -PWMapStratPtr UnordPWMap::filterMap(bool (*f)(const Map&)) const +Set UnordPWMap::sharedImage() const { - PWMapStratPtr res = std::make_unique(); - - for (const Map& m : pieces_) - if (f(m)) - res->emplaceBack(m); + Set repeated_image; + Set visited; + for (const Map& m : _pieces) { + Set image_in_visited = m.image().intersection(visited); + if (!image_in_visited.isEmpty()) { + repeated_image = std::move(repeated_image).cup(std::move( + image_in_visited)); + } + visited = std::move(visited).cup(m.image()); + } - return res; + return preImage(repeated_image); } -Set UnordPWMap::equalImage(const PWMapStrategy& other) const +Set UnordPWMap::equalImage(const UnordPWMap& other) const { - Set res = SET_FACT.createSet(); + Set result; - UnordPWMapCRef othr = static_cast(other); - for (const Map& m1 : pieces_) { - for (const Map& m2 : othr.pieces_) { - Set cap_dom = m1.dom().intersection(m2.dom()); + if (_pieces == other._pieces) { + return domain(); + } + + for (const Map& m1 : _pieces) { + for (const Map& m2 : other._pieces) { + Set cap_dom = m1.domain().intersection(m2.domain()); if (!cap_dom.isEmpty()) { - Map m1_cap(cap_dom, m1.exp()); - Map m2_cap(cap_dom, m2.exp()); - if (m1_cap == m2_cap) - res = res.disjointCup(cap_dom); + Map m1_cap{cap_dom, m1.law()}; + Map m2_cap{cap_dom, m2.law()}; + if (m1_cap == m2_cap) { + result = std::move(result).disjointCup(std::move(cap_dom)); + } } } } - return res; + return result; } -Set UnordPWMap::lessImage(const PWMapStrategy& other) const +Set UnordPWMap::lessImage(const UnordPWMap& other) const { - if (isEmpty() || other.isEmpty()) - return SET_FACT.createSet(); + if (isEmpty() || other.isEmpty()) { + return Set{}; + } - UnordPWMapCRef othr = static_cast(other); - Set min_in_pw1 = SET_FACT.createSet(); - for (const Map& m1 : pieces_) { - for (const Map& m2 : othr.pieces_) { - min_in_pw1 = min_in_pw1.disjointCup(m1.lessImage(m2)); + Set min_in_pw1; + for (const Map& m1 : _pieces) { + for (const Map& m2 : other._pieces) { + min_in_pw1 = std::move(min_in_pw1).disjointCup(m1.lessImage(m2)); } } return min_in_pw1; -} - -Set UnordPWMap::sharedImage() const -{ - Set not_present = dom().difference(firstInv()->image()); - Set res = preImage(image(not_present)); - - return res; } -PWMapStratPtr UnordPWMap::offsetDom(const MD_NAT& off) const +UnordPWMap UnordPWMap::imageMultiplicity() const { - UnordMapCollection res; + Map initial_result{image(), Expression{arity(), 0, 0}}; + UnordPWMap result{initial_result}; - for (const Map& m : pieces_) { - pushBack(res, Map(m.dom().offset(off), m.exp())); + for (const Map& m : _pieces) { + UnordPWMap jth_mult{m.imageMultiplicity()}; + UnordPWMap sum_mult = jth_mult + result; + result = std::move(sum_mult).combine(std::move(result)); } - return std::make_unique(res); -} + return result; +} -PWMapStratPtr UnordPWMap::offsetDom(const PWMapStrategy& off) const +void UnordPWMap::compact() { - PWMapStratPtr res = std::make_unique(); - - for (const Map& m : pieces_) { - Set ith_dom = off.image(m.dom()); - res->emplaceBack(Map(ith_dom, m.exp())); - } + using MapSet = std::set; - return res; -} - -PWMapStratPtr UnordPWMap::offsetImage(const MD_NAT& off) const -{ - UnordMapCollection res; + UnordMapCollection result; - for (const Map& m : pieces_) { - Exp e = m.exp(), res_e; - for (unsigned int j = 0; j < e.arity(); ++j) { - LExp res_lexp(e[j].slope(), e[j].offset() + (RATIONAL) off[j]); - res_e.emplaceBack(res_lexp); + if (!isEmpty()) { + MapSet set_result; + for (const Map& m : _pieces) { + Set new_domain = m.domain(); + new_domain.compact(); + set_result.emplace(new_domain, m.law()); } - pushBack(res, Map(m.dom(), res_e)); - } + MapSet to_erase; + do { + MapSet new_set_result; + to_erase.clear(); + + MapSet::iterator ith = set_result.begin(); + MapSet::iterator last = set_result.end(); + for (; ith != last; ++ith) { + Map ith_compact = *ith; + MapSet::iterator next = ith; + ++next; + for (; next != last; ++next) { + MaybeMap new_compact = ith_compact.compact(*next); + if (new_compact) { + ith_compact = new_compact.value(); + to_erase.insert(*next); + } + } - return std::make_unique(res); -} + if (to_erase.find(ith_compact) == to_erase.end()) { + new_set_result.insert(ith_compact); + } + } -PWMapStratPtr UnordPWMap::offsetImage(const Exp& off) const -{ - UnordMapCollection res; + std::swap(set_result, new_set_result); + } while (!to_erase.empty()); - for (const Map& m : pieces_) { - pushBack(res, Map(m.dom(), off + m.exp())); + for (const Map& m : set_result) { + result.push_back(m); + } } - return std::make_unique(res); + _pieces = std::move(result); } -PWMapStratPtr UnordPWMap::compact() const -{ - UnordMapCollection res; - if (dom().isEmpty()) - return std::make_unique(res); - - std::forward_list indices; - auto liIt = indices.before_begin(); +// Non-member functions -------------------------------------------------------- - const size_t lSize = pieces_.size(); - for (size_t i = 0; i < lSize; ++i) - liIt = indices.insert_after(liIt, i); - - auto begin = pieces_.begin(); - auto liPrev = indices.before_begin(); - auto liCurr = indices.begin(); - while (liCurr != indices.end()) { - size_t id = *liCurr; - const Map& it = *(begin + id); - Map new_ith(it.dom().compact(), it.exp()); - - liCurr = indices.erase_after(liPrev); - - while (liCurr != indices.end()) { - size_t idx = *liCurr; - const Map& nextMap = *(begin + idx); - - auto ith = new_ith.compact(nextMap); - if (ith) { - new_ith = ith.value(); - liCurr = indices.erase_after(liPrev); - continue; - } - +rapidjson::Value toJSON(UnordPWMap pw + , rapidjson::Document::AllocatorType& alloc) +{ + rapidjson::Value result{rapidjson::kArrayType}; - ++liPrev; - ++liCurr; - } - - pushBack(res, new_ith); - liPrev = indices.before_begin(); - liCurr = indices.begin(); + for (const Map& m : pw) { + rapidjson::Value jth = toJSON(m, alloc); + result.PushBack(jth, alloc); } - return std::make_unique(res); + return result; } +} // namespace detail + } // namespace LIB } // namespace SBG; diff --git a/sbg/unord_pwmap.hpp b/sbg/unord_pwmap.hpp index 66df70f3..549855be 100644 --- a/sbg/unord_pwmap.hpp +++ b/sbg/unord_pwmap.hpp @@ -21,101 +21,145 @@ ******************************************************************************/ -#ifndef SBG_UNORD_PWMAP_HPP -#define SBG_UNORD_PWMAP_HPP +#ifndef SBGRAPH_SBG_UNORD_PWMAP_HPP_ +#define SBGRAPH_SBG_UNORD_PWMAP_HPP_ -#include "sbg/pw_map.hpp" +#include "sbg/map.hpp" +#include "sbg/set.hpp" + +#include "rapidjson/document.h" + +#include +#include +#include namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// -// Unordered PWMap Implementation (concrete strategy) -------------------------- +// Unordered PWMap Implementation ---------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -class UnordPWMap : public PWMapStrategy { - public: +class UnordPWMap { +public: using UnordMapCollection = std::vector; + using ConstIt = UnordMapCollection::const_iterator; - member_class(UnordMapCollection, pieces); - - ~UnordPWMap() = default; UnordPWMap(); - UnordPWMap(const Set &s); - UnordPWMap(const Map &m); + UnordPWMap(const Set& s); + UnordPWMap(const Map& m); UnordPWMap(const UnordMapCollection& pieces); + UnordPWMap(UnordMapCollection&& pieces); - class Iterator : public PWMapStrategy::Iterator { - member_class(UnordMapCollection::const_iterator, it); - - Iterator(UnordMapCollection::const_iterator it); - void operator++() override; - bool operator!=(const PWMapStrategy::Iterator &other) const override; - const Map &operator*() const override; - }; - - std::shared_ptr begin() const override; - std::shared_ptr end() const override; + ConstIt begin() const; + ConstIt end() const; - void emplaceBack(const Map &m) override; + template + void emplace(Args&&... args); + void insert(const Map& m); + void insert(Map&& m); - bool operator==(const PWMapStrategy &other) const override; - bool operator!=(const PWMapStrategy &other) const override; - UnordPWMap &operator=(UnordPWMap &&other); - std::ostream &print(std::ostream &out) const override; - - PWMapStratPtr operator+(const PWMapStrategy &other) const override; - - PWMapStratPtr clone() const override; + bool operator==(const UnordPWMap& other) const; + bool operator!=(const UnordPWMap& other) const; + UnordPWMap operator+(const UnordPWMap& other) const; + std::ostream& print(std::ostream& out) const; // Traditional map operations ------------------------------------------------ - std::size_t arity() const override; - bool isEmpty() const override; - Set dom() const override; - PWMapStratPtr restrict(const Set &subdom) const override; - Set image() const override; - Set image(const Set &subdom) const override; - Set preImage(const Set &subcodom) const override; - PWMapStratPtr inverse() const override; - PWMapStratPtr composition(const PWMapStrategy &pw2) const override; + std::size_t arity() const; + bool isEmpty() const; + Set domain() const &; + Set domain() &&; + UnordPWMap restrict(const Set& subdom) const; + Set image() const; + Set image(const Set& subdom) const; + Set preImage(const Set& subcodom) const; + UnordPWMap inverse() const; + UnordPWMap composition(const UnordPWMap& other) const; - PWMapStratPtr mapInf(unsigned int n) const override; - PWMapStratPtr mapInf() const override; - Set fixedPoints() const override; + UnordPWMap mapInf() const; + Set fixedPoints() const; // Extra operations ---------------------------------------------------------- - PWMapStratPtr concatenation(const PWMapStrategy &other) const override; - PWMapStratPtr combine(const PWMapStrategy &other) const override; - PWMapStratPtr reduce() const override; - - PWMapStratPtr minMap(const PWMapStrategy &other) const override; - PWMapStratPtr minAdjMap(const PWMapStrategy &other) const override; + UnordPWMap concatenation(const UnordPWMap& other) const &; + UnordPWMap concatenation(const UnordPWMap& other) &&; + UnordPWMap concatenation(UnordPWMap&& other) const &; + UnordPWMap concatenation(UnordPWMap&& other) &&; + UnordPWMap combine(const UnordPWMap& other) const &; + UnordPWMap combine(const UnordPWMap& other) &&; + UnordPWMap combine(UnordPWMap&& other) const &; + UnordPWMap combine(UnordPWMap&& other) &&; + + UnordPWMap min(const UnordPWMap& other) const; + UnordPWMap minAdj(const UnordPWMap& other) const; + + Set sharedImage() const; + Set equalImage(const UnordPWMap& other) const; + Set lessImage(const UnordPWMap& other) const; + + UnordPWMap imageMultiplicity() const; + + void compact(); + +private: + template + void emplaceBack(Args&&... args); + void pushBack(const Map& m); + void pushBack(Map&& m); + + /** + * @brief Calculates (if possible) compactly the result of mapInf.\n + * + * Currently, the only expressions that can be efficiently reduced are: + * - x+h + * - x-h + */ + UnordPWMap reduce() const; + + /* + * @brief First compose the pw with itself \p n times, obtaining pw'. Then, + * compose pw' with itself up to convergence. + */ + UnordPWMap mapInf(unsigned int n) const; + + UnordMapCollection _pieces; + + friend class PWMapAccessKey; +}; - PWMapStratPtr firstInv(const Set &subdom) const override; - PWMapStratPtr firstInv() const override; +// Template definitions -------------------------------------------------------- - PWMapStratPtr filterMap(bool (*f)(const Map &)) const override; +template +inline void UnordPWMap::emplace(Args&&... args) +{ + auto&& domain = std::get<0>(std::forward_as_tuple(args...)); + if (!domain.isEmpty()) { + _pieces.emplace_back(std::forward(args)...); + } +} - Set equalImage(const PWMapStrategy &other) const override; - Set lessImage(const PWMapStrategy& other) const override; - Set sharedImage() const override; +template +inline void UnordPWMap::emplaceBack(Args&&... args) +{ + auto&& domain = std::get<0>(std::forward_as_tuple(args...)); + if (!domain.isEmpty()) { + _pieces.emplace_back(std::forward(args)...); + } +} - PWMapStratPtr offsetDom(const MD_NAT &off) const override; - PWMapStratPtr offsetDom(const PWMapStrategy &off) const override; - PWMapStratPtr offsetImage(const MD_NAT &off) const override; - PWMapStratPtr offsetImage(const Exp &off) const override; +// Non-member functions -------------------------------------------------------- - PWMapStratPtr compact() const override; -}; +rapidjson::Value toJSON(UnordPWMap pw + , rapidjson::Document::AllocatorType& alloc); -typedef const UnordPWMap &UnordPWMapCRef; -typedef std::unique_ptr UnordPWMapPtr; +} // namespace detail } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_UNORD_PWMAP_HPP_ diff --git a/sbg/unord_set.cpp b/sbg/unord_set.cpp index a700fa16..2ee04511 100644 --- a/sbg/unord_set.cpp +++ b/sbg/unord_set.cpp @@ -17,127 +17,126 @@ ******************************************************************************/ -#include - #include "sbg/unord_set.hpp" +#include +#include +#include + namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// -// Unordered Set Implementation ------------------------------------------------ +// Auxiliary functions --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -member_imp(UnorderedSet, UnorderedSet::MDIUnordCollection, pieces); - -UnorderedSet::~UnorderedSet() {} -UnorderedSet::UnorderedSet() : pieces_() {} -UnorderedSet::UnorderedSet(const MD_NAT& x) : pieces_() { - pieces_.emplace_back(SetPiece(x)); -} -UnorderedSet::UnorderedSet(const Interval& i) : pieces_() { - if (!i.isEmpty()) - pieces_.emplace_back(SetPiece(i)); -} -UnorderedSet::UnorderedSet(const SetPiece& mdi) : pieces_() { - if (!mdi.isEmpty()) - pieces_.emplace_back(mdi); -} -UnorderedSet::UnorderedSet(const UnorderedSet::MDIUnordCollection& pieces) - : pieces_(std::move(pieces)) {} - -SetStratPtr UnorderedSet::clone() const +bool overlap(const UnorderedSet& lhs, const UnorderedSet& rhs) { - return std::make_unique(*this); + return rhs.minElem() < lhs.maxElem() || lhs.minElem() < rhs.maxElem(); } -member_imp(UnorderedSet::Iterator - , UnorderedSet::MDIUnordCollection::const_iterator, it); +//////////////////////////////////////////////////////////////////////////////// +// Unordered Set Implementation ------------------------------------------------ +//////////////////////////////////////////////////////////////////////////////// -UnorderedSet::Iterator::Iterator( - UnorderedSet::MDIUnordCollection::const_iterator it) : it_(it) {} +// Constructors/Destructors ---------------------------------------------------- -void UnorderedSet::Iterator::operator++() -{ - ++it_; - return; -} +UnorderedSet::UnorderedSet() : _pieces() {} -bool UnorderedSet::Iterator::operator!=(const SetStrategy::Iterator& other) - const +UnorderedSet::UnorderedSet(const MD_NAT& x) : _pieces() { - return it_ != static_cast(&other)->it_; + _pieces.emplace_back(MultiDimInter{x}); } -bool UnorderedSet::Iterator::operator==(const SetStrategy::Iterator& other) - const +UnorderedSet::UnorderedSet(const Interval& i) : _pieces() { - return it_ == static_cast(&other)->it_; + if (!i.isEmpty()) { + _pieces.emplace_back(MultiDimInter{i}); + } } -bool UnorderedSet::Iterator::operator<(const SetStrategy::Iterator& other) const +UnorderedSet::UnorderedSet(const MultiDimInter& mdi) : _pieces() { - return it_ < static_cast(&other)->it_; + if (!mdi.isEmpty()) { + _pieces.push_back(mdi); + } } -const SetPiece& UnorderedSet::Iterator::operator*() const { return *it_; } +UnorderedSet::UnorderedSet(const UnorderedSet::MDIUnordCollection& pieces) + : _pieces(pieces) {} -std::shared_ptr UnorderedSet::begin() const -{ - return std::make_shared(pieces_.begin()); -} +UnorderedSet::UnorderedSet(UnorderedSet::MDIUnordCollection&& pieces) + : _pieces(std::move(pieces)) {} -std::shared_ptr UnorderedSet::end() const +UnorderedSet::UnorderedSet(const FixedPointsInfo& info) : _pieces() { - return std::make_shared(pieces_.end()); + if (info) { + std::vector solutions = info.value(); + Interval universe_one_dim{0, 1, Inf}; + MultiDimInter result_mdi; + for (const Solution& jth_solution : solutions) { + if (jth_solution.kind() == SolutionKind::kFixed) { + result_mdi.pushBack(jth_solution.value().value()); + } else if (jth_solution.kind() == SolutionKind::kFree) { + result_mdi.pushBack(universe_one_dim); + } + } + pushBack(result_mdi); + } } -std::size_t UnorderedSet::size() const { return pieces_.size(); } +// Getters --------------------------------------------------------------------- -void UnorderedSet::emplace(const SetPiece& mdi) -{ - if (mdi.isEmpty()) { - return; - } +UnorderedSet::ConstIt UnorderedSet::begin() const { return _pieces.begin(); } - pieces_.emplace(pieces_.begin(), mdi); - return; -} +UnorderedSet::ConstIt UnorderedSet::end() const { return _pieces.end(); } + +// Setters --------------------------------------------------------------------- -void UnorderedSet::emplaceBack(const SetPiece& mdi) +void UnorderedSet::pushBack(const MultiDimInter& mdi) { if (mdi.isEmpty()) { return; } - pieces_.emplace_back(mdi); - return; + _pieces.push_back(mdi); } -bool UnorderedSet::operator==(const SetStrategy& other) const +// Operators ------------------------------------------------------------------- + +bool UnorderedSet::operator==(const UnorderedSet& other) const { - UnordSetCRef othr = static_cast(other); + if (isEmpty() && other.isEmpty()) { + return true; + } + + if (isEmpty() != other.isEmpty()) { + return false; + } - if (pieces_ == othr.pieces_) + if (_pieces == other._pieces) { return true; + } - return difference(other)->isEmpty() && other.difference(*this)->isEmpty(); + return difference(other).isEmpty() && other.difference(*this).isEmpty(); } -bool UnorderedSet::operator!=(const SetStrategy& other) const +bool UnorderedSet::operator!=(const UnorderedSet& other) const { return !(*this == other); } std::ostream& UnorderedSet::print(std::ostream& out) const { - std::size_t sz = size(); + std::size_t sz = _pieces.size(); out << "{"; if (sz > 0) { unsigned int j = 0; - for (const SetPiece& mdi : pieces_) { + for (const MultiDimInter& mdi : _pieces) { if (j < sz - 1) { out << mdi << ", "; } else { @@ -158,313 +157,303 @@ unsigned int UnorderedSet::cardinal() const { unsigned int result = 0; - for (const SetPiece& mdi : pieces_) { + for (const MultiDimInter& mdi : _pieces) { result += mdi.cardinal(); } return result; } -bool UnorderedSet::isEmpty() const { return pieces_.empty(); } +bool UnorderedSet::isEmpty() const { return _pieces.empty(); } MD_NAT UnorderedSet::minElem() const { - MD_NAT res = pieces_.begin()->minElem(); - for (const SetPiece& mdi : pieces_) { - MD_NAT ith = mdi.minElem(); - if (ith < res) - res = ith; + MD_NAT result = _pieces.begin()->minElem(); + + for (const MultiDimInter& mdi : _pieces) { + result = std::min(result, mdi.minElem()); } - return res; + return result; } MD_NAT UnorderedSet::maxElem() const { - MD_NAT res = pieces_.begin()->maxElem(); - for (const SetPiece& mdi : pieces_) { - MD_NAT ith = mdi.maxElem(); - if (res < ith) - res = ith; + MD_NAT result = _pieces.begin()->maxElem(); + + for (const MultiDimInter& mdi : _pieces) { + result = std::max(result, mdi.maxElem()); } - return res; + return result; } -SetStratPtr UnorderedSet::intersection(const SetStrategy& other) const +UnorderedSet intersectionEpilogue(const UnorderedSet::MDIUnordCollection& lhs + , const UnorderedSet::MDIUnordCollection& rhs) { - // Special cases to enhance performance - if (isEmpty() || other.isEmpty()) { - return std::make_unique(); - } - - const MD_NAT min_elem = minElem(); - const MD_NAT max_elem = maxElem(); - const MD_NAT other_min = other.minElem(); - const MD_NAT other_max = other.maxElem(); - if (max_elem < other_min || other_max < min_elem) { - return std::make_unique(); - } - - UnorderedSet result; - if (max_elem == other_min) { - result.emplaceBack(SetPiece(max_elem)); - return std::make_unique(result); - } - - if (other_max == min_elem) { - result.emplaceBack(SetPiece(min_elem)); - return std::make_unique(result); - } - - UnordSetCRef othr = static_cast(other); - if (pieces_ == othr.pieces_) { - return std::make_unique(pieces_); - } - // General case - for (const SetPiece& mdi1 : pieces_) { - for (const SetPiece& mdi2 : othr.pieces_) { - result.emplaceBack(mdi1.intersection(mdi2)); + UnorderedSet result; + for (const MultiDimInter& mdi1 : lhs) { + for (const MultiDimInter& mdi2 : rhs) { + result.pushBack(mdi1.intersection(mdi2)); } } - return std::make_unique(std::move(result)); + return result; } -SetStratPtr UnorderedSet::cup(const SetStrategy& other) const & +UnorderedSet UnorderedSet::intersection(const UnorderedSet& other) const { - UnordSetCRef othr = static_cast(other); - - if (isEmpty()) { - return std::make_unique(othr.pieces_); + if (isEmpty() || other.isEmpty()) { + return UnorderedSet{}; } - if (other.isEmpty() || pieces_ == othr.pieces_) { - return std::make_unique(pieces_); + if (_pieces == other._pieces) { + return UnorderedSet{_pieces}; } - if (maxElem() < othr.minElem() || othr.maxElem() < minElem()) { - MDIUnordCollection result(pieces_.begin(), pieces_.end()); - result.insert(result.end(), othr.pieces_.begin(), othr.pieces_.end()); - return std::make_unique(std::move(result)); - } + return intersectionEpilogue(_pieces, other._pieces); +} - // General case - SetStratPtr diff = difference(other); +UnorderedSet UnorderedSet::cup(const UnorderedSet& other) const & +{ + return UnorderedSet{*this}.cup(other); +} - return othr.disjointCup(*diff); +UnorderedSet UnorderedSet::cup(const UnorderedSet& other) && +{ + return std::move(*this).cup(UnorderedSet{other}); } -SetStratPtr UnorderedSet::cup(SetStrategy&& other) && +UnorderedSet UnorderedSet::cup(UnorderedSet&& other) const & { - UnordSetCRef othr = static_cast(other); + return UnorderedSet{*this}.cup(std::move(other)); +} +UnorderedSet UnorderedSet::cup(UnorderedSet&& other) && +{ if (isEmpty()) { - return std::make_unique(std::move(othr.pieces_)); + return std::move(other); } - if (other.isEmpty() || pieces_ == othr.pieces_) { - return std::make_unique(std::move(pieces_)); + if (other.isEmpty() || _pieces == other._pieces) { + return std::move(*this); } - if (maxElem() < othr.minElem() || othr.maxElem() < minElem()) { - MDIUnordCollection result = std::move(pieces_); - result.insert(result.end(), othr.pieces_.begin(), othr.pieces_.end()); - return std::make_unique(std::move(result)); + if (maxElem() < other.minElem() || other.maxElem() < minElem()) { + MDIUnordCollection result = std::move(_pieces); + result.insert(result.end(), std::make_move_iterator(other._pieces.begin()) + , std::make_move_iterator(other._pieces.end())); + return UnorderedSet{std::move(result)}; } // General case - SetStratPtr diff = difference(other); - return othr.disjointCup(*diff); + return std::move(other).disjointCup(difference(other)); } -SetStratPtr UnorderedSet::complementAtom() const +UnorderedSet UnorderedSet::complementAtom() const { - MDIUnordCollection res; + MDIUnordCollection result; - SetPiece mdi = *pieces_.begin(); - SetPiece dense_mdi; - for (const Interval& i : mdi) - dense_mdi.emplaceBack(Interval(i.begin(), 1, i.end())); - SetPiece during_mdi = dense_mdi; + MultiDimInter mdi = *_pieces.begin(); + MultiDimInter dense_mdi; + for (const Interval& i : mdi) { + dense_mdi.emplaceBack(i.begin(), 1, i.end()); + } + MultiDimInter during_mdi = dense_mdi; - Interval univ_one_dim(0, 1, Inf); - SetPiece univ(mdi.arity(), univ_one_dim); + Interval universe_one_dim{0, 1, Inf}; + MultiDimInter univ{mdi.arity(), universe_one_dim}; - unsigned int dim = 0; + std::size_t dim = 0; for (const Interval& i : mdi) { - MDIUnordCollection c; - // Before interval if (i.begin() != 0) { - Interval i_res(0, 1, i.begin() - 1); + Interval i_res{0, 1, i.begin() - 1}; if (!i_res.isEmpty()) { univ[dim] = i_res; - c.emplace_back(univ); - univ[dim] = univ_one_dim; + result.push_back(univ); + univ[dim] = universe_one_dim; } } // "During" interval - if (i.begin() < Inf) { - if (i.step() > 1) { - for (unsigned int j = 0; j < i.step() - 1; ++j) { - Interval i_res(i.begin() + j + 1, i.step(), i.end()); - if (!i_res.isEmpty()) { - during_mdi[dim] = i_res; - c.emplace_back(during_mdi); - } + if (i.begin() < Inf && i.step() > 1) { + for (unsigned int j = 0; j < i.step() - 1; ++j) { + Interval i_res{i.begin() + j + 1, i.step(), i.end()}; + if (!i_res.isEmpty()) { + during_mdi[dim] = i_res; + result.push_back(during_mdi); } } } // After interval if (i.end() < Inf) { - Interval i_res(i.end() + 1, 1, Inf); + Interval i_res{i.end() + 1, 1, Inf}; if (!i_res.isEmpty()) { univ[dim] = i_res; - c.emplace_back(univ); - univ[dim] = univ_one_dim; + result.push_back(univ); + univ[dim] = universe_one_dim; } } univ[dim] = dense_mdi[dim]; during_mdi[dim] = i; - - // Insert results of current dim - for (const SetPiece& mdi : c) - res.emplace_back(mdi); - ++dim; } - return std::make_unique(std::move(res)); + return UnorderedSet{std::move(result)}; } -SetStratPtr UnorderedSet::complement() const +UnorderedSet UnorderedSet::complement() const { - SetStratPtr res = std::make_unique(MDIUnordCollection()); - - auto first_it = pieces_.begin(); - SetPiece first = *first_it; - res = std::move(UnorderedSet(first).complementAtom()); + if (isEmpty()) { + return UnorderedSet{}; + } - ++first_it; - MDIUnordCollection second(first_it, pieces_.end()); - for (const SetPiece& mdi : second) { - SetStratPtr c = UnorderedSet(mdi).complementAtom(); - res = std::move(res->intersection(*c)); + UnorderedSet result = UnorderedSet{_pieces.front()}.complementAtom(); + std::size_t j = 0; + for (const MultiDimInter& mdi : _pieces) { + if (j > 0) { + UnorderedSet c = UnorderedSet{mdi}.complementAtom(); + result = result.intersection(c); + } + ++j; } - return res; + return result; } -SetStratPtr UnorderedSet::difference(const SetStrategy& other) const +UnorderedSet UnorderedSet::difference(const UnorderedSet& other) const { // Special cases if (isEmpty() || other.isEmpty()) { - return std::make_unique(pieces_); + return UnorderedSet{_pieces}; } - if (maxElem() < other.minElem() || other.maxElem() < minElem()) { - return std::make_unique(pieces_); + if (_pieces == other._pieces) { + return UnorderedSet{}; } // General case - return intersection(*other.complement()); + return intersection(other.complement()); +} + +UnorderedSet UnorderedSet::cartesianProduct(const UnorderedSet& other) const +{ + UnorderedSet result; + + if (isEmpty() || other.isEmpty()) { + return result; + } + + for (const MultiDimInter& mdi : _pieces) { + MultiDimInter mdi_copy = mdi; + for (const MultiDimInter& other_mdi : other._pieces) { + result.pushBack(mdi.cartesianProduct(other_mdi)); + } + } + + return result; } // Extra operations ------------------------------------------------------------ std::size_t UnorderedSet::arity() const { - if (isEmpty()) + if (isEmpty()) { return 0; + } - return pieces_.begin()->arity(); + return _pieces.begin()->arity(); } -SetStratPtr UnorderedSet::disjointCup(const SetStrategy& other) const & +UnorderedSet UnorderedSet::disjointCup(const UnorderedSet& other) const & { - UnordSetCRef othr = static_cast(other); - - if (isEmpty()) { - return std::make_unique(othr.pieces_); - } - - if (other.isEmpty() || pieces_ == othr.pieces_) { - return std::make_unique(pieces_); - } - - MDIUnordCollection result(pieces_.begin(), pieces_.end()); - for (const SetPiece& mdi : othr.pieces_) { - result.emplace_back(mdi); - } + return UnorderedSet{*this}.disjointCup(other); +} - return std::make_unique(std::move(result)); +UnorderedSet UnorderedSet::disjointCup(const UnorderedSet& other) && +{ + return std::move(*this).disjointCup(UnorderedSet{other}); } -SetStratPtr UnorderedSet::disjointCup(SetStrategy&& other) && +UnorderedSet UnorderedSet::disjointCup(UnorderedSet&& other) const & { - UnordSetCRef othr = static_cast(other); + return UnorderedSet{*this}.disjointCup(std::move(other)); +} +UnorderedSet UnorderedSet::disjointCup(UnorderedSet&& other) && +{ if (isEmpty()) { - return std::make_unique(std::move(othr.pieces_)); + return std::move(other); } - if (other.isEmpty() || pieces_ == othr.pieces_) { - return std::make_unique(std::move(pieces_)); + if (other.isEmpty()) { + return std::move(*this); } - MDIUnordCollection result(pieces_.begin(), pieces_.end()); - for (const SetPiece& mdi : othr.pieces_) { - result.emplace_back(mdi); - } + MDIUnordCollection result; + result.insert(result.end(), std::make_move_iterator(_pieces.begin()) + , std::make_move_iterator(_pieces.end())); + result.insert(result.end(), std::make_move_iterator(other._pieces.begin()) + , std::make_move_iterator(other._pieces.end())); - return std::make_unique(std::move(result)); + return UnorderedSet{std::move(result)}; } -SetStratPtr UnorderedSet::filterSet(bool (*f)(const SetPiece& mdi)) const +UnorderedSet UnorderedSet::offset(const MD_NAT& off) const { - MDIUnordCollection res; + UnorderedSet result; - for (const SetPiece& mdi : pieces_) { - if (f(mdi)) { - res.emplace_back(mdi); - } + for (const MultiDimInter& mdi : _pieces) { + result.pushBack(mdi.offset(off)); } - return std::make_unique(std::move(res)); + return result; } -SetStratPtr UnorderedSet::offset(const MD_NAT& off) const +Perimeter UnorderedSet::perimeter() const { - MDIUnordCollection res; + MD_NAT min; + MD_NAT max; - for (const SetPiece& mdi : pieces_) { - res.emplace_back(mdi.offset(off)); + if (!isEmpty()) { + std::size_t arity = this->arity(); + min = MD_NAT{arity, Inf}; + max = MD_NAT{arity, 0}; + for (const MultiDimInter& mdi : _pieces) { + MD_NAT candidate_min = mdi.minElem(); + MD_NAT candidate_max = mdi.maxElem(); + for (size_t i = 0; i < arity; ++i) { + min[i] = std::min(min[i], candidate_min[i]); + max[i] = std::max(max[i], candidate_max[i]); + } + } } - return std::make_unique(std::move(res)); + return Perimeter{min, max}; } -SetStratPtr UnorderedSet::compact() const +void UnorderedSet::compact() { - MDIUnordCollection res; + using MDISet = std::set; + + MDIUnordCollection result; if (!isEmpty()) { - std::set prev(pieces_.begin(), pieces_.end()); - std::set actual = prev; + MDISet set_result{std::make_move_iterator(_pieces.begin()) + , std::make_move_iterator(_pieces.end())}; + MDISet to_erase; do { - prev = actual; - actual = std::set(); + MDISet new_set_result; + to_erase.clear(); - std::set::iterator ith = prev.begin(); - std::set::iterator last = prev.end(); - std::set to_erase; + MDISet::iterator ith = set_result.begin(); + MDISet::iterator last = set_result.end(); for (; ith != last; ++ith) { - SetPiece ith_compact = *ith; - std::set::iterator next = ith; + MultiDimInter ith_compact = *ith; + MDISet::iterator next = ith; ++next; for (; next != last; ++next) { MaybeMDI new_compact = ith_compact.compact(*next); @@ -474,18 +463,40 @@ SetStratPtr UnorderedSet::compact() const } } - if (to_erase.find(ith_compact) == to_erase.end()) - actual.insert(ith_compact); + if (to_erase.find(ith_compact) == to_erase.end()) { + new_set_result.insert(ith_compact); + } } - } while (actual != prev); - for (const SetPiece& mdi : actual) - res.emplace_back(mdi); + std::swap(set_result, new_set_result); + } while (!to_erase.empty()); + + for (const MultiDimInter& m : set_result) { + result.push_back(m); + } } - return std::make_unique(std::move(res)); + _pieces = std::move(result); } +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(UnorderedSet s + , rapidjson::Document::AllocatorType& alloc) +{ + rapidjson::Value mdi_array{rapidjson::kArrayType}; + for (const MultiDimInter& mdi : s) { + rapidjson::Value jth = detail::toJSON(mdi, alloc); + mdi_array.PushBack(jth, alloc); + } + rapidjson::Value result{rapidjson::kObjectType}; + result.AddMember("pieces", mdi_array, alloc); + + return result; +} + +} // namespace detail + } // namespace LIB } // namespace SBG diff --git a/sbg/unord_set.hpp b/sbg/unord_set.hpp index ed80cd91..6315b6b1 100644 --- a/sbg/unord_set.hpp +++ b/sbg/unord_set.hpp @@ -21,88 +21,100 @@ ******************************************************************************/ -#ifndef SBG_UNORD_SET_HPP -#define SBG_UNORD_SET_HPP +#ifndef SBGRAPH_SBG_UNORD_SET_HPP_ +#define SBGRAPH_SBG_UNORD_SET_HPP_ +#include "sbg/expression.hpp" +#include "sbg/fixed_points.hpp" +#include "sbg/interval.hpp" #include "sbg/multidim_inter.hpp" -#include "sbg/set.hpp" +#include "sbg/natural.hpp" +#include "sbg/perimeter.hpp" + +#include "rapidjson/document.h" + +#include +#include +#include namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// -// Unordered Set Implementation (concrete strategy) ---------------------------- +// Unordered Set Implementation ------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// -class UnorderedSet : public SetStrategy { - using MDIUnordCollection = std::vector; +class UnorderedSet { +public: + using MDIUnordCollection = std::vector; + using ConstIt = MDIUnordCollection::const_iterator; - member_class(MDIUnordCollection, pieces); - - ~UnorderedSet(); UnorderedSet(); UnorderedSet(const MD_NAT& x); - UnorderedSet(const Interval& i); - UnorderedSet(const SetPiece& mdi); + UnorderedSet(const detail::Interval& i); + UnorderedSet(const detail::MultiDimInter& mdi); UnorderedSet(const MDIUnordCollection& pieces); + UnorderedSet(MDIUnordCollection&& pieces); + UnorderedSet(const FixedPointsInfo& info); - SetStratPtr clone() const override; - - class Iterator : public SetStrategy::Iterator { - member_class(MDIUnordCollection::const_iterator, it); - - Iterator(MDIUnordCollection::const_iterator it); - void operator++() override; - bool operator!=(const SetStrategy::Iterator& other) const override; - bool operator==(const SetStrategy::Iterator& other) const override; - bool operator<(const SetStrategy::Iterator& other) const override; - const SetPiece& operator*() const override; - }; + ConstIt begin() const; + ConstIt end() const; - std::shared_ptr begin() const override; - std::shared_ptr end() const override; + void pushBack(const MultiDimInter& mdi); - std::size_t size() const override; - void emplace(const SetPiece& mdi) override; - void emplaceBack(const SetPiece& mdi) override; - - bool operator==(const SetStrategy& other) const override; - bool operator!=(const SetStrategy& other) const override; - std::ostream& print(std::ostream& out) const override; + bool operator==(const UnorderedSet& other) const; + bool operator!=(const UnorderedSet& other) const; + std::ostream& print(std::ostream& out) const; // Traditional set operations ------------------------------------------------ - unsigned int cardinal() const override; - bool isEmpty() const override; - MD_NAT minElem() const override; - MD_NAT maxElem() const override; - SetStratPtr intersection(const SetStrategy& other) const override; - SetStratPtr cup(const SetStrategy& other) const & override; - SetStratPtr cup(SetStrategy&& other) && override; - SetStratPtr complement() const; - SetStratPtr difference(const SetStrategy& other) const override; + unsigned int cardinal() const; + bool isEmpty() const; + MD_NAT minElem() const; + MD_NAT maxElem() const; + UnorderedSet intersection(const UnorderedSet& other) const; + UnorderedSet cup(const UnorderedSet& other) const &; + UnorderedSet cup(UnorderedSet&& other) const &; + UnorderedSet cup(const UnorderedSet& other) &&; + UnorderedSet cup(UnorderedSet&& other) &&; + UnorderedSet complement() const; + UnorderedSet difference(const UnorderedSet& other) const; + UnorderedSet cartesianProduct(const UnorderedSet& other) const; // Extra operations ---------------------------------------------------------- - std::size_t arity() const override; - SetStratPtr disjointCup(const SetStrategy& other) const & override; - SetStratPtr disjointCup(SetStrategy&& other) && override; - SetStratPtr filterSet(bool (*f)(const SetPiece& mdi)) const override; - SetStratPtr offset(const MD_NAT& off) const override; - SetStratPtr compact() const override; + std::size_t arity() const; + UnorderedSet disjointCup(const UnorderedSet& other) const &; + UnorderedSet disjointCup(const UnorderedSet& other) &&; + UnorderedSet disjointCup(UnorderedSet&& other) const &; + UnorderedSet disjointCup(UnorderedSet&& other) &&; + UnorderedSet offset(const MD_NAT& off) const; + Perimeter perimeter() const; + void compact(); - private: +private: /** * @brief Calculate the complement of an unordered set with a single piece. */ - SetStratPtr complementAtom() const; + UnorderedSet complementAtom() const; + + MDIUnordCollection _pieces; + + friend class SetAccessKey; }; -typedef const UnorderedSet& UnordSetCRef; +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(UnorderedSet s + , rapidjson::Document::AllocatorType& alloc); + +} // namespace detail } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_UNORD_SET_HPP_ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6aec7794..df763dfa 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -16,11 +16,12 @@ file(MAKE_DIRECTORY add_subdirectory(eval) add_subdirectory(parser) -add_subdirectory(partitioner) +#add_subdirectory(partitioner) add_subdirectory(performance) add_custom_target(test COMMAND echo "Running Tests." ) -add_dependencies(test run-eval-test run-parser-test run-partitioner-test) +add_dependencies(test run-eval-test run-parser-test) +#add_dependencies(test run-eval-test run-parser-test run-partitioner-test) diff --git a/test/README.md b/test/README.md index 27e2b495..05fe4605 100755 --- a/test/README.md +++ b/test/README.md @@ -26,33 +26,8 @@ Executes system tests for the partitioner. ## performance -Measures and outputs execution time of predefined tests. - -The following benchmarks can be executed from the sb-graph/build/ directory -with the following commands: - - `make run-benchmark`: benchmark for some implementations of Sets and PWMaps. - - `make run-match`: benchmark for the maximum matching algorithm applied to - TestRL1.test, TestRL2.test and TestRL3.test. - - `make run-scc`: benchmark for the SCC algorithm applied to TestRL1.test, - TestRL2.test and TestRL3.test. - -In the ./test/build/bin there are also some helpful binaries: - - boost-perf: used to evaluate the performance of traditional graphs - algorithms. - - custom-match-benchmark: benchmark for the maximum matching algorithm applied - to a custom .test file. Environmental variables TEST_FILE, SET_IMPL and - PW_IMPL are support. So, for example, - `TEST_FILE="../../TestRL1.test" SET_IMPL="2" ./custom-match-benchmark` runs - the benchmark for TestRL1.test with the ordered unidimensional dense set - implementation. - - custom-scc-benchmark: benchmark for the SCC algorithm applied to a custom - .test file. Environmental variables TEST_FILE, SET_IMPL and PW_IMPL are - supported. - - custom-boost-benchmark: benchmark for the C++ Boost Graph Library - traditional scalar algorithms. This benchmark is introduced to compare - the SBG approach with existing techniques. Environmental variable TEST_FILE - is supported. The benchmark will start calculating some data, without - printing results for some seconds. - If the process terminates with a Segmentation Fault, increase - stack size with the following command: `ulimit -s stack_size` (128000 is - recommended for stack_size). +Measures and outputs execution time of predefined tests. The corresponding +binary is sb-graph/test/build/bin/sbg-benchmark (to see available options run +the executable with --help as argument). For the algorithms benchmark it accepts +a single test file as a positional argument. The binary also supports Google +Benchmark options, i.e. --benchmark_filter=filter. diff --git a/test/TestRL1.test b/test/TestRL1.test index b5454f38..b8eb6cf3 100644 --- a/test/TestRL1.test +++ b/test/TestRL1.test @@ -1,7 +1,7 @@ /* Matching + SCC test of the following model: model TestRL1 - constant Integer N = 100000; + constant Integer N = 1000000; Real iL[N], Ua[N], Uc[N]; parameter Real Ra = 1, Rb = 1, Rc = 1, L = 1; equation @@ -20,7 +20,7 @@ equation end TestRL1; */ -N = 100000; +N = 1000000; F1 = 1; F2 = N-1+F1; diff --git a/test/TestRL2.test b/test/TestRL2.test index e9b5b585..c7e69fa8 100644 --- a/test/TestRL2.test +++ b/test/TestRL2.test @@ -5,7 +5,7 @@ model TestRL2 //iR[i] must be computed out of iR[i+1] //uL[i+1] must be computed out of uL[i] - constant Integer N=100000; + constant Integer N=1000000; Real iL[N],iR[N],uL[N]; parameter Real L=1,R=1,L1=1,I=1,R0=1; equation @@ -21,7 +21,7 @@ equation end TestRL2; */ -N = 100000; +N = 1000000; F1 = N; F2 = N-1+F1; @@ -69,25 +69,25 @@ F = {[1:1:F1], [F1+1:1:F2], [F2+1:1:F3], [F3+1:1:F4], [F4+1:1:F5]}; U = {[F5+1:1:U1], [U1+1:1:U2], [U2+1:1:U3]}; V: F \/ U -Vmap: <<{[1:1:F1]} -> |0*x+1|, {[F1+1:1:F2]} -> |0*x+2|, {[F2+1:1:F3]} -> |0*x+3 - |, {[F3+1:1:F4]} -> |0*x+4|, {[F4+1:1:F5]} -> |0*x+5 - |, {[F5+1:1:U1]} -> |0*x+6|, {[U1+1:1:U2]} -> |0*x+7|, {[U2+1:1:U3]} -> |0*x+8|>> -map1: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d - |, {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|, {[E5+1:1:E6]} -> |1*x+off6d - |, {[E6+1:1:E7]} -> |1*x+off7d|, {[E7+1:1:E8]} -> |1*x+off8d|, {[E8+1:1:E9]} -> |1*x+off9d - |, {[E9+1:1:E10]} -> |1*x+off10d|>> -map2: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b - |, {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b - |, {[E6+1:1:E7]} -> |1*x+off7b|, {[E7+1:1:E8]} -> |1*x+off8b|, {[E8+1:1:E9]} -> |1*x+off9b - |, {[E9+1:1:E10]} -> |1*x+off10b|>> -Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3], [E3+1:1:E4]} -> |0*x+3 - |, {[E4+1:1:E5]} -> |0*x+4 - |, {[E5+1:1:E6], [E6+1:1:E7]} -> |0*x+6|, {[E7+1:1:E8]} -> |0*x+7|, {[E8+1:1:E9]} -> |0*x+8 - |, {[E9+1:1:E10]} -> |0*x+9|>> +Vmap: <<{[1:1:F1]} -> |0*x+1|, {[F1+1:1:F2]} -> |0*x+2|, {[F2+1:1:F3]} -> |0*x+3| + , {[F3+1:1:F4]} -> |0*x+4|, {[F4+1:1:F5]} -> |0*x+5| + , {[F5+1:1:U1]} -> |0*x+6|, {[U1+1:1:U2]} -> |0*x+7|, {[U2+1:1:U3]} -> |0*x+8|>> +map1: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d| + , {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|, {[E5+1:1:E6]} -> |1*x+off6d| + , {[E6+1:1:E7]} -> |1*x+off7d|, {[E7+1:1:E8]} -> |1*x+off8d|, {[E8+1:1:E9]} -> |1*x+off9d| + , {[E9+1:1:E10]} -> |1*x+off10d|>> +map2: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b| + , {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b| + , {[E6+1:1:E7]} -> |1*x+off7b|, {[E7+1:1:E8]} -> |1*x+off8b|, {[E8+1:1:E9]} -> |1*x+off9b| + , {[E9+1:1:E10]} -> |1*x+off10b|>> +Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3| + , {[E3+1:1:E4]} -> |0*x+4|, {[E4+1:1:E5]} -> |0*x+5|, {[E5+1:1:E6]} -> |0*x+6| + , {[E6+1:1:E7]} -> |0*x+7|, {[E7+1:1:E8]} -> |0*x+8|, {[E8+1:1:E9]} -> |0*x+9| + , {[E9+1:1:E10]} -> |0*x+10|>> X: F Y: U; -matchSCC( +causalize( V: F \/ U Vmap: <<{[1:1:F1]} -> |0*x+1|, {[F1+1:1:F2]} -> |0*x+2|, {[F2+1:1:F3]} -> |0*x+3 |, {[F3+1:1:F4]} -> |0*x+4|, {[F4+1:1:F5]} -> |0*x+5 @@ -100,10 +100,10 @@ matchSCC( |, {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b |, {[E6+1:1:E7]} -> |1*x+off7b|, {[E7+1:1:E8]} -> |1*x+off8b|, {[E8+1:1:E9]} -> |1*x+off9b |, {[E9+1:1:E10]} -> |1*x+off10b|>> - Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3], [E3+1:1:E4]} -> |0*x+3 - |, {[E4+1:1:E5]} -> |0*x+4 - |, {[E5+1:1:E6], [E6+1:1:E7]} -> |0*x+6|, {[E7+1:1:E8]} -> |0*x+7|, {[E8+1:1:E9]} -> |0*x+8 - |, {[E9+1:1:E10]} -> |0*x+9|>> + Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3| + , {[E3+1:1:E4]} -> |0*x+4|, {[E4+1:1:E5]} -> |0*x+5|, {[E5+1:1:E6]} -> |0*x+6| + , {[E6+1:1:E7]} -> |0*x+7|, {[E7+1:1:E8]} -> |0*x+8|, {[E8+1:1:E9]} -> |0*x+9| + , {[E9+1:1:E10]} -> |0*x+10|>> X: F Y: U , 1 diff --git a/test/TestRL3.test b/test/TestRL3.test index f1487f44..e4d714b6 100644 --- a/test/TestRL3.test +++ b/test/TestRL3.test @@ -6,7 +6,7 @@ model TestRL3 //uL[i] and uL[i+1] can be computed out of each other //All variables form a large algebraic loop - constant Integer N=100000; + constant Integer N=1000000; Real iL[N],iR[N],uL[N]; parameter Real L=1,R=1,L1=1,U=1,R0=1; equation @@ -14,15 +14,15 @@ equation L*der(iL[i])=uL[i]; // der(iL[1:N]) end for; for i in 1:N-1 loop - iR[i]-iR[i+1]-iL[i]=0; // iR[1], iR[3:N] - uL[i]-uL[i+1]-R*iR[i+1]=0; // iR[2], uL[2:N-1] - end for; + iR[i]-iR[i+1]-iL[i]=0; // iR[2:N] + uL[i]-uL[i+1]-R*iR[i+1]=0; // uL[2:N] + end for; U-uL[1]-R*iR[1]=0; // uL[1] - uL[N]-(iR[N]-iL[N])*R0=0; // uL[N] + uL[N]-(iR[N]-iL[N])*R0=0; // iR[1] end TestRL3; */ -N = 100000; +N = 1000000; F1 = N; F2 = N-1+F1; @@ -73,25 +73,25 @@ F = {[1:1:F1], [F1+1:1:F2], [F2+1:1:F3], [F3+1:1:F4], [F4+1:1:F5]}; U = {[F5+1:1:U1], [U1+1:1:U2], [U2+1:1:U3]}; V: F \/ U -Vmap: <<{[1:1:F1]} -> |0*x+1|, {[F1+1:1:F2]} -> |0*x+2|, {[F2+1:1:F3]} -> |0*x+3 - |, {[F3+1:1:F4]} -> |0*x+4|, {[F4+1:1:F5]} -> |0*x+5 - |, {[F5+1:1:U1]} -> |0*x+6|, {[U1+1:1:U2]} -> |0*x+7|, {[U2+1:1:U3]} -> |0*x+8|>> -map1: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d - |, {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|, {[E5+1:1:E6]} -> |1*x+off6d - |, {[E6+1:1:E7]} -> |1*x+off7d|, {[E7+1:1:E8]} -> |1*x+off8d|, {[E8+1:1:E9]} -> |1*x+off9d - |, {[E9+1:1:E10]} -> |1*x+off10d|, {[E10+1:1:E11]} -> |1*x+off11d|>> -map2: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b - |, {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b - |, {[E6+1:1:E7]} -> |1*x+off7b|, {[E7+1:1:E8]} -> |1*x+off8b|, {[E8+1:1:E9]} -> |1*x+off9b - |, {[E9+1:1:E10]} -> |1*x+off10b|, {[E10+1:1:E11]} -> |1*x+off11b|>> -Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3], [E3+1:1:E4]} -> |0*x+3 - |, {[E4+1:1:E5], [E5+1:1:E6]} -> |0*x+4 - |, {[E6+1:1:E7]} -> |0*x+6|, {[E7+1:1:E8]} -> |0*x+7|, {[E8+1:1:E9]} -> |0*x+8 - |, {[E9+1:1:E10]} -> |0*x+9|, {[E10+1:1:E11]} -> |0*x+10|>> +Vmap: <<{[1:1:F1]} -> |0*x+1|, {[F1+1:1:F2]} -> |0*x+2|, {[F2+1:1:F3]} -> |0*x+3| + , {[F3+1:1:F4]} -> |0*x+4|, {[F4+1:1:F5]} -> |0*x+5| + , {[F5+1:1:U1]} -> |0*x+6|, {[U1+1:1:U2]} -> |0*x+7|, {[U2+1:1:U3]} -> |0*x+8|>> +map1: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d| + , {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|, {[E5+1:1:E6]} -> |1*x+off6d| + , {[E6+1:1:E7]} -> |1*x+off7d|, {[E7+1:1:E8]} -> |1*x+off8d|, {[E8+1:1:E9]} -> |1*x+off9d| + , {[E9+1:1:E10]} -> |1*x+off10d|, {[E10+1:1:E11]} -> |1*x+off11d|>> +map2: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b| + , {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b| + , {[E6+1:1:E7]} -> |1*x+off7b|, {[E7+1:1:E8]} -> |1*x+off8b|, {[E8+1:1:E9]} -> |1*x+off9b| + , {[E9+1:1:E10]} -> |1*x+off10b|, {[E10+1:1:E11]} -> |1*x+off11b|>> +Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3| + , {[E3+1:1:E4]} -> |0*x+4|, {[E4+1:1:E5]} -> |0*x+5|, {[E5+1:1:E6]} -> |0*x+6| + , {[E6+1:1:E7]} -> |0*x+7|, {[E7+1:1:E8]} -> |0*x+8|, {[E8+1:1:E9]} -> |0*x+9| + , {[E9+1:1:E10]} -> |0*x+10|, {[E10+1:1:E11]} -> |0*x+11|>> X: F Y: U; -matchSCC( +causalize( V: F \/ U Vmap: <<{[1:1:F1]} -> |0*x+1|, {[F1+1:1:F2]} -> |0*x+2|, {[F2+1:1:F3]} -> |0*x+3 |, {[F3+1:1:F4]} -> |0*x+4|, {[F4+1:1:F5]} -> |0*x+5 @@ -104,10 +104,10 @@ matchSCC( |, {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b |, {[E6+1:1:E7]} -> |1*x+off7b|, {[E7+1:1:E8]} -> |1*x+off8b|, {[E8+1:1:E9]} -> |1*x+off9b |, {[E9+1:1:E10]} -> |1*x+off10b|, {[E10+1:1:E11]} -> |1*x+off11b|>> - Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3], [E3+1:1:E4]} -> |0*x+3 - |, {[E4+1:1:E5], [E5+1:1:E6]} -> |0*x+4 - |, {[E6+1:1:E7]} -> |0*x+6|, {[E7+1:1:E8]} -> |0*x+7|, {[E8+1:1:E9]} -> |0*x+8 - |, {[E9+1:1:E10]} -> |0*x+9|, {[E10+1:1:E11]} -> |0*x+10|>> + Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3| + , {[E3+1:1:E4]} -> |0*x+4|, {[E4+1:1:E5]} -> |0*x+5|, {[E5+1:1:E6]} -> |0*x+6| + , {[E6+1:1:E7]} -> |0*x+7|, {[E7+1:1:E8]} -> |0*x+8|, {[E8+1:1:E9]} -> |0*x+9| + , {[E9+1:1:E10]} -> |0*x+10|, {[E10+1:1:E11]} -> |0*x+11|>> X: F Y: U , 1 diff --git a/test/advection2D.test b/test/advection2D.test index 7b2eb1a4..0f9971c3 100644 --- a/test/advection2D.test +++ b/test/advection2D.test @@ -241,19 +241,7 @@ Vmap: <<{[1:1:V1x]x[1:1:V1y]} -> |0*x+1|0*x+1|, {[V1x+1:1:V2x]x[V1y+1:1:V2y]} -> , {[V8x+1:1:V9x]x[V8y+1:1:V9y]} -> |0*x+9|0*x+9|, {[V9x+1:1:V10x]x[V9y+1:1:V10y]} -> |0*x+10|0*x+10| , {[V10x+1:1:V11x]x[V10y+1:1:V11y]} -> |0*x+11|0*x+11|, {[V11x+1:1:V12x]x[V11y+1:1:V12y]} -> |0*x+12|0*x+12|>> -map1: <<{[1:1:E1x]x[1:1:E1y]} -> |1*x+off1bx|1*x+off1by|, {[E1x+1:1:E2x]x[E1y+1:1:E2y]} -> |1*x+off2bx|1*x+off2by| -, {[E2x+1:1:E3x]x[E2y+1:1:E3y]} -> |1*x+off3bx|1*x+off3by|, {[E3x+1:1:E4x]x[E3y+1:1:E4y]} -> |1*x+off4bx|1*x+off4by| -, {[E4x+1:1:E5x]x[E4y+1:1:E5y]} -> |1*x+off5bx|1*x+off5by|, {[E5x+1:1:E6x]x[E5y+1:1:E6y]} -> |1*x+off6bx|1*x+off6by| -, {[E6x+1:1:E7x]x[E6y+1:1:E7y]} -> |1*x+off7bx|1*x+off7by|, {[E7x+1:1:E8x]x[E7y+1:1:E8y]} -> |1*x+off8bx|1*x+off8by| -, {[E8x+1:1:E9x]x[E8y+1:1:E9y]} -> |1*x+off9bx|1*x+off9by|, {[E9x+1:1:E10x]x[E9y+1:1:E10y]} -> |1*x+off10bx|1*x+off10by| -, {[E10x+1:1:E11x]x[E10y+1:1:E11y]} -> |1*x+off11bx|1*x+off11by|, {[E11x+1:1:E12x]x[E11y+1:1:E12y]} -> |1*x+off12bx|1*x+off12by| -, {[E12x+1:1:E13x]x[E12y+1:1:E13y]} -> |1*x+off13bx|1*x+off13by|, {[E13x+1:1:E14x]x[E13y+1:1:E14y]} -> |1*x+off14bx|1*x+off14by| -, {[E14x+1:1:E15x]x[E14y+1:1:E15y]} -> |1*x+off15bx|1*x+off15by|, {[E15x+1:1:E16x]x[E15y+1:1:E16y]} -> |1*x+off16bx|1*x+off16by| -, {[E16x+1:1:E17x]x[E16y+1:1:E17y]} -> |1*x+off17bx|1*x+off17by|, {[E17x+1:1:E18x]x[E17y+1:1:E18y]} -> |1*x+off18bx|1*x+off18by| -, {[E18x+1:1:E19x]x[E18y+1:1:E19y]} -> |1*x+off19bx|1*x+off19by|, {[E19x+1:1:E20x]x[E19y+1:1:E20y]} -> |1*x+off20bx|1*x+off20by| -, {[E20x+1:1:E21x]x[E20y+1:1:E21y]} -> |1*x+off21bx|1*x+off21by|, {[E21x+1:1:E22x]x[E21y+1:1:E22y]} -> |1*x+off22bx|1*x+off22by|>> - -map2: <<{[1:1:E1x]x[1:1:E1y]} -> |1*x+off1dx|1*x+off1dy|, {[E1x+1:1:E2x]x[E1y+1:1:E2y]} -> |1*x+off2dx|1*x+off2dy| +map1: <<{[1:1:E1x]x[1:1:E1y]} -> |1*x+off1dx|1*x+off1dy|, {[E1x+1:1:E2x]x[E1y+1:1:E2y]} -> |1*x+off2dx|1*x+off2dy| , {[E2x+1:1:E3x]x[E2y+1:1:E3y]} -> |1*x+off3dx|1*x+off3dy|, {[E3x+1:1:E4x]x[E3y+1:1:E4y]} -> |1*x+off4dx|1*x+off4dy| , {[E4x+1:1:E5x]x[E4y+1:1:E5y]} -> |1*x+off5dx|1*x+off5dy|, {[E5x+1:1:E6x]x[E5y+1:1:E6y]} -> |1*x+off6dx|1*x+off6dy| , {[E6x+1:1:E7x]x[E6y+1:1:E7y]} -> |1*x+off7dx|1*x+off7dy|, {[E7x+1:1:E8x]x[E7y+1:1:E8y]} -> |1*x+off8dx|1*x+off8dy| @@ -265,17 +253,29 @@ map2: <<{[1:1:E1x]x[1:1:E1y]} -> |1*x+off1dx|1*x+off1dy|, {[E1x+1:1:E2x]x[E1y+1: , {[E18x+1:1:E19x]x[E18y+1:1:E19y]} -> |1*x+off19dx|1*x+off19dy|, {[E19x+1:1:E20x]x[E19y+1:1:E20y]} -> |1*x+off20dx|1*x+off20dy| , {[E20x+1:1:E21x]x[E20y+1:1:E21y]} -> |1*x+off21dx|1*x+off21dy|, {[E21x+1:1:E22x]x[E21y+1:1:E22y]} -> |1*x+off22dx|1*x+off22dy|>> +map2: <<{[1:1:E1x]x[1:1:E1y]} -> |1*x+off1bx|1*x+off1by|, {[E1x+1:1:E2x]x[E1y+1:1:E2y]} -> |1*x+off2bx|1*x+off2by| +, {[E2x+1:1:E3x]x[E2y+1:1:E3y]} -> |1*x+off3bx|1*x+off3by|, {[E3x+1:1:E4x]x[E3y+1:1:E4y]} -> |1*x+off4bx|1*x+off4by| +, {[E4x+1:1:E5x]x[E4y+1:1:E5y]} -> |1*x+off5bx|1*x+off5by|, {[E5x+1:1:E6x]x[E5y+1:1:E6y]} -> |1*x+off6bx|1*x+off6by| +, {[E6x+1:1:E7x]x[E6y+1:1:E7y]} -> |1*x+off7bx|1*x+off7by|, {[E7x+1:1:E8x]x[E7y+1:1:E8y]} -> |1*x+off8bx|1*x+off8by| +, {[E8x+1:1:E9x]x[E8y+1:1:E9y]} -> |1*x+off9bx|1*x+off9by|, {[E9x+1:1:E10x]x[E9y+1:1:E10y]} -> |1*x+off10bx|1*x+off10by| +, {[E10x+1:1:E11x]x[E10y+1:1:E11y]} -> |1*x+off11bx|1*x+off11by|, {[E11x+1:1:E12x]x[E11y+1:1:E12y]} -> |1*x+off12bx|1*x+off12by| +, {[E12x+1:1:E13x]x[E12y+1:1:E13y]} -> |1*x+off13bx|1*x+off13by|, {[E13x+1:1:E14x]x[E13y+1:1:E14y]} -> |1*x+off14bx|1*x+off14by| +, {[E14x+1:1:E15x]x[E14y+1:1:E15y]} -> |1*x+off15bx|1*x+off15by|, {[E15x+1:1:E16x]x[E15y+1:1:E16y]} -> |1*x+off16bx|1*x+off16by| +, {[E16x+1:1:E17x]x[E16y+1:1:E17y]} -> |1*x+off17bx|1*x+off17by|, {[E17x+1:1:E18x]x[E17y+1:1:E18y]} -> |1*x+off18bx|1*x+off18by| +, {[E18x+1:1:E19x]x[E18y+1:1:E19y]} -> |1*x+off19bx|1*x+off19by|, {[E19x+1:1:E20x]x[E19y+1:1:E20y]} -> |1*x+off20bx|1*x+off20by| +, {[E20x+1:1:E21x]x[E20y+1:1:E21y]} -> |1*x+off21bx|1*x+off21by|, {[E21x+1:1:E22x]x[E21y+1:1:E22y]} -> |1*x+off22bx|1*x+off22by|>> + Emap: <<{[1:1:E1x]x[1:1:E1y]} -> |0*x+1|0*x+1|, {[E1x+1:1:E2x]x[E1y+1:1:E2y]} -> |0*x+2|0*x+2| , {[E2x+1:1:E3x]x[E2y+1:1:E3y]} -> |0*x+3|0*x+3|, {[E3x+1:1:E4x]x[E3y+1:1:E4y]} -> |0*x+4|0*x+4| , {[E4x+1:1:E5x]x[E4y+1:1:E5y]} -> |0*x+5|0*x+5|, {[E5x+1:1:E6x]x[E5y+1:1:E6y]} -> |0*x+6|0*x+6| -, {[E6x+1:1:E7x]x[E6y+1:1:E7y]} -> |0*x+6|0*x+6|, {[E7x+1:1:E8x]x[E7y+1:1:E8y]} -> |0*x+7|0*x+7| -, {[E8x+1:1:E9x]x[E8y+1:1:E9y]} -> |0*x+8|0*x+8|, {[E9x+1:1:E10x]x[E9y+1:1:E10y]} -> |0*x+9|0*x+9| -, {[E10x+1:1:E11x]x[E10y+1:1:E11y]} -> |0*x+10|0*x+10|, {[E11x+1:1:E12x]x[E11y+1:1:E12y]} -> |0*x+10|0*x+10| -, {[E12x+1:1:E13x]x[E12y+1:1:E13y]} -> |0*x+11|0*x+11|, {[E13x+1:1:E14x]x[E13y+1:1:E14y]} -> |0*x+12|0*x+12| -, {[E14x+1:1:E15x]x[E14y+1:1:E15y]} -> |0*x+13|0*x+13|, {[E15x+1:1:E16x]x[E15y+1:1:E16y]} -> |0*x+14|0*x+14| -, {[E16x+1:1:E17x]x[E16y+1:1:E17y]} -> |0*x+14|0*x+14|, {[E17x+1:1:E18x]x[E17y+1:1:E18y]} -> |0*x+14|0*x+14| -, {[E18x+1:1:E19x]x[E18y+1:1:E19y]} -> |0*x+15|0*x+15|, {[E19x+1:1:E20x]x[E19y+1:1:E20y]} -> |0*x+16|0*x+16| -, {[E20x+1:1:E21x]x[E20y+1:1:E21y]} -> |0*x+17|0*x+17|, {[E21x+1:1:E22x]x[E21y+1:1:E22y]} -> |0*x+18|0*x+18|>> +, {[E6x+1:1:E7x]x[E6y+1:1:E7y]} -> |0*x+7|0*x+7|, {[E7x+1:1:E8x]x[E7y+1:1:E8y]} -> |0*x+8|0*x+8| +, {[E8x+1:1:E9x]x[E8y+1:1:E9y]} -> |0*x+9|0*x+9|, {[E9x+1:1:E10x]x[E9y+1:1:E10y]} -> |0*x+10|0*x+10| +, {[E10x+1:1:E11x]x[E10y+1:1:E11y]} -> |0*x+11|0*x+11|, {[E11x+1:1:E12x]x[E11y+1:1:E12y]} -> |0*x+12|0*x+12| +, {[E12x+1:1:E13x]x[E12y+1:1:E13y]} -> |0*x+13|0*x+13|, {[E13x+1:1:E14x]x[E13y+1:1:E14y]} -> |0*x+14|0*x+14| +, {[E14x+1:1:E15x]x[E14y+1:1:E15y]} -> |0*x+15|0*x+15|, {[E15x+1:1:E16x]x[E15y+1:1:E16y]} -> |0*x+16|0*x+16| +, {[E16x+1:1:E17x]x[E16y+1:1:E17y]} -> |0*x+17|0*x+17|, {[E17x+1:1:E18x]x[E17y+1:1:E18y]} -> |0*x+18|0*x+18| +, {[E18x+1:1:E19x]x[E18y+1:1:E19y]} -> |0*x+19|0*x+19|, {[E19x+1:1:E20x]x[E19y+1:1:E20y]} -> |0*x+20|0*x+20| +, {[E20x+1:1:E21x]x[E20y+1:1:E21y]} -> |0*x+21|0*x+21|, {[E21x+1:1:E22x]x[E21y+1:1:E22y]} -> |0*x+22|0*x+22|>> X: F @@ -291,19 +291,7 @@ matchSCC( , {[V8x+1:1:V9x]x[V8y+1:1:V9y]} -> |0*x+9|0*x+9|, {[V9x+1:1:V10x]x[V9y+1:1:V10y]} -> |0*x+10|0*x+10| , {[V10x+1:1:V11x]x[V10y+1:1:V11y]} -> |0*x+11|0*x+11|, {[V11x+1:1:V12x]x[V11y+1:1:V12y]} -> |0*x+12|0*x+12|>> - map1: <<{[1:1:E1x]x[1:1:E1y]} -> |1*x+off1bx|1*x+off1by|, {[E1x+1:1:E2x]x[E1y+1:1:E2y]} -> |1*x+off2bx|1*x+off2by| - , {[E2x+1:1:E3x]x[E2y+1:1:E3y]} -> |1*x+off3bx|1*x+off3by|, {[E3x+1:1:E4x]x[E3y+1:1:E4y]} -> |1*x+off4bx|1*x+off4by| - , {[E4x+1:1:E5x]x[E4y+1:1:E5y]} -> |1*x+off5bx|1*x+off5by|, {[E5x+1:1:E6x]x[E5y+1:1:E6y]} -> |1*x+off6bx|1*x+off6by| - , {[E6x+1:1:E7x]x[E6y+1:1:E7y]} -> |1*x+off7bx|1*x+off7by|, {[E7x+1:1:E8x]x[E7y+1:1:E8y]} -> |1*x+off8bx|1*x+off8by| - , {[E8x+1:1:E9x]x[E8y+1:1:E9y]} -> |1*x+off9bx|1*x+off9by|, {[E9x+1:1:E10x]x[E9y+1:1:E10y]} -> |1*x+off10bx|1*x+off10by| - , {[E10x+1:1:E11x]x[E10y+1:1:E11y]} -> |1*x+off11bx|1*x+off11by|, {[E11x+1:1:E12x]x[E11y+1:1:E12y]} -> |1*x+off12bx|1*x+off12by| - , {[E12x+1:1:E13x]x[E12y+1:1:E13y]} -> |1*x+off13bx|1*x+off13by|, {[E13x+1:1:E14x]x[E13y+1:1:E14y]} -> |1*x+off14bx|1*x+off14by| - , {[E14x+1:1:E15x]x[E14y+1:1:E15y]} -> |1*x+off15bx|1*x+off15by|, {[E15x+1:1:E16x]x[E15y+1:1:E16y]} -> |1*x+off16bx|1*x+off16by| - , {[E16x+1:1:E17x]x[E16y+1:1:E17y]} -> |1*x+off17bx|1*x+off17by|, {[E17x+1:1:E18x]x[E17y+1:1:E18y]} -> |1*x+off18bx|1*x+off18by| - , {[E18x+1:1:E19x]x[E18y+1:1:E19y]} -> |1*x+off19bx|1*x+off19by|, {[E19x+1:1:E20x]x[E19y+1:1:E20y]} -> |1*x+off20bx|1*x+off20by| - , {[E20x+1:1:E21x]x[E20y+1:1:E21y]} -> |1*x+off21bx|1*x+off21by|, {[E21x+1:1:E22x]x[E21y+1:1:E22y]} -> |1*x+off22bx|1*x+off22by|>> - - map2: <<{[1:1:E1x]x[1:1:E1y]} -> |1*x+off1dx|1*x+off1dy|, {[E1x+1:1:E2x]x[E1y+1:1:E2y]} -> |1*x+off2dx|1*x+off2dy| + map1: <<{[1:1:E1x]x[1:1:E1y]} -> |1*x+off1dx|1*x+off1dy|, {[E1x+1:1:E2x]x[E1y+1:1:E2y]} -> |1*x+off2dx|1*x+off2dy| , {[E2x+1:1:E3x]x[E2y+1:1:E3y]} -> |1*x+off3dx|1*x+off3dy|, {[E3x+1:1:E4x]x[E3y+1:1:E4y]} -> |1*x+off4dx|1*x+off4dy| , {[E4x+1:1:E5x]x[E4y+1:1:E5y]} -> |1*x+off5dx|1*x+off5dy|, {[E5x+1:1:E6x]x[E5y+1:1:E6y]} -> |1*x+off6dx|1*x+off6dy| , {[E6x+1:1:E7x]x[E6y+1:1:E7y]} -> |1*x+off7dx|1*x+off7dy|, {[E7x+1:1:E8x]x[E7y+1:1:E8y]} -> |1*x+off8dx|1*x+off8dy| @@ -315,20 +303,30 @@ matchSCC( , {[E18x+1:1:E19x]x[E18y+1:1:E19y]} -> |1*x+off19dx|1*x+off19dy|, {[E19x+1:1:E20x]x[E19y+1:1:E20y]} -> |1*x+off20dx|1*x+off20dy| , {[E20x+1:1:E21x]x[E20y+1:1:E21y]} -> |1*x+off21dx|1*x+off21dy|, {[E21x+1:1:E22x]x[E21y+1:1:E22y]} -> |1*x+off22dx|1*x+off22dy|>> + map2: <<{[1:1:E1x]x[1:1:E1y]} -> |1*x+off1bx|1*x+off1by|, {[E1x+1:1:E2x]x[E1y+1:1:E2y]} -> |1*x+off2bx|1*x+off2by| + , {[E2x+1:1:E3x]x[E2y+1:1:E3y]} -> |1*x+off3bx|1*x+off3by|, {[E3x+1:1:E4x]x[E3y+1:1:E4y]} -> |1*x+off4bx|1*x+off4by| + , {[E4x+1:1:E5x]x[E4y+1:1:E5y]} -> |1*x+off5bx|1*x+off5by|, {[E5x+1:1:E6x]x[E5y+1:1:E6y]} -> |1*x+off6bx|1*x+off6by| + , {[E6x+1:1:E7x]x[E6y+1:1:E7y]} -> |1*x+off7bx|1*x+off7by|, {[E7x+1:1:E8x]x[E7y+1:1:E8y]} -> |1*x+off8bx|1*x+off8by| + , {[E8x+1:1:E9x]x[E8y+1:1:E9y]} -> |1*x+off9bx|1*x+off9by|, {[E9x+1:1:E10x]x[E9y+1:1:E10y]} -> |1*x+off10bx|1*x+off10by| + , {[E10x+1:1:E11x]x[E10y+1:1:E11y]} -> |1*x+off11bx|1*x+off11by|, {[E11x+1:1:E12x]x[E11y+1:1:E12y]} -> |1*x+off12bx|1*x+off12by| + , {[E12x+1:1:E13x]x[E12y+1:1:E13y]} -> |1*x+off13bx|1*x+off13by|, {[E13x+1:1:E14x]x[E13y+1:1:E14y]} -> |1*x+off14bx|1*x+off14by| + , {[E14x+1:1:E15x]x[E14y+1:1:E15y]} -> |1*x+off15bx|1*x+off15by|, {[E15x+1:1:E16x]x[E15y+1:1:E16y]} -> |1*x+off16bx|1*x+off16by| + , {[E16x+1:1:E17x]x[E16y+1:1:E17y]} -> |1*x+off17bx|1*x+off17by|, {[E17x+1:1:E18x]x[E17y+1:1:E18y]} -> |1*x+off18bx|1*x+off18by| + , {[E18x+1:1:E19x]x[E18y+1:1:E19y]} -> |1*x+off19bx|1*x+off19by|, {[E19x+1:1:E20x]x[E19y+1:1:E20y]} -> |1*x+off20bx|1*x+off20by| + , {[E20x+1:1:E21x]x[E20y+1:1:E21y]} -> |1*x+off21bx|1*x+off21by|, {[E21x+1:1:E22x]x[E21y+1:1:E22y]} -> |1*x+off22bx|1*x+off22by|>> + Emap: <<{[1:1:E1x]x[1:1:E1y]} -> |0*x+1|0*x+1|, {[E1x+1:1:E2x]x[E1y+1:1:E2y]} -> |0*x+2|0*x+2| , {[E2x+1:1:E3x]x[E2y+1:1:E3y]} -> |0*x+3|0*x+3|, {[E3x+1:1:E4x]x[E3y+1:1:E4y]} -> |0*x+4|0*x+4| , {[E4x+1:1:E5x]x[E4y+1:1:E5y]} -> |0*x+5|0*x+5|, {[E5x+1:1:E6x]x[E5y+1:1:E6y]} -> |0*x+6|0*x+6| - , {[E6x+1:1:E7x]x[E6y+1:1:E7y]} -> |0*x+6|0*x+6|, {[E7x+1:1:E8x]x[E7y+1:1:E8y]} -> |0*x+7|0*x+7| - , {[E8x+1:1:E9x]x[E8y+1:1:E9y]} -> |0*x+8|0*x+8|, {[E9x+1:1:E10x]x[E9y+1:1:E10y]} -> |0*x+9|0*x+9| - , {[E10x+1:1:E11x]x[E10y+1:1:E11y]} -> |0*x+10|0*x+10|, {[E11x+1:1:E12x]x[E11y+1:1:E12y]} -> |0*x+10|0*x+10| - , {[E12x+1:1:E13x]x[E12y+1:1:E13y]} -> |0*x+11|0*x+11|, {[E13x+1:1:E14x]x[E13y+1:1:E14y]} -> |0*x+12|0*x+12| - , {[E14x+1:1:E15x]x[E14y+1:1:E15y]} -> |0*x+13|0*x+13|, {[E15x+1:1:E16x]x[E15y+1:1:E16y]} -> |0*x+14|0*x+14| - , {[E16x+1:1:E17x]x[E16y+1:1:E17y]} -> |0*x+14|0*x+14|, {[E17x+1:1:E18x]x[E17y+1:1:E18y]} -> |0*x+14|0*x+14| - , {[E18x+1:1:E19x]x[E18y+1:1:E19y]} -> |0*x+15|0*x+15|, {[E19x+1:1:E20x]x[E19y+1:1:E20y]} -> |0*x+16|0*x+16| - , {[E20x+1:1:E21x]x[E20y+1:1:E21y]} -> |0*x+17|0*x+17|, {[E21x+1:1:E22x]x[E21y+1:1:E22y]} -> |0*x+18|0*x+18|>> - + , {[E6x+1:1:E7x]x[E6y+1:1:E7y]} -> |0*x+7|0*x+7|, {[E7x+1:1:E8x]x[E7y+1:1:E8y]} -> |0*x+8|0*x+8| + , {[E8x+1:1:E9x]x[E8y+1:1:E9y]} -> |0*x+9|0*x+9|, {[E9x+1:1:E10x]x[E9y+1:1:E10y]} -> |0*x+10|0*x+10| + , {[E10x+1:1:E11x]x[E10y+1:1:E11y]} -> |0*x+11|0*x+11|, {[E11x+1:1:E12x]x[E11y+1:1:E12y]} -> |0*x+12|0*x+12| + , {[E12x+1:1:E13x]x[E12y+1:1:E13y]} -> |0*x+13|0*x+13|, {[E13x+1:1:E14x]x[E13y+1:1:E14y]} -> |0*x+14|0*x+14| + , {[E14x+1:1:E15x]x[E14y+1:1:E15y]} -> |0*x+15|0*x+15|, {[E15x+1:1:E16x]x[E15y+1:1:E16y]} -> |0*x+16|0*x+16| + , {[E16x+1:1:E17x]x[E16y+1:1:E17y]} -> |0*x+17|0*x+17|, {[E17x+1:1:E18x]x[E17y+1:1:E18y]} -> |0*x+18|0*x+18| + , {[E18x+1:1:E19x]x[E18y+1:1:E19y]} -> |0*x+19|0*x+19|, {[E19x+1:1:E20x]x[E19y+1:1:E20y]} -> |0*x+20|0*x+20| + , {[E20x+1:1:E21x]x[E20y+1:1:E21y]} -> |0*x+21|0*x+21|, {[E21x+1:1:E22x]x[E21y+1:1:E22y]} -> |0*x+22|0*x+22|>> X: F - Y: U , 1 ); diff --git a/test/eval/gt_data/interval.log b/test/eval/gt_data/interval.log index 3ba789a5..82f5e42d 100755 --- a/test/eval/gt_data/interval.log +++ b/test/eval/gt_data/interval.log @@ -20,35 +20,31 @@ isEmpty([100:1:5]); [1:2:20]/\[2:2:20]; [201:2:399]/\[200:4:400]; [300:1:1000000]/\[300:1:500]; -minElem([500:5:499]); minElem([500:5:600]); -maxElem([500:5:499]); maxElem([500:5:600]); [1:1:100]==[1:1:100]; [1:2:100]==[1:1:100]; [2:1:100]==[1:1:100]; [1:1:101]==[1:1:100]; -[1:1:100]<[5:5:50]; -[50:3:100]<[50:5:80]; ----------------------------------- >>>>>>>>>>> Eval result <<<<<<<<<<< ----------------------------------- -i1 = [1:100]; +i1 = {[1:100]}; i2 = 1; [1:1:5] - --> [1:5] + --> {[1:5]} [1:1:5] - --> [1:5] + --> {[1:5]} [100:1:200] - --> [100:200] + --> {[100:200]} [100:10+10:200] - --> [100:20:200] + --> {[100:20:200]} #[1:1:10] --> 10 @@ -66,32 +62,26 @@ isEmpty([100:1:5]) --> true [1:1:0]/\[100:1:500] - --> + --> {} [100:1:500]/\[1:1:0] - --> + --> {} [1:2:20]/\[4:3:20] - --> [7:6:19] + --> {[7:6:19]} [1:2:20]/\[2:2:20] - --> + --> {} [201:2:399]/\[200:4:400] - --> + --> {} [300:1:1000000]/\[300:1:500] - --> [300:500] - -minElem([500:5:499]) - --> + --> {[300:500]} minElem([500:5:600]) --> 500 -maxElem([500:5:499]) - --> - maxElem([500:5:600]) --> 600 @@ -107,9 +97,3 @@ maxElem([500:5:600]) [1:1:101]==[1:1:100] --> false -[1:1:100]<[5:5:50] - --> true - -[50:3:100]<[50:5:80] - --> false - diff --git a/test/eval/gt_data/pw_map1.log b/test/eval/gt_data/pw_map1.log index 3a63af6f..5338b159 100644 --- a/test/eval/gt_data/pw_map1.log +++ b/test/eval/gt_data/pw_map1.log @@ -6,8 +6,6 @@ <<{[1:1:10], [100:10:200]} ↦ 1*x-3>>; <<{[1:1:10], [100:10:200]} ↦ 1*x-3, {[500:1:600]} ↦ 1*x+5>>; minMap(<<{[1:1:10], [15:3:30]} ↦ 1*x+0, {[12:3:12], [50:5:100]} ↦ 1*x+1>>, <<{[1:2:20], [30:5:60]} ↦ 0*x+100, {[75:5:90], [95:1:100]} ↦ 1*x+0>>); -reduce(<<{[100:1:200]} ↦ 1*x-1>>); -firstInv(<<{[1:1:10]} ↦ 0*x+10>>); mapInf(<<{[50:1:50]} ↦ 1*x-49, {[49:1:49]} ↦ 1*x-48, {[3:1:48]} ↦ 1*x+1>>); ----------------------------------- @@ -26,12 +24,6 @@ mapInf(<<{[50:1:50]} ↦ 1*x-49, {[49:1:49]} ↦ 1*x-48, {[3:1:48]} ↦ 1*x+1>>) minMap(<<{[1:1:10], [15:3:30]} ↦ 1*x+0, {[12:3:12], [50:5:100]} ↦ 1*x+1>>, <<{[1:2:20], [30:5:60]} ↦ 0*x+100, {[75:5:90], [95:1:100]} ↦ 1*x+0>>) --> <<{[1:2:9], [15:15], [30:30]} -> |x|, {[50:5:60]} -> |x+1|, {[75:5:90], [95:5:100]} -> |x|>> -reduce(<<{[100:1:200]} ↦ 1*x-1>>) - --> <<{[100:200]} -> |99|>> - -firstInv(<<{[1:1:10]} ↦ 0*x+10>>) - --> <<{[10:10]} -> |1|>> - mapInf(<<{[50:1:50]} ↦ 1*x-49, {[49:1:49]} ↦ 1*x-48, {[3:1:48]} ↦ 1*x+1>>) --> <<>> diff --git a/test/eval/gt_data/pw_map2.log b/test/eval/gt_data/pw_map2.log index f67a0554..f0ae1bae 100644 --- a/test/eval/gt_data/pw_map2.log +++ b/test/eval/gt_data/pw_map2.log @@ -13,8 +13,6 @@ preImage({[0:1:25] x [0:1:25]}, <<{[1:1:10] x [1:1:10], [20:5:30] x [20:5:30]} compose(<<{[1:1:10] x [1:1:5], [20:2:30] x [20:2:30]} ↦ 2*x+1|3*x+0, {[15:3:18] x [12:3:18]} ↦ 0*x+0|0*x+0>>, <<{[1:1:30] x [1:1:30]} ↦ 1*x+1|1*x+2>>); minAdj(<<{[10:1:100] x [10:1:100], [101:2:200] x [101:2:200]} ↦ 1*x+0|1*x+0, {[10:1:100] x [101:2:200]} ↦ 2*x+0|2*x+0>>, <<{[5:5:50] x [5:5:50]} ↦ 0*x+1|1*x+0, {[51:3:80] x [51:3:80], [90:1:150] x [95:1:150]} ↦ 2*x+3|2*x+1>>); minMap(<<{[1:1:100] x [1:1:100]} ↦ x|N*x+100>>, <<{[1:1:100] x [1:1:100]} ↦ N*x+100|x>>); -reduce(<<{[1:1:100] x [1:1:100]} ↦ x+1|x+1>>); -reduce(<<{[1:1:100] x [1:1:100]} ↦ x+1|3>>); ----------------------------------- >>>>>>>>>>> Eval result <<<<<<<<<<< @@ -46,9 +44,3 @@ minAdj(<<{[10:1:100] x [10:1:100], [101:2:200] x [101:2:200]} ↦ 1*x+0|1*x+0, { minMap(<<{[1:1:100] x [1:1:100]} ↦ x|N*x+100>>, <<{[1:1:100] x [1:1:100]} ↦ N*x+100|x>>) --> <<{[1:49]x[1:100], [50:50]x[51:100]} -> |x|-1x+100|, {[51:100]x[1:100], [50:50]x[1:50]} -> |-1x+100|x|>> -reduce(<<{[1:1:100] x [1:1:100]} ↦ x+1|x+1>>) - --> <<{[1:100]x[1:100]} -> |x+1|x+1|>> - -reduce(<<{[1:1:100] x [1:1:100]} ↦ x+1|3>>) - --> <<{[1:100]x[1:100]} -> |101|3|>> - diff --git a/test/eval/gt_data/pw_map3.log b/test/eval/gt_data/pw_map3.log index 31ca35fd..a1d1cdda 100644 --- a/test/eval/gt_data/pw_map3.log +++ b/test/eval/gt_data/pw_map3.log @@ -6,7 +6,6 @@ nmbr_dims = 3; <<>>; combine(<<{[1:1:10] x [1:1:10] x [1:1:10], [1:1:10] x [20:3:30] x [20:3:30]} ↦ 1*x+0|1*x+0|1*x+0, {[1:1:10] x [20:3:30] x [35:5:50], [35:5:50] x [35:5:50] x [20:3:30]} ↦ 3*x+0|3*x+0|1*x+1>>, <<{[1:1:20] x [1:1:20] x [1:1:20]} ↦ 1*x+1|1*x+0|1*x+0>>); -reduce(<<{[4:1:15] x [4:1:15] x [4:1:15], [4:1:15] x [20:2:25] x [4:1:15]} ↦ 1*x+0|1*x-3|3*x+0, {[4:1:15] x [15:5:50] x [20:2:25], [20:2:25] x [40:5:45] x [40:5:45]} ↦ 2*x+0|1*x+0|4*x+4>>); ----------------------------------- >>>>>>>>>>> Eval result <<<<<<<<<<< @@ -18,6 +17,3 @@ reduce(<<{[4:1:15] x [4:1:15] x [4:1:15], [4:1:15] x [20:2:25] x [4:1:15]} ↦ 1 combine(<<{[1:1:10] x [1:1:10] x [1:1:10], [1:1:10] x [20:3:30] x [20:3:30]} ↦ 1*x+0|1*x+0|1*x+0, {[1:1:10] x [20:3:30] x [35:5:50], [35:5:50] x [35:5:50] x [20:3:30]} ↦ 3*x+0|3*x+0|1*x+1>>, <<{[1:1:20] x [1:1:20] x [1:1:20]} ↦ 1*x+1|1*x+0|1*x+0>>) --> <<{[1:10]x[1:10]x[1:10], [1:10]x[20:3:29]x[20:3:29]} -> |x|x|x|, {[1:10]x[20:3:29]x[35:5:50], [35:5:50]x[35:5:50]x[20:3:29]} -> |3x|3x|x+1|, {[11:20]x[1:20]x[1:20], [1:10]x[11:19]x[1:20], [1:10]x[20:20]x[1:19], [1:10]x[1:10]x[11:20]} -> |x+1|x|x|>> -reduce(<<{[4:1:15] x [4:1:15] x [4:1:15], [4:1:15] x [20:2:25] x [4:1:15]} ↦ 1*x+0|1*x-3|3*x+0, {[4:1:15] x [15:5:50] x [20:2:25], [20:2:25] x [40:5:45] x [40:5:45]} ↦ 2*x+0|1*x+0|4*x+4>>) - --> <<{[4:15]x[4:15]x[4:15], [4:15]x[20:2:24]x[4:15]} -> |x|x-3|3x|, {[4:15]x[15:5:50]x[20:2:24], [20:2:24]x[40:5:45]x[40:5:45]} -> |2x|x|4x+4|>> - diff --git a/test/interval.test b/test/interval.test index 48765e36..09eaabb5 100644 --- a/test/interval.test +++ b/test/interval.test @@ -24,16 +24,11 @@ isEmpty([100:1:5]); [201:2:399] /\ [200:4:400]; [300:1:1000000] /\ [300:1:500]; -minElem([500:5:499]); minElem([500:5:600]); -maxElem([500:5:499]); maxElem([500:5:600]); [1:1:100] == [1:1:100]; [1:2:100] == [1:1:100]; [2:1:100] == [1:1:100]; [1:1:101] == [1:1:100]; - -[1:1:100] < [5:5:50]; -[50:3:100] < [50:5:80]; diff --git a/test/matching1.test b/test/matching1.test index a8fdb789..1291dcf9 100644 --- a/test/matching1.test +++ b/test/matching1.test @@ -37,7 +37,7 @@ V: F \/ U Vmap: <<{[1:1:V1]} -> |0*x+1|, {[V1+1:1:V2]} -> |0*x+2|, {[V2+1:1:V3]} -> |0*x+3|>> map1: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b|>> map2: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d|>> -Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2], [E2+1:1:E3]} -> |0*x+2|>> +Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3|>> X: F Y: U; @@ -46,7 +46,7 @@ match( Vmap: <<{[1:1:V1]} -> |0*x+1|, {[V1+1:1:V2]} -> |0*x+2|, {[V2+1:1:V3]} -> |0*x+3|>> map1: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d|>> map2: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b|>> - Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2], [E2+1:1:E3]} -> |0*x+2|>> + Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3|>> X: F Y: U , 1 diff --git a/test/matching2.test b/test/matching2.test index aa2ec879..75fa95f3 100644 --- a/test/matching2.test +++ b/test/matching2.test @@ -35,7 +35,7 @@ V: F \/ U Vmap: <<{[1:1:V1]} -> |0*x+1|, {[V1+1:1:V2]} -> |0*x+2|, {[V2+1:1:V3]} -> |0*x+3|>> map1: <<{[1:1:E1]} -> |1*x+0|, {[E1+1:1:E2]} -> |1*x+0|, {[E2+1:1:E3]} -> |1*x-off3b|>> map2: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d|>> -Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2], [E2+1:1:E3]} -> |0*x+2|>> +Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3|>> X: F Y: U; @@ -44,7 +44,7 @@ match( Vmap: <<{[1:1:V1]} -> |0*x+1|, {[V1+1:1:V2]} -> |0*x+2|, {[V2+1:1:V3]} -> |0*x+3|>> map1: <<{[1:1:E1]} -> |1*x+0|, {[E1+1:1:E2]} -> |1*x+0|, {[E2+1:1:E3]} -> |1*x-off3b|>> map2: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d|>> - Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2], [E2+1:1:E3]} -> |0*x+2|>> + Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3|>> X: F Y: U , 1 diff --git a/test/matching3.test b/test/matching3.test index dd4346af..40175d08 100644 --- a/test/matching3.test +++ b/test/matching3.test @@ -37,27 +37,35 @@ F = {[9:1:9], [10:1:10], [11:1:11], [12:1:12]}; U = {[2:1:2], [3:1:3], [4:1:4], [5:1:5]}; V: F \/ U -Vmap: <<{[2:1:2]} -> |0*x+1|, {[3:1:3]} -> |0*x+2|, {[4:1:4]} -> |0*x+3|, {[5:1:5]} -> |0*x+4 - |, {[9:1:9]} -> |0*x+9|, {[10:1:10]} -> |0*x+10|, {[11:1:11]} -> |0*x+11|, {[12:1:12]} -> |0*x+12|>> -map1: <<{[1:1:1]} -> |1*x+9|, {[2:1:2]} -> |1*x+8|, {[3:1:3]} -> |1*x+8|, {[4:1:4]} -> |1*x+6|, {[5:1:5]} -> |1*x+4 - |, {[6:1:6]} -> |1*x+3|, {[7:1:7]} -> |1*x+2|, {[8:1:8]} -> |1*x+3|, {[9:1:9]} -> |1*x+3|, {[10:1:10]} -> |1*x+2|>> -map2: <<{[1:1:1]} -> |1*x+3|, {[2:1:2]} -> |1*x+1|, {[3:1:3]} -> |1*x-1|, {[4:1:4]} -> |1*x+1|, {[5:1:5]} -> |1*x+0 - |, {[6:1:6]} -> |1*x-2|, {[7:1:7]} -> |1*x-4|, {[8:1:8]} -> |1*x-5|, {[9:1:9]} -> |1*x-5|, {[10:1:10]} -> |1*x-8|>> -Emap: <<{[1:1:1]} -> |0*x+1|, {[2:1:2]} -> |0*x+2|, {[3:1:3]} -> |0*x+3|, {[4:1:4]} -> |0*x+4|, {[5:1:5]} -> |0*x+5 - |, {[6:1:6]} -> |0*x+6|, {[7:1:7]} -> |0*x+7|, {[8:1:8]} -> |0*x+8|, {[9:1:9]} -> |0*x+9|, {[10:1:10]} -> |0*x+10|>> +Vmap: <<{[2:1:2]} -> |0*x+1|, {[3:1:3]} -> |0*x+2|, {[4:1:4]} -> |0*x+3|, {[5:1:5]} -> |0*x+4| + , {[9:1:9]} -> |0*x+9|, {[10:1:10]} -> |0*x+10|, {[11:1:11]} -> |0*x+11| + , {[12:1:12]} -> |0*x+12|>> +map1: <<{[1:1:1]} -> |1*x+9|, {[2:1:2]} -> |1*x+8|, {[3:1:3]} -> |1*x+8|, {[4:1:4]} -> |1*x+6| + , {[5:1:5]} -> |1*x+4|, {[6:1:6]} -> |1*x+3|, {[7:1:7]} -> |1*x+2|, {[8:1:8]} -> |1*x+3| + , {[9:1:9]} -> |1*x+3|, {[10:1:10]} -> |1*x+2|>> +map2: <<{[1:1:1]} -> |1*x+3|, {[2:1:2]} -> |1*x+1|, {[3:1:3]} -> |1*x-1|, {[4:1:4]} -> |1*x+1| + , {[5:1:5]} -> |1*x+0|, {[6:1:6]} -> |1*x-2|, {[7:1:7]} -> |1*x-4|, {[8:1:8]} -> |1*x-5| + , {[9:1:9]} -> |1*x-5|, {[10:1:10]} -> |1*x-8|>> +Emap: <<{[1:1:1]} -> |0*x+1|, {[2:1:2]} -> |0*x+2|, {[3:1:3]} -> |0*x+3|, {[4:1:4]} -> |0*x+4| + , {[5:1:5]} -> |0*x+5|, {[6:1:6]} -> |0*x+6|, {[7:1:7]} -> |0*x+7|, {[8:1:8]} -> |0*x+8| + , {[9:1:9]} -> |0*x+9|, {[10:1:10]} -> |0*x+10|>> X: F Y: U; match( V: F \/ U - Vmap: <<{[2:1:2]} -> |0*x+1|, {[3:1:3]} -> |0*x+2|, {[4:1:4]} -> |0*x+3|, {[5:1:5]} -> |0*x+4 - |, {[9:1:9]} -> |0*x+9|, {[10:1:10]} -> |0*x+10|, {[11:1:11]} -> |0*x+11|, {[12:1:12]} -> |0*x+12|>> - map1: <<{[1:1:1]} -> |1*x+9|, {[2:1:2]} -> |1*x+8|, {[3:1:3]} -> |1*x+8|, {[4:1:4]} -> |1*x+6|, {[5:1:5]} -> |1*x+4 - |, {[6:1:6]} -> |1*x+3|, {[7:1:7]} -> |1*x+2|, {[8:1:8]} -> |1*x+3|, {[9:1:9]} -> |1*x+3|, {[10:1:10]} -> |1*x+2|>> - map2: <<{[1:1:1]} -> |1*x+3|, {[2:1:2]} -> |1*x+1|, {[3:1:3]} -> |1*x-1|, {[4:1:4]} -> |1*x+1|, {[5:1:5]} -> |1*x+0 - |, {[6:1:6]} -> |1*x-2|, {[7:1:7]} -> |1*x-4|, {[8:1:8]} -> |1*x-5|, {[9:1:9]} -> |1*x-5|, {[10:1:10]} -> |1*x-8|>> - Emap: <<{[1:1:1]} -> |0*x+1|, {[2:1:2]} -> |0*x+2|, {[3:1:3]} -> |0*x+3|, {[4:1:4]} -> |0*x+4|, {[5:1:5]} -> |0*x+5 - |, {[6:1:6]} -> |0*x+6|, {[7:1:7]} -> |0*x+7|, {[8:1:8]} -> |0*x+8|, {[9:1:9]} -> |0*x+9|, {[10:1:10]} -> |0*x+10|>> + Vmap: <<{[2:1:2]} -> |0*x+1|, {[3:1:3]} -> |0*x+2|, {[4:1:4]} -> |0*x+3|, {[5:1:5]} -> |0*x+4| + , {[9:1:9]} -> |0*x+9|, {[10:1:10]} -> |0*x+10|, {[11:1:11]} -> |0*x+11| + , {[12:1:12]} -> |0*x+12|>> + map1: <<{[1:1:1]} -> |1*x+9|, {[2:1:2]} -> |1*x+8|, {[3:1:3]} -> |1*x+8|, {[4:1:4]} -> |1*x+6| + , {[5:1:5]} -> |1*x+4|, {[6:1:6]} -> |1*x+3|, {[7:1:7]} -> |1*x+2|, {[8:1:8]} -> |1*x+3| + , {[9:1:9]} -> |1*x+3|, {[10:1:10]} -> |1*x+2|>> + map2: <<{[1:1:1]} -> |1*x+3|, {[2:1:2]} -> |1*x+1|, {[3:1:3]} -> |1*x-1|, {[4:1:4]} -> |1*x+1| + , {[5:1:5]} -> |1*x+0|, {[6:1:6]} -> |1*x-2|, {[7:1:7]} -> |1*x-4|, {[8:1:8]} -> |1*x-5| + , {[9:1:9]} -> |1*x-5|, {[10:1:10]} -> |1*x-8|>> + Emap: <<{[1:1:1]} -> |0*x+1|, {[2:1:2]} -> |0*x+2|, {[3:1:3]} -> |0*x+3|, {[4:1:4]} -> |0*x+4| + , {[5:1:5]} -> |0*x+5|, {[6:1:6]} -> |0*x+6|, {[7:1:7]} -> |0*x+7|, {[8:1:8]} -> |0*x+8| + , {[9:1:9]} -> |0*x+9|, {[10:1:10]} -> |0*x+10|>> X: F Y: U , 1 diff --git a/test/matching4.test b/test/matching4.test index 03cb5a61..6dd8bd21 100644 --- a/test/matching4.test +++ b/test/matching4.test @@ -48,27 +48,27 @@ F = {[1:1:F1], [F1+1:1:F2], [F2+1:1:F3]}; U = {[F3+1:1:U1], [U1+1:1:U2], [U2+1:1:U3]}; V: F \/ U -Vmap: <<{[1:1:F1]} -> |0*x+1|, {[F1+1:1:F2]} -> |0*x+2|, {[F2+1:1:F3]} -> |0*x+3 - |, {[F3+1:1:U1]} -> |0*x+10|, {[U1+1:1:U2]} -> |0*x+11|, {[U2+1:1:U3]} -> |0*x+12|>> -map1: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d - |, {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|, {[E5+1:1:E6]} -> |1*x+off6d|>> -map2: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b - |, {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b|>> -Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3 - |, {[E3+1:1:E4]} -> |0*x+4|, {[E4+1:1:E5]} -> |0*x+5|, {[E5+1:1:E6]} -> |0*x+6|>> +Vmap: <<{[1:1:F1]} -> |0*x+1|, {[F1+1:1:F2]} -> |0*x+2|, {[F2+1:1:F3]} -> |0*x+3| + , {[F3+1:1:U1]} -> |0*x+10|, {[U1+1:1:U2]} -> |0*x+11|, {[U2+1:1:U3]} -> |0*x+12|>> +map1: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d| + , {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|, {[E5+1:1:E6]} -> |1*x+off6d|>> +map2: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b| + , {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b|>> +Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3| + , {[E3+1:1:E4]} -> |0*x+4|, {[E4+1:1:E5]} -> |0*x+5|, {[E5+1:1:E6]} -> |0*x+6|>> X: F Y: U; match( V: F \/ U - Vmap: <<{[1:1:F1]} -> |0*x+1|, {[F1+1:1:F2]} -> |0*x+2|, {[F2+1:1:F3]} -> |0*x+3 - |, {[F3+1:1:U1]} -> |0*x+10|, {[U1+1:1:U2]} -> |0*x+11|, {[U2+1:1:U3]} -> |0*x+12|>> - map1: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d - |, {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|, {[E5+1:1:E6]} -> |1*x+off6d|>> - map2: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b - |, {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b|>> - Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3 - |, {[E3+1:1:E4]} -> |0*x+4|, {[E4+1:1:E5]} -> |0*x+5|, {[E5+1:1:E6]} -> |0*x+6|>> + Vmap: <<{[1:1:F1]} -> |0*x+1|, {[F1+1:1:F2]} -> |0*x+2|, {[F2+1:1:F3]} -> |0*x+3| + , {[F3+1:1:U1]} -> |0*x+10|, {[U1+1:1:U2]} -> |0*x+11|, {[U2+1:1:U3]} -> |0*x+12|>> + map1: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d| + , {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|, {[E5+1:1:E6]} -> |1*x+off6d|>> + map2: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b| + , {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b|>> + Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3| + , {[E3+1:1:E4]} -> |0*x+4|, {[E4+1:1:E5]} -> |0*x+5|, {[E5+1:1:E6]} -> |0*x+6|>> X: F Y: U , 1 diff --git a/test/matching5.test b/test/matching5.test index eaefe710..5fc75a7a 100644 --- a/test/matching5.test +++ b/test/matching5.test @@ -92,55 +92,55 @@ F = {[1:1:F1], [F1+1:1:F2], [F2+1:1:F3], [F3+1:1:F4], [F4+1:1:F5], [F5+1:1:F6] U = {[F9+1:1:U1], [U1+1:1:U2], [U2+1:1:U3]}; V: F \/ U -Vmap: <<{[1:1:F1]} -> |0*x+1|, {[F1+1:1:F2]} -> |0*x+2|, {[F2+1:1:F3]} -> |0*x+3 - |, {[F3+1:1:F4]} -> |0*x+4|, {[F4+1:1:F5]} -> |0*x+5|, {[F5+1:1:F6]} -> |0*x+6 - |, {[F6+1:1:F7]}-> |0*x+7|, {[F7+1:1:F8]} -> |0*x+8|, {[F8+1:1:F9]} -> |0*x+9 - |, {[F9+1:1:U1]} -> |0*x+10|, {[U1+1:1:U2]} -> |0*x+11|, {[U2+1:1:U3]} -> |0*x+12|>> -map1: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d - |, {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|, {[E5+1:1:E6]} -> |1*x+off6d - |, {[E6+1:1:E7]} -> |1*x+off7d|, {[E7+1:1:E8]} -> |1*x+off8d|, {[E8+1:1:E9]} -> |1*x+off9d - |, {[E9+1:1:E10]} -> |1*x+off10d|, {[E10+1:1:E11]} -> |1*x+off11d|, {[E11+1:1:E12]} -> |1*x+off12d - |, {[E12+1:1:E13]} -> |1*x+off13d|, {[E13+1:1:E14]} -> |1*x+off14d|, {[E14+1:1:E15]} -> |1*x+off15d - |, {[E15+1:1:E16]} -> |1*x+off16d|>> -map2: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b - |, {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b - |, {[E6+1:1:E7]} -> |1*x+off7b|, {[E7+1:1:E8]} -> |1*x+off8b|, {[E8+1:1:E9]} -> |1*x+off9b - |, {[E9+1:1:E10]} -> |1*x+off10b|, {[E10+1:1:E11]} -> |1*x+off11b|, {[E11+1:1:E12]} -> |1*x+off12b - |, {[E12+1:1:E13]} -> |1*x+off13b|, {[E13+1:1:E14]} -> |1*x+off14b|, {[E14+1:1:E15]} -> |1*x+off15b - |, {[E15+1:1:E16]} -> |1*x+off16b|>> -Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3], [E3+1:1:E4]} -> |0*x+3 - |, {[E4+1:1:E5]} -> |0*x+4|, {[E5+1:1:E6]} -> |0*x+5 - |, {[E6+1:1:E7]} -> |0*x+6|, {[E7+1:1:E8]} -> |0*x+7|, {[E8+1:1:E9]} -> |0*x+8 - |, {[E9+1:1:E10]} -> |0*x+9|, {[E10+1:1:E11]} -> |0*x+10|, {[E11+1:1:E12]} -> |0*x+11 - |, {[E12+1:1:E13], [E13+1:1:E14]} -> |0*x+12|, {[E14+1:1:E15]} -> |0*x+13 - |, {[E15+1:1:E16]} -> |0*x+14|>> +Vmap: <<{[1:1:F1]} -> |0*x+1|, {[F1+1:1:F2]} -> |0*x+2|, {[F2+1:1:F3]} -> |0*x+3| + , {[F3+1:1:F4]} -> |0*x+4|, {[F4+1:1:F5]} -> |0*x+5|, {[F5+1:1:F6]} -> |0*x+6| + , {[F6+1:1:F7]}-> |0*x+7|, {[F7+1:1:F8]} -> |0*x+8|, {[F8+1:1:F9]} -> |0*x+9| + , {[F9+1:1:U1]} -> |0*x+10|, {[U1+1:1:U2]} -> |0*x+11|, {[U2+1:1:U3]} -> |0*x+12|>> +map1: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d| + , {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|, {[E5+1:1:E6]} -> |1*x+off6d| + , {[E6+1:1:E7]} -> |1*x+off7d|, {[E7+1:1:E8]} -> |1*x+off8d|, {[E8+1:1:E9]} -> |1*x+off9d| + , {[E9+1:1:E10]} -> |1*x+off10d|, {[E10+1:1:E11]} -> |1*x+off11d|, {[E11+1:1:E12]} -> |1*x+off12d| + , {[E12+1:1:E13]} -> |1*x+off13d|, {[E13+1:1:E14]} -> |1*x+off14d|, {[E14+1:1:E15]} -> |1*x+off15d| + , {[E15+1:1:E16]} -> |1*x+off16d|>> +map2: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b| + , {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b| + , {[E6+1:1:E7]} -> |1*x+off7b|, {[E7+1:1:E8]} -> |1*x+off8b|, {[E8+1:1:E9]} -> |1*x+off9b| + , {[E9+1:1:E10]} -> |1*x+off10b|, {[E10+1:1:E11]} -> |1*x+off11b|, {[E11+1:1:E12]} -> |1*x+off12b| + , {[E12+1:1:E13]} -> |1*x+off13b|, {[E13+1:1:E14]} -> |1*x+off14b|, {[E14+1:1:E15]} -> |1*x+off15b| + , {[E15+1:1:E16]} -> |1*x+off16b|>> +Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3| + , {[E3+1:1:E4]} -> |0*x+4|, {[E4+1:1:E5]} -> |0*x+5|, {[E5+1:1:E6]} -> |0*x+6| + , {[E6+1:1:E7]} -> |0*x+7|, {[E7+1:1:E8]} -> |0*x+8|, {[E8+1:1:E9]} -> |0*x+9| + , {[E9+1:1:E10]} -> |0*x+10|, {[E10+1:1:E11]} -> |0*x+11|, {[E11+1:1:E12]} -> |0*x+12| + , {[E12+1:1:E13]} -> |0*x+13|, {[E13+1:1:E14]} -> |0*x+14|, {[E14+1:1:E15]} -> |0*x+15| + , {[E15+1:1:E16]} -> |0*x+16|>> X: F Y: U; match( V: F \/ U - Vmap: <<{[1:1:F1]} -> |0*x+1|, {[F1+1:1:F2]} -> |0*x+2|, {[F2+1:1:F3]} -> |0*x+3 - |, {[F3+1:1:F4]} -> |0*x+4|, {[F4+1:1:F5]} -> |0*x+5|, {[F5+1:1:F6]} -> |0*x+6 - |, {[F6+1:1:F7]}-> |0*x+7|, {[F7+1:1:F8]} -> |0*x+8|, {[F8+1:1:F9]} -> |0*x+9 - |, {[F9+1:1:U1]} -> |0*x+10|, {[U1+1:1:U2]} -> |0*x+11|, {[U2+1:1:U3]} -> |0*x+12|>> - map1: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d - |, {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|, {[E5+1:1:E6]} -> |1*x+off6d - |, {[E6+1:1:E7]} -> |1*x+off7d|, {[E7+1:1:E8]} -> |1*x+off8d|, {[E8+1:1:E9]} -> |1*x+off9d - |, {[E9+1:1:E10]} -> |1*x+off10d|, {[E10+1:1:E11]} -> |1*x+off11d|, {[E11+1:1:E12]} -> |1*x+off12d - |, {[E12+1:1:E13]} -> |1*x+off13d|, {[E13+1:1:E14]} -> |1*x+off14d|, {[E14+1:1:E15]} -> |1*x+off15d - |, {[E15+1:1:E16]} -> |1*x+off16d|>> - map2: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b - |, {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b - |, {[E6+1:1:E7]} -> |1*x+off7b|, {[E7+1:1:E8]} -> |1*x+off8b|, {[E8+1:1:E9]} -> |1*x+off9b - |, {[E9+1:1:E10]} -> |1*x+off10b|, {[E10+1:1:E11]} -> |1*x+off11b|, {[E11+1:1:E12]} -> |1*x+off12b - |, {[E12+1:1:E13]} -> |1*x+off13b|, {[E13+1:1:E14]} -> |1*x+off14b|, {[E14+1:1:E15]} -> |1*x+off15b - |, {[E15+1:1:E16]} -> |1*x+off16b|>> - Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3], [E3+1:1:E4]} -> |0*x+3 - |, {[E4+1:1:E5]} -> |0*x+4|, {[E5+1:1:E6]} -> |0*x+5 - |, {[E6+1:1:E7]} -> |0*x+6|, {[E7+1:1:E8]} -> |0*x+7|, {[E8+1:1:E9]} -> |0*x+8 - |, {[E9+1:1:E10]} -> |0*x+9|, {[E10+1:1:E11]} -> |0*x+10|, {[E11+1:1:E12]} -> |0*x+11 - |, {[E12+1:1:E13], [E13+1:1:E14]} -> |0*x+12|, {[E14+1:1:E15]} -> |0*x+13 - |, {[E15+1:1:E16]} -> |0*x+14|>> + Vmap: <<{[1:1:F1]} -> |0*x+1|, {[F1+1:1:F2]} -> |0*x+2|, {[F2+1:1:F3]} -> |0*x+3| + , {[F3+1:1:F4]} -> |0*x+4|, {[F4+1:1:F5]} -> |0*x+5|, {[F5+1:1:F6]} -> |0*x+6| + , {[F6+1:1:F7]}-> |0*x+7|, {[F7+1:1:F8]} -> |0*x+8|, {[F8+1:1:F9]} -> |0*x+9| + , {[F9+1:1:U1]} -> |0*x+10|, {[U1+1:1:U2]} -> |0*x+11|, {[U2+1:1:U3]} -> |0*x+12|>> + map1: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d| + , {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|, {[E5+1:1:E6]} -> |1*x+off6d| + , {[E6+1:1:E7]} -> |1*x+off7d|, {[E7+1:1:E8]} -> |1*x+off8d|, {[E8+1:1:E9]} -> |1*x+off9d| + , {[E9+1:1:E10]} -> |1*x+off10d|, {[E10+1:1:E11]} -> |1*x+off11d|, {[E11+1:1:E12]} -> |1*x+off12d| + , {[E12+1:1:E13]} -> |1*x+off13d|, {[E13+1:1:E14]} -> |1*x+off14d|, {[E14+1:1:E15]} -> |1*x+off15d| + , {[E15+1:1:E16]} -> |1*x+off16d|>> + map2: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b| + , {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b| + , {[E6+1:1:E7]} -> |1*x+off7b|, {[E7+1:1:E8]} -> |1*x+off8b|, {[E8+1:1:E9]} -> |1*x+off9b| + , {[E9+1:1:E10]} -> |1*x+off10b|, {[E10+1:1:E11]} -> |1*x+off11b|, {[E11+1:1:E12]} -> |1*x+off12b| + , {[E12+1:1:E13]} -> |1*x+off13b|, {[E13+1:1:E14]} -> |1*x+off14b|, {[E14+1:1:E15]} -> |1*x+off15b| + , {[E15+1:1:E16]} -> |1*x+off16b|>> + Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3| + , {[E3+1:1:E4]} -> |0*x+4|, {[E4+1:1:E5]} -> |0*x+5|, {[E5+1:1:E6]} -> |0*x+6| + , {[E6+1:1:E7]} -> |0*x+7|, {[E7+1:1:E8]} -> |0*x+8|, {[E8+1:1:E9]} -> |0*x+9| + , {[E9+1:1:E10]} -> |0*x+10|, {[E10+1:1:E11]} -> |0*x+11|, {[E11+1:1:E12]} -> |0*x+12| + , {[E12+1:1:E13]} -> |0*x+13|, {[E13+1:1:E14]} -> |0*x+14|, {[E14+1:1:E15]} -> |0*x+15| + , {[E15+1:1:E16]} -> |0*x+16|>> X: F Y: U , 1 diff --git a/test/matching6.test b/test/matching6.test index f3a10382..fdff0695 100644 --- a/test/matching6.test +++ b/test/matching6.test @@ -91,28 +91,28 @@ F = {[1:1:F1], [F1+1:1:F2], [F2+1:1:F3], [F3+1:1:F4], [F4+1:1:F5], [F5+1:1:F6] U = {[F9+1:1:U1], [U1+1:1:U2], [U2+1:1:U3]}; V: F \/ U -Vmap: <<{[1:1:F1]} -> |0*x+1|, {[F1+1:1:F2]} -> |0*x+2|, {[F2+1:1:F3]} -> |0*x+3 - |, {[F3+1:1:F4]} -> |0*x+4|, {[F4+1:1:F5]} -> |0*x+5|, {[F5+1:1:F6]} -> |0*x+6 - |, {[F6+1:1:F7]}-> |0*x+7|, {[F7+1:1:F8]} -> |0*x+8|, {[F8+1:1:F9]} -> |0*x+9 - |, {[F9+1:1:U1]} -> |0*x+10|, {[U1+1:1:U2]} -> |0*x+11|, {[U2+1:1:U3]} -> |0*x+12|>> -map1: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d - |, {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|, {[E5+1:1:E6]} -> |1*x+off6d - |, {[E6+1:1:E7]} -> |1*x+off7d|, {[E7+1:1:E8]} -> |1*x+off8d|, {[E8+1:1:E9]} -> |1*x+off9d - |, {[E9+1:1:E10]} -> |1*x+off10d|, {[E10+1:1:E11]} -> |1*x+off11d|, {[E11+1:1:E12]} -> |1*x+off12d - |, {[E12+1:1:E13]} -> |1*x+off13d|, {[E13+1:1:E14]} -> |1*x+off14d|, {[E14+1:1:E15]} -> |1*x+off15d - |, {[E15+1:1:E16]} -> |1*x+off16d|>> -map2: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b - |, {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b - |, {[E6+1:1:E7]} -> |1*x+off7b|, {[E7+1:1:E8]} -> |1*x+off8b|, {[E8+1:1:E9]} -> |1*x+off9b - |, {[E9+1:1:E10]} -> |1*x+off10b|, {[E10+1:1:E11]} -> |1*x+off11b|, {[E11+1:1:E12]} -> |1*x+off12b - |, {[E12+1:1:E13]} -> |1*x+off13b|, {[E13+1:1:E14]} -> |1*x+off14b|, {[E14+1:1:E15]} -> |1*x+off15b - |, {[E15+1:1:E16]} -> |1*x+off16b|>> -Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3], [E3+1:1:E4]} -> |0*x+3 - |, {[E4+1:1:E5]} -> |0*x+4|, {[E5+1:1:E6]} -> |0*x+5 - |, {[E6+1:1:E7]} -> |0*x+6|, {[E7+1:1:E8]} -> |0*x+7|, {[E8+1:1:E9]} -> |0*x+8 - |, {[E9+1:1:E10]} -> |0*x+9|, {[E10+1:1:E11]} -> |0*x+10|, {[E11+1:1:E12]} -> |0*x+11 - |, {[E12+1:1:E13], [E13+1:1:E14]} -> |0*x+12|, {[E14+1:1:E15]} -> |0*x+13 - |, {[E15+1:1:E16]} -> |0*x+14|>> +Vmap: <<{[1:1:F1]} -> |0*x+1|, {[F1+1:1:F2]} -> |0*x+2|, {[F2+1:1:F3]} -> |0*x+3| + , {[F3+1:1:F4]} -> |0*x+4|, {[F4+1:1:F5]} -> |0*x+5|, {[F5+1:1:F6]} -> |0*x+6| + , {[F6+1:1:F7]}-> |0*x+7|, {[F7+1:1:F8]} -> |0*x+8|, {[F8+1:1:F9]} -> |0*x+9| + , {[F9+1:1:U1]} -> |0*x+10|, {[U1+1:1:U2]} -> |0*x+11|, {[U2+1:1:U3]} -> |0*x+12|>> +map1: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d| + , {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|, {[E5+1:1:E6]} -> |1*x+off6d| + , {[E6+1:1:E7]} -> |1*x+off7d|, {[E7+1:1:E8]} -> |1*x+off8d|, {[E8+1:1:E9]} -> |1*x+off9d| + , {[E9+1:1:E10]} -> |1*x+off10d|, {[E10+1:1:E11]} -> |1*x+off11d|, {[E11+1:1:E12]} -> |1*x+off12d| + , {[E12+1:1:E13]} -> |1*x+off13d|, {[E13+1:1:E14]} -> |1*x+off14d|, {[E14+1:1:E15]} -> |1*x+off15d| + , {[E15+1:1:E16]} -> |1*x+off16d|>> +map2: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b| + , {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b| + , {[E6+1:1:E7]} -> |1*x+off7b|, {[E7+1:1:E8]} -> |1*x+off8b|, {[E8+1:1:E9]} -> |1*x+off9b| + , {[E9+1:1:E10]} -> |1*x+off10b|, {[E10+1:1:E11]} -> |1*x+off11b|, {[E11+1:1:E12]} -> |1*x+off12b| + , {[E12+1:1:E13]} -> |1*x+off13b|, {[E13+1:1:E14]} -> |1*x+off14b|, {[E14+1:1:E15]} -> |1*x+off15b| + , {[E15+1:1:E16]} -> |1*x+off16b|>> +Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3| + , {[E3+1:1:E4]} -> |0*x+4|, {[E4+1:1:E5]} -> |0*x+5|, {[E5+1:1:E6]} -> |0*x+6| + , {[E6+1:1:E7]} -> |0*x+7|, {[E7+1:1:E8]} -> |0*x+8|, {[E8+1:1:E9]} -> |0*x+9| + , {[E9+1:1:E10]} -> |0*x+10|, {[E10+1:1:E11]} -> |0*x+11|, {[E11+1:1:E12]} -> |0*x+12| + , {[E12+1:1:E13]} -> |0*x+13|, {[E13+1:1:E14]} -> |0*x+14|, {[E14+1:1:E15]} -> |0*x+15| + , {[E15+1:1:E16]} -> |0*x+16|>> X: F Y: U; @@ -134,12 +134,12 @@ match( |, {[E9+1:1:E10]} -> |1*x+off10b|, {[E10+1:1:E11]} -> |1*x+off11b|, {[E11+1:1:E12]} -> |1*x+off12b |, {[E12+1:1:E13]} -> |1*x+off13b|, {[E13+1:1:E14]} -> |1*x+off14b|, {[E14+1:1:E15]} -> |1*x+off15b |, {[E15+1:1:E16]} -> |1*x+off16b|>> - Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3], [E3+1:1:E4]} -> |0*x+3 - |, {[E4+1:1:E5]} -> |0*x+4|, {[E5+1:1:E6]} -> |0*x+5 - |, {[E6+1:1:E7]} -> |0*x+6|, {[E7+1:1:E8]} -> |0*x+7|, {[E8+1:1:E9]} -> |0*x+8 - |, {[E9+1:1:E10]} -> |0*x+9|, {[E10+1:1:E11]} -> |0*x+10|, {[E11+1:1:E12]} -> |0*x+11 - |, {[E12+1:1:E13], [E13+1:1:E14]} -> |0*x+12|, {[E14+1:1:E15]} -> |0*x+13 - |, {[E15+1:1:E16]} -> |0*x+14|>> + Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3| + , {[E3+1:1:E4]} -> |0*x+4|, {[E4+1:1:E5]} -> |0*x+5|, {[E5+1:1:E6]} -> |0*x+6| + , {[E6+1:1:E7]} -> |0*x+7|, {[E7+1:1:E8]} -> |0*x+8|, {[E8+1:1:E9]} -> |0*x+9| + , {[E9+1:1:E10]} -> |0*x+10|, {[E10+1:1:E11]} -> |0*x+11|, {[E11+1:1:E12]} -> |0*x+12| + , {[E12+1:1:E13]} -> |0*x+13|, {[E13+1:1:E14]} -> |0*x+14|, {[E14+1:1:E15]} -> |0*x+15| + , {[E15+1:1:E16]} -> |0*x+16|>> X: F Y: U , 1 diff --git a/test/matching7.test b/test/matching7.test index feaf8b46..a84f61a4 100644 --- a/test/matching7.test +++ b/test/matching7.test @@ -29,14 +29,14 @@ F = {[1:1:V1], [V1+1:1:V2], [V2+1:1:V3]}; U = {[V3+1:1:V4]}; V: F \/ U -Vmap: <<{[1:1:V1]} -> |0*x+1|, {[V1+1:1:V2]} -> |0*x+2|, {[V2+1:1:V3]} -> |0*x+3 - |, {[V3+1:1:V4]} -> |0*x+4|>> -map1: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b - |, {[E3+1:1:E4]} -> |1*x+off4b|>> -map2: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d - |, {[E3+1:1:E4]} -> |1*x+off4d|>> -Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2 - |, {[E2+1:1:E3], [E3+1:1:E4]} -> |0*x+3|>> +Vmap: <<{[1:1:V1]} -> |0*x+1|, {[V1+1:1:V2]} -> |0*x+2|, {[V2+1:1:V3]} -> |0*x+3| + , {[V3+1:1:V4]} -> |0*x+4|>> +map1: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b| + , {[E3+1:1:E4]} -> |1*x+off4b|>> +map2: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d| + , {[E3+1:1:E4]} -> |1*x+off4d|>> +Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3| + , {[E3+1:1:E4]} -> |0*x+4|>> X: F Y: U; @@ -48,8 +48,8 @@ match( |, {[E3+1:1:E4]} -> |1*x+off4b|>> map2: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d |, {[E3+1:1:E4]} -> |1*x+off4d|>> - Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2 - |, {[E2+1:1:E3], [E3+1:1:E4]} -> |0*x+3|>> + Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3| + , {[E3+1:1:E4]} -> |0*x+4|>> X: F Y: U , 1 diff --git a/test/parser/gt_data/interval.log b/test/parser/gt_data/interval.log index 9ac73f97..dfe308c1 100755 --- a/test/parser/gt_data/interval.log +++ b/test/parser/gt_data/interval.log @@ -20,14 +20,10 @@ isEmpty([100:1:5]); [1:2:20]/\[2:2:20]; [201:2:399]/\[200:4:400]; [300:1:1000000]/\[300:1:500]; -minElem([500:5:499]); minElem([500:5:600]); -maxElem([500:5:499]); maxElem([500:5:600]); [1:1:100]==[1:1:100]; [1:2:100]==[1:1:100]; [2:1:100]==[1:1:100]; [1:1:101]==[1:1:100]; -[1:1:100]<[5:5:50]; -[50:3:100]<[50:5:80]; diff --git a/test/performance/CMakeLists.txt b/test/performance/CMakeLists.txt index dbb8a683..20af5a35 100644 --- a/test/performance/CMakeLists.txt +++ b/test/performance/CMakeLists.txt @@ -1,11 +1,19 @@ -# SBG Benchmark for different Set and PWMap implementations -add_executable(sbg-benchmark benchmark_main.cpp) +# SBG Benchmark for different Set, PWMap, and SBG algorithms implementations +add_executable(sbg-benchmark main.cpp) target_sources(sbg-benchmark PRIVATE - benchmark_main.cpp - dom_ord_pwmap_bm.cpp - ord_set_bm.cpp) + boost/boost_bm.cpp + boost/scalar_graph.cpp + boost/scalar_graph_builder.cpp + boost/scc_graph_builder.cpp + main.cpp + bm_exec.cpp + matching_bm.cpp + pwmap_bm.cpp + scc_bm.cpp + set_bm.cpp + utils.cpp) set_target_properties(sbg-benchmark PROPERTIES RUNTIME_OUTPUT_DIRECTORY @@ -23,7 +31,3 @@ target_link_libraries(sbg-benchmark PRIVATE sbg-dev sbg-eval-lib) - -add_subdirectory(boost) -add_subdirectory(matching) -add_subdirectory(scc) diff --git a/test/performance/bm_exec.cpp b/test/performance/bm_exec.cpp new file mode 100644 index 00000000..f3c7d8c9 --- /dev/null +++ b/test/performance/bm_exec.cpp @@ -0,0 +1,200 @@ +/******************************************************************************* + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "test/performance/bm_exec.hpp" +#include "algorithms/matching/matching_impl.hpp" +#include "algorithms/scc/scc_impl.hpp" +#include "eval/user_impl_map.hpp" +#include "sbg/pwmap_impl.hpp" +#include "sbg/set_impl.hpp" +#include "test/performance/boost/boost_bm.hpp" +#include "test/performance/matching_bm.hpp" +#include "test/performance/pwmap_bm.hpp" +#include "test/performance/scc_bm.hpp" +#include "test/performance/set_bm.hpp" +#include "util/debug.hpp" +#include "util/user_input_handler.hpp" + +#include + +#include +#include +#include +#include + +namespace SBG { + +namespace perf { + +namespace detail { + +//////////////////////////////////////////////////////////////////////////////// +// Auxiliary functions --------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +void printHeader(Util::prog_opts::variables_map vm) +{ + if (vm.count("debug")) { + std::cout << "-----------------------------------\n"; + std::cout << "Set implementation: " << LIB::SET_IMPL.kind() << "\n"; + std::cout << "PWMap implementation: " << LIB::PWMAP_IMPL.kind() << "\n"; + std::cout << "-----------------------------------\n"; + std::cout << "Matching algorithm: " << LIB::MATCH_IMPL.kind() << "\n"; + std::cout << "SCC algorithm: " << LIB::SCC_IMPL.kind() << "\n\n"; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Benchmark Executor ---------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +BMExecutor::BMExecutor() + : _benchmark(0), _set_impl(0), _pw_impl(0), _scc_impl(1) +{ + _config.add_options() + ("benchmark,b", Util::prog_opts::value(&_benchmark), + "Desired benchmark:" + "\n - 0 for set benchmark" + "\n - 1 for PWMap benchmark" + "\n - 2 for matching benchmark" + "\n - 3 for SCC benchmark") + ("set_impl,s", Util::prog_opts::value(&_set_impl), + " Desired set implementation:" + "\n - 0 for unordered sets (default option)" + "\n - 1 for ordered sets" + "\n - 2 for unidimensional ordered dense sets") + ("pw_impl,p", Util::prog_opts::value(&_pw_impl), + " Desired PWMap implementation:" + "\n - 0 for unordered PWMaps (default option)" + "\n - 1 for ordered PWMaps" + "\n - 2 for domain ordered PWMaps") + ("scc_impl", Util::prog_opts::value(&_scc_impl), + "Desired SCC algorithm implementation:" + "\n - 0 for V1 of minimum reachable SCC" + "\n - 1 for V2 of minimum reachable SCC (default option)") + ("boost", "Executes Boost Graph Library algorithms for scalar graphs"); + + _positional.add("input-file", 1); + _cmd_line_opts.add(_generic).add(_config).add(_hidden); + _cfg_file_opts.add(_config).add(_hidden); + _visible.add(_generic).add(_config); +} + +void BMExecutor::execute(int argc, char* argv[]) +{ + // Command line options handling --------------------------------------------- + + Util::prog_opts::variables_map vm; + store(Util::prog_opts::command_line_parser(argc, argv) + .options(_cmd_line_opts).positional(_positional).allow_unregistered().run() + , vm); + notify(vm); + + // Help handling ------------------------------------------------------------- + + if (vm.count("help")) { + std::cout << "Usage: [input-file] [options]\n"; + std::cout << "Command line options are prioritized over configuration file" + " options."; + std::cout << _visible << "\n"; + return; + } + + // Version handling ---------------------------------------------------------- + + if (vm.count("version")) { + Util::version(); + return; + } + + // Optional configuration file handling -------------------------------------- + + if (_config_file) { + std::ifstream config_fs{(*_config_file).c_str()}; + if (config_fs) { + store(parse_config_file(config_fs, _cfg_file_opts), vm); + notify(vm); + } + } + + // Benchmark execution ------------------------------------------------------- + + SBG::Eval::setSetFactory(*_set_impl); + SBG::Eval::setPWFactory(*_pw_impl); + SBG::Eval::setSCCFactory(*_scc_impl); + printHeader(vm); + + if (vm.count("boost")) { + if (_input_file) { + registerBoostBenchmarks(*_input_file); + } else { + Util::ERROR("BoostExecutor: must provide a SBG program filename to run " + , "Boost benchmark\n"); + } + } else { + switch (*_benchmark) { + case 0: { + registerSetBenchmarks(); + break; + } + + case 1: { + registerPWMapBenchmarks(); + break; + } + + case 2: { + if (_input_file) { + registerMatchingBenchmarks(*_input_file); + } else { + registerMatchingBenchmarks(); + } + break; + } + + case 3: { + if (_input_file) { + registerSCCBenchmarks(*_input_file); + } else { + registerSCCBenchmarks(); + } + break; + } + + default: { + break; + } + } + } + + Util::prog_opts::parsed_options parsed + = Util::prog_opts::command_line_parser(argc, argv).options(_cmd_line_opts) + .allow_unregistered().run(); + std::vector to_pass_further + = Util::prog_opts::collect_unrecognized(parsed.options + , Util::prog_opts::exclude_positional); + ::benchmark::Initialize(&argc, argv); + ::benchmark::RunSpecifiedBenchmarks(); +} + +} // namespace detail + +} // namespace perf + +} // namespace SBG diff --git a/test/performance/bm_exec.hpp b/test/performance/bm_exec.hpp new file mode 100644 index 00000000..286ee284 --- /dev/null +++ b/test/performance/bm_exec.hpp @@ -0,0 +1,54 @@ +/** @file bm_exec.hpp + + @brief Executor for benchmarks + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_TEST_PERFORMANCE_BM_EXEC_HPP_ +#define SBGRAPH_TEST_PERFORMANCE_BM_EXEC_HPP_ + +#include "util/user_input_handler.hpp" + +namespace SBG { + +namespace perf { + +namespace detail { + +class BMExecutor : public Util::UserInputHandler { +public: + BMExecutor(); + + void execute(int arg_count, char* args[]) override; + +private: + boost::optional _benchmark; + boost::optional _set_impl; + boost::optional _pw_impl; + boost::optional _scc_impl; +}; + +} // namespace detail + +} // namespace perf + +} // namespace SBG + +#endif // SBGRAPH_TEST_PERFORMANCE_BM_EXEC_HPP_ diff --git a/test/performance/boost/CMakeLists.txt b/test/performance/boost/CMakeLists.txt deleted file mode 100644 index 6a924b80..00000000 --- a/test/performance/boost/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -# Custom Boost Benchmark -add_executable(custom-boost-benchmark) -target_sources(custom-boost-benchmark - PRIVATE - custom_boost_bm.cpp - ordinary_graph.cpp - ordinary_graph_builder.cpp - scc_graph_builder.cpp - ../utils.cpp) -target_link_libraries(custom-boost-benchmark - PUBLIC - benchmark::benchmark - PRIVATE - sbg-dev - sbg-eval-lib) -set_target_properties(custom-boost-benchmark - PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${BIN_DIR}) diff --git a/test/performance/boost/boost_bm.cpp b/test/performance/boost/boost_bm.cpp new file mode 100644 index 00000000..34d005e2 --- /dev/null +++ b/test/performance/boost/boost_bm.cpp @@ -0,0 +1,136 @@ +/***************************************************************************** + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "test/performance/boost/boost_bm.hpp" +#include "sbg/bipartite_sbg.hpp" +#include "test/performance/boost/scalar_graph.hpp" +#include "test/performance/boost/scalar_graph_builder.hpp" +#include "test/performance/boost/scc_graph_builder.hpp" +#include "test/performance/utils.hpp" + +#include +#include +#include + +namespace SBG { + +namespace perf { + +namespace detail { + +//////////////////////////////////////////////////////////////////////////////// +// Benchmarks ------------------------------------------------------------------ +//////////////////////////////////////////////////////////////////////////////// + +static void BM_BoostMatching(benchmark::State& state, std::string filename) +{ + int N = state.range(0); + + LIB::BipartiteSBG match_sbg = generateSBG(filename, N, 1); + ScalarGraphBuilder graph_builder(match_sbg); + BipartiteGraph bgraph = graph_builder.build(); + const Graph& match_graph = bgraph.graph(); + int number_vertices = num_vertices(match_graph); + for (auto _ : state) { + VertexVector matching(number_vertices); + edmonds_maximum_cardinality_matching(match_graph, &matching[0]); + benchmark::DoNotOptimize(matching); + } + + state.SetComplexityN(N); +} + +static void BM_BoostSCC(benchmark::State& state + , std::string filename) +{ + int N = state.range(0); + + LIB::BipartiteSBG match_sbg = generateSBG(filename, N, 1); + ScalarGraphBuilder graph_builder(match_sbg); + BipartiteGraph bgraph = graph_builder.build(); + const Graph& match_graph = bgraph.graph(); + VertexVector matching(num_vertices(match_graph)); + edmonds_maximum_cardinality_matching(match_graph, &matching[0]); + + SCCGraphBuilder scc_builder(std::move(bgraph), std::move(matching)); + DirectedGraph scc_graph = scc_builder.build(); + for (auto _ : state) { + std::vector components(num_vertices(scc_graph)); + benchmark::DoNotOptimize(strong_components(scc_graph, &components[0])); + } + state.SetComplexityN(N); +} + +static void BM_BoostSCCWithBuilder(benchmark::State& state + , std::string filename) +{ + int N = state.range(0); + + LIB::BipartiteSBG match_sbg = generateSBG(filename, N, 1); + ScalarGraphBuilder graph_builder(match_sbg); + BipartiteGraph bgraph = graph_builder.build(); + const Graph& match_graph = bgraph.graph(); + VertexVector matching(num_vertices(match_graph)); + edmonds_maximum_cardinality_matching(match_graph, &matching[0]); + + SCCGraphBuilder scc_builder(std::move(bgraph), std::move(matching)); + for (auto _ : state) { + DirectedGraph scc_graph = scc_builder.build(); + std::vector components(num_vertices(scc_graph)); + benchmark::DoNotOptimize(strong_components(scc_graph, &components[0])); + } + state.SetComplexityN(N); +} + +//////////////////////////////////////////////////////////////////////////////// +// Register Benchmarks --------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +void registerBoostBenchmarks(std::string filename) +{ + benchmark::RegisterBenchmark( + ("BM_BoostMatching/" + filename).c_str(), + [filename](benchmark::State& state) { + BM_BoostMatching(state, filename); + } + )->RangeMultiplier(10)->Range(100, 1e6)->Complexity() + ->Unit(benchmark::kMillisecond); + + benchmark::RegisterBenchmark( + ("BM_BoostSCC/" + filename).c_str(), + [filename](benchmark::State& state) { + BM_BoostSCC(state, filename); + } + )->RangeMultiplier(10)->Range(100, 1e6)->Complexity() + ->Unit(benchmark::kMillisecond); + + benchmark::RegisterBenchmark( + ("BM_BoostSCCWithBuilder/" + filename).c_str(), + [filename](benchmark::State& state) { + BM_BoostSCCWithBuilder(state, filename); + } + )->RangeMultiplier(10)->Range(100, 1e6)->Complexity() + ->Unit(benchmark::kMillisecond); +} + +} // namespace detail + +} // namespace perf + +} // namespace SBG diff --git a/test/performance/boost/boost_bm.hpp b/test/performance/boost/boost_bm.hpp new file mode 100644 index 00000000..1480cf9c --- /dev/null +++ b/test/performance/boost/boost_bm.hpp @@ -0,0 +1,50 @@ +/** @file boost_bm.hpp + + @brief Boost Benchmark + + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_TEST_PERFORMANCE_BOOST_BOOST_BM_HPP_ +#define SBGRAPH_TEST_PERFORMANCE_BOOST_BOOST_BM_HPP_ + +#include + +namespace SBG { + +namespace perf { + +namespace detail { + +/** + * @brief Registers for execution the SBG matching benchmark of the desired + * test file. The benchmark first increaseas the value of N, which is the size + * of repetitive patterns in the original SBG. Then, taking the original value + * of N, it copies the SBG to increase the number of repetitive patterns. + */ +void registerBoostBenchmarks(std::string filename); + +} // namespace detail + +} // namespace perf + +} // namespace SBG + +#endif // SBGRAPH_TEST_PERFORMANCE_BOOST_BOOST_BM_HPP_ diff --git a/test/performance/boost/custom_boost_bm.cpp b/test/performance/boost/custom_boost_bm.cpp deleted file mode 100644 index d6768927..00000000 --- a/test/performance/boost/custom_boost_bm.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/***************************************************************************** - - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -/** - * @file custom_boost_bm.cpp - * @brief Executes the scalar causalization workflow for the desired file. - * @note The input .test file should define a variable N that describes the - * "size" of the repetitive patterns of the graph. - */ - -#include - -#include -#include -#include - -#include "eval/user_impl_map.hpp" -#include "test/performance/boost/ordinary_graph_builder.hpp" -#include "test/performance/boost/scc_graph_builder.hpp" -#include "test/performance/utils.hpp" -#include "util/defs.hpp" -#include "util/time_profiler.hpp" - -namespace Test { - -namespace Internal { - -int lower = 100; -int mult = 10; -int upper = 1e6; -std::unordered_map input_graphs; - -/** - * @brief Creates single instances of the input bipartite graph of size N, - * varying N accordingly. - */ -void initialize(const char *filename) -{ - input_graphs.reserve(upper/lower); - for (int N = lower; N <= upper; N *= mult) { - SBG::LIB::BipartiteSBG match_sbg = generateSBG(filename, N, 1); - OG::OrdinaryGraphBuilder graph_builder(match_sbg); - OG::BipartiteGraph bgraph = graph_builder.build(); - input_graphs[N] = bgraph; - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Benchmarks ------------------------------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -static void BM_CustomBoostMatch(benchmark::State& state) -{ - int N = state.range(0); - - OG::BipartiteGraph& bgraph = input_graphs[N]; - const OG::Graph& match_graph = bgraph.graph(); - int number_vertices = num_vertices(match_graph); - - for (auto _ : state) { - OG::VertexVector matching(number_vertices); - edmonds_maximum_cardinality_matching(match_graph, &matching[0]); - } - state.SetComplexityN(N); -} -BENCHMARK(BM_CustomBoostMatch)->RangeMultiplier(mult) - ->Range(lower, upper)->Complexity()->Unit(benchmark::kMillisecond); - -static void BM_CustomBoostSCC(benchmark::State& state) -{ - int N = state.range(0); - - OG::BipartiteGraph& bgraph = input_graphs[N]; - const OG::Graph& match_graph = bgraph.graph(); - OG::VertexVector matching(num_vertices(match_graph)); - edmonds_maximum_cardinality_matching(match_graph, &matching[0]); - OG::SCCGraphBuilder scc_builder(std::move(bgraph), std::move(matching)); - OG::DirectedGraph scc_graph = scc_builder.build(); - - for (auto _ : state) { - std::vector components(num_vertices(scc_graph)); - strong_components(scc_graph, &components[0]); - } - state.SetComplexityN(N); -} -BENCHMARK(BM_CustomBoostSCC)->RangeMultiplier(mult) - ->Range(lower, upper)->Complexity()->Unit(benchmark::kMillisecond); - -static void BM_CustomBoostSCCWithBuilder(benchmark::State& state) -{ - int N = state.range(0); - - OG::BipartiteGraph& bgraph = input_graphs[N]; - const OG::Graph& match_graph = bgraph.graph(); - OG::VertexVector matching(num_vertices(match_graph)); - edmonds_maximum_cardinality_matching(match_graph, &matching[0]); - OG::SCCGraphBuilder scc_builder(std::move(bgraph), std::move(matching)); - - for (auto _ : state) { - OG::DirectedGraph scc_graph = scc_builder.build(); - std::vector components(num_vertices(scc_graph)); - strong_components(scc_graph, &components[0]); - } - state.SetComplexityN(N); -} -BENCHMARK(BM_CustomBoostSCCWithBuilder)->RangeMultiplier(mult) - ->Range(lower, upper)->Complexity()->Unit(benchmark::kMillisecond); - -} // namespace Internal - -} // namespace Test - -//////////////////////////////////////////////////////////////////////////////// -// Main ------------------------------------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -int main(int argc, char *argv[]) -{ - const char *filename = std::getenv("TEST_FILE"); - if (filename) { - Test::Internal::initialize(filename); - - ::benchmark::Initialize(&argc, argv); - ::benchmark::RunSpecifiedBenchmarks(); - } - - return 0; -} diff --git a/test/performance/boost/ordinary_graph_builder.cpp b/test/performance/boost/ordinary_graph_builder.cpp deleted file mode 100644 index ae5d841b..00000000 --- a/test/performance/boost/ordinary_graph_builder.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/***************************************************************************** - - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -#include "test/performance/boost/ordinary_graph_builder.hpp" -#include "util/time_profiler.hpp" - -namespace OG { - -//////////////////////////////////////////////////////////////////////////////// -// Auxiliary functions --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -static SBG::LIB::MD_NAT nextElem(SBG::LIB::MD_NAT curr, SBG::LIB::SetPiece mdi) -{ - SBG::LIB::MD_NAT min = mdi.minElem(); - SBG::LIB::MD_NAT max = mdi.maxElem(); - SBG::LIB::MD_NAT res; - for (unsigned int j = 0; j < mdi.arity(); ++j) { - if (curr[j] == max[j]) { - res.emplaceBack(min[j]); - } else { - res.emplaceBack(curr[j] + 1); - for (unsigned int k = 1; k < mdi.arity() - j; ++k) { - res.emplaceBack(curr[j + k]); - } - break; - } - } - - return res; -} - -//////////////////////////////////////////////////////////////////////////////// -// Ordinary undirected graph builder ------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -OrdinaryGraphBuilder::OrdinaryGraphBuilder(SBG::LIB::BipartiteSBG bsbg) - : _bsbg(bsbg), _vertex_map(), _partition() {} - -BipartiteGraph OrdinaryGraphBuilder::build() -{ - translateVertices(); - EdgeVector edges = getEdgeList(); - Graph graph(edges.begin(), edges.end(), _bsbg.V().cardinal()); - return BipartiteGraph(std::move(graph), std::move(_partition)); -} - -BipartiteGraph OrdinaryGraphBuilder::build(SBG::LIB::NAT number_vertices - , EdgeVector& E, std::vector&& partition) -{ - Graph graph(E.begin(), E.end(), number_vertices); - return BipartiteGraph(std::move(graph), std::move(_partition)); -} - -void OrdinaryGraphBuilder::translateVertices() -{ - SBG::LIB::Set V = _bsbg.V(); - _partition.reserve(V.cardinal()); - SBG::LIB::Set X = _bsbg.X(); - SBG::LIB::NAT count = 0; - for (const SBG::LIB::SetPiece& mdi : V) { - SBG::LIB::MD_NAT begin = mdi.minElem(), end = mdi.maxElem(); - for (auto it = begin; it != end; it = nextElem(it, mdi)) { - _vertex_map[it] = count; - _partition.emplace_back( - SBG::LIB::SET_FACT.createSet(it).intersection(X).isEmpty()); - ++count; - } - _vertex_map[end] = count; - _partition.emplace_back( - SBG::LIB::SET_FACT.createSet(end).intersection(X).isEmpty()); - ++count; - } -} - -EdgeVector OrdinaryGraphBuilder::getEdgeList() -{ - EdgeVector result; - const SBG::LIB::Set& E = _bsbg.E(); - result.reserve(E.cardinal()); - - const SBG::LIB::PWMap& map1 = _bsbg.map1(); - const SBG::LIB::PWMap& map2 = _bsbg.map2(); - for (const SBG::LIB::SetPiece& mdi : E) { - SBG::LIB::MD_NAT begin = mdi.minElem(), end = mdi.maxElem(); - for (auto it = begin; it != end; it = nextElem(it, mdi)) { - // Get endings of edge - SBG::LIB::SetPiece it_mdi(it); - SBG::LIB::Set dom = SBG::LIB::SET_FACT.createSet(it_mdi); - Vertex v1 = _vertex_map[map1.image(dom).minElem()]; - Vertex v2 = _vertex_map[map2.image(dom).minElem()]; - result.emplace_back(Edge(v1, v2)); - } - SBG::LIB::SetPiece end_mdi(end); - SBG::LIB::Set end_dom = SBG::LIB::SET_FACT.createSet(end_mdi); - Vertex end_v1 = _vertex_map[map1.image(end_dom).minElem()]; - Vertex end_v2 = _vertex_map[map2.image(end_dom).minElem()]; - result.emplace_back(Edge(end_v1, end_v2)); - } - - return result; -} - -} // namespace OG diff --git a/test/performance/boost/ordinary_graph.cpp b/test/performance/boost/scalar_graph.cpp similarity index 94% rename from test/performance/boost/ordinary_graph.cpp rename to test/performance/boost/scalar_graph.cpp index abb93fbc..0d1bc73b 100644 --- a/test/performance/boost/ordinary_graph.cpp +++ b/test/performance/boost/scalar_graph.cpp @@ -17,9 +17,13 @@ ******************************************************************************/ -#include +#include -namespace OG { +namespace SBG { + +namespace perf { + +namespace detail { // Graph ----------------------------------------------------------------------- @@ -92,4 +96,8 @@ std::ostream& operator<<(std::ostream& out, const DirectedGraph& dgraph) return out; } -} // namespace OG +} // namespace detail + +} // namespace perf + +} // namespace SBG diff --git a/test/performance/boost/ordinary_graph.hpp b/test/performance/boost/scalar_graph.hpp similarity index 84% rename from test/performance/boost/ordinary_graph.hpp rename to test/performance/boost/scalar_graph.hpp index 22b92aad..7f979035 100644 --- a/test/performance/boost/ordinary_graph.hpp +++ b/test/performance/boost/scalar_graph.hpp @@ -1,6 +1,6 @@ -/** @file ordinary_graph.hpp +/** @file scalar_graph.hpp - @brief Ordinary Graph + @brief Scalar Graph Module that defines the structure for scalar graphs. @@ -23,14 +23,18 @@ ******************************************************************************/ -#ifndef PERF_ORDINARY_GRAPH_HPP -#define PERF_ORDINARY_GRAPH_HPP +#ifndef SBGRAPH_TEST_PERFORMANCE_BOOST_SCALAR_GRAPH_HPP_ +#define SBGRAPH_TEST_PERFORMANCE_BOOST_SCALAR_GRAPH_HPP_ + +#include "sbg/natural.hpp" #include -#include "sbg/natural.hpp" +namespace SBG { -namespace OG { +namespace perf { + +namespace detail { using Vertex = SBG::LIB::NAT; using VertexVector = std::vector; @@ -65,6 +69,10 @@ using DirectedGraph = boost::adjacency_list; std::ostream& operator<<(std::ostream& out, const DirectedGraph& dgraph); -} // namespace OG +} // namespace detail + +} // namespace perf + +} // namespace SBG -#endif +#endif // SBGRAPH_TEST_PERFORMANCE_BOOST_SCALAR_GRAPH_HPP_ diff --git a/test/performance/boost/scalar_graph_builder.cpp b/test/performance/boost/scalar_graph_builder.cpp new file mode 100644 index 00000000..97fcb967 --- /dev/null +++ b/test/performance/boost/scalar_graph_builder.cpp @@ -0,0 +1,114 @@ +/***************************************************************************** + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "sbg/multidim_inter.hpp" +#include "sbg/set_detail.hpp" +#include "test/performance/boost/scalar_graph_builder.hpp" +#include "util/time_profiler.hpp" + +#include + +namespace SBG { + +namespace perf { + +namespace detail { + +using SBG::LIB::NAT; +using SBG::LIB::MD_NAT; +using SBG::LIB::Set; +using SBG::LIB::detail::SetAccessKey; +using SBG::LIB::detail::SetAccess; +using SBG::LIB::detail::MaybeMD_NAT; +using SBG::LIB::PWMap; +using SBG::LIB::BipartiteSBG; + +//////////////////////////////////////////////////////////////////////////////// +// Scalar undirected graph builder --------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +ScalarGraphBuilder::ScalarGraphBuilder(BipartiteSBG bsbg) + : _bsbg(bsbg), _vertex_map(), _partition() {} + +BipartiteGraph ScalarGraphBuilder::build() +{ + translateVertices(); + EdgeVector edges = getEdgeList(); + Graph graph(edges.begin(), edges.end(), _bsbg.V().cardinal()); + return BipartiteGraph(std::move(graph), std::move(_partition)); +} + +BipartiteGraph ScalarGraphBuilder::build(NAT number_vertices + , EdgeVector& E, std::vector&& partition) +{ + Graph graph(E.begin(), E.end(), number_vertices); + return BipartiteGraph(std::move(graph), std::move(_partition)); +} + +void ScalarGraphBuilder::translateVertices() +{ + + Set V = _bsbg.V(); + if (V.isEmpty()) { + return; + } + + _partition.reserve(V.cardinal()); + Set X = _bsbg.X(); + + NAT count = 0; + SetAccessKey key = SetAccess::key(); + std::vector vertices = key.flatten(V); + for (const MD_NAT& v : vertices) { + _vertex_map[v] = count; + _partition.emplace_back( + SBG::LIB::Set{v}.intersection(X).isEmpty()); + ++count; + } +} + +EdgeVector ScalarGraphBuilder::getEdgeList() +{ + EdgeVector result; + const Set& E = _bsbg.E(); + if (E.isEmpty()) { + return result; + } + result.reserve(E.cardinal()); + + const PWMap& map1 = _bsbg.map1(); + const PWMap& map2 = _bsbg.map2(); + SetAccessKey key = SetAccess::key(); + std::vector edges = key.flatten(E); + for (const MD_NAT& e : edges) { + // Get endings of edge + Set domain = SBG::LIB::Set{e}; + Vertex v1 = _vertex_map[map1.image(domain).minElem()]; + Vertex v2 = _vertex_map[map2.image(domain).minElem()]; + result.emplace_back(v1, v2); + } + + return result; +} + +} // namespace detail + +} // namespace perf + +} // namespace SBG diff --git a/test/performance/boost/ordinary_graph_builder.hpp b/test/performance/boost/scalar_graph_builder.hpp similarity index 73% rename from test/performance/boost/ordinary_graph_builder.hpp rename to test/performance/boost/scalar_graph_builder.hpp index bbb18ec7..22ac3ef0 100644 --- a/test/performance/boost/ordinary_graph_builder.hpp +++ b/test/performance/boost/scalar_graph_builder.hpp @@ -1,6 +1,6 @@ /** @file ordinary_graph_builder.hpp - @brief Ordinary Graph Builder + @brief Scalar Graph Builder Module in charge of constructing the scalar graph used as input of the scalar causalization from a SBG. The generated result will be used as input of the @@ -25,20 +25,26 @@ ******************************************************************************/ -#ifndef PERF_ORDINARY_BUILDER_HPP -#define PERF_ORDINARY_BUILDER_HPP +#ifndef SBGRAPH_TEST_PERFORMANCE_BOOST_SCALAR_GRAPH_BUILDER_HPP_ +#define SBGRAPH_TEST_PERFORMANCE_BOOST_SCALAR_GRAPH_BUILDER_HPP_ -#include - -#include "test/performance/boost/ordinary_graph.hpp" #include "sbg/bipartite_sbg.hpp" +#include "sbg/natural.hpp" +#include "test/performance/boost/scalar_graph.hpp" #include "util/logger.hpp" -namespace OG { +#include +#include + +namespace SBG { -class OrdinaryGraphBuilder { - public: - OrdinaryGraphBuilder(SBG::LIB::BipartiteSBG bsbg); +namespace perf { + +namespace detail { + +class ScalarGraphBuilder { +public: + ScalarGraphBuilder(SBG::LIB::BipartiteSBG bsbg); BipartiteGraph build(); BipartiteGraph build(SBG::LIB::NAT number_vertices, EdgeVector& edges @@ -46,13 +52,17 @@ class OrdinaryGraphBuilder { void translateVertices(); EdgeVector getEdgeList(); - private: +private: const SBG::LIB::BipartiteSBG _bsbg; ///< Input bipartite SBG to convert std::map _vertex_map; ///< Map from SBG vertex identifier to Graph element std::vector _partition; }; -} // namespace OG +} // namespace detail + +} // namespace perf + +} // namespace SBG -#endif +#endif // SBGRAPH_TEST_PERFORMANCE_BOOST_SCALAR_GRAPH_BUILDER_HPP_ diff --git a/test/performance/boost/scc_graph_builder.cpp b/test/performance/boost/scc_graph_builder.cpp index 67edb074..bef93f9d 100644 --- a/test/performance/boost/scc_graph_builder.cpp +++ b/test/performance/boost/scc_graph_builder.cpp @@ -19,7 +19,16 @@ #include "test/performance/boost/scc_graph_builder.hpp" -namespace OG { +#include +#include + +#include + +namespace SBG { + +namespace perf { + +namespace detail { //////////////////////////////////////////////////////////////////////////////// // Auxiliary structures -------------------------------------------------------- @@ -103,4 +112,8 @@ EdgeVector SCCGraphBuilder::getEdgeList() return result; } -} // namespace OG +} // namespace detail + +} // namespace perf + +} // namespace SBG diff --git a/test/performance/boost/scc_graph_builder.hpp b/test/performance/boost/scc_graph_builder.hpp index c749d632..9756674c 100644 --- a/test/performance/boost/scc_graph_builder.hpp +++ b/test/performance/boost/scc_graph_builder.hpp @@ -25,21 +25,26 @@ ******************************************************************************/ -#ifndef PERF_SCC_BUILDER_HPP -#define PERF_SCC_BUILDER_HPP +#ifndef SBGRAPH_TEST_PERFORMANCE_BOOST_SCC_GRAPH_BUILDER_HPP_ +#define SBGRAPH_TEST_PERFORMANCE_BOOST_SCC_GRAPH_BUILDER_HPP_ -#include +#include "sbg/natural.hpp" +#include "test/performance/boost/scalar_graph.hpp" -#include "test/performance/boost/ordinary_graph.hpp" -#include "util/logger.hpp" +#include -namespace OG { +namespace SBG { + +namespace perf { + +namespace detail { //////////////////////////////////////////////////////////////////////////////// // Auxiliary structures -------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -struct EdgeHash { +class EdgeHash { +public: std::size_t operator()(const Edge& e) const; }; @@ -56,7 +61,7 @@ struct EdgeHash { * and {X ∩ {u1, v1}, Y ∩ {u2, v2}} ∈ (E\M)}. */ class SCCGraphBuilder { - public: +public: SCCGraphBuilder(BipartiteGraph&& g, VertexVector&& matching); DirectedGraph build(); @@ -64,12 +69,16 @@ class SCCGraphBuilder { SBG::LIB::NAT translateVertices(); EdgeVector getEdgeList(); - private: +private: const BipartiteGraph _bgraph; ///< Input bipartite graph const VertexVector _matching; std::unordered_map _vertex_map; }; -} // namespace OG +} // namespace detail + +} // namespace perf + +} // namespace SBG -#endif +#endif // SBGRAPH_TEST_PERFORMANCE_BOOST_SCC_GRAPH_BUILDER_HPP_ diff --git a/test/performance/dom_ord_pwmap_bm.cpp b/test/performance/dom_ord_pwmap_bm.cpp deleted file mode 100644 index 3c91c3bc..00000000 --- a/test/performance/dom_ord_pwmap_bm.cpp +++ /dev/null @@ -1,463 +0,0 @@ -/***************************************************************************** - - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -#include - -#include "eval/user_impl_map.hpp" - -namespace Test { - -namespace Internal { - -using SBG::LIB::RATIONAL; -using SBG::LIB::Interval; -using SBG::LIB::SetPiece; -using SBG::LIB::Set; -using SBG::LIB::LExp; -using SBG::LIB::Exp; -using SBG::LIB::Map; -using SBG::LIB::PWMap; - -//////////////////////////////////////////////////////////////////////////////// -// Auxiliary functions --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -PWMap denseDom(SBG::LIB::NAT map_sz) -{ - SBG::LIB::NAT inter_sz = 100; - SBG::LIB::NAT set_sz = 10; - - PWMap pw = SBG::LIB::PW_FACT.createPWMap(); - for (unsigned int j = 0; j < map_sz; ++j) { - Set dom1 = SBG::LIB::SET_FACT.createSet(); - SBG::LIB::NAT off = j*set_sz*inter_sz; - for (unsigned int h = 0; h < set_sz; ++h) { - Interval i1(off + (h*inter_sz), 1, off + (h + 1)*inter_sz - 1); - SetPiece mdi1; - mdi1.emplaceBack(i1); - dom1.emplaceBack(mdi1); - } - - LExp id; - Exp multidim_id(1, id); - - pw.emplaceBack(Map(dom1, multidim_id)); - } - - return pw; -} - -PWMap mapInfPW(SBG::LIB::NAT map_sz) -{ - SBG::LIB::NAT inter_sz = 100; - SBG::LIB::NAT set_sz = 10; - - PWMap pw = SBG::LIB::PW_FACT.createPWMap(); - unsigned int j = 0; - for (; j < map_sz; ++j) { - Set dom1 = SBG::LIB::SET_FACT.createSet(); - SBG::LIB::NAT off = j*set_sz*inter_sz; - for (unsigned int h = 0; h < set_sz; ++h) { - Interval i1(off + (h*inter_sz), 1, off + (h + 1)*inter_sz - 1); - SetPiece mdi1; - mdi1.emplaceBack(i1); - dom1.emplaceBack(mdi1); - } - - Exp plus_one(1, LExp(1, 1)); - - pw.emplaceBack(Map(dom1, plus_one)); - } - - Set dom_id = SBG::LIB::SET_FACT.createSet(); - SBG::LIB::NAT off = j*set_sz*inter_sz; - for (unsigned int h = 0; h < set_sz; ++h) { - Interval i1(off + (h*inter_sz), 1, off + (h + 1)*inter_sz - 1); - SetPiece mdi1; - mdi1.emplaceBack(i1); - dom_id.emplaceBack(mdi1); - } - - Exp multidim_id(1, LExp()); - - pw.emplaceBack(Map(dom_id, multidim_id)); - - return pw; -} - -std::pair minAdjMaps(SBG::LIB::NAT map_sz) -{ - SBG::LIB::NAT inter_sz = 100; - SBG::LIB::NAT set_sz = 10; - - Interval second_dim(1, 1, inter_sz); - PWMap pw1 = SBG::LIB::PW_FACT.createPWMap(); - PWMap pw2 = SBG::LIB::PW_FACT.createPWMap(); - for (unsigned int j = 0; j < map_sz; ++j) { - Set dom1 = SBG::LIB::SET_FACT.createSet(); - Set dom2 = SBG::LIB::SET_FACT.createSet(); - SBG::LIB::NAT off = j*set_sz*inter_sz; - for (unsigned int h = 0; h < set_sz; ++h) { - Interval i1(off + (h*inter_sz), 1, off + (h + 1)*inter_sz - 1); - SetPiece mdi1; - mdi1.emplaceBack(i1); - mdi1.emplaceBack(second_dim); - dom1.emplaceBack(mdi1); - - SBG::LIB::NAT off2 = off + inter_sz/2; - Interval i2(off2 + (h*inter_sz), 1, off2 + (h + 1)*inter_sz - 1); - SetPiece mdi2; - mdi2.emplaceBack(i2); - mdi2.emplaceBack(second_dim); - dom2.emplaceBack(mdi2); - } - - Exp multidim_id(2, LExp()); - Exp minus_one(2, LExp(1, RATIONAL(-1, 1))); - - pw1.emplaceBack(Map(dom1, multidim_id)); - pw2.emplaceBack(Map(dom2, minus_one)); - } - - return {pw1, pw2}; -} - -std::pair interlacedMaps(SBG::LIB::NAT map_sz) -{ - SBG::LIB::NAT inter_sz = 100; - SBG::LIB::NAT set_sz = 10; - - Interval second_dim(0, 1, inter_sz - 1); - PWMap pw1 = SBG::LIB::PW_FACT.createPWMap(); - PWMap pw2 = SBG::LIB::PW_FACT.createPWMap(); - for (unsigned int j = 0; j < 2*map_sz; j += 2) { - Set dom1 = SBG::LIB::SET_FACT.createSet(); - Set dom2 = SBG::LIB::SET_FACT.createSet(); - SBG::LIB::NAT off = j*set_sz*inter_sz; - for (unsigned int h = 0; h < set_sz; ++h) { - Interval i1(off + (h*inter_sz), 1, off + (h + 1)*inter_sz - 1); - SetPiece mdi1; - mdi1.emplaceBack(i1); - mdi1.emplaceBack(second_dim); - dom1.emplaceBack(mdi1); - - SBG::LIB::NAT off2 = off + inter_sz; - Interval i2(off2 + (h*inter_sz), 1, off2 + (h + 1)*inter_sz - 1); - SetPiece mdi2; - mdi2.emplaceBack(i2); - mdi2.emplaceBack(second_dim); - dom2.emplaceBack(mdi2); - } - - LExp id; - Exp multidim_id(2, id); - - pw1.emplaceBack(Map(dom1, multidim_id)); - pw2.emplaceBack(Map(dom2, multidim_id)); - } - - return {pw1, pw2}; -} - -/* - * @brief Test suite created to analyze the time growth of the different domain - * ordered PWs operations. - */ -std::pair contiguousMaps(SBG::LIB::NAT map_sz) -{ - SBG::LIB::NAT inter_sz = 100; - SBG::LIB::NAT set_sz = 10; - - Interval second_dim(0, 1, inter_sz - 1); - PWMap pw1 = SBG::LIB::PW_FACT.createPWMap(); - PWMap pw2 = SBG::LIB::PW_FACT.createPWMap(); - for (unsigned int j = 0; j < map_sz; ++j) { - Set dom1 = SBG::LIB::SET_FACT.createSet(); - Set dom2 = SBG::LIB::SET_FACT.createSet(); - SBG::LIB::NAT off = j*set_sz*inter_sz; - for (unsigned int h = 0; h < set_sz; ++h) { - Interval i1(off + (h*inter_sz), 1, off + (h + 1)*inter_sz - 1); - SetPiece mdi1; - mdi1.emplaceBack(i1); - mdi1.emplaceBack(second_dim); - dom1.emplaceBack(mdi1); - - SBG::LIB::NAT off2 = off + inter_sz/2; - Interval i2(off2 + (h*inter_sz), 1, off2 + (h + 1)*inter_sz - 1); - SetPiece mdi2; - mdi2.emplaceBack(i2); - mdi2.emplaceBack(second_dim); - dom2.emplaceBack(mdi2); - } - - LExp id; - Exp multidim_id(2, id); - - pw1.emplaceBack(Map(dom1, multidim_id)); - pw2.emplaceBack(Map(dom2, multidim_id)); - } - - return {pw1, pw2}; -} - -//////////////////////////////////////////////////////////////////////////////// -// Benchmarks ------------------------------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -static void BM_DomOrdPWDenseDom(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::Eval::setSetFactory(2); - SBG::Eval::setPWFactory(2); - auto pw = denseDom(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw.dom()); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_DomOrdPWDenseDom)->RangeMultiplier(10)->Range(100, 1e5)->Complexity(); - -static void BM_DomOrdPWEq(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::Eval::setSetFactory(1); - SBG::Eval::setPWFactory(2); - auto [pw1, pw2] = contiguousMaps(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1 == pw2); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_DomOrdPWEq)->RangeMultiplier(10)->Range(10, 1e4)->Complexity(); - -static void BM_DomOrdPWSum(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::Eval::setSetFactory(1); - SBG::Eval::setPWFactory(2); - auto [pw1, pw2] = contiguousMaps(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1 + pw2); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_DomOrdPWSum)->RangeMultiplier(10)->Range(10, 1e5)->Complexity(); - -static void BM_DomOrdPWDom(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::Eval::setSetFactory(2); - SBG::Eval::setPWFactory(2); - auto [pw1, pw2] = contiguousMaps(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.dom()); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_DomOrdPWDom)->RangeMultiplier(10)->Range(100, 1e5)->Complexity(); - -static void BM_DomOrdPWRestrict(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::Eval::setSetFactory(1); - SBG::Eval::setPWFactory(2); - auto [pw1, pw2] = contiguousMaps(map_sz); - Set dom2 = pw2.dom(); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.restrict(dom2)); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_DomOrdPWRestrict)->RangeMultiplier(10)->Range(10, 1e4) - ->Complexity(); - -static void BM_DomOrdPWImage(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::Eval::setSetFactory(1); - SBG::Eval::setPWFactory(2); - auto [pw1, pw2] = contiguousMaps(map_sz); - Set dom2 = pw2.dom(); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.image(dom2)); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_DomOrdPWImage)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); - -static void BM_DomOrdPWPreImage(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::Eval::setSetFactory(1); - SBG::Eval::setPWFactory(2); - auto [pw1, pw2] = contiguousMaps(map_sz); - Set img2 = pw2.image(); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.preImage(img2)); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_DomOrdPWPreImage)->RangeMultiplier(10)->Range(10, 1e3) - ->Complexity(); - -static void BM_DomOrdPWComposition(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::Eval::setSetFactory(1); - SBG::Eval::setPWFactory(2); - auto [pw1, pw2] = contiguousMaps(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.composition(pw2)); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_DomOrdPWComposition)->RangeMultiplier(10)->Range(10, 1e3) - ->Complexity(); - -static void BM_DomOrdPWMapInf(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::Eval::setSetFactory(1); - SBG::Eval::setPWFactory(2); - auto pw = mapInfPW(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw.mapInf()); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_DomOrdPWMapInf)->RangeMultiplier(10)->Range(10, 1e2) - ->Complexity(); - -static void BM_DomOrdPWConcat(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::Eval::setSetFactory(1); - SBG::Eval::setPWFactory(2); - auto [pw1, pw2] = interlacedMaps(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.concatenation(pw2)); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_DomOrdPWConcat)->RangeMultiplier(10)->Range(10, 1e5)->Complexity(); - -static void BM_DomOrdPWCombine(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::Eval::setSetFactory(1); - SBG::Eval::setPWFactory(2); - auto [pw1, pw2] = contiguousMaps(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.combine(pw2)); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_DomOrdPWCombine)->RangeMultiplier(10)->Range(10, 1e4)->Complexity(); - -// TODO: reduce - -static void BM_DomOrdPWMinAdj(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::Eval::setSetFactory(1); - SBG::Eval::setPWFactory(2); - auto [pw1, pw2] = minAdjMaps(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.minAdjMap(pw2)); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_DomOrdPWMinAdj)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); - -static void BM_DomOrdPWFirstInv(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::Eval::setSetFactory(1); - SBG::Eval::setPWFactory(2); - auto [pw1, pw2] = contiguousMaps(map_sz); - Set dom2 = pw2.dom(); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.firstInv(dom2)); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_DomOrdPWFirstInv)->RangeMultiplier(10)->Range(10, 1e3) - ->Complexity(); - -static void BM_DomOrdPWEqImage(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::Eval::setSetFactory(1); - SBG::Eval::setPWFactory(2); - auto [pw1, pw2] = contiguousMaps(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.equalImage(pw2)); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_DomOrdPWEqImage)->RangeMultiplier(10)->Range(10, 1e4) - ->Complexity(); - -static void BM_DomOrdPWLessImage(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::Eval::setSetFactory(1); - SBG::Eval::setPWFactory(2); - auto [pw1, pw2] = contiguousMaps(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.lessImage(pw2)); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_DomOrdPWLessImage)->RangeMultiplier(10)->Range(10, 1e4) - ->Complexity(); - -static void BM_DomOrdPWCompact(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::Eval::setSetFactory(1); - SBG::Eval::setPWFactory(2); - auto [pw1, pw2] = contiguousMaps(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.compact()); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_DomOrdPWCompact)->RangeMultiplier(10)->Range(10, 1e3) - ->Complexity(); - -} // namespace Internal - -} // namespace Test diff --git a/test/performance/benchmark_main.cpp b/test/performance/main.cpp similarity index 83% rename from test/performance/benchmark_main.cpp rename to test/performance/main.cpp index b00160fb..84a57432 100644 --- a/test/performance/benchmark_main.cpp +++ b/test/performance/main.cpp @@ -17,6 +17,12 @@ ******************************************************************************/ -#include +#include "test/performance/bm_exec.hpp" -BENCHMARK_MAIN(); +int main(int argc, char *argv[]) +{ + SBG::perf::detail::BMExecutor bm_exec; + bm_exec.execute(argc, argv); + + return 0; +} diff --git a/test/performance/matching/CMakeLists.txt b/test/performance/matching/CMakeLists.txt deleted file mode 100644 index 7f803daf..00000000 --- a/test/performance/matching/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -# Matching Benchmark -add_executable(match-benchmark) -target_sources(match-benchmark - PRIVATE - ../benchmark_main.cpp - match_bm.cpp - ../utils.cpp) -target_link_libraries(match-benchmark - PRIVATE - benchmark::benchmark - sbg-dev - sbg-eval-lib) -set_target_properties(match-benchmark - PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${BIN_DIR}) -add_custom_target(run-match - COMMAND cd ${BIN_DIR} && ./match-benchmark -) -add_dependencies(run-match match-benchmark) - -# Custom Matching Benchmark -add_executable(custom-match-benchmark) -target_sources(custom-match-benchmark - PRIVATE - custom_match_bm.cpp - ../utils.cpp) -target_link_libraries(custom-match-benchmark - PRIVATE - benchmark::benchmark - sbg-dev - sbg-eval-lib) -set_target_properties(custom-match-benchmark - PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${BIN_DIR}) diff --git a/test/performance/matching/custom_match_bm.cpp b/test/performance/matching/custom_match_bm.cpp deleted file mode 100644 index 75c5aa42..00000000 --- a/test/performance/matching/custom_match_bm.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/***************************************************************************** - - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -/** - * @file custom_match_bm.cpp - * @brief Executes the SBG version of the matching algorithm for the desired - * file. It is used to showcase the constant execution time when the repetitive - * patterns increase its size. The final benchmark increases the number of - * repetitve patterns, copying the original graph several times. - * @note The input .test file should define a variable N that describes the - * "size" of the repetitive patterns of the graph. - */ - -#include - -#include "eval/user_impl_map.hpp" -#include "test/performance/utils.hpp" - -namespace Test { - -namespace Internal { - -//////////////////////////////////////////////////////////////////////////////// -// Auxiliary data -------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -int lower = 100; -int mult = 10; -int upper = 1e6; - -const char *filename = std::getenv("TEST_FILE"); - -//////////////////////////////////////////////////////////////////////////////// -// Benchmarks ------------------------------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -static void BM_CustomMatchTest(benchmark::State& state) -{ - int N = state.range(0); - - SBG::LIB::Matching match_algorithm - = SBG::LIB::MATCH_FACT.createMatchAlgorithm(); - SBG::LIB::BipartiteSBG match_sbg = generateSBG(filename, N, 1); - - for (auto _ : state) { - match_algorithm.calculate(match_sbg); - } - state.SetComplexityN(N); -} -BENCHMARK(BM_CustomMatchTest)->RangeMultiplier(10)->Range(lower, upper) - ->Complexity()->Unit(benchmark::kMillisecond); - -static void BM_CustomMatchCopies(benchmark::State& state) -{ - int N = state.range(0); - - SBG::LIB::Matching match_algorithm - = SBG::LIB::MATCH_FACT.createMatchAlgorithm(); - SBG::LIB::BipartiteSBG match_sbg = generateSBG(filename, 100, N); - - for (auto _ : state) { - match_algorithm.calculate(match_sbg); - } - state.SetComplexityN(N); -} -BENCHMARK(BM_CustomMatchCopies)->RangeMultiplier(2)->Range(1, 128) - ->Complexity()->Unit(benchmark::kMillisecond); - -} // namespace Internal - -} // namespace Test - -//////////////////////////////////////////////////////////////////////////////// -// Main ------------------------------------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -int main(int argc, char *argv[]) -{ - if (Test::Internal::filename) { - const char *set_impl = std::getenv("SET_IMPL"); - const char *pw_impl = std::getenv("PW_IMPL"); - SBG::Eval::setSetFactory(set_impl ? std::stoi(set_impl) : 1); - SBG::Eval::setPWFactory(pw_impl ? std::stoi(pw_impl) : 1); - - ::benchmark::Initialize(&argc, argv); - ::benchmark::RunSpecifiedBenchmarks(); - } - - return 0; -} diff --git a/test/performance/matching/match_bm.cpp b/test/performance/matching/match_bm.cpp deleted file mode 100644 index b257978c..00000000 --- a/test/performance/matching/match_bm.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/***************************************************************************** - - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -/** - * @file match_bm.cpp - * @brief Executes the SBG version of the matching algorithm for TestRL1.test - * , TestRL2.test and TestRL3.test. It is used to showcase the constant - * execution time when the repetitive patterns increase its size. - */ - -#include - -#include "eval/user_impl_map.hpp" -#include "test/performance/utils.hpp" - -namespace Test { - -namespace Internal { - -//////////////////////////////////////////////////////////////////////////////// -// Benchmarks ------------------------------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -static void BM_TestRL1(benchmark::State& state) -{ - int N = state.range(0); - SBG::Eval::setSetFactory(2); - SBG::Eval::setPWFactory(0); - - // Calculate Matching - SBG::LIB::Matching match_algorithm - = SBG::LIB::MATCH_FACT.createMatchAlgorithm(); - SBG::LIB::BipartiteSBG match_sbg = generateSBG("../../TestRL1.test", N, 1); - - for (auto _ : state) { - match_algorithm.calculate(match_sbg); - } - state.SetComplexityN(N); -} -BENCHMARK(BM_TestRL1)->RangeMultiplier(10)->Range(100, 1e6)->Complexity() - ->Unit(benchmark::kMillisecond); - -static void BM_TestRL2(benchmark::State& state) -{ - int N = state.range(0); - SBG::Eval::setSetFactory(2); - SBG::Eval::setPWFactory(0); - - // Calculate Matching - SBG::LIB::Matching match_algorithm - = SBG::LIB::MATCH_FACT.createMatchAlgorithm(); - SBG::LIB::BipartiteSBG match_sbg = generateSBG("../../TestRL2.test", N, 1); - - for (auto _ : state) { - match_algorithm.calculate(match_sbg); - } - - state.SetComplexityN(N); -} -BENCHMARK(BM_TestRL2)->RangeMultiplier(10)->Range(100, 1e6)->Complexity() - ->Unit(benchmark::kMillisecond); - -static void BM_TestRL3(benchmark::State& state) -{ - int N = state.range(0); - SBG::Eval::setSetFactory(2); - SBG::Eval::setPWFactory(1); - - // Calculate Matching - SBG::LIB::Matching match_algorithm - = SBG::LIB::MATCH_FACT.createMatchAlgorithm(); - SBG::LIB::BipartiteSBG match_sbg = generateSBG("../../TestRL3.test", N, 1); - - for (auto _ : state) { - match_algorithm.calculate(match_sbg); - } - state.SetComplexityN(N); -} -BENCHMARK(BM_TestRL3)->RangeMultiplier(10)->Range(100, 1e6)->Complexity() - ->Unit(benchmark::kMillisecond); - -static void BM_TestRL1Copies(benchmark::State& state) -{ - int N = state.range(0); - SBG::Eval::setSetFactory(2); - SBG::Eval::setPWFactory(2); - - // Calculate Matching - SBG::LIB::Matching match_algorithm - = SBG::LIB::MATCH_FACT.createMatchAlgorithm(); - SBG::LIB::BipartiteSBG match_sbg = generateSBG("../../TestRL1.test", 100, N); - - for (auto _ : state) { - match_algorithm.calculate(match_sbg); - } - state.SetComplexityN(N); -} -BENCHMARK(BM_TestRL1Copies)->RangeMultiplier(2)->Range(1, 128)->Complexity() - ->Unit(benchmark::kMillisecond); - -static void BM_TestRL2Copies(benchmark::State& state) -{ - int N = state.range(0); - SBG::Eval::setSetFactory(2); - SBG::Eval::setPWFactory(2); - - // Calculate Matching - SBG::LIB::Matching match_algorithm - = SBG::LIB::MATCH_FACT.createMatchAlgorithm(); - SBG::LIB::BipartiteSBG match_sbg = generateSBG("../../TestRL2.test", 100, N); - - for (auto _ : state) { - match_algorithm.calculate(match_sbg); - } - state.SetComplexityN(N); -} -BENCHMARK(BM_TestRL2Copies)->RangeMultiplier(2)->Range(1, 128)->Complexity() - ->Unit(benchmark::kMillisecond); - -static void BM_TestRL3Copies(benchmark::State& state) -{ - int N = state.range(0); - SBG::Eval::setSetFactory(2); - SBG::Eval::setPWFactory(2); - - // Calculate Matching - SBG::LIB::Matching match_algorithm - = SBG::LIB::MATCH_FACT.createMatchAlgorithm(); - SBG::LIB::BipartiteSBG match_sbg = generateSBG("../../TestRL3.test", 100, N); - - for (auto _ : state) { - match_algorithm.calculate(match_sbg); - } - state.SetComplexityN(N); -} -BENCHMARK(BM_TestRL3Copies)->RangeMultiplier(2)->Range(1, 128)->Complexity() - ->Unit(benchmark::kMillisecond); - -} // namespace Internal - -} // namespace Test diff --git a/test/performance/matching_bm.cpp b/test/performance/matching_bm.cpp new file mode 100644 index 00000000..09160885 --- /dev/null +++ b/test/performance/matching_bm.cpp @@ -0,0 +1,98 @@ +/***************************************************************************** + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "test/performance/matching_bm.hpp" +#include "algorithms/matching/matching.hpp" +#include "sbg/bipartite_sbg.hpp" +#include "test/performance/utils.hpp" + +#include + +namespace SBG { + +namespace perf { + +namespace detail { + +//////////////////////////////////////////////////////////////////////////////// +// Benchmarks ------------------------------------------------------------------ +//////////////////////////////////////////////////////////////////////////////// + +static void BM_Matching(benchmark::State& state, std::string filename) +{ + int N = state.range(0); + + SBG::LIB::Matching match_algorithm; + SBG::LIB::BipartiteSBG match_sbg = generateSBG(filename, N, 1); + for (auto _ : state) { + benchmark::DoNotOptimize(match_algorithm.calculate(match_sbg)); + } + + state.SetComplexityN(N); +} + +static void BM_MatchingCopies(benchmark::State& state, std::string filename) +{ + int N = state.range(0); + + // Calculate Matching + SBG::LIB::Matching match_algorithm; + SBG::LIB::BipartiteSBG match_sbg = generateSBG(filename, 100, N); + + for (auto _ : state) { + benchmark::DoNotOptimize(match_algorithm.calculate(match_sbg)); + } + state.SetComplexityN(N); +} + +//////////////////////////////////////////////////////////////////////////////// +// Register Benchmarks --------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +void registerMatchingBenchmarks(std::string filename) +{ + benchmark::RegisterBenchmark( + ("BM_Matching/" + filename).c_str(), + [filename](benchmark::State& state) { + BM_Matching(state, filename); + } + )->RangeMultiplier(10)->Range(100, 1e6)->Complexity() + ->Unit(benchmark::kMillisecond); + + benchmark::RegisterBenchmark( + ("BM_MatchingCopies/" + filename).c_str(), + [filename](benchmark::State& state) { + BM_MatchingCopies(state, filename); + } + )->RangeMultiplier(2)->Range(1, 128)->Complexity() + ->Unit(benchmark::kMillisecond); +} + +void registerMatchingBenchmarks() +{ + registerMatchingBenchmarks("../../TestRL1.test"); + registerMatchingBenchmarks("../../TestRL2.test"); + registerMatchingBenchmarks("../../TestRL3.test"); +} + +} // namespace detail + +} // namespace perf + +} // namespace SBG diff --git a/test/performance/matching_bm.hpp b/test/performance/matching_bm.hpp new file mode 100644 index 00000000..cc02272e --- /dev/null +++ b/test/performance/matching_bm.hpp @@ -0,0 +1,56 @@ +/** @file matching_bm.hpp + + @brief Matching Benchmark + + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_TEST_PERFORMANCE_MATCHING_BM_HPP_ +#define SBGRAPH_TEST_PERFORMANCE_MATCHING_BM_HPP_ + +#include + +namespace SBG { + +namespace perf { + +namespace detail { + +/** + * @brief Registers for execution the SBG matching benchmark of the desired + * test file. The benchmark first increaseas the value of N, which is the size + * of repetitive patterns in the original SBG. Then, taking the original value + * of N, it copies the SBG to increase the number of repetitive patterns. + */ +void registerMatchingBenchmarks(std::string filename); + +/** + * @brief Registers for execution the SBG matching benchmark of TestRL1.test + * , TestRL2.test and TestRL3.test, using the previous function. + */ +void registerMatchingBenchmarks(); + +} // namespace detail + +} // namespace perf + +} // namespace SBG + +#endif // SBGRAPH_TEST_PERFORMANCE_MATCHING_BM_HPP_ diff --git a/test/performance/ord_set_bm.cpp b/test/performance/ord_set_bm.cpp deleted file mode 100644 index 4b219108..00000000 --- a/test/performance/ord_set_bm.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/***************************************************************************** - - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -#include - -#include "eval/user_impl_map.hpp" - -namespace Test { - -namespace Internal { - -using SBG::LIB::Interval; -using SBG::LIB::SetPiece; -using SBG::LIB::Set; - -/** - * @brief Test suite created to analyze the time growth of the different ordered - * set operations. - */ -std::pair contiguousPieces(int set_sz) -{ - SBG::LIB::NAT inter_sz = 100; - - Interval second_dim(0, 1, inter_sz - 1); - Set s1 = SBG::LIB::SET_FACT.createSet(); - Set s2 = SBG::LIB::SET_FACT.createSet(); - for (unsigned int h = 0; h < set_sz; ++h) { - Interval i1(h*inter_sz, 1, (h + 1)*inter_sz - 1); - SetPiece mdi1; - mdi1.emplaceBack(i1); - mdi1.emplaceBack(second_dim); - s1.emplaceBack(mdi1); - - SBG::LIB::NAT off = inter_sz/2; - Interval i2(off + (h*inter_sz), 1, off + (h + 1)*inter_sz - 1); - SetPiece mdi2; - mdi2.emplaceBack(i2); - mdi2.emplaceBack(second_dim); - s2.emplaceBack(mdi2); - } - - return {s1, s2}; -} - -static void BM_OrdSetEq(benchmark::State& state) -{ - int set_sz = state.range(0); - SBG::Eval::setSetFactory(1); - auto [s1, s2] = contiguousPieces(set_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(s1 == s2); - } - state.SetComplexityN(set_sz); -} -BENCHMARK(BM_OrdSetEq)->RangeMultiplier(10)->Range(1000, 1e6)->Complexity(); - -static void BM_OrdSetCap(benchmark::State& state) -{ - int set_sz = state.range(0); - SBG::Eval::setSetFactory(1); - auto [s1, s2] = contiguousPieces(set_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(s1.intersection(s2)); - } - state.SetComplexityN(set_sz); -} -BENCHMARK(BM_OrdSetCap)->RangeMultiplier(10)->Range(1000, 1e6)->Complexity(); - -static void BM_OrdSetCup(benchmark::State& state) -{ - int set_sz = state.range(0); - SBG::Eval::setSetFactory(1); - auto [s1, s2] = contiguousPieces(set_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(s1.cup(s2)); - } - state.SetComplexityN(set_sz); -} -BENCHMARK(BM_OrdSetCup)->RangeMultiplier(10)->Range(1000, 1e6)->Complexity(); - -static void BM_OrdSetComplement(benchmark::State& state) -{ - int set_sz = state.range(0); - SBG::Eval::setSetFactory(1); - auto [s1, s2] = contiguousPieces(set_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(s1.complement()); - } - state.SetComplexityN(set_sz); -} -BENCHMARK(BM_OrdSetComplement)->RangeMultiplier(10)->Range(1000, 1e6) - ->Complexity(); - -static void BM_OrdSetDiff(benchmark::State& state) -{ - int set_sz = state.range(0); - SBG::Eval::setSetFactory(1); - auto [s1, s2] = contiguousPieces(set_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(s1.difference(s2)); - } - state.SetComplexityN(set_sz); -} -BENCHMARK(BM_OrdSetDiff)->RangeMultiplier(10)->Range(1000, 1e6)->Complexity(); - -static void BM_OrdSetDisjointUnion(benchmark::State& state) -{ - int set_sz = state.range(0); - SBG::Eval::setSetFactory(1); - Set s1 = SBG::LIB::SET_FACT.createSet(); - Set s2 = SBG::LIB::SET_FACT.createSet(); - for (SBG::LIB::NAT j = 0; j < set_sz; j += 2) { - Interval i(j*100 + 1, 1, (j + 1)*100); - s1.emplaceBack(i); - Interval i2((j + 1)*100+1, 1, (j + 2)*100); - s2.emplaceBack(i2); - } - - for (auto _ : state) { - benchmark::DoNotOptimize(s1.disjointCup(s2)); - } - state.SetComplexityN(set_sz); -} -BENCHMARK(BM_OrdSetDisjointUnion)->RangeMultiplier(10)->Range(1000, 1e6) - ->Complexity(); - -static void BM_OrdSetCompact(benchmark::State& state) -{ - int set_sz = state.range(0); - SBG::Eval::setSetFactory(1); - auto [s1, s2] = contiguousPieces(set_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(s1.compact()); - } - state.SetComplexityN(set_sz); -} -BENCHMARK(BM_OrdSetCompact)->RangeMultiplier(10)->Range(10, 1e3) - ->Complexity(); - -} // namespace Internal - -} // namespace Test diff --git a/test/performance/pwmap_bm.cpp b/test/performance/pwmap_bm.cpp new file mode 100644 index 00000000..377487ec --- /dev/null +++ b/test/performance/pwmap_bm.cpp @@ -0,0 +1,260 @@ +/***************************************************************************** + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "sbg/set.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/pwmap_detail.hpp" +#include "test/performance/utils.hpp" + +#include + +#include + +namespace SBG { + +namespace perf { + +namespace detail { + +using SBG::LIB::Set; + +//////////////////////////////////////////////////////////////////////////////// +// Benchmarks ------------------------------------------------------------------ +//////////////////////////////////////////////////////////////////////////////// + +static void BM_PWMapDenseDom(benchmark::State& state) +{ + int map_sz = state.range(0); + auto pw = denseDom(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw.domain()); + } + state.SetComplexityN(map_sz); +} + +static void BM_PWMapEq(benchmark::State& state) +{ + int map_sz = state.range(0); + auto [pw1, pw2] = nonDisjointMaps(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1 == pw2); + } + state.SetComplexityN(map_sz); +} + +static void BM_PWMapSum(benchmark::State& state) +{ + int map_sz = state.range(0); + auto [pw1, pw2] = nonDisjointMaps(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1 + pw2); + } + state.SetComplexityN(map_sz); +} + +static void BM_PWMapDom(benchmark::State& state) +{ + int map_sz = state.range(0); + auto [pw1, pw2] = nonDisjointMaps(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.domain()); + } + state.SetComplexityN(map_sz); +} + +static void BM_PWMapRestrict(benchmark::State& state) +{ + int map_sz = state.range(0); + auto [pw1, pw2] = nonDisjointMaps(map_sz); + Set domain2 = pw2.domain(); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.restrict(domain2)); + } + state.SetComplexityN(map_sz); +} + +static void BM_PWMapImage(benchmark::State& state) +{ + int map_sz = state.range(0); + auto [pw1, pw2] = nonDisjointMaps(map_sz); + Set domain2 = pw2.domain(); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.image(domain2)); + } + state.SetComplexityN(map_sz); +} + +static void BM_PWMapPreImage(benchmark::State& state) +{ + int map_sz = state.range(0); + auto [pw1, pw2] = nonDisjointMaps(map_sz); + Set img2 = pw2.image(); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.preImage(img2)); + } + state.SetComplexityN(map_sz); +} + +static void BM_PWMapComposition(benchmark::State& state) +{ + int map_sz = state.range(0); + auto [pw1, pw2] = nonDisjointMaps(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.composition(pw2)); + } + state.SetComplexityN(map_sz); +} + +static void BM_PWMapConcat(benchmark::State& state) +{ + int map_sz = state.range(0); + auto [pw1, pw2] = interlacedMaps(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.concatenation(pw2)); + } + state.SetComplexityN(map_sz); +} + +static void BM_PWMapCombine(benchmark::State& state) +{ + int map_sz = state.range(0); + auto [pw1, pw2] = nonDisjointMaps(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.combine(pw2)); + } + state.SetComplexityN(map_sz); +} + +static void BM_PWMapReduce(benchmark::State& state) +{ + int map_sz = state.range(0); + PWMap pw = reducibleMaps(map_sz); + + LIB::detail::PWMapAccessKey key = LIB::detail::PWMapAccess::key(); + for (auto _ : state) { + benchmark::DoNotOptimize(key.reduce(pw)); + } + state.SetComplexityN(map_sz); +} + +static void BM_PWMapMinAdj(benchmark::State& state) +{ + int map_sz = state.range(0); + auto [pw1, pw2] = minAdjMaps(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.minAdj(pw2)); + } + state.SetComplexityN(map_sz); +} + +static void BM_PWMapEqImage(benchmark::State& state) +{ + int map_sz = state.range(0); + auto [pw1, pw2] = nonDisjointMaps(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.equalImage(pw2)); + } + state.SetComplexityN(map_sz); +} + +static void BM_PWMapLessImage(benchmark::State& state) +{ + int map_sz = state.range(0); + auto [pw1, pw2] = nonDisjointMaps(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.lessImage(pw2)); + } + state.SetComplexityN(map_sz); +} + +static void BM_PWMapCompact(benchmark::State& state) +{ + int map_sz = state.range(0); + auto [pw1, pw2] = nonDisjointMaps(map_sz); + + for (auto _ : state) { + pw1.compact(); + benchmark::DoNotOptimize(pw1); + } + state.SetComplexityN(map_sz); +} + +//////////////////////////////////////////////////////////////////////////////// +// Register Benchmarks --------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +void registerPWMapBenchmarks() +{ + BENCHMARK(BM_PWMapDenseDom)->RangeMultiplier(10)->Range(10, 1e3) + ->Complexity(); + + BENCHMARK(BM_PWMapEq)->RangeMultiplier(10)->Range(10, 1e2)->Complexity(); + + BENCHMARK(BM_PWMapSum)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); + + BENCHMARK(BM_PWMapDom)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); + + BENCHMARK(BM_PWMapRestrict)->RangeMultiplier(10)->Range(10, 1e3) + ->Complexity(); + + BENCHMARK(BM_PWMapImage)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); + + BENCHMARK(BM_PWMapPreImage)->RangeMultiplier(10)->Range(10, 1e3) + ->Complexity(); + + BENCHMARK(BM_PWMapComposition)->RangeMultiplier(10)->Range(10, 1e3) + ->Complexity(); + + BENCHMARK(BM_PWMapConcat)->RangeMultiplier(10)->Range(10, 1e3) + ->Complexity(); + + BENCHMARK(BM_PWMapCombine)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); + + BENCHMARK(BM_PWMapReduce)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); + + BENCHMARK(BM_PWMapMinAdj)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); + + BENCHMARK(BM_PWMapEqImage)->RangeMultiplier(10)->Range(10, 1e3) + ->Complexity(); + + BENCHMARK(BM_PWMapLessImage)->RangeMultiplier(10)->Range(10, 1e3) + ->Complexity(); + + BENCHMARK(BM_PWMapCompact)->RangeMultiplier(10)->Range(10, 1e2) + ->Complexity(); +} + +} // namespace detail + +} // namespace perf + +} // namespace SBG diff --git a/test/performance/pwmap_bm.hpp b/test/performance/pwmap_bm.hpp new file mode 100644 index 00000000..e68f2c66 --- /dev/null +++ b/test/performance/pwmap_bm.hpp @@ -0,0 +1,41 @@ +/** @file pwmap_bm.hpp + + @brief PWMap Benchmark + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_TEST_PERFORMANCE_PWMAP_BM_HPP_ +#define SBGRAPH_TEST_PERFORMANCE_PWMAP_BM_HPP_ + +namespace SBG { + +namespace perf { + +namespace detail { + +void registerPWMapBenchmarks(); + +} // namespace detail + +} // namespace perf + +} // namespace SBG + +#endif // SBGRAPH_TEST_PERFORMANCE_PWMAP_BM_HPP_ diff --git a/test/performance/scc/CMakeLists.txt b/test/performance/scc/CMakeLists.txt deleted file mode 100644 index 87cc05fc..00000000 --- a/test/performance/scc/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -# SCC Benchmark -add_executable(scc-benchmark) -target_sources(scc-benchmark - PRIVATE - ../benchmark_main.cpp - scc_bm.cpp - ../utils.cpp) -target_link_libraries(scc-benchmark - PRIVATE - benchmark::benchmark - sbg-dev - sbg-eval-lib) -set_target_properties(scc-benchmark - PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${BIN_DIR}) -add_custom_target(run-scc - COMMAND cd ${BIN_DIR} && ./scc-benchmark -) -add_dependencies(run-scc scc-benchmark) - -# Custom SCC Benchmark -add_executable(custom-scc-benchmark) -target_sources(custom-scc-benchmark - PRIVATE - custom_scc_bm.cpp - ../utils.cpp) -target_link_libraries(custom-scc-benchmark - PRIVATE - benchmark::benchmark - sbg-dev - sbg-eval-lib) -set_target_properties(custom-scc-benchmark - PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${BIN_DIR}) diff --git a/test/performance/scc/custom_scc_bm.cpp b/test/performance/scc/custom_scc_bm.cpp deleted file mode 100644 index 257b2903..00000000 --- a/test/performance/scc/custom_scc_bm.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/***************************************************************************** - - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -/** - * @file custom_scc_bm.cpp - * @brief Executes the SBG version of the SCC algorithm for the desired file. It - * is used to showcase the constant execution time when the repetitive patterns - * increase its size. The final benchmark increases the number of repetitve - * patterns, copying the original graph several times. - * @note The input .test file should define a variable N that describes the - * "size" of the repetitive patterns of the graph. - */ - -#include - -#include "eval/user_impl_map.hpp" -#include "test/performance/utils.hpp" - -namespace Test { - -namespace Internal { - -//////////////////////////////////////////////////////////////////////////////// -// Auxiliary data -------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -int lower = 100; -int mult = 10; -int upper = 1e6; - -const char *filename = std::getenv("TEST_FILE"); - -//////////////////////////////////////////////////////////////////////////////// -// Benchmarks ------------------------------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -static void BM_CustomSCCTest(benchmark::State& state) -{ - int N = state.range(0); - SBG::LIB::MatchData match_result = calculateMatching(filename, N, 1); - SBG::LIB::DSBG scc_dsbg = MISC::buildSCCFromMatching(match_result); - SBG::LIB::SCC scc_algorithm = SBG::LIB::SCC_FACT.createSCCAlgorithm(); - - for (auto _ : state) { - scc_algorithm.calculate(scc_dsbg); - } - state.SetComplexityN(N); -} -BENCHMARK(BM_CustomSCCTest)->RangeMultiplier(mult)->Range(lower, upper) - ->Complexity()->Unit(benchmark::kMillisecond); - -static void BM_CustomSCCTestWithBuilder(benchmark::State& state) -{ - int N = state.range(0); - SBG::LIB::MatchData match_result = calculateMatching(filename, N, 1); - SBG::LIB::SCC scc_algorithm = SBG::LIB::SCC_FACT.createSCCAlgorithm(); - - for (auto _ : state) { - SBG::LIB::DSBG scc_dsbg = MISC::buildSCCFromMatching(match_result); - scc_algorithm.calculate(scc_dsbg); - } - state.SetComplexityN(N); -} -BENCHMARK(BM_CustomSCCTestWithBuilder)->RangeMultiplier(mult) - ->Range(lower, upper)->Complexity()->Unit(benchmark::kMillisecond); - -static void BM_CustomSCCTestCopies(benchmark::State& state) -{ - int N = state.range(0); - SBG::LIB::MatchData match_result = calculateMatching(filename, 100, N); - SBG::LIB::SCC scc_algorithm = SBG::LIB::SCC_FACT.createSCCAlgorithm(); - - for (auto _ : state) { - SBG::LIB::DSBG scc_dsbg = MISC::buildSCCFromMatching(match_result); - scc_algorithm.calculate(scc_dsbg); - } - state.SetComplexityN(N); -} -BENCHMARK(BM_CustomSCCTestCopies)->RangeMultiplier(2)->Range(1, 128) - ->Complexity()->Unit(benchmark::kMillisecond); - -} // namespace Internal - -} // namespace Test - -//////////////////////////////////////////////////////////////////////////////// -// Main ------------------------------------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -int main(int argc, char *argv[]) -{ - if (Test::Internal::filename) { - const char *set_impl = std::getenv("SET_IMPL"); - const char *pw_impl = std::getenv("PW_IMPL"); - SBG::Eval::setSetFactory(set_impl ? std::stoi(set_impl) : 1); - SBG::Eval::setPWFactory(pw_impl ? std::stoi(pw_impl) : 1); - - ::benchmark::Initialize(&argc, argv); - ::benchmark::RunSpecifiedBenchmarks(); - } - - return 0; -} diff --git a/test/performance/scc/scc_bm.cpp b/test/performance/scc/scc_bm.cpp deleted file mode 100644 index 2580a29a..00000000 --- a/test/performance/scc/scc_bm.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/***************************************************************************** - - This file is part of Set--Based Graph Library. - - SBG Library is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SBG Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with SBG Library. If not, see . - - ******************************************************************************/ - -/** - * @file scc_bm.cpp - * @brief Executes the SBG version of the SCC algorithm for TestRL1.test - * , TestRL2.test and TestRL3.test. It is used to showcase the constant - * execution time when the repetitive patterns increase its size. - */ - -#include - -#include "eval/user_impl_map.hpp" -#include "test/performance/utils.hpp" - -namespace Test { - -namespace Internal { - -//////////////////////////////////////////////////////////////////////////////// -// Benchmarks ------------------------------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -static void BM_TestRL1(benchmark::State& state) -{ - int N = state.range(0); - SBG::Eval::setSetFactory(2); - SBG::Eval::setPWFactory(0); - - // Calculate SCC - SBG::LIB::SCC scc_algorithm = SBG::LIB::SCC_FACT.createSCCAlgorithm(); - SBG::LIB::MatchData match_result - = calculateMatching("../../TestRL1.test", N, 1); - SBG::LIB::DSBG scc_dsbg = MISC::buildSCCFromMatching(match_result); - - for (auto _ : state) { - scc_algorithm.calculate(scc_dsbg); - } - state.SetComplexityN(N); -} -BENCHMARK(BM_TestRL1)->RangeMultiplier(10)->Range(100, 1e6)->Complexity() - ->Unit(benchmark::kMillisecond); - -static void BM_TestRL1WithBuilder(benchmark::State& state) -{ - int N = state.range(0); - SBG::Eval::setSetFactory(2); - SBG::Eval::setPWFactory(0); - - // Calculate SCC - SBG::LIB::SCC scc_algorithm = SBG::LIB::SCC_FACT.createSCCAlgorithm(); - SBG::LIB::MatchData match_result - = calculateMatching("../../TestRL1.test", N, 1); - - for (auto _ : state) { - SBG::LIB::DSBG scc_dsbg = MISC::buildSCCFromMatching(match_result); - scc_algorithm.calculate(scc_dsbg); - } - state.SetComplexityN(N); -} -BENCHMARK(BM_TestRL1WithBuilder)->RangeMultiplier(10)->Range(100, 1e6) - ->Complexity()->Unit(benchmark::kMillisecond); - -static void BM_TestRL2(benchmark::State& state) -{ - int N = state.range(0); - SBG::Eval::setSetFactory(2); - SBG::Eval::setPWFactory(0); - - // Calculate SCC - SBG::LIB::SCC scc_algorithm = SBG::LIB::SCC_FACT.createSCCAlgorithm(); - SBG::LIB::MatchData match_result - = calculateMatching("../../TestRL2.test", N, 1); - SBG::LIB::DSBG scc_dsbg = MISC::buildSCCFromMatching(match_result); - - for (auto _ : state) { - scc_algorithm.calculate(scc_dsbg); - } - state.SetComplexityN(N); -} -BENCHMARK(BM_TestRL2)->RangeMultiplier(10)->Range(100, 1e6)->Complexity() - ->Unit(benchmark::kMillisecond); - -static void BM_TestRL2WithBuilder(benchmark::State& state) -{ - int N = state.range(0); - SBG::Eval::setSetFactory(2); - SBG::Eval::setPWFactory(0); - - // Calculate SCC - SBG::LIB::SCC scc_algorithm = SBG::LIB::SCC_FACT.createSCCAlgorithm(); - SBG::LIB::MatchData match_result - = calculateMatching("../../TestRL2.test", N, 1); - - for (auto _ : state) { - SBG::LIB::DSBG scc_dsbg = MISC::buildSCCFromMatching(match_result); - scc_algorithm.calculate(scc_dsbg); - } - state.SetComplexityN(N); -} -BENCHMARK(BM_TestRL2WithBuilder)->RangeMultiplier(10)->Range(100, 1e6) - ->Complexity()->Unit(benchmark::kMillisecond); - -static void BM_TestRL3(benchmark::State& state) -{ - int N = state.range(0); - SBG::Eval::setSetFactory(2); - SBG::Eval::setPWFactory(1); - - // Calculate SCC - SBG::LIB::SCC scc_algorithm = SBG::LIB::SCC_FACT.createSCCAlgorithm(); - SBG::LIB::MatchData match_result - = calculateMatching("../../TestRL3.test", N, 1); - SBG::LIB::DSBG scc_dsbg = MISC::buildSCCFromMatching(match_result); - - for (auto _ : state) { - scc_algorithm.calculate(scc_dsbg); - } - state.SetComplexityN(N); -} -BENCHMARK(BM_TestRL3)->RangeMultiplier(10)->Range(100, 1e6)->Complexity() - ->Unit(benchmark::kMillisecond); - -static void BM_TestRL3WithBuilder(benchmark::State& state) -{ - int N = state.range(0); - SBG::Eval::setSetFactory(2); - SBG::Eval::setPWFactory(1); - - // Calculate SCC - SBG::LIB::SCC scc_algorithm = SBG::LIB::SCC_FACT.createSCCAlgorithm(); - SBG::LIB::MatchData match_result - = calculateMatching("../../TestRL3.test", N, 1); - - for (auto _ : state) { - SBG::LIB::DSBG scc_dsbg = MISC::buildSCCFromMatching(match_result); - scc_algorithm.calculate(scc_dsbg); - } - state.SetComplexityN(N); -} -BENCHMARK(BM_TestRL3WithBuilder)->RangeMultiplier(10)->Range(100, 1e6) - ->Complexity()->Unit(benchmark::kMillisecond); - -} // namespace Internal - -} // namespace Test diff --git a/test/performance/scc_bm.cpp b/test/performance/scc_bm.cpp new file mode 100644 index 00000000..d39e11b0 --- /dev/null +++ b/test/performance/scc_bm.cpp @@ -0,0 +1,120 @@ +/***************************************************************************** + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "algorithms/matching/match_data.hpp" +#include "algorithms/scc/scc.hpp" +#include "algorithms/misc/causalization_builders.hpp" +#include "sbg/directed_sbg.hpp" +#include "test/performance/scc_bm.hpp" +#include "test/performance/utils.hpp" + +#include + +namespace SBG { + +namespace perf { + +namespace detail { + +//////////////////////////////////////////////////////////////////////////////// +// Benchmarks ------------------------------------------------------------------ +//////////////////////////////////////////////////////////////////////////////// + +static void BM_SCC(benchmark::State& state, std::string filename) +{ + int N = state.range(0); + SBG::LIB::MatchData match_result = calculateMatching(filename, N, 1); + SBG::LIB::DirectedSBG scc_dsbg = misc::buildLoopDetectionSBG(match_result); + SBG::LIB::SCC scc_algorithm; + + for (auto _ : state) { + benchmark::DoNotOptimize(scc_algorithm.calculate(scc_dsbg)); + } + state.SetComplexityN(N); +} + +static void BM_SCCWithBuilder(benchmark::State& state, std::string filename) +{ + int N = state.range(0); + SBG::LIB::MatchData match_result = calculateMatching(filename, 100, N); + SBG::LIB::SCC scc_algorithm; + + for (auto _ : state) { + SBG::LIB::DirectedSBG scc_dsbg = misc::buildLoopDetectionSBG(match_result); + benchmark::DoNotOptimize(scc_algorithm.calculate(scc_dsbg)); + } + state.SetComplexityN(N); +} + +static void BM_SCCCopies(benchmark::State& state, std::string filename) +{ + int N = state.range(0); + SBG::LIB::MatchData match_result = calculateMatching(filename, 100, N); + SBG::LIB::SCC scc_algorithm; + + for (auto _ : state) { + SBG::LIB::DirectedSBG scc_dsbg = misc::buildLoopDetectionSBG(match_result); + benchmark::DoNotOptimize(scc_algorithm.calculate(scc_dsbg)); + } + state.SetComplexityN(N); +} + +//////////////////////////////////////////////////////////////////////////////// +// Register Benchmarks --------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +void registerSCCBenchmarks(std::string filename) +{ + benchmark::RegisterBenchmark( + ("BM_SCC/" + filename).c_str(), + [filename](benchmark::State& state) { + BM_SCC(state, filename); + } + )->RangeMultiplier(10)->Range(100, 1e6)->Complexity() + ->Unit(benchmark::kMillisecond); + + benchmark::RegisterBenchmark( + ("BM_SCCWithBuilder/" + filename).c_str(), + [filename](benchmark::State& state) { + BM_SCCWithBuilder(state, filename); + } + )->RangeMultiplier(10)->Range(100, 1e6)->Complexity() + ->Unit(benchmark::kMillisecond); + + benchmark::RegisterBenchmark( + ("BM_SCCCopies/" + filename).c_str(), + [filename](benchmark::State& state) { + BM_SCCCopies(state, filename); + } + )->RangeMultiplier(2)->Range(1, 128)->Complexity() + ->Unit(benchmark::kMillisecond); +} + +void registerSCCBenchmarks() +{ + registerSCCBenchmarks("../../TestRL1.test"); + registerSCCBenchmarks("../../TestRL2.test"); + registerSCCBenchmarks("../../TestRL3.test"); +} + +} // namespace detail + +} // namespace perf + +} // namespace SBG diff --git a/test/performance/scc_bm.hpp b/test/performance/scc_bm.hpp new file mode 100644 index 00000000..134458d3 --- /dev/null +++ b/test/performance/scc_bm.hpp @@ -0,0 +1,59 @@ +/** @file scc_bm.hpp + + @brief SCC Benchmark + + Executes the SBG version of the matching algorithm for TestRL1.test + , TestRL2.test and TestRL3.test. It is used to showcase the constant + execution time when the repetitive patterns increase its size. + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_TEST_PERFORMANCE_SCC_BM_HPP_ +#define SBGRAPH_TEST_PERFORMANCE_SCC_BM_HPP_ + +#include + +namespace SBG { + +namespace perf { + +namespace detail { + +/** + * @brief Registers for execution the SBG SCC benchmark of the desired test + * file. The benchmark first increaseas the value of N, which is the size + * of repetitive patterns in the original SBG. Then, taking the original value + * of N, it copies the SBG to increase the number of repetitive patterns. + */ +void registerSCCBenchmarks(std::string filename); + +/** + * @brief Registers for execution the SBG SCC benchmark of TestRL1.test + * , TestRL2.test and TestRL3.test, using the previous function. + */ +void registerSCCBenchmarks(); + +} // namespace detail + +} // namespace perf + +} // namespace SBG + +#endif // SBGRAPH_TEST_PERFORMANCE_SCC_BM_HPP_ diff --git a/test/performance/set_bm.cpp b/test/performance/set_bm.cpp new file mode 100644 index 00000000..565f7116 --- /dev/null +++ b/test/performance/set_bm.cpp @@ -0,0 +1,151 @@ +/***************************************************************************** + + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#include "sbg/interval.hpp" +#include "sbg/multidim_inter.hpp" +#include "sbg/natural.hpp" +#include "sbg/set.hpp" +#include "test/performance/utils.hpp" + +#include + +#include +#include + +namespace SBG { + +namespace perf { + +namespace detail { + +using SBG::LIB::NAT; +using SBG::LIB::detail::Interval; +using SBG::LIB::Set; + +//////////////////////////////////////////////////////////////////////////////// +// Benchmarks ------------------------------------------------------------------ +//////////////////////////////////////////////////////////////////////////////// + +static void BM_SetEq(benchmark::State& state) +{ + int set_sz = state.range(0); + auto [s1, s2] = nonDisjointPieces(set_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(s1 == s2); + } + state.SetComplexityN(set_sz); +} + +static void BM_SetCap(benchmark::State& state) +{ + int set_sz = state.range(0); + auto [s1, s2] = nonDisjointPieces(set_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(s1.intersection(s2)); + } + state.SetComplexityN(set_sz); +} + +static void BM_SetCup(benchmark::State& state) +{ + int set_sz = state.range(0); + auto [s1, s2] = nonDisjointPieces(set_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(s1.cup(s2)); + } + state.SetComplexityN(set_sz); +} + +static void BM_SetComplement(benchmark::State& state) +{ + int set_sz = state.range(0); + auto [s1, s2] = nonDisjointPieces(set_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(s1.complement()); + } + state.SetComplexityN(set_sz); +} + +static void BM_SetDiff(benchmark::State& state) +{ + int set_sz = state.range(0); + auto [s1, s2] = nonDisjointPieces(set_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(s1.difference(s2)); + } + state.SetComplexityN(set_sz); +} + +static void BM_SetDisjointUnion(benchmark::State& state) +{ + int set_sz = state.range(0); + auto [s1, s2] = interlacedPieces(set_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(std::move(s1).disjointCup(std::move(s2))); + } + state.SetComplexityN(set_sz); +} + +static void BM_SetCompact(benchmark::State& state) +{ + int set_sz = state.range(0); + auto [s1, s2] = nonDisjointPieces(set_sz); + + for (auto _ : state) { + s1.compact(); + benchmark::DoNotOptimize(s1); + } + state.SetComplexityN(set_sz); +} + +//////////////////////////////////////////////////////////////////////////////// +// Register Benchmarks --------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +void registerSetBenchmarks() +{ + BENCHMARK(BM_SetEq)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); + + BENCHMARK(BM_SetCap)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); + + BENCHMARK(BM_SetCup)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); + + BENCHMARK(BM_SetComplement)->RangeMultiplier(10)->Range(10, 1e3) + ->Complexity(); + + BENCHMARK(BM_SetDiff)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); + + BENCHMARK(BM_SetDisjointUnion)->RangeMultiplier(10)->Range(10, 1e3) + ->Complexity(); + + BENCHMARK(BM_SetCompact)->RangeMultiplier(10)->Range(10, 1e2) + ->Complexity(); +} + +} // namespace detail + +} // namespace perf + +} // namespace SBG diff --git a/test/performance/set_bm.hpp b/test/performance/set_bm.hpp new file mode 100644 index 00000000..50b7b2bb --- /dev/null +++ b/test/performance/set_bm.hpp @@ -0,0 +1,41 @@ +/** @file set_bm.hpp + + @brief Set Benchmark + +
+ + This file is part of Set--Based Graph Library. + + SBG Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SBG Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SBG Library. If not, see . + + ******************************************************************************/ + +#ifndef SBGRAPH_TEST_PERFORMANCE_SET_BM_HPP_ +#define SBGRAPH_TEST_PERFORMANCE_SET_BM_HPP_ + +namespace SBG { + +namespace perf { + +namespace detail { + +void registerSetBenchmarks(); + +} // namespace detail + +} // namespace perf + +} // namespace SBG + +#endif // SBGRAPH_TEST_PERFORMANCE_SET_BM_HPP_ diff --git a/test/performance/utils.cpp b/test/performance/utils.cpp index ffb44c6c..56475ee3 100644 --- a/test/performance/utils.cpp +++ b/test/performance/utils.cpp @@ -17,22 +17,44 @@ ******************************************************************************/ +#include "algorithms/matching/matching.hpp" +#include "algorithms/matching/match_data.hpp" +#include "eval/base_type.hpp" +#include "eval/file_evaluator.cpp" +#include "eval/pretty_print.hpp" +#include "sbg/bipartite_sbg.hpp" +#include "sbg/expression.hpp" +#include "sbg/interval.hpp" +#include "sbg/natural.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/rational.hpp" +#include "sbg/set.hpp" + #include +#include #include -#include #include +#include +#include -#include "algorithms/misc/causalization_builders.hpp" -#include "eval/file_evaluator.cpp" -#include "eval/user_impl_map.hpp" +namespace SBG { -namespace Test { +namespace perf { -namespace Internal { +namespace detail { +using SBG::LIB::NAT; +using SBG::LIB::RATIONAL; +using SBG::LIB::detail::Interval; +using SBG::LIB::Set; +using SBG::LIB::Expression; +using SBG::LIB::PWMap; +using SBG::LIB::BipartiteSBG; +using SBG::LIB::Matching; +using SBG::LIB::MatchData; //////////////////////////////////////////////////////////////////////////////// -// Auxiliary functions --------------------------------------------------------- +// File Manipulation ----------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// bool updateN(const std::string& filename, int N) @@ -69,7 +91,7 @@ bool updateN(const std::string& filename, int N) return true; } -SBG::LIB::BipartiteSBG generateSBG(std::string filename, int N, int copies) +BipartiteSBG generateSBG(std::string filename, int N, int copies) { std::streambuf* original_buf = std::cout.rdbuf(); std::ofstream nullStream("/dev/null"); @@ -79,31 +101,232 @@ SBG::LIB::BipartiteSBG generateSBG(std::string filename, int N, int copies) updateN(filename, N); // Get graph from file - SBG::LIB::BipartiteSBG g; + BipartiteSBG g; SBG::Eval::ProgramIO eval_result = SBG::Eval::parseEvalFile(filename); - for (const SBG::Eval::ExprResult &ev : eval_result.exprs()) { + for (const SBG::Eval::ExprResult& ev : eval_result.exprs()) { SBG::Eval::ExprBaseType e = std::get<1>(ev); - if (std::holds_alternative(e)) { - g = std::get(e); + if (std::holds_alternative(e)) { + g = std::get(e); } } std::cout.rdbuf(original_buf); - return g.copy(copies); + return copy(copies, g); } -SBG::LIB::MatchData calculateMatching(std::string filename, int N, int copies) +MatchData calculateMatching(std::string filename, int N, int copies) { // Calculate matching - SBG::LIB::BipartiteSBG match_sbg = generateSBG(filename, N, copies); - SBG::LIB::Matching match_algorithm - = SBG::LIB::MATCH_FACT.createMatchAlgorithm(); - SBG::LIB::MatchData match_result = match_algorithm.calculate(match_sbg); + BipartiteSBG match_sbg = generateSBG(filename, N, copies); + Matching match_algorithm; + MatchData match_result = match_algorithm.calculate(match_sbg); return match_result; } -} // namespace Internal +//////////////////////////////////////////////////////////////////////////////// +// Set Construction ------------------------------------------------------------ +//////////////////////////////////////////////////////////////////////////////// + +std::pair nonDisjointPieces(NAT set_sz) +{ + NAT inter_sz = 100; + + Set s1; + Set s2; + for (unsigned int h = 0; h < set_sz; ++h) { + Interval i1{h*inter_sz, 1, (h + 1)*inter_sz - 1}; + Set jth_s1{i1.begin(), i1.step(), i1.end()}; + s1 = s1.disjointCup(jth_s1); + + NAT off = inter_sz/2; + Interval i2{off + (h*inter_sz), 1, off + (h + 1)*inter_sz - 1}; + Set jth_s2{i2.begin(), i2.step(), i2.end()}; + s2 = s2.disjointCup(jth_s2); + } + + Set second_dim{0, 1, inter_sz - 1}; + s1 = s1.cartesianProduct(second_dim); + s2 = s2.cartesianProduct(second_dim); + + return std::make_pair(std::move(s1), std::move(s2)); +} + +std::pair interlacedPieces(NAT set_sz) +{ + NAT inter_sz = 100; + + Set s1; + Set s2; + for (SBG::LIB::NAT j = 0; j < set_sz; j += 2) { + Set jth_s1{j*inter_sz, 1, (j + 1)*inter_sz - 1}; + s1 = std::move(s1.disjointCup(jth_s1)); + Set jth_s2{(j + 1)*inter_sz, 1, (j + 2)*inter_sz - 1}; + s2 = std::move(s2.disjointCup(jth_s2)); + } + + return std::make_pair(std::move(s1), std::move(s2)); +} + +//////////////////////////////////////////////////////////////////////////////// +// PWMap Construction ---------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +PWMap denseDom(NAT map_sz) +{ + NAT inter_sz = 100; + NAT set_sz = 10; + + PWMap pw; + for (unsigned int j = 0; j < map_sz; ++j) { + Set domain; + NAT offset = j*set_sz*inter_sz; + for (unsigned int h = 0; h < set_sz; ++h) { + Interval i{offset + (h*inter_sz), 1, offset + (h + 1)*inter_sz - 1}; + Set jth_domain{i.begin(), i.step(), i.end()}; + domain = std::move(domain).disjointCup(std::move(jth_domain)); + } + Expression id{RATIONAL{1}, RATIONAL{0}}; + + pw.emplace(domain, id); + } + + return pw; +} + +std::pair minAdjMaps(NAT map_sz) +{ + NAT inter_sz = 100; + NAT set_sz = 10; + + Set second_dim{0, 1, inter_sz - 1}; + PWMap pw1; + PWMap pw2; + for (unsigned int j = 0; j < map_sz; ++j) { + Set domain1; + Set domain2; + NAT offset = j*set_sz*inter_sz; + for (unsigned int h = 0; h < set_sz; ++h) { + Interval i1{offset + (h*inter_sz), 1, offset + (h + 1)*inter_sz - 1}; + Set jth_domain1{i1.begin(), i1.step(), i1.end()}; + domain1 = std::move(domain1).disjointCup(std::move(jth_domain1)); + + NAT offset2 = offset + inter_sz/2; + Interval i2{offset2 + (h*inter_sz), 1, offset2 + (h + 1)*inter_sz - 1}; + Set jth_domain2{i2.begin(), i2.step(), i2.end()}; + domain2 = std::move(domain2).disjointCup(std::move(jth_domain2)); + } + + Expression id{RATIONAL{1}, RATIONAL{0}}; + Expression minus_one{RATIONAL{1}, RATIONAL{-1, 1}}; + + pw1.emplace(domain1, id); + pw2.emplace(domain2, minus_one); + } + + return {pw1, pw2}; +} + +std::pair interlacedMaps(NAT map_sz) +{ + NAT inter_sz = 100; + NAT set_sz = 10; + + Set second_dim{0, 1, inter_sz - 1}; + PWMap pw1; + PWMap pw2; + for (unsigned int j = 0; j < map_sz; ++j) { + Set domain1; + Set domain2; + NAT offset = j*set_sz*inter_sz; + for (unsigned int h = 0; h < set_sz; h += 2) { + Interval i1{offset + (h*inter_sz), 1, offset + (h + 1)*inter_sz - 1}; + Set jth_domain1{i1.begin(), i1.step(), i1.end()}; + domain1 = std::move(domain1).disjointCup(std::move(jth_domain1)); + + NAT offset2 = offset + inter_sz; + Interval i2{offset2 + (h*inter_sz), 1, offset2 + (h + 1)*inter_sz - 1}; + Set jth_domain2{i2.begin(), i2.step(), i2.end()}; + domain2 = std::move(domain2).disjointCup(std::move(jth_domain2)); + } + domain1 = domain1.cartesianProduct(second_dim); + domain2 = domain2.cartesianProduct(second_dim); + + Expression multidim_id{2, 1, 0}; + + pw1.emplace(domain1, multidim_id); + pw2.emplace(domain2, multidim_id); + } + + return {pw1, pw2}; +} + +std::pair nonDisjointMaps(NAT map_sz) +{ + NAT inter_sz = 100; + NAT set_sz = 10; + + Set second_dim{0, 1, inter_sz - 1}; + PWMap pw1; + PWMap pw2; + for (unsigned int j = 0; j < map_sz; ++j) { + Set domain1; + Set domain2; + NAT offset = j*set_sz*inter_sz; + for (unsigned int h = 0; h < set_sz; ++h) { + Interval i1{offset + (h*inter_sz), 1, offset + (h + 1)*inter_sz - 1}; + Set jth_domain1{i1.begin(), i1.step(), i1.end()}; + domain1 = std::move(domain1).disjointCup(std::move(jth_domain1)); + + NAT offset2 = offset + inter_sz/2; + Interval i2{offset2 + (h*inter_sz), 1, offset2 + (h + 1)*inter_sz - 1}; + Set jth_domain2{i2.begin(), i2.step(), i2.end()}; + domain2 = std::move(domain2).disjointCup(std::move(jth_domain2)); + } + domain1 = domain1.cartesianProduct(second_dim); + domain2 = domain2.cartesianProduct(second_dim); + + Expression multidim_id{2, 1, 0}; + + pw1.emplace(domain1, multidim_id); + pw2.emplace(domain2, multidim_id); + } + + return {pw1, pw2}; +} + +PWMap reducibleMaps(NAT map_sz) +{ + NAT inter_sz = 100; + NAT set_sz = 10; + + Set second_dim{0, 1, inter_sz - 1}; + PWMap pw; + for (unsigned int j = 0; j < map_sz; ++j) { + Set domain; + NAT offset = j*set_sz*inter_sz; + for (unsigned int h = 0; h < set_sz; ++h) { + Interval i{offset + (h*inter_sz), 1, offset + (h + 1)*inter_sz - 1}; + Set jth_domain{i.begin(), i.step(), i.end()}; + domain = std::move(domain).disjointCup(std::move(jth_domain)); + } + domain = domain.cartesianProduct(second_dim); + + Expression plus_one{RATIONAL{1}, RATIONAL{1}}; + Expression id{RATIONAL{1}, RATIONAL{0}}; + Expression expr = plus_one.cartesianProduct(id); + + pw.emplace(domain, expr); + } + + return pw; +} + + + +} // namespace detail + +} // namespace perf -} // namespace Test +} // namespace SBG diff --git a/test/performance/utils.hpp b/test/performance/utils.hpp index eb922366..f4d43eec 100644 --- a/test/performance/utils.hpp +++ b/test/performance/utils.hpp @@ -1,8 +1,8 @@ -/** @file interval.hpp +/** @file utils.hpp @brief Utils - Declares useful functions that all benchmarks can use + Declares useful functions for all benchmarks.
@@ -23,14 +23,32 @@ ******************************************************************************/ -#ifndef TEST_PERF_UTILS -#define TEST_PERF_UTILS +#ifndef SBGRAPH_TEST_PERFORMANCE_UTILS_HPP_ +#define SBGRAPH_TEST_PERFORMANCE_UTILS_HPP_ -#include "algorithms/misc/causalization_builders.hpp" +#include "algorithms/matching/match_data.hpp" +#include "sbg/bipartite_sbg.hpp" +#include "sbg/natural.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/set.hpp" -namespace Test { +#include -namespace Internal { +namespace SBG { + +namespace perf { + +namespace detail { + +using SBG::LIB::NAT; +using SBG::LIB::Set; +using SBG::LIB::PWMap; +using SBG::LIB::BipartiteSBG; +using SBG::LIB::MatchData; + +//////////////////////////////////////////////////////////////////////////////// +// File Manipulation ----------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// /** * @brief Replaces the value of N with the desired value in the designated @@ -46,7 +64,7 @@ bool updateN(const std::string& filename, int N); * @param N Size of set-vertices and set-edges. * @param copies Copies of the SBG, i.e. number of set-vertices and set-edges. */ -SBG::LIB::BipartiteSBG generateSBG(std::string filename, int N, int copies); +BipartiteSBG generateSBG(std::string filename, int N, int copies); /** * @brief Reads a .test file to search for an SBG that will be the input for @@ -57,10 +75,91 @@ SBG::LIB::BipartiteSBG generateSBG(std::string filename, int N, int copies); * @param N Size of set-vertices and set-edges. * @param copies Copies of the SBG, i.e. number of set-vertices and set-edges. */ -SBG::LIB::MatchData calculateMatching(std::string filename, int N, int copies); +MatchData calculateMatching(std::string filename, int N, int copies); + +//////////////////////////////////////////////////////////////////////////////// +// Set Construction ------------------------------------------------------------ +//////////////////////////////////////////////////////////////////////////////// + +/* + * @brief Creates two dense sets, where the first one is: + * {[0:99]x[0:99], [100:199]x[0:99], ..., [N-99:N]x[0:99]} + * and the second PW: + * {[50:149]x[0:99], [150:249]x[0:99], ..., [N-49:N+50]x[0:99]} + * where N = set_sz*100-1. + */ +std::pair nonDisjointPieces(NAT set_sz); + +/* + * @brief Creates two dense sets, where the first one is: + * {[0:99], [200:199], ..., [N-199:N-100]} + * and the second PW: + * {[100:199], [300:399], ..., [N-99:N]} + * where N = set_sz*100-1. + */ +std::pair interlacedPieces(NAT set_sz); + +//////////////////////////////////////////////////////////////////////////////// +// PWMap Construction ---------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +/* + * @brief Creates a PW with a dense domain of the form: + * <<{[0:99], [100:199], ..., [900:999]} -> |x| + * , {[1000:1099], ..., [1900:1999]} -> |x| + * , ..., {[N-999:N-900], ..., [N-99:N]} -> |x|>>. + * where N = map_sz*1e3-1. + */ +PWMap denseDom(NAT map_sz); + +/* + * @brief Creates two PWs with a dense domain, where the first one is: + * <<{[0:99], [100:199], ..., [900:999]} -> |x| + * , {[1000:1099], ..., [1900:1999]} -> |x| + * , ..., {[N-999:N-900], ..., [N-99:N]} -> |x|>>. + * and the second PW: + * <<{[50:149], [150:249], ..., [950:1049]} -> |x-1| + * , {[1050:1149], ..., [1950:2049]} -> |x-1| + * , ..., {[N-949:N-850], ..., [N-49:N+50]} -> |x-1|>> + * where N = map_sz*1e3-1. + */ +std::pair minAdjMaps(NAT map_sz); + +/* + * @brief Creates two PWs with a dense domain, where the first one is: + * <<{[0:99]x[0:99], [200:299]x[0:99], ..., [800:899]x[0:99]} -> |x|x| + * , {[1000:1099]x[0:99], ..., [1800:1899]x[0:99]} -> |x|x| + * , ..., {[N-999:N-900]x[0:99], ..., [N-199:N-100]x[0:99]} -> |x|x|>>. + * and the second PW: + * <<{[100:199]x[0:99], [300:399]x[0:99], ..., [900:999]x[0:99]} -> |x|x| + * , {[1100:1199]x[0:99], ..., [1300:1399]x[0:99]} -> |x|x| + * , ..., {[N-899:N-800]x[0:99], ..., [N-99:N]x[0:99]} -> |x|x|>> + * where N = map_sz*1e3-1. + */ +std::pair interlacedMaps(NAT map_sz); + +/* + * @brief Creates two PWs with a dense domain, where the first one is: + * <<{[0:99]x[0:99], [100:199]x[0:99], ..., [900:999]x[0:99]} -> |x|x| + * , {[1000:1099]x[0:99]x, ..., [1900:1999]x[0:99]} -> |x|x| + * , ..., {[N-999:N-900]x[0:99], ..., [N-99:N]x[0:99]} -> |x|x|>>. + * and the second PW: + * <<{[50:149]x[0:99], [150:249]x[0:99], ..., [950:1049]x[0:99]} -> |x|x| + * , {[1050:1149]x[0:99], ..., [1950:2049]x[0:99]} -> |x|x| + * , ..., {[N-949:N-850]x[0:99], ..., [N-49:N+50]x[0:99]} -> |x|x|>> + * where N = map_sz*1e3-1. + */ +std::pair nonDisjointMaps(NAT map_sz); + +/** + * @brief TODO + */ +PWMap reducibleMaps(NAT map_sz); + +} // namespace detail -} // namespace Internal +} // namespace perf -} // namespace Test +} // namespace SBG -#endif +#endif // SBGRAPH_TEST_PERFORMANCE_UTILS_HPP_ diff --git a/test/pw_map1.test b/test/pw_map1.test index ce13f305..1a61872d 100644 --- a/test/pw_map1.test +++ b/test/pw_map1.test @@ -8,8 +8,4 @@ minMap(<<{[1:1:10], [15:3:30]} -> |1*x+0|, {[12:3:12], [50:5:100]} -> |1*x+1|>>, <<{[1:2:20], [30:5:60]} -> |0*x+100|, {[75:5:90], [95:1:100]} -> |1*x+0|>>); -reduce(<<{[100:1:200]} -> |1*x-1|>>); - -firstInv(<<{[1:1:10]} -> |0*x+10|>>); - mapInf(<<{[50:1:50]} -> |1*x-49|, {[49:1:49]} -> |1*x-48|, {[3:1:48]} -> |1*x+1|>>); diff --git a/test/pw_map2.test b/test/pw_map2.test index 14d737a0..a2b63c63 100644 --- a/test/pw_map2.test +++ b/test/pw_map2.test @@ -14,7 +14,7 @@ image({[1:1:5] x [1:1:5], [10:1:15] x [10:1:15], [20:3:30] x [35:5:100], [45:5:5 , <<{[1:1:5] x [1:1:5], [10:1:15] x [10:1:15]} -> |1*x+0|1*x+0|, {[20:3:30] x [20:3:30], [45:5:50] x [45:5:50]} -> |2*x+0|2*x+0|>>); preImage({[0:1:25] x [0:1:25]}, <<{[1:1:10] x [1:1:10], [20:5:30] x [20:5:30]} -> |0*x+3|0*x+4 - |, {[11:1:14] x [11:1:14], [1:1:10] x [50:5:70]} -> |2*x+0|2*x+1|>>); +|, {[11:1:14] x [11:1:14], [1:1:10] x [50:5:70]} -> |2*x+0|2*x+1|>>); compose(<<{[1:1:10] x [1:1:5], [20:2:30] x [20:2:30]} -> |2*x+1|3*x+0|, {[15:3:18] x [12:3:18]} -> |0*x+0|0*x+0|>> , <<{[1:1:30] x [1:1:30]} -> |1*x+1|1*x+2|>>) ; @@ -22,7 +22,3 @@ compose(<<{[1:1:10] x [1:1:5], [20:2:30] x [20:2:30]} -> |2*x+1|3*x+0|, {[15:3:1 minAdj(<<{[10:1:100] x [10:1:100], [101:2:200] x [101:2:200]} -> |1*x+0|1*x+0|, {[10:1:100] x [101:2:200]} -> |2*x+0|2*x+0|>>, <<{[5:5:50] x [5:5:50]} -> |0*x+1|1*x+0|, {[51:3:80] x [51:3:80], [90:1:150] x [95:1:150]} -> |2*x+3|2*x+1|>>); minMap(<<{[1:1:100]x[1:1:100]} -> |x|N*x+100|>>, <<{[1:1:100]x[1:1:100]} -> |N*x+100|x|>>); - -reduce(<<{[1:100]x[1:100]} -> |x+1|x+1|>>); - -reduce(<<{[1:100]x[1:100]} -> |x+1|3|>>); diff --git a/test/pw_map3.test b/test/pw_map3.test index 3c8e6c4f..214b9c96 100644 --- a/test/pw_map3.test +++ b/test/pw_map3.test @@ -9,6 +9,3 @@ dims = 3; combine(<<{[1:1:10] x [1:1:10] x [1:1:10], [1:1:10] x [20:3:30] x [20:3:30]} -> |1*x+0|1*x+0|1*x+0|, {[1:1:10] x [20:3:30] x [35:5:50], [35:5:50] x [35:5:50] x [20:3:30]} -> |3*x+0|3*x+0|1*x+1|>>, <<{[1:1:20] x [1:1:20] x [1:1:20]} -> |1*x+1|1*x+0|1*x+0|>>); - -reduce(<<{[4:1:15] x [4:1:15] x [4:1:15], [4:1:15] x [20:2:25] x [4:1:15]} -> |1*x+0|1*x-3|3*x+0 - |, {[4:1:15] x [15:5:50] x [20:2:25], [20:2:25] x [40:5:45] x [40:5:45]} -> |2*x+0|1*x+0|4*x+4|>>); diff --git a/test/scc3.test b/test/scc3.test index e3640f9b..524a221b 100644 --- a/test/scc3.test +++ b/test/scc3.test @@ -24,18 +24,20 @@ off4d = V3-E4-1; V: {[1:1:V1], [V1+1:1:V2], [V2+1:1:V3]} Vmap: <<{[1:1:V1]} -> |0*x+1|, {[V1+1:1:V2]} -> |0*x+2|, {[V2+1:1:V3]} -> |0*x+3|>> -mapB: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b - |, {[E3+1:1:E4]} -> |1*x+off4b|>> -mapD: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d - |, {[E3+1:1:E4]} -> |1*x+off4d|>> -Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2], [E2+1:1:E3], [E3+1:1:E4]} -> |0*x+2|>>; +mapB: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b| + , {[E3+1:1:E4]} -> |1*x+off4b|>> +mapD: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d| + , {[E3+1:1:E4]} -> |1*x+off4d|>> +Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3| + , {[E3+1:1:E4]} -> |0*x+4|>>; scc( V: {[1:1:V1], [V1+1:1:V2], [V2+1:1:V3]} Vmap: <<{[1:1:V1]} -> |0*x+1|, {[V1+1:1:V2]} -> |0*x+2|, {[V2+1:1:V3]} -> |0*x+3|>> - mapB: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b - |, {[E3+1:1:E4]} -> |1*x+off4b|>> - mapD: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d - |, {[E3+1:1:E4]} -> |1*x+off4d|>> - Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2], [E2+1:1:E3], [E3+1:1:E4]} -> |0*x+2|>> + mapB: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b| + , {[E3+1:1:E4]} -> |1*x+off4b|>> + mapD: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d| + , {[E3+1:1:E4]} -> |1*x+off4d|>> + Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3| + , {[E3+1:1:E4]} -> |0*x+4|>> ); diff --git a/test/scc4.test b/test/scc4.test index b6c7e7c3..5b231b59 100644 --- a/test/scc4.test +++ b/test/scc4.test @@ -27,18 +27,20 @@ off5d = V2-E5-1; V: {[1:1:V1], [V1+1:1:V2], [V2+1:1:V3]} Vmap: <<{[1:1:V1]} -> |0*x+1|, {[V1+1:1:V2]} -> |0*x+2|, {[V2+1:1:V3]} -> |0*x+3|>> -mapB: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b - |, {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|>> -mapD: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d - |, {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|>> -Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2], [E2+1:1:E3], [E3+1:1:E4], [E4+1:1:E5]} -> |0*x+2|>>; +mapB: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b| + , {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|>> +mapD: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d| + , {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|>> +Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3| + , {[E3+1:1:E4]} -> |0*x+4|, {[E4+1:1:E5]} -> |0*x+5|>>; scc( V: {[1:1:V1], [V1+1:1:V2], [V2+1:1:V3]} Vmap: <<{[1:1:V1]} -> |0*x+1|, {[V1+1:1:V2]} -> |0*x+2|, {[V2+1:1:V3]} -> |0*x+3|>> - mapB: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b - |, {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|>> - mapD: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d - |, {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|>> - Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2], [E2+1:1:E3], [E3+1:1:E4], [E4+1:1:E5]} -> |0*x+2|>> + mapB: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b| + , {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|>> + mapD: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d| + , {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|>> + Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3| + , {[E3+1:1:E4]} -> |0*x+4|, {[E4+1:1:E5]} -> |0*x+5|>> ); diff --git a/test/tearing1.test b/test/tearing1.test index 4e18f9cd..3bfb8aee 100644 --- a/test/tearing1.test +++ b/test/tearing1.test @@ -1,4 +1,4 @@ -// SCC test, with a simple long cycle +// Tearing test, with a simple long cycle N = 100000; @@ -23,7 +23,7 @@ mapB: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} - mapD: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d|>> Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3|>>; -cut( +mfvs( V: {[1:1:V1], [V1+1:1:V2]} Vmap: <<{[1:1:V1]} -> |0*x+1|, {[V1+1:1:V2]} -> |0*x+2|>> mapB: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b|>> diff --git a/test/tearing2.test b/test/tearing2.test index a4c4631a..09512114 100644 --- a/test/tearing2.test +++ b/test/tearing2.test @@ -20,7 +20,7 @@ mapB: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|>> mapD: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|>> Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|>>; -cut( +mfvs( V: {[1:1:V1], [V1+1:1:V2]} Vmap: <<{[1:1:V1]} -> |0*x+1|, {[V1+1:1:V2]} -> |0*x+2|>> mapB: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|>> diff --git a/test/topsort2.test b/test/topsort2.test index e05d8ea1..12ef140c 100644 --- a/test/topsort2.test +++ b/test/topsort2.test @@ -1,4 +1,4 @@ -// Topological sort test, with a simple recursion, and a self recursion on the right +// Topological sort test, with a simple recursion N = 100000; @@ -29,5 +29,5 @@ sort( |, {[V3:1:V3]} -> |0*x+4|>> mapB: <<{[1:1:E1]} -> |1*x+0|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x-off3b|>> mapD: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+0|, {[E2+1:1:E3]} -> |1*x+off3d|>> - Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2], [E2+1:1:E3]} -> |0*x+2|>> + Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3|>> ); diff --git a/test/topsort3.test b/test/topsort3.test index ed96636f..152090e6 100644 --- a/test/topsort3.test +++ b/test/topsort3.test @@ -2,7 +2,7 @@ /* model test - constant Integer N=10; + constant Integer N=100000; Real a[N], b[N-1], c[N-1]; equation for i in 1:N-1 loop diff --git a/test/topsort4.test b/test/topsort4.test index 30ed6a0e..13a4b6ed 100644 --- a/test/topsort4.test +++ b/test/topsort4.test @@ -28,25 +28,25 @@ off5d = V3-E5; off6d = V2-E6; V: {[1:1:V1], [V1+1:1:V2], [V2+1:1:V3]} -Vmap: <<{[1:1:V1-1]} -> |0*x+1|, {[V1:1:V1]} -> |0*x+2|, {[V1+1:1:V1+1]} -> |0*x+3 - |, {[V1+2:1:V2-1]} -> |0*x+4|, {[V2:1:V2]} -> |0*x+5|, {[V2+1:1:V2+1]} -> |0*x+6 - |, {[V2+2:1:V3]} -> |0*x+7|>> -mapB: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b - |, {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b|>> -mapD: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d - |, {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|, {[E5+1:1:E6]} -> |1*x+off6d|>> -Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2], [E2+1:1:E3]} -> |0*x+2 - |, {[E3+1:1:E4]} -> |0*x+3|, {[E4+1:1:E5], [E5+1:1:E6]} -> |0*x+4|>>; +Vmap: <<{[1:1:V1-1]} -> |0*x+1|, {[V1:1:V1]} -> |0*x+2|, {[V1+1:1:V1+1]} -> |0*x+3| + , {[V1+2:1:V2-1]} -> |0*x+4|, {[V2:1:V2]} -> |0*x+5|, {[V2+1:1:V2+1]} -> |0*x+6| + , {[V2+2:1:V3]} -> |0*x+7|>> +mapB: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b| + , {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b|>> +mapD: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d| + , {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|, {[E5+1:1:E6]} -> |1*x+off6d|>> +Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3| + , {[E3+1:1:E4]} -> |0*x+4|, {[E4+1:1:E5]} -> |0*x+5|, {[E5+1:1:E6]} -> |0*x+6|>>; sort( V: {[1:1:V1], [V1+1:1:V2], [V2+1:1:V3]} - Vmap: <<{[1:1:V1-1]} -> |0*x+1|, {[V1:1:V1]} -> |0*x+2|, {[V1+1:1:V1+1]} -> |0*x+3 - |, {[V1+2:1:V2-1]} -> |0*x+4|, {[V2:1:V2]} -> |0*x+5|, {[V2+1:1:V2+1]} -> |0*x+6 - |, {[V2+2:1:V3]} -> |0*x+7|>> - mapB: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b - |, {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b|>> - mapD: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d - |, {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|, {[E5+1:1:E6]} -> |1*x+off6d|>> - Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2], [E2+1:1:E3]} -> |0*x+2 - |, {[E3+1:1:E4]} -> |0*x+3|, {[E4+1:1:E5], [E5+1:1:E6]} -> |0*x+4|>> + Vmap: <<{[1:1:V1-1]} -> |0*x+1|, {[V1:1:V1]} -> |0*x+2|, {[V1+1:1:V1+1]} -> |0*x+3| + , {[V1+2:1:V2-1]} -> |0*x+4|, {[V2:1:V2]} -> |0*x+5|, {[V2+1:1:V2+1]} -> |0*x+6| + , {[V2+2:1:V3]} -> |0*x+7|>> + mapB: <<{[1:1:E1]} -> |1*x+off1b|, {[E1+1:1:E2]} -> |1*x+off2b|, {[E2+1:1:E3]} -> |1*x+off3b| + , {[E3+1:1:E4]} -> |1*x+off4b|, {[E4+1:1:E5]} -> |1*x+off5b|, {[E5+1:1:E6]} -> |1*x+off6b|>> + mapD: <<{[1:1:E1]} -> |1*x+off1d|, {[E1+1:1:E2]} -> |1*x+off2d|, {[E2+1:1:E3]} -> |1*x+off3d| + , {[E3+1:1:E4]} -> |1*x+off4d|, {[E4+1:1:E5]} -> |1*x+off5d|, {[E5+1:1:E6]} -> |1*x+off6d|>> + Emap: <<{[1:1:E1]} -> |0*x+1|, {[E1+1:1:E2]} -> |0*x+2|, {[E2+1:1:E3]} -> |0*x+3| + , {[E3+1:1:E4]} -> |0*x+4|, {[E4+1:1:E5]} -> |0*x+5|, {[E5+1:1:E6]} -> |0*x+6|>> ); diff --git a/util/defs.hpp b/util/defs.hpp index fff0ef79..b0d36e3e 100755 --- a/util/defs.hpp +++ b/util/defs.hpp @@ -23,8 +23,8 @@ ******************************************************************************/ -#ifndef SBG_DEFS_HPP -#define SBG_DEFS_HPP +#ifndef SBGRAPH_UTIL_DEFS_HPP_ +#define SBGRAPH_UTIL_DEFS_HPP_ namespace SBG { @@ -67,8 +67,22 @@ constexpr bool time_profiler_enabled = true; */ void time_profiler_results(); +/** + * @brief Provides in-place lambdas to visit std::variant types. + */ + +template +class Overload : Ts... { +public: + using Ts::operator()...; + Overload(Ts... ts) : Ts(ts)... {}; +}; + +template +Overload(Ts...) -> Overload; + } // namespace Util } // namespace SBG -#endif +#endif // SBGRAPH_UTIL_DEFS_HPP_ diff --git a/util/logger.cpp b/util/logger.cpp index e3b589f4..e831e4fc 100755 --- a/util/logger.cpp +++ b/util/logger.cpp @@ -17,23 +17,27 @@ ******************************************************************************/ -#include "logger.hpp" - -using namespace std; +#include "util/logger.hpp" namespace SBG { namespace Util { -SBGLogger::SBGLogger() { file_.open("SBG.log", std::ofstream::out); } +SBGLogger::SBGLogger() { _file.open("SBG.log", std::ofstream::out); } + +SBGLogger::~SBGLogger() { _file.close(); } -SBGLogger::~SBGLogger() { file_.close(); } +SBGLogger& SBGLogger::instance() +{ + static SBGLogger _instance; + return _instance; +} -void SBGLogger::setLevel(LogLevel lvl) { level_ = lvl; } +void SBGLogger::setLevel(LogLevel lvl) { _level = lvl; } std::ostream& SBGLogger::log(LogLevel msg_lvl) { - return (msg_lvl <= level_) ? file_ : null_stream; + return (msg_lvl <= _level) ? _file : null_stream; } } // namespace Util diff --git a/util/logger.hpp b/util/logger.hpp index 97cb380a..e6614e75 100755 --- a/util/logger.hpp +++ b/util/logger.hpp @@ -48,11 +48,7 @@ static std::ostream null_stream(&null_buffer); class SBGLogger { public: - static SBGLogger& instance() - { - static SBGLogger _instance; - return _instance; - } + static SBGLogger& instance(); ~SBGLogger(); @@ -61,8 +57,8 @@ class SBGLogger { private: SBGLogger(); - std::ofstream file_; - LogLevel level_{LogLevel::Info}; + std::ofstream _file; + LogLevel _level{LogLevel::Info}; }; } // namespace Util diff --git a/util/time_profiler.cpp b/util/time_profiler.cpp index b0b2d93f..75c8e140 100644 --- a/util/time_profiler.cpp +++ b/util/time_profiler.cpp @@ -23,49 +23,57 @@ namespace SBG { namespace Util { - void time_profiler_results() { - Internal::TimeProfiler::print_execution_time(); + Internal::TimeProfiler::print_execution_time(); } - -namespace Internal{ +namespace Internal { std::unordered_map TimeProfiler::_execution_time = {}; TimeProfiler::TimeProfiler(std::string&& function_name) - : _function_name(move(function_name)) + : _function_name(move(function_name)) { - if (time_profiler_enabled) { - _start = std::chrono::high_resolution_clock::now(); - } + if (time_profiler_enabled) { + _start = std::chrono::high_resolution_clock::now(); + } } TimeProfiler::~TimeProfiler() { - if (time_profiler_enabled) { - auto end = std::chrono::high_resolution_clock::now(); - auto exec_time = std::chrono::duration(end - _start).count(); - if (_execution_time.find(_function_name) == _execution_time.end()) { - _execution_time.insert({_function_name, 0.0}); - } - _execution_time[_function_name] += exec_time; + if (time_profiler_enabled) { + auto end = std::chrono::high_resolution_clock::now(); + auto exec_time = std::chrono::duration(end - _start).count(); + if (_execution_time.find(_function_name) == _execution_time.end()) { + _execution_time.insert({_function_name, 0.0}); } + _execution_time[_function_name] += exec_time; + } } void TimeProfiler::print_execution_time() { - if (time_profiler_enabled) { - for (auto&& pair : TimeProfiler::_execution_time) { - std::cout << pair.first << ": " << pair.second << " ms" << std::endl; - } + if (time_profiler_enabled) { + for (auto&& pair : TimeProfiler::_execution_time) { + std::cout << pair.first << ": " << pair.second << " ms" << std::endl; } + } } +void TimeProfiler::print_execution_time(std::string function_name) { + if (time_profiler_enabled) { + for (auto&& pair : TimeProfiler::_execution_time) { + if (pair.first == function_name) { + std::cout << pair.first << ": " << pair.second << " ms" << std::endl; + } + } + } } +} // namespace Internal + } // namespace Util } // namespace SBG diff --git a/util/time_profiler.hpp b/util/time_profiler.hpp index 6d7867ef..b658689d 100644 --- a/util/time_profiler.hpp +++ b/util/time_profiler.hpp @@ -37,16 +37,18 @@ namespace Internal { * defining TimeProfiler objects. */ struct TimeProfiler { - TimeProfiler(std::string&& function_name); +public: + TimeProfiler(std::string&& function_name); - ~TimeProfiler(); + ~TimeProfiler(); - static void print_execution_time(); + static void print_execution_time(); + static void print_execution_time(std::string function_name); private: - std::string _function_name; - std::chrono::_V2::system_clock::time_point _start; - static std::unordered_map _execution_time; + std::string _function_name; + std::chrono::_V2::system_clock::time_point _start; + static std::unordered_map _execution_time; }; } // namespace Internal diff --git a/util/user_input_handler.cpp b/util/user_input_handler.cpp index 714183c1..06d9d131 100644 --- a/util/user_input_handler.cpp +++ b/util/user_input_handler.cpp @@ -45,23 +45,20 @@ void version() // User Input Handler ---------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -UserInputHandler::UserInputHandler() : generic_("Generic options") - , config_("Configuration options"), hidden_("Hidden options") - , cmd_line_opts_("Command line options") - , cfg_file_opts_("Configuration file options"), positional_() +UserInputHandler::UserInputHandler() : _generic("Generic options") + , _config("Configuration options"), _hidden("Hidden options") + , _cmd_line_opts("Command line options") + , _cfg_file_opts("Configuration file options"), _positional() { - generic_.add_options() + _generic.add_options() ("help,h", "Prints all available options") ("version,v", "Displays version information") ("debug,d", "Activates debug messages") - ("config,c", prog_opts::value(&config_file_), "Configuration filename"); + ("config,c", prog_opts::value(&_config_file), "Configuration filename"); - hidden_.add_options() - ("input-file", prog_opts::value(&input_file_) + _hidden.add_options() + ("input-file", prog_opts::value(&_input_file) , "Input SBG program"); - - // First option without name is the input file - positional_.add("input-file", 1); } } // namespace Util diff --git a/util/user_input_handler.hpp b/util/user_input_handler.hpp index d069ebdd..65faa40a 100644 --- a/util/user_input_handler.hpp +++ b/util/user_input_handler.hpp @@ -43,18 +43,18 @@ class UserInputHandler { UserInputHandler(); virtual ~UserInputHandler() = default; - virtual void execute(int arg_count, char* args[]) = 0; + virtual void execute(int argc, char* argv[]) = 0; protected: - prog_opts::options_description generic_; ///< Descriptive info (version, etc.) - prog_opts::options_description config_; ///< SBG Program configuration - prog_opts::options_description hidden_; ///< Options hidden to the user - prog_opts::options_description cmd_line_opts_; ///< Command line options - prog_opts::options_description cfg_file_opts_; ///< Options in config files - prog_opts::options_description visible_; ///< All visible options for the user - prog_opts::positional_options_description positional_; - boost::optional config_file_; - boost::optional input_file_; + prog_opts::options_description _generic; ///< Descriptive info (version, etc.) + prog_opts::options_description _config; ///< SBG Program configuration + prog_opts::options_description _hidden; ///< Options hidden to the user + prog_opts::options_description _cmd_line_opts; ///< Command line options + prog_opts::options_description _cfg_file_opts; ///< Options in config files + prog_opts::options_description _visible; ///< All visible options for the user + prog_opts::positional_options_description _positional; + boost::optional _config_file; + boost::optional _input_file; }; } // namespace Util