From 93b2ff7dfaf3aba57631f45a48f479bb2af47e75 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 5 Mar 2026 20:31:11 -0300 Subject: [PATCH 01/66] [iss-132] --- CMakeLists.txt | 2 +- ast/expr.cpp | 46 +++++++++++++++++++++------------------------ ast/expr.hpp | 12 ++++++------ parser/expr.hpp | 11 ++++++----- parser/expr_def.hpp | 46 ++++++++++++++------------------------------- 5 files changed, 48 insertions(+), 69 deletions(-) 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/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/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_ From 2757885552e7556e1d580aa4c6d0603142b172b8 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 5 Mar 2026 20:33:29 -0300 Subject: [PATCH 02/66] Added compact structures (implementation details) --- sbg/interval.cpp | 189 +++++++++++++++++++++++--------------- sbg/interval.hpp | 69 +++++++------- sbg/linear_expr.cpp | 141 ++++++++++++++++++++++++++++ sbg/linear_expr.hpp | 105 +++++++++++++++++++++ sbg/multidim_inter.cpp | 203 ++++++++++++++++++++++++----------------- sbg/multidim_inter.hpp | 85 +++++++++-------- sbg/natural.cpp | 87 ++++++++++-------- sbg/natural.hpp | 66 +++++++------- sbg/rational.cpp | 126 +++++++++++-------------- sbg/rational.hpp | 62 +++++++------ 10 files changed, 731 insertions(+), 402 deletions(-) create mode 100755 sbg/linear_expr.cpp create mode 100755 sbg/linear_expr.hpp diff --git a/sbg/interval.cpp b/sbg/interval.cpp index 3a878389..14837806 100755 --- a/sbg/interval.cpp +++ b/sbg/interval.cpp @@ -19,58 +19,105 @@ #include "sbg/interval.hpp" +#include +#include +#include + +namespace { + +// 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; +} + +} // namespace + namespace SBG { namespace LIB { -member_imp(Interval, NAT, begin); -member_imp(Interval, NAT, step); -member_imp(Interval, NAT, end); +namespace detail { + +// Constructors/Destructors ---------------------------------------------------- + +Interval::Interval() : _begin(1), _step(1), _end(0) {} + +Interval::Interval(const NAT x) : _begin(x), _step(1), _end(x) {} -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 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 false; + } + + if (lhs.step() != rhs.step()) { + return false; + } + + if (lhs.end() != rhs.end()) { + return false; + } + + return true; } -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 +127,75 @@ 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::isMember(NAT x) const -{ - if (x < begin_ || x > end_) - return false; +bool Interval::isEmpty() const { return _end < _begin; } - int rem = fmod(x - begin_, step_); +NAT Interval::minElem() const { return _begin; } - return rem == 0; -} +NAT Interval::maxElem() const { return _end; } -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 +MaybeInterval Interval::compact(const Interval& other) const { - return std::min(*this, other); -} - -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 {}; } +} // namespace detail + } // namespace LIB } // namespace SBG diff --git a/sbg/interval.hpp b/sbg/interval.hpp index 59415708..adf52f7d 100755 --- a/sbg/interval.hpp +++ b/sbg/interval.hpp @@ -28,26 +28,26 @@ ******************************************************************************/ -#ifndef SBG_INTERVAL_HPP -#define SBG_INTERVAL_HPP - -#include +#ifndef SBGRAPH_SBG_INTERVAL_HPP_ +#define SBGRAPH_SBG_INTERVAL_HPP_ #include "sbg/natural.hpp" +#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 +56,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); - - bool operator==(const Interval &i) const; - bool operator!=(const Interval &i) const; + Interval(const NAT begin, const NAT step, const NAT end); - /** - * @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; + const NAT& begin() const; + const NAT& step() const; + const NAT& end() const; - // Traditional set operations ------------------------------------------------ + bool operator<(const Interval& other) const; /** * @brief Number of elements contained in the interval, i.e. @@ -81,32 +75,37 @@ 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; - - /** - * @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; + Interval offset(const NAT off) 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); + +} // namespace detail } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_INTERVAL_HPP_ diff --git a/sbg/linear_expr.cpp b/sbg/linear_expr.cpp new file mode 100755 index 00000000..0d921530 --- /dev/null +++ b/sbg/linear_expr.cpp @@ -0,0 +1,141 @@ +/******************************************************************************* + + 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" + +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); +} + +} // namespace detail + +} // namespace LIB + +} // namespace SBG diff --git a/sbg/linear_expr.hpp b/sbg/linear_expr.hpp new file mode 100755 index 00000000..cdff8c87 --- /dev/null +++ b/sbg/linear_expr.hpp @@ -0,0 +1,105 @@ +/** @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" + +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); + +} // namespace detail + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_SBG_LINEAR_EXPR_HPP_ diff --git a/sbg/multidim_inter.cpp b/sbg/multidim_inter.cpp index 16b6e6ad..90e7d76b 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,125 @@ 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 +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]; + MaybeInterval jth_compact = jth_this.compact(jth_other); + if (jth_this == jth_other) { + result.pushBack(jth_this); + } else { + 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 - res.emplaceBack(operator[](j)); + } else { + result.pushBack(operator[](j)); + } } - return res; + return result; } +} // namespace detail + } // namespace LIB } // namespace SBG diff --git a/sbg/multidim_inter.hpp b/sbg/multidim_inter.hpp index 6c6dc120..a06bb34d 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,29 @@ ******************************************************************************/ -#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 +#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 +57,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); - 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; + ConstIt begin() const; + ConstIt end() const; - bool operator==(const MultiDimInter &other) const; - bool operator!=(const MultiDimInter &other) const; + template + void emplaceBack(Args&&... args); + void pushBack(const Interval& i); + + 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 +100,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 +114,35 @@ 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; /** * @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 +inline void MultiDimInter::emplaceBack(Args&&... args) +{ + _intervals.emplace_back(std::forward(args)...); +} -typedef MultiDimInter SetPiece; +} // namespace detail } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_MULTIDIM_INTER_HPP_ 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/rational.cpp b/sbg/rational.cpp index dbb1ba20..51e66679 100755 --- a/sbg/rational.cpp +++ b/sbg/rational.cpp @@ -19,144 +19,122 @@ #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(RatType{n, 1}) {} -bool RATIONAL::operator!=(const RATIONAL &r) const -{ - return value_ != r.value_; -} +RATIONAL::RATIONAL(const RatType& 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 --------------------------------------------------------------------- + +const RatType& RATIONAL::value() const { return _value; } -bool RATIONAL::operator>=(const RATIONAL &r) const +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); + RATIONAL aux = *this; + return aux.numerator() == other && aux.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(); INT num = rv.numerator(), den = rv.denominator(); @@ -165,10 +143,10 @@ std::ostream &operator<<(std::ostream &out, const RATIONAL &r) 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..e9cb2b67 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,17 +43,16 @@ namespace LIB { * * @brief Integers implementation, used in rationals definition. */ -typedef long long int INT; -const INT INT_Inf = std::numeric_limits::max(); +using INT = long long int; +constexpr INT INT_Inf = std::numeric_limits::max(); -typedef boost::rational RatType; +using RatType = boost::rational; /** * @brief Used as coefficients and slopes in linear expressions. */ class RATIONAL { - member_class(RatType, value); - +public: /** * @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 RatType& 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 RatType& 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: + RatType _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_ From a6d384256090e4421e36a51de123e8037b97827b Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 5 Mar 2026 20:36:18 -0300 Subject: [PATCH 03/66] Redefined Sets using variant --- sbg/CMakeLists.txt | 16 +- sbg/ord_unidim_dense_set.cpp | 570 ++++++++++++++++------------------- sbg/ord_unidim_dense_set.hpp | 127 ++++---- sbg/set.cpp | 310 ++++++++++++++----- sbg/set.hpp | 213 ++++--------- sbg/set_fact.cpp | 142 ++++++--- sbg/set_fact.hpp | 97 +++--- sbg/unord_set.cpp | 444 +++++++++++++-------------- sbg/unord_set.hpp | 103 +++---- 9 files changed, 1033 insertions(+), 989 deletions(-) diff --git a/sbg/CMakeLists.txt b/sbg/CMakeLists.txt index d528027c..9daaee93 100644 --- a/sbg/CMakeLists.txt +++ b/sbg/CMakeLists.txt @@ -9,25 +9,27 @@ target_sources( PRIVATE 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_entry.cpp + map_detail.cpp multidim_inter.cpp - multidim_lexp.cpp natural.cpp - ord_set.cpp ord_unidim_dense_set.cpp - ord_pwmap.cpp pw_map.cpp pwmap_fact.cpp rational.cpp sbg.cpp set.cpp set_fact.cpp - unord_set.cpp unord_pwmap.cpp + unord_set.cpp + #ord_set.cpp + #dom_ord_pwmap.cpp + #map_entry.cpp + #ord_pwmap.cpp ) add_custom_target(sbg-doc diff --git a/sbg/ord_unidim_dense_set.cpp b/sbg/ord_unidim_dense_set.cpp index 6d4ab9e8..50ccbd2e 100644 --- a/sbg/ord_unidim_dense_set.cpp +++ b/sbg/ord_unidim_dense_set.cpp @@ -18,163 +18,211 @@ ******************************************************************************/ #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::IntervalOrdCollection& lhs, + const OrdUnidimDenseSet::IntervalOrdCollection& 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::IntervalOrdCollection + compact(const OrdUnidimDenseSet::IntervalOrdCollection& c) +{ + OrdUnidimDenseSet::IntervalOrdCollection 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::IntervalOrdCollection& pieces) + : _pieces(pieces) {} + +OrdUnidimDenseSet::OrdUnidimDenseSet( + OrdUnidimDenseSet::IntervalOrdCollection&& 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) { - if (mdi.isEmpty()) + if (mdi.isEmpty()) { return; + } - if (pieces_.empty() || pieces_.back() < mdi) { - pieces_.emplace_back(mdi); + if (_pieces.empty() || _pieces.back() < mdi) { + _pieces.emplace_back(mdi); return; } - if (mdi < pieces_.front()) { - pieces_.emplace(pieces_.begin(), mdi); + if (mdi < _pieces.front()) { + _pieces.emplace(_pieces.begin(), mdi); return; } - auto it = pieces_.begin(); - auto end = pieces_.end(); + auto it = _pieces.begin(); + auto end = _pieces.end(); for (; it != end; ++it) { - if (mdi < *it) + if (mdi < *it) { break; + } } - pieces_.emplace(it, mdi); - - return; + _pieces.emplace(it, mdi); } +*/ -void OrdUnidimDenseSet::emplaceBack(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_.rbegin(); - auto rend = pieces_.rend(); + auto it = _pieces.rbegin(); + auto rend = _pieces.rend(); for (; it != rend; ++it) { - if (*it < mdi) { + if (*it < i) { break; } } - pieces_.emplace(it.base(), mdi); - - return; + _pieces.insert(it.base(), i); } -bool OrdUnidimDenseSet::operator==(const SetStrategy& other) const +// Operators ------------------------------------------------------------------- + +bool OrdUnidimDenseSet::operator==(const OrdUnidimDenseSet& other) const { - SetStratPtr this_comp = compact(); - OrdUnidimDenseSetCRef ths = static_cast(*this_comp); - SetStratPtr other_comp = other.compact(); - OrdUnidimDenseSetCRef othr = static_cast(*other_comp); + if (isEmpty() && other.isEmpty()) { + return true; + } + + if (isEmpty() != other.isEmpty()) { + return false; + } + + if (_pieces == other._pieces) { + return true; + } - return ths.pieces_ == othr.pieces_; + return detail::compact(_pieces) == detail::compact(other._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 +239,210 @@ 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_)); - } - - 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)); + return OrdUnidimDenseSet{std::move(other._pieces)}; } - if (othr.maxElem() < minElem()) { - result = std::move(othr.pieces_); - result.insert(result.end(), pieces_.begin(), pieces_.end()); - return std::make_unique(std::move(result)); + IntervalOrdCollection 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()); + return intersection(other.complement()); } -// Extra operations ------------------------------------------------------------ - -std::size_t OrdUnidimDenseSet::arity() const +OrdUnidimDenseSet OrdUnidimDenseSet::cartesianProduct(const OrdUnidimDenseSet& + other) const { - if (isEmpty()) - return 0; + Util::ERROR("OrdUnidimDenseSet::cartesianProduct: operation not supported"); - 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_)); - } - - if (othr.isEmpty() || pieces_ == othr.pieces_) { - return std::make_unique(std::move(pieces_)); + return OrdUnidimDenseSet{std::move(other._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 (other.isEmpty() || _pieces == other._pieces) { + return OrdUnidimDenseSet{std::move(_pieces)}; } - 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)) { + IntervalOrdCollection 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)); -} - -SetStratPtr OrdUnidimDenseSet::filterSet(bool (*f)(const SetPiece& mdi)) const -{ - MDIOrdCollection res; - - for (const SetPiece& mdi : pieces_) - if (f(mdi)) - res.emplace_back(mdi); - - return std::make_unique(std::move(res)); + return traverse(least, other); } -SetStratPtr OrdUnidimDenseSet::offset(const MD_NAT& off) const +OrdUnidimDenseSet OrdUnidimDenseSet::offset(const MD_NAT& offset) const { - MDIOrdCollection res; + OrdUnidimDenseSet result; - for (const SetPiece& mdi : pieces_) - res.emplace_back(mdi.offset(off)); + for (const Interval& i : _pieces) { + result.pushBack(i.offset(offset[0])); + } - return std::make_unique(std::move(res)); + return result; } -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(); + IntervalOrdCollection 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 +450,64 @@ 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; + 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; } } - 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; - - 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; } } + result._pieces.insert(result.end(), it1, end1); + result._pieces.insert(result.end(), it2, end2); - for (; it1 != end1; ++it1) { - mdi1 = *it1; - res.emplace_back(mdi1); - } - - for (; it2 != end2; ++it2) { - mdi2 = *it2; - res.emplace_back(mdi2); - } - - 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..da434b0f 100644 --- a/sbg/ord_unidim_dense_set.hpp +++ b/sbg/ord_unidim_dense_set.hpp @@ -24,102 +24,103 @@ ******************************************************************************/ -#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 +#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 IntervalOrdCollection = std::vector; + using ConstIt = IntervalOrdCollection::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; + OrdUnidimDenseSet(const NAT x); + OrdUnidimDenseSet(const detail::Interval& i); + OrdUnidimDenseSet(const IntervalOrdCollection& pieces); + OrdUnidimDenseSet(IntervalOrdCollection&& pieces); + OrdUnidimDenseSet(const FixedPointsInfo& info); - class Iterator : public SetStrategy::Iterator { - member_class(MDIOrdCollection::const_iterator, it); + ConstIt begin() const; + ConstIt end() const; - 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; - }; + void pushBack(const Interval& mdi); - 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 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; + 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; + +private: + IntervalOrdCollection _pieces; }; -typedef const OrdUnidimDenseSet& OrdUnidimDenseSetCRef; -typedef OrdUnidimDenseSet& OrdUnidimDenseSetRef; +} // namespace detail } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_ORD_UNIDIM_DENSE_SET_HPP_ diff --git a/sbg/set.cpp b/sbg/set.cpp index f6e0ae2e..622fd2bc 100644 --- a/sbg/set.cpp +++ b/sbg/set.cpp @@ -17,91 +17,167 @@ ******************************************************************************/ -#include - #include "sbg/set.hpp" +#include "util/debug.hpp" + +#include namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Set Abstract Strategy Constructors ------------------------------------------ +// Set implementations --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -SetStrategy::SetStrategy() {} -SetStrategy::SetStrategy(const MD_NAT& x) {} -SetStrategy::SetStrategy(const Interval& i) {} -SetStrategy::SetStrategy(const SetPiece& mdi) {} +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; +} //////////////////////////////////////////////////////////////////////////////// -// Set Interface --------------------------------------------------------------- +// Set ------------------------------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// -Set::Set(SetStratPtr strat) : strategy_(std::move(strat)) {} -Set::Set(const Set& other) - : strategy_(other.strategy_ ? other.strategy_->clone() : nullptr) {} +// Constructors ---------------------------------------------------------------- -Set::Iterator::Iterator(std::shared_ptr it) - : it_(std::move(it)) {} - -void Set::Iterator::operator++() +Set::Set(const SetKind kind) : _impl() { - ++(*it_); - return; + switch (kind) { + case SetKind::kUnordered: { + _impl = detail::UnorderedSet{}; + break; + } + + case SetKind::kOrdered: { + 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(); } - -void Set::emplace(SetPiece mdi) +Set::Set(const SetKind kind, const MD_NAT& x) : _impl() { - strategy_->emplace(mdi); - return; + switch (kind) { + case SetKind::kUnordered: { + _impl = detail::UnorderedSet{x}; + break; + } + + case SetKind::kOrdered: { + 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 SetKind kind, const NAT lo, const NAT step, const NAT hi) + : _impl() { - strategy_->emplaceBack(mdi); - return; + switch (kind) { + case SetKind::kUnordered: { + _impl = detail::UnorderedSet{detail::Interval(lo, step, hi)}; + break; + } + + case SetKind::kOrdered: { + 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 SetKind kind, const FixedPointsInfo& info) : _impl() { - return *strategy_ == *other.strategy_; + switch (kind) { + case SetKind::kUnordered: { + _impl = detail::UnorderedSet{info}; + break; + } + + case SetKind::kOrdered: { + } + + 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 +187,160 @@ 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); +} -MD_NAT Set::minElem() const { return strategy_->minElem(); } +bool Set::isEmpty() const +{ + return std::visit([](const auto& a) { return a.isEmpty(); }, _impl); +} -MD_NAT Set::maxElem() const { return strategy_->maxElem(); } +MD_NAT Set::minElem() const +{ + return std::visit([](const auto& a) { return a.minElem(); }, _impl); +} + +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{SetKind::kUnordered}; + } + } + , _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{SetKind::kUnordered}; + } + } + , 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{SetKind::kUnordered}; + } + } + , _impl, other._impl); } -std::size_t Set::arity() const { return strategy_->arity(); } +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{SetKind::kUnordered}; + } + } + , _impl, other._impl); +} + +// 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{SetKind::kUnordered}; + } + } + , 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(); } +void Set::compact() { std::visit([](auto& a) { a.compact(); }, _impl); } } // namespace LIB diff --git a/sbg/set.hpp b/sbg/set.hpp index a4d2dcaa..549d8329 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,60 @@ ******************************************************************************/ -#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_unidim_dense_set.hpp" +#include "sbg/set.hpp" +#include "sbg/unord_set.hpp" + +#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; +using SetImpl = std::variant; - // Traditional set operations ------------------------------------------------ +using SetConstIt = std::variant; - /** - * @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; +class MapDetail; - // Extra operations ---------------------------------------------------------- +} - /** - * @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; -}; +enum class SetKind { kUnordered, kOrdered, kOrdUnidimDense }; + +std::ostream& operator<<(std::ostream& out, const SetKind kind); //////////////////////////////////////////////////////////////////////////////// -// 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(const SetKind kind); + Set(const SetKind kind, const MD_NAT& x); + Set(const SetKind kind, MD_NAT&& x); + Set(const SetKind kind, const NAT lo, const NAT st, const NAT hi); + Set(const SetKind kind, 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 +92,38 @@ 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; + void compact(); - private: - SetStratPtr strategy_; +private: + Set(const detail::SetImpl& impl); + Set(detail::SetImpl&& impl); + + detail::SetImpl _impl; + + friend class detail::MapDetail; }; + 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_fact.cpp b/sbg/set_fact.cpp index 975eb89a..a29b4d85 100644 --- a/sbg/set_fact.cpp +++ b/sbg/set_fact.cpp @@ -18,9 +18,8 @@ ******************************************************************************/ #include "sbg/set_fact.hpp" -#include "sbg/ord_set.hpp" -#include "sbg/ord_unidim_dense_set.hpp" #include "sbg/unord_set.hpp" +#include "util/debug.hpp" namespace SBG { @@ -30,103 +29,148 @@ namespace LIB { // Unordered Set Factory ------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -Set UnordSetFact::createSet() const -{ - return Set(std::make_unique()); -} +UnordSetFact::UnordSetFact() {} -Set UnordSetFact::createSet(const MD_NAT &x) const +Set UnordSetFact::createSet() { - return Set(std::make_unique(x)); + return Set{SetKind::kUnordered}; } -Set UnordSetFact::createSet(const Interval &i) const +Set UnordSetFact::createSet(const MD_NAT& x) { - return Set(std::make_unique(i)); + return Set{SetKind::kUnordered, x}; } -Set UnordSetFact::createSet(const SetPiece &mdi) const +Set UnordSetFact::createSet(const NAT lo, const NAT step, const NAT hi) { - return Set(std::make_unique(mdi)); + return Set{SetKind::kUnordered, lo, step, hi}; } -std::string UnordSetFact::prettyPrint() const +Set UnordSetFact::createSet(const FixedPointsInfo& info) { - return "unordered"; + return Set{SetKind::kUnordered, info}; } +////////////////////////////////////////////////////////////////////////////////// +//// 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)); +//} +// +//Set OrdSetFact::createSet(const FixedPointsInfo& info) const +//{ +// return Set(std::make_unique(info)); +//} + //////////////////////////////////////////////////////////////////////////////// // Ordered Unidimensional Dense Set Factory ------------------------------------ //////////////////////////////////////////////////////////////////////////////// Set OrdUnidimDenseSetFact::createSet() const { - return Set(std::make_unique()); + return Set{SetKind::kOrdUnidimDense}; } -Set OrdUnidimDenseSetFact::createSet(const MD_NAT &x) const +Set OrdUnidimDenseSetFact::createSet(const MD_NAT& x) const { - return Set(std::make_unique(x)); + return Set{SetKind::kOrdUnidimDense, x}; } -Set OrdUnidimDenseSetFact::createSet(const Interval &i) const +Set OrdUnidimDenseSetFact::createSet(const NAT lo, const NAT step, const NAT hi) + const { - return Set(std::make_unique(i)); + return Set{SetKind::kOrdUnidimDense, lo, step, hi}; } -Set OrdUnidimDenseSetFact::createSet(const SetPiece &mdi) const +Set OrdUnidimDenseSetFact::createSet(const FixedPointsInfo& info) const { - return Set(std::make_unique(mdi)); -} - -std::string OrdUnidimDenseSetFact::prettyPrint() const -{ - return "ordered unidimensional dense"; + return Set{SetKind::kOrdUnidimDense, info}; } //////////////////////////////////////////////////////////////////////////////// -// Ordered Set Factory --------------------------------------------------------- +// Factory for clients --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -Set OrdSetFact::createSet() const -{ - return Set(std::make_unique()); -} +SetFactory::SetFactory() : _kind(SetKind::kUnordered), _impl(UnordSetFact{}) {} -Set OrdSetFact::createSet(const MD_NAT &x) const +SetFactory& SetFactory::instance() { - return Set(std::make_unique(x)); + static SetFactory _instance; + return _instance; } -Set OrdSetFact::createSet(const Interval &i) const +const SetKind& SetFactory::kind() const { return _kind; } + +void SetFactory::set_set_fact(SetKind kind) { - return Set(std::make_unique(i)); + _kind = kind; + switch (kind) { + case SetKind::kUnordered: { + _impl = UnordSetFact{}; + break; + } + + //case SetKind::kOrdered: { + // _impl = OrdSetFact{}; + // break; + //} + + case SetKind::kOrdUnidimDense: { + _impl = OrdUnidimDenseSetFact{}; + break; + } + + default: { + Util::ERROR("Unsupported ", kind, " Set implementation\n"); + break; + } + } } -Set OrdSetFact::createSet(const SetPiece &mdi) const +Set SetFactory::createSet() const { - return Set(std::make_unique(mdi)); + return std::visit( + [](const auto& a) { return a.createSet(); } + , _impl); } -std::string OrdSetFact::prettyPrint() const +Set SetFactory::createSet(const MD_NAT& x) const { - return "ordered"; + return std::visit( + [&x](const auto& a) { return a.createSet(x); } + , _impl); } -//////////////////////////////////////////////////////////////////////////////// -// Factory for clients --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -SetFactory::SetFactory() : set_fact_(std::make_unique()) {} - -SetFact& SetFactory::set_fact() +Set SetFactory::createSet(const NAT lo, const NAT step, const NAT hi) const { - return *set_fact_; + return std::visit( + [&](const auto& a) { return a.createSet(lo, step, hi); } + , _impl); } -void SetFactory::set_set_fact(SetFactPtr set_fact) +Set SetFactory::createSet(const FixedPointsInfo& info) const { - set_fact_ = std::move(set_fact); + return std::visit( + [&info](const auto& a) { return a.createSet(info); } + , _impl); } } // namespace LIB diff --git a/sbg/set_fact.hpp b/sbg/set_fact.hpp index b769b6ad..826c149d 100644 --- a/sbg/set_fact.hpp +++ b/sbg/set_fact.hpp @@ -25,80 +25,79 @@ ******************************************************************************/ -#ifndef SBG_SET_FACT_HPP -#define SBG_SET_FACT_HPP +#ifndef SBGRAPH_SBG_SET_FACT_HPP_ +#define SBGRAPH_SBG_SET_FACT_HPP_ -#include "set.hpp" +#include "sbg/interval.hpp" +#include "sbg/multidim_inter.hpp" +#include "sbg/natural.hpp" +#include "sbg/set.hpp" + +#include +#include namespace SBG { namespace LIB { -#define SET_FACT SetFactory::instance().set_fact() - -class SetFact { - public: - virtual ~SetFact() = default; +#define SET_FACT SetFactory::instance() - 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 UnordSetFact { +public: + UnordSetFact(); -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; + static Set createSet(); + static Set createSet(const MD_NAT& x); + static Set createSet(const NAT lo, const NAT step, const NAT hi); + static Set createSet(const FixedPointsInfo& info); }; -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; +//class OrdSetFact { +//public: +// Set createSet() const; +// Set createSet(const MD_NAT& x) const; +// Set createSet(const NAT lo, const NAT step, const NAT hi) const; +// Set createSet(const FixedPointsInfo& mdi) const; +//}; + +class OrdUnidimDenseSetFact { +public: + Set createSet() const; + Set createSet(const MD_NAT& x) const; + Set createSet(const NAT lo, const NAT step, const NAT hi) const; + Set createSet(const FixedPointsInfo& info) const; }; -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: +public: ~SetFactory() = default; - static SetFactory& instance() { - static SetFactory instance_; - return instance_; - } - SetFact& set_fact(); - void set_set_fact(SetFactPtr set_fact); + static SetFactory& instance(); + + void set_set_fact(SetKind kind); + const SetKind& kind() const; + + Set createSet() const; + Set createSet(const MD_NAT& x) const; + Set createSet(const NAT lo, const NAT step, const NAT hi) const; + Set createSet(const FixedPointsInfo& mdi) const; + +private: + using FactImpl = std::variant; - private: SetFactory(); - SetFactPtr set_fact_; + + SetKind _kind; + FactImpl _impl; }; } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_SET_FACT_HPP_ diff --git a/sbg/unord_set.cpp b/sbg/unord_set.cpp index a700fa16..35895cc9 100644 --- a/sbg/unord_set.cpp +++ b/sbg/unord_set.cpp @@ -17,127 +17,117 @@ ******************************************************************************/ -#include - #include "sbg/unord_set.hpp" +#include +#include +#include + namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // Unordered Set Implementation ------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// -member_imp(UnorderedSet, UnorderedSet::MDIUnordCollection, pieces); +// Constructors/Destructors ---------------------------------------------------- -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)) {} +UnorderedSet::UnorderedSet() : _pieces() {} -SetStratPtr UnorderedSet::clone() const +UnorderedSet::UnorderedSet(const MD_NAT& x) : _pieces() { - return std::make_unique(*this); + _pieces.emplace_back(MultiDimInter{x}); } -member_imp(UnorderedSet::Iterator - , UnorderedSet::MDIUnordCollection::const_iterator, it); - -UnorderedSet::Iterator::Iterator( - UnorderedSet::MDIUnordCollection::const_iterator it) : it_(it) {} - -void UnorderedSet::Iterator::operator++() +UnorderedSet::UnorderedSet(const Interval& i) : _pieces() { - ++it_; - return; + 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); + } } -bool UnorderedSet::Iterator::operator==(const SetStrategy::Iterator& other) - const -{ - return it_ == static_cast(&other)->it_; -} +UnorderedSet::UnorderedSet(const UnorderedSet::MDIUnordCollection& pieces) + : _pieces(pieces) {} -bool UnorderedSet::Iterator::operator<(const SetStrategy::Iterator& other) const +UnorderedSet::UnorderedSet(UnorderedSet::MDIUnordCollection&& pieces) + : _pieces(std::move(pieces)) {} + +UnorderedSet::UnorderedSet(const FixedPointsInfo& info) : _pieces() { - return it_ < static_cast(&other)->it_; + 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); + } } -const SetPiece& UnorderedSet::Iterator::operator*() const { return *it_; } +// Getters --------------------------------------------------------------------- -std::shared_ptr UnorderedSet::begin() const -{ - return std::make_shared(pieces_.begin()); -} +UnorderedSet::ConstIt UnorderedSet::begin() const { return _pieces.begin(); } -std::shared_ptr UnorderedSet::end() const -{ - return std::make_shared(pieces_.end()); -} +UnorderedSet::ConstIt UnorderedSet::end() const { return _pieces.end(); } -std::size_t UnorderedSet::size() const { return pieces_.size(); } +// Setters --------------------------------------------------------------------- -void UnorderedSet::emplace(const SetPiece& mdi) +void UnorderedSet::pushBack(const MultiDimInter& mdi) { if (mdi.isEmpty()) { return; } - pieces_.emplace(pieces_.begin(), mdi); - return; + _pieces.push_back(mdi); } -void UnorderedSet::emplaceBack(const SetPiece& mdi) +// Operators ------------------------------------------------------------------- + +bool UnorderedSet::operator==(const UnorderedSet& other) const { - if (mdi.isEmpty()) { - return; + if (isEmpty() && other.isEmpty()) { + return true; } - pieces_.emplace_back(mdi); - return; -} - -bool UnorderedSet::operator==(const SetStrategy& other) const -{ - UnordSetCRef othr = static_cast(other); + 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,139 +148,113 @@ 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; for (const Interval& i : mdi) { @@ -298,11 +262,11 @@ SetStratPtr UnorderedSet::complementAtom() const // 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; + c.push_back(univ); + univ[dim] = universe_one_dim; } } @@ -310,10 +274,10 @@ SetStratPtr UnorderedSet::complementAtom() const 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()); + 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); + c.push_back(during_mdi); } } } @@ -321,57 +285,80 @@ SetStratPtr UnorderedSet::complementAtom() const // 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; + c.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); + for (const MultiDimInter& mdi : c) { + result.push_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()); + UnorderedSet result; - auto first_it = pieces_.begin(); - SetPiece first = *first_it; - res = std::move(UnorderedSet(first).complementAtom()); + if (isEmpty()) { + return result; + } + + auto first_it = _pieces.begin(); + MultiDimInter first = *first_it; + result = UnorderedSet{first}.complementAtom(); ++first_it; - MDIUnordCollection second(first_it, pieces_.end()); - for (const SetPiece& mdi : second) { - SetStratPtr c = UnorderedSet(mdi).complementAtom(); - res = std::move(res->intersection(*c)); + MDIUnordCollection second{first_it, _pieces.end()}; + for (const MultiDimInter& mdi : second) { + UnorderedSet c = UnorderedSet{mdi}.complementAtom(); + result = result.intersection(c); } - 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 ------------------------------------------------------------ @@ -381,90 +368,71 @@ std::size_t UnorderedSet::arity() const 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; + MDIUnordCollection result; - for (const SetPiece& mdi : pieces_) { - if (f(mdi)) { - res.emplace_back(mdi); - } + for (const MultiDimInter& mdi : _pieces) { + result.push_back(mdi.offset(off)); } - return std::make_unique(std::move(res)); + return UnorderedSet{std::move(result)}; } -SetStratPtr UnorderedSet::offset(const MD_NAT& off) const +void UnorderedSet::compact() { - MDIUnordCollection res; - - for (const SetPiece& mdi : pieces_) { - res.emplace_back(mdi.offset(off)); - } - - return std::make_unique(std::move(res)); -} - -SetStratPtr UnorderedSet::compact() const -{ - MDIUnordCollection res; + MDIUnordCollection result; if (!isEmpty()) { - std::set prev(pieces_.begin(), pieces_.end()); - std::set actual = prev; + std::set prev{_pieces.begin(), _pieces.end()}; + std::set actual = prev; do { prev = actual; - actual = std::set(); + actual = std::set{}; - std::set::iterator ith = prev.begin(); - std::set::iterator last = prev.end(); - std::set to_erase; + std::set::iterator ith = prev.begin(); + std::set::iterator last = prev.end(); + std::set to_erase; for (; ith != last; ++ith) { - SetPiece ith_compact = *ith; - std::set::iterator next = ith; + MultiDimInter ith_compact = *ith; + std::set::iterator next = ith; ++next; for (; next != last; ++next) { MaybeMDI new_compact = ith_compact.compact(*next); @@ -474,18 +442,22 @@ SetStratPtr UnorderedSet::compact() const } } - if (to_erase.find(ith_compact) == to_erase.end()) + if (to_erase.find(ith_compact) == to_erase.end()) { actual.insert(ith_compact); - } + } + } } while (actual != prev); - for (const SetPiece& mdi : actual) - res.emplace_back(mdi); + for (const MultiDimInter& mdi : actual) { + result.push_back(mdi); + } } - return std::make_unique(std::move(res)); + _pieces = std::move(result); } +} // namespace detail + } // namespace LIB } // namespace SBG diff --git a/sbg/unord_set.hpp b/sbg/unord_set.hpp index ed80cd91..593dadc1 100644 --- a/sbg/unord_set.hpp +++ b/sbg/unord_set.hpp @@ -21,88 +21,89 @@ ******************************************************************************/ -#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 +#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); + ConstIt begin() const; + ConstIt end() const; - 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; - }; + void pushBack(const MultiDimInter& mdi); - 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 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; + void compact(); - private: +private: /** * @brief Calculate the complement of an unordered set with a single piece. */ - SetStratPtr complementAtom() const; + UnorderedSet complementAtom() const; + + MDIUnordCollection _pieces; }; -typedef const UnorderedSet& UnordSetCRef; +} // namespace detail } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_UNORD_SET_HPP_ From c7f00443fc2fcb42348fb44c52916f19e1fdcab0 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 5 Mar 2026 20:38:05 -0300 Subject: [PATCH 04/66] Redefined up to Maps --- sbg/expression.cpp | 224 ++++++++++++++++++++ sbg/expression.hpp | 139 ++++++++++++ sbg/expression_impl.hpp | 44 ++++ sbg/fixed_points.cpp | 37 ++++ sbg/fixed_points.hpp | 59 ++++++ sbg/lexp.cpp | 124 ----------- sbg/lexp.hpp | 83 -------- sbg/map.cpp | 405 ++++++++--------------------------- sbg/map.hpp | 88 ++++---- sbg/map_detail.cpp | 459 ++++++++++++++++++++++++++++++++++++++++ sbg/map_detail.hpp | 77 +++++++ sbg/multidim_lexp.cpp | 139 ------------ sbg/multidim_lexp.hpp | 116 ---------- 13 files changed, 1163 insertions(+), 831 deletions(-) create mode 100755 sbg/expression.cpp create mode 100755 sbg/expression.hpp create mode 100755 sbg/expression_impl.hpp create mode 100755 sbg/fixed_points.cpp create mode 100755 sbg/fixed_points.hpp delete mode 100755 sbg/lexp.cpp delete mode 100755 sbg/lexp.hpp create mode 100755 sbg/map_detail.cpp create mode 100755 sbg/map_detail.hpp delete mode 100755 sbg/multidim_lexp.cpp delete mode 100755 sbg/multidim_lexp.hpp diff --git a/sbg/expression.cpp b/sbg/expression.cpp new file mode 100755 index 00000000..b2b25415 --- /dev/null +++ b/sbg/expression.cpp @@ -0,0 +1,224 @@ +/******************************************************************************* + + 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 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; + + std::optional empty = {}; + 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; +} + +} // namespace LIB + +} // namespace SBG diff --git a/sbg/expression.hpp b/sbg/expression.hpp new file mode 100755 index 00000000..810ed86b --- /dev/null +++ b/sbg/expression.hpp @@ -0,0 +1,139 @@ +/** @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 + +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); + + 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; + +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/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/map.cpp b/sbg/map.cpp index dfe54653..beec9089 100755 --- a/sbg/map.cpp +++ b/sbg/map.cpp @@ -18,176 +18,49 @@ ******************************************************************************/ #include "sbg/map.hpp" +#include "sbg/map_detail.hpp" +#include "sbg/set_fact.hpp" + +#include namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Auxiliary functions --------------------------------------------------------- +// Map Implementation ---------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -// Image ----------------------------------------------------------------------- +// Constructors/Destructors ---------------------------------------------------- -Interval image(Interval i, LExp le) { - RATIONAL m = le.slope(), h = le.offset(); - NAT new_begin = 0, new_step = 0, new_end = 0; +Map::Map() : _domain(SET_FACT.createSet()) {} - RATIONAL rat_inf(INT_Inf, 1); - if (m == rat_inf || m > rat_inf) - return Interval(0, 1, Inf); +Map::Map(const MD_NAT& x, const Expression& expr) + : _domain(SET_FACT.createSet(x)), _law(expr) {} - if (le.isId()) { - return i; - } +Map::Map(const Set& s, const Expression& expr) : _domain(s), _law(expr) {} - if (le.isConstant()) { - NAT off = le.offset().toNat(); - return Interval(off, 1, off); - } +Map::Map(Set&& s, Expression&& expr) + : _domain(std::move(s)), _law(std::move(expr)) {} - if (i.begin() == i.end()) { - NAT x = (m * i.begin() + h).toNat(); - return Interval(x, 1, x); - } +// Getters --------------------------------------------------------------------- - // 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(); - } +const Set& Map::domain() const & { return _domain; } - // 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(); - } - - return Interval(new_begin, new_step, new_end); -} - -SetPiece image(SetPiece mdi, Exp mdle) -{ - if (mdi.isEmpty()) - return mdi; - - SetPiece res; - for (unsigned int j = 0; j < mdi.arity(); ++j) - res.emplaceBack(image(mdi[j], mdle[j])); - - 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 ---------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// +Set Map::domain() && { return std::move(_domain); } -member_imp(Map, Set, dom); -member_imp(Map, Exp, exp); +const Expression& Map::law() const { return _law; } -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,242 +71,132 @@ 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_FACT.createSet(); + } - 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_FACT.createSet(); } - 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); - } - } - Map inv(cap_subcodom, inv_exp); - Set inv_im = inv.image(); - - return dom_.intersection(inv_im); + Set image_subcodom = image().intersection(subcodom); + return detail::MapDetail::preImage(image_subcodom, _law) + .intersection(_domain); } 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 = SET_FACT.createSet(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); + Set result = detail::MapDetail::lessImage(_law, other._law); + result = std::move(result).intersection(cap_dom); return result; } -std::vector Map::reduce() const +Map Map::minAdj(const Map& other) const { - std::vector result; + Set result_domain = image(_domain.intersection(other._domain)); - Map m = *this; - if (!reductionIsEfficient(m)) { - result.emplace_back(m); + Expression result_expr; + Set image2 = other.image(result_domain); + 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()); - } - } - } + result_expr = Expression{image2.minElem()}; } - return result; + return Map{result_domain, result_expr}; +} + +std::vector Map::reduce() const +{ + return detail::MapDetail::reduce(*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 = SET_FACT.createSet(); + if (_law == other.law()) { + Set result_dom = _domain.disjointCup(other.domain()); + result_dom.compact(); + return Map{std::move(result_dom), Expression{_law}}; } return {}; diff --git a/sbg/map.hpp b/sbg/map.hpp index 8a034fbc..a177fb92 100755 --- a/sbg/map.hpp +++ b/sbg/map.hpp @@ -26,11 +26,15 @@ ******************************************************************************/ -#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 +#include namespace SBG { @@ -38,19 +42,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 +55,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 +80,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 +90,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. @@ -120,7 +110,7 @@ class Map { * @param subcodom Set of elements in the image of the map for which the * pre image will be calculated. */ - Set preImage(const Set& subcodom) const; + Set preImage(const Set& subcodom) const; // opt /** * @brief Calculate the composition of \p this with \p other, i.e. @@ -135,14 +125,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,19 +134,29 @@ 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 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); @@ -172,4 +164,4 @@ std::ostream& operator<<(std::ostream& out, const Map& s); } // 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..6b5dd1f3 --- /dev/null +++ b/sbg/map_detail.cpp @@ -0,0 +1,459 @@ +/******************************************************************************* + + 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_fact.hpp" +#include "sbg/unord_set.hpp" + +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; +} + +UnorderedSet image(const UnorderedSet& s, const ExpressionImpl& expr + , bool is_injective) +{ + return compactImage( + s, expr, is_injective); +} + +OrdUnidimDenseSet image(const OrdUnidimDenseSet& s + , const LinearExpr& linear_expr, bool is_injective) +{ + return compactImage( + s, linear_expr, is_injective); +} + +Set MapDetail::image(const Set& s, const Expression& expr) +{ + auto image_evaluator = Overload { + [&](const UnorderedSet& a) + { + return Set{detail::image(a, expr._impl, expr.isInjective())}; + }, + [&](const OrdUnidimDenseSet& a) + { + return Set{detail::image(a, expr._impl[0], expr.isInjective())}; + }, + [&](const auto& a) { return Set{SetKind::kUnordered}; } + }; + return std::visit(image_evaluator, s._impl); +} + +// 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; +} + +UnorderedSet preImage(const UnorderedSet& s, const ExpressionImpl& linear_expr) +{ + return compactPreImage( + s, linear_expr); +} + +OrdUnidimDenseSet preImage(const OrdUnidimDenseSet& s + , const LinearExpr& linear_expr) +{ + return compactPreImage( + s, linear_expr); +} + +Set MapDetail::preImage(const Set& s, const Expression& expr) +{ + auto pre_image_evaluator = Overload { + [&](const UnorderedSet& a) + { + return Set{detail::preImage(a, expr._impl)}; + }, + [&](const OrdUnidimDenseSet& a) + { + return Set{detail::preImage(a, expr._impl[0])}; + }, + [&](const auto& a) { return Set{SetKind::kUnordered}; } + }; + return std::visit(pre_image_evaluator, s._impl); +} + +// 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 = SET_FACT.createSet(); + + auto less_image_evaluator = Overload { + [&](UnorderedSet& a) + { + detail::lessImage( + expr1._impl, expr2._impl, a); + return Set{a}; + }, + [&](OrdUnidimDenseSet& a) + { + a.pushBack(detail::lessImage(expr1._impl[0], expr2._impl[0])); + return Set{a}; + }, + [&](auto& a) { return Set{SetKind::kUnordered}; } + }; + return std::visit(less_image_evaluator, result._impl); + + 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 + unsigned int arity = mdi.arity(); + Interval reducible_interval; + LinearExpr reducible_expr; + for (auto 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); +} + +MapVector MapDetail::reduce(const UnorderedSet& s, const ExpressionImpl& expr) +{ + MapVector result; + + 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) { + UnorderedSet domain; + mdi_copy[k_reduce] = r.first; + domain.pushBack(mdi_copy); + expr_copy[k_reduce] = r.second; + result.emplace_back(Set{domain} + , Expression{expr_copy}); + } + } + + return result; +} + +MapVector MapDetail::reduce(const OrdUnidimDenseSet& s + , const ExpressionImpl& expr) +{ + MapVector result; + + 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(Set{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; + } + + result = std::visit([&](const auto& a) + { + return reduce(a, law._impl); + } + , domain._impl); + + return result; +} + +} // namespace detail + +} // namespace LIB + +} // namespace SBG diff --git a/sbg/map_detail.hpp b/sbg/map_detail.hpp new file mode 100755 index 00000000..a884845c --- /dev/null +++ b/sbg/map_detail.hpp @@ -0,0 +1,77 @@ +/** @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" + +namespace SBG { + +namespace LIB { + +namespace detail { + +using AtomicMap = std::pair; +using AtomicMapVector = std::vector; +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); + +private: + static MapVector reduce(const UnorderedSet& s, const ExpressionImpl& expr); + static MapVector reduce(const OrdUnidimDenseSet& s + , const ExpressionImpl& expr); +}; + +template +class Overload : Ts... { +public: + using Ts::operator()...; + Overload(Ts... ts) : Ts(ts)... {}; +}; + +template +Overload(Ts...) -> Overload; + +} // namespace detail + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_SBG_MAP_DETAIL_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 From d9857e4aab8c038b33940f7eaed9b591498dcae2 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 5 Mar 2026 20:38:38 -0300 Subject: [PATCH 05/66] Refined up to PWMaps --- sbg/pw_map.cpp | 391 +++++++++++++++++++++++------ sbg/pw_map.hpp | 269 ++++++-------------- sbg/pwmap_fact.cpp | 143 ++++++----- sbg/pwmap_fact.hpp | 106 ++++---- sbg/unord_pwmap.cpp | 596 ++++++++++++++++++++------------------------ sbg/unord_pwmap.hpp | 152 ++++++----- 6 files changed, 877 insertions(+), 780 deletions(-) diff --git a/sbg/pw_map.cpp b/sbg/pw_map.cpp index 958dafd2..5dd9fbb8 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,420 @@ ******************************************************************************/ #include "sbg/pw_map.hpp" +#include "util/debug.hpp" + +#include namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// PWMap Abstract Strategy Constructors ---------------------------------------- +// PWMap implementations ------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -PWMapStrategy::PWMapStrategy() {} +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; +} //////////////////////////////////////////////////////////////////////////////// -// PWMap Interface ------------------------------------------------------------- +// PWMap ---------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -PWMap::PWMap(PWMapStratPtr strat) : strategy_(std::move(strat)) {} +// Constructors ---------------------------------------------------------------- -PWMap::PWMap(const PWMap& other) - : strategy_(other.strategy_ ? other.strategy_->clone() : nullptr) {} +PWMap::PWMap(const PWMapKind kind) : _impl() +{ + switch (kind) { + case PWMapKind::kUnordered: { + _impl = detail::UnordPWMap{}; + break; + } + + case PWMapKind::kOrdered: { + break; + } + + case PWMapKind::kDomOrdered: { + break; + } + + default: { + Util::ERROR("Unsupported ", kind, " PWMap implementation\n"); + break; + } + } +} -PWMap::Iterator::Iterator(std::shared_ptr it) - : it_(std::move(it)) {} +PWMap::PWMap(const PWMapKind kind, Set s) : _impl() +{ + switch (kind) { + case PWMapKind::kUnordered: { + _impl = detail::UnordPWMap{s}; + break; + } + + case PWMapKind::kOrdered: { + break; + } + + case PWMapKind::kDomOrdered: { + break; + } + + default: { + Util::ERROR("Unsupported ", kind, " PWMap implementation\n"); + break; + } + } +} -void PWMap::Iterator::operator++() +PWMap::PWMap(const PWMapKind kind, Map m) : _impl() { - ++(*it_); - return; + switch (kind) { + case PWMapKind::kUnordered: { + _impl = detail::UnordPWMap{m}; + break; + } + + case PWMapKind::kOrdered: { + break; + } + + case PWMapKind::kDomOrdered: { + break; + } + + default: { + Util::ERROR("Unsupported ", kind, " PWMap implementation\n"); + break; + } + } } -Map PWMap::Iterator::operator*() const { return **it_; } +PWMap::PWMap(const detail::PWMapImpl& impl) + : _impl(impl) {} + +PWMap::PWMap(detail::PWMapImpl&& impl) + : _impl(std::move(impl)) {} + +// Getters --------------------------------------------------------------------- + +PWMap::ConstIt PWMap::begin() +{ + return std::visit([](const auto& a) { return a.begin(); }, _impl); +} -bool PWMap::Iterator::operator!=(const Iterator& other) const +PWMap::ConstIt PWMap::end() { - return *it_ != *other.it_; + return std::visit([](const auto& a) { return a.end(); }, _impl); } -PWMap::Iterator PWMap::begin() const { return strategy_->begin(); } -PWMap::Iterator PWMap::end() const { return strategy_->end(); } +// Setters --------------------------------------------------------------------- -void PWMap::emplaceBack(const Map& m) +void PWMap::pushBack(const Map& m) { - strategy_->emplaceBack(m); - return; + std::visit([&m](auto& a) -> void { a.pushBack(m); } , _impl); } -bool PWMap::operator==(const PWMap& other) const +void PWMap::pushBack(Map&& m) { - return *strategy_ == *other.strategy_; + std::visit([move_m = std::move(m)](auto& a) { a.pushBack(move_m); } + , _impl); } -bool PWMap::operator!=(const PWMap& other) const { return !(*this == other); } +// Operators ------------------------------------------------------------------- -PWMap& PWMap::operator=(const PWMap& other) +bool PWMap::operator==(const PWMap& other) const { - if (this !=& other) - strategy_ = other.strategy_->clone(); - - return *this; + 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{PWMapKind::kUnordered}; + } + } + , _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{PWMapKind::kUnordered}; + } + } + , _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{PWMapKind::kUnordered}; + } + } + , 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::filterMap(bool (*f)(const Map&)) const +PWMap PWMap::combine(const PWMap& other) && { - return strategy_->filterMap(f); + return std::move(*this).combine(PWMap{other}); } -Set PWMap::equalImage(const PWMap& other) const +PWMap PWMap::combine(PWMap&& other) const & { - return strategy_->equalImage(*other.strategy_); + return PWMap{*this}.combine(std::move(other)); } -Set PWMap::lessImage(const PWMap& other) const +PWMap PWMap::combine(PWMap&& other) && { - return strategy_->lessImage(*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{PWMapKind::kUnordered}; + } + } + , std::move(_impl), std::move(other._impl)); } -Set PWMap::sharedImage() const { return strategy_->sharedImage(); } +PWMap PWMap::min(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.min(b)}; + } else { + Util::ERROR("PWMap::min: mismatched implementations\n"); + return PWMap{PWMapKind::kUnordered}; + } + } + , _impl, other._impl); +} -PWMap PWMap::offsetDom(const MD_NAT& off) const +PWMap PWMap::minAdj(const PWMap& other) const { - return strategy_->offsetDom(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 PWMap{a.minAdj(b)}; + } else { + Util::ERROR("PWMap::minAdj: mismatched implementations\n"); + return PWMap{PWMapKind::kUnordered}; + } + } + , _impl, other._impl); } -PWMap PWMap::offsetDom(const PWMap& off) const +Set PWMap::sharedImage() const { - return strategy_->offsetDom(*off.strategy_); + return std::visit([](const auto& a) { return a.sharedImage(); }, _impl); } -PWMap PWMap::offsetImage(const MD_NAT& off) const +Set PWMap::equalImage(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.equalImage(b); + } else { + Util::ERROR("PWMap::equalImage: mismatched implementations\n"); + return PWMap{PWMapKind::kUnordered}; + } + } + , _impl, other._impl); } -PWMap PWMap::offsetImage(const Exp& 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 PWMap{PWMapKind::kUnordered}; + } + } + , _impl, other._impl); } -PWMap PWMap::compact() const { return strategy_->compact(); } +PWMap PWMap::offsetDom(const MD_NAT& offset) const +{ + return std::visit([&offset](const auto& a) -> PWMap + { + return PWMap{a.offsetDom(offset)}; + } + , _impl); +} -} // namespace LIB +void PWMap::compact() +{ + std::visit([](auto& a) { a.compact(); }, _impl); +} -} // namespace SBG; +} // namespace LIB +} // namespace SBG diff --git a/sbg/pw_map.hpp b/sbg/pw_map.hpp index 10bf6663..3e6a99c4 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,67 @@ ******************************************************************************/ -#ifndef SBG_PWMAP_HPP -#define SBG_PWMAP_HPP - -#include +#ifndef SBGRAPH_SBG_PW_MAP_HPP_ +#define SBGRAPH_SBG_PW_MAP_HPP_ #include "sbg/map.hpp" +#include "sbg/set.hpp" +#include "sbg/unord_pwmap.hpp" namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// -// PWMap Abstract Strategy ----------------------------------------------------- +// PWMaps implementations ------------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// -class PWMapStrategy; +using PWMapImpl = std::variant; -typedef std::unique_ptr PWMapStratPtr; +} // namespace detail -class PWMapStrategy { - public: - virtual ~PWMapStrategy() = default; +enum class PWMapKind { kUnordered, kOrdered, kDomOrdered }; - /** - * @brief Constructs an empty pw. - */ - PWMapStrategy(); +std::ostream& operator<<(std::ostream& out, PWMapKind kind); + +//////////////////////////////////////////////////////////////////////////////// +// PWMap ----------------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +class PWMap { +public: + using ConstIt = std::vector::const_iterator; /** - * @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(const PWMapKind kind); + PWMap(const PWMapKind kind, Set s); + PWMap(const PWMapKind kind, Map m); - virtual std::shared_ptr begin() const = 0; - virtual std::shared_ptr end() const = 0; + ConstIt begin(); + ConstIt end(); + template + void emplaceBack(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 pushBack(const Map& m); + void pushBack(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 +99,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 +136,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 +166,81 @@ 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. - */ - virtual PWMapStratPtr minAdjMap(const PWMapStrategy& other) const = 0; - - /** - * @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. + * minimum value according to pw \p other. */ - virtual PWMapStratPtr firstInv(const Set& subdom) const = 0; + PWMap minAdj(const PWMap& other) const; /** - * @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; - - /** - * @brief Given a map, return elements of the domain that share its image with - * other values of the domain. - */ - virtual Set sharedImage() const = 0; + Set lessImage(const PWMap& other) const; /** * @brief Sum a constant value to every element in the domain of the pw. The * law remains unchanged. */ - virtual PWMapStratPtr offsetDom(const MD_NAT& off) const = 0; + PWMap offsetDom(const MD_NAT& offset) const; /** - * @brief Sum the value indicated by pw \p off for every value in the domain - * of the pw \p this. The law remains unchanged. + * @brief Minimize internal representation cost. Heuristic guided. */ - virtual PWMapStratPtr offsetDom(const PWMapStrategy& off) const = 0; + void compact(); - /** - * @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; - - /** - * @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; +private: + PWMap(const detail::PWMapImpl& impl); + PWMap(detail::PWMapImpl&& impl); - /** - * @brief Compact in the same piece all maps that have the same expression. - */ - virtual PWMapStratPtr compact() const = 0; + detail::PWMapImpl _impl; }; -//////////////////////////////////////////////////////////////////////////////// -// 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; - - PWMap compact() const; - - private: - PWMapStratPtr strategy_; -}; std::ostream& operator<<(std::ostream& out, const PWMap& pw); +template +inline void PWMap::emplaceBack(Args&&... args) +{ + std::visit([&](auto& a) { a.emplaceBack(std::forward(args)...); } , _impl); +} + } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_PW_MAP_HPP_ diff --git a/sbg/pwmap_fact.cpp b/sbg/pwmap_fact.cpp index 292fc00b..1572fc92 100644 --- a/sbg/pwmap_fact.cpp +++ b/sbg/pwmap_fact.cpp @@ -17,21 +17,13 @@ ******************************************************************************/ -#include "sbg/dom_ord_pwmap.hpp" #include "sbg/pwmap_fact.hpp" -#include "sbg/ord_pwmap.hpp" -#include "sbg/unord_pwmap.hpp" +#include "util/debug.hpp" namespace SBG { namespace LIB { -//////////////////////////////////////////////////////////////////////////////// -// PWMap Factory --------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -PWMapFact::PWMapFact() {} - //////////////////////////////////////////////////////////////////////////////// // UnordPWMap Factory ---------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// @@ -40,90 +32,115 @@ UnordPWMapFact::UnordPWMapFact() {} PWMap UnordPWMapFact::createPWMap() const { - return PWMap(std::make_unique()); -} - -PWMap UnordPWMapFact::createPWMap(const Set &s) const -{ - return PWMap(std::make_unique(s)); + return PWMap{PWMapKind::kUnordered}; } -PWMap UnordPWMapFact::createPWMap(const Map &m) const +PWMap UnordPWMapFact::createPWMap(const Set& s) const { - return PWMap(std::make_unique(m)); + return PWMap{PWMapKind::kUnordered, s}; } -std::string UnordPWMapFact::prettyPrint() const +PWMap UnordPWMapFact::createPWMap(const Map& m) const { - return "unordered"; + return PWMap{PWMapKind::kUnordered, m}; } //////////////////////////////////////////////////////////////////////////////// // 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"; -} - +//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)); +//} +// +////////////////////////////////////////////////////////////////////////////////// +//// 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)); +//} +// //////////////////////////////////////////////////////////////////////////////// -// DomOrdPWMap Factory ------------------------------------------------------------ +// Factory for clients --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -DomOrdPWMapFact::DomOrdPWMapFact() {} +PWMapFactory::PWMapFactory() : _kind(PWMapKind::kUnordered) + , _impl(UnordPWMapFact{}) {} -PWMap DomOrdPWMapFact::createPWMap() const +PWMapFactory& PWMapFactory::instance() { - return PWMap(std::make_unique()); + static PWMapFactory _instance; + return _instance; } -PWMap DomOrdPWMapFact::createPWMap(const Set &s) const -{ - return PWMap(std::make_unique(s)); -} +const PWMapKind& PWMapFactory::kind() const { return _kind; } -PWMap DomOrdPWMapFact::createPWMap(const Map &m) const +void PWMapFactory::set_pwmap_fact(PWMapKind kind) { - return PWMap(std::make_unique(m)); + switch (kind) { + case PWMapKind::kUnordered: { + _kind = kind; + _impl = UnordPWMapFact{}; + break; + } + + //case SetKind::kOrdered: { + // _impl = OrdPWMapFact{}; + //} + + //case SetKind::OrdUnidimDense: { + // _impl = DomOrdPWMapFact{}; + //} + + default: { + Util::ERROR("Unsupported ", kind, " PWMap implementation\n"); + break; + } + } } -std::string DomOrdPWMapFact::prettyPrint() const +PWMap PWMapFactory::createPWMap() const { - return "domain ordered"; + return std::visit([](const auto& a) { return a.createPWMap(); }, _impl); } -//////////////////////////////////////////////////////////////////////////////// -// Factory for clients --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -PWFactory::PWFactory() : pw_fact_(std::make_unique()) {} - -PWMapFact& PWFactory::pw_fact() +PWMap PWMapFactory::createPWMap(Set s) const { - return *pw_fact_; + return std::visit([&s](const auto& a) { return a.createPWMap(std::move(s)); } + , _impl); } -void PWFactory::set_pw_fact(PWMapFactPtr pw_fact) +PWMap PWMapFactory::createPWMap(Map m) const { - pw_fact_ = std::move(pw_fact); + return std::visit([&m](const auto& a) { return a.createPWMap(std::move(m)); } + , _impl); } } // namespace LIB diff --git a/sbg/pwmap_fact.hpp b/sbg/pwmap_fact.hpp index d111f566..c58ad246 100644 --- a/sbg/pwmap_fact.hpp +++ b/sbg/pwmap_fact.hpp @@ -21,85 +21,75 @@ ******************************************************************************/ -#ifndef SBG_PWMAP_FACT_HPP -#define SBG_PWMAP_FACT_HPP +#ifndef SBGRAPH_SBG_PWMAP_FACT_HPP_ +#define SBGRAPH_SBG_PWMAP_FACT_HPP_ -#include "pw_map.hpp" +#include "sbg/map.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/set.hpp" namespace SBG { namespace LIB { -#define PW_FACT PWFactory::instance().pw_fact() +#define PWMAP_FACT PWMapFactory::instance() -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: +class UnordPWMapFact { +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; + PWMap createPWMap() const; + PWMap createPWMap(const Set &s) const; + PWMap createPWMap(const Map &m) const; }; -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; +//class OrdPWMapFact { +// public: +// OrdPWMapFact(); +// +// PWMap createPWMap() const override; +// PWMap createPWMap(const Set &s) const override; +// PWMap createPWMap(const Map &m) const override; +//}; +// +//class DomOrdPWMapFact { +// public: +// DomOrdPWMapFact(); +// +// PWMap createPWMap() const override; +// PWMap createPWMap(const Set &s) const override; +// PWMap createPWMap(const Map &m) const override; +//}; /** * @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_; -}; +class PWMapFactory { +public: + ~PWMapFactory() = default; + + static PWMapFactory& instance(); + const PWMapKind& kind() const; + + void set_pwmap_fact(PWMapKind kind); + PWMap createPWMap() const; + PWMap createPWMap(Set s) const; + PWMap createPWMap(Map m) const; +private: + using FactImpl = std::variant; + + PWMapFactory(); + + PWMapKind _kind; + FactImpl _impl; +}; } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_PWMAP_FACT_HPP_ diff --git a/sbg/unord_pwmap.cpp b/sbg/unord_pwmap.cpp index 1a23080d..88e109d6 100644 --- a/sbg/unord_pwmap.cpp +++ b/sbg/unord_pwmap.cpp @@ -17,102 +17,97 @@ ******************************************************************************/ -#include - +#include "sbg/set_fact.hpp" #include "sbg/unord_pwmap.hpp" +#include +#include +#include + namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // Unordered PWMap Implementation ---------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -// Auxiliary functions - Unordered Piecewise maps ------------------------------ +// Auxliary definitions -------------------------------------------------------- -void pushBack(UnordPWMap::UnordMapCollection& unord_pw, const Map& m) -{ - unord_pw.emplace_back(m); -} - -// Member functions - Unordered Piecewise maps --------------------------------- +class MapLess { +public: + bool operator()(const Map& a, const Map& b) const { + return a.domain().minElem() < b.domain().minElem(); + } +}; -member_imp(UnordPWMap, UnordPWMap::UnordMapCollection, pieces); +// Constructors/Destructors ---------------------------------------------------- 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)) {} -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::pushBack(const Map& m) { - return std::make_shared(pieces_.begin()); -} - -std::shared_ptr UnordPWMap::end() const -{ - return std::make_shared(pieces_.end()); + if (!m.isEmpty()) { + _pieces.push_back(m); + } } -void UnordPWMap::emplaceBack(const Map& m) +void UnordPWMap::pushBack(Map&& m) { if (!m.isEmpty()) { - pieces_.emplace_back(m); + _pieces.push_back(std::move(m)); } } -bool UnordPWMap::operator==(const PWMapStrategy& other) const -{ - UnordPWMapCRef othr = static_cast(other); +// 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,269 +118,287 @@ 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::domain() const & +{ + Set result = SET_FACT.createSet(); + + for (const Map& m : _pieces) { + result = std::move(result).disjointCup(m.domain()); + } -Set UnordPWMap::dom() const + return result; +} + +Set UnordPWMap::domain() && { Set result = SET_FACT.createSet(); - for (const Map& m : pieces_) { - Set ith_dom = m.dom(); - result = std::move(result).disjointCup(std::move(ith_dom)); + + for (Map& m : _pieces) { + result = std::move(result).disjointCup(std::move(m).domain()); } return result; } -PWMapStratPtr UnordPWMap::restrict(const Set& subdom) const +UnordPWMap UnordPWMap::restrict(const Set& subdom) const { - PWMapStratPtr res = std::make_unique(); + UnordPWMap result; - for (const Map& m : pieces_) - res->emplaceBack(m.restrict(subdom)); + for (const Map& m : _pieces) { + result.pushBack(m.restrict(subdom)); + } - return res; + return result; } Set UnordPWMap::image() const { - Set res = SET_FACT.createSet(); + Set result = SET_FACT.createSet(); - 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 = SET_FACT.createSet(); - 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.emplaceBack(m.image(), m.law().inverse()); } - return res; + return result; } -PWMapStratPtr UnordPWMap::composition(const PWMapStrategy& other) const +UnordPWMap UnordPWMap::composition(const UnordPWMap& other) const { - PWMapStratPtr res = std::make_unique(); + UnordPWMap result; - UnordPWMapCRef othr = static_cast(other); - - 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 = SET_FACT.createSet(); - 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}); +} + +UnordPWMap UnordPWMap::concatenation(UnordPWMap&& other) const & +{ + return UnordPWMap{*this}.concatenation(std::move(other)); +} + +UnordPWMap UnordPWMap::concatenation(UnordPWMap&& other) && +{ + if (isEmpty()) { + return std::move(other); } - return result; + if (other.isEmpty()) { + return std::move(*this); + } + + 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())); + + return UnordPWMap{std::move(result)}; } -PWMapStratPtr UnordPWMap::combine(const PWMapStrategy& other) const -{ - UnordPWMapCRef othr = static_cast(other); +UnordPWMap UnordPWMap::combine(const UnordPWMap& other) const & +{ + return UnordPWMap{*this}.combine(other); +} + +UnordPWMap UnordPWMap::combine(const UnordPWMap& other) && +{ + return std::move(*this).combine(UnordPWMap{other}); +} + +UnordPWMap UnordPWMap::combine(UnordPWMap&& other) const & +{ + return UnordPWMap{*this}.combine(std::move(other)); +} + +UnordPWMap UnordPWMap::combine(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_); + 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 UnordPWMap::reduce() const +UnordPWMap UnordPWMap::reduce() const { - UnordMapCollection result; - for (const Map& m : pieces_) { + UnordPWMap result; + + for (const Map& m : _pieces) { std::vector reduced = m.reduce(); - for(const Map& reduced_map : reduced) { - result.emplace_back(reduced_map); + for(Map& reduced_map : reduced) { + result._pieces.push_back(std::move(reduced_map)); } } - return std::make_unique(std::move(result)); + return result; } -PWMapStratPtr UnordPWMap::minMap(const PWMapStrategy& other) const +UnordPWMap UnordPWMap::min(const UnordPWMap& other) const { - if (isEmpty() || other.isEmpty()) - return std::make_unique(); + if (isEmpty() || other.isEmpty()) { + return UnordPWMap{}; + } Set min_in_pw1 = lessImage(other); - return restrict(min_in_pw1)->combine(*other.restrict(dom())); -} + return restrict(min_in_pw1).combine(other.restrict(domain())); +} -PWMapStratPtr UnordPWMap::minAdjMap(const PWMapStrategy& other) const +UnordPWMap UnordPWMap::minAdj(const UnordPWMap& other) const { - PWMapStratPtr result = std::make_unique(); + UnordPWMap result; - 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; - - 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()); + 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 { - e_res = MDLExp(im2.minElem()); - } - - 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)); - } + result.pushBack(std::move(min_adj)); + visited = std::move(visited).disjointCup(std::move(min_adj_domain)); } } } @@ -394,180 +407,123 @@ PWMapStratPtr UnordPWMap::minAdjMap(const PWMapStrategy& other) const return result; } -PWMapStratPtr UnordPWMap::firstInv(const Set& subdom) const +Set UnordPWMap::sharedImage() const { - UnordMapCollection result; - + Set repeated_image = SET_FACT.createSet(); 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()); - - for (const SetPiece& mdi : res_dom) - visited.emplaceBack(mdi); + 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 std::make_unique(result); + return preImage(repeated_image); } -PWMapStratPtr UnordPWMap::firstInv() const { return firstInv(dom()); } - -PWMapStratPtr UnordPWMap::filterMap(bool (*f)(const Map&)) const +Set UnordPWMap::equalImage(const UnordPWMap& other) const { - PWMapStratPtr res = std::make_unique(); - - for (const Map& m : pieces_) - if (f(m)) - res->emplaceBack(m); - - return res; -} + Set result = SET_FACT.createSet(); -Set UnordPWMap::equalImage(const PWMapStrategy& other) const -{ - Set res = SET_FACT.createSet(); + if (_pieces == other._pieces) { + return domain(); + } - UnordPWMapCRef othr = static_cast(other); - for (const Map& m1 : pieces_) { - for (const Map& m2 : othr.pieces_) { - Set cap_dom = m1.dom().intersection(m2.dom()); + 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()) + if (isEmpty() || other.isEmpty()) { return SET_FACT.createSet(); + } - 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)); + 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::offsetDom(const MD_NAT& offset) const { - UnordMapCollection res; + UnordPWMap result; - for (const Map& m : pieces_) { - pushBack(res, Map(m.dom().offset(off), m.exp())); + for (const Map& m : _pieces) { + result._pieces.emplace_back(m.domain().offset(offset), m.law()); } - return std::make_unique(res); -} - -PWMapStratPtr UnordPWMap::offsetDom(const PWMapStrategy& off) const -{ - PWMapStratPtr res = std::make_unique(); - - for (const Map& m : pieces_) { - Set ith_dom = off.image(m.dom()); - res->emplaceBack(Map(ith_dom, m.exp())); - } - - return res; + return result; } -PWMapStratPtr UnordPWMap::offsetImage(const MD_NAT& off) const +bool operator<(const Map& m1, const Map& m2) { - UnordMapCollection res; - - 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); - } - - pushBack(res, Map(m.dom(), res_e)); - } - - return std::make_unique(res); + return true; } -PWMapStratPtr UnordPWMap::offsetImage(const Exp& off) const +void UnordPWMap::compact() { - UnordMapCollection res; + using MapSet = std::set; - for (const Map& m : pieces_) { - pushBack(res, Map(m.dom(), off + m.exp())); - } - - return std::make_unique(res); -} + UnordMapCollection result; -PWMapStratPtr UnordPWMap::compact() const -{ - UnordMapCollection res; - if (dom().isEmpty()) - return std::make_unique(res); - - std::forward_list indices; - auto liIt = indices.before_begin(); + if (!isEmpty()) { + MapSet prev{std::make_move_iterator(_pieces.begin()) + , std::make_move_iterator(_pieces.end())}; + MapSet actual = prev; + do { + prev = actual; + actual = MapSet{}; + + MapSet::iterator ith = prev.begin(); + MapSet::iterator last = prev.end(); + MapSet to_erase; + 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); + } + } - 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; + if (to_erase.find(ith_compact) == to_erase.end()) { + actual.insert(ith_compact); + } } - + } while (actual != prev); - ++liPrev; - ++liCurr; + for (const Map& mdi : actual) { + result.push_back(mdi); } - - pushBack(res, new_ith); - liPrev = indices.before_begin(); - liCurr = indices.begin(); } - return std::make_unique(res); + _pieces = std::move(result); } +} // namespace detail + } // namespace LIB } // namespace SBG; diff --git a/sbg/unord_pwmap.hpp b/sbg/unord_pwmap.hpp index 66df70f3..79084b94 100644 --- a/sbg/unord_pwmap.hpp +++ b/sbg/unord_pwmap.hpp @@ -21,101 +21,115 @@ ******************************************************************************/ -#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 +#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 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; - - void emplaceBack(const Map &m) override; + UnordPWMap(const Set& s); + UnordPWMap(const Map& m); + UnordPWMap(UnordMapCollection pieces); - 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; + ConstIt begin() const; + ConstIt end() const; - PWMapStratPtr operator+(const PWMapStrategy &other) const override; + template + void emplaceBack(Args&&... args); + void pushBack(const Map& m); + void pushBack(Map&& m); - 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; - - PWMapStratPtr firstInv(const Set &subdom) const override; - PWMapStratPtr firstInv() const override; - - PWMapStratPtr filterMap(bool (*f)(const Map &)) const override; - - Set equalImage(const PWMapStrategy &other) const override; - Set lessImage(const PWMapStrategy& other) const override; - Set sharedImage() const override; - - 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; - - PWMapStratPtr compact() 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 offsetDom(const MD_NAT& offset) const; + + void compact(); + +private: + UnordMapCollection _pieces; + + /** + * @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; }; -typedef const UnordPWMap &UnordPWMapCRef; -typedef std::unique_ptr UnordPWMapPtr; +template +inline void UnordPWMap::emplaceBack(Args&&... args) +{ + _pieces.emplace_back(std::forward(args)...); +} + +} // namespace detail } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_UNORD_PWMAP_HPP_ From 821f3e3f20b1f52fc7102e8a33c700993e5369b7 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 5 Mar 2026 20:39:19 -0300 Subject: [PATCH 06/66] Redefined SBGS --- sbg/bipartite_sbg.cpp | 188 +++++++++++++----------------------------- sbg/bipartite_sbg.hpp | 35 ++++---- sbg/directed_sbg.cpp | 187 +++++++++++++++++++---------------------- sbg/directed_sbg.hpp | 65 ++++++++------- sbg/sbg.cpp | 166 +++++++++++++------------------------ sbg/sbg.hpp | 35 +++----- 6 files changed, 259 insertions(+), 417 deletions(-) diff --git a/sbg/bipartite_sbg.cpp b/sbg/bipartite_sbg.cpp index 6520f2df..ca4444b1 100644 --- a/sbg/bipartite_sbg.cpp +++ b/sbg/bipartite_sbg.cpp @@ -18,25 +18,32 @@ ******************************************************************************/ #include "sbg/bipartite_sbg.hpp" +#include "sbg/natural.hpp" +#include "sbg/pwmap_fact.hpp" +#include "sbg/set_fact.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()) + : _V(SET_FACT.createSet()), _Vmap(PWMAP_FACT.createPWMap()) + , _E(SET_FACT.createSet()), _map1(PWMAP_FACT.createPWMap()) + , _map2(PWMAP_FACT.createPWMap()), _Emap(PWMAP_FACT.createPWMap()) , _X(SET_FACT.createSet()), _Y(SET_FACT.createSet()) {} 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,150 +57,69 @@ 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) -{ - _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; -} +// Setters --------------------------------------------------------------------- -std::ostream& operator<<(std::ostream& out, const BipartiteSBG& g) -{ - out << "V: " << g.V() << "\n"; - out << "Vmap: " << g.Vmap() << "\n\n"; - out << "E: " << g.E() << "\n"; - 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) +void BipartiteSBG::addSetVertex(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()) { + } else if (!vertices.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))); + 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.emplaceBack(vertices, max + one_all_dims); _X = _X.cup(X); _Y = _Y.cup(Y); } } -void BipartiteSBG::addSE(const PWMap& pw1, const PWMap& pw2) +void BipartiteSBG::addSetEdge(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)); + Set edges1 = pw1.domain(); + Set edges2 = pw2.domain(); + if (edges1 != edges2) { + // TODO + Util::ERROR("The domain of ", 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.emplaceBack(edges, max + one_all_dims); } + } else { + Util::ERROR("Trying to add existing edges: ", edges1, " to SBG\n"); } } -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)); - } +// Operators ------------------------------------------------------------------- - 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); - } - } +std::ostream& operator<<(std::ostream& out, const BipartiteSBG& g) +{ + out << "V: " << g.V() << "\n"; + out << "Vmap: " << g.Vmap() << "\n\n"; + out << "E: " << g.E() << "\n"; + out << "map1: " << g.map1() << "\n"; + out << "map2: " << g.map2() << "\n"; + out << "Emap: " << g.Emap() << "\n"; + out << "X: " << g.X() << "\n"; + out << "Y: " << g.Y() << "\n"; - BipartiteSBG result(new_V, new_Vmap, new_map1, new_map2, new_Emap, new_subE - , new_X, new_Y); - return result; + return out; } } // namespace LIB diff --git a/sbg/bipartite_sbg.hpp b/sbg/bipartite_sbg.hpp index 9c0914de..37e5aaec 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,29 @@ 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); - - BipartiteSBG& operator=(const BipartiteSBG& other); - - /** - * @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; + void addSetEdge(const PWMap& pw1, const PWMap& pw2); - 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); } // 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..7861b50a 100644 --- a/sbg/directed_sbg.cpp +++ b/sbg/directed_sbg.cpp @@ -17,7 +17,13 @@ ******************************************************************************/ +#include "sbg/natural.hpp" #include "sbg/directed_sbg.hpp" +#include "sbg/pwmap_fact.hpp" +#include "sbg/set_fact.hpp" +#include "util/debug.hpp" + +#include namespace SBG { @@ -27,123 +33,100 @@ 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(SET_FACT.createSet()), _Vmap(PWMAP_FACT.createPWMap()) + , _E(SET_FACT.createSet()), _mapB(PWMAP_FACT.createPWMap()) + , _mapD(PWMAP_FACT.createPWMap()), _Emap(PWMAP_FACT.createPWMap()) {} - 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; } - else if (!vertices.intersection(V_).isEmpty()) - Util::ERROR("Trying to add existing vertices: ", vertices, " to DSBG\n"); +const PWMap& DirectedSBG::mapB() const { return _mapB; } - return DSBG(); +const PWMap& DirectedSBG::mapD() const { return _mapD; } + +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.emplaceBack(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.emplaceBack(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(); } -DSBG DSBG::eraseVertices(const Set &vs) const +void DirectedSBG::eraseVertices(const Set& vs) { - Set new_V = V_.difference(vs); - PWMap new_Vmap = Vmap_.restrict(V_); + _V = _V.difference(vs); + _Vmap = _Vmap.restrict(_V); + + Set eraseE = _mapB.preImage(vs).cup(_mapD.preImage(vs)); + _E = _E.difference(eraseE); + _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..d95511d1 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,61 @@ 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 + * @brief Erase vertices \p vs from the DirectedSBG, together with associated edges * with \p vs. */ - DSBG eraseVertices(const Set &vs) const; + void eraseVertices(const Set& vs); + +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); } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_DIRECTED_SBG_HPP_ diff --git a/sbg/sbg.cpp b/sbg/sbg.cpp index 1cd89770..3fdbaac7 100644 --- a/sbg/sbg.cpp +++ b/sbg/sbg.cpp @@ -17,7 +17,13 @@ ******************************************************************************/ +#include "sbg/natural.hpp" +#include "sbg/pwmap_fact.hpp" #include "sbg/sbg.hpp" +#include "sbg/set_fact.hpp" +#include "util/debug.hpp" + +#include namespace SBG { @@ -27,16 +33,20 @@ 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(SET_FACT.createSet()), _Vmap(PWMAP_FACT.createPWMap()) + , _E(SET_FACT.createSet()), _map1(PWMAP_FACT.createPWMap()) + , _map2(PWMAP_FACT.createPWMap()), _Emap(PWMAP_FACT.createPWMap()) {} + 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,123 +60,59 @@ 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) -{ - _V = other._V; - _Vmap = other._Vmap; - _E = other._E; - _map1 = other._map1; - _map2 = other._map2; - _Emap = other._Emap; - _subEmap = other._subEmap; - - return *this; -} - -std::ostream& operator<<(std::ostream& out, const SBG& g) -{ - out << "V: " << g.V() << "\n"; - out << "Vmap: " << g.Vmap() << "\n\n"; - out << "E: " << g.E() << "\n"; - 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) +void SBG::addSetVertex(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))); - + } 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.emplaceBack(vertices, max + one_all_dims); } } -void SBG::addSE(const PWMap& pw1, const PWMap& pw2) +void SBG::addSetEdge(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)); + Set edges1 = pw1.domain(); + Set edges2 = pw2.domain(); + if (edges1 != edges2) { + // TODO + Util::ERROR("The domain of ", 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.emplaceBack(edges, max + one_all_dims); } + } else { + Util::ERROR("Trying to add existing edges: ", edges1, " to SBG\n"); } } -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)); - } +// Operators ------------------------------------------------------------------- - 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); - } - } +std::ostream& operator<<(std::ostream& out, const SBG& g) +{ + out << "V: " << g.V() << "\n"; + out << "Vmap: " << g.Vmap() << "\n\n"; + out << "E: " << g.E() << "\n"; + out << "map1: " << g.map1() << "\n"; + out << "map2: " << g.map2() << "\n"; + out << "Emap: " << g.Emap() << "\n"; - return SBG(new_V, new_Vmap, new_map1, new_map2, new_Emap, new_subE); + return out; } } // namespace LIB diff --git a/sbg/sbg.hpp b/sbg/sbg.hpp index 73b1d010..fcc2f4ef 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,33 @@ 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); - - /** - * @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; + void addSetEdge(const PWMap& pw1, const PWMap& pw2); - private: +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); } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_SBG_HPP_ From e6d7b87b27890b8d9778eef39f82f24baf3afa21 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 5 Mar 2026 20:40:15 -0300 Subject: [PATCH 07/66] Refined Matching algorithm --- algorithms/matching/CMakeLists.txt | 1 + algorithms/matching/bfs_matching.cpp | 123 ++++++++++++++------------ algorithms/matching/bfs_matching.hpp | 35 +++++--- algorithms/matching/bfs_paths.cpp | 39 ++++---- algorithms/matching/bfs_paths.hpp | 17 ++-- algorithms/matching/match_data.cpp | 72 +++++++++++++++ algorithms/matching/match_data.hpp | 64 ++++++++++++++ algorithms/matching/matching.cpp | 64 ++++++-------- algorithms/matching/matching.hpp | 64 +++++--------- algorithms/matching/matching_fact.cpp | 41 ++++++--- algorithms/matching/matching_fact.hpp | 47 ++++------ algorithms/matching/paths.hpp | 18 ++-- 12 files changed, 364 insertions(+), 221 deletions(-) create mode 100644 algorithms/matching/match_data.cpp create mode 100644 algorithms/matching/match_data.hpp diff --git a/algorithms/matching/CMakeLists.txt b/algorithms/matching/CMakeLists.txt index 7c9cc99e..b8018075 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 + match_data.cpp matching_fact.cpp ) diff --git a/algorithms/matching/bfs_matching.cpp b/algorithms/matching/bfs_matching.cpp index b74a178c..0b4c0b57 100644 --- a/algorithms/matching/bfs_matching.cpp +++ b/algorithms/matching/bfs_matching.cpp @@ -17,15 +17,18 @@ ******************************************************************************/ -#include - #include "algorithms/matching/bfs_matching.hpp" +#include "sbg/pwmap_fact.hpp" +#include "sbg/set_fact.hpp" #include "util/logger.hpp" +#include "util/time_profiler.hpp" namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // BFS Matching Algorithm ------------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// @@ -44,42 +47,46 @@ bool BFSMatching::ExitCondition::isSatisfied() // Algorithm ------------------------------------------------------------------- -BFSMatching::BFSMatching() : M_(SET_FACT.createSet()), dsbg_() - , direction_(Direction::kForward) {} +BFSMatching::BFSMatching() : _M(SET_FACT.createSet()), _dsbg() + , _direction(Direction::kForward) {} 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); - - dsbg_ = DSBG(dsbg_.V().compact(), dsbg_.Vmap().compact() - , mapB.compact(), mapD.compact(), dsbg_.Emap().compact() - , dsbg_.subEmap().compact()); + mapB = mapD.restrict(E).combine(std::move(mapB)); + mapB.compact(); + mapD = temp_mapB.restrict(E).combine(std::move(mapD)); + mapD.compact(); - return; + _dsbg = DirectedSBG{_dsbg.V(), _dsbg.Vmap(), mapB, mapD, _dsbg.Emap()}; } 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); + PWMap result = PWMAP_FACT.createPWMap(); + Set free_edges = _dsbg.E().difference(_M); + std::size_t arity = free_edges.arity(); + NAT j = 1; + PWMap Emap = _dsbg.Emap(); + Set set_edges = Emap.image(); + while (!set_edges.isEmpty()) { + Set min_elem_set = SET_FACT.createSet(set_edges.minElem()); + Set domain_edges = Emap.preImage(min_elem_set); + + Expression matched_expr{MD_NAT{arity, j}}; + Map matched_map{_M.intersection(domain_edges), matched_expr}; ++j; - Exp free_exp(MD_NAT(dims, j)); - Map free_map(free_edges.intersection(dom), free_exp); + Expression free_expr{MD_NAT{arity, j}}; + Map free_map{free_edges.intersection(domain_edges), free_expr}; ++j; result.emplaceBack(matched_map); result.emplaceBack(free_map); + + set_edges = set_edges.difference(min_elem_set); } return result; @@ -87,11 +94,11 @@ PWMap BFSMatching::partitionSubsetEdges() const Set BFSMatching::edgesInPaths(const PWMap& smap, const Set& E) const { - PWMap mapB = dsbg_.mapB().restrict(E); - PWMap mapD = dsbg_.mapD().restrict(E); + 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 not_fixed = smap.domain().difference(smap.fixedPoints()); Set succs = smap.restrict(not_fixed).image(); // Edges whose endings are successors Set ending_edges = mapD.preImage(succs); @@ -105,23 +112,22 @@ Set BFSMatching::edgesInPaths(const PWMap& smap, const Set& E) const Set BFSMatching::directedStep(const Set& E, const Set& right_vertices) { - 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) { + Set forward_vertices = _dsbg.V().difference(right_vertices); + Set matched_forward_vertices = mapB.image(_M); + if (_direction == Direction::kBackward) { forward_vertices = right_vertices; } Set unmatched_forward_vertices = forward_vertices.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); @@ -131,7 +137,7 @@ Set BFSMatching::directedStep(const Set& E, const Set& right_vertices) 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: " + Util::DEBUG_LOG << "paths_edges in " << _direction << " direction: " << paths_edges << "\n"; return paths_edges; @@ -139,14 +145,14 @@ Set BFSMatching::directedStep(const Set& E, const Set& right_vertices) BFSMatching::ExitCondition BFSMatching::step(const Set& right_vertices) { - Set E = dsbg_.E(); + Set E = _dsbg.E(); // Forward direction Set paths_edgesD = directedStep(E, right_vertices); // Backward direction swapEdgesDirection(E); - direction_ = Direction::kBackward; + _direction = Direction::kBackward; Set paths_edgesB = directedStep(paths_edgesD, right_vertices); // Calculate augmenting paths and swap edges in these paths @@ -156,61 +162,66 @@ BFSMatching::ExitCondition BFSMatching::step(const Set& right_vertices) // 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(right_vertices); // Calculate exit conditions - Set matchedU = dsbg_.mapD().image(M_); + Set matchedU = _dsbg.mapD().image(_M); bool full_match = right_vertices.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"; + Util::Internal::TimeProfiler profiler{"Total matching exec time: "}; - auto begin = std::chrono::high_resolution_clock::now(); init(bsbg); Set right_vertices = bsbg.Y(); - ExitCondition exit_cond(false, false); + ExitCondition exit_cond{false, false}; do { exit_cond = step(right_vertices); } 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..2b060c0d 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_; }; @@ -118,13 +123,15 @@ class BFSMatching : public MatchStrategy { */ 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; }; +} // 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..0942a54a 100644 --- a/algorithms/matching/bfs_paths.cpp +++ b/algorithms/matching/bfs_paths.cpp @@ -18,73 +18,80 @@ ******************************************************************************/ #include "algorithms/matching/bfs_paths.hpp" +#include "sbg/pwmap_fact.hpp" +#include "sbg/set_fact.hpp" #include "util/logger.hpp" namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // Path Finder BFS Implementation ---------------------------------------------- //////////////////////////////////////////////////////////////////////////////// BFSPaths::BFSPaths() {} -PWMap BFSPaths::calculate(const DSBG& dsbg, const Set& endings) +PWMap BFSPaths::calculate(const DirectedSBG& dsbg, const Set& endings) { Set dsbgV = dsbg.V(); PWMap dsbgB = dsbg.mapB(); PWMap dsbgD = dsbg.mapD(); - PWMap subEmap = dsbg.subEmap(); + PWMap Emap = dsbg.Emap(); - // Unmatched vertices in forward direction - PWMap res = PW_FACT.createPWMap(endings); + // Successor map to unmatched vertices + PWMap result = PWMAP_FACT.createPWMap(endings); // A record of allowed edges to keep out cycle edges Set allowed_edges = dsbg.E(); - // Ingoing edges to vertices that reach unmatched_D + // Ingoing edges to vertices that reach endings Set ingoing = dsbgD.preImage(endings); // A record of visited set-edges Set visitedE = SET_FACT.createSet(); do { // Calculate successor for ith vertices - PWMap ingB = dsbgB.restrict(ingoing), ingD = dsbgD.restrict(ingoing); - PWMap ith_smap = ingB.minAdjMap(ingD); + PWMap ingoingB = dsbgB.restrict(ingoing); + PWMap ingoingD = dsbgD.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)); // Visited set-edges - Set Erec = visitedE.intersection(subEmap.image(Eith)); + Set Erec = visitedE.intersection(Emap.image(Eith)); // Handle recursion if (!Erec.isEmpty()) { - Set Eplus = subEmap.preImage(Erec); - PWMap rec_smap = dsbgB.restrict(Eplus).minAdjMap(dsbgD.restrict(Eplus)); + Set Eplus = Emap.preImage(Erec); + PWMap rec_smap = dsbgB.restrict(Eplus).minAdj(dsbgD.restrict(Eplus)); Util::DEBUG_LOG << "rec_smap: " << rec_smap << "\n"; ith_smap = ith_smap.combine(rec_smap); } - res = ith_smap.combine(res); + result = ith_smap.combine(result); // Take out other outgoing edges to avoid cycles - allowed_edges = allowed_edges.difference(dsbgB.preImage(res.dom())); + allowed_edges = allowed_edges.difference(dsbgB.preImage(result.domain())); dsbgD = dsbgD.restrict(allowed_edges); dsbgB = dsbgB.restrict(allowed_edges); // Edges that reach vertices with a successor - ingoing = dsbgD.preImage(res.dom()).intersection(allowed_edges); + ingoing = dsbgD.preImage(result.domain()).intersection(allowed_edges); - visitedE = visitedE.cup(subEmap.image(Eith)); + visitedE = visitedE.cup(Emap.image(Eith)); 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 << "res: " << result << "\n\n"; } while (!ingoing.isEmpty()); - return res; + return result; } +} // namespace detail + } // namespace LIB } // namespace SBG diff --git a/algorithms/matching/bfs_paths.hpp b/algorithms/matching/bfs_paths.hpp index 5b8b699c..5bd6e86c 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,7 +45,7 @@ namespace LIB { * @brief Backward BFS implementation to calculate paths. */ class BFSPaths : public PathsContext { - public: +public: BFSPaths(); /** @@ -50,11 +55,13 @@ class BFSPaths : public PathsContext { * than once, replicating the same path for every element of the same * Set-Vertex. */ - PWMap calculate(const DSBG& dsbg, const Set& endings); + PWMap 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..330cb472 100644 --- a/algorithms/matching/matching.cpp +++ b/algorithms/matching/matching.cpp @@ -17,66 +17,54 @@ ******************************************************************************/ -#include - #include "algorithms/matching/matching.hpp" -#include "util/logger.hpp" +#include "util/debug.hpp" +#include "util/time_profiler.hpp" namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Auxiliary structures -------------------------------------------------------- +// Matching Algorithm implementations ------------------------------------------ //////////////////////////////////////////////////////////////////////////////// -std::ostream& operator<<(std::ostream& out, const Direction& direction) +std::ostream& operator<<(std::ostream& out, const MatchKind kind) { - switch (direction) { - case Direction::kForward: - out << "forward"; - break; - case Direction::kBackward: - out << "backward"; - break; + switch (kind) { + case MatchKind::kBFSPaths: { + out << "BFS paths"; + } + + default: { + Util::ERROR("Unsupported matching algorithm implementation"); + } } 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; -} - -//////////////////////////////////////////////////////////////////////////////// -// Matching Algorithm Abstract Strategy Constructors --------------------------- -//////////////////////////////////////////////////////////////////////////////// - -MatchStrategy::MatchStrategy() {} - //////////////////////////////////////////////////////////////////////////////// // Matching Algorithm Interface ------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// -Matching::Matching(MatchStratPtr strat) : strategy_(std::move(strat)) {} +Matching::Matching(MatchKind kind) : _kind(kind), _impl() +{ + switch (kind) { + case MatchKind::kBFSPaths: { + _impl = detail::BFSMatching{}; + break; + } + + default: { + Util::ERROR("Unsupported matching algorithm implementation"); + } + } +} MatchData Matching::calculate(const BipartiteSBG& bsbg) { - return strategy_->calculate(bsbg); + 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..157b667f 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,50 @@ ******************************************************************************/ -#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; +using MatchImpl = std::variant; -class MatchStrategy { - public: - virtual ~MatchStrategy() = default; +} // namespace detail - MatchStrategy(); - - virtual MatchData calculate(const BipartiteSBG& bsbg) = 0; -}; +enum class MatchKind { kBFSPaths }; +std::ostream& operator<<(std::ostream& out, const MatchKind kind); //////////////////////////////////////////////////////////////////////////////// -// Matching Algorithm Interface (context) -------------------------------------- +// Matching Algorithm ---------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// class Matching { - public: - Matching(MatchStratPtr strat); +public: + Matching(MatchKind kind); MatchData calculate(const BipartiteSBG& bsbg); - private: - MatchStratPtr strategy_; +private: + MatchKind _kind; + detail::MatchImpl _impl; }; } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_MATCHING_MATCHING_HPP_ diff --git a/algorithms/matching/matching_fact.cpp b/algorithms/matching/matching_fact.cpp index 8f8f7508..dc5e0974 100755 --- a/algorithms/matching/matching_fact.cpp +++ b/algorithms/matching/matching_fact.cpp @@ -17,42 +17,55 @@ ******************************************************************************/ -#include "algorithms/matching/bfs_matching.hpp" #include "algorithms/matching/matching_fact.hpp" +#include "util/debug.hpp" namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Minimum Reachable SCC Factory ----------------------------------------------- +// BFS Paths Matching Factory -------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// Matching BFSMatchingFact::createMatchAlgorithm() const { - return Matching(std::make_unique()); -} - -std::string BFSMatchingFact::prettyPrint() const -{ - return "BFS paths"; + return Matching(MatchKind::kBFSPaths); } //////////////////////////////////////////////////////////////////////////////// // Factory for clients --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -MatchFactory::MatchFactory() - : match_fact_(std::make_unique()) {} +MatchFactory::MatchFactory() : _kind(MatchKind::kBFSPaths), _impl() {} + +MatchFactory& MatchFactory::instance() +{ + static MatchFactory _instance; + return _instance; +} + +const MatchKind& MatchFactory::kind() const { return _kind; } -MatchingFact& MatchFactory::match_fact() +void MatchFactory::set_match_fact(MatchKind kind) { - return *match_fact_; + _kind = kind; + switch (kind) { + case MatchKind::kBFSPaths: { + _impl = BFSMatchingFact{}; + break; + } + + default: { + Util::ERROR("Unsupported matching implementation"); + } + } } -void MatchFactory::set_match_fact(MatchFactPtr match_fact) +Matching MatchFactory::createMatchAlgorithm() const { - match_fact_ = std::move(match_fact); + return std::visit([](const auto& a) { return a.createMatchAlgorithm(); } + , _impl); } } // namespace LIB diff --git a/algorithms/matching/matching_fact.hpp b/algorithms/matching/matching_fact.hpp index c69a9f71..950b69a4 100755 --- a/algorithms/matching/matching_fact.hpp +++ b/algorithms/matching/matching_fact.hpp @@ -21,8 +21,8 @@ ******************************************************************************/ -#ifndef SBG_MATCHING_FACT_HPP -#define SBG_MATCHING_FACT_HPP +#ifndef SBGRAPH_ALGORITHMS_MATCHING_MATCHING_FACT_HPP_ +#define SBGRAPH_ALGORITHMS_MATCHING_MATCHING_FACT_HPP_ #include "algorithms/matching/matching.hpp" @@ -30,51 +30,42 @@ namespace SBG { namespace LIB { -#define MATCH_FACT MatchFactory::instance().match_fact() +#define MATCH_FACT MatchFactory::instance() -class MatchingFact { - public: - virtual ~MatchingFact() = default; - MatchingFact() = default; - - virtual Matching createMatchAlgorithm() const = 0; - virtual std::string prettyPrint() const = 0; -}; - -class BFSMatchingFact : public MatchingFact { - public: +class BFSMatchingFact { +public: BFSMatchingFact() = default; - Matching createMatchAlgorithm() const override; - std::string prettyPrint() const override; + Matching createMatchAlgorithm() const; }; -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: +public: ~MatchFactory() = default; - static MatchFactory& instance() { - static MatchFactory instance_; - return instance_; - } - MatchingFact& match_fact(); - void set_match_fact(MatchFactPtr match_fact); + static MatchFactory& instance(); + const MatchKind& kind() const; + + void set_match_fact(MatchKind kind); + + Matching createMatchAlgorithm() const; + +private: + using MatchFactImpl = std::variant; - private: MatchFactory(); - MatchFactPtr match_fact_; + MatchKind _kind; + MatchFactImpl _impl; }; } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_MATCHING_MATCHING_FACT_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_ From 74fa84ebb659f67dbb8b26828d6c01821d343ed6 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 5 Mar 2026 20:40:37 -0300 Subject: [PATCH 08/66] Refined SCC algorithm --- algorithms/scc/CMakeLists.txt | 1 + algorithms/scc/decreasing_edges_mrv.cpp | 79 +++++++++++++------------ algorithms/scc/decreasing_edges_mrv.hpp | 21 ++++--- algorithms/scc/minadj_mrv.cpp | 67 +++++++++++++-------- algorithms/scc/minadj_mrv.hpp | 12 ++-- algorithms/scc/minreach_scc.cpp | 77 +++++++++++------------- algorithms/scc/minreach_scc.hpp | 45 ++++++++------ algorithms/scc/mrv.hpp | 13 ++-- algorithms/scc/scc.cpp | 64 ++++++++++++++------ algorithms/scc/scc.hpp | 61 +++++++------------ algorithms/scc/scc_data.cpp | 37 ++++++++++++ algorithms/scc/scc_data.hpp | 60 +++++++++++++++++++ algorithms/scc/scc_fact.cpp | 51 ++++++++++------ algorithms/scc/scc_fact.hpp | 58 ++++++++---------- 14 files changed, 392 insertions(+), 254 deletions(-) create mode 100644 algorithms/scc/scc_data.cpp create mode 100644 algorithms/scc/scc_data.hpp diff --git a/algorithms/scc/CMakeLists.txt b/algorithms/scc/CMakeLists.txt index f9b20d1f..84368bab 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_data.cpp scc_fact.cpp ) diff --git a/algorithms/scc/decreasing_edges_mrv.cpp b/algorithms/scc/decreasing_edges_mrv.cpp index 015bc568..28e88e34 100644 --- a/algorithms/scc/decreasing_edges_mrv.cpp +++ b/algorithms/scc/decreasing_edges_mrv.cpp @@ -18,6 +18,8 @@ ******************************************************************************/ #include "algorithms/scc/decreasing_edges_mrv.hpp" +#include "sbg/pwmap_fact.hpp" +#include "sbg/set_fact.hpp" #include "util/logger.hpp" namespace SBG { @@ -28,16 +30,17 @@ namespace LIB { // Minimum Adjacent MRV Implementation ----------------------------------------- //////////////////////////////////////////////////////////////////////////////// -LtEdgesMRV::LtEdgesMRV() : dsbg_(), smap_(PW_FACT.createPWMap()) - , visitedSE_(SET_FACT.createSet()) {} +LtEdgesMRV::LtEdgesMRV() : _dsbg(), _smap(PWMAP_FACT.createPWMap()) + , _visitedSE(SET_FACT.createSet()) {} 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()) + if (mapB.isEmpty() || mapD.isEmpty()) { return SET_FACT.createSet(); + } PWMap rmapB = rmap.composition(mapB); PWMap rmapD = rmap.composition(mapD); @@ -48,11 +51,11 @@ Set LtEdgesMRV::decreasingRepresentative(const PWMap& rmap) const Set LtEdgesMRV::edgesInPaths(const PWMap& smap) const { - PWMap mapB = dsbg_.mapB(); - PWMap mapD = dsbg_.mapD(); + 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 not_fixed = smap.domain().difference(smap.fixedPoints()); Set succs = smap.restrict(not_fixed).image(); // Edges whose endings are successors Set ending_edges = mapD.preImage(succs); @@ -66,60 +69,58 @@ Set LtEdgesMRV::edgesInPaths(const PWMap& smap) const PWMap LtEdgesMRV::recursivePaths(const Set& ith_paths_edges, const Set& outgoing) { - PWMap result = PW_FACT.createPWMap(); + PWMap result = PWMAP_FACT.createPWMap(); - PWMap subEmap = dsbg_.subEmap(); - Set ithSE = subEmap.image(ith_paths_edges); - visitedSE_ = visitedSE_.cup(ithSE); - Set repeatedSE = visitedSE_.intersection(ithSE); + PWMap Emap = _dsbg.Emap(); + Set ithSE = Emap.image(ith_paths_edges); + _visitedSE = std::move(_visitedSE).cup(ithSE); + Set repeatedSE = _visitedSE.intersection(ithSE); if (!repeatedSE.isEmpty()) { - PWMap mapB = dsbg_.mapB(); - PWMap mapD = dsbg_.mapD(); + PWMap mapB = _dsbg.mapB(); + PWMap mapD = _dsbg.mapD(); - Set ith_start = smap_.dom().difference(smap_.image()); + Set ith_start = _smap.domain().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); + E = std::move(E).disjointCup(std::move(ithE)); ith_start = mapD.image(ithE); - exit_condition = !repeatedSE.intersection(subEmap.image(E)).isEmpty(); + exit_condition = !repeatedSE.intersection(Emap.image(E)).isEmpty(); } while (!exit_condition); } - Set smap_edges = edgesInPaths(smap_); + Set smap_edges = edgesInPaths(_smap); Set adj = mapB.preImage(mapB.image(smap_edges)); - Set E_plus = subEmap.preImage(subEmap.image(E)); + Set E_plus = Emap.preImage(Emap.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 mapB_plus = _dsbg.mapB().restrict(E_plus); + PWMap mapD_plus = _dsbg.mapD().restrict(E_plus); + result = mapB_plus.minAdj(mapD_plus); } 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 = SET_FACT.createSet(); - smap_ = PW_FACT.createPWMap(dsbg.V()); - PWMap rmap = smap_; + _smap = PWMAP_FACT.createPWMap(dsbg.V()); + PWMap rmap = _smap; - if (!dsbg_.V().isEmpty() && !dsbg_.E().isEmpty()) { - PWMap old_rmap = PW_FACT.createPWMap(); + if (!_dsbg.V().isEmpty() && !_dsbg.E().isEmpty()) { + PWMap old_rmap = PWMAP_FACT.createPWMap(); Set E = SET_FACT.createSet(); Set paths_edges = SET_FACT.createSet(); do { @@ -129,18 +130,18 @@ 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_); + _smap = std::move(smap_plus).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)); } while (!E.isEmpty()); } diff --git a/algorithms/scc/decreasing_edges_mrv.hpp b/algorithms/scc/decreasing_edges_mrv.hpp index f3931fed..2f7f80e3 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(); /** @@ -51,9 +54,9 @@ class LtEdgesMRV : public MRVContext { * It also handles recursive 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 @@ -68,13 +71,13 @@ class LtEdgesMRV : public MRVContext { */ PWMap recursivePaths(const Set& paths_edges, const Set& outgoing); - DSBG dsbg_; - PWMap smap_; - Set visitedSE_; + DirectedSBG _dsbg; + PWMap _smap; + Set _visitedSE; }; } // 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..8e92884b 100644 --- a/algorithms/scc/minadj_mrv.cpp +++ b/algorithms/scc/minadj_mrv.cpp @@ -18,6 +18,8 @@ ******************************************************************************/ #include "algorithms/scc/minadj_mrv.hpp" +#include "sbg/pwmap_fact.hpp" +#include "sbg/set_fact.hpp" #include "util/logger.hpp" namespace SBG { @@ -30,16 +32,20 @@ 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 = PWMAP_FACT.createPWMap(V), old_rmap = PWMAP_FACT.createPWMap(); - if (E.isEmpty()) + if (E.isEmpty()) { return rmap; + } Set Vc = SET_FACT.createSet(); do { @@ -47,20 +53,23 @@ PWMap MinAdjMRV::calculate(const DSBG& dsbg) 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 = PWMAP_FACT.createPWMap(); 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(); + 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_FACT.createSet(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 @@ -73,36 +82,40 @@ PWMap MinAdjMRV::calculate(const DSBG& dsbg) 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 = PWMAP_FACT.createPWMap(); 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.emplaceBack(Map{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(); + 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 +128,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 +142,7 @@ PWMap MinAdjMRV::calculate(const DSBG& dsbg) return rmap; } - return PW_FACT.createPWMap(); + return PWMAP_FACT.createPWMap(); } } // namespace LIB diff --git a/algorithms/scc/minadj_mrv.hpp b/algorithms/scc/minadj_mrv.hpp index 0a00cd6d..0f264088 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,7 +42,7 @@ namespace LIB { * @brief Minimum Adjacent implementation to calculate MRV. */ class MinAdjMRV : public MRVContext { - public: +public: MinAdjMRV(); /** @@ -50,11 +52,11 @@ class MinAdjMRV : public MRVContext { * It also handles recursive 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..5b1763e6 100644 --- a/algorithms/scc/minreach_scc.cpp +++ b/algorithms/scc/minreach_scc.cpp @@ -17,77 +17,68 @@ ******************************************************************************/ -#include - #include "algorithms/scc/decreasing_edges_mrv.hpp" #include "algorithms/scc/minreach_scc.hpp" #include "algorithms/scc/minadj_mrv.hpp" +#include "sbg/pwmap_fact.hpp" +#include "sbg/set_fact.hpp" #include "util/logger.hpp" +#include "util/time_profiler.hpp" namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // Minimum Reachable SCC Algorithm --------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -MinReachSCC::MinReachSCC() : dsbg_(), E_(SET_FACT.createSet()) {} +MinReachSCC::MinReachSCC() : _dsbg(), _E(SET_FACT.createSet()) {} 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"; + Util::Internal::TimeProfiler profiler{"Total MinReachSCC exec time: "}; init(dsbg); - auto begin = std::chrono::high_resolution_clock::now(); - PWMap rmap = PW_FACT.createPWMap(); + PWMap rmap = PWMAP_FACT.createPWMap(); Set Ediff = SET_FACT.createSet(); Set oldE = dsbg.E(); Set deleted_edges = SET_FACT.createSet(); do { - oldE = dsbg_.E(); + oldE = _dsbg.E(); rmap = sccStep(); - Ediff = oldE.difference(dsbg_.E()); - deleted_edges = deleted_edges.disjointCup(Ediff); + Ediff = oldE.difference(_dsbg.E()); + deleted_edges = std::move(deleted_edges).disjointCup(std::move(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(); Util::DEBUG_LOG << "MinReachSCC result: " << rmap << "\n\n"; - return SCCData(dsbg, rmap, deleted_edges); + return SCCData{dsbg, rmap, deleted_edges}; } //////////////////////////////////////////////////////////////////////////////// @@ -100,19 +91,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 +118,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..0cec14d3 100644 --- a/algorithms/scc/scc.cpp +++ b/algorithms/scc/scc.cpp @@ -17,10 +17,9 @@ ******************************************************************************/ -#include - #include "algorithms/scc/mrv.hpp" #include "algorithms/scc/scc.hpp" +#include "util/debug.hpp" #include "util/logger.hpp" namespace SBG { @@ -28,31 +27,58 @@ namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Auxiliary structures -------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -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 -------------------------------- +// SCC Algorithm implementations ----------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -SCCStrategy::SCCStrategy() {} +std::ostream& operator<<(std::ostream& out, const SCCKind kind) +{ + switch (kind) { + case SCCKind::MinReachV1: { + out << "minimum reachable V1"; + break; + } + + case SCCKind::MinReachV2: { + out << "minimum reachable V2"; + break; + } + + default: { + Util::ERROR("Unsupported SCC implementation"); + break; + } + } + + return out; +} //////////////////////////////////////////////////////////////////////////////// -// SCC Algorithm Interface ----------------------------------------------------- +// SCC Algorithm --------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -SCC::SCC(SCCStratPtr strat) : strategy_(std::move(strat)) {} +SCC::SCC(SCCKind kind) : _kind(kind), _impl() +{ + switch (kind) { + case SCCKind::MinReachV1: { + _impl = detail::MinReachSCCV1{}; + break; + } + + case SCCKind::MinReachV2: { + _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); + 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..16098b00 100644 --- a/algorithms/scc/scc.hpp +++ b/algorithms/scc/scc.hpp @@ -21,69 +21,52 @@ ******************************************************************************/ -#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; - -typedef std::unique_ptr SCCStratPtr; +using SCCImpl = std::variant; -class SCCStrategy { - public: - virtual ~SCCStrategy() = default; +} // namespace detail - SCCStrategy(); +enum class SCCKind { MinReachV1, MinReachV2 }; - virtual SCCData calculate(const DSBG& dsbg) = 0; -}; +std::ostream& operator<<(std::ostream& out, const SCCKind kind); //////////////////////////////////////////////////////////////////////////////// -// SCC Algorithm Interface (context) ------------------------------------------- +// SCC Algorithm --------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// class SCC { - public: - SCC(SCCStratPtr strat); +public: + SCC(SCCKind kind); - SCCData calculate(const DSBG& dsbg); + SCCData calculate(const DirectedSBG& dsbg); - private: - SCCStratPtr strategy_; +private: + SCCKind _kind; + 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/scc/scc_data.hpp b/algorithms/scc/scc_data.hpp new file mode 100644 index 00000000..b72a8cd8 --- /dev/null +++ b/algorithms/scc/scc_data.hpp @@ -0,0 +1,60 @@ +/** @file scc_data.hpp + + @brief SCC Input and Ouput 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_SCC_SCC_DATA_HPP_ +#define SBGRAPH_ALGORITHMS_SCC_SCC_DATA_HPP_ + +#include "sbg/directed_sbg.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/set.hpp" + +namespace SBG { + +namespace LIB { + +//////////////////////////////////////////////////////////////////////////////// +// SCC Factory implementations ------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Saves input and output data from a SCC algorithm run. + */ +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 // SBGRAPH_ALGORITHMS_SCC_SCC_DATA_HPP_ diff --git a/algorithms/scc/scc_fact.cpp b/algorithms/scc/scc_fact.cpp index 78b3739f..1ae8df23 100755 --- a/algorithms/scc/scc_fact.cpp +++ b/algorithms/scc/scc_fact.cpp @@ -19,6 +19,7 @@ #include "algorithms/scc/minreach_scc.hpp" #include "algorithms/scc/scc_fact.hpp" +#include "util/debug.hpp" namespace SBG { @@ -30,12 +31,7 @@ namespace LIB { SCC MinReachSCCV1Fact::createSCCAlgorithm() const { - return SCC(std::make_unique()); -} - -std::string MinReachSCCV1Fact::prettyPrint() const -{ - return "MRV V1"; + return SCC{SCCKind::MinReachV1}; } //////////////////////////////////////////////////////////////////////////////// @@ -44,28 +40,49 @@ std::string MinReachSCCV1Fact::prettyPrint() const SCC MinReachSCCV2Fact::createSCCAlgorithm() const { - return SCC(std::make_unique()); -} - -std::string MinReachSCCV2Fact::prettyPrint() const -{ - return "MRV V2"; + return SCC{SCCKind::MinReachV2}; } //////////////////////////////////////////////////////////////////////////////// // Factory for clients --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -SCCFactory::SCCFactory() : scc_fact_(std::make_unique()) {} +SCCFactory::SCCFactory() + : _kind(SCCKind::MinReachV2), _impl(MinReachSCCV2Fact{}) {} + +SCCFactory& SCCFactory::instance() +{ + static SCCFactory _instance; + return _instance; +} + +const SCCKind& SCCFactory::kind() const { return _kind; } -SCCFact& SCCFactory::scc_fact() +void SCCFactory::set_scc_fact(SCCKind kind) { - return *scc_fact_; + _kind = kind; + switch (kind) { + case SCCKind::MinReachV1: { + _impl = MinReachSCCV1Fact{}; + break; + } + + case SCCKind::MinReachV2: { + _impl = MinReachSCCV2Fact{}; + break; + } + + default: { + Util::ERROR("Unsupported SCC algorithm implementation"); + break; + } + } } -void SCCFactory::set_scc_fact(SCCFactPtr scc_fact) +SCC SCCFactory::createSCCAlgorithm() const { - scc_fact_ = std::move(scc_fact); + return std::visit([](const auto& a) { return a.createSCCAlgorithm(); } + , _impl); } } // namespace LIB diff --git a/algorithms/scc/scc_fact.hpp b/algorithms/scc/scc_fact.hpp index cd464115..49ffdee3 100755 --- a/algorithms/scc/scc_fact.hpp +++ b/algorithms/scc/scc_fact.hpp @@ -21,68 +21,60 @@ ******************************************************************************/ -#ifndef SBG_SCC_FACT_HPP -#define SBG_SCC_FACT_HPP +#ifndef SBGRAPH_ALGORITHMS_SCC_SCC_FACT_HPP_ +#define SBGRAPH_ALGORITHMS_SBG_SCC_FACT_HPP_ -#include "scc.hpp" +#include "algorithms/scc/scc.hpp" + +#include 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; -}; +#define SCC_FACT SCCFactory::instance() -class MinReachSCCV1Fact : public SCCFact { - public: +class MinReachSCCV1Fact { +public: MinReachSCCV1Fact() = default; - SCC createSCCAlgorithm() const override; - std::string prettyPrint() const override; + SCC createSCCAlgorithm() const; }; -class MinReachSCCV2Fact : public SCCFact { - public: +class MinReachSCCV2Fact { +public: MinReachSCCV2Fact() = default; - SCC createSCCAlgorithm() const override; - std::string prettyPrint() const override; + SCC createSCCAlgorithm() const; }; -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: +public: ~SCCFactory() = default; - static SCCFactory& instance() { - static SCCFactory instance_; - return instance_; - } - SCCFact& scc_fact(); - void set_scc_fact(SCCFactPtr scc_fact); + static SCCFactory& instance(); + const SCCKind& kind() const; + + void set_scc_fact(SCCKind kind); + + SCC createSCCAlgorithm() const; + +private: + using SCCFactImpl = std::variant; - private: SCCFactory(); - SCCFactPtr scc_fact_; + SCCKind _kind; + SCCFactImpl _impl; }; } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_SCC_SCC_FACT_HPP_ From 0580ca639c3b58c6dc4c7151801c601d0052f36b Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 5 Mar 2026 20:42:00 -0300 Subject: [PATCH 09/66] Refined CC and SBG builders --- algorithms/CMakeLists.txt | 6 +- algorithms/cc/cc.cpp | 45 +++++++------- algorithms/cc/cc.hpp | 9 +-- algorithms/misc/CMakeLists.txt | 2 +- algorithms/misc/causalization_builders.cpp | 70 +++++++++------------- algorithms/misc/causalization_builders.hpp | 19 +++--- 6 files changed, 72 insertions(+), 79 deletions(-) diff --git a/algorithms/CMakeLists.txt b/algorithms/CMakeLists.txt index 83933a57..43ca47cf 100644 --- a/algorithms/CMakeLists.txt +++ b/algorithms/CMakeLists.txt @@ -1,10 +1,10 @@ # Add subdirectories add_subdirectory(cc) -add_subdirectory(cutvertex) +#add_subdirectory(cutvertex) add_subdirectory(matching) add_subdirectory(misc) -add_subdirectory(partitioner) +#add_subdirectory(partitioner) add_subdirectory(scc) -add_subdirectory(toposort) +#add_subdirectory(toposort) install_lib_headers("${CMAKE_CURRENT_SOURCE_DIR}") diff --git a/algorithms/cc/cc.cpp b/algorithms/cc/cc.cpp index 1156f717..7df50682 100644 --- a/algorithms/cc/cc.cpp +++ b/algorithms/cc/cc.cpp @@ -17,10 +17,11 @@ ******************************************************************************/ -#include - #include "algorithms/cc/cc.hpp" +#include "sbg/pwmap_fact.hpp" +#include "sbg/set.hpp" #include "util/logger.hpp" +#include "util/time_profiler.hpp" namespace SBG { @@ -30,29 +31,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 exec 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 = PWMAP_FACT.createPWMap(V); + PWMap old_rmap = PWMAP_FACT.createPWMap(); - 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 +66,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_FACT.createPWMap(); } } // 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/misc/CMakeLists.txt b/algorithms/misc/CMakeLists.txt index 059c12aa..c63671cb 100644 --- a/algorithms/misc/CMakeLists.txt +++ b/algorithms/misc/CMakeLists.txt @@ -2,5 +2,5 @@ target_sources( sbgraph PRIVATE causalization_builders.cpp - causalization_json.cpp +# causalization_json.cpp ) diff --git a/algorithms/misc/causalization_builders.cpp b/algorithms/misc/causalization_builders.cpp index e529d055..21ec0618 100644 --- a/algorithms/misc/causalization_builders.cpp +++ b/algorithms/misc/causalization_builders.cpp @@ -17,28 +17,32 @@ ******************************************************************************/ -#include - #include "algorithms/misc/causalization_builders.hpp" +#include "sbg/bipartite_sbg.hpp" +#include "sbg/set.hpp" +#include "sbg/pw_map.hpp" #include "sbg/pwmap_fact.hpp" -#include "util/logger.hpp" +#include "sbg/map.hpp" +#include "util/time_profiler.hpp" -namespace MISC { +namespace misc { -SBG::LIB::DSBG buildSCCFromMatching(const SBG::LIB::MatchData& data) +SBG::LIB::DirectedSBG buildSCCFromMatching(const SBG::LIB::MatchData& data) { - auto start = std::chrono::high_resolution_clock::now(); + SBG::Util::Internal::TimeProfiler profiler{"SBG SCC builder: "}; 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 = SBG::LIB::PWMAP_FACT.createPWMap(); + for (const SBG::LIB::Map& m : auxVmap) { + SBG::LIB::Set domain = m.domain(); + domain.compact(); + Vmap.pushBack(SBG::LIB::Map(domain, m.law())); } SBG::LIB::PWMap map1 = bsbg.map1(); @@ -57,56 +61,40 @@ SBG::LIB::DSBG buildSCCFromMatching(const SBG::LIB::MatchData& data) 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); - - 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 res; + return SBG::LIB::DirectedSBG{V, Vmap, mapB, mapD, Emap}; } -SBG::LIB::DSBG buildSortFromSCC(const SBG::LIB::SCCData& data) +SBG::LIB::DirectedSBG buildSortFromSCC(const SBG::LIB::SCCData& data) { - auto start = std::chrono::high_resolution_clock::now(); + SBG::Util::Internal::TimeProfiler profiler{"SBG Topological Sort builder: "}; - const SBG::LIB::DSBG& dsbg = data.dsbg(); + const SBG::LIB::DirectedSBG& dsbg = data.dsbg(); SBG::LIB::PWMap rmap = data.rmap(); SBG::LIB::Set Ediff = data.Ediff(); SBG::LIB::PWMap mapB = rmap.composition(dsbg.mapB().restrict(Ediff)); - mapB = mapB.compact(); + mapB.compact(); SBG::LIB::PWMap mapD = rmap.composition(dsbg.mapD().restrict(Ediff)); - mapD = mapD.compact(); + mapD.compact(); - SBG::LIB::PWMap aux_rmap = rmap.compact(); + rmap.compact(); + SBG::LIB::PWMap aux_rmap = rmap; SBG::LIB::PWMap reps_rmap = aux_rmap.restrict(aux_rmap.fixedPoints()); - SBG::LIB::Set V = reps_rmap.dom(); + SBG::LIB::Set V = reps_rmap.domain(); SBG::LIB::PWMap Vmap = dsbg.Vmap().restrict(V); SBG::LIB::PWMap Emap = dsbg.Emap().restrict(Ediff); - SBG::LIB::PWMap subEmap = dsbg.subEmap().restrict(Ediff); - - 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"; - 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..1cca970d 100644 --- a/algorithms/misc/causalization_builders.hpp +++ b/algorithms/misc/causalization_builders.hpp @@ -25,18 +25,19 @@ ******************************************************************************/ -#ifndef MISC_CAUSALIZATION_BUILDERS_HPP -#define MISC_CAUSALIZATION_BUILDERS_HPP +#ifndef SBGRAPH_ALGORITHMS_MISC_CAUSALIZATION_BUILDERS_HPP_ +#define SBGRAPH_ALGORITHMS_MISC_CAUSALIZATION_BUILDERS_HPP_ -#include "algorithms/matching/matching.hpp" -#include "algorithms/scc/scc.hpp" +#include "algorithms/matching/match_data.hpp" +#include "algorithms/scc/scc_data.hpp" +#include "sbg/directed_sbg.hpp" -namespace MISC { +namespace misc { -SBG::LIB::DSBG buildSCCFromMatching(const SBG::LIB::MatchData& data); +SBG::LIB::DirectedSBG buildSCCFromMatching(const SBG::LIB::MatchData& data); -SBG::LIB::DSBG buildSortFromSCC(const SBG::LIB::SCCData& data); +SBG::LIB::DirectedSBG buildSortFromSCC(const SBG::LIB::SCCData& data); -} // namespace MISC +} // namespace misc -#endif +#endif // SBGRAPH_ALGORITHMS_MISC_CAUSALIZATION_BUILDERS_HPP_ From a1878a3bd0547aca0459877f21070743e10249a8 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 5 Mar 2026 20:43:32 -0300 Subject: [PATCH 10/66] Redefined evaluator to support new interfaces --- eval/base_type.hpp | 31 +- eval/eval_context.cpp | 4 + eval/eval_context.hpp | 14 +- eval/eval_exec.cpp | 82 +++-- eval/eval_exec.hpp | 10 +- eval/file_evaluator.cpp | 10 +- eval/file_evaluator.hpp | 9 +- eval/func_env.cpp | 12 +- eval/func_env.hpp | 21 +- eval/input_translator.cpp | 29 +- eval/input_translator.hpp | 14 +- eval/pretty_print.cpp | 45 +-- eval/pretty_print.hpp | 40 ++- eval/user_impl_map.cpp | 109 +++--- eval/user_impl_map.hpp | 48 +-- eval/user_input.cpp | 4 + eval/user_input.hpp | 12 +- eval/var_env.cpp | 14 +- eval/var_env.hpp | 20 +- eval/visitors/autom_impl_visitor.cpp | 18 +- eval/visitors/autom_impl_visitor.hpp | 14 +- eval/visitors/expr_evaluator.cpp | 185 +++++----- eval/visitors/expr_evaluator.hpp | 20 +- eval/visitors/func_evaluator.cpp | 427 +++++++++++++++--------- eval/visitors/func_evaluator.hpp | 32 +- eval/visitors/int_evaluator.cpp | 53 +-- eval/visitors/int_evaluator.hpp | 22 +- eval/visitors/linear_expr_evaluator.cpp | 158 +++++---- eval/visitors/linear_expr_evaluator.hpp | 60 ++-- eval/visitors/nat_evaluator.cpp | 52 +-- eval/visitors/nat_evaluator.hpp | 20 +- eval/visitors/program_evaluator.cpp | 20 +- eval/visitors/program_evaluator.hpp | 18 +- eval/visitors/rational_evaluator.cpp | 85 +++-- eval/visitors/rational_evaluator.hpp | 19 +- eval/visitors/set_impl_visitor.cpp | 28 +- eval/visitors/set_impl_visitor.hpp | 22 +- eval/visitors/stm_evaluator.cpp | 14 +- eval/visitors/stm_evaluator.hpp | 18 +- 39 files changed, 1053 insertions(+), 760 deletions(-) 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..185e858a 100644 --- a/eval/eval_exec.cpp +++ b/eval/eval_exec.cpp @@ -17,22 +17,28 @@ ******************************************************************************/ -#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/cutvertex/cv_fact.hpp" +//#include "algorithms/cc/cc.hpp" +//#include "algorithms/matching/matching_fact.hpp" +//#include "algorithms/scc/scc_fact.hpp" +//#include "algorithms/toposort/ts_fact.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/set_fact.hpp" +#include "sbg/pwmap_fact.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,15 +52,14 @@ 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_FACT.kind() << "\n"; + std::cout << "PWMap implementation: " << LIB::PWMAP_FACT.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() - << "\n"; + //std::cout << "Matching algorithm: " << LIB::MATCH_FACT.kind() << "\n"; + //std::cout << "SCC algorithm: " << LIB::SCC_FACT.kind() << "\n"; + //std::cout << "Cut vertex algorithm: " << LIB::CV_FACT.kind() << "\n"; + //std::cout << "Topological sort algorithm: " << LIB::TS_FACT.kind() + // << "\n"; } std::cout << "-----------------------------------\n"; std::cout << ">>>>>>>>>>> Eval result <<<<<<<<<<<\n"; @@ -67,7 +72,7 @@ void printHeader(Util::prog_opts::variables_map vm) EvalExecutor::EvalExecutor() : scc_impl_(1) { - config_.add_options() + _config.add_options() ("set_impl,s", Util::prog_opts::value(&set_impl_), " Desired set implementation:" "\n - 0 for unordered sets (default option)" @@ -83,31 +88,33 @@ EvalExecutor::EvalExecutor() : scc_impl_(1) "\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_); + _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_ > autom_impl.set_impl()) { Util::ERROR("Incompatible set implementation for the SBG input\n"); + } 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_ > autom_impl.pw_impl()) { + Util::ERROR("Incompatible PWMap implementation for the SBG input\n"); + } result.set_pw_impl(pw_impl_); } @@ -122,7 +129,7 @@ void EvalExecutor::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 ------------------------------------------------------------- @@ -131,7 +138,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 +151,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 +165,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..e542e735 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,13 +32,13 @@ 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_; 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..b52896dc 100755 --- a/eval/input_translator.cpp +++ b/eval/input_translator.cpp @@ -19,43 +19,42 @@ #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); } - EvalUserInput::MaybeInt scc = input.scc_impl(); - if (scc) { - setSCCFactory(*scc); - } - - return; + //EvalUserInput::MaybeInt scc = input.scc_impl(); + //if (scc) { + // setSCCFactory(*scc); + //} } +} // 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/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..5255293b 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,15 +53,22 @@ 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 diff --git a/eval/user_impl_map.cpp b/eval/user_impl_map.cpp index bd36d4a7..37c2baf4 100755 --- a/eval/user_impl_map.cpp +++ b/eval/user_impl_map.cpp @@ -17,65 +17,69 @@ ******************************************************************************/ +#include "algorithms/scc/scc_fact.hpp" #include "eval/user_impl_map.hpp" +#include "sbg/pwmap_fact.hpp" +#include "sbg/set_fact.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,27 +87,28 @@ 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::MinReachV1; + scc_mapping[1] = LIB::SCCKind::MinReachV2; scc_mapping.freeze(); return scc_mapping; } -UserImplMap::StructImplMap tsMap() -{ - UserImplMap::StructImplMap ts_mapping; - ts_mapping[0] = []() { return std::make_unique(); }; - 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; -} +// TODO +//UserImplMap::StructImplMap tsMap() +//{ +// UserImplMap::StructImplMap ts_mapping; +// ts_mapping[0] = []() { return std::make_unique(); }; +// 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 +117,44 @@ UserImplMap::StructImplMap cvMap() UserImplMap::UserImplMap() { implementations_["set"] = setMap(); - implementations_["pw"] = pwMap(); + implementations_["pwmap"] = pwMap(); implementations_["match"] = matchMap(); implementations_["scc"] = sccMap(); - implementations_["ts"] = tsMap(); - implementations_["cv"] = cvMap(); + //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_FACT.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)); - - return; + LIB::PWMapKind pwmap_fact = std::get( + detail::IMPL_MAP.getFactory("pwmap", pw_impl)); + LIB::PWMAP_FACT.set_pwmap_fact(pwmap_fact); } void setSCCFactory(int scc_impl) { - LIB::SCCFactPtr scc_fact = std::get(IMPL_MAP.getFactory("scc" - , scc_impl)); - LIB::SCCFactory::instance().set_scc_fact(std::move(scc_fact)); + LIB::SCCKind scc_fact = std::get( + detail::IMPL_MAP.getFactory("scc", scc_impl)); + LIB::SCC_FACT.set_scc_fact(scc_fact); return; } diff --git a/eval/user_impl_map.hpp b/eval/user_impl_map.hpp index 2f1f46c1..7ae716cb 100755 --- a/eval/user_impl_map.hpp +++ b/eval/user_impl_map.hpp @@ -26,24 +26,26 @@ ******************************************************************************/ -#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/cutvertex/cv_fact.hpp" +#include "algorithms/matching/matching.hpp" +#include "algorithms/scc/scc.hpp" +//#include "algorithms/toposort/ts_fact.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/set.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 +53,26 @@ 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 +81,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 +94,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 ------------------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// @@ -110,4 +116,4 @@ void setSCCFactory(int scc_impl); } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_USER_IMPL_MAP_HPP diff --git a/eval/user_input.cpp b/eval/user_input.cpp index 619716ba..b07184df 100755 --- a/eval/user_input.cpp +++ b/eval/user_input.cpp @@ -23,6 +23,8 @@ namespace SBG { namespace Eval { +namespace detail { + // Constructors ---------------------------------------------------------------- EvalUserInput::EvalUserInput() {} @@ -91,6 +93,8 @@ void EvalUserInput::set_cv_impl(MaybeInt cv_impl) cv_impl_ = cv_impl; } +} // namespace detail + } // namespace Eval } // namespace SBG diff --git a/eval/user_input.hpp b/eval/user_input.hpp index 808dab04..9933116d 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(); @@ -54,7 +56,7 @@ class EvalUserInput { void set_ts_impl(MaybeInt ts_impl); void set_cv_impl(MaybeInt cv_impl); - private: +private: MaybeInt set_impl_; MaybeInt pw_impl_; MaybeInt match_impl_; @@ -63,6 +65,8 @@ class EvalUserInput { MaybeInt cv_impl_; }; +} // detail + } // namespace Eval } // namespace SBG 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..a1ad44ea 100755 --- a/eval/visitors/autom_impl_visitor.cpp +++ b/eval/visitors/autom_impl_visitor.cpp @@ -27,6 +27,8 @@ namespace SBG { namespace Eval { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // Automatic Implementation Visitor -------------------------------------------- //////////////////////////////////////////////////////////////////////////////// @@ -39,23 +41,25 @@ EvalUserInput AutomImplVisitor::visit(AST::SBGProgram p) const 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 +78,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..aeddd4e4 100755 --- a/eval/visitors/expr_evaluator.cpp +++ b/eval/visitors/expr_evaluator.cpp @@ -18,11 +18,10 @@ ******************************************************************************/ #include "algorithms/cc/cc.hpp" -#include "algorithms/cutvertex/cv_fact.hpp" -#include "algorithms/matching/bfs_matching.hpp" +//#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/toposort/ts_fact.hpp" #include "algorithms/misc/causalization_builders.hpp" #include "algorithms/misc/causalization_json.hpp" #include "eval/visitors/expr_evaluator.hpp" @@ -30,17 +29,22 @@ #include "eval/visitors/linear_expr_evaluator.hpp" #include "eval/visitors/nat_evaluator.hpp" #include "eval/visitors/rational_evaluator.hpp" +#include "sbg/pwmap_fact.hpp" +#include "sbg/set_fact.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 +54,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,16 +67,12 @@ 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("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); } @@ -83,19 +83,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 +122,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 +133,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_FACT.createSet(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 = LIB::SET_FACT.createSet(); + + 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 = LIB::SET_FACT.createSet(); - 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 = LIB::PWMAP_FACT.createPWMap(); - for (const AST::Expr &e : v.maps()) - res.emplaceBack(eval(*this, e, "Map")); + for (const AST::Expr& e : v.maps()) { + result.emplaceBack(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 +249,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 +260,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 +273,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 +282,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..a2f5d09a 100755 --- a/eval/visitors/func_evaluator.cpp +++ b/eval/visitors/func_evaluator.cpp @@ -18,18 +18,109 @@ ******************************************************************************/ #include "algorithms/cc/cc.hpp" -#include "algorithms/cutvertex/cv_fact.hpp" +//#include "algorithms/cutvertex/cv_fact.hpp" #include "algorithms/matching/matching_fact.hpp" #include "algorithms/misc/causalization_builders.hpp" #include "algorithms/scc/scc_fact.hpp" -#include "algorithms/toposort/ts_fact.hpp" +//#include "algorithms/toposort/ts_fact.hpp" +#include "eval/base_type.hpp" #include "eval/visitors/func_evaluator.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" namespace SBG { namespace Eval { +namespace detail { + +//////////////////////////////////////////////////////////////////////////////// +// Auxiliary functions --------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +//TODO +/** + * @brief Returns a new bipartite SBG constructed by copying \p times the + * the current bipartite SBG, disconnected one from each other. + */ +/* +LIB::BipartiteSBG copy(unsigned int times, BipartiteSBG bsbg) +{ + 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)); + } + + 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); + } + } + + return BipartiteSBG{new_V, new_Vmap, new_map1, new_map2, new_Emap, new_subE + , new_X, new_Y}; +} +*/ + //////////////////////////////////////////////////////////////////////////////// // Built-in operators evaluators ----------------------------------------------- //////////////////////////////////////////////////////////////////////////////// @@ -40,13 +131,16 @@ ExprBaseType BuiltInOperators::oppositeEvaluator(const EBTList& args) , "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()); }, + [](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]); @@ -58,8 +152,6 @@ ExprBaseType BuiltInOperators::cardinalEvaluator(const EBTList& args) , "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(); }, [](LIB::Set a) { return (LIB::NAT) a.cardinal(); }, [](auto a) { Util::ERROR("cardinalEvaluator: wrong argument ", a, " for #\n"); @@ -75,11 +167,11 @@ ExprBaseType BuiltInOperators::complementEvaluator(const EBTList& args) , "complementEvaluator: wrong number of arguments\n"); const auto complement_evaluator = Overload { - [](LIB::Set a) { return ExprBaseType(a.complement()); }, + [](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]); @@ -91,22 +183,22 @@ ExprBaseType BuiltInOperators::addEvaluator(const EBTList& args) , "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); }, + [](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]); @@ -119,23 +211,25 @@ ExprBaseType BuiltInOperators::subEvaluator(const EBTList& args) const auto sub_evaluator = 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]); @@ -147,14 +241,23 @@ ExprBaseType BuiltInOperators::multEvaluator(const EBTList& args) , "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)); }, + [](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]); @@ -168,10 +271,8 @@ ExprBaseType BuiltInOperators::eqEvaluator(const EBTList& args) const auto eq_evaluator = 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) { @@ -191,8 +292,6 @@ ExprBaseType BuiltInOperators::lessEvaluator(const EBTList& args) const auto less_evaluator = 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"); @@ -208,17 +307,11 @@ ExprBaseType BuiltInOperators::capEvaluator(const EBTList& args) , "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)); }, + [](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]); @@ -230,11 +323,11 @@ ExprBaseType BuiltInOperators::cupEvaluator(const EBTList& args) , "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) { + [](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]); @@ -246,11 +339,11 @@ ExprBaseType BuiltInOperators::diffEvaluator(const EBTList& args) , "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) { + [](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 +356,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 +384,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{}; } //////////////////////////////////////////////////////////////////////////////// @@ -338,8 +443,6 @@ ExprBaseType BuiltInFunctions::emptyEvaluator(const EBTList& args) , "emptyEvaluator: wrong number of arguments\n"); const auto empty_evaluator = Overload { - [](LIB::Interval a) { return a.isEmpty(); }, - [](LIB::MultiDimInter a) { return a.isEmpty(); }, [](LIB::Set a) { return a.isEmpty(); }, [](auto a) { Util::ERROR("emptyEvaluator: wrong argument ", a, " for isEmpty\n"); @@ -355,12 +458,10 @@ ExprBaseType BuiltInFunctions::minEvaluator(const EBTList& args) , "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(); }, [](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]); @@ -372,12 +473,10 @@ ExprBaseType BuiltInFunctions::maxEvaluator(const EBTList& args) , "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(); }, [](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]); @@ -389,11 +488,11 @@ ExprBaseType BuiltInFunctions::restrictEvaluator(const EBTList& args) , "restrictEvaluator: wrong number of arguments\n"); const auto restrict_evaluator = Overload { - [](LIB::PWMap a, LIB::Set b) { return ExprBaseType(a.restrict(b)); }, + [](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]); @@ -405,14 +504,16 @@ ExprBaseType BuiltInFunctions::composeEvaluator(const EBTList& args) , "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)); }, + [](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]); @@ -424,13 +525,11 @@ ExprBaseType BuiltInFunctions::inverseEvaluator(const EBTList& args) , "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()); }, + [](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]); @@ -440,23 +539,23 @@ 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()); }, + [](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)); }, + [](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 +563,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) @@ -473,12 +572,12 @@ ExprBaseType BuiltInFunctions::preImageEvaluator(const EBTList& args) , "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)); }, + [](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]); @@ -490,10 +589,10 @@ ExprBaseType BuiltInFunctions::domEvaluator(const EBTList& args) , "domEvaluator: wrong number of arguments\n"); const auto dom_evaluator = Overload { - [](LIB::PWMap a) { return ExprBaseType(a.dom()); }, + [](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]); @@ -505,61 +604,47 @@ ExprBaseType BuiltInFunctions::combineEvaluator(const EBTList& args) , "combineEvaluator: wrong number of arguments\n"); const auto combine_evaluator = Overload { - [](LIB::PWMap a, LIB::PWMap b) { return ExprBaseType(a.combine(b)); }, + [](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)); }, + [](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]); -} +// TODO +//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) { @@ -567,11 +652,11 @@ ExprBaseType BuiltInFunctions::minAdjEvaluator(const EBTList& args) , "minAdjEvaluator: wrong number of arguments\n"); const auto min_adj_evaluator = Overload { - [](LIB::PWMap a, LIB::PWMap b) { return ExprBaseType(a.minAdjMap(b)); }, + [](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]); @@ -583,10 +668,10 @@ ExprBaseType BuiltInFunctions::mapInfEvaluator(const EBTList& args) , "mapInfEvaluator: wrong number of arguments\n"); const auto inf_evaluator = Overload { - [](LIB::PWMap a) { return ExprBaseType(a.mapInf()); }, + [](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]); @@ -600,10 +685,10 @@ ExprBaseType BuiltInFunctions::connectedEvaluator(const EBTList& args) , "connectedEvaluator: wrong number of arguments\n"); const auto connected_evaluator = Overload { - [](LIB::SBG a) { return ExprBaseType(connectedComponents(a)); }, + [](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]); @@ -617,15 +702,17 @@ ExprBaseType BuiltInFunctions::matchingEvaluator(const EBTList& args) LIB::Matching match_impl = LIB::MATCH_FACT.createMatchAlgorithm(); const auto matching_evaluator = Overload { [&match_impl](LIB::BipartiteSBG a, LIB::NAT b) { - return ExprBaseType(match_impl.calculate(a.copy(b))); + // TODO return ExprBaseType{match_impl.calculate(a.copy(b))}; + return ExprBaseType{match_impl.calculate(a)}; }, [&match_impl](LIB::BipartiteSBG a, LIB::MD_NAT b) { - return ExprBaseType(match_impl.calculate(a.copy(b[0]))); + // TODO return ExprBaseType{match_impl.calculate(a.copy(b[0]))}; + return ExprBaseType{match_impl.calculate(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]); @@ -638,17 +725,18 @@ ExprBaseType BuiltInFunctions::sccEvaluator(const EBTList& args) 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()); + [&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) { Util::ERROR_UNLESS(args.size() == 1 @@ -656,12 +744,12 @@ ExprBaseType BuiltInFunctions::topoSortEvaluator(const EBTList& args) LIB::TopoSort ts_impl = LIB::TS_FACT.createTSAlgorithm(); const auto ts_evaluator = Overload { - [&ts_impl](LIB::DSBG a) { - return ExprBaseType(ts_impl.calculate(a)); + [&ts_impl](LIB::DirectedSBG a) { + return ExprBaseType{ts_impl.calculate(a)}; }, [](auto a) { Util::ERROR("topoSortEvaluator: wrong argument ", a, " for sort\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(ts_evaluator, args[0]); @@ -674,16 +762,17 @@ ExprBaseType BuiltInFunctions::cutVertexEvaluator(const EBTList& args) LIB::CutVertex cv_impl = LIB::CV_FACT.createCVAlgorithm(); const auto cv_evaluator = Overload { - [&cv_impl](LIB::DSBG a) { - return ExprBaseType(cv_impl.calculate(a)); + [&cv_impl](LIB::DirectedSBG a) { + return ExprBaseType{cv_impl.calculate(a)}; }, [](auto a) { Util::ERROR("topoSortEvaluator: wrong argument ", a, " for sort\n"); - return ExprBaseType(); + return ExprBaseType{}; } }; return std::visit(cv_evaluator, args[0]); } +*/ ExprBaseType BuiltInFunctions::matchSCCEvaluator(const EBTList& args) { @@ -694,19 +783,21 @@ ExprBaseType BuiltInFunctions::matchSCCEvaluator(const EBTList& args) 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()); + // TODO LIB::MatchData match_result = match_impl.calculate(a.copy(b)); + LIB::MatchData match_result = match_impl.calculate(a); + LIB::DirectedSBG 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()); + // TODO LIB::MatchData match_result = match_impl.calculate(a.copy(b[0])); + LIB::MatchData match_result = match_impl.calculate(a); + LIB::DirectedSBG 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(); + return ExprBaseType{}; } }; @@ -720,34 +811,36 @@ ExprBaseType BuiltInFunctions::matchSCCTSEvaluator(const EBTList& args) [](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::SCC scc(misc::buildSCCFromMatching(match), c); LIB::PWMap scc_res = scc.calculate(); - LIB::DSBG ts_dsbg = MISC::buildSortFromSCC(scc, scc_res); + LIB::DirectedSBG 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); + 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::SCC scc(misc::buildSCCFromMatching(match), c); LIB::PWMap scc_res = scc.calculate(); - LIB::DSBG ts_dsbg = MISC::buildSortFromSCC(scc, scc_res); + LIB::DirectedSBG 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); + 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(); + return ExprBaseType{}; } }; } */ +} // namespace detail + } // namespace Eval } // namespace SBG diff --git a/eval/visitors/func_evaluator.hpp b/eval/visitors/func_evaluator.hpp index 440a2080..b1bfc21c 100755 --- a/eval/visitors/func_evaluator.hpp +++ b/eval/visitors/func_evaluator.hpp @@ -24,19 +24,18 @@ ******************************************************************************/ -#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 { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// // Overload pattern ------------------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// @@ -47,19 +46,22 @@ namespace Eval { * functions (for example, isEmpty can be applied to intervals, sets, etc.). */ -template class Overload : Ts... { - public: +template +class Overload : Ts... { +public: using Ts::operator()...; Overload(Ts... ts) : Ts(ts)... {}; }; -template Overload(Ts...) -> Overload; + +template +Overload(Ts...) -> Overload; //////////////////////////////////////////////////////////////////////////////// // 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 +76,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 +94,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); @@ -116,8 +118,10 @@ class BuiltInFunctions { static ExprBaseType matchSCCEvaluator(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..809cb3ea 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; } @@ -55,15 +57,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 +74,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 +88,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 +106,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 +124,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 +177,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_ From 9bc3e3df4b329c7589df50cb719573def71c9fa7 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 5 Mar 2026 20:46:50 -0300 Subject: [PATCH 11/66] Redefined tests for new interface --- test/CMakeLists.txt | 5 +-- test/interval.test | 5 --- test/matching1.test | 4 +-- test/matching2.test | 4 +-- test/matching3.test | 40 ++++++++++++--------- test/matching4.test | 32 ++++++++--------- test/matching5.test | 88 ++++++++++++++++++++++----------------------- test/matching6.test | 56 ++++++++++++++--------------- test/matching7.test | 20 +++++------ test/pw_map1.test | 4 --- test/pw_map2.test | 6 +--- test/pw_map3.test | 3 -- test/scc3.test | 22 ++++++------ test/scc4.test | 22 ++++++------ 14 files changed, 154 insertions(+), 157 deletions(-) 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/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/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|>> ); From 2e92379202fd70c91e58bcd2c60e7aa01f3982b8 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 5 Mar 2026 20:49:57 -0300 Subject: [PATCH 12/66] Redefined tests for new interface --- test/TestRL1.test | 2 +- test/TestRL2.test | 40 ++++++++++++++++---------------- test/TestRL3.test | 40 ++++++++++++++++---------------- test/eval/gt_data/interval.log | 38 +++++++++--------------------- test/eval/gt_data/pw_map1.log | 8 ------- test/eval/gt_data/pw_map2.log | 8 ------- test/eval/gt_data/pw_map3.log | 4 ---- test/parser/gt_data/interval.log | 4 ---- 8 files changed, 52 insertions(+), 92 deletions(-) diff --git a/test/TestRL1.test b/test/TestRL1.test index b5454f38..8aa0cbde 100644 --- a/test/TestRL1.test +++ b/test/TestRL1.test @@ -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..ceb97813 100644 --- a/test/TestRL2.test +++ b/test/TestRL2.test @@ -21,7 +21,7 @@ equation end TestRL2; */ -N = 100000; +N = 1000000; F1 = N; F2 = N-1+F1; @@ -69,21 +69,21 @@ 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; @@ -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..5bbea74a 100644 --- a/test/TestRL3.test +++ b/test/TestRL3.test @@ -22,7 +22,7 @@ equation end TestRL3; */ -N = 100000; +N = 1000000; F1 = N; F2 = N-1+F1; @@ -73,21 +73,21 @@ 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; @@ -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/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/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]; From 0483aa2e0c187efed2f4b35f1ced392b43efb6b6 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 5 Mar 2026 20:59:10 -0300 Subject: [PATCH 13/66] Redefined benchmarksfor for new interfaces --- test/performance/CMakeLists.txt | 7 +- .../boost/ordinary_graph_builder.cpp | 20 +- .../boost/ordinary_graph_builder.hpp | 18 +- test/performance/matching/custom_match_bm.cpp | 3 + test/performance/matching/match_bm.cpp | 6 +- test/performance/ord_set_bm.cpp | 230 +++++----- test/performance/scc/custom_scc_bm.cpp | 13 +- test/performance/scc/scc_bm.cpp | 19 +- test/performance/unord_pwmap_bm.cpp | 402 ++++++++++++++++++ test/performance/unord_set_bm.cpp | 181 ++++++++ test/performance/utils.cpp | 6 +- 11 files changed, 770 insertions(+), 135 deletions(-) create mode 100644 test/performance/unord_pwmap_bm.cpp create mode 100644 test/performance/unord_set_bm.cpp diff --git a/test/performance/CMakeLists.txt b/test/performance/CMakeLists.txt index dbb8a683..9363b20e 100644 --- a/test/performance/CMakeLists.txt +++ b/test/performance/CMakeLists.txt @@ -4,8 +4,9 @@ add_executable(sbg-benchmark benchmark_main.cpp) target_sources(sbg-benchmark PRIVATE benchmark_main.cpp - dom_ord_pwmap_bm.cpp - ord_set_bm.cpp) + #dom_ord_pwmap_bm.cpp + #unord_set_bm.cpp + unord_pwmap_bm.cpp) set_target_properties(sbg-benchmark PROPERTIES RUNTIME_OUTPUT_DIRECTORY @@ -24,6 +25,6 @@ target_link_libraries(sbg-benchmark sbg-dev sbg-eval-lib) -add_subdirectory(boost) +#add_subdirectory(boost) add_subdirectory(matching) add_subdirectory(scc) diff --git a/test/performance/boost/ordinary_graph_builder.cpp b/test/performance/boost/ordinary_graph_builder.cpp index ae5d841b..cc8dbce2 100644 --- a/test/performance/boost/ordinary_graph_builder.cpp +++ b/test/performance/boost/ordinary_graph_builder.cpp @@ -17,6 +17,7 @@ ******************************************************************************/ +#include "sbg/multidim_inter.hpp" #include "test/performance/boost/ordinary_graph_builder.hpp" #include "util/time_profiler.hpp" @@ -26,24 +27,25 @@ namespace OG { // Auxiliary functions --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -static SBG::LIB::MD_NAT nextElem(SBG::LIB::MD_NAT curr, SBG::LIB::SetPiece mdi) +static SBG::LIB::MD_NAT nextElem(SBG::LIB::MD_NAT curr + , SBG::LIB::detail::MultiDimInter mdi) { SBG::LIB::MD_NAT min = mdi.minElem(); SBG::LIB::MD_NAT max = mdi.maxElem(); - SBG::LIB::MD_NAT res; + SBG::LIB::MD_NAT result; for (unsigned int j = 0; j < mdi.arity(); ++j) { if (curr[j] == max[j]) { - res.emplaceBack(min[j]); + result.pushBack(min[j]); } else { - res.emplaceBack(curr[j] + 1); + result.pushBack(curr[j] + 1); for (unsigned int k = 1; k < mdi.arity() - j; ++k) { - res.emplaceBack(curr[j + k]); + result.pushBack(curr[j + k]); } break; } } - return res; + return result; } //////////////////////////////////////////////////////////////////////////////// @@ -75,7 +77,8 @@ void OrdinaryGraphBuilder::translateVertices() 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(); + SBG::LIB::MD_NAT begin = mdi.minElem(); + SBG::LIB::MD_NAT end = mdi.maxElem(); for (auto it = begin; it != end; it = nextElem(it, mdi)) { _vertex_map[it] = count; _partition.emplace_back( @@ -98,7 +101,8 @@ EdgeVector OrdinaryGraphBuilder::getEdgeList() 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(); + SBG::LIB::MD_NAT begin = mdi.minElem(); + SBG::LIB::MD_NAT end = mdi.maxElem(); for (auto it = begin; it != end; it = nextElem(it, mdi)) { // Get endings of edge SBG::LIB::SetPiece it_mdi(it); diff --git a/test/performance/boost/ordinary_graph_builder.hpp b/test/performance/boost/ordinary_graph_builder.hpp index bbb18ec7..2b579744 100644 --- a/test/performance/boost/ordinary_graph_builder.hpp +++ b/test/performance/boost/ordinary_graph_builder.hpp @@ -25,19 +25,21 @@ ******************************************************************************/ -#ifndef PERF_ORDINARY_BUILDER_HPP -#define PERF_ORDINARY_BUILDER_HPP +#ifndef SBGRAPH_TEST_PERFORMANCE_BOOST_ORDINARY_GRAPH_BUILDER_HPP_ +#define SBGRAPH_TEST_PERFORMANCE_BOOST_ORDINARY_GRAPH_BUILDER_HPP_ -#include - -#include "test/performance/boost/ordinary_graph.hpp" #include "sbg/bipartite_sbg.hpp" +#include "sbg/natural.hpp" +#include "test/performance/boost/ordinary_graph.hpp" #include "util/logger.hpp" +#include +#include + namespace OG { class OrdinaryGraphBuilder { - public: +public: OrdinaryGraphBuilder(SBG::LIB::BipartiteSBG bsbg); BipartiteGraph build(); @@ -46,7 +48,7 @@ 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 @@ -55,4 +57,4 @@ class OrdinaryGraphBuilder { } // namespace OG -#endif +#endif // SBGRAPH_TEST_PERFORMANCE_BOOST_ORRDINARY_GRAPH_BUILDER_HPP_ diff --git a/test/performance/matching/custom_match_bm.cpp b/test/performance/matching/custom_match_bm.cpp index 75c5aa42..7729f1fe 100644 --- a/test/performance/matching/custom_match_bm.cpp +++ b/test/performance/matching/custom_match_bm.cpp @@ -29,7 +29,10 @@ #include +#include "algorithms/matching/matching.hpp" +#include "algorithms/matching/matching_fact.hpp" #include "eval/user_impl_map.hpp" +#include "sbg/directed_sbg.hpp" #include "test/performance/utils.hpp" namespace Test { diff --git a/test/performance/matching/match_bm.cpp b/test/performance/matching/match_bm.cpp index b257978c..ea70fbda 100644 --- a/test/performance/matching/match_bm.cpp +++ b/test/performance/matching/match_bm.cpp @@ -24,11 +24,13 @@ * execution time when the repetitive patterns increase its size. */ -#include - +#include "algorithms/matching/matching.hpp" +#include "algorithms/matching/matching_fact.hpp" #include "eval/user_impl_map.hpp" #include "test/performance/utils.hpp" +#include + namespace Test { namespace Internal { diff --git a/test/performance/ord_set_bm.cpp b/test/performance/ord_set_bm.cpp index 4b219108..f619aa31 100644 --- a/test/performance/ord_set_bm.cpp +++ b/test/performance/ord_set_bm.cpp @@ -17,29 +17,42 @@ ******************************************************************************/ +//#include "eval/user_impl_map.hpp" +#include "sbg/interval.hpp" +#include "sbg/multidim_inter.hpp" +#include "sbg/set.hpp" +#include "sbg/unord_set.hpp" + #include -#include "eval/user_impl_map.hpp" +#include namespace Test { namespace Internal { -using SBG::LIB::Interval; -using SBG::LIB::SetPiece; +using SBG::LIB::detail::Interval; +using SBG::LIB::detail::SetPiece; using SBG::LIB::Set; +using SBG::LIB::SetKind; +using SBG::LIB::detail::UnorderedSet; + +//////////////////////////////////////////////////////////////////////////////// +// Auxiliary functions --------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// /** * @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(); + UnorderedSet s1; + UnorderedSet s2; for (unsigned int h = 0; h < set_sz; ++h) { Interval i1(h*inter_sz, 1, (h + 1)*inter_sz - 1); SetPiece mdi1; @@ -55,109 +68,126 @@ std::pair contiguousPieces(int set_sz) 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); + return {Set(SetKind::Unordered, s1), Set(SetKind::Unordered, s2)}; } -BENCHMARK(BM_OrdSetDiff)->RangeMultiplier(10)->Range(1000, 1e6)->Complexity(); -static void BM_OrdSetDisjointUnion(benchmark::State& state) +static void BM_UnordCap(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); - + auto [s1, s2] = contiguousPieces(2); for (auto _ : state) { - benchmark::DoNotOptimize(s1.compact()); + for (int j = 0; j < set_sz; ++j) + s1.intersection(s2); } state.SetComplexityN(set_sz); } -BENCHMARK(BM_OrdSetCompact)->RangeMultiplier(10)->Range(10, 1e3) - ->Complexity(); +BENCHMARK(BM_UnordCap)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); +*/ + +//////////////////////////////////////////////////////////////////////////////// +// Benchmarks ------------------------------------------------------------------ +//////////////////////////////////////////////////////////////////////////////// + +//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 diff --git a/test/performance/scc/custom_scc_bm.cpp b/test/performance/scc/custom_scc_bm.cpp index 257b2903..994127ae 100644 --- a/test/performance/scc/custom_scc_bm.cpp +++ b/test/performance/scc/custom_scc_bm.cpp @@ -27,11 +27,14 @@ * "size" of the repetitive patterns of the graph. */ -#include - +#include "algorithms/scc/scc.hpp" +#include "algorithms/scc/scc_fact.hpp" #include "eval/user_impl_map.hpp" +#include "sbg/directed_sbg.hpp" #include "test/performance/utils.hpp" +#include + namespace Test { namespace Internal { @@ -54,7 +57,7 @@ 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::DirectedSBG scc_dsbg = misc::buildSCCFromMatching(match_result); SBG::LIB::SCC scc_algorithm = SBG::LIB::SCC_FACT.createSCCAlgorithm(); for (auto _ : state) { @@ -72,7 +75,7 @@ static void BM_CustomSCCTestWithBuilder(benchmark::State& state) SBG::LIB::SCC scc_algorithm = SBG::LIB::SCC_FACT.createSCCAlgorithm(); for (auto _ : state) { - SBG::LIB::DSBG scc_dsbg = MISC::buildSCCFromMatching(match_result); + SBG::LIB::DirectedSBG scc_dsbg = misc::buildSCCFromMatching(match_result); scc_algorithm.calculate(scc_dsbg); } state.SetComplexityN(N); @@ -87,7 +90,7 @@ static void BM_CustomSCCTestCopies(benchmark::State& state) SBG::LIB::SCC scc_algorithm = SBG::LIB::SCC_FACT.createSCCAlgorithm(); for (auto _ : state) { - SBG::LIB::DSBG scc_dsbg = MISC::buildSCCFromMatching(match_result); + SBG::LIB::DirectedSBG scc_dsbg = misc::buildSCCFromMatching(match_result); scc_algorithm.calculate(scc_dsbg); } state.SetComplexityN(N); diff --git a/test/performance/scc/scc_bm.cpp b/test/performance/scc/scc_bm.cpp index 2580a29a..a76d0286 100644 --- a/test/performance/scc/scc_bm.cpp +++ b/test/performance/scc/scc_bm.cpp @@ -24,11 +24,14 @@ * execution time when the repetitive patterns increase its size. */ -#include - +#include "algorithms/scc/scc.hpp" +#include "algorithms/scc/scc_fact.hpp" #include "eval/user_impl_map.hpp" +#include "sbg/directed_sbg.hpp" #include "test/performance/utils.hpp" +#include + namespace Test { namespace Internal { @@ -47,7 +50,7 @@ static void BM_TestRL1(benchmark::State& state) 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); + SBG::LIB::DirectedSBG scc_dsbg = misc::buildSCCFromMatching(match_result); for (auto _ : state) { scc_algorithm.calculate(scc_dsbg); @@ -69,7 +72,7 @@ static void BM_TestRL1WithBuilder(benchmark::State& state) = calculateMatching("../../TestRL1.test", N, 1); for (auto _ : state) { - SBG::LIB::DSBG scc_dsbg = MISC::buildSCCFromMatching(match_result); + SBG::LIB::DirectedSBG scc_dsbg = misc::buildSCCFromMatching(match_result); scc_algorithm.calculate(scc_dsbg); } state.SetComplexityN(N); @@ -87,7 +90,7 @@ static void BM_TestRL2(benchmark::State& state) 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); + SBG::LIB::DirectedSBG scc_dsbg = misc::buildSCCFromMatching(match_result); for (auto _ : state) { scc_algorithm.calculate(scc_dsbg); @@ -109,7 +112,7 @@ static void BM_TestRL2WithBuilder(benchmark::State& state) = calculateMatching("../../TestRL2.test", N, 1); for (auto _ : state) { - SBG::LIB::DSBG scc_dsbg = MISC::buildSCCFromMatching(match_result); + SBG::LIB::DirectedSBG scc_dsbg = misc::buildSCCFromMatching(match_result); scc_algorithm.calculate(scc_dsbg); } state.SetComplexityN(N); @@ -127,7 +130,7 @@ static void BM_TestRL3(benchmark::State& state) 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); + SBG::LIB::DirectedSBG scc_dsbg = misc::buildSCCFromMatching(match_result); for (auto _ : state) { scc_algorithm.calculate(scc_dsbg); @@ -149,7 +152,7 @@ static void BM_TestRL3WithBuilder(benchmark::State& state) = calculateMatching("../../TestRL3.test", N, 1); for (auto _ : state) { - SBG::LIB::DSBG scc_dsbg = MISC::buildSCCFromMatching(match_result); + SBG::LIB::DirectedSBG scc_dsbg = misc::buildSCCFromMatching(match_result); scc_algorithm.calculate(scc_dsbg); } state.SetComplexityN(N); diff --git a/test/performance/unord_pwmap_bm.cpp b/test/performance/unord_pwmap_bm.cpp new file mode 100644 index 00000000..4d8e3a03 --- /dev/null +++ b/test/performance/unord_pwmap_bm.cpp @@ -0,0 +1,402 @@ +/***************************************************************************** + + 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 "sbg/set_fact.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/pwmap_fact.hpp" + +#include + +#include +#include + +namespace Test { + +namespace Internal { + +using SBG::LIB::NAT; +using SBG::LIB::detail::Interval; +using SBG::LIB::detail::MultiDimInter; +using SBG::LIB::SetKind; +using SBG::LIB::Set; +using SBG::LIB::RATIONAL; +using SBG::LIB::detail::LinearExpr; +using SBG::LIB::Expression; +using SBG::LIB::Map; +using SBG::LIB::PWMapKind; +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::PWMAP_FACT.createPWMap(); + for (unsigned int j = 0; j < map_sz; ++j) { + Set domain = SBG::LIB::SET_FACT.createSet(); + SBG::LIB::NAT off = j*set_sz*inter_sz; + for (unsigned int h = 0; h < set_sz; ++h) { + Interval i{off + (h*inter_sz), 1, off + (h + 1)*inter_sz - 1}; + Set jth_domain + = SBG::LIB::SET_FACT.createSet(i.begin(), i.step(), i.end()); + domain = std::move(domain).disjointCup(std::move(jth_domain)); + } + Expression multidim_id{1, 0}; + + pw.emplaceBack(domain, multidim_id); + } + + return pw; +} + +std::pair minAdjMaps(SBG::LIB::NAT map_sz) +{ + SBG::LIB::NAT inter_sz = 100; + SBG::LIB::NAT set_sz = 10; + + Set second_dim = SBG::LIB::SET_FACT.createSet(0, 1, inter_sz - 1); + PWMap pw1 = SBG::LIB::PWMAP_FACT.createPWMap(); + PWMap pw2 = SBG::LIB::PWMAP_FACT.createPWMap(); + for (unsigned int j = 0; j < map_sz; ++j) { + Set domain1 = SBG::LIB::SET_FACT.createSet(); + Set domain2 = 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); + Set jth_domain1 = SBG::LIB::SET_FACT.createSet(i1.begin(), i1.step() + , i1.end()); + domain1 = std::move(domain1).disjointCup(std::move(jth_domain1)); + + SBG::LIB::NAT off2 = off + inter_sz/2; + Interval i2(off2 + (h*inter_sz), 1, off2 + (h + 1)*inter_sz - 1); + Set jth_domain2 = SBG::LIB::SET_FACT.createSet(i2.begin(), i2.step() + , i2.end()); + domain2 = std::move(domain2).disjointCup(std::move(jth_domain2)); + } + + Expression multidim_id{2, 1, 0}; + Expression minus_one{2, 1, RATIONAL{-1, 1}}; + + pw1.emplaceBack(domain1, multidim_id); + pw2.emplaceBack(domain2, 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; + + Set second_dim = SBG::LIB::SET_FACT.createSet(0, 1, inter_sz - 1); + PWMap pw1 = SBG::LIB::PWMAP_FACT.createPWMap(); + PWMap pw2 = SBG::LIB::PWMAP_FACT.createPWMap(); + for (unsigned int j = 0; j < 2*map_sz; j += 2) { + Set domain1 = SBG::LIB::SET_FACT.createSet(); + Set domain2 = SBG::LIB::SET_FACT.createSet(); + SBG::LIB::NAT off = j*set_sz*inter_sz; + for (unsigned int h = 0; h < set_sz; h += 2) { + Interval i1{off + (h*inter_sz), 1, off + (h + 1)*inter_sz - 1}; + Set jth_domain1 = SBG::LIB::SET_FACT.createSet(i1.begin(), i1.step() + , i1.end()); + domain1 = std::move(domain1).disjointCup(std::move(jth_domain1)); + + SBG::LIB::NAT off2 = off + inter_sz; + Interval i2{off2 + (h*inter_sz), 1, off2 + (h + 1)*inter_sz - 1}; + Set jth_domain2 = SBG::LIB::SET_FACT.createSet(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.emplaceBack(domain1, multidim_id); + pw2.emplaceBack(domain2, 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; + + Set second_dim = SBG::LIB::SET_FACT.createSet(0, 1, inter_sz - 1); + PWMap pw1 = SBG::LIB::PWMAP_FACT.createPWMap(); + PWMap pw2 = SBG::LIB::PWMAP_FACT.createPWMap(); + for (unsigned int j = 0; j < map_sz; ++j) { + Set domain1 = SBG::LIB::SET_FACT.createSet(); + Set domain2 = 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}; + Set jth_domain1 = SBG::LIB::SET_FACT.createSet(i1.begin(), i1.step() + , i1.end()); + domain1 = std::move(domain1).disjointCup(std::move(jth_domain1)); + + SBG::LIB::NAT off2 = off + inter_sz/2; + Interval i2{off2 + (h*inter_sz), 1, off2 + (h + 1)*inter_sz - 1}; + Set jth_domain2 = SBG::LIB::SET_FACT.createSet(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.emplaceBack(domain1, multidim_id); + pw2.emplaceBack(domain2, multidim_id); + } + + return {pw1, pw2}; +} + +//////////////////////////////////////////////////////////////////////////////// +// Benchmarks ------------------------------------------------------------------ +//////////////////////////////////////////////////////////////////////////////// + +static void BM_UnordPWMapDenseDom(benchmark::State& state) +{ + int map_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); + auto pw = denseDom(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw.domain()); + } + state.SetComplexityN(map_sz); +} +BENCHMARK(BM_UnordPWMapDenseDom)->RangeMultiplier(10)->Range(10, 1e3) + ->Complexity(); + +static void BM_UnordPWMapEq(benchmark::State& state) +{ + int map_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); + auto [pw1, pw2] = contiguousMaps(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1 == pw2); + } + state.SetComplexityN(map_sz); +} +BENCHMARK(BM_UnordPWMapEq)->RangeMultiplier(10)->Range(10, 1e2)->Complexity(); + +static void BM_UnordPWMapSum(benchmark::State& state) +{ + int map_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); + auto [pw1, pw2] = contiguousMaps(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1 + pw2); + } + state.SetComplexityN(map_sz); +} +BENCHMARK(BM_UnordPWMapSum)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); + +static void BM_UnordPWMapDom(benchmark::State& state) +{ + int map_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); + auto [pw1, pw2] = contiguousMaps(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.domain()); + } + state.SetComplexityN(map_sz); +} +BENCHMARK(BM_UnordPWMapDom)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); + +static void BM_UnordPWMapRestrict(benchmark::State& state) +{ + int map_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); + auto [pw1, pw2] = contiguousMaps(map_sz); + Set domain2 = pw2.domain(); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.restrict(domain2)); + } + state.SetComplexityN(map_sz); +} +BENCHMARK(BM_UnordPWMapRestrict)->RangeMultiplier(10)->Range(10, 1e3) + ->Complexity(); + +static void BM_UnordPWMapImage(benchmark::State& state) +{ + int map_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); + auto [pw1, pw2] = contiguousMaps(map_sz); + Set domain2 = pw2.domain(); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.image(domain2)); + } + state.SetComplexityN(map_sz); +} +BENCHMARK(BM_UnordPWMapImage)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); + +static void BM_UnordPWMapPreImage(benchmark::State& state) +{ + int map_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); + auto [pw1, pw2] = contiguousMaps(map_sz); + Set img2 = pw2.image(); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.preImage(img2)); + } + state.SetComplexityN(map_sz); +} +BENCHMARK(BM_UnordPWMapPreImage)->RangeMultiplier(10)->Range(10, 1e3) + ->Complexity(); + +static void BM_UnordPWMapComposition(benchmark::State& state) +{ + int map_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); + auto [pw1, pw2] = contiguousMaps(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.composition(pw2)); + } + state.SetComplexityN(map_sz); +} +BENCHMARK(BM_UnordPWMapComposition)->RangeMultiplier(10)->Range(10, 1e3) + ->Complexity(); + +static void BM_UnordPWMapConcat(benchmark::State& state) +{ + int map_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); + auto [pw1, pw2] = interlacedMaps(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.concatenation(pw2)); + } + state.SetComplexityN(map_sz); +} +BENCHMARK(BM_UnordPWMapConcat)->RangeMultiplier(10)->Range(10, 1e3) + ->Complexity(); + +static void BM_UnordPWMapCombine(benchmark::State& state) +{ + int map_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); + auto [pw1, pw2] = contiguousMaps(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.combine(pw2)); + } + state.SetComplexityN(map_sz); +} +BENCHMARK(BM_UnordPWMapCombine)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); + +// TODO: reduce + +static void BM_UnordPWMapMinAdj(benchmark::State& state) +{ + int map_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); + auto [pw1, pw2] = minAdjMaps(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.minAdj(pw2)); + } + state.SetComplexityN(map_sz); +} +BENCHMARK(BM_UnordPWMapMinAdj)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); + +static void BM_UnordPWMapEqImage(benchmark::State& state) +{ + int map_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); + auto [pw1, pw2] = contiguousMaps(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.equalImage(pw2)); + } + state.SetComplexityN(map_sz); +} +BENCHMARK(BM_UnordPWMapEqImage)->RangeMultiplier(10)->Range(10, 1e3) + ->Complexity(); + +static void BM_UnordPWMapLessImage(benchmark::State& state) +{ + int map_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); + auto [pw1, pw2] = contiguousMaps(map_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(pw1.lessImage(pw2)); + } + state.SetComplexityN(map_sz); +} +BENCHMARK(BM_UnordPWMapLessImage)->RangeMultiplier(10)->Range(10, 1e3) + ->Complexity(); + +static void BM_UnordPWMapCompact(benchmark::State& state) +{ + int map_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); + auto [pw1, pw2] = contiguousMaps(map_sz); + + for (auto _ : state) { + pw1.compact(); + } + state.SetComplexityN(map_sz); +} +BENCHMARK(BM_UnordPWMapCompact)->RangeMultiplier(10)->Range(10, 1e2) + ->Complexity(); + +} // namespace Internal + +} // namespace Test diff --git a/test/performance/unord_set_bm.cpp b/test/performance/unord_set_bm.cpp new file mode 100644 index 00000000..55f147e8 --- /dev/null +++ b/test/performance/unord_set_bm.cpp @@ -0,0 +1,181 @@ +/***************************************************************************** + + 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 "sbg/set_fact.hpp" + +#include + +#include +#include + +namespace Test { + +namespace Internal { + +using SBG::LIB::NAT; +using SBG::LIB::detail::Interval; +using SBG::LIB::detail::SetPiece; +using SBG::LIB::SetKind; +using SBG::LIB::Set; + +//////////////////////////////////////////////////////////////////////////////// +// Auxiliary functions --------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +/** + * @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; + + 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); + Set jth_s1 = SBG::LIB::SET_FACT.createSet(i1.begin(), i1.step() + , i1.end()); + s1 = s1.disjointCup(jth_s1); + + SBG::LIB::NAT off = inter_sz/2; + Interval i2(off + (h*inter_sz), 1, off + (h + 1)*inter_sz - 1); + Set jth_s2 = SBG::LIB::SET_FACT.createSet(i2.begin(), i2.step(), i2.end()); + s2 = s2.disjointCup(jth_s2); + } + + Set second_dim = SBG::LIB::SET_FACT.createSet(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)); +} + +//////////////////////////////////////////////////////////////////////////////// +// Benchmarks ------------------------------------------------------------------ +//////////////////////////////////////////////////////////////////////////////// + +static void BM_UnordSetEq(benchmark::State& state) +{ + int set_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + auto [s1, s2] = contiguousPieces(set_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(s1 == s2); + } + state.SetComplexityN(set_sz); +} +BENCHMARK(BM_UnordSetEq)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); + +static void BM_UnordSetCap(benchmark::State& state) +{ + int set_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + auto [s1, s2] = contiguousPieces(set_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(s1.intersection(s2)); + } + state.SetComplexityN(set_sz); +} +BENCHMARK(BM_UnordSetCap)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); + +static void BM_UnordSetCup(benchmark::State& state) +{ + int set_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + auto [s1, s2] = contiguousPieces(set_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(s1.cup(s2)); + } + state.SetComplexityN(set_sz); +} +BENCHMARK(BM_UnordSetCup)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); + +static void BM_UnordSetComplement(benchmark::State& state) +{ + int set_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + auto [s1, s2] = contiguousPieces(set_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(s1.complement()); + } + state.SetComplexityN(set_sz); +} +BENCHMARK(BM_UnordSetComplement)->RangeMultiplier(10)->Range(10, 1e3) + ->Complexity(); + +static void BM_UnordSetDiff(benchmark::State& state) +{ + int set_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + auto [s1, s2] = contiguousPieces(set_sz); + + for (auto _ : state) { + benchmark::DoNotOptimize(s1.difference(s2)); + } + state.SetComplexityN(set_sz); +} +BENCHMARK(BM_UnordSetDiff)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); + +static void BM_UnordSetDisjointUnion(benchmark::State& state) +{ + int set_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + 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) { + Set jth_s1 = SBG::LIB::SET_FACT.createSet(j*100 + 1, 1, (j + 1)*100); + s1 = std::move(s1.disjointCup(jth_s1)); + Set jth_s2 = SBG::LIB::SET_FACT.createSet((j + 1)*100+1, 1, (j + 2)*100); + s2 = std::move(s2.disjointCup(jth_s2)); + } + + for (auto _ : state) { + benchmark::DoNotOptimize(std::move(s1).disjointCup(std::move(s2))); + } + state.SetComplexityN(set_sz); +} +BENCHMARK(BM_UnordSetDisjointUnion)->RangeMultiplier(10)->Range(10, 1e3) + ->Complexity(); + +static void BM_UnordSetCompact(benchmark::State& state) +{ + int set_sz = state.range(0); + SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); + auto [s1, s2] = contiguousPieces(set_sz); + + for (auto _ : state) { + s1.compact(); + } + state.SetComplexityN(set_sz); +} +BENCHMARK(BM_UnordSetCompact)->RangeMultiplier(10)->Range(10, 1e2) + ->Complexity(); + +} // namespace Internal + +} // namespace Test diff --git a/test/performance/utils.cpp b/test/performance/utils.cpp index ffb44c6c..a4ddd9a4 100644 --- a/test/performance/utils.cpp +++ b/test/performance/utils.cpp @@ -22,9 +22,12 @@ #include #include +#include "algorithms/matching/matching.hpp" +#include "algorithms/matching/matching_fact.hpp" #include "algorithms/misc/causalization_builders.hpp" #include "eval/file_evaluator.cpp" #include "eval/user_impl_map.hpp" +#include "sbg/bipartite_sbg.hpp" namespace Test { @@ -90,7 +93,8 @@ SBG::LIB::BipartiteSBG generateSBG(std::string filename, int N, int copies) std::cout.rdbuf(original_buf); - return g.copy(copies); + return g; + //TODO return g.copy(copies); } SBG::LIB::MatchData calculateMatching(std::string filename, int N, int copies) From 375a2ba55ea3be1e18ad5de36287ea2e810401d7 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 5 Mar 2026 21:00:16 -0300 Subject: [PATCH 14/66] Style fix --- parser/parser_exec.cpp | 20 ++++++++++---------- util/logger.cpp | 18 +++++++++++------- util/logger.hpp | 10 +++------- util/time_profiler.cpp | 34 ++++++++++++++++------------------ util/time_profiler.hpp | 13 +++++++------ util/user_input_handler.cpp | 18 +++++++++--------- util/user_input_handler.hpp | 18 +++++++++--------- 7 files changed, 65 insertions(+), 66 deletions(-) diff --git a/parser/parser_exec.cpp b/parser/parser_exec.cpp index d0cafe36..ddf5515f 100644 --- a/parser/parser_exec.cpp +++ b/parser/parser_exec.cpp @@ -36,9 +36,9 @@ 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_); + _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 +47,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 +56,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 +69,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/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..fb99fa21 100644 --- a/util/time_profiler.cpp +++ b/util/time_profiler.cpp @@ -23,45 +23,43 @@ namespace SBG { namespace Util { - void time_profiler_results() { - Internal::TimeProfiler::print_execution_time(); + Internal::TimeProfiler::print_execution_time(); } - 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; } + } } } diff --git a/util/time_profiler.hpp b/util/time_profiler.hpp index 6d7867ef..01e3bcf9 100644 --- a/util/time_profiler.hpp +++ b/util/time_profiler.hpp @@ -37,16 +37,17 @@ 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(); 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..28cef79b 100644 --- a/util/user_input_handler.cpp +++ b/util/user_input_handler.cpp @@ -45,23 +45,23 @@ 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); + _positional.add("input-file", 1); } } // namespace Util diff --git a/util/user_input_handler.hpp b/util/user_input_handler.hpp index d069ebdd..b3d97943 100644 --- a/util/user_input_handler.hpp +++ b/util/user_input_handler.hpp @@ -46,15 +46,15 @@ class UserInputHandler { virtual void execute(int arg_count, char* args[]) = 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 From fe6a3e74d1586f3612e73466e443a1195f67df0f Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Fri, 6 Mar 2026 15:11:50 -0300 Subject: [PATCH 15/66] Redefined OrderedSet --- algorithms/scc/minreach_scc.cpp | 2 +- eval/user_impl_map.cpp | 2 + sbg/CMakeLists.txt | 2 +- sbg/map_detail.cpp | 78 ++-- sbg/map_detail.hpp | 4 +- sbg/ord_set.cpp | 764 ++++++++++++++------------------ sbg/ord_set.hpp | 126 +++--- sbg/ord_unidim_dense_set.cpp | 4 + sbg/set.cpp | 5 + sbg/set.hpp | 7 +- sbg/set_fact.cpp | 72 ++- sbg/set_fact.hpp | 30 +- sbg/unord_set.cpp | 67 ++- 13 files changed, 539 insertions(+), 624 deletions(-) diff --git a/algorithms/scc/minreach_scc.cpp b/algorithms/scc/minreach_scc.cpp index 5b1763e6..c864b2a0 100644 --- a/algorithms/scc/minreach_scc.cpp +++ b/algorithms/scc/minreach_scc.cpp @@ -72,7 +72,7 @@ SCCData MinReachSCC::calculate(const DirectedSBG& dsbg) oldE = _dsbg.E(); rmap = sccStep(); Ediff = oldE.difference(_dsbg.E()); - deleted_edges = std::move(deleted_edges).disjointCup(std::move(Ediff)); + deleted_edges = std::move(deleted_edges).disjointCup(Ediff); } while (Ediff != SET_FACT.createSet()); rmap.compact(); diff --git a/eval/user_impl_map.cpp b/eval/user_impl_map.cpp index 37c2baf4..12a62cdb 100755 --- a/eval/user_impl_map.cpp +++ b/eval/user_impl_map.cpp @@ -19,7 +19,9 @@ #include "algorithms/scc/scc_fact.hpp" #include "eval/user_impl_map.hpp" +#include "sbg/pw_map.hpp" #include "sbg/pwmap_fact.hpp" +#include "sbg/set.hpp" #include "sbg/set_fact.hpp" #include "util/debug.hpp" diff --git a/sbg/CMakeLists.txt b/sbg/CMakeLists.txt index 9daaee93..be74246b 100644 --- a/sbg/CMakeLists.txt +++ b/sbg/CMakeLists.txt @@ -17,6 +17,7 @@ target_sources( map_detail.cpp multidim_inter.cpp natural.cpp + ord_set.cpp ord_unidim_dense_set.cpp pw_map.cpp pwmap_fact.cpp @@ -26,7 +27,6 @@ target_sources( set_fact.cpp unord_pwmap.cpp unord_set.cpp - #ord_set.cpp #dom_ord_pwmap.cpp #map_entry.cpp #ord_pwmap.cpp diff --git a/sbg/map_detail.cpp b/sbg/map_detail.cpp index 6b5dd1f3..1628e463 100755 --- a/sbg/map_detail.cpp +++ b/sbg/map_detail.cpp @@ -89,30 +89,23 @@ CompactSetImpl compactImage(const CompactSetImpl& s, const Expr& expr return result; } -UnorderedSet image(const UnorderedSet& s, const ExpressionImpl& expr - , bool is_injective) -{ - return compactImage( - s, expr, is_injective); -} - -OrdUnidimDenseSet image(const OrdUnidimDenseSet& s - , const LinearExpr& linear_expr, bool is_injective) -{ - return compactImage( - s, linear_expr, is_injective); -} - Set MapDetail::image(const Set& s, const Expression& expr) { auto image_evaluator = Overload { [&](const UnorderedSet& a) { - return Set{detail::image(a, expr._impl, expr.isInjective())}; + return Set{detail::compactImage(a, expr._impl, expr.isInjective())}; }, [&](const OrdUnidimDenseSet& a) { - return Set{detail::image(a, expr._impl[0], expr.isInjective())}; + return Set{detail::compactImage( + a, expr._impl[0], expr.isInjective())}; + }, + [&](const OrderedSet& a) + { + return Set{detail::compactImage(a, expr._impl, expr.isInjective())}; }, [&](const auto& a) { return Set{SetKind::kUnordered}; } }; @@ -159,29 +152,23 @@ CompactSetImpl compactPreImage(const CompactSetImpl& s, const Expr& expr) return result; } -UnorderedSet preImage(const UnorderedSet& s, const ExpressionImpl& linear_expr) -{ - return compactPreImage( - s, linear_expr); -} - -OrdUnidimDenseSet preImage(const OrdUnidimDenseSet& s - , const LinearExpr& linear_expr) -{ - return compactPreImage( - s, linear_expr); -} - Set MapDetail::preImage(const Set& s, const Expression& expr) { auto pre_image_evaluator = Overload { [&](const UnorderedSet& a) { - return Set{detail::preImage(a, expr._impl)}; + return Set{detail::compactPreImage(a, expr._impl)}; }, [&](const OrdUnidimDenseSet& a) { - return Set{detail::preImage(a, expr._impl[0])}; + return Set{detail::compactPreImage(a, expr._impl[0])}; + }, + [&](const OrderedSet& a) + { + return Set{detail::compactPreImage(a, expr._impl)}; }, [&](const auto& a) { return Set{SetKind::kUnordered}; } }; @@ -289,6 +276,12 @@ Set MapDetail::lessImage(const Expression& expr1, const Expression& expr2) a.pushBack(detail::lessImage(expr1._impl[0], expr2._impl[0])); return Set{a}; }, + [&](OrderedSet& a) + { + detail::lessImage( + expr1._impl, expr2._impl, a); + return Set{a}; + }, [&](auto& a) { return Set{SetKind::kUnordered}; } }; return std::visit(less_image_evaluator, result._impl); @@ -392,7 +385,9 @@ AtomicMapVector reduce(const MultiDimInter& mdi, const ExpressionImpl& expr return reduce(reducible_interval, reducible_expr); } -MapVector MapDetail::reduce(const UnorderedSet& s, const ExpressionImpl& expr) +template +MapVector MapDetail::MDICollectionReduce(const SetMDIImpl& s + , const ExpressionImpl& expr) { MapVector result; @@ -443,13 +438,22 @@ MapVector MapDetail::reduce(const Map& m) return result; } - result = std::visit([&](const auto& a) + auto reduce_evaluator = Overload { + [&](const UnorderedSet& a) + { + return MDICollectionReduce(a, law._impl); + }, + [&](const OrdUnidimDenseSet& a) { return reduce(a, law._impl); - } - , domain._impl); - - return result; + }, + [&](const OrderedSet& a) + { + return MDICollectionReduce(a, law._impl); + }, + [&](const auto& a) { return Set{SetKind::kUnordered}; } + }; + return std::visit(reduce_evaluator, m.domain()._impl); } } // namespace detail diff --git a/sbg/map_detail.hpp b/sbg/map_detail.hpp index a884845c..fbd6e072 100755 --- a/sbg/map_detail.hpp +++ b/sbg/map_detail.hpp @@ -53,7 +53,9 @@ class MapDetail { static MapVector reduce(const Map& m); private: - static MapVector reduce(const UnorderedSet& s, const ExpressionImpl& expr); + template + static MapVector MDICollectionReduce(const SetMDIImpl& s + , const ExpressionImpl& expr); static MapVector reduce(const OrdUnidimDenseSet& s , const ExpressionImpl& expr); }; diff --git a/sbg/ord_set.cpp b/sbg/ord_set.cpp index 8b3f1d5e..c3f20ded 100644 --- a/sbg/ord_set.cpp +++ b/sbg/ord_set.cpp @@ -17,25 +17,28 @@ ******************************************************************************/ -#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 +47,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::MDIOrdCollection& pieces) + : _pieces(pieces) {} -const SetPiece& OrderedSet::Iterator::operator*() const { return *it_; } +OrderedSet::OrderedSet(OrderedSet::MDIOrdCollection&& 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(); } + +// Setters --------------------------------------------------------------------- - if (pieces_.empty() || pieces_.back() < mdi) { - pieces_.emplace_back(mdi); +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 +223,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::MDIOrdCollection short_set = lhs._pieces; + OrderedSet::MDIOrdCollection 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 +268,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 +290,351 @@ 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 (maxElem() < other.minElem()) { + MDIOrdCollection 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 (othr.maxElem() < minElem()) { - result = std::move(othr.pieces_); - result.insert(result.end(), pieces_.begin(), pieces_.end()); - return std::make_unique(std::move(result)); + if (other.maxElem() < minElem()) { + MDIOrdCollection 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; + MDIOrdCollection 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) +std::size_t 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_); - return; + if (isEmpty()) { + return 0; } // General case - size_t i = 0; - for (const SetPiece& elem : pieces_) { - if (!(elem.maxElem() < mdi.minElem())) + std::size_t i = 0; + // 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. + for (const MultiDimInter& elem : _pieces) { + if (!(elem.maxElem() < mdi.minElem())) { break; - rem.emplaceBack(elem); + } ++i; } - 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); + NAT global_position = 0; + OrderedSet result; + for (auto it = _pieces.begin() + i; 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); - pieces_ = std::move(result.pieces_); - return; + return i; } -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 OrderedSet::complement() const +{ + if (isEmpty()) { + return OrderedSet{}; + } + + OrderedSet result = OrderedSet{_pieces.front()}.complementAtom(); + std::size_t i = 0; + std::size_t j = 0; + for (const MultiDimInter& mdi : _pieces) { + if (j > 0) { + OrderedSet c = OrderedSet{mdi}.complementAtom(); + i = result.intersectionComplement(c, mdi); + } + ++j; + } + + // Calculate remnant OrderedSet remnant; - for (const SetPiece& mdi : second) { - SetStratPtr c = OrderedSet(mdi).complementAtom(); - result.intersectionComp(*c, mdi, remnant); + for (j = 0; j < i; ++j) { + remnant.pushBack(result._pieces[j]); } - - return remnant.disjointCup(result); + + return std::move(remnant).disjointCup(std::move(result)); } -SetStratPtr OrderedSet::difference(const SetStrategy& other) const -{ +OrderedSet OrderedSet::difference(const OrderedSet& other) const +{ // Special cases - if (isEmpty() || other.isEmpty()) - return std::make_unique(pieces_); + if (isEmpty() || other.isEmpty()) { + return OrderedSet{_pieces}; + } - if (maxElem() < other.minElem() || other.maxElem() < minElem()) - return std::make_unique(pieces_); - - // General case - return intersection(*other.complement()); -} + if (_pieces == other._pieces) { + return OrderedSet{}; + } -// Extra operations ------------------------------------------------------------ + // General case + return intersection(other.complement()); +} -std::size_t OrderedSet::arity() const +OrderedSet OrderedSet::cartesianProduct(const OrderedSet& other) const { - if (isEmpty()) - return 0; + OrderedSet result; - return pieces_.begin()->arity(); + 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; } -SetStratPtr OrderedSet::disjointCup(const SetStrategy& other) const & +// Extra operations ------------------------------------------------------------ + +std::size_t OrderedSet::arity() const { - OrdSetCRef 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 _pieces.begin()->arity(); +} - 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)); - } +OrderedSet OrderedSet::disjointCup(const OrderedSet& other) const & +{ + return OrderedSet{*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)); - } +OrderedSet OrderedSet::disjointCup(const OrderedSet& other) && +{ + return std::move(*this).disjointCup(OrderedSet{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; - } - } - result.insert(result.end(), it1, end1); - result.insert(result.end(), it2, end2); - - return std::make_unique(std::move(result)); +OrderedSet OrderedSet::disjointCup(OrderedSet&& other) const & +{ + return OrderedSet{*this}.disjointCup(std::move(other)); } -SetStratPtr OrderedSet::disjointCup(SetStrategy&& other) && -{ +OrderedSet OrderedSet::disjointCup(OrderedSet&& other) && +{ // Special cases - OrdSetRef othr = static_cast(other); - if (other.isEmpty() || pieces_ == othr.pieces_) { - return std::make_unique(std::move(pieces_)); - } - if (isEmpty()) { - return std::make_unique(std::move(othr.pieces_)); + return std::move(other); } - 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 (other.isEmpty()) { + return std::move(*this); } - 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)); + MDIOrdCollection 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())); } // General case - auto it1 = pieces_.begin(); - auto end1 = pieces_.end(); - auto it2 = othr.pieces_.begin(); - auto end2 = othr.pieces_.end(); + 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.emplace_back(*it1); + result.push_back(*it1); ++it1; } else { - result.emplace_back(*it2); + result.push_back(*it2); ++it2; } } - result.insert(result.end(), it1, end1); - result.insert(result.end(), it2, end2); - - return std::make_unique(std::move(result)); -} - -SetStratPtr OrderedSet::filterSet(bool (*f)(const SetPiece& mdi)) const -{ - MDIOrdCollection res; - - for (const SetPiece& mdi : pieces_) { - if (f(mdi)) { - res.push_back(mdi); - } - } + 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)); - return std::make_unique(std::move(res)); + return OrderedSet{std::move(result)}; } -SetStratPtr OrderedSet::offset(const MD_NAT& off) const +OrderedSet OrderedSet::offset(const MD_NAT& off) const { - MDIOrdCollection res; + OrderedSet result; - for (const SetPiece& mdi : pieces_) { - res.emplace_back(mdi.offset(off)); + for (const MultiDimInter& mdi : _pieces) { + result.pushBack(mdi.offset(off)); } - return std::make_unique(std::move(res)); + return result; } -SetStratPtr OrderedSet::compact() const +void OrderedSet::compact() { MDIOrdCollection result; if (!isEmpty()) { - std::set prev(pieces_.begin(), pieces_.end()); - std::set actual = prev; + std::set prev{_pieces.begin(), _pieces.end()}; + std::set actual = prev; do { prev = actual; - actual = std::set(); + actual = std::set{}; - std::set::iterator ith = prev.begin(); - std::set::iterator last = prev.end(); - std::set to_erase; + std::set::iterator ith = prev.begin(); + std::set::iterator last = prev.end(); + std::set to_erase; for (; ith != last; ++ith) { - SetPiece ith_compact = *ith; - std::set::iterator next = ith; + MultiDimInter ith_compact = *ith; + std::set::iterator next = ith; ++next; for (; next != last; ++next) { MaybeMDI new_compact = ith_compact.compact(*next); @@ -743,19 +644,22 @@ SetStratPtr OrderedSet::compact() const } } - if (to_erase.find(ith_compact) == to_erase.end()) + if (to_erase.find(ith_compact) == to_erase.end()) { actual.insert(ith_compact); - } + } + } } while (actual != prev); - for (const SetPiece& mdi : actual) { - result.emplace_back(mdi); + for (const MultiDimInter& mdi : actual) { + result.push_back(mdi); } } - return std::make_unique(std::move(result)); + _pieces = std::move(result); } +} // namespace detail + } // namespace LIB } // namespace SBG diff --git a/sbg/ord_set.hpp b/sbg/ord_set.hpp index 014f544b..f2792ac5 100644 --- a/sbg/ord_set.hpp +++ b/sbg/ord_set.hpp @@ -21,101 +21,103 @@ ******************************************************************************/ -#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 +#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 MDIOrdCollection = std::vector; + using ConstIt = MDIOrdCollection::const_iterator; - ~OrderedSet(); OrderedSet(); - OrderedSet(MD_NAT x); - OrderedSet(Interval i); - OrderedSet(SetPiece mdi); - OrderedSet(MDIOrdCollection pieces); - - SetStratPtr clone() const override; - - class Iterator : public SetStrategy::Iterator { - member_class(MDIOrdCollection::const_iterator, it); - - 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; - }; + OrderedSet(const MD_NAT& x); + OrderedSet(const detail::Interval& i); + OrderedSet(const detail::MultiDimInter& mdi); + OrderedSet(const MDIOrdCollection& pieces); + OrderedSet(MDIOrdCollection&& pieces); + OrderedSet(const FixedPointsInfo& info); - std::shared_ptr begin() const override; - std::shared_ptr end() const override; + ConstIt begin() const; + ConstIt end() const; - std::size_t size() const override; - void emplace(const SetPiece& mdi) override; - void emplaceBack(const SetPiece& mdi) override; + void pushBack(const MultiDimInter& mdi); - 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; + 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); + std::size_t intersectionComplement(const OrderedSet& other + , const MultiDimInter& mdi); + + /** + * @brief Calculate the complement of an unordered set with a single piece. + */ + OrderedSet complementAtom() const; + + MDIOrdCollection _pieces; }; -typedef const OrderedSet& OrdSetCRef; -typedef OrderedSet& OrdSetRef; +} // 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 50ccbd2e..0bf8e666 100644 --- a/sbg/ord_unidim_dense_set.cpp +++ b/sbg/ord_unidim_dense_set.cpp @@ -355,6 +355,10 @@ OrdUnidimDenseSet OrdUnidimDenseSet::difference(const OrdUnidimDenseSet& other) return OrdUnidimDenseSet{_pieces}; } + if (_pieces == other._pieces) { + return OrdUnidimDenseSet{}; + } + return intersection(other.complement()); } diff --git a/sbg/set.cpp b/sbg/set.cpp index 622fd2bc..9ec905d2 100644 --- a/sbg/set.cpp +++ b/sbg/set.cpp @@ -72,6 +72,7 @@ Set::Set(const SetKind kind) : _impl() } case SetKind::kOrdered: { + _impl = detail::OrderedSet{}; break; } @@ -96,6 +97,7 @@ Set::Set(const SetKind kind, const MD_NAT& x) : _impl() } case SetKind::kOrdered: { + _impl = detail::OrderedSet{x}; break; } @@ -121,6 +123,7 @@ Set::Set(const SetKind kind, const NAT lo, const NAT step, const NAT hi) } case SetKind::kOrdered: { + _impl = detail::OrderedSet{detail::Interval(lo, step, hi)}; break; } @@ -145,6 +148,8 @@ Set::Set(const SetKind kind, const FixedPointsInfo& info) : _impl() } case SetKind::kOrdered: { + _impl = detail::OrderedSet{info}; + break; } case SetKind::kOrdUnidimDense: { diff --git a/sbg/set.hpp b/sbg/set.hpp index 549d8329..1c2e3e0e 100644 --- a/sbg/set.hpp +++ b/sbg/set.hpp @@ -38,6 +38,7 @@ #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/unord_set.hpp" @@ -57,10 +58,8 @@ namespace detail { //////////////////////////////////////////////////////////////////////////////// using SetImpl = std::variant; - -using SetConstIt = std::variant; + , detail::OrdUnidimDenseSet + , detail::OrderedSet>; class MapDetail; diff --git a/sbg/set_fact.cpp b/sbg/set_fact.cpp index a29b4d85..b11478cb 100644 --- a/sbg/set_fact.cpp +++ b/sbg/set_fact.cpp @@ -17,6 +17,8 @@ ******************************************************************************/ +#include "sbg/ord_set.hpp" +#include "sbg/ord_unidim_dense_set.hpp" #include "sbg/set_fact.hpp" #include "sbg/unord_set.hpp" #include "util/debug.hpp" @@ -29,8 +31,6 @@ namespace LIB { // Unordered Set Factory ------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -UnordSetFact::UnordSetFact() {} - Set UnordSetFact::createSet() { return Set{SetKind::kUnordered}; @@ -51,56 +51,52 @@ Set UnordSetFact::createSet(const FixedPointsInfo& info) return Set{SetKind::kUnordered, info}; } -////////////////////////////////////////////////////////////////////////////////// -//// 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)); -//} -// -//Set OrdSetFact::createSet(const FixedPointsInfo& info) const -//{ -// return Set(std::make_unique(info)); -//} +//////////////////////////////////////////////////////////////////////////////// +// Ordered Set Factory --------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +Set OrdSetFact::createSet() +{ + return Set{SetKind::kOrdered}; +} + +Set OrdSetFact::createSet(const MD_NAT& x) +{ + return Set{SetKind::kOrdered, x}; +} + +Set OrdSetFact::createSet(const NAT lo, const NAT step, const NAT hi) +{ + return Set{SetKind::kOrdered, lo, step, hi}; +} + +Set OrdSetFact::createSet(const FixedPointsInfo& info) +{ + return Set{SetKind::kOrdered, info}; +} + +//////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // Ordered Unidimensional Dense Set Factory ------------------------------------ //////////////////////////////////////////////////////////////////////////////// -Set OrdUnidimDenseSetFact::createSet() const +Set OrdUnidimDenseSetFact::createSet() { return Set{SetKind::kOrdUnidimDense}; } -Set OrdUnidimDenseSetFact::createSet(const MD_NAT& x) const +Set OrdUnidimDenseSetFact::createSet(const MD_NAT& x) { return Set{SetKind::kOrdUnidimDense, x}; } Set OrdUnidimDenseSetFact::createSet(const NAT lo, const NAT step, const NAT hi) - const { return Set{SetKind::kOrdUnidimDense, lo, step, hi}; } -Set OrdUnidimDenseSetFact::createSet(const FixedPointsInfo& info) const +Set OrdUnidimDenseSetFact::createSet(const FixedPointsInfo& info) { return Set{SetKind::kOrdUnidimDense, info}; } @@ -128,10 +124,10 @@ void SetFactory::set_set_fact(SetKind kind) break; } - //case SetKind::kOrdered: { - // _impl = OrdSetFact{}; - // break; - //} + case SetKind::kOrdered: { + _impl = OrdSetFact{}; + break; + } case SetKind::kOrdUnidimDense: { _impl = OrdUnidimDenseSetFact{}; diff --git a/sbg/set_fact.hpp b/sbg/set_fact.hpp index 826c149d..ec2f33de 100644 --- a/sbg/set_fact.hpp +++ b/sbg/set_fact.hpp @@ -44,28 +44,26 @@ namespace LIB { class UnordSetFact { public: - UnordSetFact(); - static Set createSet(); static Set createSet(const MD_NAT& x); static Set createSet(const NAT lo, const NAT step, const NAT hi); static Set createSet(const FixedPointsInfo& info); }; -//class OrdSetFact { -//public: -// Set createSet() const; -// Set createSet(const MD_NAT& x) const; -// Set createSet(const NAT lo, const NAT step, const NAT hi) const; -// Set createSet(const FixedPointsInfo& mdi) const; -//}; - class OrdUnidimDenseSetFact { public: - Set createSet() const; - Set createSet(const MD_NAT& x) const; - Set createSet(const NAT lo, const NAT step, const NAT hi) const; - Set createSet(const FixedPointsInfo& info) const; + static Set createSet(); + static Set createSet(const MD_NAT& x); + static Set createSet(const NAT lo, const NAT step, const NAT hi); + static Set createSet(const FixedPointsInfo& info); +}; + +class OrdSetFact { +public: + static Set createSet(); + static Set createSet(const MD_NAT& x); + static Set createSet(const NAT lo, const NAT step, const NAT hi); + static Set createSet(const FixedPointsInfo& info); }; /** @@ -88,7 +86,9 @@ class SetFactory { Set createSet(const FixedPointsInfo& mdi) const; private: - using FactImpl = std::variant; + using FactImpl = std::variant; SetFactory(); diff --git a/sbg/unord_set.cpp b/sbg/unord_set.cpp index 35895cc9..d10cabe1 100644 --- a/sbg/unord_set.cpp +++ b/sbg/unord_set.cpp @@ -29,6 +29,15 @@ namespace LIB { namespace detail { +//////////////////////////////////////////////////////////////////////////////// +// Auxiliary functions --------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +bool overlap(const UnorderedSet& lhs, const UnorderedSet& rhs) +{ + return rhs.minElem() < lhs.maxElem() || lhs.minElem() < rhs.maxElem(); +} + //////////////////////////////////////////////////////////////////////////////// // Unordered Set Implementation ------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// @@ -256,29 +265,25 @@ UnorderedSet UnorderedSet::complementAtom() const 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}; if (!i_res.isEmpty()) { univ[dim] = i_res; - c.push_back(univ); + 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.push_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); } } } @@ -288,18 +293,12 @@ UnorderedSet UnorderedSet::complementAtom() const Interval i_res{i.end() + 1, 1, Inf}; if (!i_res.isEmpty()) { univ[dim] = i_res; - c.push_back(univ); + 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 MultiDimInter& mdi : c) { - result.push_back(mdi); - } - ++dim; } @@ -308,21 +307,18 @@ UnorderedSet UnorderedSet::complementAtom() const UnorderedSet UnorderedSet::complement() const { - UnorderedSet result; - if (isEmpty()) { - return result; + return UnorderedSet{}; } - auto first_it = _pieces.begin(); - MultiDimInter first = *first_it; - result = UnorderedSet{first}.complementAtom(); - - ++first_it; - MDIUnordCollection second{first_it, _pieces.end()}; - for (const MultiDimInter& mdi : second) { - UnorderedSet c = UnorderedSet{mdi}.complementAtom(); - result = result.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 result; @@ -365,8 +361,9 @@ UnorderedSet UnorderedSet::cartesianProduct(const UnorderedSet& other) const std::size_t UnorderedSet::arity() const { - if (isEmpty()) + if (isEmpty()) { return 0; + } return _pieces.begin()->arity(); } @@ -407,13 +404,13 @@ UnorderedSet UnorderedSet::disjointCup(UnorderedSet&& other) && UnorderedSet UnorderedSet::offset(const MD_NAT& off) const { - MDIUnordCollection result; + UnorderedSet result; for (const MultiDimInter& mdi : _pieces) { - result.push_back(mdi.offset(off)); + result.pushBack(mdi.offset(off)); } - return UnorderedSet{std::move(result)}; + return result; } void UnorderedSet::compact() From 4322d03dce43612ffb3b956a3203ed0a1036b445 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Tue, 17 Mar 2026 10:41:49 -0300 Subject: [PATCH 16/66] Debugged Interval::operator!= --- sbg/interval.cpp | 8 ++++---- sbg/map.cpp | 3 +-- sbg/multidim_inter.cpp | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/sbg/interval.cpp b/sbg/interval.cpp index 14837806..a21393a7 100755 --- a/sbg/interval.cpp +++ b/sbg/interval.cpp @@ -93,18 +93,18 @@ bool operator==(const Interval& lhs, const Interval& rhs) bool operator!=(const Interval& lhs, const Interval& rhs) { if (lhs.begin() != rhs.begin()) { - return false; + return true; } if (lhs.step() != rhs.step()) { - return false; + return true; } if (lhs.end() != rhs.end()) { - return false; + return true; } - return true; + return false; } bool Interval::operator<(const Interval& other) const diff --git a/sbg/map.cpp b/sbg/map.cpp index beec9089..4da8a4fa 100755 --- a/sbg/map.cpp +++ b/sbg/map.cpp @@ -166,8 +166,7 @@ Set Map::lessImage(const Map& other) const } Set result = detail::MapDetail::lessImage(_law, other._law); - result = std::move(result).intersection(cap_dom); - return result; + return result.intersection(cap_dom); } Map Map::minAdj(const Map& other) const diff --git a/sbg/multidim_inter.cpp b/sbg/multidim_inter.cpp index 90e7d76b..4abc1af8 100755 --- a/sbg/multidim_inter.cpp +++ b/sbg/multidim_inter.cpp @@ -224,10 +224,10 @@ MaybeMDI MultiDimInter::compact(const MultiDimInter& other) const for (; j < arity(); ++j) { Interval jth_this = operator[](j); Interval jth_other = other[j]; - MaybeInterval jth_compact = jth_this.compact(jth_other); 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; From 3686ba83b725d3458c6dfc38e68c9923df3ce2b7 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Tue, 17 Mar 2026 10:50:03 -0300 Subject: [PATCH 17/66] Matching notation --- algorithms/matching/bfs_matching.cpp | 2 -- algorithms/matching/bfs_paths.cpp | 28 ++++++++++++++-------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/algorithms/matching/bfs_matching.cpp b/algorithms/matching/bfs_matching.cpp index 0b4c0b57..97716d1a 100644 --- a/algorithms/matching/bfs_matching.cpp +++ b/algorithms/matching/bfs_matching.cpp @@ -57,9 +57,7 @@ void BFSMatching::swapEdgesDirection(const Set& E) PWMap temp_mapB = mapB.restrict(E); mapB = mapD.restrict(E).combine(std::move(mapB)); - mapB.compact(); mapD = temp_mapB.restrict(E).combine(std::move(mapD)); - mapD.compact(); _dsbg = DirectedSBG{_dsbg.V(), _dsbg.Vmap(), mapB, mapD, _dsbg.Emap()}; } diff --git a/algorithms/matching/bfs_paths.cpp b/algorithms/matching/bfs_paths.cpp index 0942a54a..301f9c98 100644 --- a/algorithms/matching/bfs_paths.cpp +++ b/algorithms/matching/bfs_paths.cpp @@ -36,9 +36,9 @@ BFSPaths::BFSPaths() {} PWMap BFSPaths::calculate(const DirectedSBG& dsbg, const Set& endings) { - Set dsbgV = dsbg.V(); - PWMap dsbgB = dsbg.mapB(); - PWMap dsbgD = dsbg.mapD(); + Set V = dsbg.V(); + PWMap mapB = dsbg.mapB(); + PWMap mapD = dsbg.mapD(); PWMap Emap = dsbg.Emap(); // Successor map to unmatched vertices @@ -47,44 +47,44 @@ PWMap BFSPaths::calculate(const DirectedSBG& dsbg, const Set& endings) // A record of allowed edges to keep out cycle edges Set allowed_edges = dsbg.E(); // Ingoing edges to vertices that reach endings - Set ingoing = dsbgD.preImage(endings); + Set ingoing = mapD.preImage(endings); // A record of visited set-edges Set visitedE = SET_FACT.createSet(); do { // Calculate successor for ith vertices - PWMap ingoingB = dsbgB.restrict(ingoing); - PWMap ingoingD = dsbgD.restrict(ingoing); + PWMap ingoingB = mapB.restrict(ingoing); + PWMap ingoingD = mapD.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 Eith = mapD.equalImage(ith_smap.composition(mapB)); // Visited set-edges Set Erec = visitedE.intersection(Emap.image(Eith)); // Handle recursion if (!Erec.isEmpty()) { Set Eplus = Emap.preImage(Erec); - PWMap rec_smap = dsbgB.restrict(Eplus).minAdj(dsbgD.restrict(Eplus)); + PWMap rec_smap = mapB.restrict(Eplus).minAdj(mapD.restrict(Eplus)); Util::DEBUG_LOG << "rec_smap: " << rec_smap << "\n"; ith_smap = ith_smap.combine(rec_smap); } result = ith_smap.combine(result); - + // Take out other outgoing edges to avoid cycles - allowed_edges = allowed_edges.difference(dsbgB.preImage(result.domain())); - dsbgD = dsbgD.restrict(allowed_edges); - dsbgB = dsbgB.restrict(allowed_edges); + allowed_edges = allowed_edges.difference(mapB.preImage(result.domain())); + mapD = mapD.restrict(allowed_edges); + mapB = mapB.restrict(allowed_edges); // Edges that reach vertices with a successor - ingoing = dsbgD.preImage(result.domain()).intersection(allowed_edges); + ingoing = mapD.preImage(result.domain()).intersection(allowed_edges); visitedE = visitedE.cup(Emap.image(Eith)); Util::DEBUG_LOG << "Eith: " << Eith << "\n"; Util::DEBUG_LOG << "Erec: " << Erec << "\n"; Util::DEBUG_LOG << "visitedE: " << visitedE << "\n"; - Util::DEBUG_LOG << "res: " << result << "\n\n"; + Util::DEBUG_LOG << "result: " << result << "\n\n"; } while (!ingoing.isEmpty()); return result; From dccd18fd9718e419d9c77d1942a7deefcfb76c0c Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Tue, 17 Mar 2026 10:50:31 -0300 Subject: [PATCH 18/66] Updated tests --- test/TestRL1.test | 2 +- test/TestRL2.test | 2 +- test/TestRL3.test | 10 ++--- test/advection2D.test | 86 +++++++++++++++++++++---------------------- 4 files changed, 49 insertions(+), 51 deletions(-) diff --git a/test/TestRL1.test b/test/TestRL1.test index 8aa0cbde..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 diff --git a/test/TestRL2.test b/test/TestRL2.test index ceb97813..ee1c01c1 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 diff --git a/test/TestRL3.test b/test/TestRL3.test index 5bbea74a..3ce50716 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,11 +14,11 @@ 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; */ 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 ); From c95efdca93bedb1c5a7b35a7d2fca53a48124cb9 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Tue, 17 Mar 2026 10:52:38 -0300 Subject: [PATCH 19/66] Debugged SCC algorithm --- algorithms/scc/decreasing_edges_mrv.cpp | 81 +++++++++++-------------- algorithms/scc/decreasing_edges_mrv.hpp | 4 +- 2 files changed, 38 insertions(+), 47 deletions(-) diff --git a/algorithms/scc/decreasing_edges_mrv.cpp b/algorithms/scc/decreasing_edges_mrv.cpp index 28e88e34..f0afeb8a 100644 --- a/algorithms/scc/decreasing_edges_mrv.cpp +++ b/algorithms/scc/decreasing_edges_mrv.cpp @@ -49,58 +49,55 @@ Set LtEdgesMRV::decreasingRepresentative(const PWMap& rmap) const return result; } -Set LtEdgesMRV::edgesInPaths(const PWMap& smap) const -{ - PWMap mapB = _dsbg.mapB(); - PWMap mapD = _dsbg.mapD(); - - // Vertices that are successors of other vertices in a path - Set not_fixed = smap.domain().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 LtEdgesMRV::recursivePaths(const Set& ith_paths_edges, const Set& outgoing) +PWMap LtEdgesMRV::recursivePaths(const PWMap& rmap + , const PWMap& decreasing_smap) { PWMap result = PWMAP_FACT.createPWMap(); + // Calculate edges in paths described by _smap + const PWMap& mapB = _dsbg.mapB(); + const PWMap& mapD = _dsbg.mapD(); + Set ithP = decreasing_smap.composition(mapB).equalImage(mapD); + + // Check if there is a recursion PWMap Emap = _dsbg.Emap(); - Set ithSE = Emap.image(ith_paths_edges); - _visitedSE = std::move(_visitedSE).cup(ithSE); + Set ithSE = Emap.image(ithP); Set repeatedSE = _visitedSE.intersection(ithSE); if (!repeatedSE.isEmpty()) { - PWMap mapB = _dsbg.mapB(); - PWMap mapD = _dsbg.mapD(); - + Set P = _smap.composition(mapB).equalImage(mapD); Set ith_start = _smap.domain().difference(_smap.image()); - Set E = SET_FACT.createSet(); - Set ithE = mapB.preImage(ith_start).intersection(ith_paths_edges); + Set ithE = mapB.preImage(ith_start).intersection(P); if (!ithE.isEmpty()) { + Set E = SET_FACT.createSet(); bool exit_condition = true; do { - ithE = mapB.preImage(ith_start).intersection(ith_paths_edges); - E = std::move(E).disjointCup(std::move(ithE)); - ith_start = mapD.image(ithE); exit_condition = !repeatedSE.intersection(Emap.image(E)).isEmpty(); + ithE = mapB.preImage(ith_start).intersection(P); + ith_start = mapD.image(ithE); + E = std::move(E).disjointCup(std::move(ithE)); } while (!exit_condition); + // Take out edges that reach a MRV different from that of the recursion + PWMap ithP_rmap = rmap.composition(mapD.restrict(ithP)); + Set ithP_mrvs = ithP_rmap.image(); + E = E.intersection(ithP_rmap.preImage(ithP_mrvs)); + + Set E_plus = Emap.preImage(Emap.image(E)); + // In the presence of a cycle, if the minimum vertex belongs to the + // recursion, 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 vertices that already reach the desired MRV. + Set outgoing = mapB.preImage(rmap.preImage(ithP_mrvs)); + 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); } - - Set smap_edges = edgesInPaths(_smap); - Set adj = mapB.preImage(mapB.image(smap_edges)); - - Set E_plus = Emap.preImage(Emap.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.minAdj(mapD_plus); + _visitedSE = _visitedSE.difference(Emap.image(P)); + } else { + _visitedSE = std::move(_visitedSE).disjointCup(std::move(ithSE)); } return result; @@ -122,7 +119,6 @@ PWMap LtEdgesMRV::calculate(const DirectedSBG& dsbg) if (!_dsbg.V().isEmpty() && !_dsbg.E().isEmpty()) { PWMap old_rmap = PWMAP_FACT.createPWMap(); Set E = SET_FACT.createSet(); - Set paths_edges = SET_FACT.createSet(); do { old_rmap = rmap; @@ -134,10 +130,7 @@ PWMap LtEdgesMRV::calculate(const DirectedSBG& dsbg) _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 = std::move(smap_plus).combine(std::move(_smap)); + _smap = recursivePaths(rmap, decreasing_smap).combine(std::move(_smap)); // Calculate representatives map rmap = _smap.mapInf(); diff --git a/algorithms/scc/decreasing_edges_mrv.hpp b/algorithms/scc/decreasing_edges_mrv.hpp index 2f7f80e3..d6bf4836 100644 --- a/algorithms/scc/decreasing_edges_mrv.hpp +++ b/algorithms/scc/decreasing_edges_mrv.hpp @@ -64,12 +64,10 @@ class LtEdgesMRV : public MRVContext { */ Set decreasingRepresentative(const PWMap& rmap) const; - Set edgesInPaths(const PWMap& smap) const; - /* * @brief Calculates the MRV for recursive paths. */ - PWMap recursivePaths(const Set& paths_edges, const Set& outgoing); + PWMap recursivePaths(const PWMap& rmap, const PWMap& decreasing_smap); DirectedSBG _dsbg; PWMap _smap; From 766da8fbb6e16579890d0ece37e11d867b46da78 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Fri, 20 Mar 2026 10:40:55 -0300 Subject: [PATCH 20/66] Simplified SCC algorithm --- algorithms/scc/decreasing_edges_mrv.cpp | 78 ++++++++++++------------- algorithms/scc/decreasing_edges_mrv.hpp | 3 +- 2 files changed, 39 insertions(+), 42 deletions(-) diff --git a/algorithms/scc/decreasing_edges_mrv.cpp b/algorithms/scc/decreasing_edges_mrv.cpp index f0afeb8a..41719205 100644 --- a/algorithms/scc/decreasing_edges_mrv.cpp +++ b/algorithms/scc/decreasing_edges_mrv.cpp @@ -22,6 +22,8 @@ #include "sbg/set_fact.hpp" #include "util/logger.hpp" +#include + namespace SBG { namespace LIB { @@ -31,7 +33,7 @@ namespace LIB { //////////////////////////////////////////////////////////////////////////////// LtEdgesMRV::LtEdgesMRV() : _dsbg(), _smap(PWMAP_FACT.createPWMap()) - , _visitedSE(SET_FACT.createSet()) {} + , _visitedSE(SET_FACT.createSet()), _n(0) {} Set LtEdgesMRV::decreasingRepresentative(const PWMap& rmap) const { @@ -49,55 +51,48 @@ Set LtEdgesMRV::decreasingRepresentative(const PWMap& rmap) const return result; } -PWMap LtEdgesMRV::recursivePaths(const PWMap& rmap +PWMap LtEdgesMRV::repetitivePaths(const PWMap& rmap , const PWMap& decreasing_smap) { PWMap result = PWMAP_FACT.createPWMap(); - // Calculate edges in paths described by _smap + // Calculate edges in paths described by decreasing_smap const PWMap& mapB = _dsbg.mapB(); const PWMap& mapD = _dsbg.mapD(); - Set ithP = decreasing_smap.composition(mapB).equalImage(mapD); + Set Pj = decreasing_smap.composition(mapB).equalImage(mapD); - // Check if there is a recursion + // Check if there is a repetition PWMap Emap = _dsbg.Emap(); - Set ithSE = Emap.image(ithP); - Set repeatedSE = _visitedSE.intersection(ithSE); + Set repeatedSE = _visitedSE.intersection(Emap.image(Pj)); if (!repeatedSE.isEmpty()) { - Set P = _smap.composition(mapB).equalImage(mapD); - Set ith_start = _smap.domain().difference(_smap.image()); - Set ithE = mapB.preImage(ith_start).intersection(P); - if (!ithE.isEmpty()) { - Set E = SET_FACT.createSet(); - bool exit_condition = true; - do { - exit_condition = !repeatedSE.intersection(Emap.image(E)).isEmpty(); - ithE = mapB.preImage(ith_start).intersection(P); - ith_start = mapD.image(ithE); - E = std::move(E).disjointCup(std::move(ithE)); - } while (!exit_condition); - // Take out edges that reach a MRV different from that of the recursion - PWMap ithP_rmap = rmap.composition(mapD.restrict(ithP)); - Set ithP_mrvs = ithP_rmap.image(); - E = E.intersection(ithP_rmap.preImage(ithP_mrvs)); - - Set E_plus = Emap.preImage(Emap.image(E)); - // In the presence of a cycle, if the minimum vertex belongs to the - // recursion, 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 vertices that already reach the desired MRV. - Set outgoing = mapB.preImage(rmap.preImage(ithP_mrvs)); - 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); + 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); } - _visitedSE = _visitedSE.difference(Emap.image(P)); + PWMap rec_smap = _smap.restrict(V); + Set E_repetition = rec_smap.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(std::move(ithSE)); + _visitedSE = std::move(_visitedSE).disjointCup(std::move(Emap.image(Pj))); + ++_n; } return result; @@ -117,6 +112,7 @@ PWMap LtEdgesMRV::calculate(const DirectedSBG& dsbg) PWMap rmap = _smap; if (!_dsbg.V().isEmpty() && !_dsbg.E().isEmpty()) { + _n = 0; PWMap old_rmap = PWMAP_FACT.createPWMap(); Set E = SET_FACT.createSet(); do { @@ -129,8 +125,8 @@ PWMap LtEdgesMRV::calculate(const DirectedSBG& dsbg) PWMap decreasing_smap = decreasingB.minAdj(decreasingD); _smap = decreasing_smap.combine(std::move(_smap)); - // Recursive paths - _smap = recursivePaths(rmap, decreasing_smap).combine(std::move(_smap)); + // Repetitive paths + _smap = repetitivePaths(rmap, decreasing_smap).combine(std::move(_smap)); // Calculate representatives map rmap = _smap.mapInf(); diff --git a/algorithms/scc/decreasing_edges_mrv.hpp b/algorithms/scc/decreasing_edges_mrv.hpp index d6bf4836..c2fb9c81 100644 --- a/algorithms/scc/decreasing_edges_mrv.hpp +++ b/algorithms/scc/decreasing_edges_mrv.hpp @@ -67,11 +67,12 @@ class LtEdgesMRV : public MRVContext { /* * @brief Calculates the MRV for recursive paths. */ - PWMap recursivePaths(const PWMap& rmap, const PWMap& decreasing_smap); + PWMap repetitivePaths(const PWMap& rmap, const PWMap& decreasing_smap); DirectedSBG _dsbg; PWMap _smap; Set _visitedSE; + unsigned int _n; }; } // namespace LIB From 89bb1c33aedb4f3c8d7d4792c6376fa5147898e9 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Fri, 27 Mar 2026 14:47:19 -0300 Subject: [PATCH 21/66] Debugged OrderedSet::intersectionComplement --- sbg/map_detail.cpp | 6 ++-- sbg/ord_set.cpp | 71 +++++++++++++++++++++------------------------- sbg/ord_set.hpp | 2 +- sbg/set_fact.cpp | 2 -- 4 files changed, 36 insertions(+), 45 deletions(-) diff --git a/sbg/map_detail.cpp b/sbg/map_detail.cpp index 1628e463..04acf011 100755 --- a/sbg/map_detail.cpp +++ b/sbg/map_detail.cpp @@ -385,8 +385,8 @@ AtomicMapVector reduce(const MultiDimInter& mdi, const ExpressionImpl& expr return reduce(reducible_interval, reducible_expr); } -template -MapVector MapDetail::MDICollectionReduce(const SetMDIImpl& s +template +MapVector MapDetail::MDICollectionReduce(const CompactSetImpl& s , const ExpressionImpl& expr) { MapVector result; @@ -397,7 +397,7 @@ MapVector MapDetail::MDICollectionReduce(const SetMDIImpl& s MultiDimInter mdi_copy = mdi; ExpressionImpl expr_copy = expr; for (const AtomicMap& r : reduced) { - UnorderedSet domain; + CompactSetImpl domain; mdi_copy[k_reduce] = r.first; domain.pushBack(mdi_copy); expr_copy[k_reduce] = r.second; diff --git a/sbg/ord_set.cpp b/sbg/ord_set.cpp index c3f20ded..b303068b 100644 --- a/sbg/ord_set.cpp +++ b/sbg/ord_set.cpp @@ -31,14 +31,13 @@ namespace LIB { namespace detail { //////////////////////////////////////////////////////////////////////////////// -// Auxiliary functions +// Auxiliary functions --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /** * @brief Checks if the both set pieces overlap. */ -bool overlap(const MultiDimInter& mdi1 - , const MultiDimInter& mdi2) +bool overlap(const MultiDimInter& mdi1, const MultiDimInter& mdi2) { const auto max1 = mdi1.maxElem(); const auto min1 = mdi1.minElem(); @@ -430,29 +429,32 @@ OrderedSet OrderedSet::complementAtom() const return OrderedSet{std::move(result)}; } -std::size_t OrderedSet::intersectionComplement(const OrderedSet& local_complement - , const MultiDimInter& mdi) +void OrderedSet::intersectionComplement(const OrderedSet& + local_complement, const MultiDimInter& mdi) { // Special cases if (isEmpty()) { - return 0; + return; } // General case - std::size_t i = 0; + // 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; } - ++i; + ++it; } + result._pieces.insert(result.end(), std::make_move_iterator(_pieces.begin()) + , std::make_move_iterator(it)); NAT global_position = 0; - OrderedSet result; - for (auto it = _pieces.begin() + i; it != _pieces.end(); ++it) { + 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 @@ -472,8 +474,6 @@ std::size_t OrderedSet::intersectionComplement(const OrderedSet& local_complemen } } _pieces = std::move(result._pieces); - - return i; } OrderedSet OrderedSet::complement() const @@ -483,23 +483,16 @@ OrderedSet OrderedSet::complement() const } OrderedSet result = OrderedSet{_pieces.front()}.complementAtom(); - std::size_t i = 0; std::size_t j = 0; for (const MultiDimInter& mdi : _pieces) { if (j > 0) { OrderedSet c = OrderedSet{mdi}.complementAtom(); - i = result.intersectionComplement(c, mdi); + result.intersectionComplement(c, mdi); } ++j; } - // Calculate remnant - OrderedSet remnant; - for (j = 0; j < i; ++j) { - remnant.pushBack(result._pieces[j]); - } - - return std::move(remnant).disjointCup(std::move(result)); + return result; } OrderedSet OrderedSet::difference(const OrderedSet& other) const @@ -583,26 +576,26 @@ OrderedSet OrderedSet::disjointCup(OrderedSet&& other) && , std::make_move_iterator(other._pieces.end())); result.insert(result.end(), std::make_move_iterator(_pieces.begin()) , std::make_move_iterator(_pieces.end())); - } - - // 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; + } 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(), std::make_move_iterator(it1) - , std::make_move_iterator(end1)); - result.insert(result.end(), std::make_move_iterator(it2) - , std::make_move_iterator(end2)); return OrderedSet{std::move(result)}; } diff --git a/sbg/ord_set.hpp b/sbg/ord_set.hpp index f2792ac5..99e2c73f 100644 --- a/sbg/ord_set.hpp +++ b/sbg/ord_set.hpp @@ -103,7 +103,7 @@ class OrderedSet { * which represents the complement of an ordered set, and an ordered set * (other), which represents the complement of an atomic ordered set. */ - std::size_t intersectionComplement(const OrderedSet& other + void intersectionComplement(const OrderedSet& other , const MultiDimInter& mdi); /** diff --git a/sbg/set_fact.cpp b/sbg/set_fact.cpp index b11478cb..6aa07089 100644 --- a/sbg/set_fact.cpp +++ b/sbg/set_fact.cpp @@ -75,8 +75,6 @@ Set OrdSetFact::createSet(const FixedPointsInfo& info) return Set{SetKind::kOrdered, info}; } -//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// // Ordered Unidimensional Dense Set Factory ------------------------------------ //////////////////////////////////////////////////////////////////////////////// From 3c0c990978d579916d74a58eb33a395bd2fa3e29 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Fri, 27 Mar 2026 16:40:52 -0300 Subject: [PATCH 22/66] Optimized matching algorithm --- algorithms/matching/bfs_matching.cpp | 71 +++++++++---------------- algorithms/matching/bfs_matching.hpp | 14 +++-- algorithms/matching/bfs_paths.cpp | 63 +++++++++++++--------- algorithms/matching/bfs_paths.hpp | 2 +- algorithms/scc/decreasing_edges_mrv.cpp | 4 +- eval/visitors/set_impl_visitor.cpp | 10 ++-- 6 files changed, 75 insertions(+), 89 deletions(-) diff --git a/algorithms/matching/bfs_matching.cpp b/algorithms/matching/bfs_matching.cpp index 97716d1a..6eefce4a 100644 --- a/algorithms/matching/bfs_matching.cpp +++ b/algorithms/matching/bfs_matching.cpp @@ -48,7 +48,8 @@ bool BFSMatching::ExitCondition::isSatisfied() // Algorithm ------------------------------------------------------------------- BFSMatching::BFSMatching() : _M(SET_FACT.createSet()), _dsbg() - , _direction(Direction::kForward) {} + , _direction(Direction::kForward), _X(SET_FACT.createSet()) + , _Y(SET_FACT.createSet()) {} void BFSMatching::swapEdgesDirection(const Set& E) { @@ -62,6 +63,14 @@ void BFSMatching::swapEdgesDirection(const Set& E) _dsbg = DirectedSBG{_dsbg.V(), _dsbg.Vmap(), mapB, mapD, _dsbg.Emap()}; } +void BFSMatching::swapDirection(const Set& E) +{ + swapEdgesDirection(E); + Set temp_X = _X; + _X = _Y; + _Y = temp_X; +} + PWMap BFSMatching::partitionSubsetEdges() const { PWMap result = PWMAP_FACT.createPWMap(); @@ -90,25 +99,7 @@ PWMap BFSMatching::partitionSubsetEdges() const 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.domain().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); PWMap mapD = _dsbg.mapD().restrict(E); @@ -116,58 +107,43 @@ Set BFSMatching::directedStep(const Set& E, const Set& right_vertices) // 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 unmatched_forward_vertices - = forward_vertices.difference(matched_forward_vertices); + = _X.difference(matched_forward_vertices); // Detect paths leading to unmatched_forward_vertices 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(); // Forward direction - Set paths_edgesD = directedStep(E, right_vertices); + Set P = directedStep(E); // Backward direction - swapEdgesDirection(E); + swapDirection(E); _direction = Direction::kBackward; - Set paths_edgesB = directedStep(paths_edgesD, right_vertices); + 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; // 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(); + bool full_match = _Y.difference(matchedU).isEmpty(); bool found_paths = !augmenting_edges.isEmpty(); return ExitCondition{full_match, found_paths}; @@ -204,11 +180,12 @@ MatchData BFSMatching::calculate(const BipartiteSBG& bsbg) Util::Internal::TimeProfiler profiler{"Total matching exec time: "}; init(bsbg); - Set right_vertices = bsbg.Y(); + _X = bsbg.X(); + _Y = bsbg.Y(); ExitCondition exit_cond{false, false}; do { - exit_cond = step(right_vertices); + exit_cond = step(); } while (!exit_cond.isSatisfied()); _M.compact(); diff --git a/algorithms/matching/bfs_matching.hpp b/algorithms/matching/bfs_matching.hpp index 2b060c0d..ae84473e 100644 --- a/algorithms/matching/bfs_matching.hpp +++ b/algorithms/matching/bfs_matching.hpp @@ -94,7 +94,7 @@ class BFSMatching { * 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. @@ -103,7 +103,7 @@ class BFSMatching { * @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 @@ -111,21 +111,19 @@ class BFSMatching { */ 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; - DirectedSBG _dsbg; ///< Directed graph according to matching Set _M; ///< Matched edges Direction _direction; + Set _X; + Set _Y; }; } // namespace detail diff --git a/algorithms/matching/bfs_paths.cpp b/algorithms/matching/bfs_paths.cpp index 301f9c98..3189fe86 100644 --- a/algorithms/matching/bfs_paths.cpp +++ b/algorithms/matching/bfs_paths.cpp @@ -34,60 +34,71 @@ namespace detail { BFSPaths::BFSPaths() {} -PWMap BFSPaths::calculate(const DirectedSBG& dsbg, const Set& endings) +Set BFSPaths::calculate(const DirectedSBG& dsbg, const Set& endings) { Set V = dsbg.V(); PWMap mapB = dsbg.mapB(); + PWMap auxB = mapB; PWMap mapD = dsbg.mapD(); + PWMap auxD = mapD; PWMap Emap = dsbg.Emap(); // Successor map to unmatched vertices - PWMap result = PWMAP_FACT.createPWMap(endings); + PWMap smap = PWMAP_FACT.createPWMap(endings); // A record of allowed edges to keep out cycle edges - Set allowed_edges = dsbg.E(); + 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 = SET_FACT.createSet(); do { // Calculate successor for ith vertices - PWMap ingoingB = mapB.restrict(ingoing); - PWMap ingoingD = mapD.restrict(ingoing); + 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 = mapD.equalImage(ith_smap.composition(mapB)); + Set Ei = auxD.equalImage(ith_smap.composition(auxB)); // Visited set-edges - Set Erec = visitedE.intersection(Emap.image(Eith)); - // Handle recursion - if (!Erec.isEmpty()) { - Set Eplus = Emap.preImage(Erec); - PWMap rec_smap = mapB.restrict(Eplus).minAdj(mapD.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)); } - result = ith_smap.combine(result); + smap = ith_smap.combine(smap); // Take out other outgoing edges to avoid cycles - allowed_edges = allowed_edges.difference(mapB.preImage(result.domain())); - mapD = mapD.restrict(allowed_edges); - mapB = mapB.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 = mapD.preImage(result.domain()).intersection(allowed_edges); + ingoing = auxD.preImage(smap.domain()).intersection(E); - visitedE = visitedE.cup(Emap.image(Eith)); - - Util::DEBUG_LOG << "Eith: " << Eith << "\n"; - Util::DEBUG_LOG << "Erec: " << Erec << "\n"; - Util::DEBUG_LOG << "visitedE: " << visitedE << "\n"; - Util::DEBUG_LOG << "result: " << result << "\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 result; + // 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 diff --git a/algorithms/matching/bfs_paths.hpp b/algorithms/matching/bfs_paths.hpp index 5bd6e86c..cb008fc0 100644 --- a/algorithms/matching/bfs_paths.hpp +++ b/algorithms/matching/bfs_paths.hpp @@ -55,7 +55,7 @@ class BFSPaths : public PathsContext { * than once, replicating the same path for every element of the same * Set-Vertex. */ - PWMap calculate(const DirectedSBG& dsbg, const Set& endings); + Set calculate(const DirectedSBG& dsbg, const Set& endings); }; } // namespace detail diff --git a/algorithms/scc/decreasing_edges_mrv.cpp b/algorithms/scc/decreasing_edges_mrv.cpp index 41719205..78c99b78 100644 --- a/algorithms/scc/decreasing_edges_mrv.cpp +++ b/algorithms/scc/decreasing_edges_mrv.cpp @@ -71,8 +71,8 @@ PWMap LtEdgesMRV::repetitivePaths(const PWMap& rmap Vi = _smap.image(Vi); V = V.disjointCup(Vi); } - PWMap rec_smap = _smap.restrict(V); - Set E_repetition = rec_smap.composition(mapB).equalImage(mapD); + 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 diff --git a/eval/visitors/set_impl_visitor.cpp b/eval/visitors/set_impl_visitor.cpp index 809cb3ea..7a9526f9 100755 --- a/eval/visitors/set_impl_visitor.cpp +++ b/eval/visitors/set_impl_visitor.cpp @@ -57,7 +57,7 @@ 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)); } @@ -78,7 +78,7 @@ int SetImplExprVisitor::operator()(AST::MultiDimInter v) const 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)); } @@ -88,7 +88,7 @@ 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)); } @@ -106,7 +106,7 @@ 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)); } @@ -124,7 +124,7 @@ 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)); } From cbf6dfaeeb5858aa7ed5481ef9217b2b528a6a22 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Tue, 31 Mar 2026 09:40:11 -0300 Subject: [PATCH 23/66] Refined PWMap interfaces --- algorithms/matching/bfs_matching.cpp | 8 ++--- algorithms/misc/causalization_builders.cpp | 4 +-- algorithms/scc/minadj_mrv.cpp | 2 +- eval/visitors/expr_evaluator.cpp | 2 +- sbg/bipartite_sbg.cpp | 4 +-- sbg/directed_sbg.cpp | 4 +-- sbg/pw_map.cpp | 23 ++++-------- sbg/pw_map.hpp | 16 +++------ sbg/sbg.cpp | 4 +-- sbg/unord_pwmap.cpp | 41 +++++++++++----------- sbg/unord_pwmap.hpp | 24 +++++++++---- test/performance/unord_pwmap_bm.cpp | 14 ++++---- 12 files changed, 69 insertions(+), 77 deletions(-) diff --git a/algorithms/matching/bfs_matching.cpp b/algorithms/matching/bfs_matching.cpp index 6eefce4a..5e58393d 100644 --- a/algorithms/matching/bfs_matching.cpp +++ b/algorithms/matching/bfs_matching.cpp @@ -84,15 +84,13 @@ PWMap BFSMatching::partitionSubsetEdges() const Set domain_edges = Emap.preImage(min_elem_set); Expression matched_expr{MD_NAT{arity, j}}; - Map matched_map{_M.intersection(domain_edges), matched_expr}; + result.emplace(_M.intersection(domain_edges), matched_expr); ++j; + Expression free_expr{MD_NAT{arity, j}}; - Map free_map{free_edges.intersection(domain_edges), free_expr}; + result.emplace(free_edges.intersection(domain_edges), free_expr); ++j; - result.emplaceBack(matched_map); - result.emplaceBack(free_map); - set_edges = set_edges.difference(min_elem_set); } diff --git a/algorithms/misc/causalization_builders.cpp b/algorithms/misc/causalization_builders.cpp index 21ec0618..bceef6af 100644 --- a/algorithms/misc/causalization_builders.cpp +++ b/algorithms/misc/causalization_builders.cpp @@ -42,7 +42,7 @@ SBG::LIB::DirectedSBG buildSCCFromMatching(const SBG::LIB::MatchData& data) for (const SBG::LIB::Map& m : auxVmap) { SBG::LIB::Set domain = m.domain(); domain.compact(); - Vmap.pushBack(SBG::LIB::Map(domain, m.law())); + Vmap.emplace(domain, m.law()); } SBG::LIB::PWMap map1 = bsbg.map1(); @@ -94,7 +94,7 @@ SBG::LIB::DirectedSBG buildSortFromSCC(const SBG::LIB::SCCData& data) SBG::LIB::PWMap Emap = dsbg.Emap().restrict(Ediff); - return SBG::LIB::DirectedSBG {V, Vmap, mapB, mapD, Emap}; + return SBG::LIB::DirectedSBG{V, Vmap, mapB, mapD, Emap}; } } // namespace misc diff --git a/algorithms/scc/minadj_mrv.cpp b/algorithms/scc/minadj_mrv.cpp index 8e92884b..8eb11fc3 100644 --- a/algorithms/scc/minadj_mrv.cpp +++ b/algorithms/scc/minadj_mrv.cpp @@ -94,7 +94,7 @@ PWMap MinAdjMRV::calculate(const DirectedSBG& dsbg) for (; dmap.domain().intersection(Vc.intersection(VR)).isEmpty();) { Set domain = ith.difference(dmap.domain()); Expression expr(MD_NAT{arity, dist}); - dmap.emplaceBack(Map{domain, expr}); + dmap.emplace(domain, expr); // Update ith to vertices that have outgoing edges entering ith ith = mapB.image(mapD.preImage(ith)); ++dist; diff --git a/eval/visitors/expr_evaluator.cpp b/eval/visitors/expr_evaluator.cpp index aeddd4e4..347aa506 100755 --- a/eval/visitors/expr_evaluator.cpp +++ b/eval/visitors/expr_evaluator.cpp @@ -232,7 +232,7 @@ ExprBaseType ExprEvaluator::operator()(AST::PWLMap v) const LIB::PWMap result = LIB::PWMAP_FACT.createPWMap(); for (const AST::Expr& e : v.maps()) { - result.emplaceBack(eval(*this, e, "Map")); + result.insert(eval(*this, e, "Map")); } Util::ERROR_UNLESS(result.arity() == _eval_context.arity() diff --git a/sbg/bipartite_sbg.cpp b/sbg/bipartite_sbg.cpp index ca4444b1..243ee832 100644 --- a/sbg/bipartite_sbg.cpp +++ b/sbg/bipartite_sbg.cpp @@ -75,7 +75,7 @@ void BipartiteSBG::addSetVertex(const Set& X, const Set& Y) MD_NAT max = set_vertices.isEmpty() ? MD_NAT{arity, 0} : set_vertices.maxElem(); MD_NAT one_all_dims{arity, 1}; - _Vmap.emplaceBack(vertices, max + one_all_dims); + _Vmap.emplace(vertices, max + one_all_dims); _X = _X.cup(X); _Y = _Y.cup(Y); } @@ -99,7 +99,7 @@ void BipartiteSBG::addSetEdge(const PWMap& pw1, const PWMap& pw2) MD_NAT one_all_dims{arity, 1}; _map1 = std::move(_map1).concatenation(pw1); _map2 = std::move(_map2).concatenation(pw2); - _Emap.emplaceBack(edges, max + one_all_dims); + _Emap.emplace(edges, max + one_all_dims); } } else { Util::ERROR("Trying to add existing edges: ", edges1, " to SBG\n"); diff --git a/sbg/directed_sbg.cpp b/sbg/directed_sbg.cpp index 7861b50a..51a3497d 100644 --- a/sbg/directed_sbg.cpp +++ b/sbg/directed_sbg.cpp @@ -75,7 +75,7 @@ void DirectedSBG::addSetVertex(const Set& vertices) MD_NAT max = set_vertices.isEmpty() ? MD_NAT{arity, 0} : set_vertices.maxElem(); MD_NAT one_all_dims{arity, 1}; - _Vmap.emplaceBack(vertices, max + one_all_dims); + _Vmap.emplace(vertices, max + one_all_dims); } } @@ -96,7 +96,7 @@ void DirectedSBG::addSetEdge(const PWMap& pwB, const PWMap& pwD) MD_NAT one_all_dims{arity, 1}; _mapB = std::move(_mapB).concatenation(pwB); _mapD = std::move(_mapD).concatenation(pwD); - _Emap.emplaceBack(edges, max + one_all_dims); + _Emap.emplace(edges, max + one_all_dims); } } else { Util::ERROR("Trying to add existing edges: ", edgesB, " to SBG\n"); diff --git a/sbg/pw_map.cpp b/sbg/pw_map.cpp index 5dd9fbb8..b52cb8b8 100644 --- a/sbg/pw_map.cpp +++ b/sbg/pw_map.cpp @@ -132,11 +132,9 @@ PWMap::PWMap(const PWMapKind kind, Map m) : _impl() } } -PWMap::PWMap(const detail::PWMapImpl& impl) - : _impl(impl) {} +PWMap::PWMap(const detail::PWMapImpl& impl) : _impl(impl) {} -PWMap::PWMap(detail::PWMapImpl&& impl) - : _impl(std::move(impl)) {} +PWMap::PWMap(detail::PWMapImpl&& impl) : _impl(std::move(impl)) {} // Getters --------------------------------------------------------------------- @@ -152,14 +150,14 @@ PWMap::ConstIt PWMap::end() // Setters --------------------------------------------------------------------- -void PWMap::pushBack(const Map& m) +void PWMap::insert(const Map& m) { - std::visit([&m](auto& a) -> void { a.pushBack(m); } , _impl); + std::visit([&m](auto& a) -> void { a.insert(m); } , _impl); } -void PWMap::pushBack(Map&& m) +void PWMap::insert(Map&& m) { - std::visit([move_m = std::move(m)](auto& a) { a.pushBack(move_m); } + std::visit([move_m = std::move(m)](auto& a) { a.insert(move_m); } , _impl); } @@ -418,15 +416,6 @@ Set PWMap::lessImage(const PWMap& other) const , _impl, other._impl); } -PWMap PWMap::offsetDom(const MD_NAT& offset) const -{ - return std::visit([&offset](const auto& a) -> PWMap - { - return PWMap{a.offsetDom(offset)}; - } - , _impl); -} - void PWMap::compact() { std::visit([](auto& a) { a.compact(); }, _impl); diff --git a/sbg/pw_map.hpp b/sbg/pw_map.hpp index 3e6a99c4..e1a0f0b4 100644 --- a/sbg/pw_map.hpp +++ b/sbg/pw_map.hpp @@ -75,14 +75,14 @@ class PWMap { ConstIt end(); template - void emplaceBack(Args&&... args); + 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. */ - void pushBack(const Map& m); - void pushBack(Map&& m); + void insert(const Map& m); + void insert(Map&& m); /** * @brief Two pws are equal if they satisfy the function extensionality @@ -213,12 +213,6 @@ class PWMap { */ Set lessImage(const PWMap& other) const; - /** - * @brief Sum a constant value to every element in the domain of the pw. The - * law remains unchanged. - */ - PWMap offsetDom(const MD_NAT& offset) const; - /** * @brief Minimize internal representation cost. Heuristic guided. */ @@ -234,9 +228,9 @@ class PWMap { std::ostream& operator<<(std::ostream& out, const PWMap& pw); template -inline void PWMap::emplaceBack(Args&&... args) +inline void PWMap::emplace(Args&&... args) { - std::visit([&](auto& a) { a.emplaceBack(std::forward(args)...); } , _impl); + std::visit([&](auto& a) { a.emplace(std::forward(args)...); } , _impl); } } // namespace LIB diff --git a/sbg/sbg.cpp b/sbg/sbg.cpp index 3fdbaac7..0e792e91 100644 --- a/sbg/sbg.cpp +++ b/sbg/sbg.cpp @@ -73,7 +73,7 @@ void SBG::addSetVertex(const Set& vertices) MD_NAT max = set_vertices.isEmpty() ? MD_NAT{arity, 0} : set_vertices.maxElem(); MD_NAT one_all_dims{arity, 1}; - _Vmap.emplaceBack(vertices, max + one_all_dims); + _Vmap.emplace(vertices, max + one_all_dims); } } @@ -94,7 +94,7 @@ void SBG::addSetEdge(const PWMap& pw1, const PWMap& pw2) MD_NAT one_all_dims{arity, 1}; _map1 = std::move(_map1).concatenation(pw1); _map2 = std::move(_map2).concatenation(pw2); - _Emap.emplaceBack(edges, max + one_all_dims); + _Emap.emplace(edges, max + one_all_dims); } } else { Util::ERROR("Trying to add existing edges: ", edges1, " to SBG\n"); diff --git a/sbg/unord_pwmap.cpp b/sbg/unord_pwmap.cpp index 88e109d6..465238e1 100644 --- a/sbg/unord_pwmap.cpp +++ b/sbg/unord_pwmap.cpp @@ -45,7 +45,7 @@ class MapLess { // Constructors/Destructors ---------------------------------------------------- -UnordPWMap::UnordPWMap() {} +UnordPWMap::UnordPWMap() : _pieces() {} UnordPWMap::UnordPWMap(const Set& s) : _pieces() { if (!s.isEmpty()) { @@ -59,7 +59,10 @@ UnordPWMap::UnordPWMap(const Map& m) : _pieces() { } } -UnordPWMap::UnordPWMap(UnordPWMap::UnordMapCollection pieces) +UnordPWMap::UnordPWMap(const UnordPWMap::UnordMapCollection& pieces) + : _pieces(pieces) {} + +UnordPWMap::UnordPWMap(UnordPWMap::UnordMapCollection&& pieces) : _pieces(std::move(pieces)) {} // Getters --------------------------------------------------------------------- @@ -70,6 +73,20 @@ UnordPWMap::ConstIt UnordPWMap::end() const { return _pieces.end(); } // Setters --------------------------------------------------------------------- +void UnordPWMap::insert(const Map& m) +{ + if (!m.isEmpty()) { + _pieces.push_back(m); + } +} + +void UnordPWMap::insert(Map&& m) +{ + if (!m.isEmpty()) { + _pieces.push_back(std::move(m)); + } +} + void UnordPWMap::pushBack(const Map& m) { if (!m.isEmpty()) { @@ -463,22 +480,6 @@ Set UnordPWMap::lessImage(const UnordPWMap& other) const return min_in_pw1; } -UnordPWMap UnordPWMap::offsetDom(const MD_NAT& offset) const -{ - UnordPWMap result; - - for (const Map& m : _pieces) { - result._pieces.emplace_back(m.domain().offset(offset), m.law()); - } - - return result; -} - -bool operator<(const Map& m1, const Map& m2) -{ - return true; -} - void UnordPWMap::compact() { using MapSet = std::set; @@ -514,8 +515,8 @@ void UnordPWMap::compact() } } while (actual != prev); - for (const Map& mdi : actual) { - result.push_back(mdi); + for (const Map& m : actual) { + result.push_back(m); } } diff --git a/sbg/unord_pwmap.hpp b/sbg/unord_pwmap.hpp index 79084b94..08a0a0fd 100644 --- a/sbg/unord_pwmap.hpp +++ b/sbg/unord_pwmap.hpp @@ -48,15 +48,16 @@ class UnordPWMap { UnordPWMap(); UnordPWMap(const Set& s); UnordPWMap(const Map& m); - UnordPWMap(UnordMapCollection pieces); + UnordPWMap(const UnordMapCollection& pieces); + UnordPWMap(UnordMapCollection&& pieces); ConstIt begin() const; ConstIt end() const; template - void emplaceBack(Args&&... args); - void pushBack(const Map& m); - void pushBack(Map&& m); + void emplace(Args&&... args); + void insert(const Map& m); + void insert(Map&& m); bool operator==(const UnordPWMap& other) const; bool operator!=(const UnordPWMap& other) const; @@ -97,12 +98,13 @@ class UnordPWMap { Set equalImage(const UnordPWMap& other) const; Set lessImage(const UnordPWMap& other) const; - UnordPWMap offsetDom(const MD_NAT& offset) const; - void compact(); private: - UnordMapCollection _pieces; + template + void emplaceBack(Args&&... args); + void pushBack(const Map& m); + void pushBack(Map&& m); /** * @brief Calculates (if possible) compactly the result of mapInf.\n @@ -118,8 +120,16 @@ class UnordPWMap { * compose pw' with itself up to convergence. */ UnordPWMap mapInf(unsigned int n) const; + + UnordMapCollection _pieces; }; +template +inline void UnordPWMap::emplace(Args&&... args) +{ + _pieces.emplace_back(std::forward(args)...); +} + template inline void UnordPWMap::emplaceBack(Args&&... args) { diff --git a/test/performance/unord_pwmap_bm.cpp b/test/performance/unord_pwmap_bm.cpp index 4d8e3a03..caa34e43 100644 --- a/test/performance/unord_pwmap_bm.cpp +++ b/test/performance/unord_pwmap_bm.cpp @@ -67,7 +67,7 @@ PWMap denseDom(SBG::LIB::NAT map_sz) } Expression multidim_id{1, 0}; - pw.emplaceBack(domain, multidim_id); + pw.emplace(domain, multidim_id); } return pw; @@ -101,8 +101,8 @@ std::pair minAdjMaps(SBG::LIB::NAT map_sz) Expression multidim_id{2, 1, 0}; Expression minus_one{2, 1, RATIONAL{-1, 1}}; - pw1.emplaceBack(domain1, multidim_id); - pw2.emplaceBack(domain2, minus_one); + pw1.emplace(domain1, multidim_id); + pw2.emplace(domain2, minus_one); } return {pw1, pw2}; @@ -137,8 +137,8 @@ std::pair interlacedMaps(SBG::LIB::NAT map_sz) Expression multidim_id{2, 1, 0}; - pw1.emplaceBack(domain1, multidim_id); - pw2.emplaceBack(domain2, multidim_id); + pw1.emplace(domain1, multidim_id); + pw2.emplace(domain2, multidim_id); } return {pw1, pw2}; @@ -177,8 +177,8 @@ std::pair contiguousMaps(SBG::LIB::NAT map_sz) Expression multidim_id{2, 1, 0}; - pw1.emplaceBack(domain1, multidim_id); - pw2.emplaceBack(domain2, multidim_id); + pw1.emplace(domain1, multidim_id); + pw2.emplace(domain2, multidim_id); } return {pw1, pw2}; From cd372f5b8f1b8e4a069a9cf876a14cb2151026e4 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Tue, 31 Mar 2026 09:40:41 -0300 Subject: [PATCH 24/66] Added stand-alone set perimeter --- sbg/ord_set.cpp | 42 ++++++++++++++++++++------- sbg/ord_set.hpp | 12 ++++---- sbg/ord_unidim_dense_set.cpp | 25 +++++++++------- sbg/ord_unidim_dense_set.hpp | 12 ++++---- sbg/set.cpp | 5 ++++ sbg/set.hpp | 2 ++ sbg/set_perimeter.cpp | 51 +++++++++++++++++++++++++++++++++ sbg/set_perimeter.hpp | 55 ++++++++++++++++++++++++++++++++++++ sbg/unord_set.cpp | 22 +++++++++++++++ sbg/unord_set.hpp | 2 ++ 10 files changed, 198 insertions(+), 30 deletions(-) create mode 100755 sbg/set_perimeter.cpp create mode 100755 sbg/set_perimeter.hpp diff --git a/sbg/ord_set.cpp b/sbg/ord_set.cpp index b303068b..f36e74b3 100644 --- a/sbg/ord_set.cpp +++ b/sbg/ord_set.cpp @@ -82,10 +82,10 @@ OrderedSet::OrderedSet(const MultiDimInter& mdi) : _pieces() } } -OrderedSet::OrderedSet(const OrderedSet::MDIOrdCollection& pieces) +OrderedSet::OrderedSet(const OrderedSet::OrdMDICollection& pieces) : _pieces(pieces) {} -OrderedSet::OrderedSet(OrderedSet::MDIOrdCollection&& pieces) +OrderedSet::OrderedSet(OrderedSet::OrdMDICollection&& pieces) : _pieces(std::move(pieces)) {} OrderedSet::OrderedSet(const FixedPointsInfo& info) : _pieces() @@ -253,8 +253,8 @@ OrderedSet OrderedSet::intersectionEpilogue(const OrderedSet& lhs OrderedSet result; // General case - OrderedSet::MDIOrdCollection short_set = lhs._pieces; - OrderedSet::MDIOrdCollection long_set = rhs._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; @@ -352,14 +352,14 @@ OrderedSet OrderedSet::cup(OrderedSet&& other) && } if (maxElem() < other.minElem()) { - MDIOrdCollection result = std::move(_pieces); + 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()) { - MDIOrdCollection result = std::move(other._pieces); + 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)}; @@ -371,7 +371,7 @@ OrderedSet OrderedSet::cup(OrderedSet&& other) && OrderedSet OrderedSet::complementAtom() const { - MDIOrdCollection result; + OrdMDICollection result; MultiDimInter mdi = *_pieces.begin(); MultiDimInter dense_mdi; @@ -565,7 +565,7 @@ OrderedSet OrderedSet::disjointCup(OrderedSet&& other) && return std::move(*this); } - MDIOrdCollection result; + OrdMDICollection result; if (_pieces.back() < other._pieces.front()) { result.insert(result.end(), std::make_move_iterator(_pieces.begin()) , std::make_move_iterator(_pieces.end())); @@ -576,7 +576,7 @@ OrderedSet OrderedSet::disjointCup(OrderedSet&& other) && , std::make_move_iterator(other._pieces.end())); result.insert(result.end(), std::make_move_iterator(_pieces.begin()) , std::make_move_iterator(_pieces.end())); - } else{ + } else { // General case auto it1 = _pieces.begin(); auto end1 = _pieces.end(); @@ -611,9 +611,31 @@ OrderedSet OrderedSet::offset(const MD_NAT& off) const return result; } +SetPerimeter OrderedSet::perimeter() const +{ + MD_NAT min; + MD_NAT max; + + 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 SetPerimeter{min, max}; +} + void OrderedSet::compact() { - MDIOrdCollection result; + OrdMDICollection result; if (!isEmpty()) { std::set prev{_pieces.begin(), _pieces.end()}; diff --git a/sbg/ord_set.hpp b/sbg/ord_set.hpp index 99e2c73f..5d380bda 100644 --- a/sbg/ord_set.hpp +++ b/sbg/ord_set.hpp @@ -29,6 +29,7 @@ #include "sbg/interval.hpp" #include "sbg/multidim_inter.hpp" #include "sbg/natural.hpp" +#include "sbg/set_perimeter.hpp" #include #include @@ -46,15 +47,15 @@ namespace detail { class OrderedSet { public: - using MDIOrdCollection = std::vector; - using ConstIt = MDIOrdCollection::const_iterator; + using OrdMDICollection = std::vector; + using ConstIt = OrdMDICollection::const_iterator; OrderedSet(); OrderedSet(const MD_NAT& x); OrderedSet(const detail::Interval& i); OrderedSet(const detail::MultiDimInter& mdi); - OrderedSet(const MDIOrdCollection& pieces); - OrderedSet(MDIOrdCollection&& pieces); + OrderedSet(const OrdMDICollection& pieces); + OrderedSet(OrdMDICollection&& pieces); OrderedSet(const FixedPointsInfo& info); ConstIt begin() const; @@ -89,6 +90,7 @@ class OrderedSet { OrderedSet disjointCup(OrderedSet&& other) const &; OrderedSet disjointCup(OrderedSet&& other) &&; OrderedSet offset(const MD_NAT& off) const; + SetPerimeter perimeter() const; void compact(); private: @@ -111,7 +113,7 @@ class OrderedSet { */ OrderedSet complementAtom() const; - MDIOrdCollection _pieces; + OrdMDICollection _pieces; }; } // namespace detail diff --git a/sbg/ord_unidim_dense_set.cpp b/sbg/ord_unidim_dense_set.cpp index 0bf8e666..2de08726 100644 --- a/sbg/ord_unidim_dense_set.cpp +++ b/sbg/ord_unidim_dense_set.cpp @@ -37,8 +37,8 @@ Interval least(const Interval& lhs, const Interval& rhs) return lhs < rhs ? lhs : rhs; } -bool overlap(const OrdUnidimDenseSet::IntervalOrdCollection& lhs, - const OrdUnidimDenseSet::IntervalOrdCollection& rhs) +bool overlap(const OrdUnidimDenseSet::OrdIntervalCollection& lhs, + const OrdUnidimDenseSet::OrdIntervalCollection& rhs) { return lhs.back().end() >= rhs.front().begin() || rhs.back().end() >= lhs.front().begin(); @@ -49,10 +49,10 @@ Interval intersection(const Interval& lhs, const Interval& rhs) return lhs.intersection(rhs); } -OrdUnidimDenseSet::IntervalOrdCollection - compact(const OrdUnidimDenseSet::IntervalOrdCollection& c) +OrdUnidimDenseSet::OrdIntervalCollection + compact(const OrdUnidimDenseSet::OrdIntervalCollection& c) { - OrdUnidimDenseSet::IntervalOrdCollection result; + OrdUnidimDenseSet::OrdIntervalCollection result; if (c.empty()) { return result; @@ -98,11 +98,11 @@ OrdUnidimDenseSet::OrdUnidimDenseSet(const Interval& i) : _pieces() } OrdUnidimDenseSet::OrdUnidimDenseSet( - const OrdUnidimDenseSet::IntervalOrdCollection& pieces) + const OrdUnidimDenseSet::OrdIntervalCollection& pieces) : _pieces(pieces) {} OrdUnidimDenseSet::OrdUnidimDenseSet( - OrdUnidimDenseSet::IntervalOrdCollection&& pieces) + OrdUnidimDenseSet::OrdIntervalCollection&& pieces) : _pieces(std::move(pieces)) {} OrdUnidimDenseSet::OrdUnidimDenseSet(const FixedPointsInfo& info) @@ -303,7 +303,7 @@ OrdUnidimDenseSet OrdUnidimDenseSet::cup(OrdUnidimDenseSet&& other) && return OrdUnidimDenseSet{std::move(other._pieces)}; } - IntervalOrdCollection result; + OrdIntervalCollection result; if (!overlap(_pieces, other._pieces)) { return std::move(*this).disjointCup(std::move(other)); } @@ -411,7 +411,7 @@ OrdUnidimDenseSet OrdUnidimDenseSet::disjointCup(OrdUnidimDenseSet&& other) && } if (!overlap(_pieces, other._pieces)) { - IntervalOrdCollection result; + 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()) @@ -433,13 +433,18 @@ OrdUnidimDenseSet OrdUnidimDenseSet::offset(const MD_NAT& offset) const return result; } +SetPerimeter OrdUnidimDenseSet::perimeter() const +{ + return SetPerimeter{minElem(), maxElem()}; +} + void OrdUnidimDenseSet::compact() { if (isEmpty()) { return; } - IntervalOrdCollection result; + OrdIntervalCollection result; auto next_it = _pieces.begin(); ++next_it; Interval compacted = _pieces.front(); diff --git a/sbg/ord_unidim_dense_set.hpp b/sbg/ord_unidim_dense_set.hpp index da434b0f..94e42c1c 100644 --- a/sbg/ord_unidim_dense_set.hpp +++ b/sbg/ord_unidim_dense_set.hpp @@ -32,6 +32,7 @@ #include "sbg/interval.hpp" #include "sbg/multidim_inter.hpp" #include "sbg/natural.hpp" +#include "sbg/set_perimeter.hpp" #include #include @@ -49,14 +50,14 @@ namespace detail { class OrdUnidimDenseSet { public: - using IntervalOrdCollection = std::vector; - using ConstIt = IntervalOrdCollection::const_iterator; + using OrdIntervalCollection = std::vector; + using ConstIt = OrdIntervalCollection::const_iterator; OrdUnidimDenseSet(); OrdUnidimDenseSet(const NAT x); OrdUnidimDenseSet(const detail::Interval& i); - OrdUnidimDenseSet(const IntervalOrdCollection& pieces); - OrdUnidimDenseSet(IntervalOrdCollection&& pieces); + OrdUnidimDenseSet(const OrdIntervalCollection& pieces); + OrdUnidimDenseSet(OrdIntervalCollection&& pieces); OrdUnidimDenseSet(const FixedPointsInfo& info); ConstIt begin() const; @@ -91,6 +92,7 @@ class OrdUnidimDenseSet { OrdUnidimDenseSet disjointCup(OrdUnidimDenseSet&& other) const &; OrdUnidimDenseSet disjointCup(OrdUnidimDenseSet&& other) &&; OrdUnidimDenseSet offset(const MD_NAT& offset) const; + SetPerimeter perimeter() const; void compact(); private: @@ -114,7 +116,7 @@ class OrdUnidimDenseSet { , const OrdUnidimDenseSet& other) const; private: - IntervalOrdCollection _pieces; + OrdIntervalCollection _pieces; }; } // namespace detail diff --git a/sbg/set.cpp b/sbg/set.cpp index 9ec905d2..dc26e4bf 100644 --- a/sbg/set.cpp +++ b/sbg/set.cpp @@ -345,6 +345,11 @@ Set Set::offset(const MD_NAT& off) const , _impl); } +SetPerimeter Set::perimeter() const +{ + return std::visit([](const auto& a) { return a.perimeter(); }, _impl); +} + void Set::compact() { std::visit([](auto& a) { a.compact(); }, _impl); } } // namespace LIB diff --git a/sbg/set.hpp b/sbg/set.hpp index 1c2e3e0e..7c84ee9d 100644 --- a/sbg/set.hpp +++ b/sbg/set.hpp @@ -41,6 +41,7 @@ #include "sbg/ord_set.hpp" #include "sbg/ord_unidim_dense_set.hpp" #include "sbg/set.hpp" +#include "sbg/set_perimeter.hpp" #include "sbg/unord_set.hpp" #include @@ -108,6 +109,7 @@ class Set { Set disjointCup(Set&& other) const &; Set disjointCup(Set&& other) &&; Set offset(const MD_NAT& off) const; + SetPerimeter perimeter() const; void compact(); private: diff --git a/sbg/set_perimeter.cpp b/sbg/set_perimeter.cpp new file mode 100755 index 00000000..d8df3fb7 --- /dev/null +++ b/sbg/set_perimeter.cpp @@ -0,0 +1,51 @@ +/******************************************************************************* + + 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_perimeter.hpp" + +namespace SBG { + +namespace LIB { + +//////////////////////////////////////////////////////////////////////////////// +// Set perimeter --------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +SetPerimeter::SetPerimeter(const MD_NAT& min, const MD_NAT& max) + : _min(min), _max(max) {} + +const MD_NAT& SetPerimeter::min() const { return _min; } + +const MD_NAT& SetPerimeter::max() const { return _max; } + +bool SetPerimeter::overlap(const SetPerimeter& other) const +{ + 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 + +} // namespace SBG diff --git a/sbg/set_perimeter.hpp b/sbg/set_perimeter.hpp new file mode 100755 index 00000000..75aadf29 --- /dev/null +++ b/sbg/set_perimeter.hpp @@ -0,0 +1,55 @@ +/** @file set_perimeter.pp + + @brief Set Perimeter + + The set perimeter is the smallest dense MultiDimInter that contains all of the + elements of the set. 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_SET_PERIMETER_HPP_ +#define SBGRAPH_SBG_SET_PERIMETER_HPP_ + +#include "sbg/natural.hpp" + +namespace SBG { + +namespace LIB { + +class SetPerimeter { +public: + SetPerimeter(const MD_NAT& min, const MD_NAT& max); + + const MD_NAT& min() const; + const MD_NAT& max() const; + + bool overlap(const SetPerimeter& other) const; + +private: + MD_NAT _min; + MD_NAT _max; +}; + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_SBG_SET_PERIMETER_HPP_ diff --git a/sbg/unord_set.cpp b/sbg/unord_set.cpp index d10cabe1..8a470fbd 100644 --- a/sbg/unord_set.cpp +++ b/sbg/unord_set.cpp @@ -413,6 +413,28 @@ UnorderedSet UnorderedSet::offset(const MD_NAT& off) const return result; } +SetPerimeter UnorderedSet::perimeter() const +{ + MD_NAT min; + MD_NAT max; + + 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 SetPerimeter{min, max}; +} + void UnorderedSet::compact() { MDIUnordCollection result; diff --git a/sbg/unord_set.hpp b/sbg/unord_set.hpp index 593dadc1..5a5353e0 100644 --- a/sbg/unord_set.hpp +++ b/sbg/unord_set.hpp @@ -29,6 +29,7 @@ #include "sbg/interval.hpp" #include "sbg/multidim_inter.hpp" #include "sbg/natural.hpp" +#include "sbg/set_perimeter.hpp" #include #include @@ -89,6 +90,7 @@ class UnorderedSet { UnorderedSet disjointCup(UnorderedSet&& other) const &; UnorderedSet disjointCup(UnorderedSet&& other) &&; UnorderedSet offset(const MD_NAT& off) const; + SetPerimeter perimeter() const; void compact(); private: From 2e58221f6e6ea3a172e857474b80e3f333f5fca2 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Tue, 31 Mar 2026 09:41:07 -0300 Subject: [PATCH 25/66] Redefined OrdPWMap --- sbg/CMakeLists.txt | 5 +- sbg/map_entry.cpp | 100 +---- sbg/map_entry.hpp | 36 +- sbg/ord_pwmap.cpp | 1033 +++++++++++++++++++------------------------- sbg/ord_pwmap.hpp | 232 ++++------ 5 files changed, 588 insertions(+), 818 deletions(-) diff --git a/sbg/CMakeLists.txt b/sbg/CMakeLists.txt index be74246b..d6708828 100644 --- a/sbg/CMakeLists.txt +++ b/sbg/CMakeLists.txt @@ -15,8 +15,10 @@ target_sources( linear_expr.cpp map.cpp map_detail.cpp + map_entry.cpp multidim_inter.cpp natural.cpp + ord_pwmap.cpp ord_set.cpp ord_unidim_dense_set.cpp pw_map.cpp @@ -25,11 +27,10 @@ target_sources( sbg.cpp set.cpp set_fact.cpp + set_perimeter.cpp unord_pwmap.cpp unord_set.cpp #dom_ord_pwmap.cpp - #map_entry.cpp - #ord_pwmap.cpp ) add_custom_target(sbg-doc diff --git a/sbg/map_entry.cpp b/sbg/map_entry.cpp index 5e51f2f0..57a79f48 100755 --- a/sbg/map_entry.cpp +++ b/sbg/map_entry.cpp @@ -23,101 +23,33 @@ 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 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; -} +MapEntry::MapEntry(Map&& m) + : _map(std::move(m)), _perimeter(m.domain().perimeter()) {} -void emplaceBack(OrdMapCollection& ord_pw, const MapEntry& entry) -{ - if (!entry.first.isEmpty()) { - ord_pw.emplace_back(entry); - } -} +const Map& MapEntry::map() const { return _map; } -void emplaceBack(OrdMapCollection& ord_pw, const Map& m) -{ - if (!m.isEmpty()) { - ord_pw.emplace_back(createMapEntry(m)); - } -} +const SetPerimeter& MapEntry::perimeter() const { return _perimeter; } -void emplaceHint(OrdMapCollection& ord_pw, const Map& m, NAT hint) +bool MapEntry::operator==(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); - } + return _map == other._map; } -void advanceHint(OrdMapCollection& ord_pw, const MD_NAT crit, NAT& hint) +bool MapEntry::operator<(const MapEntry& other) const { - 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 _perimeter.min() < other._perimeter.min(); } - -} // namespace Internal + +} // namespace detail } // namespace LIB diff --git a/sbg/map_entry.hpp b/sbg/map_entry.hpp index f63433a3..5de6ed2f 100755 --- a/sbg/map_entry.hpp +++ b/sbg/map_entry.hpp @@ -23,34 +23,38 @@ ******************************************************************************/ -#ifndef SBG_MAP_ENTRY_HPP -#define SBG_MAP_ENTRY_HPP +#ifndef SBGRAPH_SBG_MAP_ENTRY_HPP_ +#define SBGRAPH_SBG_MAP_ENTRY_HPP_ #include "sbg/map.hpp" +#include "sbg/set_perimeter.hpp" namespace SBG { namespace LIB { -namespace Internal { +namespace detail { -using SetPerimeter = std::pair; -using MapEntry = std::pair; -using OrdMapCollection = std::vector; +class MapEntry { +public: + MapEntry(const Map& m); + MapEntry(Map&& m); -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); + const Map& map() const; + const SetPerimeter& perimeter() const; -} // namespace Internal + bool operator==(const MapEntry& other) const; + bool operator<(const MapEntry& other) const; + +private: + Map _map; + SetPerimeter _perimeter; +}; + +} // namespace detail } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_MAP_ENTRY_HPP_ diff --git a/sbg/ord_pwmap.cpp b/sbg/ord_pwmap.cpp index 4aa766e0..c0a0c4c0 100644 --- a/sbg/ord_pwmap.cpp +++ b/sbg/ord_pwmap.cpp @@ -17,103 +17,156 @@ ******************************************************************************/ -#include - -#include "sbg/map_entry.hpp" +#include "sbg/set_fact.hpp" #include "sbg/ord_pwmap.hpp" +#include +#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 ----------------------------------- +// Auxliary 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(); + } +}; + +// Constructors/Destructors ---------------------------------------------------- -OrdPWMap::OrdPWMap() : pieces_() {} -OrdPWMap::OrdPWMap(const Set& s) : pieces_() { +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 OrdPWMap::OrdMapCollection& pieces) + : _pieces(pieces) {} -OrdPWMap::Iterator::Iterator(OrdMapCollection::const_iterator it) - : it_(it) {} +OrdPWMap::OrdPWMap(OrdPWMap::OrdMapCollection&& pieces) + : _pieces(std::move(pieces)) {} -void OrdPWMap::Iterator::operator++() +// Getters --------------------------------------------------------------------- + +OrdPWMap::ConstIt OrdPWMap::begin() const { return _pieces.begin(); } + +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().perimeter().min() < entry.perimeter().min()) { + _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; - } - - OrdMapCollection short_pw = pieces_; - OrdMapCollection long_pw = othr.pieces_; - if (othr.pieces_.size() < pieces_.size()) { - short_pw = othr.pieces_; - long_pw = pieces_; +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; + } + } + + return hint; +} + +// Traverse -------------------------------------------------------------------- + +template +CoreOperation OrdPWMap::traverse(const OrdPWMap& other, CoreOperation core_op) + const +{ + OrdMapCollection short_pw = _pieces; + OrdMapCollection long_pw = other._pieces; + if (other._pieces.size() < _pieces.size()) { + short_pw = other._pieces; + long_pw = _pieces; } // Indexes list corresponding to remaining maps in short_pw @@ -125,39 +178,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 SetPerimeter& 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 SetPerimeter& 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 +215,269 @@ bool OrdPWMap::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 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 PWMapStrategy& other) const +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; + } + + 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 = SET_FACT.createSet(); + + 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); - } + + 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); - } + SetPerimeter subdom_perimeter = subdom.perimeter(); + const MD_NAT subdom_max_perimeter = subdom_perimeter.max(); + for (const MapEntry& entry : _pieces) { + const SetPerimeter& 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 = SET_FACT.createSet(); - 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(); - 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 +{ + OrdMapCollection result; - for (const MapEntry& mpe : pieces_){ - const Map& inv = mpe.first.minInv(); - if(!inv.isEmpty()) - Internal::emplaceBack(res, inv); + for (const MapEntry& entry : _pieces) { + Map m = entry.map(); + result.emplace_back(Map{m.image(), m.law().inverse()}); } - - std::sort(res.begin(),res.end(), operator<); - return std::make_unique(std::move(res)); + std::sort(result.begin(), result.end()); + return OrdPWMap{std::move(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); + SetPerimeter img_perimeter = img.perimeter(); + result.advanceHint(global_pos, other_entry); + MD_NAT img_max_perimeter = img_perimeter.max(); + + for (const MapEntry& entry : _pieces) { + const SetPerimeter& 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(); - 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 +485,253 @@ 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_); - } - - 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)); - } - - 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; - } - } + return OrdPWMap{*this}.concatenation(other); +} - res.insert(res.end(), it1, end1); - res.insert(res.end(), it2, end2); +OrdPWMap OrdPWMap::concatenation(const OrdPWMap& other) && +{ + return std::move(*this).concatenation(OrdPWMap{other}); +} - return std::make_unique(std::move(res)); +OrdPWMap OrdPWMap::concatenation(OrdPWMap&& other) const & +{ + return OrdPWMap{*this}.concatenation(std::move(other)); } -PWMapStratPtr OrdPWMap::combine(const PWMapStrategy& other) const +OrdPWMap OrdPWMap::concatenation(OrdPWMap&& other) && { - OrdPWMapCRef othr = static_cast(other); - if (isEmpty()) { - return std::make_unique(othr.pieces_); + // Special cases + if (isEmpty()) { + return std::move(other); } if (other.isEmpty()) { - return std::make_unique(pieces_); - } - - if (pieces_ == othr.pieces_) { - return std::make_unique(pieces_); + return std::move(*this); } - Set exclusive_other = other.dom().difference(dom()); - - return 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); + 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 OrdPWMap{std::move(result)}; } -PWMapStratPtr OrdPWMap::minMap(const PWMapStrategy& other) const +OrdPWMap OrdPWMap::combine(const OrdPWMap& 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 OrdPWMap{*this}.combine(other); } -PWMapStratPtr OrdPWMap::minAdjMap(const PWMapStrategy& other) const +OrdPWMap OrdPWMap::combine(const OrdPWMap& other) && { - 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)); + return std::move(*this).combine(OrdPWMap{other}); } -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)); - } - } - } +OrdPWMap OrdPWMap::combine(OrdPWMap&& other) const & +{ + return OrdPWMap{*this}.combine(std::move(other)); } -PWMapStratPtr OrdPWMap::firstInv(const Set& subdom) const +OrdPWMap OrdPWMap::combine(OrdPWMap&& other) && { - OrdMapCollection res; - if (isEmpty() || subdom.isEmpty()) { - return std::make_unique(res); + if (isEmpty()) { + return std::move(other); } - 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; + if (other.isEmpty()) { + return std::move(*this); + } - - 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; + if (_pieces == other._pieces) { + return std::move(*this); } - std::sort(res.begin(), res.end(), operator<); - return std::make_unique(std::move(res)); + Set exclusive_other = other.domain().difference(domain()); + return std::move(*this).concatenation(other.restrict(exclusive_other)); } -PWMapStratPtr OrdPWMap::firstInv() const { return firstInv(dom()); } +OrdPWMap OrdPWMap::reduce() const +{ + OrdPWMap result; -PWMapStratPtr OrdPWMap::filterMap(bool (*f)(const Map& )) const -{ - OrdMapCollection res; - for (const MapEntry& mpe : pieces_) { - if (f(mpe.first)) { - Internal::emplaceBack(res, mpe); + for (const MapEntry& entry : _pieces) { + std::vector reduced = entry.map().reduce(); + for(Map& reduced_map : reduced) { + result.pushBack(std::move(reduced_map)); } } - - return std::make_unique(std::move(res)); -} -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)); - } - } -} - -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)); + return result; } -void OrdPWMap::processMapsOrd( - const PWMapStrategy& other, - Set& set_in, - Set& set_out, - OrdMapCollection& ord_map, - ProcessFunc process, - bool order_mts -) const +OrdPWMap OrdPWMap::min(const OrdPWMap& other) const { - OrdPWMapCRef othr = static_cast(other); - - int sz = pieces_.size(); - int othr_sz = othr.pieces_.size(); - ord_map.reserve(2*(sz + othr_sz)); - - const OrdPWMap *short_pw = this; - const OrdPWMap *long_pw = &othr; - if (!order_mts && othr.pieces_.size() < pieces_.size()) { - short_pw = &othr; - long_pw = this; - } - - 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 (isEmpty() || other.isEmpty()) { + return OrdPWMap{}; } - 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; - - // Process overlapping perimeters - if (doInt(s_sp, long_sp)) { - (this->*process)(s_m, long_map, set_in, set_out, ord_map, global_pos); + 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()) { + 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.pushBack(std::move(min_adj)); + _visited = std::move(_visited).disjointCup(std::move(min_adj_domain)); } - - ++si_prev; - ++si_curr; } - if (indexes.empty()) { - break; - } + return true; } -} - -Set OrdPWMap::sharedImage() const -{ - Set not_present = dom().difference(firstInv()->image()); - Set res = preImage(image(not_present)); + OrdPWMap result() const { return _result; } - return res; -} +private: + OrdPWMap _result; + Set _visited = SET_FACT.createSet(); +}; -PWMapStratPtr OrdPWMap::offsetDom(const MD_NAT& off) const +OrdPWMap OrdPWMap::minAdj(const OrdPWMap& other) const { - OrdMapCollection res; - - for (const MapEntry& mpe : pieces_) { - Map map(mpe.first.dom().offset(off), mpe.first.exp()); - if(!map.isEmpty()) - Internal::emplaceBack(res, map); + if (isEmpty() || other.isEmpty()) { + return OrdPWMap{}; } - return std::make_unique(std::move(res)); + return traverse(other, MinAdjCore{}).result(); } -PWMapStratPtr OrdPWMap::offsetDom(const PWMapStrategy& off) const +Set OrdPWMap::sharedImage() 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; + Set repeated_image = SET_FACT.createSet(); + Set visited = SET_FACT.createSet(); + 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)); } - - if (o_max_per < m_min_per) - break; + visited = std::move(visited).cup(m_image); } - std::sort(res.begin(),res.end(), operator<); - - return std::make_unique(std::move(res)); + return preImage(repeated_image); } -PWMapStratPtr OrdPWMap::offsetImage(const MD_NAT& off) const -{ - OrdMapCollection res; - - 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); +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)); + } } - Internal::emplaceBack(res, Map(mpe.first.dom(), res_e)); + return true; } - return std::make_unique(std::move(res)); -} + Set result() const { return _result; } + +private: + Set _result = SET_FACT.createSet(); +}; -PWMapStratPtr OrdPWMap::offsetImage(const Exp& off) const +Set OrdPWMap::equalImage(const OrdPWMap& other) const { - OrdMapCollection res; + if (isEmpty() || other.isEmpty()) { + return SET_FACT.createSet(); + } - for (const MapEntry& mpe : pieces_) - Internal::emplaceBack(res, Map(mpe.first.dom(), off + mpe.first.exp())); + if (_pieces == other._pieces) { + return domain(); + } - return std::make_unique(std::move(res)); + return traverse(other, EqualImageCore{}).result(); } -PWMapStratPtr OrdPWMap::compact() const -{ - OrdMapCollection res; - if (dom().isEmpty()) { - return std::make_unique(res); +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::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); + Set result() const { return _result; } - 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()); +private: + Set _result = SET_FACT.createSet(); +}; - 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(); +Set OrdPWMap::lessImage(const OrdPWMap& other) const +{ + if (isEmpty() || other.isEmpty()) { + return SET_FACT.createSet(); + } + + if (_pieces == other._pieces) { + return domain(); } - return std::make_unique(std::move(res)); + return traverse(other, LessImageCore{}).result(); +} + +// TODO +void OrdPWMap::compact() +{ } +} // namespace detail + } // namespace LIB } // namespace SBG; diff --git a/sbg/ord_pwmap.hpp b/sbg/ord_pwmap.hpp index 78b46308..c09f830b 100644 --- a/sbg/ord_pwmap.hpp +++ b/sbg/ord_pwmap.hpp @@ -21,183 +21,143 @@ ******************************************************************************/ -#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 +#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 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; + void compact(); - Set equalImage(const PWMapStrategy& other) const override; - Set lessImage(const PWMapStrategy& other) const override; - Set sharedImage() const override; +private: + template + void emplaceBack(Args&&... args); + void pushBack(const Map& entry); + void pushBack(Map&& entry); + void pushBack(const MapEntry& entry); + void pushBack(MapEntry&& entry); - 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; + void insertHint(std::size_t hint, const Map& m); + void insertHint(std::size_t hint, Map&& m); - 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. + * @brief Advances the hint to point the next element that has jth_entry as + * its minimum in its perimeter. */ - 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; + std::size_t advanceHint(std::size_t hint, const MapEntry& jth_entry); /** - * @brief Calculates the lessImage core, which contains the entire main process of the function. - */ - void processLessImage( - const Map& m1, - const Map& m2, - Set& set_in, - Set& set_out, - OrdMapCollection& ord_pwmap, - NAT& global_pos) const; - - /** - * @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; }; -typedef const OrdPWMap& OrdPWMapCRef; -typedef OrdPWMap& OrdPWMapRef; -typedef std::unique_ptr OrdPWMapPtr; +template +inline void OrdPWMap::emplace(Args&&... args) +{ + _pieces.emplace(std::forward(args)...); +} + +template +inline void OrdPWMap::emplaceBack(Args&&... args) +{ + _pieces.emplace_back(std::forward(args)...); +} + +} // namespace detail } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_ORD_PWMAP_HPP_ From de7bbd767e681bcc8fa4ef21fb85a41b9675fc5e Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Tue, 31 Mar 2026 14:34:55 -0300 Subject: [PATCH 26/66] Added Overload pattern to utils --- eval/visitors/func_evaluator.cpp | 67 ++++++++++++++++---------------- eval/visitors/func_evaluator.hpp | 20 ---------- sbg/map_detail.cpp | 8 ++-- sbg/map_detail.hpp | 11 +----- util/defs.hpp | 20 ++++++++-- 5 files changed, 56 insertions(+), 70 deletions(-) diff --git a/eval/visitors/func_evaluator.cpp b/eval/visitors/func_evaluator.cpp index a2f5d09a..7db3c59b 100755 --- a/eval/visitors/func_evaluator.cpp +++ b/eval/visitors/func_evaluator.cpp @@ -35,6 +35,7 @@ #include "sbg/set.hpp" #include "sbg/pw_map.hpp" #include "util/debug.hpp" +#include "util/defs.hpp" namespace SBG { @@ -130,7 +131,7 @@ ExprBaseType BuiltInOperators::oppositeEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "oppositeEvaluator: wrong number of arguments\n"); - auto opposite_evaluator = Overload { + auto opposite_evaluator = Util::Overload { [](LIB::NAT a) { return ExprBaseType{LIB::RATIONAL{static_cast(a), -1}}; @@ -151,7 +152,7 @@ ExprBaseType BuiltInOperators::cardinalEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "cardinalEvaluator: wrong number of arguments\n"); - const auto cardinal_evaluator = Overload { + const auto cardinal_evaluator = Util::Overload { [](LIB::Set a) { return (LIB::NAT) a.cardinal(); }, [](auto a) { Util::ERROR("cardinalEvaluator: wrong argument ", a, " for #\n"); @@ -166,7 +167,7 @@ ExprBaseType BuiltInOperators::complementEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "complementEvaluator: wrong number of arguments\n"); - const auto complement_evaluator = Overload { + const auto complement_evaluator = Util::Overload { [](LIB::Set a) { return ExprBaseType{a.complement()}; }, [](auto a) { Util::ERROR("complementEvaluator: wrong argument ", a @@ -182,7 +183,7 @@ ExprBaseType BuiltInOperators::addEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "addEvaluator: wrong number of arguments\n"); - const auto add_evaluator = Overload { + 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}; }, @@ -209,7 +210,7 @@ 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}}; @@ -240,7 +241,7 @@ ExprBaseType BuiltInOperators::multEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "multEvaluator: wrong number of arguments\n"); - const auto mult_evaluator = Overload { + const auto mult_evaluator = Util::Overload { [](LIB::NAT a, LIB::NAT b) { return ExprBaseType{LIB::RATIONAL{static_cast(a*b)}}; @@ -268,7 +269,7 @@ 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::Set a, LIB::Set b) { return a == b; }, @@ -289,7 +290,7 @@ 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; }, [](auto a, auto b) { @@ -306,7 +307,7 @@ ExprBaseType BuiltInOperators::capEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "capEvaluator: wrong number of arguments\n"); - const auto cap_evaluator = Overload{ + 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 @@ -322,7 +323,7 @@ ExprBaseType BuiltInOperators::cupEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "cupEvaluator: wrong number of arguments\n"); - const auto cup_evaluator = Overload{ + 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 @@ -338,7 +339,7 @@ ExprBaseType BuiltInOperators::diffEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "diffEvaluator: wrong number of arguments\n"); - const auto diff_evaluator = Overload{ + 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 @@ -442,7 +443,7 @@ ExprBaseType BuiltInFunctions::emptyEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "emptyEvaluator: wrong number of arguments\n"); - const auto empty_evaluator = Overload { + const auto empty_evaluator = Util::Overload { [](LIB::Set a) { return a.isEmpty(); }, [](auto a) { Util::ERROR("emptyEvaluator: wrong argument ", a, " for isEmpty\n"); @@ -457,7 +458,7 @@ ExprBaseType BuiltInFunctions::minEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "minEvaluator: wrong number of arguments\n"); - const auto min_evaluator = Overload { + const auto min_evaluator = Util::Overload { [](LIB::Set a) { return a.minElem(); }, [](auto a) { Util::ERROR("minEvaluator: wrong argument ", a, " for minElem\n"); @@ -472,7 +473,7 @@ ExprBaseType BuiltInFunctions::maxEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "maxEvaluator: wrong number of arguments\n"); - const auto max_evaluator = Overload { + const auto max_evaluator = Util::Overload { [](LIB::Set a) { return a.maxElem(); }, [](auto a) { Util::ERROR("maxEvaluator: wrong argument ", a, " for maxElem\n"); @@ -487,7 +488,7 @@ ExprBaseType BuiltInFunctions::restrictEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "restrictEvaluator: wrong number of arguments\n"); - const auto restrict_evaluator = Overload { + 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 @@ -503,7 +504,7 @@ ExprBaseType BuiltInFunctions::composeEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "composeEvaluator: wrong number of arguments\n"); - const auto compose_evaluator = Overload { + const auto compose_evaluator = Util::Overload { [](LIB::Expression a, LIB::Expression b) { return ExprBaseType{a.composition(b)}; @@ -524,7 +525,7 @@ ExprBaseType BuiltInFunctions::inverseEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "inverseEvaluator: wrong number of arguments\n"); - const auto inverse_evaluator = Overload { + const auto inverse_evaluator = Util::Overload { [](LIB::Expression a) { return ExprBaseType{a.inverse()}; }, [](LIB::PWMap a) { return ExprBaseType{a.inverse()}; }, [](auto a) { @@ -538,7 +539,7 @@ ExprBaseType BuiltInFunctions::inverseEvaluator(const EBTList& args) ExprBaseType BuiltInFunctions::imageEvaluator(const EBTList& args) { if (args.size() == 1) { - const auto image_evaluator = Overload { + const auto image_evaluator = Util::Overload { [](LIB::Map a) { return ExprBaseType{a.image()}; }, [](LIB::PWMap a) { return ExprBaseType{a.image()}; }, [](auto a) { @@ -549,7 +550,7 @@ ExprBaseType BuiltInFunctions::imageEvaluator(const EBTList& args) return std::visit(image_evaluator, args[0]); } else if (args.size() == 2) { - const auto image2_evaluator = Overload { + 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) { @@ -571,7 +572,7 @@ ExprBaseType BuiltInFunctions::preImageEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "preImageEvaluator: wrong number of arguments\n"); - const auto pre_image_evaluator = Overload { + 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) { @@ -588,7 +589,7 @@ ExprBaseType BuiltInFunctions::domEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "domEvaluator: wrong number of arguments\n"); - const auto dom_evaluator = Overload { + const auto dom_evaluator = Util::Overload { [](LIB::PWMap a) { return ExprBaseType{a.domain()}; }, [](auto a) { Util::ERROR("domEvaluator: wrong arguments ", a, "for dom\n"); @@ -603,7 +604,7 @@ ExprBaseType BuiltInFunctions::combineEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "combineEvaluator: wrong number of arguments\n"); - const auto combine_evaluator = Overload { + 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 @@ -619,7 +620,7 @@ ExprBaseType BuiltInFunctions::minMapEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "minMapEvaluator: wrong number of arguments\n"); - const auto min_map_evaluator = Overload { + 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 @@ -636,7 +637,7 @@ ExprBaseType BuiltInFunctions::minMapEvaluator(const EBTList& args) // Util::ERROR_UNLESS(args.size() == 1 // , "reduceEvaluator: wrong number of arguments\n"); // -// const auto reduce_evaluator = Overload { +// const auto reduce_evaluator = Util::Overload { // [](LIB::PWMap a) { return ExprBaseType{a.reduce()}; }, // [](auto a) { // Util::ERROR("reduceEvaluator: wrong argument ", a, " for reduce\n"); @@ -651,7 +652,7 @@ ExprBaseType BuiltInFunctions::minAdjEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "minAdjEvaluator: wrong number of arguments\n"); - const auto min_adj_evaluator = Overload { + 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 @@ -667,7 +668,7 @@ ExprBaseType BuiltInFunctions::mapInfEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "mapInfEvaluator: wrong number of arguments\n"); - const auto inf_evaluator = Overload { + const auto inf_evaluator = Util::Overload { [](LIB::PWMap a) { return ExprBaseType{a.mapInf()}; }, [](auto a) { Util::ERROR("mapInfEvaluator: wrong argument ", a, " for mapInf\n"); @@ -684,7 +685,7 @@ ExprBaseType BuiltInFunctions::connectedEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "connectedEvaluator: wrong number of arguments\n"); - const auto connected_evaluator = Overload { + const auto connected_evaluator = Util::Overload { [](LIB::SBG a) { return ExprBaseType{connectedComponents(a)}; }, [](auto a) { Util::ERROR("connectedEvaluator: wrong argument ", a, " for CC\n"); @@ -700,7 +701,7 @@ ExprBaseType BuiltInFunctions::matchingEvaluator(const EBTList& args) , "matchingEvaluator: wrong number of arguments\n"); LIB::Matching match_impl = LIB::MATCH_FACT.createMatchAlgorithm(); - const auto matching_evaluator = Overload { + const auto matching_evaluator = Util::Overload { [&match_impl](LIB::BipartiteSBG a, LIB::NAT b) { // TODO return ExprBaseType{match_impl.calculate(a.copy(b))}; return ExprBaseType{match_impl.calculate(a)}; @@ -724,7 +725,7 @@ ExprBaseType BuiltInFunctions::sccEvaluator(const EBTList& args) , "sccEvaluator: wrong number of arguments\n"); LIB::SCC scc_impl = LIB::SCC_FACT.createSCCAlgorithm(); - const auto scc_evaluator = Overload { + const auto scc_evaluator = Util::Overload { [&scc_impl](LIB::DirectedSBG a) { return ExprBaseType{scc_impl.calculate(a).rmap()}; }, @@ -743,7 +744,7 @@ ExprBaseType BuiltInFunctions::topoSortEvaluator(const EBTList& args) , "topoSortEvaluator: wrong number of arguments\n"); LIB::TopoSort ts_impl = LIB::TS_FACT.createTSAlgorithm(); - const auto ts_evaluator = Overload { + const auto ts_evaluator = Util::Overload { [&ts_impl](LIB::DirectedSBG a) { return ExprBaseType{ts_impl.calculate(a)}; }, @@ -761,7 +762,7 @@ ExprBaseType BuiltInFunctions::cutVertexEvaluator(const EBTList& args) , "cutVertexEvaluator: wrong number of arguments\n"); LIB::CutVertex cv_impl = LIB::CV_FACT.createCVAlgorithm(); - const auto cv_evaluator = Overload { + const auto cv_evaluator = Util::Overload { [&cv_impl](LIB::DirectedSBG a) { return ExprBaseType{cv_impl.calculate(a)}; }, @@ -781,7 +782,7 @@ ExprBaseType BuiltInFunctions::matchSCCEvaluator(const EBTList& args) LIB::Matching match_impl = LIB::MATCH_FACT.createMatchAlgorithm(); LIB::SCC scc_impl = LIB::SCC_FACT.createSCCAlgorithm(); - const auto match_scc_evaluator = Overload { + const auto match_scc_evaluator = Util::Overload { [&match_impl, &scc_impl](LIB::BipartiteSBG a, LIB::NAT b) { // TODO LIB::MatchData match_result = match_impl.calculate(a.copy(b)); LIB::MatchData match_result = match_impl.calculate(a); @@ -807,7 +808,7 @@ ExprBaseType BuiltInFunctions::matchSCCEvaluator(const EBTList& args) /* ExprBaseType BuiltInFunctions::matchSCCTSEvaluator(const EBTList& args) { - const auto match_scc_ts_evaluator = Overload { + const auto match_scc_ts_evaluator = Util::Overload { [](LIB::SBG a, LIB::NAT b, bool c) { LIB::BFSMatching match(a.copy(b), c); LIB::Set match_res = match.calculate().matched_edges(); diff --git a/eval/visitors/func_evaluator.hpp b/eval/visitors/func_evaluator.hpp index b1bfc21c..6e97088d 100755 --- a/eval/visitors/func_evaluator.hpp +++ b/eval/visitors/func_evaluator.hpp @@ -36,26 +36,6 @@ namespace Eval { namespace detail { -//////////////////////////////////////////////////////////////////////////////// -// 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; - //////////////////////////////////////////////////////////////////////////////// // Built-in Operators ---------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// diff --git a/sbg/map_detail.cpp b/sbg/map_detail.cpp index 04acf011..37e1d096 100755 --- a/sbg/map_detail.cpp +++ b/sbg/map_detail.cpp @@ -91,7 +91,7 @@ CompactSetImpl compactImage(const CompactSetImpl& s, const Expr& expr Set MapDetail::image(const Set& s, const Expression& expr) { - auto image_evaluator = Overload { + auto image_evaluator = Util::Overload { [&](const UnorderedSet& a) { return Set{detail::compactImage( @@ -438,7 +438,7 @@ MapVector MapDetail::reduce(const Map& m) return result; } - auto reduce_evaluator = Overload { + auto reduce_evaluator = Util::Overload { [&](const UnorderedSet& a) { return MDICollectionReduce(a, law._impl); diff --git a/sbg/map_detail.hpp b/sbg/map_detail.hpp index fbd6e072..e703fdfc 100755 --- a/sbg/map_detail.hpp +++ b/sbg/map_detail.hpp @@ -34,6 +34,7 @@ #include "sbg/linear_expr.hpp" #include "sbg/map.hpp" #include "sbg/multidim_inter.hpp" +#include "util/defs.hpp" namespace SBG { @@ -60,16 +61,6 @@ class MapDetail { , const ExpressionImpl& expr); }; -template -class Overload : Ts... { -public: - using Ts::operator()...; - Overload(Ts... ts) : Ts(ts)... {}; -}; - -template -Overload(Ts...) -> Overload; - } // namespace detail } // namespace LIB 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_ From d57cd8a46e79588fc60eed83350ecbc13e616572 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Tue, 31 Mar 2026 14:35:36 -0300 Subject: [PATCH 27/66] Added PWMap::ConstIt --- sbg/pw_map.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++++---- sbg/pw_map.hpp | 19 +++++++++++++++++-- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/sbg/pw_map.cpp b/sbg/pw_map.cpp index b52cb8b8..5dcc5c9a 100644 --- a/sbg/pw_map.cpp +++ b/sbg/pw_map.cpp @@ -18,7 +18,9 @@ ******************************************************************************/ #include "sbg/pw_map.hpp" +#include "sbg/set_fact.hpp" #include "util/debug.hpp" +#include "util/defs.hpp" #include @@ -26,6 +28,39 @@ namespace SBG { namespace LIB { +//////////////////////////////////////////////////////////////////////////////// +// PWMap Iterator -------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +PWMap::ConstIt::ConstIt(detail::UnordPWMap::ConstIt it) : _it(it) {} + +PWMap::ConstIt::ConstIt(detail::OrdPWMap::ConstIt it) : _it(it) {} + +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::ConstIt PWMap::ConstIt::operator++() +{ + std::visit([](auto& i) { ++i; }, _it); + return *this; +} + +bool PWMap::ConstIt::operator==(const ConstIt& other) +{ + return _it == other._it; +} + +bool PWMap::ConstIt::operator!=(const ConstIt& other) +{ + return _it != other._it; +} + //////////////////////////////////////////////////////////////////////////////// // PWMap implementations ------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// @@ -72,6 +107,7 @@ PWMap::PWMap(const PWMapKind kind) : _impl() } case PWMapKind::kOrdered: { + _impl = detail::OrdPWMap{}; break; } @@ -95,6 +131,7 @@ PWMap::PWMap(const PWMapKind kind, Set s) : _impl() } case PWMapKind::kOrdered: { + _impl = detail::UnordPWMap{s}; break; } @@ -118,6 +155,7 @@ PWMap::PWMap(const PWMapKind kind, Map m) : _impl() } case PWMapKind::kOrdered: { + _impl = detail::UnordPWMap{m}; break; } @@ -140,12 +178,14 @@ PWMap::PWMap(detail::PWMapImpl&& impl) : _impl(std::move(impl)) {} PWMap::ConstIt PWMap::begin() { - return std::visit([](const auto& a) { return a.begin(); }, _impl); + return std::visit([](const auto& a) { return PWMap::ConstIt(a.begin()); } + , _impl); } PWMap::ConstIt PWMap::end() { - return std::visit([](const auto& a) { return a.end(); }, _impl); + return std::visit([](const auto& a) { return PWMap::ConstIt(a.end()); } + , _impl); } // Setters --------------------------------------------------------------------- @@ -394,7 +434,7 @@ Set PWMap::equalImage(const PWMap& other) const return a.equalImage(b); } else { Util::ERROR("PWMap::equalImage: mismatched implementations\n"); - return PWMap{PWMapKind::kUnordered}; + return SET_FACT.createSet(); } } , _impl, other._impl); @@ -410,7 +450,7 @@ Set PWMap::lessImage(const PWMap& other) const return a.lessImage(b); } else { Util::ERROR("PWMap::lessImage: mismatched implementations\n"); - return PWMap{PWMapKind::kUnordered}; + return SET_FACT.createSet(); } } , _impl, other._impl); diff --git a/sbg/pw_map.hpp b/sbg/pw_map.hpp index e1a0f0b4..d2e0e117 100644 --- a/sbg/pw_map.hpp +++ b/sbg/pw_map.hpp @@ -36,6 +36,7 @@ #include "sbg/map.hpp" #include "sbg/set.hpp" +#include "sbg/ord_pwmap.hpp" #include "sbg/unord_pwmap.hpp" namespace SBG { @@ -48,7 +49,7 @@ namespace detail { // PWMaps implementations ------------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// -using PWMapImpl = std::variant; +using PWMapImpl = std::variant; } // namespace detail @@ -62,7 +63,21 @@ std::ostream& operator<<(std::ostream& out, PWMapKind kind); class PWMap { public: - using ConstIt = std::vector::const_iterator; + 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 Constructs an empty domain pw. From 1a6a7c12263d3b68d378a55fc783dbdccc0eb3fb Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Tue, 31 Mar 2026 15:40:58 -0300 Subject: [PATCH 28/66] Added OrdPWMap to evaluator --- sbg/map_entry.cpp | 6 +++--- sbg/map_entry.hpp | 4 +++- sbg/ord_pwmap.cpp | 2 +- sbg/ord_pwmap.hpp | 6 +++--- sbg/pw_map.cpp | 4 ++-- sbg/pwmap_fact.cpp | 47 +++++++++++++++++++++++----------------------- sbg/pwmap_fact.hpp | 28 +++++++++++++-------------- 7 files changed, 50 insertions(+), 47 deletions(-) diff --git a/sbg/map_entry.cpp b/sbg/map_entry.cpp index 57a79f48..fb9d63e5 100755 --- a/sbg/map_entry.cpp +++ b/sbg/map_entry.cpp @@ -29,12 +29,12 @@ namespace detail { // Map entry ------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// +MapEntry::MapEntry(const Set& s, const Expression& expr) + : _map(s, expr), _perimeter(s.perimeter()) {} + MapEntry::MapEntry(const Map& m) : _map(m), _perimeter(m.domain().perimeter()) {} -MapEntry::MapEntry(Map&& m) - : _map(std::move(m)), _perimeter(m.domain().perimeter()) {} - const Map& MapEntry::map() const { return _map; } const SetPerimeter& MapEntry::perimeter() const { return _perimeter; } diff --git a/sbg/map_entry.hpp b/sbg/map_entry.hpp index 5de6ed2f..97701dac 100755 --- a/sbg/map_entry.hpp +++ b/sbg/map_entry.hpp @@ -26,7 +26,9 @@ #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/set_perimeter.hpp" namespace SBG { @@ -37,8 +39,8 @@ namespace detail { class MapEntry { public: + MapEntry(const Set& s, const Expression& expr); MapEntry(const Map& m); - MapEntry(Map&& m); const Map& map() const; const SetPerimeter& perimeter() const; diff --git a/sbg/ord_pwmap.cpp b/sbg/ord_pwmap.cpp index c0a0c4c0..e74ca8b9 100644 --- a/sbg/ord_pwmap.cpp +++ b/sbg/ord_pwmap.cpp @@ -151,7 +151,7 @@ std::size_t OrdPWMap::advanceHint(std::size_t hint, const MapEntry& jth_entry) } else { break; } - } + } return hint; } diff --git a/sbg/ord_pwmap.hpp b/sbg/ord_pwmap.hpp index c09f830b..f3ef1d0a 100644 --- a/sbg/ord_pwmap.hpp +++ b/sbg/ord_pwmap.hpp @@ -104,8 +104,8 @@ class OrdPWMap { private: template void emplaceBack(Args&&... args); - void pushBack(const Map& entry); - void pushBack(Map&& entry); + void pushBack(const Map& m); + void pushBack(Map&& m); void pushBack(const MapEntry& entry); void pushBack(MapEntry&& entry); @@ -145,7 +145,7 @@ class OrdPWMap { template inline void OrdPWMap::emplace(Args&&... args) { - _pieces.emplace(std::forward(args)...); + insert(Map{std::forward(args)...}); } template diff --git a/sbg/pw_map.cpp b/sbg/pw_map.cpp index 5dcc5c9a..4b0e669b 100644 --- a/sbg/pw_map.cpp +++ b/sbg/pw_map.cpp @@ -131,7 +131,7 @@ PWMap::PWMap(const PWMapKind kind, Set s) : _impl() } case PWMapKind::kOrdered: { - _impl = detail::UnordPWMap{s}; + _impl = detail::OrdPWMap{s}; break; } @@ -155,7 +155,7 @@ PWMap::PWMap(const PWMapKind kind, Map m) : _impl() } case PWMapKind::kOrdered: { - _impl = detail::UnordPWMap{m}; + _impl = detail::OrdPWMap{m}; break; } diff --git a/sbg/pwmap_fact.cpp b/sbg/pwmap_fact.cpp index 1572fc92..1f4ce337 100644 --- a/sbg/pwmap_fact.cpp +++ b/sbg/pwmap_fact.cpp @@ -49,25 +49,25 @@ PWMap UnordPWMapFact::createPWMap(const Map& m) const // 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)); -//} -// +OrdPWMapFact::OrdPWMapFact() {} + +PWMap OrdPWMapFact::createPWMap() const +{ + return PWMap{PWMapKind::kOrdered}; +} + +PWMap OrdPWMapFact::createPWMap(const Set& s) const +{ + return PWMap{PWMapKind::kOrdered, s}; +} + +PWMap OrdPWMapFact::createPWMap(const Map& m) const +{ + return PWMap{PWMapKind::kOrdered, m}; +} + ////////////////////////////////////////////////////////////////////////////////// -//// DomOrdPWMap Factory ------------------------------------------------------------ +//// DomOrdPWMap Factory --------------------------------------------------------- ////////////////////////////////////////////////////////////////////////////////// // //DomOrdPWMapFact::DomOrdPWMapFact() {} @@ -104,18 +104,19 @@ const PWMapKind& PWMapFactory::kind() const { return _kind; } void PWMapFactory::set_pwmap_fact(PWMapKind kind) { + _kind = kind; switch (kind) { case PWMapKind::kUnordered: { - _kind = kind; _impl = UnordPWMapFact{}; break; } - //case SetKind::kOrdered: { - // _impl = OrdPWMapFact{}; - //} + case PWMapKind::kOrdered: { + _impl = OrdPWMapFact{}; + break; + } - //case SetKind::OrdUnidimDense: { + //case PWMapKind::kDomOrdered: { // _impl = DomOrdPWMapFact{}; //} diff --git a/sbg/pwmap_fact.hpp b/sbg/pwmap_fact.hpp index c58ad246..31eaeee1 100644 --- a/sbg/pwmap_fact.hpp +++ b/sbg/pwmap_fact.hpp @@ -39,26 +39,26 @@ class UnordPWMapFact { UnordPWMapFact(); PWMap createPWMap() const; - PWMap createPWMap(const Set &s) const; - PWMap createPWMap(const Map &m) const; + PWMap createPWMap(const Set& s) const; + PWMap createPWMap(const Map& m) const; +}; + +class OrdPWMapFact { +public: + OrdPWMapFact(); + + PWMap createPWMap() const; + PWMap createPWMap(const Set& s) const; + PWMap createPWMap(const Map& m) const; }; -//class OrdPWMapFact { -// public: -// OrdPWMapFact(); -// -// PWMap createPWMap() const override; -// PWMap createPWMap(const Set &s) const override; -// PWMap createPWMap(const Map &m) const override; -//}; -// //class DomOrdPWMapFact { // public: // DomOrdPWMapFact(); // // PWMap createPWMap() const override; -// PWMap createPWMap(const Set &s) const override; -// PWMap createPWMap(const Map &m) const override; +// PWMap createPWMap(const Set& s) const override; +// PWMap createPWMap(const Map& m) const override; //}; /** @@ -80,7 +80,7 @@ class PWMapFactory { PWMap createPWMap(Map m) const; private: - using FactImpl = std::variant; + using FactImpl = std::variant; PWMapFactory(); From 6f1855b9a3eb2b91dab8aa9ec4d22358716dd00e Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Wed, 1 Apr 2026 14:21:56 -0300 Subject: [PATCH 29/66] Debugged OrdPWMap --- sbg/ord_pwmap.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/sbg/ord_pwmap.cpp b/sbg/ord_pwmap.cpp index e74ca8b9..162a9299 100644 --- a/sbg/ord_pwmap.cpp +++ b/sbg/ord_pwmap.cpp @@ -164,7 +164,7 @@ CoreOperation OrdPWMap::traverse(const OrdPWMap& other, CoreOperation core_op) { OrdMapCollection short_pw = _pieces; OrdMapCollection long_pw = other._pieces; - if (other._pieces.size() < _pieces.size()) { + if (!core_op.orderMatters() && other._pieces.size() < _pieces.size()) { short_pw = other._pieces; long_pw = _pieces; } @@ -247,6 +247,8 @@ class EqualCore { return true; } + bool orderMatters() const { return false; } + bool result() const { return _are_equal; } private: @@ -280,6 +282,8 @@ class AddCore { return true; } + bool orderMatters() const { return false; } + OrdPWMap result() const { return _result; } private: @@ -586,7 +590,7 @@ OrdPWMap OrdPWMap::reduce() const for (const MapEntry& entry : _pieces) { std::vector reduced = entry.map().reduce(); for(Map& reduced_map : reduced) { - result.pushBack(std::move(reduced_map)); + result.insert(std::move(reduced_map)); } } @@ -628,6 +632,8 @@ class MinAdjCore { return true; } + bool orderMatters() const { return true; } + OrdPWMap result() const { return _result; } private: @@ -678,6 +684,8 @@ class EqualImageCore { return true; } + bool orderMatters() const { return false; } + Set result() const { return _result; } private: @@ -706,6 +714,8 @@ class LessImageCore { return true; } + bool orderMatters() const { return true; } + Set result() const { return _result; } private: @@ -719,7 +729,7 @@ Set OrdPWMap::lessImage(const OrdPWMap& other) const } if (_pieces == other._pieces) { - return domain(); + return SET_FACT.createSet(); } return traverse(other, LessImageCore{}).result(); From e321f3a711a17e155db57cb854b8b5dc8abfcbf5 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Wed, 1 Apr 2026 14:59:39 -0300 Subject: [PATCH 30/66] New version of compact for UnordSet, OrdSet, UnordPWMap and OrdPWMap --- sbg/map_entry.cpp | 10 ++++++++++ sbg/map_entry.hpp | 8 ++++++++ sbg/ord_pwmap.cpp | 46 +++++++++++++++++++++++++++++++++++++++++---- sbg/ord_set.cpp | 30 ++++++++++++++++------------- sbg/unord_pwmap.cpp | 21 +++++++++++---------- sbg/unord_set.cpp | 30 ++++++++++++++++------------- 6 files changed, 105 insertions(+), 40 deletions(-) diff --git a/sbg/map_entry.cpp b/sbg/map_entry.cpp index fb9d63e5..1a333800 100755 --- a/sbg/map_entry.cpp +++ b/sbg/map_entry.cpp @@ -48,6 +48,16 @@ bool MapEntry::operator<(const MapEntry& other) const { return _perimeter.min() < other._perimeter.min(); } + +MaybeMapEntry MapEntry::compact(const MapEntry& other) const +{ + MaybeMap compacted = _map.compact(other._map); + if (compacted) { + return MaybeMapEntry{compacted.value()}; + } + + return {}; +} } // namespace detail diff --git a/sbg/map_entry.hpp b/sbg/map_entry.hpp index 97701dac..18ecdbd3 100755 --- a/sbg/map_entry.hpp +++ b/sbg/map_entry.hpp @@ -31,12 +31,18 @@ #include "sbg/set.hpp" #include "sbg/set_perimeter.hpp" +#include + namespace SBG { namespace LIB { namespace detail { +class MapEntry; + +using MaybeMapEntry = std::optional; + class MapEntry { public: MapEntry(const Set& s, const Expression& expr); @@ -48,6 +54,8 @@ class MapEntry { bool operator==(const MapEntry& other) const; bool operator<(const MapEntry& other) const; + MaybeMapEntry compact(const MapEntry& other) const; + private: Map _map; SetPerimeter _perimeter; diff --git a/sbg/ord_pwmap.cpp b/sbg/ord_pwmap.cpp index 162a9299..323cf868 100644 --- a/sbg/ord_pwmap.cpp +++ b/sbg/ord_pwmap.cpp @@ -37,10 +37,10 @@ namespace detail { // Auxliary definitions -------------------------------------------------------- -class MapLess { +class MapEntryLess { public: - bool operator()(const Map& a, const Map& b) const { - return a.domain().minElem() < b.domain().minElem(); + bool operator()(const MapEntry& a, const MapEntry& b) const { + return a.map().domain().minElem() < b.map().domain().minElem(); } }; @@ -735,9 +735,47 @@ Set OrdPWMap::lessImage(const OrdPWMap& other) const return traverse(other, LessImageCore{}).result(); } -// TODO void OrdPWMap::compact() { + using MapSet = std::set; + + OrdMapCollection result; + + if (!isEmpty()) { + MapSet set_result; + 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) { + MapEntry ith_compact = *ith; + MapSet::iterator next = ith; + ++next; + for (; next != last; ++next) { + MaybeMapEntry new_compact = ith_compact.compact(*next); + if (new_compact) { + ith_compact = new_compact.value(); + to_erase.insert(*next); + } + } + + if (to_erase.find(ith_compact) == to_erase.end()) { + new_set_result.insert(ith_compact); + } + } + + std::swap(set_result, new_set_result); + } while (!to_erase.empty()); + + for (const MapEntry& map_entry : set_result) { + result.push_back(map_entry); + } + } + + _pieces = std::move(result); } } // namespace detail diff --git a/sbg/ord_set.cpp b/sbg/ord_set.cpp index f36e74b3..f6bd46fa 100644 --- a/sbg/ord_set.cpp +++ b/sbg/ord_set.cpp @@ -635,21 +635,23 @@ SetPerimeter OrderedSet::perimeter() const void OrderedSet::compact() { + 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) { MultiDimInter ith_compact = *ith; - std::set::iterator next = ith; + MDISet::iterator next = ith; ++next; for (; next != last; ++next) { MaybeMDI new_compact = ith_compact.compact(*next); @@ -660,13 +662,15 @@ void OrderedSet::compact() } if (to_erase.find(ith_compact) == to_erase.end()) { - actual.insert(ith_compact); + new_set_result.insert(ith_compact); } - } - } while (actual != prev); + } + + std::swap(set_result, new_set_result); + } while (!to_erase.empty()); - for (const MultiDimInter& mdi : actual) { - result.push_back(mdi); + for (const MultiDimInter& m : set_result) { + result.push_back(m); } } diff --git a/sbg/unord_pwmap.cpp b/sbg/unord_pwmap.cpp index 465238e1..1cea09d4 100644 --- a/sbg/unord_pwmap.cpp +++ b/sbg/unord_pwmap.cpp @@ -487,16 +487,15 @@ void UnordPWMap::compact() UnordMapCollection result; if (!isEmpty()) { - MapSet prev{std::make_move_iterator(_pieces.begin()) + MapSet set_result{std::make_move_iterator(_pieces.begin()) , std::make_move_iterator(_pieces.end())}; - MapSet actual = prev; + MapSet to_erase; do { - prev = actual; - actual = MapSet{}; + MapSet new_set_result; + to_erase.clear(); - MapSet::iterator ith = prev.begin(); - MapSet::iterator last = prev.end(); - MapSet to_erase; + MapSet::iterator ith = set_result.begin(); + MapSet::iterator last = set_result.end(); for (; ith != last; ++ith) { Map ith_compact = *ith; MapSet::iterator next = ith; @@ -510,12 +509,14 @@ void UnordPWMap::compact() } if (to_erase.find(ith_compact) == to_erase.end()) { - actual.insert(ith_compact); + new_set_result.insert(ith_compact); } } - } while (actual != prev); - for (const Map& m : actual) { + std::swap(set_result, new_set_result); + } while (!to_erase.empty()); + + for (const Map& m : set_result) { result.push_back(m); } } diff --git a/sbg/unord_set.cpp b/sbg/unord_set.cpp index 8a470fbd..78ae0a4e 100644 --- a/sbg/unord_set.cpp +++ b/sbg/unord_set.cpp @@ -437,21 +437,23 @@ SetPerimeter UnorderedSet::perimeter() const void UnorderedSet::compact() { + 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) { MultiDimInter ith_compact = *ith; - std::set::iterator next = ith; + MDISet::iterator next = ith; ++next; for (; next != last; ++next) { MaybeMDI new_compact = ith_compact.compact(*next); @@ -462,13 +464,15 @@ void UnorderedSet::compact() } if (to_erase.find(ith_compact) == to_erase.end()) { - actual.insert(ith_compact); + new_set_result.insert(ith_compact); } - } - } while (actual != prev); + } + + std::swap(set_result, new_set_result); + } while (!to_erase.empty()); - for (const MultiDimInter& mdi : actual) { - result.push_back(mdi); + for (const MultiDimInter& m : set_result) { + result.push_back(m); } } From 51c469d8da96a10fea0a29e0a30c50626c930053 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Wed, 8 Apr 2026 15:10:46 -0300 Subject: [PATCH 31/66] Debugged MatchKind --- algorithms/matching/matching.cpp | 2 ++ algorithms/matching/matching_fact.cpp | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/algorithms/matching/matching.cpp b/algorithms/matching/matching.cpp index 330cb472..2f054bcf 100644 --- a/algorithms/matching/matching.cpp +++ b/algorithms/matching/matching.cpp @@ -34,10 +34,12 @@ 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; } } diff --git a/algorithms/matching/matching_fact.cpp b/algorithms/matching/matching_fact.cpp index dc5e0974..0aea1be8 100755 --- a/algorithms/matching/matching_fact.cpp +++ b/algorithms/matching/matching_fact.cpp @@ -37,7 +37,8 @@ Matching BFSMatchingFact::createMatchAlgorithm() const // Factory for clients --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -MatchFactory::MatchFactory() : _kind(MatchKind::kBFSPaths), _impl() {} +MatchFactory::MatchFactory() + : _kind(MatchKind::kBFSPaths), _impl(BFSMatchingFact{}) {} MatchFactory& MatchFactory::instance() { @@ -58,6 +59,7 @@ void MatchFactory::set_match_fact(MatchKind kind) default: { Util::ERROR("Unsupported matching implementation"); + break; } } } From 66d66ab3cc5453864efa46c8a27eea05ea84ee63 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Wed, 8 Apr 2026 15:13:06 -0300 Subject: [PATCH 32/66] Added SCC algorithm selection --- eval/input_translator.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/eval/input_translator.cpp b/eval/input_translator.cpp index b52896dc..32614386 100755 --- a/eval/input_translator.cpp +++ b/eval/input_translator.cpp @@ -47,10 +47,10 @@ void InputTranslator::translate(EvalUserInput& input) setPWFactory(*pw); } - //EvalUserInput::MaybeInt scc = input.scc_impl(); - //if (scc) { - // setSCCFactory(*scc); - //} + EvalUserInput::MaybeInt scc = input.scc_impl(); + if (scc) { + setSCCFactory(*scc); + } } } // namespace detail From ad0bc2565d51cf9603e7cd27b1a5f375d09a33bc Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Wed, 8 Apr 2026 15:38:58 -0300 Subject: [PATCH 33/66] Improved benchmark code --- eval/eval_exec.cpp | 16 +- eval/eval_exec.hpp | 2 +- eval/main.cpp | 2 +- eval/pretty_print.hpp | 2 +- eval/user_input.hpp | 2 +- parser/parser_exec.cpp | 2 + sbg/CMakeLists.txt | 1 + sbg/ord_pwmap.cpp | 10 +- sbg/ord_pwmap.hpp | 1 + sbg/pw_map.hpp | 4 + sbg/pwmap_detail.cpp | 43 ++ sbg/pwmap_detail.hpp | 59 +++ sbg/unord_pwmap.hpp | 2 + test/README.md | 23 +- test/performance/CMakeLists.txt | 15 +- test/performance/bm_exec.cpp | 188 +++++++ test/performance/bm_exec.hpp | 54 ++ test/performance/dom_ord_pwmap_bm.cpp | 463 ------------------ .../{benchmark_main.cpp => main.cpp} | 10 +- test/performance/matching/CMakeLists.txt | 32 -- test/performance/matching/match_bm.cpp | 159 ------ .../custom_match_bm.cpp => matching_bm.cpp} | 89 ++-- test/performance/matching_bm.hpp | 56 +++ test/performance/ord_set_bm.cpp | 194 -------- test/performance/pwmap_bm.cpp | 264 ++++++++++ test/performance/pwmap_bm.hpp | 41 ++ test/performance/scc/CMakeLists.txt | 32 -- test/performance/scc/scc_bm.cpp | 165 ------- .../{scc/custom_scc_bm.cpp => scc_bm.cpp} | 101 ++-- test/performance/scc_bm.hpp | 59 +++ test/performance/set_bm.cpp | 153 ++++++ test/performance/set_bm.hpp | 41 ++ test/performance/unord_pwmap_bm.cpp | 402 --------------- test/performance/unord_set_bm.cpp | 181 ------- test/performance/utils.cpp | 275 ++++++++++- test/performance/utils.hpp | 123 ++++- util/user_input_handler.cpp | 3 - util/user_input_handler.hpp | 2 +- 38 files changed, 1463 insertions(+), 1808 deletions(-) create mode 100755 sbg/pwmap_detail.cpp create mode 100755 sbg/pwmap_detail.hpp create mode 100644 test/performance/bm_exec.cpp create mode 100644 test/performance/bm_exec.hpp delete mode 100644 test/performance/dom_ord_pwmap_bm.cpp rename test/performance/{benchmark_main.cpp => main.cpp} (83%) delete mode 100644 test/performance/matching/CMakeLists.txt delete mode 100644 test/performance/matching/match_bm.cpp rename test/performance/{matching/custom_match_bm.cpp => matching_bm.cpp} (51%) create mode 100644 test/performance/matching_bm.hpp delete mode 100644 test/performance/ord_set_bm.cpp create mode 100644 test/performance/pwmap_bm.cpp create mode 100644 test/performance/pwmap_bm.hpp delete mode 100644 test/performance/scc/CMakeLists.txt delete mode 100644 test/performance/scc/scc_bm.cpp rename test/performance/{scc/custom_scc_bm.cpp => scc_bm.cpp} (53%) create mode 100644 test/performance/scc_bm.hpp create mode 100644 test/performance/set_bm.cpp create mode 100644 test/performance/set_bm.hpp delete mode 100644 test/performance/unord_pwmap_bm.cpp delete mode 100644 test/performance/unord_set_bm.cpp diff --git a/eval/eval_exec.cpp b/eval/eval_exec.cpp index 185e858a..07b2b00b 100644 --- a/eval/eval_exec.cpp +++ b/eval/eval_exec.cpp @@ -19,8 +19,8 @@ //#include "algorithms/cutvertex/cv_fact.hpp" //#include "algorithms/cc/cc.hpp" -//#include "algorithms/matching/matching_fact.hpp" -//#include "algorithms/scc/scc_fact.hpp" +#include "algorithms/matching/matching_fact.hpp" +#include "algorithms/scc/scc_fact.hpp" //#include "algorithms/toposort/ts_fact.hpp" #include "eval/eval_exec.hpp" #include "eval/file_evaluator.hpp" @@ -55,11 +55,11 @@ void printHeader(Util::prog_opts::variables_map vm) std::cout << "Set implementation: " << LIB::SET_FACT.kind() << "\n"; std::cout << "PWMap implementation: " << LIB::PWMAP_FACT.kind() << "\n"; std::cout << "-----------------------------------\n"; - //std::cout << "Matching algorithm: " << LIB::MATCH_FACT.kind() << "\n"; - //std::cout << "SCC algorithm: " << LIB::SCC_FACT.kind() << "\n"; + std::cout << "Matching algorithm: " << LIB::MATCH_FACT.kind() << "\n"; + std::cout << "SCC algorithm: " << LIB::SCC_FACT.kind() << "\n\n"; //std::cout << "Cut vertex algorithm: " << LIB::CV_FACT.kind() << "\n"; //std::cout << "Topological sort algorithm: " << LIB::TS_FACT.kind() - // << "\n"; + // << "\n"; } std::cout << "-----------------------------------\n"; std::cout << ">>>>>>>>>>> Eval result <<<<<<<<<<<\n"; @@ -88,6 +88,8 @@ EvalExecutor::EvalExecutor() : scc_impl_(1) "\n - 0 for V1 of minimum reachable SCC" "\n - 1 for V2 of minimum reachable SCC (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); @@ -123,12 +125,12 @@ detail::EvalUserInput EvalExecutor::chooseImplementation() 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) + store(Util::prog_opts::command_line_parser(argc, argv) .options(_cmd_line_opts).positional(_positional).run(), vm); notify(vm); diff --git a/eval/eval_exec.hpp b/eval/eval_exec.hpp index e542e735..57926879 100644 --- a/eval/eval_exec.hpp +++ b/eval/eval_exec.hpp @@ -49,4 +49,4 @@ class EvalExecutor : public Util::UserInputHandler { } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_EVAL_EXEC_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.hpp b/eval/pretty_print.hpp index 5255293b..f1d61722 100755 --- a/eval/pretty_print.hpp +++ b/eval/pretty_print.hpp @@ -74,4 +74,4 @@ std::ostream& operator<<(std::ostream& out, const ProgramIO& p); } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_PRETTY_PRINT_HPP_ diff --git a/eval/user_input.hpp b/eval/user_input.hpp index 9933116d..6205b40e 100755 --- a/eval/user_input.hpp +++ b/eval/user_input.hpp @@ -71,4 +71,4 @@ class EvalUserInput { } // namespace SBG -#endif +#endif // SBGRAPH_EVAL_USER_INPUT_HPP_ diff --git a/parser/parser_exec.cpp b/parser/parser_exec.cpp index ddf5515f..f6cfb58e 100644 --- a/parser/parser_exec.cpp +++ b/parser/parser_exec.cpp @@ -36,6 +36,8 @@ namespace Parser { ParserExecutor::ParserExecutor() : UserInputHandler() { + // 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); diff --git a/sbg/CMakeLists.txt b/sbg/CMakeLists.txt index d6708828..fa2ca98e 100644 --- a/sbg/CMakeLists.txt +++ b/sbg/CMakeLists.txt @@ -22,6 +22,7 @@ target_sources( ord_set.cpp ord_unidim_dense_set.cpp pw_map.cpp + pwmap_detail.cpp pwmap_fact.cpp rational.cpp sbg.cpp diff --git a/sbg/ord_pwmap.cpp b/sbg/ord_pwmap.cpp index 323cf868..865634d6 100644 --- a/sbg/ord_pwmap.cpp +++ b/sbg/ord_pwmap.cpp @@ -20,7 +20,6 @@ #include "sbg/set_fact.hpp" #include "sbg/ord_pwmap.hpp" -#include #include #include #include @@ -410,15 +409,14 @@ Set OrdPWMap::preImage(const Set& subcodom) const OrdPWMap OrdPWMap::inverse() const { - OrdMapCollection result; + OrdPWMap result; for (const MapEntry& entry : _pieces) { Map m = entry.map(); - result.emplace_back(Map{m.image(), m.law().inverse()}); + result.emplace(Map{m.image(), m.law().inverse()}); } - std::sort(result.begin(), result.end()); - return OrdPWMap{std::move(result)}; + return result; } OrdPWMap OrdPWMap::composition(const OrdPWMap& other) const @@ -589,7 +587,7 @@ OrdPWMap OrdPWMap::reduce() const for (const MapEntry& entry : _pieces) { std::vector reduced = entry.map().reduce(); - for(Map& reduced_map : reduced) { + for (Map& reduced_map : reduced) { result.insert(std::move(reduced_map)); } } diff --git a/sbg/ord_pwmap.hpp b/sbg/ord_pwmap.hpp index f3ef1d0a..acf7c632 100644 --- a/sbg/ord_pwmap.hpp +++ b/sbg/ord_pwmap.hpp @@ -140,6 +140,7 @@ class OrdPWMap { friend class AddCore; friend class MinAdjCore; + friend class PWMapAccessKey; }; template diff --git a/sbg/pw_map.hpp b/sbg/pw_map.hpp index d2e0e117..e8496045 100644 --- a/sbg/pw_map.hpp +++ b/sbg/pw_map.hpp @@ -51,6 +51,8 @@ namespace detail { using PWMapImpl = std::variant; +class PWMapAccessKey; + } // namespace detail enum class PWMapKind { kUnordered, kOrdered, kDomOrdered }; @@ -238,6 +240,8 @@ class PWMap { PWMap(detail::PWMapImpl&& impl); detail::PWMapImpl _impl; + + friend class detail::PWMapAccessKey; }; std::ostream& operator<<(std::ostream& out, const PWMap& pw); diff --git a/sbg/pwmap_detail.cpp b/sbg/pwmap_detail.cpp new file mode 100755 index 00000000..45c890f2 --- /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) +{ + 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..a2669e16 --- /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); + +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/unord_pwmap.hpp b/sbg/unord_pwmap.hpp index 08a0a0fd..9fe8191a 100644 --- a/sbg/unord_pwmap.hpp +++ b/sbg/unord_pwmap.hpp @@ -122,6 +122,8 @@ class UnordPWMap { UnordPWMap mapInf(unsigned int n) const; UnordMapCollection _pieces; + + friend class PWMapAccessKey; }; template diff --git a/test/README.md b/test/README.md index 27e2b495..54a4d02e 100755 --- a/test/README.md +++ b/test/README.md @@ -26,28 +26,15 @@ 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. +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. 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 diff --git a/test/performance/CMakeLists.txt b/test/performance/CMakeLists.txt index 9363b20e..58369ed7 100644 --- a/test/performance/CMakeLists.txt +++ b/test/performance/CMakeLists.txt @@ -1,12 +1,15 @@ # SBG Benchmark for different Set and PWMap implementations -add_executable(sbg-benchmark benchmark_main.cpp) +add_executable(sbg-benchmark main.cpp) target_sources(sbg-benchmark PRIVATE - benchmark_main.cpp - #dom_ord_pwmap_bm.cpp - #unord_set_bm.cpp - unord_pwmap_bm.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 @@ -26,5 +29,3 @@ target_link_libraries(sbg-benchmark 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..7cb2ae70 --- /dev/null +++ b/test/performance/bm_exec.cpp @@ -0,0 +1,188 @@ +/******************************************************************************* + + 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/matching_fact.hpp" +#include "algorithms/scc/scc_fact.hpp" +#include "eval/user_impl_map.hpp" +#include "sbg/pwmap_fact.hpp" +#include "sbg/set_fact.hpp" +#include "test/performance/bm_exec.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/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_FACT.kind() << "\n"; + std::cout << "PWMap implementation: " << LIB::PWMAP_FACT.kind() << "\n"; + std::cout << "-----------------------------------\n"; + std::cout << "Matching algorithm: " << LIB::MATCH_FACT.kind() << "\n"; + std::cout << "SCC algorithm: " << LIB::SCC_FACT.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)"); + + _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); + + 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/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/match_bm.cpp b/test/performance/matching/match_bm.cpp deleted file mode 100644 index ea70fbda..00000000 --- a/test/performance/matching/match_bm.cpp +++ /dev/null @@ -1,159 +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 "algorithms/matching/matching.hpp" -#include "algorithms/matching/matching_fact.hpp" -#include "eval/user_impl_map.hpp" -#include "test/performance/utils.hpp" - -#include - -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/custom_match_bm.cpp b/test/performance/matching_bm.cpp similarity index 51% rename from test/performance/matching/custom_match_bm.cpp rename to test/performance/matching_bm.cpp index 7729f1fe..b930c818 100644 --- a/test/performance/matching/custom_match_bm.cpp +++ b/test/performance/matching_bm.cpp @@ -17,93 +17,86 @@ ******************************************************************************/ -/** - * @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 "algorithms/matching/matching.hpp" #include "algorithms/matching/matching_fact.hpp" #include "eval/user_impl_map.hpp" -#include "sbg/directed_sbg.hpp" +#include "sbg/bipartite_sbg.hpp" #include "test/performance/utils.hpp" +#include "test/performance/matching_bm.hpp" -namespace Test { +#include -namespace Internal { +namespace SBG { -//////////////////////////////////////////////////////////////////////////////// -// Auxiliary data -------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -int lower = 100; -int mult = 10; -int upper = 1e6; +namespace perf { -const char *filename = std::getenv("TEST_FILE"); +namespace detail { //////////////////////////////////////////////////////////////////////////////// // Benchmarks ------------------------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// -static void BM_CustomMatchTest(benchmark::State& state) +static void BM_Matching(benchmark::State& state, std::string filename) { 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); + benchmark::DoNotOptimize(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) +static void BM_MatchingCopies(benchmark::State& state, std::string filename) { int N = state.range(0); + // Calculate Matching 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); + benchmark::DoNotOptimize(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 ------------------------------------------------------------------------ +// Register Benchmarks --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -int main(int argc, char *argv[]) +void registerMatchingBenchmarks(std::string filename) { - 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(); - } + 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); +} - return 0; +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 f619aa31..00000000 --- a/test/performance/ord_set_bm.cpp +++ /dev/null @@ -1,194 +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 "eval/user_impl_map.hpp" -#include "sbg/interval.hpp" -#include "sbg/multidim_inter.hpp" -#include "sbg/set.hpp" -#include "sbg/unord_set.hpp" - -#include - -#include - -namespace Test { - -namespace Internal { - -using SBG::LIB::detail::Interval; -using SBG::LIB::detail::SetPiece; -using SBG::LIB::Set; -using SBG::LIB::SetKind; -using SBG::LIB::detail::UnorderedSet; - -//////////////////////////////////////////////////////////////////////////////// -// Auxiliary functions --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -/** - * @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); - UnorderedSet s1; - UnorderedSet s2; - 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 {Set(SetKind::Unordered, s1), Set(SetKind::Unordered, s2)}; -} - -static void BM_UnordCap(benchmark::State& state) -{ - int set_sz = state.range(0); - auto [s1, s2] = contiguousPieces(2); - for (auto _ : state) { - for (int j = 0; j < set_sz; ++j) - s1.intersection(s2); - } - state.SetComplexityN(set_sz); -} -BENCHMARK(BM_UnordCap)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); -*/ - -//////////////////////////////////////////////////////////////////////////////// -// Benchmarks ------------------------------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -//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..c9f49efe --- /dev/null +++ b/test/performance/pwmap_bm.cpp @@ -0,0 +1,264 @@ +/***************************************************************************** + + 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/set_fact.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/pwmap_fact.hpp" +#include "sbg/pwmap_detail.hpp" +#include "test/performance/utils.hpp" + +#include + +#include + +namespace SBG { + +namespace perf { + +namespace detail { + +using SBG::LIB::SetKind; +using SBG::LIB::Set; +using SBG::LIB::PWMapKind; + +//////////////////////////////////////////////////////////////////////////////// +// 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/scc_bm.cpp b/test/performance/scc/scc_bm.cpp deleted file mode 100644 index a76d0286..00000000 --- a/test/performance/scc/scc_bm.cpp +++ /dev/null @@ -1,165 +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 "algorithms/scc/scc.hpp" -#include "algorithms/scc/scc_fact.hpp" -#include "eval/user_impl_map.hpp" -#include "sbg/directed_sbg.hpp" -#include "test/performance/utils.hpp" - -#include - -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::DirectedSBG 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::DirectedSBG 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::DirectedSBG 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::DirectedSBG 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::DirectedSBG 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::DirectedSBG 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/custom_scc_bm.cpp b/test/performance/scc_bm.cpp similarity index 53% rename from test/performance/scc/custom_scc_bm.cpp rename to test/performance/scc_bm.cpp index 994127ae..a6a6da04 100644 --- a/test/performance/scc/custom_scc_bm.cpp +++ b/test/performance/scc_bm.cpp @@ -17,43 +17,27 @@ ******************************************************************************/ -/** - * @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 "algorithms/matching/match_data.hpp" #include "algorithms/scc/scc.hpp" #include "algorithms/scc/scc_fact.hpp" -#include "eval/user_impl_map.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 Test { - -namespace Internal { - -//////////////////////////////////////////////////////////////////////////////// -// Auxiliary data -------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// +namespace SBG { -int lower = 100; -int mult = 10; -int upper = 1e6; +namespace perf { -const char *filename = std::getenv("TEST_FILE"); +namespace detail { //////////////////////////////////////////////////////////////////////////////// // Benchmarks ------------------------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// -static void BM_CustomSCCTest(benchmark::State& state) +static void BM_SCC(benchmark::State& state, std::string filename) { int N = state.range(0); SBG::LIB::MatchData match_result = calculateMatching(filename, N, 1); @@ -61,29 +45,25 @@ static void BM_CustomSCCTest(benchmark::State& state) SBG::LIB::SCC scc_algorithm = SBG::LIB::SCC_FACT.createSCCAlgorithm(); for (auto _ : state) { - scc_algorithm.calculate(scc_dsbg); + benchmark::DoNotOptimize(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) +static void BM_SCCWithBuilder(benchmark::State& state, std::string filename) { int N = state.range(0); - SBG::LIB::MatchData match_result = calculateMatching(filename, N, 1); + SBG::LIB::MatchData match_result = calculateMatching(filename, 100, N); SBG::LIB::SCC scc_algorithm = SBG::LIB::SCC_FACT.createSCCAlgorithm(); for (auto _ : state) { SBG::LIB::DirectedSBG scc_dsbg = misc::buildSCCFromMatching(match_result); - scc_algorithm.calculate(scc_dsbg); + benchmark::DoNotOptimize(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) +static void BM_SCCCopies(benchmark::State& state, std::string filename) { int N = state.range(0); SBG::LIB::MatchData match_result = calculateMatching(filename, 100, N); @@ -91,32 +71,51 @@ static void BM_CustomSCCTestCopies(benchmark::State& state) for (auto _ : state) { SBG::LIB::DirectedSBG scc_dsbg = misc::buildSCCFromMatching(match_result); - scc_algorithm.calculate(scc_dsbg); + benchmark::DoNotOptimize(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 ------------------------------------------------------------------------ +// Register Benchmarks --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -int main(int argc, char *argv[]) +void registerSCCBenchmarks(std::string filename) { - 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(); - } + 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_SCCWithBuilder(state, filename); + } + )->RangeMultiplier(2)->Range(1, 128)->Complexity() + ->Unit(benchmark::kMillisecond); +} - return 0; +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..6a656c03 --- /dev/null +++ b/test/performance/set_bm.cpp @@ -0,0 +1,153 @@ +/***************************************************************************** + + 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 "sbg/set_fact.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::SetKind; +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/unord_pwmap_bm.cpp b/test/performance/unord_pwmap_bm.cpp deleted file mode 100644 index caa34e43..00000000 --- a/test/performance/unord_pwmap_bm.cpp +++ /dev/null @@ -1,402 +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/interval.hpp" -#include "sbg/multidim_inter.hpp" -#include "sbg/natural.hpp" -#include "sbg/set.hpp" -#include "sbg/set_fact.hpp" -#include "sbg/pw_map.hpp" -#include "sbg/pwmap_fact.hpp" - -#include - -#include -#include - -namespace Test { - -namespace Internal { - -using SBG::LIB::NAT; -using SBG::LIB::detail::Interval; -using SBG::LIB::detail::MultiDimInter; -using SBG::LIB::SetKind; -using SBG::LIB::Set; -using SBG::LIB::RATIONAL; -using SBG::LIB::detail::LinearExpr; -using SBG::LIB::Expression; -using SBG::LIB::Map; -using SBG::LIB::PWMapKind; -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::PWMAP_FACT.createPWMap(); - for (unsigned int j = 0; j < map_sz; ++j) { - Set domain = SBG::LIB::SET_FACT.createSet(); - SBG::LIB::NAT off = j*set_sz*inter_sz; - for (unsigned int h = 0; h < set_sz; ++h) { - Interval i{off + (h*inter_sz), 1, off + (h + 1)*inter_sz - 1}; - Set jth_domain - = SBG::LIB::SET_FACT.createSet(i.begin(), i.step(), i.end()); - domain = std::move(domain).disjointCup(std::move(jth_domain)); - } - Expression multidim_id{1, 0}; - - pw.emplace(domain, multidim_id); - } - - return pw; -} - -std::pair minAdjMaps(SBG::LIB::NAT map_sz) -{ - SBG::LIB::NAT inter_sz = 100; - SBG::LIB::NAT set_sz = 10; - - Set second_dim = SBG::LIB::SET_FACT.createSet(0, 1, inter_sz - 1); - PWMap pw1 = SBG::LIB::PWMAP_FACT.createPWMap(); - PWMap pw2 = SBG::LIB::PWMAP_FACT.createPWMap(); - for (unsigned int j = 0; j < map_sz; ++j) { - Set domain1 = SBG::LIB::SET_FACT.createSet(); - Set domain2 = 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); - Set jth_domain1 = SBG::LIB::SET_FACT.createSet(i1.begin(), i1.step() - , i1.end()); - domain1 = std::move(domain1).disjointCup(std::move(jth_domain1)); - - SBG::LIB::NAT off2 = off + inter_sz/2; - Interval i2(off2 + (h*inter_sz), 1, off2 + (h + 1)*inter_sz - 1); - Set jth_domain2 = SBG::LIB::SET_FACT.createSet(i2.begin(), i2.step() - , i2.end()); - domain2 = std::move(domain2).disjointCup(std::move(jth_domain2)); - } - - Expression multidim_id{2, 1, 0}; - Expression minus_one{2, 1, RATIONAL{-1, 1}}; - - pw1.emplace(domain1, multidim_id); - pw2.emplace(domain2, 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; - - Set second_dim = SBG::LIB::SET_FACT.createSet(0, 1, inter_sz - 1); - PWMap pw1 = SBG::LIB::PWMAP_FACT.createPWMap(); - PWMap pw2 = SBG::LIB::PWMAP_FACT.createPWMap(); - for (unsigned int j = 0; j < 2*map_sz; j += 2) { - Set domain1 = SBG::LIB::SET_FACT.createSet(); - Set domain2 = SBG::LIB::SET_FACT.createSet(); - SBG::LIB::NAT off = j*set_sz*inter_sz; - for (unsigned int h = 0; h < set_sz; h += 2) { - Interval i1{off + (h*inter_sz), 1, off + (h + 1)*inter_sz - 1}; - Set jth_domain1 = SBG::LIB::SET_FACT.createSet(i1.begin(), i1.step() - , i1.end()); - domain1 = std::move(domain1).disjointCup(std::move(jth_domain1)); - - SBG::LIB::NAT off2 = off + inter_sz; - Interval i2{off2 + (h*inter_sz), 1, off2 + (h + 1)*inter_sz - 1}; - Set jth_domain2 = SBG::LIB::SET_FACT.createSet(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}; -} - -///* -// * @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; - - Set second_dim = SBG::LIB::SET_FACT.createSet(0, 1, inter_sz - 1); - PWMap pw1 = SBG::LIB::PWMAP_FACT.createPWMap(); - PWMap pw2 = SBG::LIB::PWMAP_FACT.createPWMap(); - for (unsigned int j = 0; j < map_sz; ++j) { - Set domain1 = SBG::LIB::SET_FACT.createSet(); - Set domain2 = 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}; - Set jth_domain1 = SBG::LIB::SET_FACT.createSet(i1.begin(), i1.step() - , i1.end()); - domain1 = std::move(domain1).disjointCup(std::move(jth_domain1)); - - SBG::LIB::NAT off2 = off + inter_sz/2; - Interval i2{off2 + (h*inter_sz), 1, off2 + (h + 1)*inter_sz - 1}; - Set jth_domain2 = SBG::LIB::SET_FACT.createSet(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}; -} - -//////////////////////////////////////////////////////////////////////////////// -// Benchmarks ------------------------------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -static void BM_UnordPWMapDenseDom(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); - auto pw = denseDom(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw.domain()); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_UnordPWMapDenseDom)->RangeMultiplier(10)->Range(10, 1e3) - ->Complexity(); - -static void BM_UnordPWMapEq(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); - auto [pw1, pw2] = contiguousMaps(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1 == pw2); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_UnordPWMapEq)->RangeMultiplier(10)->Range(10, 1e2)->Complexity(); - -static void BM_UnordPWMapSum(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); - auto [pw1, pw2] = contiguousMaps(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1 + pw2); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_UnordPWMapSum)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); - -static void BM_UnordPWMapDom(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); - auto [pw1, pw2] = contiguousMaps(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.domain()); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_UnordPWMapDom)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); - -static void BM_UnordPWMapRestrict(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); - auto [pw1, pw2] = contiguousMaps(map_sz); - Set domain2 = pw2.domain(); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.restrict(domain2)); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_UnordPWMapRestrict)->RangeMultiplier(10)->Range(10, 1e3) - ->Complexity(); - -static void BM_UnordPWMapImage(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); - auto [pw1, pw2] = contiguousMaps(map_sz); - Set domain2 = pw2.domain(); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.image(domain2)); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_UnordPWMapImage)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); - -static void BM_UnordPWMapPreImage(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); - auto [pw1, pw2] = contiguousMaps(map_sz); - Set img2 = pw2.image(); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.preImage(img2)); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_UnordPWMapPreImage)->RangeMultiplier(10)->Range(10, 1e3) - ->Complexity(); - -static void BM_UnordPWMapComposition(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); - auto [pw1, pw2] = contiguousMaps(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.composition(pw2)); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_UnordPWMapComposition)->RangeMultiplier(10)->Range(10, 1e3) - ->Complexity(); - -static void BM_UnordPWMapConcat(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); - auto [pw1, pw2] = interlacedMaps(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.concatenation(pw2)); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_UnordPWMapConcat)->RangeMultiplier(10)->Range(10, 1e3) - ->Complexity(); - -static void BM_UnordPWMapCombine(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); - auto [pw1, pw2] = contiguousMaps(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.combine(pw2)); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_UnordPWMapCombine)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); - -// TODO: reduce - -static void BM_UnordPWMapMinAdj(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); - auto [pw1, pw2] = minAdjMaps(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.minAdj(pw2)); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_UnordPWMapMinAdj)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); - -static void BM_UnordPWMapEqImage(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); - auto [pw1, pw2] = contiguousMaps(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.equalImage(pw2)); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_UnordPWMapEqImage)->RangeMultiplier(10)->Range(10, 1e3) - ->Complexity(); - -static void BM_UnordPWMapLessImage(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); - auto [pw1, pw2] = contiguousMaps(map_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(pw1.lessImage(pw2)); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_UnordPWMapLessImage)->RangeMultiplier(10)->Range(10, 1e3) - ->Complexity(); - -static void BM_UnordPWMapCompact(benchmark::State& state) -{ - int map_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - SBG::LIB::PWMAP_FACT.set_pwmap_fact(PWMapKind::kUnordered); - auto [pw1, pw2] = contiguousMaps(map_sz); - - for (auto _ : state) { - pw1.compact(); - } - state.SetComplexityN(map_sz); -} -BENCHMARK(BM_UnordPWMapCompact)->RangeMultiplier(10)->Range(10, 1e2) - ->Complexity(); - -} // namespace Internal - -} // namespace Test diff --git a/test/performance/unord_set_bm.cpp b/test/performance/unord_set_bm.cpp deleted file mode 100644 index 55f147e8..00000000 --- a/test/performance/unord_set_bm.cpp +++ /dev/null @@ -1,181 +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/interval.hpp" -#include "sbg/multidim_inter.hpp" -#include "sbg/natural.hpp" -#include "sbg/set.hpp" -#include "sbg/set_fact.hpp" - -#include - -#include -#include - -namespace Test { - -namespace Internal { - -using SBG::LIB::NAT; -using SBG::LIB::detail::Interval; -using SBG::LIB::detail::SetPiece; -using SBG::LIB::SetKind; -using SBG::LIB::Set; - -//////////////////////////////////////////////////////////////////////////////// -// Auxiliary functions --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -/** - * @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; - - 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); - Set jth_s1 = SBG::LIB::SET_FACT.createSet(i1.begin(), i1.step() - , i1.end()); - s1 = s1.disjointCup(jth_s1); - - SBG::LIB::NAT off = inter_sz/2; - Interval i2(off + (h*inter_sz), 1, off + (h + 1)*inter_sz - 1); - Set jth_s2 = SBG::LIB::SET_FACT.createSet(i2.begin(), i2.step(), i2.end()); - s2 = s2.disjointCup(jth_s2); - } - - Set second_dim = SBG::LIB::SET_FACT.createSet(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)); -} - -//////////////////////////////////////////////////////////////////////////////// -// Benchmarks ------------------------------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -static void BM_UnordSetEq(benchmark::State& state) -{ - int set_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - auto [s1, s2] = contiguousPieces(set_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(s1 == s2); - } - state.SetComplexityN(set_sz); -} -BENCHMARK(BM_UnordSetEq)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); - -static void BM_UnordSetCap(benchmark::State& state) -{ - int set_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - auto [s1, s2] = contiguousPieces(set_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(s1.intersection(s2)); - } - state.SetComplexityN(set_sz); -} -BENCHMARK(BM_UnordSetCap)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); - -static void BM_UnordSetCup(benchmark::State& state) -{ - int set_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - auto [s1, s2] = contiguousPieces(set_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(s1.cup(s2)); - } - state.SetComplexityN(set_sz); -} -BENCHMARK(BM_UnordSetCup)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); - -static void BM_UnordSetComplement(benchmark::State& state) -{ - int set_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - auto [s1, s2] = contiguousPieces(set_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(s1.complement()); - } - state.SetComplexityN(set_sz); -} -BENCHMARK(BM_UnordSetComplement)->RangeMultiplier(10)->Range(10, 1e3) - ->Complexity(); - -static void BM_UnordSetDiff(benchmark::State& state) -{ - int set_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - auto [s1, s2] = contiguousPieces(set_sz); - - for (auto _ : state) { - benchmark::DoNotOptimize(s1.difference(s2)); - } - state.SetComplexityN(set_sz); -} -BENCHMARK(BM_UnordSetDiff)->RangeMultiplier(10)->Range(10, 1e3)->Complexity(); - -static void BM_UnordSetDisjointUnion(benchmark::State& state) -{ - int set_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - 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) { - Set jth_s1 = SBG::LIB::SET_FACT.createSet(j*100 + 1, 1, (j + 1)*100); - s1 = std::move(s1.disjointCup(jth_s1)); - Set jth_s2 = SBG::LIB::SET_FACT.createSet((j + 1)*100+1, 1, (j + 2)*100); - s2 = std::move(s2.disjointCup(jth_s2)); - } - - for (auto _ : state) { - benchmark::DoNotOptimize(std::move(s1).disjointCup(std::move(s2))); - } - state.SetComplexityN(set_sz); -} -BENCHMARK(BM_UnordSetDisjointUnion)->RangeMultiplier(10)->Range(10, 1e3) - ->Complexity(); - -static void BM_UnordSetCompact(benchmark::State& state) -{ - int set_sz = state.range(0); - SBG::LIB::SET_FACT.set_set_fact(SetKind::kUnordered); - auto [s1, s2] = contiguousPieces(set_sz); - - for (auto _ : state) { - s1.compact(); - } - state.SetComplexityN(set_sz); -} -BENCHMARK(BM_UnordSetCompact)->RangeMultiplier(10)->Range(10, 1e2) - ->Complexity(); - -} // namespace Internal - -} // namespace Test diff --git a/test/performance/utils.cpp b/test/performance/utils.cpp index a4ddd9a4..798d1232 100644 --- a/test/performance/utils.cpp +++ b/test/performance/utils.cpp @@ -17,25 +17,47 @@ ******************************************************************************/ -#include -#include -#include -#include - #include "algorithms/matching/matching.hpp" #include "algorithms/matching/matching_fact.hpp" -#include "algorithms/misc/causalization_builders.hpp" +#include "algorithms/matching/match_data.hpp" +#include "eval/base_type.hpp" #include "eval/file_evaluator.cpp" -#include "eval/user_impl_map.hpp" +#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/pwmap_fact.hpp" +#include "sbg/rational.hpp" +#include "sbg/set.hpp" +#include "sbg/set_fact.hpp" + +#include +#include +#include +#include +#include +#include + +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) @@ -72,7 +94,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"); @@ -82,12 +104,12 @@ 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); } } @@ -97,17 +119,228 @@ SBG::LIB::BipartiteSBG generateSBG(std::string filename, int N, int copies) //TODO return g.copy(copies); } -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 + BipartiteSBG match_sbg = generateSBG(filename, N, copies); + Matching match_algorithm = SBG::LIB::MATCH_FACT.createMatchAlgorithm(); - SBG::LIB::MatchData match_result = match_algorithm.calculate(match_sbg); + 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 = 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}; + Set jth_s1 = SBG::LIB::SET_FACT.createSet(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 = SBG::LIB::SET_FACT.createSet(i2.begin(), i2.step(), i2.end()); + s2 = s2.disjointCup(jth_s2); + } + + Set second_dim = SBG::LIB::SET_FACT.createSet(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 = SBG::LIB::SET_FACT.createSet(); + Set s2 = SBG::LIB::SET_FACT.createSet(); + for (SBG::LIB::NAT j = 0; j < set_sz; j += 2) { + Set jth_s1 = SBG::LIB::SET_FACT.createSet(j*100, 1, (j + 1)*100 - 1); + s1 = std::move(s1.disjointCup(jth_s1)); + Set jth_s2 = SBG::LIB::SET_FACT.createSet((j + 1)*100, 1, (j + 2)*100 - 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 = SBG::LIB::PWMAP_FACT.createPWMap(); + for (unsigned int j = 0; j < map_sz; ++j) { + Set domain = SBG::LIB::SET_FACT.createSet(); + 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 + = SBG::LIB::SET_FACT.createSet(i.begin(), i.step(), i.end()); + domain = std::move(domain).disjointCup(std::move(jth_domain)); + } + Expression id{1, 0}; + + pw.emplace(domain, id); + } + + return pw; +} + +std::pair minAdjMaps(NAT map_sz) +{ + NAT inter_sz = 100; + NAT set_sz = 10; + + Set second_dim = SBG::LIB::SET_FACT.createSet(0, 1, inter_sz - 1); + PWMap pw1 = SBG::LIB::PWMAP_FACT.createPWMap(); + PWMap pw2 = SBG::LIB::PWMAP_FACT.createPWMap(); + for (unsigned int j = 0; j < map_sz; ++j) { + Set domain1 = SBG::LIB::SET_FACT.createSet(); + Set domain2 = SBG::LIB::SET_FACT.createSet(); + 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 = SBG::LIB::SET_FACT.createSet(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 = SBG::LIB::SET_FACT.createSet(i2.begin(), i2.step() + , i2.end()); + domain2 = std::move(domain2).disjointCup(std::move(jth_domain2)); + } + + Expression id{1, 0}; + Expression minus_one{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 = SBG::LIB::SET_FACT.createSet(0, 1, inter_sz - 1); + PWMap pw1 = SBG::LIB::PWMAP_FACT.createPWMap(); + PWMap pw2 = SBG::LIB::PWMAP_FACT.createPWMap(); + for (unsigned int j = 0; j < map_sz; ++j) { + Set domain1 = SBG::LIB::SET_FACT.createSet(); + Set domain2 = SBG::LIB::SET_FACT.createSet(); + 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 = SBG::LIB::SET_FACT.createSet(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 = SBG::LIB::SET_FACT.createSet(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 = SBG::LIB::SET_FACT.createSet(0, 1, inter_sz - 1); + PWMap pw1 = SBG::LIB::PWMAP_FACT.createPWMap(); + PWMap pw2 = SBG::LIB::PWMAP_FACT.createPWMap(); + for (unsigned int j = 0; j < map_sz; ++j) { + Set domain1 = SBG::LIB::SET_FACT.createSet(); + Set domain2 = SBG::LIB::SET_FACT.createSet(); + 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 = SBG::LIB::SET_FACT.createSet(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 = SBG::LIB::SET_FACT.createSet(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 = SBG::LIB::SET_FACT.createSet(0, 1, inter_sz - 1); + PWMap pw = SBG::LIB::PWMAP_FACT.createPWMap(); + for (unsigned int j = 0; j < map_sz; ++j) { + Set domain = SBG::LIB::SET_FACT.createSet(); + 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 + = SBG::LIB::SET_FACT.createSet(i.begin(), i.step(), i.end()); + domain = std::move(domain).disjointCup(std::move(jth_domain)); + } + domain = domain.cartesianProduct(second_dim); + + Expression plus_one{1, 1}; + Expression id{1, 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/util/user_input_handler.cpp b/util/user_input_handler.cpp index 28cef79b..06d9d131 100644 --- a/util/user_input_handler.cpp +++ b/util/user_input_handler.cpp @@ -59,9 +59,6 @@ UserInputHandler::UserInputHandler() : _generic("Generic options") _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 b3d97943..65faa40a 100644 --- a/util/user_input_handler.hpp +++ b/util/user_input_handler.hpp @@ -43,7 +43,7 @@ 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.) From f33780921f2aaaffcfa0313687d453ee35e3dfb3 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Fri, 10 Apr 2026 17:04:58 -0300 Subject: [PATCH 34/66] Generalized perimeter --- sbg/interval.cpp | 2 ++ sbg/interval.hpp | 3 +++ sbg/map_entry.cpp | 2 +- sbg/map_entry.hpp | 6 +++--- sbg/multidim_inter.cpp | 5 +++++ sbg/multidim_inter.hpp | 3 +++ sbg/ord_set.cpp | 4 ++-- sbg/ord_set.hpp | 6 ++++-- sbg/ord_unidim_dense_set.cpp | 6 +++--- sbg/ord_unidim_dense_set.hpp | 6 ++++-- sbg/{set_perimeter.cpp => perimeter.cpp} | 10 +++++----- sbg/{set_perimeter.hpp => perimeter.hpp} | 22 +++++++++++----------- sbg/set.cpp | 2 +- sbg/set.hpp | 8 ++++---- sbg/unord_set.cpp | 4 ++-- sbg/unord_set.hpp | 4 ++-- 16 files changed, 55 insertions(+), 38 deletions(-) rename sbg/{set_perimeter.cpp => perimeter.cpp} (83%) rename sbg/{set_perimeter.hpp => perimeter.hpp} (67%) diff --git a/sbg/interval.cpp b/sbg/interval.cpp index a21393a7..39c85591 100755 --- a/sbg/interval.cpp +++ b/sbg/interval.cpp @@ -178,6 +178,8 @@ Interval Interval::offset(const NAT off) const return Interval{_begin + off, _step, _end + off}; } +Perimeter Interval::perimeter() const { return Perimeter(_begin, _end); } + MaybeInterval Interval::compact(const Interval& other) const { if (_step == other._step) { diff --git a/sbg/interval.hpp b/sbg/interval.hpp index adf52f7d..cc052285 100755 --- a/sbg/interval.hpp +++ b/sbg/interval.hpp @@ -32,6 +32,7 @@ #define SBGRAPH_SBG_INTERVAL_HPP_ #include "sbg/natural.hpp" +#include "sbg/perimeter.hpp" #include #include @@ -84,6 +85,8 @@ class Interval { */ Interval offset(const NAT off) 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. diff --git a/sbg/map_entry.cpp b/sbg/map_entry.cpp index 1a333800..76768bdf 100755 --- a/sbg/map_entry.cpp +++ b/sbg/map_entry.cpp @@ -37,7 +37,7 @@ MapEntry::MapEntry(const Map& m) const Map& MapEntry::map() const { return _map; } -const SetPerimeter& MapEntry::perimeter() const { return _perimeter; } +const Perimeter& MapEntry::perimeter() const { return _perimeter; } bool MapEntry::operator==(const MapEntry& other) const { diff --git a/sbg/map_entry.hpp b/sbg/map_entry.hpp index 18ecdbd3..282d7d46 100755 --- a/sbg/map_entry.hpp +++ b/sbg/map_entry.hpp @@ -29,7 +29,7 @@ #include "sbg/expression.hpp" #include "sbg/map.hpp" #include "sbg/set.hpp" -#include "sbg/set_perimeter.hpp" +#include "sbg/perimeter.hpp" #include @@ -49,7 +49,7 @@ class MapEntry { MapEntry(const Map& m); const Map& map() const; - const SetPerimeter& perimeter() const; + const Perimeter& perimeter() const; bool operator==(const MapEntry& other) const; bool operator<(const MapEntry& other) const; @@ -58,7 +58,7 @@ class MapEntry { private: Map _map; - SetPerimeter _perimeter; + Perimeter _perimeter; }; } // namespace detail diff --git a/sbg/multidim_inter.cpp b/sbg/multidim_inter.cpp index 4abc1af8..6bb69ff6 100755 --- a/sbg/multidim_inter.cpp +++ b/sbg/multidim_inter.cpp @@ -216,6 +216,11 @@ MultiDimInter MultiDimInter::least(const MultiDimInter& other) const return std::min(*this, other); } +Perimeter MultiDimInter::perimeter() const +{ + return Perimeter{minElem(), maxElem()}; +} + MaybeMDI MultiDimInter::compact(const MultiDimInter& other) const { MultiDimInter result; diff --git a/sbg/multidim_inter.hpp b/sbg/multidim_inter.hpp index a06bb34d..9f71cdaf 100755 --- a/sbg/multidim_inter.hpp +++ b/sbg/multidim_inter.hpp @@ -30,6 +30,7 @@ #include "sbg/interval.hpp" #include "sbg/natural.hpp" +#include "sbg/perimeter.hpp" #include #include @@ -122,6 +123,8 @@ class MultiDimInter { */ 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. diff --git a/sbg/ord_set.cpp b/sbg/ord_set.cpp index f6bd46fa..7451850c 100644 --- a/sbg/ord_set.cpp +++ b/sbg/ord_set.cpp @@ -611,7 +611,7 @@ OrderedSet OrderedSet::offset(const MD_NAT& off) const return result; } -SetPerimeter OrderedSet::perimeter() const +Perimeter OrderedSet::perimeter() const { MD_NAT min; MD_NAT max; @@ -630,7 +630,7 @@ SetPerimeter OrderedSet::perimeter() const } } - return SetPerimeter{min, max}; + return Perimeter{min, max}; } void OrderedSet::compact() diff --git a/sbg/ord_set.hpp b/sbg/ord_set.hpp index 5d380bda..f44ae1cd 100644 --- a/sbg/ord_set.hpp +++ b/sbg/ord_set.hpp @@ -29,7 +29,7 @@ #include "sbg/interval.hpp" #include "sbg/multidim_inter.hpp" #include "sbg/natural.hpp" -#include "sbg/set_perimeter.hpp" +#include "sbg/perimeter.hpp" #include #include @@ -90,7 +90,7 @@ class OrderedSet { OrderedSet disjointCup(OrderedSet&& other) const &; OrderedSet disjointCup(OrderedSet&& other) &&; OrderedSet offset(const MD_NAT& off) const; - SetPerimeter perimeter() const; + Perimeter perimeter() const; void compact(); private: @@ -114,6 +114,8 @@ class OrderedSet { OrderedSet complementAtom() const; OrdMDICollection _pieces; + + friend class SetAccessKey; }; } // namespace detail diff --git a/sbg/ord_unidim_dense_set.cpp b/sbg/ord_unidim_dense_set.cpp index 2de08726..a04d6dcc 100644 --- a/sbg/ord_unidim_dense_set.cpp +++ b/sbg/ord_unidim_dense_set.cpp @@ -365,7 +365,7 @@ OrdUnidimDenseSet OrdUnidimDenseSet::difference(const OrdUnidimDenseSet& other) OrdUnidimDenseSet OrdUnidimDenseSet::cartesianProduct(const OrdUnidimDenseSet& other) const { - Util::ERROR("OrdUnidimDenseSet::cartesianProduct: operation not supported"); + Util::ERROR("OrdUnidimDenseSet::cartesianProduct: operation not supported\n"); return OrdUnidimDenseSet{}; } @@ -433,9 +433,9 @@ OrdUnidimDenseSet OrdUnidimDenseSet::offset(const MD_NAT& offset) const return result; } -SetPerimeter OrdUnidimDenseSet::perimeter() const +Perimeter OrdUnidimDenseSet::perimeter() const { - return SetPerimeter{minElem(), maxElem()}; + return Perimeter{minElem(), maxElem()}; } void OrdUnidimDenseSet::compact() diff --git a/sbg/ord_unidim_dense_set.hpp b/sbg/ord_unidim_dense_set.hpp index 94e42c1c..2b190c6e 100644 --- a/sbg/ord_unidim_dense_set.hpp +++ b/sbg/ord_unidim_dense_set.hpp @@ -32,7 +32,7 @@ #include "sbg/interval.hpp" #include "sbg/multidim_inter.hpp" #include "sbg/natural.hpp" -#include "sbg/set_perimeter.hpp" +#include "sbg/perimeter.hpp" #include #include @@ -92,7 +92,7 @@ class OrdUnidimDenseSet { OrdUnidimDenseSet disjointCup(OrdUnidimDenseSet&& other) const &; OrdUnidimDenseSet disjointCup(OrdUnidimDenseSet&& other) &&; OrdUnidimDenseSet offset(const MD_NAT& offset) const; - SetPerimeter perimeter() const; + Perimeter perimeter() const; void compact(); private: @@ -117,6 +117,8 @@ class OrdUnidimDenseSet { private: OrdIntervalCollection _pieces; + + friend class SetAccessKey; }; } // namespace detail diff --git a/sbg/set_perimeter.cpp b/sbg/perimeter.cpp similarity index 83% rename from sbg/set_perimeter.cpp rename to sbg/perimeter.cpp index d8df3fb7..9dac1e0d 100755 --- a/sbg/set_perimeter.cpp +++ b/sbg/perimeter.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include "sbg/set_perimeter.hpp" +#include "sbg/perimeter.hpp" namespace SBG { @@ -27,14 +27,14 @@ namespace LIB { // Set perimeter --------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -SetPerimeter::SetPerimeter(const MD_NAT& min, const MD_NAT& max) +Perimeter::Perimeter(const MD_NAT& min, const MD_NAT& max) : _min(min), _max(max) {} -const MD_NAT& SetPerimeter::min() const { return _min; } +const MD_NAT& Perimeter::min() const { return _min; } -const MD_NAT& SetPerimeter::max() const { return _max; } +const MD_NAT& Perimeter::max() const { return _max; } -bool SetPerimeter::overlap(const SetPerimeter& other) const +bool Perimeter::overlap(const Perimeter& other) const { std::size_t arity = _min.arity(); for (std::size_t j = 0; j < arity; ++j) { diff --git a/sbg/set_perimeter.hpp b/sbg/perimeter.hpp similarity index 67% rename from sbg/set_perimeter.hpp rename to sbg/perimeter.hpp index 75aadf29..cbf95340 100755 --- a/sbg/set_perimeter.hpp +++ b/sbg/perimeter.hpp @@ -1,10 +1,10 @@ -/** @file set_perimeter.pp +/** @file perimeter.pp - @brief Set Perimeter + @brief Perimeter - The set perimeter is the smallest dense MultiDimInter that contains all of the - elements of the set. Thus, is can be defined using only two multi-dimensional - values. + 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.
@@ -25,8 +25,8 @@ ******************************************************************************/ -#ifndef SBGRAPH_SBG_SET_PERIMETER_HPP_ -#define SBGRAPH_SBG_SET_PERIMETER_HPP_ +#ifndef SBGRAPH_SBG_PERIMETER_HPP_ +#define SBGRAPH_SBG_PERIMETER_HPP_ #include "sbg/natural.hpp" @@ -34,14 +34,14 @@ namespace SBG { namespace LIB { -class SetPerimeter { +class Perimeter { public: - SetPerimeter(const MD_NAT& min, const MD_NAT& max); + Perimeter(const MD_NAT& min, const MD_NAT& max); const MD_NAT& min() const; const MD_NAT& max() const; - bool overlap(const SetPerimeter& other) const; + bool overlap(const Perimeter& other) const; private: MD_NAT _min; @@ -52,4 +52,4 @@ class SetPerimeter { } // namespace SBG -#endif // SBGRAPH_SBG_SET_PERIMETER_HPP_ +#endif // SBGRAPH_SBG_PERIMETER_HPP_ diff --git a/sbg/set.cpp b/sbg/set.cpp index dc26e4bf..c2ba3275 100644 --- a/sbg/set.cpp +++ b/sbg/set.cpp @@ -345,7 +345,7 @@ Set Set::offset(const MD_NAT& off) const , _impl); } -SetPerimeter Set::perimeter() const +Perimeter Set::perimeter() const { return std::visit([](const auto& a) { return a.perimeter(); }, _impl); } diff --git a/sbg/set.hpp b/sbg/set.hpp index 7c84ee9d..9eb30441 100644 --- a/sbg/set.hpp +++ b/sbg/set.hpp @@ -41,7 +41,7 @@ #include "sbg/ord_set.hpp" #include "sbg/ord_unidim_dense_set.hpp" #include "sbg/set.hpp" -#include "sbg/set_perimeter.hpp" +#include "sbg/perimeter.hpp" #include "sbg/unord_set.hpp" #include @@ -62,7 +62,7 @@ using SetImpl = std::variant; -class MapDetail; +class SetAccessKey; } @@ -109,7 +109,7 @@ class Set { Set disjointCup(Set&& other) const &; Set disjointCup(Set&& other) &&; Set offset(const MD_NAT& off) const; - SetPerimeter perimeter() const; + Perimeter perimeter() const; void compact(); private: @@ -118,7 +118,7 @@ class Set { detail::SetImpl _impl; - friend class detail::MapDetail; + friend class detail::SetAccessKey; }; std::ostream& operator<<(std::ostream& out, const Set& s); diff --git a/sbg/unord_set.cpp b/sbg/unord_set.cpp index 78ae0a4e..487f0276 100644 --- a/sbg/unord_set.cpp +++ b/sbg/unord_set.cpp @@ -413,7 +413,7 @@ UnorderedSet UnorderedSet::offset(const MD_NAT& off) const return result; } -SetPerimeter UnorderedSet::perimeter() const +Perimeter UnorderedSet::perimeter() const { MD_NAT min; MD_NAT max; @@ -432,7 +432,7 @@ SetPerimeter UnorderedSet::perimeter() const } } - return SetPerimeter{min, max}; + return Perimeter{min, max}; } void UnorderedSet::compact() diff --git a/sbg/unord_set.hpp b/sbg/unord_set.hpp index 5a5353e0..076cb9e1 100644 --- a/sbg/unord_set.hpp +++ b/sbg/unord_set.hpp @@ -29,7 +29,7 @@ #include "sbg/interval.hpp" #include "sbg/multidim_inter.hpp" #include "sbg/natural.hpp" -#include "sbg/set_perimeter.hpp" +#include "sbg/perimeter.hpp" #include #include @@ -90,7 +90,7 @@ class UnorderedSet { UnorderedSet disjointCup(UnorderedSet&& other) const &; UnorderedSet disjointCup(UnorderedSet&& other) &&; UnorderedSet offset(const MD_NAT& off) const; - SetPerimeter perimeter() const; + Perimeter perimeter() const; void compact(); private: From 522b4da829af191067dae961fd19d652f384811d Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Fri, 10 Apr 2026 17:06:51 -0300 Subject: [PATCH 35/66] Redefined DomOrdPWMap --- sbg/CMakeLists.txt | 5 +- sbg/dom_ord_pwmap.cpp | 1095 +++++++++++++++++++---------------------- sbg/dom_ord_pwmap.hpp | 249 ++++------ sbg/map_detail.cpp | 58 ++- sbg/ord_pwmap.cpp | 28 +- sbg/pw_map.cpp | 3 + sbg/pw_map.hpp | 5 +- sbg/pwmap_detail.cpp | 2 +- sbg/pwmap_detail.hpp | 6 +- sbg/pwmap_fact.cpp | 49 +- sbg/pwmap_fact.hpp | 18 +- sbg/set_detail.cpp | 49 ++ sbg/set_detail.hpp | 65 +++ 13 files changed, 827 insertions(+), 805 deletions(-) create mode 100755 sbg/set_detail.cpp create mode 100755 sbg/set_detail.hpp diff --git a/sbg/CMakeLists.txt b/sbg/CMakeLists.txt index fa2ca98e..3c549b5f 100644 --- a/sbg/CMakeLists.txt +++ b/sbg/CMakeLists.txt @@ -9,6 +9,7 @@ target_sources( PRIVATE bipartite_sbg.cpp directed_sbg.cpp + dom_ord_pwmap.cpp expression.cpp fixed_points.cpp interval.cpp @@ -21,17 +22,17 @@ target_sources( ord_pwmap.cpp ord_set.cpp ord_unidim_dense_set.cpp + perimeter.cpp pw_map.cpp pwmap_detail.cpp pwmap_fact.cpp rational.cpp sbg.cpp set.cpp + set_detail.cpp set_fact.cpp - set_perimeter.cpp unord_pwmap.cpp unord_set.cpp - #dom_ord_pwmap.cpp ) add_custom_target(sbg-doc diff --git a/sbg/dom_ord_pwmap.cpp b/sbg/dom_ord_pwmap.cpp index c03ae513..f5fe454b 100644 --- a/sbg/dom_ord_pwmap.cpp +++ b/sbg/dom_ord_pwmap.cpp @@ -17,159 +17,200 @@ ******************************************************************************/ -#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_fact.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 ---------------------------- +// Auxliary definitions -------------------------------------------------------- + +class MapEntryLess { +public: + bool operator()(const MapEntry& a, const MapEntry& b) const { + return a.map().domain().minElem() < b.map().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(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)) {} -DomOrdPWMap::Iterator::Iterator(OrdMapCollection::const_iterator it) - : it_(it) {} +// Getters --------------------------------------------------------------------- -void DomOrdPWMap::Iterator::operator++() +DomOrdPWMap::ConstIt DomOrdPWMap::begin() const { return _pieces.begin(); } + +DomOrdPWMap::ConstIt DomOrdPWMap::end() const { return _pieces.end(); } + +// 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; + //if (!core_op.orderMatters() + // && long_collection.size() < short_collection.size()) { + // short_collection = rhs; + // long_collection = lhs; + //} + + // 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 +222,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; } + +private: + DomOrdPWMap _result; + std::size_t _global_pos = 0; +}; -PWMapStratPtr DomOrdPWMap::operator+(const PWMapStrategy& other) const +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 +332,93 @@ 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)); + + 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 = SET_FACT.createSet(); + + for (MapEntry& entry : _pieces) { + result = std::move(result).disjointCup(std::move(entry.map()).domain()); } - // 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); + return result; +} + +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)); + + return true; } - 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; - } + bool orderMatters() const { return true; } - // 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; - } + DomOrdPWMap result() const { return DomOrdPWMap(std::move(_result)); } - // 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)); - } +private: + DomOrdPWMap _result; +}; - ++prev_index; - ++curr_index; +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_FACT.kind() + , " set implementation"); + return DomOrdPWMap{}; } + }; - if (indexes.empty()) { - break; - } - } + //print(std::cout); + //std::cout << "\n"; + //std::cout << subdom << "\n"; + //std::visit(restrict_evaluator, key.impl(subdom)).print(std::cout); + //std::cout << "\n\n"; - return std::make_unique(std::move(result)); + return std::visit(restrict_evaluator, key.impl(subdom)); } Set DomOrdPWMap::image() const { Set result = SET_FACT.createSet(); - 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 +426,93 @@ 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)); + + 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) { + Map m = entry.map(); + result.emplace(Map{m.image(), m.law().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)); + + for (const MapEntry& entry : _pieces) { + result = std::move(result).disjointCup(entry.map().fixedPoints()); } return result; @@ -440,441 +520,298 @@ 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); - - int sz = pieces_.size(); - int othr_sz = othr.pieces_.size(); - ord_map.reserve(2*(sz + othr_sz)); - - const DomOrdPWMap *short_pw = this; - const DomOrdPWMap *long_pw = &othr; - if (!order_mts && othr_sz < sz) { - short_pw = &othr; - long_pw = this; + if (isEmpty() || other.isEmpty()) { + return DomOrdPWMap{}; } - std::forward_list indexes; - auto si_it = indexes.before_begin(); + 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 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); + return true; } - 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; - - // 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; - } - - // 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; - } + bool orderMatters() const { return true; } - // 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); - } + DomOrdPWMap result() const { return _result; } - ++prev_index; - ++curr_index; - } +private: + DomOrdPWMap _result; + Set _visited = SET_FACT.createSet(); +}; - if (indexes.empty()) { - break; - } +DomOrdPWMap DomOrdPWMap::minAdj(const DomOrdPWMap& other) const +{ + if (isEmpty() || other.isEmpty()) { + return DomOrdPWMap{}; } + + return traverse(_pieces, other._pieces, MinAdjCore{}).result(); } Set DomOrdPWMap::sharedImage() const { - Set not_present = dom().difference(firstInv()->image()); - Set res = preImage(image(not_present)); + Set repeated_image = SET_FACT.createSet(); + Set visited = SET_FACT.createSet(); + 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 res; + return preImage(repeated_image); } -PWMapStratPtr DomOrdPWMap::offsetDom(const MD_NAT& off) const -{ - OrdMapCollection res; +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)); + } + } - for (const MapEntry& mpe : pieces_){ - Map map(mpe.first.dom().offset(off), mpe.first.exp()); - Internal::emplaceBack(res, map); + return true; } - return std::make_unique(res); -} + bool orderMatters() const { return false; } -PWMapStratPtr DomOrdPWMap::offsetDom(const PWMapStrategy& off) const + Set result() const { return _result; } + +private: + Set _result = SET_FACT.createSet(); +}; + +Set DomOrdPWMap::equalImage(const DomOrdPWMap& other) 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; + if (isEmpty() || other.isEmpty()) { + return SET_FACT.createSet(); } - std::sort(res.begin(),res.end(), operator<); - - return std::make_unique(res); + if (_pieces == other._pieces) { + return domain(); + } + return traverse(_pieces, other._pieces, EqualImageCore{}).result(); } -PWMapStratPtr DomOrdPWMap::offsetImage(const MD_NAT& off) const -{ - OrdMapCollection res; +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)); - 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); - } - - Internal::emplaceBack(res, Map(mpe.first.dom(), res_e)); + return true; } - return std::make_unique(res); -} + bool orderMatters() const { return true; } + + Set result() const { return _result; } -PWMapStratPtr DomOrdPWMap::offsetImage(const Exp& off) const +private: + Set _result = SET_FACT.createSet(); +}; + +Set DomOrdPWMap::lessImage(const DomOrdPWMap& other) const { - OrdMapCollection res; + if (isEmpty() || other.isEmpty()) { + return SET_FACT.createSet(); + } - for (const MapEntry& mpe : pieces_) - Internal::emplaceBack(res, Map(mpe.first.dom(), off + mpe.first.exp())); + if (_pieces == other._pieces) { + return SET_FACT.createSet(); + } - return std::make_unique(res); -} + return traverse(_pieces, other._pieces, LessImageCore{}).result(); +} -PWMapStratPtr DomOrdPWMap::compact() const +void DomOrdPWMap::compact() { + using MapSet = std::set; + OrdMapCollection result; if (!isEmpty()) { - std::set prev(pieces_.begin(), pieces_.end()); - std::set actual = prev; + MapSet set_result{std::make_move_iterator(_pieces.begin()) + , std::make_move_iterator(_pieces.end())}; + 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; + MapEntry ith_compact = *ith; + MapSet::iterator next = ith; ++next; for (; next != last; ++next) { - MaybeMap new_compact = ith_compact.compact(next->first); + MaybeMapEntry 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 MapEntry& map_entry : set_result) { + result.push_back(map_entry); } } - return std::make_unique(result); + _pieces = std::move(result); } +} // namespace detail + } // namespace LIB } // namespace SBG; diff --git a/sbg/dom_ord_pwmap.hpp b/sbg/dom_ord_pwmap.hpp index f713659c..ab945bf7 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,146 @@ ******************************************************************************/ -#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 +#include namespace SBG { namespace LIB { +namespace detail { + //////////////////////////////////////////////////////////////////////////////// -// Domain Ordered PWMap Implementation (concrete strategy) --------------------- +// 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 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; + void compact(); - Set equalImage(const PWMapStrategy& other) const override; - Set lessImage(const PWMapStrategy& other) const override; - Set sharedImage() 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 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; + void insertHint(std::size_t hint, const Map& m); + void insertHint(std::size_t hint, Map&& m); - 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. + * @brief Advances the hint to point the next element that has jth_entry as + * its minimum in its perimeter. */ - void processAdd( - 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 Calculates the lessImage core, which contains the entire main - * process of the function. + * @brief Calculates (if possible) compactly the result of mapInf.\n + * + * Currently, the only expressions that can be efficiently reduced are: + * - x+h + * - x-h */ - 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; - - /** - * @brief Type used in the 'processMapsOrd' declaration to reduce its size. - * This type is the same as the process functions above. - */ - 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 +inline void DomOrdPWMap::emplace(Args&&... args) +{ + insert(Map{std::forward(args)...}); +} + +template +inline void DomOrdPWMap::emplaceBack(Args&&... args) +{ + _pieces.emplace_back(std::forward(args)...); +} + +template +Core traverse(const OrdCollection1& lhs, const OrdCollection2& rhs, Core op); + +} // namespace detail } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_SBG_DOM_ORD_PWMAP_HPP_ diff --git a/sbg/map_detail.cpp b/sbg/map_detail.cpp index 37e1d096..26e80bfc 100755 --- a/sbg/map_detail.cpp +++ b/sbg/map_detail.cpp @@ -21,6 +21,7 @@ #include "sbg/natural.hpp" #include "sbg/ord_unidim_dense_set.hpp" #include "sbg/rational.hpp" +#include "sbg/set_detail.hpp" #include "sbg/set_fact.hpp" #include "sbg/unord_set.hpp" @@ -91,25 +92,26 @@ CompactSetImpl compactImage(const CompactSetImpl& s, const Expr& expr Set MapDetail::image(const Set& s, const Expression& expr) { + SetAccessKey key = SetAccess::key(); auto image_evaluator = Util::Overload { [&](const UnorderedSet& a) { - return Set{detail::compactImage(a, expr._impl, expr.isInjective())}; + return key.createSet(detail::compactImage(a, expr._impl, expr.isInjective())); }, [&](const OrdUnidimDenseSet& a) { - return Set{detail::compactImage( - a, expr._impl[0], expr.isInjective())}; + return key.createSet(detail::compactImage(a, expr._impl[0], expr.isInjective())); }, [&](const OrderedSet& a) { - return Set{detail::compactImage(a, expr._impl, expr.isInjective())}; + return key.createSet(detail::compactImage(a, expr._impl, expr.isInjective())); }, [&](const auto& a) { return Set{SetKind::kUnordered}; } }; - return std::visit(image_evaluator, s._impl); + return std::visit(image_evaluator, key.impl(s)); } // Pre-image ------------------------------------------------------------------- @@ -154,25 +156,26 @@ CompactSetImpl compactPreImage(const CompactSetImpl& s, const Expr& expr) Set MapDetail::preImage(const Set& s, const Expression& expr) { + SetAccessKey key = SetAccess::key(); auto pre_image_evaluator = Util::Overload { [&](const UnorderedSet& a) { - return Set{detail::compactPreImage(a, expr._impl)}; + return key.createSet(detail::compactPreImage(a, expr._impl)); }, [&](const OrdUnidimDenseSet& a) { - return Set{detail::compactPreImage(a, expr._impl[0])}; + return key.createSet(detail::compactPreImage(a, expr._impl[0])); }, [&](const OrderedSet& a) { - return Set{detail::compactPreImage(a, expr._impl)}; + return key.createSet(detail::compactPreImage(a, expr._impl)); }, [&](const auto& a) { return Set{SetKind::kUnordered}; } }; - return std::visit(pre_image_evaluator, s._impl); + return std::visit(pre_image_evaluator, key.impl(s)); } // Less image ------------------------------------------------------------------ @@ -264,27 +267,28 @@ Set MapDetail::lessImage(const Expression& expr1, const Expression& expr2) { Set result = SET_FACT.createSet(); + SetAccessKey key = SetAccess::key(); auto less_image_evaluator = Util::Overload { - [&](UnorderedSet& a) + [&](UnorderedSet&& a) { detail::lessImage( expr1._impl, expr2._impl, a); - return Set{a}; + return key.createSet(a); }, - [&](OrdUnidimDenseSet& a) + [&](OrdUnidimDenseSet&& a) { a.pushBack(detail::lessImage(expr1._impl[0], expr2._impl[0])); - return Set{a}; + return key.createSet(a); }, - [&](OrderedSet& a) + [&](OrderedSet&& a) { detail::lessImage( expr1._impl, expr2._impl, a); - return Set{a}; + return key.createSet(a); }, - [&](auto& a) { return Set{SetKind::kUnordered}; } + [&](auto&& a) { return Set{SetKind::kUnordered}; } }; - return std::visit(less_image_evaluator, result._impl); + return std::visit(less_image_evaluator, key.impl(result)); return result; } @@ -391,6 +395,7 @@ MapVector MapDetail::MDICollectionReduce(const CompactSetImpl& s { MapVector result; + SetAccessKey key = SetAccess::key(); for (const MultiDimInter& mdi : s) { unsigned int k_reduce = 0; AtomicMapVector reduced = detail::reduce(mdi, expr, k_reduce); @@ -401,8 +406,7 @@ MapVector MapDetail::MDICollectionReduce(const CompactSetImpl& s mdi_copy[k_reduce] = r.first; domain.pushBack(mdi_copy); expr_copy[k_reduce] = r.second; - result.emplace_back(Set{domain} - , Expression{expr_copy}); + result.emplace_back(key.createSet(domain), Expression{expr_copy}); } } @@ -414,12 +418,13 @@ MapVector MapDetail::reduce(const OrdUnidimDenseSet& s { 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(Set{domain} + result.emplace_back(key.createSet(domain) , Expression{ExpressionImpl{r.second}}); } } @@ -438,6 +443,7 @@ MapVector MapDetail::reduce(const Map& m) return result; } + SetAccessKey key = SetAccess::key(); auto reduce_evaluator = Util::Overload { [&](const UnorderedSet& a) { @@ -453,7 +459,7 @@ MapVector MapDetail::reduce(const Map& m) }, [&](const auto& a) { return Set{SetKind::kUnordered}; } }; - return std::visit(reduce_evaluator, m.domain()._impl); + return std::visit(reduce_evaluator, key.impl(m.domain())); } } // namespace detail diff --git a/sbg/ord_pwmap.cpp b/sbg/ord_pwmap.cpp index 865634d6..fbba880a 100644 --- a/sbg/ord_pwmap.cpp +++ b/sbg/ord_pwmap.cpp @@ -19,6 +19,7 @@ #include "sbg/set_fact.hpp" #include "sbg/ord_pwmap.hpp" +#include "sbg/perimeter.hpp" #include #include @@ -82,8 +83,7 @@ void OrdPWMap::insert(Map&& m) { if (!m.isEmpty()) { MapEntry entry{m}; - if (isEmpty() - || _pieces.back().perimeter().min() < entry.perimeter().min()) { + if (isEmpty() || _pieces.back() < entry) { _pieces.push_back(entry); } else { insertHint(0, std::move(m)); @@ -157,13 +157,12 @@ std::size_t OrdPWMap::advanceHint(std::size_t hint, const MapEntry& jth_entry) // Traverse -------------------------------------------------------------------- -template -CoreOperation OrdPWMap::traverse(const OrdPWMap& other, CoreOperation core_op) - const +template +Core OrdPWMap::traverse(const OrdPWMap& other, Core core_op) const { OrdMapCollection short_pw = _pieces; OrdMapCollection long_pw = other._pieces; - if (!core_op.orderMatters() && other._pieces.size() < _pieces.size()) { + if (!core_op.orderMatters() && long_pw.size() < short_pw.size()) { short_pw = other._pieces; long_pw = _pieces; } @@ -177,14 +176,14 @@ CoreOperation OrdPWMap::traverse(const OrdPWMap& other, CoreOperation core_op) auto short_begin = short_pw.begin(); for (const MapEntry& long_mpe : long_pw) { - const SetPerimeter& long_perimeter = long_mpe.perimeter(); + 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 SetPerimeter& short_perimeter = short_mpe.perimeter(); + const Perimeter& short_perimeter = short_mpe.perimeter(); // Here short_map is "before" long_map, so it is also "before" all the // remaining sets in long_pw, thus it can be discarded. @@ -360,10 +359,10 @@ OrdPWMap OrdPWMap::restrict(const Set& subdom) const OrdPWMap result; NAT global_pos = 0; - SetPerimeter subdom_perimeter = subdom.perimeter(); + Perimeter subdom_perimeter = subdom.perimeter(); const MD_NAT subdom_max_perimeter = subdom_perimeter.max(); for (const MapEntry& entry : _pieces) { - const SetPerimeter& entry_perimeter = entry.perimeter(); + 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)); @@ -428,12 +427,12 @@ OrdPWMap OrdPWMap::composition(const OrdPWMap& other) const Map other_map = other_entry.map(); Set img = other_map.image(); - SetPerimeter img_perimeter = img.perimeter(); + 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 SetPerimeter& entry_perimeter = entry.perimeter(); + const Perimeter& entry_perimeter = entry.perimeter(); if (entry_perimeter.overlap(img_perimeter)) { Map composed = entry.map().composition(other_map); result.insertHint(global_pos, composed); @@ -622,7 +621,7 @@ class MinAdjCore { _result = std::move(min_adj_result).combine(std::move(_result)); _visited = std::move(_visited).cup(std::move(min_adj_domain)); } else { - _result.pushBack(std::move(min_adj)); + _result.insert(std::move(min_adj)); _visited = std::move(_visited).disjointCup(std::move(min_adj_domain)); } } @@ -740,7 +739,8 @@ void OrdPWMap::compact() OrdMapCollection result; if (!isEmpty()) { - MapSet set_result; + MapSet set_result{std::make_move_iterator(_pieces.begin()) + , std::make_move_iterator(_pieces.end())}; MapSet to_erase; do { MapSet new_set_result; diff --git a/sbg/pw_map.cpp b/sbg/pw_map.cpp index 4b0e669b..caa57e06 100644 --- a/sbg/pw_map.cpp +++ b/sbg/pw_map.cpp @@ -112,6 +112,7 @@ PWMap::PWMap(const PWMapKind kind) : _impl() } case PWMapKind::kDomOrdered: { + _impl = detail::DomOrdPWMap{}; break; } @@ -136,6 +137,7 @@ PWMap::PWMap(const PWMapKind kind, Set s) : _impl() } case PWMapKind::kDomOrdered: { + _impl = detail::DomOrdPWMap{s}; break; } @@ -160,6 +162,7 @@ PWMap::PWMap(const PWMapKind kind, Map m) : _impl() } case PWMapKind::kDomOrdered: { + _impl = detail::DomOrdPWMap{m}; break; } diff --git a/sbg/pw_map.hpp b/sbg/pw_map.hpp index e8496045..23d7e31b 100644 --- a/sbg/pw_map.hpp +++ b/sbg/pw_map.hpp @@ -34,9 +34,10 @@ #ifndef SBGRAPH_SBG_PW_MAP_HPP_ #define SBGRAPH_SBG_PW_MAP_HPP_ +#include "sbg/dom_ord_pwmap.hpp" #include "sbg/map.hpp" -#include "sbg/set.hpp" #include "sbg/ord_pwmap.hpp" +#include "sbg/set.hpp" #include "sbg/unord_pwmap.hpp" namespace SBG { @@ -49,7 +50,7 @@ namespace detail { // PWMaps implementations ------------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// -using PWMapImpl = std::variant; +using PWMapImpl = std::variant; class PWMapAccessKey; diff --git a/sbg/pwmap_detail.cpp b/sbg/pwmap_detail.cpp index 45c890f2..dcd2f454 100755 --- a/sbg/pwmap_detail.cpp +++ b/sbg/pwmap_detail.cpp @@ -25,7 +25,7 @@ namespace LIB { namespace detail { -PWMap PWMapAccessKey::reduce(PWMap pw) +PWMap PWMapAccessKey::reduce(PWMap pw) const { auto& impl = pw._impl; return std::visit( diff --git a/sbg/pwmap_detail.hpp b/sbg/pwmap_detail.hpp index a2669e16..a3d3e451 100755 --- a/sbg/pwmap_detail.hpp +++ b/sbg/pwmap_detail.hpp @@ -24,8 +24,8 @@ ******************************************************************************/ -#ifndef SBGRAPH_SBG_PWMAP_DETAIL__HPP_ -#define SBGRAPH_SBG_PWMAP_DETAIL__HPP_ +#ifndef SBGRAPH_SBG_PWMAP_DETAIL_HPP_ +#define SBGRAPH_SBG_PWMAP_DETAIL_HPP_ #include "sbg/pw_map.hpp" @@ -37,7 +37,7 @@ namespace detail { class PWMapAccessKey { public: - PWMap reduce(PWMap pw); + PWMap reduce(PWMap pw) const; private: PWMapAccessKey() = default; diff --git a/sbg/pwmap_fact.cpp b/sbg/pwmap_fact.cpp index 1f4ce337..2b3fc85b 100644 --- a/sbg/pwmap_fact.cpp +++ b/sbg/pwmap_fact.cpp @@ -66,27 +66,27 @@ PWMap OrdPWMapFact::createPWMap(const Map& m) const return PWMap{PWMapKind::kOrdered, m}; } -////////////////////////////////////////////////////////////////////////////////// -//// 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)); -//} -// +//////////////////////////////////////////////////////////////////////////////// +// DomOrdPWMap Factory --------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +DomOrdPWMapFact::DomOrdPWMapFact() {} + +PWMap DomOrdPWMapFact::createPWMap() const +{ + return PWMap{PWMapKind::kDomOrdered}; +} + +PWMap DomOrdPWMapFact::createPWMap(const Set &s) const +{ + return PWMap{PWMapKind::kDomOrdered, s}; +} + +PWMap DomOrdPWMapFact::createPWMap(const Map &m) const +{ + return PWMap{PWMapKind::kDomOrdered, m}; +} + //////////////////////////////////////////////////////////////////////////////// // Factory for clients --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// @@ -116,9 +116,10 @@ void PWMapFactory::set_pwmap_fact(PWMapKind kind) break; } - //case PWMapKind::kDomOrdered: { - // _impl = DomOrdPWMapFact{}; - //} + case PWMapKind::kDomOrdered: { + _impl = DomOrdPWMapFact{}; + break; + } default: { Util::ERROR("Unsupported ", kind, " PWMap implementation\n"); diff --git a/sbg/pwmap_fact.hpp b/sbg/pwmap_fact.hpp index 31eaeee1..021c36d2 100644 --- a/sbg/pwmap_fact.hpp +++ b/sbg/pwmap_fact.hpp @@ -52,14 +52,14 @@ class OrdPWMapFact { PWMap createPWMap(const Map& m) const; }; -//class DomOrdPWMapFact { -// public: -// DomOrdPWMapFact(); -// -// PWMap createPWMap() const override; -// PWMap createPWMap(const Set& s) const override; -// PWMap createPWMap(const Map& m) const override; -//}; +class DomOrdPWMapFact { +public: + DomOrdPWMapFact(); + + PWMap createPWMap() const; + PWMap createPWMap(const Set& s) const; + PWMap createPWMap(const Map& m) const; +}; /** * @brief Single instance of pw factory to be used by clients in need of @@ -80,7 +80,7 @@ class PWMapFactory { PWMap createPWMap(Map m) const; private: - using FactImpl = std::variant; + using FactImpl = std::variant; PWMapFactory(); diff --git a/sbg/set_detail.cpp b/sbg/set_detail.cpp new file mode 100755 index 00000000..60d99c50 --- /dev/null +++ b/sbg/set_detail.cpp @@ -0,0 +1,49 @@ +/******************************************************************************* + + 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" + +namespace SBG { + +namespace LIB { + +namespace detail { + +SetImpl SetAccessKey::impl(Set s) const { return s._impl; } + +Set SetAccessKey::createSet(SetImpl s_impl) const { return Set{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..8d446211 --- /dev/null +++ b/sbg/set_detail.hpp @@ -0,0 +1,65 @@ +/** @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" + +namespace SBG { + +namespace LIB { + +namespace detail { + +class SetAccessKey { +public: + SetImpl impl(Set s) const; + Set createSet(SetImpl s_impl) const; + + OrderedSet::OrdMDICollection pieces(OrderedSet s) const; + OrdUnidimDenseSet::OrdIntervalCollection pieces(OrdUnidimDenseSet s) const; + +private: + SetAccessKey() = default; + + friend class SetAccess; +}; + +class SetAccess { +public: + static SetAccessKey key(); +}; + +} // namespace detail + +} // namespace LIB + +} // namespace SBG + +#endif // SBGRAPH_SBG_SET_DETAIL_HPP_ From 8df368ec1809f420124a022bffacd3467b398921 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Mon, 13 Apr 2026 15:34:15 -0300 Subject: [PATCH 36/66] Small fixes --- algorithms/matching/bfs_matching.cpp | 1 + eval/visitors/autom_impl_visitor.cpp | 1 - eval/visitors/set_impl_visitor.cpp | 1 - sbg/expression.cpp | 1 - sbg/map_detail.cpp | 4 ++-- sbg/rational.cpp | 8 ++++---- sbg/rational.hpp | 10 +++++----- sbg/sbg.cpp | 10 ++++++---- test/performance/scc_bm.cpp | 2 +- test/performance/utils.cpp | 6 ++++-- 10 files changed, 23 insertions(+), 21 deletions(-) diff --git a/algorithms/matching/bfs_matching.cpp b/algorithms/matching/bfs_matching.cpp index 5e58393d..ef438dea 100644 --- a/algorithms/matching/bfs_matching.cpp +++ b/algorithms/matching/bfs_matching.cpp @@ -178,6 +178,7 @@ MatchData BFSMatching::calculate(const BipartiteSBG& bsbg) Util::Internal::TimeProfiler profiler{"Total matching exec time: "}; init(bsbg); + Util::SBG_LOG << "Matching bipartite SBG: " << bsbg << "\n\n"; _X = bsbg.X(); _Y = bsbg.Y(); diff --git a/eval/visitors/autom_impl_visitor.cpp b/eval/visitors/autom_impl_visitor.cpp index a1ad44ea..042deeaf 100755 --- a/eval/visitors/autom_impl_visitor.cpp +++ b/eval/visitors/autom_impl_visitor.cpp @@ -39,7 +39,6 @@ EvalUserInput AutomImplVisitor::visit(AST::SBGProgram p) const { // Statement inspection ------------------------------------------------------ - LIB::NAT dims = 1; AST::IsConfig cfg_visit; EvalContext eval_context; if (!p.stms().empty()) { diff --git a/eval/visitors/set_impl_visitor.cpp b/eval/visitors/set_impl_visitor.cpp index 7a9526f9..80f82e27 100755 --- a/eval/visitors/set_impl_visitor.cpp +++ b/eval/visitors/set_impl_visitor.cpp @@ -47,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()); diff --git a/sbg/expression.cpp b/sbg/expression.cpp index b2b25415..941cb830 100755 --- a/sbg/expression.cpp +++ b/sbg/expression.cpp @@ -193,7 +193,6 @@ FixedPointsInfo Expression::fixedPoints() const { std::vector result; - std::optional empty = {}; for (unsigned int k = 0; k < arity(); ++k) { detail::LinearExpr kth = _impl[k]; if (kth.isId()) { diff --git a/sbg/map_detail.cpp b/sbg/map_detail.cpp index 26e80bfc..851cdb82 100755 --- a/sbg/map_detail.cpp +++ b/sbg/map_detail.cpp @@ -373,10 +373,10 @@ AtomicMapVector reduce(const MultiDimInter& mdi, const ExpressionImpl& expr , unsigned int& k_reduce) { // Identify reducible dimension k_reduce - unsigned int arity = mdi.arity(); + std::size_t arity = mdi.arity(); Interval reducible_interval; LinearExpr reducible_expr; - for (auto k = 0; k < arity; ++k) { + 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; diff --git a/sbg/rational.cpp b/sbg/rational.cpp index 51e66679..3c30995d 100755 --- a/sbg/rational.cpp +++ b/sbg/rational.cpp @@ -29,9 +29,9 @@ namespace LIB { RATIONAL::RATIONAL() : _value() {} -RATIONAL::RATIONAL(INT n) : _value(RatType{n, 1}) {} +RATIONAL::RATIONAL(INT n) : _value(RATIONAL::RATIONALT{n, 1}) {} -RATIONAL::RATIONAL(const RatType& value) : _value(value) {} +RATIONAL::RATIONAL(const RATIONAL::RATIONALT& value) : _value(value) {} RATIONAL::RATIONAL(INT n, INT d) : _value() { @@ -41,7 +41,7 @@ RATIONAL::RATIONAL(INT n, INT d) : _value() // Getters --------------------------------------------------------------------- -const RatType& RATIONAL::value() const { return _value; } +const RATIONAL::RATIONALT& RATIONAL::value() const { return _value; } INT RATIONAL::numerator() const { return _value.numerator(); } @@ -136,7 +136,7 @@ INT RATIONAL::ceiling() const 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) { diff --git a/sbg/rational.hpp b/sbg/rational.hpp index e9cb2b67..5e0f9314 100755 --- a/sbg/rational.hpp +++ b/sbg/rational.hpp @@ -46,13 +46,13 @@ namespace LIB { using INT = long long int; constexpr INT INT_Inf = std::numeric_limits::max(); -using RatType = boost::rational; - /** * @brief Used as coefficients and slopes in linear expressions. */ class RATIONAL { public: + using RATIONALT = boost::rational; + /** * @brief Zero constructor. */ @@ -66,7 +66,7 @@ class RATIONAL { /** * @brief Copy constructor. */ - RATIONAL(const RatType& value); + RATIONAL(const RATIONALT& value); /** * @brief Construct rational r = n/d. @@ -76,7 +76,7 @@ class RATIONAL { RATIONAL(const RATIONAL& r) = default; RATIONAL(RATIONAL&& r) = default; - const RatType& value() const; + const RATIONALT& value() const; INT numerator() const; INT denominator() const; @@ -101,7 +101,7 @@ class RATIONAL { INT ceiling() const; private: - RatType _value; + RATIONALT _value; }; std::ostream& operator<<(std::ostream& out, const RATIONAL& r); diff --git a/sbg/sbg.cpp b/sbg/sbg.cpp index 0e792e91..016cebcc 100644 --- a/sbg/sbg.cpp +++ b/sbg/sbg.cpp @@ -65,7 +65,8 @@ const PWMap& SBG::Emap() const { return _Emap; } void SBG::addSetVertex(const Set& vertices) { if (!vertices.intersection(_V).isEmpty()) { - Util::ERROR("Trying to add existing vertices: ", vertices, " to SBG\n"); + 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(); @@ -82,8 +83,8 @@ void SBG::addSetEdge(const PWMap& pw1, const PWMap& pw2) Set edges1 = pw1.domain(); Set edges2 = pw2.domain(); if (edges1 != edges2) { - // TODO - Util::ERROR("The domain of ", edges1, " is different from ", edges2, "\n"); + Util::ERROR("SBG::addSetEdge: ", edges1, " is different from ", edges2 + , "\n"); } else if (edges1.intersection(_E).isEmpty()) { Set edges = edges1; if (!edges.isEmpty()) { @@ -97,7 +98,8 @@ void SBG::addSetEdge(const PWMap& pw1, const PWMap& pw2) _Emap.emplace(edges, max + one_all_dims); } } else { - Util::ERROR("Trying to add existing edges: ", edges1, " to SBG\n"); + Util::ERROR("SBG::addSetEdge: trying to add existing edges: ", edges1 + , " to SBG\n"); } } diff --git a/test/performance/scc_bm.cpp b/test/performance/scc_bm.cpp index a6a6da04..c1cb1e52 100644 --- a/test/performance/scc_bm.cpp +++ b/test/performance/scc_bm.cpp @@ -101,7 +101,7 @@ void registerSCCBenchmarks(std::string filename) benchmark::RegisterBenchmark( ("BM_SCCCopies/" + filename).c_str(), [filename](benchmark::State& state) { - BM_SCCWithBuilder(state, filename); + BM_SCCCopies(state, filename); } )->RangeMultiplier(2)->Range(1, 128)->Complexity() ->Unit(benchmark::kMillisecond); diff --git a/test/performance/utils.cpp b/test/performance/utils.cpp index 798d1232..9510ed09 100644 --- a/test/performance/utils.cpp +++ b/test/performance/utils.cpp @@ -166,9 +166,11 @@ std::pair interlacedPieces(NAT set_sz) 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) { - Set jth_s1 = SBG::LIB::SET_FACT.createSet(j*100, 1, (j + 1)*100 - 1); + Set jth_s1 = SBG::LIB::SET_FACT.createSet(j*inter_sz, 1 + , (j + 1)*inter_sz - 1); s1 = std::move(s1.disjointCup(jth_s1)); - Set jth_s2 = SBG::LIB::SET_FACT.createSet((j + 1)*100, 1, (j + 2)*100 - 1); + Set jth_s2 = SBG::LIB::SET_FACT.createSet((j + 1)*inter_sz, 1 + , (j + 2)*inter_sz - 1); s2 = std::move(s2.disjointCup(jth_s2)); } From 1902dc15cf841770888da1262f8b6cfde7c3f37a Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Mon, 13 Apr 2026 15:34:36 -0300 Subject: [PATCH 37/66] Added copy for Bipartite SBGs --- eval/visitors/func_evaluator.cpp | 12 ++---- sbg/bipartite_sbg.cpp | 71 ++++++++++++++++++++++++++++++-- sbg/bipartite_sbg.hpp | 2 + 3 files changed, 73 insertions(+), 12 deletions(-) diff --git a/eval/visitors/func_evaluator.cpp b/eval/visitors/func_evaluator.cpp index 7db3c59b..5763386f 100755 --- a/eval/visitors/func_evaluator.cpp +++ b/eval/visitors/func_evaluator.cpp @@ -703,12 +703,10 @@ ExprBaseType BuiltInFunctions::matchingEvaluator(const EBTList& args) LIB::Matching match_impl = LIB::MATCH_FACT.createMatchAlgorithm(); const auto matching_evaluator = Util::Overload { [&match_impl](LIB::BipartiteSBG a, LIB::NAT b) { - // TODO return ExprBaseType{match_impl.calculate(a.copy(b))}; - return ExprBaseType{match_impl.calculate(a)}; + return ExprBaseType{match_impl.calculate(copy(b, a))}; }, [&match_impl](LIB::BipartiteSBG a, LIB::MD_NAT b) { - // TODO return ExprBaseType{match_impl.calculate(a.copy(b[0]))}; - return ExprBaseType{match_impl.calculate(a)}; + return ExprBaseType{match_impl.calculate(copy(b[0], a))}; }, [](auto a, auto b) { Util::ERROR("matchingEvaluator: wrong arguments ", a, ", ", b @@ -784,14 +782,12 @@ ExprBaseType BuiltInFunctions::matchSCCEvaluator(const EBTList& args) LIB::SCC scc_impl = LIB::SCC_FACT.createSCCAlgorithm(); const auto match_scc_evaluator = Util::Overload { [&match_impl, &scc_impl](LIB::BipartiteSBG a, LIB::NAT b) { - // TODO LIB::MatchData match_result = match_impl.calculate(a.copy(b)); - LIB::MatchData match_result = match_impl.calculate(a); + LIB::MatchData match_result = match_impl.calculate(copy(b, a)); LIB::DirectedSBG dsbg = misc::buildSCCFromMatching(match_result); return ExprBaseType{scc_impl.calculate(dsbg).rmap()}; }, [&match_impl, &scc_impl](LIB::BipartiteSBG a, LIB::MD_NAT b) { - // TODO LIB::MatchData match_result = match_impl.calculate(a.copy(b[0])); - LIB::MatchData match_result = match_impl.calculate(a); + LIB::MatchData match_result = match_impl.calculate(copy(b[0], a)); LIB::DirectedSBG dsbg = misc::buildSCCFromMatching(match_result); return ExprBaseType{scc_impl.calculate(dsbg).rmap()}; }, diff --git a/sbg/bipartite_sbg.cpp b/sbg/bipartite_sbg.cpp index 243ee832..074d00ad 100644 --- a/sbg/bipartite_sbg.cpp +++ b/sbg/bipartite_sbg.cpp @@ -67,7 +67,8 @@ void BipartiteSBG::addSetVertex(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"); + 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(); @@ -86,8 +87,8 @@ void BipartiteSBG::addSetEdge(const PWMap& pw1, const PWMap& pw2) Set edges1 = pw1.domain(); Set edges2 = pw2.domain(); if (edges1 != edges2) { - // TODO - Util::ERROR("The domain of ", edges1, " is different from ", edges2, "\n"); + Util::ERROR("BipartiteSBG::addSetEdge: ", edges1, " is different from " + , edges2, "\n"); } else if (edges1.intersection(_E).isEmpty()) { Set edges = edges1; if (!edges.isEmpty()) { @@ -102,7 +103,8 @@ void BipartiteSBG::addSetEdge(const PWMap& pw1, const PWMap& pw2) _Emap.emplace(edges, max + one_all_dims); } } else { - Util::ERROR("Trying to add existing edges: ", edges1, " to SBG\n"); + Util::ERROR("BipartiteSBG::addSetEdge: trying to add existing edges: " + , edges1, " to SBG\n"); } } @@ -122,6 +124,67 @@ std::ostream& operator<<(std::ostream& out, const BipartiteSBG& g) return out; } +// Extra operations ------------------------------------------------------------ + +BipartiteSBG copy(unsigned int copies, BipartiteSBG sbg) +{ + if (copies == 0) { + Util::ERROR("BipartiteSBG::copy: zeros copies is not allowed\n"); + } + + 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_FACT.createSet(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); + } + + Expression offset_v; + for (std::size_t k = 0; k < max_v.arity(); ++k) { + offset_v = offset_v.cartesianProduct(Expression{1, max_v[k]}); + } + PWMap offset_pw_v = PWMAP_FACT.createPWMap(Map{V, offset_v}); + + 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{1, max_e[k]}); + } + PWMap offset_pw_e = PWMAP_FACT.createPWMap(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_FACT.createSet(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); + } + } + + return sbg; +} + } // namespace LIB } // namespace SBG diff --git a/sbg/bipartite_sbg.hpp b/sbg/bipartite_sbg.hpp index 37e5aaec..d004f16d 100644 --- a/sbg/bipartite_sbg.hpp +++ b/sbg/bipartite_sbg.hpp @@ -97,6 +97,8 @@ class BipartiteSBG { std::ostream& operator<<(std::ostream& out, const BipartiteSBG& g); +BipartiteSBG copy(unsigned int copies, BipartiteSBG sbg); + } // namespace LIB } // namespace SBG From a4fc9ffc30adf6ba56b973776b0cb052791c1603 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Tue, 14 Apr 2026 15:23:53 -0300 Subject: [PATCH 38/66] Redefined boost performance test [IN PROGRESS] --- sbg/interval.cpp | 14 +- sbg/set_detail.cpp | 63 +++++++++ sbg/set_detail.hpp | 10 ++ sbg/unord_set.hpp | 2 + test/performance/CMakeLists.txt | 7 +- test/performance/boost/CMakeLists.txt | 17 --- .../boost/ordinary_graph_builder.cpp | 124 ------------------ .../{ordinary_graph.cpp => scalar_graph.cpp} | 14 +- .../{ordinary_graph.hpp => scalar_graph.hpp} | 24 ++-- .../boost/scalar_graph_builder.cpp | 113 ++++++++++++++++ ...h_builder.hpp => scalar_graph_builder.hpp} | 26 ++-- test/performance/boost/scc_graph_builder.cpp | 17 ++- test/performance/boost/scc_graph_builder.hpp | 31 +++-- 13 files changed, 276 insertions(+), 186 deletions(-) delete mode 100644 test/performance/boost/CMakeLists.txt delete mode 100644 test/performance/boost/ordinary_graph_builder.cpp rename test/performance/boost/{ordinary_graph.cpp => scalar_graph.cpp} (94%) rename test/performance/boost/{ordinary_graph.hpp => scalar_graph.hpp} (84%) create mode 100644 test/performance/boost/scalar_graph_builder.cpp rename test/performance/boost/{ordinary_graph_builder.hpp => scalar_graph_builder.hpp} (76%) diff --git a/sbg/interval.cpp b/sbg/interval.cpp index 39c85591..e79bf820 100755 --- a/sbg/interval.cpp +++ b/sbg/interval.cpp @@ -23,7 +23,11 @@ #include #include -namespace { +namespace SBG { + +namespace LIB { + +namespace detail { // Auxiliary functions --------------------------------------------------------- @@ -37,14 +41,6 @@ bool isMember(const SBG::LIB::NAT x, const SBG::LIB::detail::Interval& i) return rem == 0; } -} // namespace - -namespace SBG { - -namespace LIB { - -namespace detail { - // Constructors/Destructors ---------------------------------------------------- Interval::Interval() : _begin(1), _step(1), _end(0) {} diff --git a/sbg/set_detail.cpp b/sbg/set_detail.cpp index 60d99c50..979b15c3 100755 --- a/sbg/set_detail.cpp +++ b/sbg/set_detail.cpp @@ -18,6 +18,9 @@ ******************************************************************************/ #include "sbg/set_detail.hpp" +#include "util/defs.hpp" + +#include namespace SBG { @@ -25,10 +28,70 @@ 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(); + for (unsigned int j = 0; j < mdi_sz; ++j) { + unsigned int accumulated_sz = 1; + for (std::size_t k = 0; k < arity; ++k) { + Interval i = mdi[k]; + accumulated_sz *= i.cardinal(); + x[k] = i.begin() + i.step()*fmod(j, accumulated_sz); + } + } + } + + 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; diff --git a/sbg/set_detail.hpp b/sbg/set_detail.hpp index 8d446211..c62bfc02 100755 --- a/sbg/set_detail.hpp +++ b/sbg/set_detail.hpp @@ -31,16 +31,22 @@ #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; + MaybeMD_NAT nextElem(const MD_NAT& current, const Set& s) const; + std::vector flatten(const Set& s) const; OrderedSet::OrdMDICollection pieces(OrderedSet s) const; OrdUnidimDenseSet::OrdIntervalCollection pieces(OrdUnidimDenseSet s) const; @@ -48,6 +54,10 @@ class SetAccessKey { private: SetAccessKey() = default; + template + std::vector flatten(const SetImplT& s) const; + std::vector flatten(const OrdUnidimDenseSet& s) const; + friend class SetAccess; }; diff --git a/sbg/unord_set.hpp b/sbg/unord_set.hpp index 076cb9e1..75f4c0ac 100644 --- a/sbg/unord_set.hpp +++ b/sbg/unord_set.hpp @@ -100,6 +100,8 @@ class UnorderedSet { UnorderedSet complementAtom() const; MDIUnordCollection _pieces; + + friend class SetAccessKey; }; } // namespace detail diff --git a/test/performance/CMakeLists.txt b/test/performance/CMakeLists.txt index 58369ed7..aa9dcbab 100644 --- a/test/performance/CMakeLists.txt +++ b/test/performance/CMakeLists.txt @@ -1,8 +1,11 @@ -# SBG Benchmark for different Set and PWMap implementations +# SBG Benchmark for different Set, PWMap, and SBG algorithms implementations add_executable(sbg-benchmark main.cpp) target_sources(sbg-benchmark PRIVATE + boost/scalar_graph.cpp + boost/scalar_graph_builder.cpp + boost/scc_graph_builder.cpp main.cpp bm_exec.cpp matching_bm.cpp @@ -27,5 +30,3 @@ target_link_libraries(sbg-benchmark PRIVATE sbg-dev sbg-eval-lib) - -#add_subdirectory(boost) 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/ordinary_graph_builder.cpp b/test/performance/boost/ordinary_graph_builder.cpp deleted file mode 100644 index cc8dbce2..00000000 --- a/test/performance/boost/ordinary_graph_builder.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/multidim_inter.hpp" -#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::detail::MultiDimInter mdi) -{ - SBG::LIB::MD_NAT min = mdi.minElem(); - SBG::LIB::MD_NAT max = mdi.maxElem(); - SBG::LIB::MD_NAT result; - for (unsigned int j = 0; j < mdi.arity(); ++j) { - if (curr[j] == max[j]) { - result.pushBack(min[j]); - } else { - result.pushBack(curr[j] + 1); - for (unsigned int k = 1; k < mdi.arity() - j; ++k) { - result.pushBack(curr[j + k]); - } - break; - } - } - - return result; -} - -//////////////////////////////////////////////////////////////////////////////// -// 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(); - SBG::LIB::MD_NAT 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(); - SBG::LIB::MD_NAT 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..c32ac99b --- /dev/null +++ b/test/performance/boost/scalar_graph_builder.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 "sbg/multidim_inter.hpp" +#include "sbg/set_detail.hpp" +#include "sbg/set_fact.hpp" +#include "test/performance/boost/scalar_graph_builder.hpp" +#include "util/time_profiler.hpp" + +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_FACT.createSet(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_FACT.createSet(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 76% rename from test/performance/boost/ordinary_graph_builder.hpp rename to test/performance/boost/scalar_graph_builder.hpp index 2b579744..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,22 +25,26 @@ ******************************************************************************/ -#ifndef SBGRAPH_TEST_PERFORMANCE_BOOST_ORDINARY_GRAPH_BUILDER_HPP_ -#define SBGRAPH_TEST_PERFORMANCE_BOOST_ORDINARY_GRAPH_BUILDER_HPP_ +#ifndef SBGRAPH_TEST_PERFORMANCE_BOOST_SCALAR_GRAPH_BUILDER_HPP_ +#define SBGRAPH_TEST_PERFORMANCE_BOOST_SCALAR_GRAPH_BUILDER_HPP_ #include "sbg/bipartite_sbg.hpp" #include "sbg/natural.hpp" -#include "test/performance/boost/ordinary_graph.hpp" +#include "test/performance/boost/scalar_graph.hpp" #include "util/logger.hpp" #include #include -namespace OG { +namespace SBG { -class OrdinaryGraphBuilder { +namespace perf { + +namespace detail { + +class ScalarGraphBuilder { public: - OrdinaryGraphBuilder(SBG::LIB::BipartiteSBG bsbg); + ScalarGraphBuilder(SBG::LIB::BipartiteSBG bsbg); BipartiteGraph build(); BipartiteGraph build(SBG::LIB::NAT number_vertices, EdgeVector& edges @@ -55,6 +59,10 @@ class OrdinaryGraphBuilder { std::vector _partition; }; -} // namespace OG +} // namespace detail + +} // namespace perf + +} // namespace SBG -#endif // SBGRAPH_TEST_PERFORMANCE_BOOST_ORRDINARY_GRAPH_BUILDER_HPP_ +#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_ From 3c383bec922d37468c2bfe88fca400490ad58d1f Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 16 Apr 2026 16:31:39 -0300 Subject: [PATCH 39/66] Redefined boost performance benchmark --- sbg/set_detail.cpp | 12 +- test/README.md | 12 -- test/performance/CMakeLists.txt | 1 + test/performance/bm_exec.cpp | 64 ++++---- test/performance/boost/boost_bm.cpp | 136 +++++++++++++++++ test/performance/boost/boost_bm.hpp | 50 ++++++ test/performance/boost/custom_boost_bm.cpp | 144 ------------------ .../boost/scalar_graph_builder.cpp | 2 + test/performance/matching_bm.cpp | 1 - 9 files changed, 234 insertions(+), 188 deletions(-) create mode 100644 test/performance/boost/boost_bm.cpp create mode 100644 test/performance/boost/boost_bm.hpp delete mode 100644 test/performance/boost/custom_boost_bm.cpp diff --git a/sbg/set_detail.cpp b/sbg/set_detail.cpp index 979b15c3..62e84c00 100755 --- a/sbg/set_detail.cpp +++ b/sbg/set_detail.cpp @@ -46,12 +46,14 @@ std::vector SetAccessKey::flatten(const SetImplT& s) const 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 accumulated_sz = 1; - for (std::size_t k = 0; k < arity; ++k) { - Interval i = mdi[k]; - accumulated_sz *= i.cardinal(); - x[k] = i.begin() + i.step()*fmod(j, accumulated_sz); + 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; } } } diff --git a/test/README.md b/test/README.md index 54a4d02e..05fe4605 100755 --- a/test/README.md +++ b/test/README.md @@ -31,15 +31,3 @@ 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. - -In the ./test/build/bin there are also some helpful binaries: - - boost-perf: used to evaluate the performance of traditional graphs - algorithms. - - 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). diff --git a/test/performance/CMakeLists.txt b/test/performance/CMakeLists.txt index aa9dcbab..20af5a35 100644 --- a/test/performance/CMakeLists.txt +++ b/test/performance/CMakeLists.txt @@ -3,6 +3,7 @@ add_executable(sbg-benchmark main.cpp) target_sources(sbg-benchmark PRIVATE + boost/boost_bm.cpp boost/scalar_graph.cpp boost/scalar_graph_builder.cpp boost/scc_graph_builder.cpp diff --git a/test/performance/bm_exec.cpp b/test/performance/bm_exec.cpp index 7cb2ae70..16fcc2b1 100644 --- a/test/performance/bm_exec.cpp +++ b/test/performance/bm_exec.cpp @@ -17,16 +17,18 @@ ******************************************************************************/ +#include "test/performance/bm_exec.hpp" #include "algorithms/matching/matching_fact.hpp" #include "algorithms/scc/scc_fact.hpp" #include "eval/user_impl_map.hpp" #include "sbg/pwmap_fact.hpp" #include "sbg/set_fact.hpp" -#include "test/performance/bm_exec.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 @@ -85,7 +87,8 @@ BMExecutor::BMExecutor() ("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)"); + "\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); @@ -137,37 +140,46 @@ void BMExecutor::execute(int argc, char* argv[]) SBG::Eval::setSCCFactory(*_scc_impl); printHeader(vm); - switch (*_benchmark) { - case 0: { - registerSetBenchmarks(); - break; + 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 1: { + registerPWMapBenchmarks(); + break; + } - case 2: { - if (_input_file) { - registerMatchingBenchmarks(*_input_file); - } else { - registerMatchingBenchmarks(); + case 2: { + if (_input_file) { + registerMatchingBenchmarks(*_input_file); + } else { + registerMatchingBenchmarks(); + } + break; } - break; - } - case 3: { - if (_input_file) { - registerSCCBenchmarks(*_input_file); - } else { - registerSCCBenchmarks(); + case 3: { + if (_input_file) { + registerSCCBenchmarks(*_input_file); + } else { + registerSCCBenchmarks(); + } + break; } - break; - } - default: { - break; + default: { + break; + } } } 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/scalar_graph_builder.cpp b/test/performance/boost/scalar_graph_builder.cpp index c32ac99b..916355f8 100644 --- a/test/performance/boost/scalar_graph_builder.cpp +++ b/test/performance/boost/scalar_graph_builder.cpp @@ -23,6 +23,8 @@ #include "test/performance/boost/scalar_graph_builder.hpp" #include "util/time_profiler.hpp" +#include + namespace SBG { namespace perf { diff --git a/test/performance/matching_bm.cpp b/test/performance/matching_bm.cpp index b930c818..92760965 100644 --- a/test/performance/matching_bm.cpp +++ b/test/performance/matching_bm.cpp @@ -19,7 +19,6 @@ #include "algorithms/matching/matching.hpp" #include "algorithms/matching/matching_fact.hpp" -#include "eval/user_impl_map.hpp" #include "sbg/bipartite_sbg.hpp" #include "test/performance/utils.hpp" #include "test/performance/matching_bm.hpp" From c6a1c3f6bb218f13715bdc23c4e42c1225ac20b0 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Tue, 21 Apr 2026 12:29:56 -0300 Subject: [PATCH 40/66] Added set-vertex and set-edge traversals --- algorithms/matching/bfs_matching.cpp | 12 ++++------ sbg/bipartite_sbg.hpp | 33 ++++++++++++++++++++++++++ sbg/directed_sbg.hpp | 35 ++++++++++++++++++++++++++-- sbg/dom_ord_pwmap.hpp | 2 ++ sbg/ord_pwmap.hpp | 2 ++ sbg/pw_map.hpp | 2 ++ sbg/sbg.hpp | 32 +++++++++++++++++++++++++ sbg/unord_pwmap.hpp | 2 ++ 8 files changed, 111 insertions(+), 9 deletions(-) diff --git a/algorithms/matching/bfs_matching.cpp b/algorithms/matching/bfs_matching.cpp index ef438dea..300c26ee 100644 --- a/algorithms/matching/bfs_matching.cpp +++ b/algorithms/matching/bfs_matching.cpp @@ -18,6 +18,7 @@ ******************************************************************************/ #include "algorithms/matching/bfs_matching.hpp" +#include "sbg/natural.hpp" #include "sbg/pwmap_fact.hpp" #include "sbg/set_fact.hpp" #include "util/logger.hpp" @@ -78,10 +79,9 @@ PWMap BFSMatching::partitionSubsetEdges() const std::size_t arity = free_edges.arity(); NAT j = 1; PWMap Emap = _dsbg.Emap(); - Set set_edges = Emap.image(); - while (!set_edges.isEmpty()) { - Set min_elem_set = SET_FACT.createSet(set_edges.minElem()); - Set domain_edges = Emap.preImage(min_elem_set); + _dsbg.foreachSetEdge([&](const MD_NAT& SE) + { + Set domain_edges = Emap.preImage(SET_FACT.createSet(SE)); Expression matched_expr{MD_NAT{arity, j}}; result.emplace(_M.intersection(domain_edges), matched_expr); @@ -90,9 +90,7 @@ PWMap BFSMatching::partitionSubsetEdges() const Expression free_expr{MD_NAT{arity, j}}; result.emplace(free_edges.intersection(domain_edges), free_expr); ++j; - - set_edges = set_edges.difference(min_elem_set); - } + }); return result; } diff --git a/sbg/bipartite_sbg.hpp b/sbg/bipartite_sbg.hpp index d004f16d..b4e1b5a0 100644 --- a/sbg/bipartite_sbg.hpp +++ b/sbg/bipartite_sbg.hpp @@ -29,6 +29,7 @@ #include "sbg/pw_map.hpp" #include "sbg/set.hpp" +#include "sbg/set_fact.hpp" #include @@ -84,6 +85,12 @@ class BipartiteSBG { */ void addSetEdge(const PWMap& pw1, const PWMap& pw2); + template + void foreachSetVertex(FuncT&& f) const; + + template + void foreachSetEdge(FuncT&& f) const; + private: Set _V; ///< Vertex definitions PWMap _Vmap; @@ -97,6 +104,32 @@ class BipartiteSBG { 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_FACT.createSet(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_FACT.createSet(x)); + } +} + +// Extra operations ------------------------------------------------------------ + BipartiteSBG copy(unsigned int copies, BipartiteSBG sbg); } // namespace LIB diff --git a/sbg/directed_sbg.hpp b/sbg/directed_sbg.hpp index d95511d1..d9f545e4 100644 --- a/sbg/directed_sbg.hpp +++ b/sbg/directed_sbg.hpp @@ -40,6 +40,7 @@ #define SBGRAPH_SBG_DIRECTED_SBG_HPP_ #include "sbg/set.hpp" +#include "sbg/set_fact.hpp" #include "sbg/pw_map.hpp" #include @@ -89,11 +90,17 @@ class DirectedSBG { void addSetEdge(const PWMap& pw1, const PWMap& pw2); /** - * @brief Erase vertices \p vs from the DirectedSBG, together with associated edges - * with \p vs. + * @brief Erase vertices \p vs from the DirectedSBG, together with associated + * edges with \p vs. */ void eraseVertices(const Set& vs); + template + void foreachSetVertex(FuncT&& f) const; + + template + void foreachSetEdge(FuncT&& f) const; + private: Set _V; ///< Vertices definitions PWMap _Vmap; @@ -105,6 +112,30 @@ class DirectedSBG { 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_FACT.createSet(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_FACT.createSet(x)); + } +} + } // namespace LIB } // namespace SBG diff --git a/sbg/dom_ord_pwmap.hpp b/sbg/dom_ord_pwmap.hpp index ab945bf7..497ac898 100644 --- a/sbg/dom_ord_pwmap.hpp +++ b/sbg/dom_ord_pwmap.hpp @@ -146,6 +146,8 @@ class DomOrdPWMap { friend class PWMapAccessKey; }; +// Template definitions -------------------------------------------------------- + template inline void DomOrdPWMap::emplace(Args&&... args) { diff --git a/sbg/ord_pwmap.hpp b/sbg/ord_pwmap.hpp index acf7c632..3819092b 100644 --- a/sbg/ord_pwmap.hpp +++ b/sbg/ord_pwmap.hpp @@ -143,6 +143,8 @@ class OrdPWMap { friend class PWMapAccessKey; }; +// Template definitions -------------------------------------------------------- + template inline void OrdPWMap::emplace(Args&&... args) { diff --git a/sbg/pw_map.hpp b/sbg/pw_map.hpp index 23d7e31b..9ffcfd48 100644 --- a/sbg/pw_map.hpp +++ b/sbg/pw_map.hpp @@ -247,6 +247,8 @@ class PWMap { std::ostream& operator<<(std::ostream& out, const PWMap& pw); +// Template definitions -------------------------------------------------------- + template inline void PWMap::emplace(Args&&... args) { diff --git a/sbg/sbg.hpp b/sbg/sbg.hpp index fcc2f4ef..3c394032 100644 --- a/sbg/sbg.hpp +++ b/sbg/sbg.hpp @@ -41,6 +41,7 @@ #include "sbg/pw_map.hpp" #include "sbg/set.hpp" +#include "sbg/set_fact.hpp" #include @@ -92,6 +93,12 @@ class SBG { */ void addSetEdge(const PWMap& pw1, const PWMap& pw2); + template + void foreachSetVertex(FuncT&& f) const; + + template + void foreachSetEdge(FuncT&& f) const; + private: Set _V; ///< Vertex definitions PWMap _Vmap; @@ -103,6 +110,31 @@ class SBG { 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_FACT.createSet(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_FACT.createSet(x)); + } +} + + } // namespace LIB } // namespace SBG diff --git a/sbg/unord_pwmap.hpp b/sbg/unord_pwmap.hpp index 9fe8191a..379a691a 100644 --- a/sbg/unord_pwmap.hpp +++ b/sbg/unord_pwmap.hpp @@ -126,6 +126,8 @@ class UnordPWMap { friend class PWMapAccessKey; }; +// Template definitions -------------------------------------------------------- + template inline void UnordPWMap::emplace(Args&&... args) { From 2796986de0c5a44517b246a3bb5880371e13a5ba Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Tue, 21 Apr 2026 12:30:27 -0300 Subject: [PATCH 41/66] Debugge SCC graph creation [SLOW] --- algorithms/misc/causalization_builders.cpp | 94 +++++++++++++++++++++- 1 file changed, 90 insertions(+), 4 deletions(-) diff --git a/algorithms/misc/causalization_builders.cpp b/algorithms/misc/causalization_builders.cpp index bceef6af..4d70db36 100644 --- a/algorithms/misc/causalization_builders.cpp +++ b/algorithms/misc/causalization_builders.cpp @@ -20,20 +20,25 @@ #include "algorithms/misc/causalization_builders.hpp" #include "sbg/bipartite_sbg.hpp" #include "sbg/set.hpp" +#include "sbg/set_fact.hpp" #include "sbg/pw_map.hpp" #include "sbg/pwmap_fact.hpp" #include "sbg/map.hpp" #include "util/time_profiler.hpp" +#include + namespace misc { -SBG::LIB::DirectedSBG buildSCCFromMatching(const SBG::LIB::MatchData& data) -{ - SBG::Util::Internal::TimeProfiler profiler{"SBG SCC builder: "}; +//////////////////////////////////////////////////////////////////////////////// +// Algebraic loops graph ------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// +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); M.compact(); SBG::LIB::Set V = M; @@ -45,6 +50,15 @@ SBG::LIB::DirectedSBG buildSCCFromMatching(const SBG::LIB::MatchData& data) 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(); @@ -58,20 +72,92 @@ SBG::LIB::DirectedSBG 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.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.compact(); SBG::LIB::PWMap Emap = bsbg.Emap().restrict(free_edges); + Emap.compact(); + + return {mapB, mapD, Emap}; +} + +SBG::LIB::PWMap partitionEmap(const SBG::LIB::DirectedSBG& dsbg) +{ + 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 = dsbg.V().arity(); + SBG::LIB::NAT j = 1; + SBG::LIB::PWMap partitioned_Emap = SBG::LIB::PWMAP_FACT.createPWMap(); + dsbg.foreachSetEdge([&](const SBG::LIB::MD_NAT& SE) + { + SBG::LIB::Set E = Emap.preImage(SBG::LIB::SET_FACT.createSet(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_FACT.createSet(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_FACT.createSet(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; + } + }); + + return partitioned_Emap; +} + +SBG::LIB::DirectedSBG buildSCCFromMatching(const SBG::LIB::MatchData& data) +{ + SBG::Util::Internal::TimeProfiler profiler{"SBG SCC builder: "}; + + SBG::LIB::Set V = SBG::LIB::SET_FACT.createSet(); + SBG::LIB::PWMap Vmap = SBG::LIB::PWMAP_FACT.createPWMap(); + std::tie(V, Vmap) = buildSCCVertices(data); + + SBG::LIB::PWMap mapB = SBG::LIB::PWMAP_FACT.createPWMap(); + SBG::LIB::PWMap mapD = SBG::LIB::PWMAP_FACT.createPWMap(); + SBG::LIB::PWMap Emap = SBG::LIB::PWMAP_FACT.createPWMap(); + std::tie(mapB, mapD, Emap) = buildSCCEdges(data, Vmap); + + SBG::LIB::DirectedSBG dsbg{V, Vmap, mapB, mapD, Emap}; + Emap = partitionEmap(dsbg); return SBG::LIB::DirectedSBG{V, Vmap, mapB, mapD, Emap}; } +//////////////////////////////////////////////////////////////////////////////// +// Vertical ordering graph ----------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + SBG::LIB::DirectedSBG buildSortFromSCC(const SBG::LIB::SCCData& data) { SBG::Util::Internal::TimeProfiler profiler{"SBG Topological Sort builder: "}; From e8ba29d9b804c2a9b40f3ed177c1bb4ecabea75e Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Tue, 21 Apr 2026 15:13:35 -0300 Subject: [PATCH 42/66] Updated PWMap::compact for SCC graph builder --- algorithms/misc/causalization_json.cpp | 20 +++++++--------- algorithms/scc/decreasing_edges_mrv.cpp | 1 + algorithms/scc/minreach_scc.cpp | 2 +- sbg/dom_ord_pwmap.cpp | 32 +++++++++++++++---------- sbg/ord_pwmap.cpp | 32 +++++++++++++++---------- sbg/unord_pwmap.cpp | 12 +++++++--- 6 files changed, 58 insertions(+), 41 deletions(-) diff --git a/algorithms/misc/causalization_json.cpp b/algorithms/misc/causalization_json.cpp index 29d830ea..021fcd02 100644 --- a/algorithms/misc/causalization_json.cpp +++ b/algorithms/misc/causalization_json.cpp @@ -30,7 +30,7 @@ using namespace SBG::LIB; rapidjson::Value setJson(const Set &s , rapidjson::Document::AllocatorType &alloc) { - rapidjson::Value res(rapidjson::kArrayType); + rapidjson::Value result(rapidjson::kArrayType); for (const SetPiece &mdi : s) { rapidjson::Value inter_array(rapidjson::kArrayType); @@ -51,15 +51,15 @@ rapidjson::Value setJson(const Set &s } rapidjson::Value mdi_obj(rapidjson::kObjectType); mdi_obj.AddMember("interval", inter_array, alloc); - res.PushBack(mdi_obj, alloc); + result.PushBack(mdi_obj, alloc); } - return res; + return result; } rapidjson::Value expJson(Exp exp, rapidjson::Document::AllocatorType &alloc) { - rapidjson::Value res(rapidjson::kArrayType); + rapidjson::Value result(rapidjson::kArrayType); for (const LExp &le : exp) { rapidjson::Value le_array(rapidjson::kArrayType); @@ -76,17 +76,17 @@ rapidjson::Value expJson(Exp exp, rapidjson::Document::AllocatorType &alloc) h.SetString(ssh.str().c_str(), strlen(ssh.str().c_str()), alloc); le_array.PushBack(h, alloc); - res.PushBack(le_array, alloc); + result.PushBack(le_array, alloc); } - return res; + return result; } rapidjson::Value mapJson( const PWMap &pw, rapidjson::Document::AllocatorType &alloc ) { - rapidjson::Value res(rapidjson::kArrayType); + rapidjson::Value result(rapidjson::kArrayType); for (const Map &map : pw) { rapidjson::Value ith(rapidjson::kObjectType); @@ -94,10 +94,10 @@ rapidjson::Value mapJson( ith.AddMember("dom", setJson(map.dom(), alloc), alloc); ith.AddMember("exp", expJson(map.exp(), alloc), alloc); - res.PushBack(ith, alloc); + result.PushBack(ith, alloc); } - return res; + return result; } void buildJson(const Set &matching, const PWMap &scc, const PWMap &order) @@ -127,8 +127,6 @@ void buildJson(const Set &matching, const PWMap &scc, const PWMap &order) d.Accept(writer); fclose(fp); - - return; } } // namespace MISC diff --git a/algorithms/scc/decreasing_edges_mrv.cpp b/algorithms/scc/decreasing_edges_mrv.cpp index 78c99b78..5eab1e91 100644 --- a/algorithms/scc/decreasing_edges_mrv.cpp +++ b/algorithms/scc/decreasing_edges_mrv.cpp @@ -131,6 +131,7 @@ PWMap LtEdgesMRV::calculate(const DirectedSBG& dsbg) // Calculate representatives map rmap = _smap.mapInf(); rmap = rmap.min(old_rmap).combine(std::move(rmap)); + rmap.compact(); } while (!E.isEmpty()); } diff --git a/algorithms/scc/minreach_scc.cpp b/algorithms/scc/minreach_scc.cpp index c864b2a0..5f482b31 100644 --- a/algorithms/scc/minreach_scc.cpp +++ b/algorithms/scc/minreach_scc.cpp @@ -71,10 +71,10 @@ SCCData MinReachSCC::calculate(const DirectedSBG& dsbg) do { oldE = _dsbg.E(); rmap = sccStep(); + rmap.compact(); Ediff = oldE.difference(_dsbg.E()); deleted_edges = std::move(deleted_edges).disjointCup(Ediff); } while (Ediff != SET_FACT.createSet()); - rmap.compact(); Util::DEBUG_LOG << "MinReachSCC result: " << rmap << "\n\n"; diff --git a/sbg/dom_ord_pwmap.cpp b/sbg/dom_ord_pwmap.cpp index f5fe454b..1be84ae8 100644 --- a/sbg/dom_ord_pwmap.cpp +++ b/sbg/dom_ord_pwmap.cpp @@ -42,12 +42,12 @@ namespace detail { // Domain Ordered PWMap Implementation ----------------------------------------- //////////////////////////////////////////////////////////////////////////////// -// Auxliary definitions -------------------------------------------------------- +// Auxiliary definitions ------------------------------------------------------- -class MapEntryLess { +class MapLess { public: - bool operator()(const MapEntry& a, const MapEntry& b) const { - return a.map().domain().minElem() < b.map().domain().minElem(); + bool operator()(const Map& a, const Map& b) const { + return a.domain().minElem() < b.domain().minElem(); } }; @@ -768,13 +768,19 @@ Set DomOrdPWMap::lessImage(const DomOrdPWMap& other) const void DomOrdPWMap::compact() { - using MapSet = std::set; + using MapSet = std::set; - OrdMapCollection result; + DomOrdPWMap result; if (!isEmpty()) { - MapSet set_result{std::make_move_iterator(_pieces.begin()) - , std::make_move_iterator(_pieces.end())}; + 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 { MapSet new_set_result; @@ -783,11 +789,11 @@ void DomOrdPWMap::compact() MapSet::iterator ith = set_result.begin(); MapSet::iterator last = set_result.end(); for (; ith != last; ++ith) { - MapEntry ith_compact = *ith; + Map ith_compact = *ith; MapSet::iterator next = ith; ++next; for (; next != last; ++next) { - MaybeMapEntry new_compact = ith_compact.compact(*next); + MaybeMap new_compact = ith_compact.compact(*next); if (new_compact) { ith_compact = new_compact.value(); to_erase.insert(*next); @@ -802,12 +808,12 @@ void DomOrdPWMap::compact() std::swap(set_result, new_set_result); } while (!to_erase.empty()); - for (const MapEntry& map_entry : set_result) { - result.push_back(map_entry); + for (const Map& m : set_result) { + result.insert(m); } } - _pieces = std::move(result); + _pieces = std::move(result._pieces); } } // namespace detail diff --git a/sbg/ord_pwmap.cpp b/sbg/ord_pwmap.cpp index fbba880a..d2eda1b0 100644 --- a/sbg/ord_pwmap.cpp +++ b/sbg/ord_pwmap.cpp @@ -35,12 +35,12 @@ namespace detail { // Ordered PWMap Implementation ------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// -// Auxliary definitions -------------------------------------------------------- +// Auxiliary definitions ------------------------------------------------------- -class MapEntryLess { +class MapLess { public: - bool operator()(const MapEntry& a, const MapEntry& b) const { - return a.map().domain().minElem() < b.map().domain().minElem(); + bool operator()(const Map& a, const Map& b) const { + return a.domain().minElem() < b.domain().minElem(); } }; @@ -734,13 +734,19 @@ Set OrdPWMap::lessImage(const OrdPWMap& other) const void OrdPWMap::compact() { - using MapSet = std::set; + using MapSet = std::set; - OrdMapCollection result; + OrdPWMap result; if (!isEmpty()) { - MapSet set_result{std::make_move_iterator(_pieces.begin()) - , std::make_move_iterator(_pieces.end())}; + 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 { MapSet new_set_result; @@ -749,11 +755,11 @@ void OrdPWMap::compact() MapSet::iterator ith = set_result.begin(); MapSet::iterator last = set_result.end(); for (; ith != last; ++ith) { - MapEntry ith_compact = *ith; + Map ith_compact = *ith; MapSet::iterator next = ith; ++next; for (; next != last; ++next) { - MaybeMapEntry new_compact = ith_compact.compact(*next); + MaybeMap new_compact = ith_compact.compact(*next); if (new_compact) { ith_compact = new_compact.value(); to_erase.insert(*next); @@ -768,12 +774,12 @@ void OrdPWMap::compact() std::swap(set_result, new_set_result); } while (!to_erase.empty()); - for (const MapEntry& map_entry : set_result) { - result.push_back(map_entry); + for (const Map& m : set_result) { + result.insert(m); } } - _pieces = std::move(result); + _pieces = std::move(result._pieces); } } // namespace detail diff --git a/sbg/unord_pwmap.cpp b/sbg/unord_pwmap.cpp index 1cea09d4..e3df6b16 100644 --- a/sbg/unord_pwmap.cpp +++ b/sbg/unord_pwmap.cpp @@ -20,6 +20,7 @@ #include "sbg/set_fact.hpp" #include "sbg/unord_pwmap.hpp" +#include #include #include #include @@ -34,7 +35,7 @@ namespace detail { // Unordered PWMap Implementation ---------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -// Auxliary definitions -------------------------------------------------------- +// Auxiliary definitions ------------------------------------------------------- class MapLess { public: @@ -487,8 +488,13 @@ void UnordPWMap::compact() UnordMapCollection result; if (!isEmpty()) { - MapSet set_result{std::make_move_iterator(_pieces.begin()) - , std::make_move_iterator(_pieces.end())}; + MapSet set_result; + for (const Map& m : _pieces) { + Set new_domain = m.domain(); + new_domain.compact(); + set_result.emplace(new_domain, m.law()); + } + MapSet to_erase; do { MapSet new_set_result; From b09ac6f7f4b27d3a235b9153556c76a9c15b7ada Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Wed, 22 Apr 2026 18:26:14 -0300 Subject: [PATCH 43/66] Added imageMultiplicity --- eval/visitors/expr_evaluator.cpp | 1 + eval/visitors/func_evaluator.cpp | 16 ++++ eval/visitors/func_evaluator.hpp | 1 + sbg/dom_ord_pwmap.cpp | 20 +++++ sbg/dom_ord_pwmap.hpp | 3 + sbg/map.cpp | 5 ++ sbg/map.hpp | 7 ++ sbg/map_detail.cpp | 142 ++++++++++++++++++++++++++++++- sbg/map_detail.hpp | 8 ++ sbg/ord_pwmap.cpp | 20 +++++ sbg/ord_pwmap.hpp | 3 + sbg/pw_map.cpp | 6 ++ sbg/pw_map.hpp | 2 + sbg/set_detail.hpp | 1 - sbg/unord_pwmap.cpp | 16 +++- sbg/unord_pwmap.hpp | 2 + 16 files changed, 247 insertions(+), 6 deletions(-) diff --git a/eval/visitors/expr_evaluator.cpp b/eval/visitors/expr_evaluator.cpp index 347aa506..b5297fa8 100755 --- a/eval/visitors/expr_evaluator.cpp +++ b/eval/visitors/expr_evaluator.cpp @@ -70,6 +70,7 @@ ExprEvaluator::ExprEvaluator(EvalContext& eval_ctx) : _eval_context(eval_ctx) eval_ctx.insertFunction("minMap", BuiltInFunctions::minMapEvaluator); 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); diff --git a/eval/visitors/func_evaluator.cpp b/eval/visitors/func_evaluator.cpp index 5763386f..3ea7612f 100755 --- a/eval/visitors/func_evaluator.cpp +++ b/eval/visitors/func_evaluator.cpp @@ -677,6 +677,22 @@ ExprBaseType BuiltInFunctions::mapInfEvaluator(const EBTList& args) }; 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 ------------------------------------------------------ diff --git a/eval/visitors/func_evaluator.hpp b/eval/visitors/func_evaluator.hpp index 6e97088d..ea7dcd91 100755 --- a/eval/visitors/func_evaluator.hpp +++ b/eval/visitors/func_evaluator.hpp @@ -90,6 +90,7 @@ 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); diff --git a/sbg/dom_ord_pwmap.cpp b/sbg/dom_ord_pwmap.cpp index 1be84ae8..385a65a3 100644 --- a/sbg/dom_ord_pwmap.cpp +++ b/sbg/dom_ord_pwmap.cpp @@ -67,6 +67,12 @@ DomOrdPWMap::DomOrdPWMap(const Map& m) : _pieces() { } } +DomOrdPWMap::DomOrdPWMap(const std::vector& pieces) : _pieces() { + for (const Map& m : pieces) { + insert(m); + } +} + DomOrdPWMap::DomOrdPWMap(const DomOrdPWMap::OrdMapCollection& pieces) : _pieces(pieces) {} @@ -766,6 +772,20 @@ Set DomOrdPWMap::lessImage(const DomOrdPWMap& other) const return traverse(_pieces, other._pieces, LessImageCore{}).result(); } +DomOrdPWMap DomOrdPWMap::imageMultiplicity() const +{ + Map initial_result{image(), Expression{arity(), 0, 0}}; + DomOrdPWMap result{initial_result}; + + 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 result; +} + void DomOrdPWMap::compact() { using MapSet = std::set; diff --git a/sbg/dom_ord_pwmap.hpp b/sbg/dom_ord_pwmap.hpp index 497ac898..ac8ea5ab 100644 --- a/sbg/dom_ord_pwmap.hpp +++ b/sbg/dom_ord_pwmap.hpp @@ -53,6 +53,7 @@ class DomOrdPWMap { DomOrdPWMap(); DomOrdPWMap(const Set& s); DomOrdPWMap(const Map& m); + DomOrdPWMap(const std::vector& pieces); DomOrdPWMap(const OrdMapCollection& pieces); DomOrdPWMap(OrdMapCollection&& pieces); @@ -103,6 +104,8 @@ class DomOrdPWMap { Set equalImage(const DomOrdPWMap& other) const; Set lessImage(const DomOrdPWMap& other) const; + DomOrdPWMap imageMultiplicity() const; + void compact(); private: diff --git a/sbg/map.cpp b/sbg/map.cpp index 4da8a4fa..5d1a192e 100755 --- a/sbg/map.cpp +++ b/sbg/map.cpp @@ -189,6 +189,11 @@ 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 result_domain = SET_FACT.createSet(); diff --git a/sbg/map.hpp b/sbg/map.hpp index a177fb92..7780f027 100755 --- a/sbg/map.hpp +++ b/sbg/map.hpp @@ -35,6 +35,7 @@ #include #include +#include namespace SBG { @@ -148,6 +149,12 @@ class Map { */ std::vector reduce() const; + /** + * @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. diff --git a/sbg/map_detail.cpp b/sbg/map_detail.cpp index 851cdb82..1938e2e9 100755 --- a/sbg/map_detail.cpp +++ b/sbg/map_detail.cpp @@ -24,6 +24,10 @@ #include "sbg/set_detail.hpp" #include "sbg/set_fact.hpp" #include "sbg/unord_set.hpp" +#include "util/debug.hpp" + +#include +#include namespace SBG { @@ -109,7 +113,11 @@ Set MapDetail::image(const Set& s, const Expression& expr) return key.createSet(detail::compactImage(a, expr._impl, expr.isInjective())); }, - [&](const auto& a) { return Set{SetKind::kUnordered}; } + [&](const auto& a) + { + Util::ERROR("MapDetail::image: unsupported Set implementation"); + return Set{SetKind::kUnordered}; + } }; return std::visit(image_evaluator, key.impl(s)); } @@ -173,7 +181,11 @@ Set MapDetail::preImage(const Set& s, const Expression& expr) return key.createSet(detail::compactPreImage(a, expr._impl)); }, - [&](const auto& a) { return Set{SetKind::kUnordered}; } + [&](const auto& a) + { + Util::ERROR("MapDetail::preImage: unsupported Set implementation"); + return Set{SetKind::kUnordered}; + } }; return std::visit(pre_image_evaluator, key.impl(s)); } @@ -286,7 +298,11 @@ Set MapDetail::lessImage(const Expression& expr1, const Expression& expr2) expr1._impl, expr2._impl, a); return key.createSet(a); }, - [&](auto&& a) { return Set{SetKind::kUnordered}; } + [&](auto&& a) + { + Util::ERROR("MapDetail::lessImage: unsupported Set implementation"); + return Set{SetKind::kUnordered}; + } }; return std::visit(less_image_evaluator, key.impl(result)); @@ -457,11 +473,129 @@ MapVector MapDetail::reduce(const Map& m) { return MDICollectionReduce(a, law._impl); }, - [&](const auto& a) { return Set{SetKind::kUnordered}; } + [&](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 diff --git a/sbg/map_detail.hpp b/sbg/map_detail.hpp index e703fdfc..b0a410a1 100755 --- a/sbg/map_detail.hpp +++ b/sbg/map_detail.hpp @@ -36,6 +36,8 @@ #include "sbg/multidim_inter.hpp" #include "util/defs.hpp" +#include + namespace SBG { namespace LIB { @@ -44,6 +46,7 @@ namespace detail { using AtomicMap = std::pair; using AtomicMapVector = std::vector; +using AtomicMDMap = std::pair; using MapVector = std::vector; class MapDetail { @@ -52,6 +55,7 @@ class MapDetail { 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 @@ -59,6 +63,10 @@ class MapDetail { , const ExpressionImpl& expr); static MapVector reduce(const OrdUnidimDenseSet& s , const ExpressionImpl& expr); + + template + static MapVector imageMultiplicity(const CompactSetImplT& s + , const ExprT& expr); }; } // namespace detail diff --git a/sbg/ord_pwmap.cpp b/sbg/ord_pwmap.cpp index d2eda1b0..ff78e465 100644 --- a/sbg/ord_pwmap.cpp +++ b/sbg/ord_pwmap.cpp @@ -60,6 +60,12 @@ OrdPWMap::OrdPWMap(const Map& m) : _pieces() { } } +OrdPWMap::OrdPWMap(const std::vector& pieces) : _pieces() { + for (const Map& m : pieces) { + insert(m); + } +} + OrdPWMap::OrdPWMap(const OrdPWMap::OrdMapCollection& pieces) : _pieces(pieces) {} @@ -732,6 +738,20 @@ Set OrdPWMap::lessImage(const OrdPWMap& other) const return traverse(other, LessImageCore{}).result(); } +OrdPWMap OrdPWMap::imageMultiplicity() const +{ + 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)); + } + + return result; +} + void OrdPWMap::compact() { using MapSet = std::set; diff --git a/sbg/ord_pwmap.hpp b/sbg/ord_pwmap.hpp index 3819092b..e0934391 100644 --- a/sbg/ord_pwmap.hpp +++ b/sbg/ord_pwmap.hpp @@ -49,6 +49,7 @@ class OrdPWMap { OrdPWMap(); OrdPWMap(const Set& s); OrdPWMap(const Map& m); + OrdPWMap(const std::vector& pieces); OrdPWMap(const OrdMapCollection& pieces); OrdPWMap(OrdMapCollection&& pieces); @@ -99,6 +100,8 @@ class OrdPWMap { Set equalImage(const OrdPWMap& other) const; Set lessImage(const OrdPWMap& other) const; + OrdPWMap imageMultiplicity() const; + void compact(); private: diff --git a/sbg/pw_map.cpp b/sbg/pw_map.cpp index caa57e06..060c4ae2 100644 --- a/sbg/pw_map.cpp +++ b/sbg/pw_map.cpp @@ -459,6 +459,12 @@ Set PWMap::lessImage(const PWMap& other) const , _impl, other._impl); } +PWMap PWMap::imageMultiplicity() const +{ + return std::visit([](const auto& a) { return PWMap{a.imageMultiplicity()}; } + , _impl); +} + void PWMap::compact() { std::visit([](auto& a) { a.compact(); }, _impl); diff --git a/sbg/pw_map.hpp b/sbg/pw_map.hpp index 9ffcfd48..b3dd6856 100644 --- a/sbg/pw_map.hpp +++ b/sbg/pw_map.hpp @@ -231,6 +231,8 @@ class PWMap { */ Set lessImage(const PWMap& other) const; + PWMap imageMultiplicity() const; + /** * @brief Minimize internal representation cost. Heuristic guided. */ diff --git a/sbg/set_detail.hpp b/sbg/set_detail.hpp index c62bfc02..e9825466 100755 --- a/sbg/set_detail.hpp +++ b/sbg/set_detail.hpp @@ -45,7 +45,6 @@ class SetAccessKey { public: SetImpl impl(Set s) const; Set createSet(SetImpl s_impl) const; - MaybeMD_NAT nextElem(const MD_NAT& current, const Set& s) const; std::vector flatten(const Set& s) const; OrderedSet::OrdMDICollection pieces(OrderedSet s) const; diff --git a/sbg/unord_pwmap.cpp b/sbg/unord_pwmap.cpp index e3df6b16..87031df6 100644 --- a/sbg/unord_pwmap.cpp +++ b/sbg/unord_pwmap.cpp @@ -479,7 +479,21 @@ Set UnordPWMap::lessImage(const UnordPWMap& other) const } return min_in_pw1; -} +} + +UnordPWMap UnordPWMap::imageMultiplicity() const +{ + Map initial_result{image(), Expression{arity(), 0, 0}}; + UnordPWMap result{initial_result}; + + 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 result; +} void UnordPWMap::compact() { diff --git a/sbg/unord_pwmap.hpp b/sbg/unord_pwmap.hpp index 379a691a..2d6d26d3 100644 --- a/sbg/unord_pwmap.hpp +++ b/sbg/unord_pwmap.hpp @@ -98,6 +98,8 @@ class UnordPWMap { Set equalImage(const UnordPWMap& other) const; Set lessImage(const UnordPWMap& other) const; + UnordPWMap imageMultiplicity() const; + void compact(); private: From f2a111cde7e6fad98761e9255625aa686039a8a0 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 23 Apr 2026 10:44:22 -0300 Subject: [PATCH 44/66] Small changes --- algorithms/scc/decreasing_edges_mrv.cpp | 2 +- algorithms/scc/scc.cpp | 8 ++++---- algorithms/scc/scc.hpp | 2 +- algorithms/scc/scc_fact.cpp | 10 +++++----- eval/user_impl_map.cpp | 4 ++-- test/tearing1.test | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/algorithms/scc/decreasing_edges_mrv.cpp b/algorithms/scc/decreasing_edges_mrv.cpp index 5eab1e91..313cdf9c 100644 --- a/algorithms/scc/decreasing_edges_mrv.cpp +++ b/algorithms/scc/decreasing_edges_mrv.cpp @@ -91,7 +91,7 @@ PWMap LtEdgesMRV::repetitivePaths(const PWMap& rmap _visitedSE = _visitedSE.difference(Emap.image(E_repetition)); _n = 0; } else { - _visitedSE = std::move(_visitedSE).disjointCup(std::move(Emap.image(Pj))); + _visitedSE = std::move(_visitedSE).disjointCup(Emap.image(Pj)); ++_n; } diff --git a/algorithms/scc/scc.cpp b/algorithms/scc/scc.cpp index 0cec14d3..33db31ae 100644 --- a/algorithms/scc/scc.cpp +++ b/algorithms/scc/scc.cpp @@ -33,12 +33,12 @@ namespace LIB { std::ostream& operator<<(std::ostream& out, const SCCKind kind) { switch (kind) { - case SCCKind::MinReachV1: { + case SCCKind::kMinReachV1: { out << "minimum reachable V1"; break; } - case SCCKind::MinReachV2: { + case SCCKind::kMinReachV2: { out << "minimum reachable V2"; break; } @@ -59,12 +59,12 @@ std::ostream& operator<<(std::ostream& out, const SCCKind kind) SCC::SCC(SCCKind kind) : _kind(kind), _impl() { switch (kind) { - case SCCKind::MinReachV1: { + case SCCKind::kMinReachV1: { _impl = detail::MinReachSCCV1{}; break; } - case SCCKind::MinReachV2: { + case SCCKind::kMinReachV2: { _impl = detail::MinReachSCCV2{}; break; } diff --git a/algorithms/scc/scc.hpp b/algorithms/scc/scc.hpp index 16098b00..6b6e69ea 100644 --- a/algorithms/scc/scc.hpp +++ b/algorithms/scc/scc.hpp @@ -46,7 +46,7 @@ using SCCImpl = std::variant; } // namespace detail -enum class SCCKind { MinReachV1, MinReachV2 }; +enum class SCCKind { kMinReachV1, kMinReachV2 }; std::ostream& operator<<(std::ostream& out, const SCCKind kind); diff --git a/algorithms/scc/scc_fact.cpp b/algorithms/scc/scc_fact.cpp index 1ae8df23..9ad0d497 100755 --- a/algorithms/scc/scc_fact.cpp +++ b/algorithms/scc/scc_fact.cpp @@ -31,7 +31,7 @@ namespace LIB { SCC MinReachSCCV1Fact::createSCCAlgorithm() const { - return SCC{SCCKind::MinReachV1}; + return SCC{SCCKind::kMinReachV1}; } //////////////////////////////////////////////////////////////////////////////// @@ -40,7 +40,7 @@ SCC MinReachSCCV1Fact::createSCCAlgorithm() const SCC MinReachSCCV2Fact::createSCCAlgorithm() const { - return SCC{SCCKind::MinReachV2}; + return SCC{SCCKind::kMinReachV2}; } //////////////////////////////////////////////////////////////////////////////// @@ -48,7 +48,7 @@ SCC MinReachSCCV2Fact::createSCCAlgorithm() const //////////////////////////////////////////////////////////////////////////////// SCCFactory::SCCFactory() - : _kind(SCCKind::MinReachV2), _impl(MinReachSCCV2Fact{}) {} + : _kind(SCCKind::kMinReachV2), _impl(MinReachSCCV2Fact{}) {} SCCFactory& SCCFactory::instance() { @@ -62,12 +62,12 @@ void SCCFactory::set_scc_fact(SCCKind kind) { _kind = kind; switch (kind) { - case SCCKind::MinReachV1: { + case SCCKind::kMinReachV1: { _impl = MinReachSCCV1Fact{}; break; } - case SCCKind::MinReachV2: { + case SCCKind::kMinReachV2: { _impl = MinReachSCCV2Fact{}; break; } diff --git a/eval/user_impl_map.cpp b/eval/user_impl_map.cpp index 12a62cdb..8e6b063e 100755 --- a/eval/user_impl_map.cpp +++ b/eval/user_impl_map.cpp @@ -89,8 +89,8 @@ UserImplMap::StructImplMap matchMap() UserImplMap::StructImplMap sccMap() { UserImplMap::StructImplMap scc_mapping; - scc_mapping[0] = LIB::SCCKind::MinReachV1; - scc_mapping[1] = LIB::SCCKind::MinReachV2; + scc_mapping[0] = LIB::SCCKind::kMinReachV1; + scc_mapping[1] = LIB::SCCKind::kMinReachV2; scc_mapping.freeze(); return scc_mapping; } diff --git a/test/tearing1.test b/test/tearing1.test index 4e18f9cd..fd7d7c4a 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; From fcc655520d8472095fcb11244c77397a0b161f31 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 23 Apr 2026 10:44:59 -0300 Subject: [PATCH 45/66] Redefined CutVertex into MFVS --- algorithms/CMakeLists.txt | 2 +- algorithms/cutvertex/CMakeLists.txt | 7 - algorithms/cutvertex/maxdeg_cv.cpp | 147 ------------------ algorithms/mfvs/CMakeLists.txt | 7 + algorithms/mfvs/greedy_mfvs.cpp | 121 ++++++++++++++ .../maxdeg_cv.hpp => mfvs/greedy_mfvs.hpp} | 31 ++-- .../cv_fact.cpp => mfvs/mfvs_fact.cpp} | 44 ++++-- .../cv_fact.hpp => mfvs/mfvs_fact.hpp} | 63 ++++---- .../min_feedback_vertex_set.cpp} | 48 ++++-- .../min_feedback_vertex_set.hpp} | 50 +++--- 10 files changed, 262 insertions(+), 258 deletions(-) delete mode 100644 algorithms/cutvertex/CMakeLists.txt delete mode 100644 algorithms/cutvertex/maxdeg_cv.cpp create mode 100644 algorithms/mfvs/CMakeLists.txt create mode 100644 algorithms/mfvs/greedy_mfvs.cpp rename algorithms/{cutvertex/maxdeg_cv.hpp => mfvs/greedy_mfvs.hpp} (67%) rename algorithms/{cutvertex/cv_fact.cpp => mfvs/mfvs_fact.cpp} (62%) rename algorithms/{cutvertex/cv_fact.hpp => mfvs/mfvs_fact.hpp} (53%) rename algorithms/{cutvertex/cut_vertex.cpp => mfvs/min_feedback_vertex_set.cpp} (55%) rename algorithms/{cutvertex/cut_vertex.hpp => mfvs/min_feedback_vertex_set.hpp} (59%) diff --git a/algorithms/CMakeLists.txt b/algorithms/CMakeLists.txt index 43ca47cf..2210e896 100644 --- a/algorithms/CMakeLists.txt +++ b/algorithms/CMakeLists.txt @@ -1,7 +1,7 @@ # Add subdirectories add_subdirectory(cc) -#add_subdirectory(cutvertex) add_subdirectory(matching) +add_subdirectory(mfvs) add_subdirectory(misc) #add_subdirectory(partitioner) add_subdirectory(scc) 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/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/mfvs/CMakeLists.txt b/algorithms/mfvs/CMakeLists.txt new file mode 100644 index 00000000..7dca6f68 --- /dev/null +++ b/algorithms/mfvs/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources( + sbgraph + PRIVATE + min_feedback_vertex_set.cpp + mfvs_fact.cpp + greedy_mfvs.cpp +) diff --git a/algorithms/mfvs/greedy_mfvs.cpp b/algorithms/mfvs/greedy_mfvs.cpp new file mode 100644 index 00000000..30c515f3 --- /dev/null +++ b/algorithms/mfvs/greedy_mfvs.cpp @@ -0,0 +1,121 @@ +/******************************************************************************* + + 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 "algorithms/scc/scc_fact.hpp" +#include "sbg/natural.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/set_fact.hpp" +#include "util/logger.hpp" +#include "util/time_profiler.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_FACT.createSet(jth_mult)); + } + + Set max_mult_set = SET_FACT.createSet(max_mult); + Set max_degree_vertices = mmap.preImage(max_mult_set); + + return max_degree_vertices.minElem(); +} + +Set GreedyMFVS::calculate(const DirectedSBG& input_dsbg) const +{ + Util::Internal::TimeProfiler profiler{"Total MFVS exec time: "}; + + DirectedSBG dsbg = input_dsbg; + + Util::DEBUG_LOG << "initial mfvs dsbg:\n" << dsbg << "\n"; + + PWMap rmap = SCC_FACT.createSCCAlgorithm().calculate(dsbg).rmap(); + if (rmap.fixedPoints() == rmap.domain()) { + return SET_FACT.createSet(); + } + + Set fvs_result = SET_FACT.createSet(); + Set visitedSV = SET_FACT.createSet(); + while (!dsbg.V().isEmpty()) { + // Get minimum vertex with maximum degree + MD_NAT max_degree_vertex = maxDegreeVertex(dsbg); + Set Vj = SET_FACT.createSet(max_degree_vertex); + fvs_result = std::move(fvs_result).disjointCup(std::move(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).disjointCup(std::move(V_plus)); + + repeatedSV = repeatedSV.difference(Vmap.image(Vj)); + } else { + repeatedSV = std::move(repeatedSV).disjointCup(Vmap.image(Vj)); + } + + // Erase selected vertices + dsbg.eraseVertices(fvs_result); + + // Resulting SCC from induced graph + rmap = SCC_FACT.createSCCAlgorithm().calculate(dsbg).rmap(); + + Util::DEBUG_LOG << "Vj: " << Vj << "\n\n"; + Util::DEBUG_LOG << "new rmap: " << rmap << "\n\n"; + } + + 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 67% rename from algorithms/cutvertex/maxdeg_cv.hpp rename to algorithms/mfvs/greedy_mfvs.hpp index 8081f725..79f2b473 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,36 @@ ******************************************************************************/ -#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. */ -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/cutvertex/cv_fact.cpp b/algorithms/mfvs/mfvs_fact.cpp similarity index 62% rename from algorithms/cutvertex/cv_fact.cpp rename to algorithms/mfvs/mfvs_fact.cpp index 3d59fca9..e7f2961d 100755 --- a/algorithms/cutvertex/cv_fact.cpp +++ b/algorithms/mfvs/mfvs_fact.cpp @@ -17,8 +17,8 @@ ******************************************************************************/ -#include "algorithms/cutvertex/cv_fact.hpp" -#include "algorithms/cutvertex/maxdeg_cv.hpp" +#include "algorithms/mfvs/mfvs_fact.hpp" +#include "util/debug.hpp" namespace SBG { @@ -28,30 +28,46 @@ namespace LIB { // Maximum Degree Cut Vertex Factory ------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -CutVertex MaxDegCVFact::createCVAlgorithm() const +MinFeedbackVertexSet GreedyMFVSFact::createMFVSAlgorithm() const { - return CutVertex(std::make_unique()); -} - -std::string MaxDegCVFact::prettyPrint() const -{ - return "maximum degree vertex"; + return MinFeedbackVertexSet{MFVSKind::kGreedy}; } //////////////////////////////////////////////////////////////////////////////// // Factory for clients --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -CVFactory::CVFactory() : cv_fact_(std::make_unique()) {} +MFVSFactory::MFVSFactory() + : _kind(MFVSKind::kGreedy), _impl(GreedyMFVSFact{}) {} + +MFVSFactory& MFVSFactory::instance() +{ + static MFVSFactory _instance; + return _instance; +} + +const MFVSKind& MFVSFactory::kind() const { return _kind; } -CVFact& CVFactory::cv_fact() +void MFVSFactory::set_mfvs_fact(MFVSKind kind) { - return *cv_fact_; + _kind = kind; + switch (kind) { + case MFVSKind::kGreedy: { + _impl = GreedyMFVSFact{}; + } + + default: { + Util::ERROR("MFVSFactory::set_mfvs_fact: unsupported MFVS ", kind + , " implementation"); + break; + } + } } -void CVFactory::set_cv_fact(CVFactPtr cv_fact) +MinFeedbackVertexSet MFVSFactory::createMFVSAlgorithm() const { - cv_fact_ = std::move(cv_fact); + return std::visit([](const auto& a) { return a.createMFVSAlgorithm(); } + , _impl); } } // namespace LIB diff --git a/algorithms/cutvertex/cv_fact.hpp b/algorithms/mfvs/mfvs_fact.hpp similarity index 53% rename from algorithms/cutvertex/cv_fact.hpp rename to algorithms/mfvs/mfvs_fact.hpp index dcae5f4b..96f36369 100755 --- a/algorithms/cutvertex/cv_fact.hpp +++ b/algorithms/mfvs/mfvs_fact.hpp @@ -1,6 +1,6 @@ -/** @file cv_fact.hpp +/** @file mfvs_fact.hpp - @brief Vertex Cut Set Algorithm Factory + @brief Minimum Feedback Vertex Set Algorithm Factory
@@ -21,60 +21,51 @@ ******************************************************************************/ -#ifndef SBG_CV_FACT_HPP -#define SBG_CV_FACT_HPP +#ifndef SBGRAPH_ALGORITHMS_MFVS_MFVS_FACT_HPP_ +#define SBGRAPH_ALGORITHMS_MFVS_MFVS_FACT_HPP_ -#include "cut_vertex.hpp" +#include "min_feedback_vertex_set.hpp" namespace SBG { namespace LIB { -#define CV_FACT CVFactory::instance().cv_fact() +#define MFVS_FACT MFVSFactory::instance().cv_fact() -class CVFact { - public: - virtual ~CVFact() = default; - CVFact() = default; +class GreedyMFVSFact { +public: + GreedyMFVSFact() = default; - virtual CutVertex createCVAlgorithm() const = 0; - virtual std::string prettyPrint() const = 0; + MinFeedbackVertexSet createMFVSAlgorithm() const; }; -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). + * calls MFVS_FACT.createMFVSAlgorithm(args). */ -class CVFactory { - public: - ~CVFactory() = default; +class MFVSFactory { +public: + ~MFVSFactory() = default; + + static MFVSFactory& instance(); + const MFVSKind& kind() const; + + void set_mfvs_fact(MFVSKind kind); + + MinFeedbackVertexSet createMFVSAlgorithm() const; - static CVFactory& instance() { - static CVFactory instance_; - return instance_; - } - CVFact& cv_fact(); - void set_cv_fact(CVFactPtr cv_fact); +private: + using MFVSFactImpl = std::variant; - private: - CVFactory(); + MFVSFactory(); - CVFactPtr cv_fact_; + MFVSKind _kind; + MFVSFactImpl _impl; }; } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_MFVS_MFVS_FACT_HPP_ diff --git a/algorithms/cutvertex/cut_vertex.cpp b/algorithms/mfvs/min_feedback_vertex_set.cpp similarity index 55% rename from algorithms/cutvertex/cut_vertex.cpp rename to algorithms/mfvs/min_feedback_vertex_set.cpp index c24a5ede..08cc6dc8 100644 --- a/algorithms/cutvertex/cut_vertex.cpp +++ b/algorithms/mfvs/min_feedback_vertex_set.cpp @@ -17,31 +17,57 @@ ******************************************************************************/ -#include - -#include "algorithms/cutvertex/cut_vertex.hpp" -#include "algorithms/scc/scc.hpp" -#include "util/logger.hpp" +#include "algorithms/mfvs/min_feedback_vertex_set.hpp" +#include "util/debug.hpp" +#include "util/time_profiler.hpp" namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Vertex Cut Set Algorithm Abstract Strategy Constructors --------------------- +// MFVS Algorithm implementations ---------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -CVStrategy::CVStrategy() {} +std::ostream& operator<<(std::ostream& out, const MFVSKind kind) +{ + switch (kind) { + case MFVSKind::kGreedy: { + out << "maximum degree greedy"; + break; + } + + default: { + Util::ERROR("MFVSKind::operator<<: unsupported MFVS implementation"); + break; + } + } + + return out; +} //////////////////////////////////////////////////////////////////////////////// -// Vertex Cut Set Algorithm Interface ------------------------------------------ +// MFVS Algorithm Interface ---------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -CutVertex::CutVertex(CVStratPtr strat) : strategy_(std::move(strat)) {} +MinFeedbackVertexSet::MinFeedbackVertexSet(MFVSKind kind) : _kind(kind), _impl() +{ + switch (kind) { + case MFVSKind::kGreedy: { + _impl = detail::GreedyMFVS{}; + break; + } + + default: { + Util::ERROR("MinFeedbackVertexSet: unsupported MFVS implementation"); + break; + } + } +} -Set CutVertex::calculate(const DSBG& dsbg) const +Set MinFeedbackVertexSet::calculate(const DirectedSBG& dsbg) { - return strategy_->calculate(dsbg); + 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..2471ed12 100644 --- a/algorithms/cutvertex/cut_vertex.hpp +++ b/algorithms/mfvs/min_feedback_vertex_set.hpp @@ -21,54 +21,50 @@ ******************************************************************************/ -#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 "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; +using MFVSImpl = std::variant; -typedef std::unique_ptr CVStratPtr; +} -/** -* @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; +enum class MFVSKind { kGreedy }; - CVStrategy(); - - virtual Set calculate(const DSBG& dsbg) const = 0; -}; +std::ostream& operator<<(std::ostream& out, const MFVSKind kind); /////////////////////////////////////////////////////////////////////////////// -// Vertex Cut Set Algorithm Interface (context) ------------------------------- +// Minimum Feedback Vertex Set Algorithm -------------------------------------- /////////////////////////////////////////////////////////////////////////////// -class CutVertex { - public: - CutVertex(CVStratPtr strat); +class MinFeedbackVertexSet { +public: + MinFeedbackVertexSet(MFVSKind kind); - Set calculate(const DSBG& dsbg) const; + Set calculate(const DirectedSBG& dsbg); - private: - CVStratPtr strategy_; +private: + MFVSKind _kind; + detail::MFVSImpl _impl; }; } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_MFVS_MIN_FEEDBACK_VERTEX_SET_HPP_ From 53cd61dd248f3415cd7ba29852937a869b0b6d15 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 23 Apr 2026 11:08:59 -0300 Subject: [PATCH 46/66] Added MFVS algorithm to evaluator --- algorithms/mfvs/mfvs_fact.hpp | 2 +- eval/eval_exec.cpp | 7 +- eval/user_impl_map.cpp | 18 ++-- eval/user_impl_map.hpp | 5 +- eval/visitors/func_evaluator.cpp | 175 +++++++------------------------ eval/visitors/func_evaluator.hpp | 4 +- 6 files changed, 58 insertions(+), 153 deletions(-) diff --git a/algorithms/mfvs/mfvs_fact.hpp b/algorithms/mfvs/mfvs_fact.hpp index 96f36369..fefd4c11 100755 --- a/algorithms/mfvs/mfvs_fact.hpp +++ b/algorithms/mfvs/mfvs_fact.hpp @@ -30,7 +30,7 @@ namespace SBG { namespace LIB { -#define MFVS_FACT MFVSFactory::instance().cv_fact() +#define MFVS_FACT MFVSFactory::instance() class GreedyMFVSFact { public: diff --git a/eval/eval_exec.cpp b/eval/eval_exec.cpp index 07b2b00b..72c27b8f 100644 --- a/eval/eval_exec.cpp +++ b/eval/eval_exec.cpp @@ -17,9 +17,8 @@ ******************************************************************************/ -//#include "algorithms/cutvertex/cv_fact.hpp" -//#include "algorithms/cc/cc.hpp" #include "algorithms/matching/matching_fact.hpp" +#include "algorithms/mfvs/mfvs_fact.hpp" #include "algorithms/scc/scc_fact.hpp" //#include "algorithms/toposort/ts_fact.hpp" #include "eval/eval_exec.hpp" @@ -56,8 +55,8 @@ void printHeader(Util::prog_opts::variables_map vm) std::cout << "PWMap implementation: " << LIB::PWMAP_FACT.kind() << "\n"; std::cout << "-----------------------------------\n"; std::cout << "Matching algorithm: " << LIB::MATCH_FACT.kind() << "\n"; - std::cout << "SCC algorithm: " << LIB::SCC_FACT.kind() << "\n\n"; - //std::cout << "Cut vertex algorithm: " << LIB::CV_FACT.kind() << "\n"; + std::cout << "SCC algorithm: " << LIB::SCC_FACT.kind() << "\n"; + std::cout << "MFVS algorithm: " << LIB::MFVS_FACT.kind() << "\n\n"; //std::cout << "Topological sort algorithm: " << LIB::TS_FACT.kind() // << "\n"; } diff --git a/eval/user_impl_map.cpp b/eval/user_impl_map.cpp index 8e6b063e..85cabb28 100755 --- a/eval/user_impl_map.cpp +++ b/eval/user_impl_map.cpp @@ -95,6 +95,14 @@ UserImplMap::StructImplMap sccMap() return scc_mapping; } +UserImplMap::StructImplMap mfvsMap() +{ + UserImplMap::StructImplMap mfvs_mapping; + mfvs_mapping[0] = LIB::MFVSKind::kGreedy; + mfvs_mapping.freeze(); + return mfvs_mapping; +} + // TODO //UserImplMap::StructImplMap tsMap() //{ @@ -103,14 +111,6 @@ UserImplMap::StructImplMap sccMap() // 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 ----------------------------------------------------- @@ -122,8 +122,8 @@ UserImplMap::UserImplMap() implementations_["pwmap"] = pwMap(); implementations_["match"] = matchMap(); implementations_["scc"] = sccMap(); + implementations_["mfvs"] = mfvsMap(); //implementations_["ts"] = tsMap(); - //implementations_["cv"] = cvMap(); } Kind UserImplMap::getFactory(std::string strct, int impl) diff --git a/eval/user_impl_map.hpp b/eval/user_impl_map.hpp index 7ae716cb..e7e4e749 100755 --- a/eval/user_impl_map.hpp +++ b/eval/user_impl_map.hpp @@ -29,7 +29,7 @@ #ifndef SBGRAPH_EVAL_USER_IMPL_MAP_HPP_ #define SBGRAPH_EVAL_USER_IMPL_MAP_HPP_ -//#include "algorithms/cutvertex/cv_fact.hpp" +#include "algorithms/mfvs/min_feedback_vertex_set.hpp" #include "algorithms/matching/matching.hpp" #include "algorithms/scc/scc.hpp" //#include "algorithms/toposort/ts_fact.hpp" @@ -58,7 +58,8 @@ namespace detail { using Kind = std::variant; + , LIB::SCCKind + , LIB::MFVSKind>; /** * @brief Mapping for all structures such as Set, PW and algorithms. diff --git a/eval/visitors/func_evaluator.cpp b/eval/visitors/func_evaluator.cpp index 3ea7612f..75dbb7aa 100755 --- a/eval/visitors/func_evaluator.cpp +++ b/eval/visitors/func_evaluator.cpp @@ -17,14 +17,15 @@ ******************************************************************************/ +#include "eval/visitors/func_evaluator.hpp" #include "algorithms/cc/cc.hpp" -//#include "algorithms/cutvertex/cv_fact.hpp" +#include "algorithms/mfvs/min_feedback_vertex_set.hpp" +#include "algorithms/mfvs/mfvs_fact.hpp" #include "algorithms/matching/matching_fact.hpp" #include "algorithms/misc/causalization_builders.hpp" #include "algorithms/scc/scc_fact.hpp" //#include "algorithms/toposort/ts_fact.hpp" #include "eval/base_type.hpp" -#include "eval/visitors/func_evaluator.hpp" #include "sbg/bipartite_sbg.hpp" #include "sbg/expression.hpp" #include "sbg/interval.hpp" @@ -43,85 +44,6 @@ namespace Eval { namespace detail { -//////////////////////////////////////////////////////////////////////////////// -// Auxiliary functions --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -//TODO -/** - * @brief Returns a new bipartite SBG constructed by copying \p times the - * the current bipartite SBG, disconnected one from each other. - */ -/* -LIB::BipartiteSBG copy(unsigned int times, BipartiteSBG bsbg) -{ - 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)); - } - - 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); - } - } - - return BipartiteSBG{new_V, new_Vmap, new_map1, new_map2, new_Emap, new_subE - , new_X, new_Y}; -} -*/ - //////////////////////////////////////////////////////////////////////////////// // Built-in operators evaluators ----------------------------------------------- //////////////////////////////////////////////////////////////////////////////// @@ -631,22 +553,6 @@ ExprBaseType BuiltInFunctions::minMapEvaluator(const EBTList& args) return std::visit(min_map_evaluator, args[0], args[1]); } -// TODO -//ExprBaseType BuiltInFunctions::reduceEvaluator(const EBTList& args) -//{ -// Util::ERROR_UNLESS(args.size() == 1 -// , "reduceEvaluator: wrong number of arguments\n"); -// -// const auto reduce_evaluator = Util::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 @@ -751,44 +657,6 @@ ExprBaseType BuiltInFunctions::sccEvaluator(const EBTList& args) return std::visit(scc_evaluator, args[0]); } -/* -ExprBaseType BuiltInFunctions::topoSortEvaluator(const EBTList& args) -{ - Util::ERROR_UNLESS(args.size() == 1 - , "topoSortEvaluator: wrong number of arguments\n"); - - LIB::TopoSort ts_impl = LIB::TS_FACT.createTSAlgorithm(); - const auto ts_evaluator = Util::Overload { - [&ts_impl](LIB::DirectedSBG a) { - return ExprBaseType{ts_impl.calculate(a)}; - }, - [](auto a) { - Util::ERROR("topoSortEvaluator: wrong argument ", a, " for sort\n"); - return ExprBaseType{}; - } - }; - return std::visit(ts_evaluator, args[0]); -} - -ExprBaseType BuiltInFunctions::cutVertexEvaluator(const EBTList& args) -{ - Util::ERROR_UNLESS(args.size() == 1 - , "cutVertexEvaluator: wrong number of arguments\n"); - - LIB::CutVertex cv_impl = LIB::CV_FACT.createCVAlgorithm(); - const auto cv_evaluator = Util::Overload { - [&cv_impl](LIB::DirectedSBG a) { - return ExprBaseType{cv_impl.calculate(a)}; - }, - [](auto a) { - Util::ERROR("topoSortEvaluator: wrong argument ", a, " for sort\n"); - return ExprBaseType{}; - } - }; - return std::visit(cv_evaluator, args[0]); -} -*/ - ExprBaseType BuiltInFunctions::matchSCCEvaluator(const EBTList& args) { Util::ERROR_UNLESS(args.size() == 2 @@ -817,7 +685,44 @@ ExprBaseType BuiltInFunctions::matchSCCEvaluator(const EBTList& args) return std::visit(match_scc_evaluator, args[0], args[1]); } +ExprBaseType BuiltInFunctions::mfvsEvaluator(const EBTList& args) +{ + Util::ERROR_UNLESS(args.size() == 1 + , "mfvsEvaluator: wrong number of arguments\n"); + + LIB::MinFeedbackVertexSet mfvs_impl = LIB::MFVS_FACT.createMFVSAlgorithm(); + const auto mfvs_evaluator = Util::Overload { + [&mfvs_impl](LIB::DirectedSBG a) { + return ExprBaseType{mfvs_impl.calculate(a)}; + }, + [](auto a) { + Util::ERROR("mfvsEvaluator: wrong type of argument ", a + , " for MFVS algorithm\n"); + return ExprBaseType{}; + } + }; + return std::visit(mfvs_evaluator, args[0]); +} + /* +ExprBaseType BuiltInFunctions::topoSortEvaluator(const EBTList& args) +{ + Util::ERROR_UNLESS(args.size() == 1 + , "topoSortEvaluator: wrong number of arguments\n"); + + LIB::TopoSort ts_impl = LIB::TS_FACT.createTSAlgorithm(); + const auto ts_evaluator = Util::Overload { + [&ts_impl](LIB::DirectedSBG a) { + return ExprBaseType{ts_impl.calculate(a)}; + }, + [](auto a) { + Util::ERROR("topoSortEvaluator: wrong argument ", a, " for sort\n"); + return ExprBaseType{}; + } + }; + return std::visit(ts_evaluator, args[0]); +} + ExprBaseType BuiltInFunctions::matchSCCTSEvaluator(const EBTList& args) { const auto match_scc_ts_evaluator = Util::Overload { diff --git a/eval/visitors/func_evaluator.hpp b/eval/visitors/func_evaluator.hpp index ea7dcd91..62bec04f 100755 --- a/eval/visitors/func_evaluator.hpp +++ b/eval/visitors/func_evaluator.hpp @@ -94,9 +94,9 @@ class BuiltInFunctions { 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 topoSortEvaluator(const EBTList& args); }; } // namespace detail From bba958bea31f6776db541142688d6a2c60d9ee4f Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 23 Apr 2026 15:23:20 -0300 Subject: [PATCH 47/66] Added tearing SBG builder --- algorithms/mfvs/greedy_mfvs.cpp | 16 +++++-------- algorithms/misc/causalization_builders.cpp | 26 +++++++++++++++++----- algorithms/misc/causalization_builders.hpp | 12 ++++++++-- eval/visitors/expr_evaluator.cpp | 1 + eval/visitors/func_evaluator.cpp | 8 +++---- sbg/directed_sbg.cpp | 14 +++++++++--- sbg/directed_sbg.hpp | 8 ++++--- test/performance/scc_bm.cpp | 6 ++--- test/tearing1.test | 2 +- test/tearing2.test | 2 +- 10 files changed, 62 insertions(+), 33 deletions(-) diff --git a/algorithms/mfvs/greedy_mfvs.cpp b/algorithms/mfvs/greedy_mfvs.cpp index 30c515f3..a484afa1 100644 --- a/algorithms/mfvs/greedy_mfvs.cpp +++ b/algorithms/mfvs/greedy_mfvs.cpp @@ -77,28 +77,24 @@ Set GreedyMFVS::calculate(const DirectedSBG& input_dsbg) const Util::DEBUG_LOG << "initial mfvs dsbg:\n" << dsbg << "\n"; PWMap rmap = SCC_FACT.createSCCAlgorithm().calculate(dsbg).rmap(); - if (rmap.fixedPoints() == rmap.domain()) { - return SET_FACT.createSet(); - } - Set fvs_result = SET_FACT.createSet(); Set visitedSV = SET_FACT.createSet(); - while (!dsbg.V().isEmpty()) { + while (rmap.fixedPoints() != rmap.domain()) { // Get minimum vertex with maximum degree MD_NAT max_degree_vertex = maxDegreeVertex(dsbg); Set Vj = SET_FACT.createSet(max_degree_vertex); - fvs_result = std::move(fvs_result).disjointCup(std::move(Vj)); + 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).disjointCup(std::move(V_plus)); + fvs_result = std::move(fvs_result).cup(std::move(V_plus)); - repeatedSV = repeatedSV.difference(Vmap.image(Vj)); + visitedSV = repeatedSV.difference(Vmap.image(Vj)); } else { - repeatedSV = std::move(repeatedSV).disjointCup(Vmap.image(Vj)); + visitedSV = std::move(repeatedSV).disjointCup(Vmap.image(Vj)); } // Erase selected vertices @@ -107,7 +103,7 @@ Set GreedyMFVS::calculate(const DirectedSBG& input_dsbg) const // Resulting SCC from induced graph rmap = SCC_FACT.createSCCAlgorithm().calculate(dsbg).rmap(); - Util::DEBUG_LOG << "Vj: " << Vj << "\n\n"; + Util::DEBUG_LOG << "Vj: " << Vj << "\n"; Util::DEBUG_LOG << "new rmap: " << rmap << "\n\n"; } diff --git a/algorithms/misc/causalization_builders.cpp b/algorithms/misc/causalization_builders.cpp index 4d70db36..92162f54 100644 --- a/algorithms/misc/causalization_builders.cpp +++ b/algorithms/misc/causalization_builders.cpp @@ -31,7 +31,7 @@ namespace misc { //////////////////////////////////////////////////////////////////////////////// -// Algebraic loops graph ------------------------------------------------------- +// Algebraic loops detection graph builder ------------------------------------- //////////////////////////////////////////////////////////////////////////////// std::tuple buildSCCVertices( @@ -135,9 +135,9 @@ SBG::LIB::PWMap partitionEmap(const SBG::LIB::DirectedSBG& dsbg) return partitioned_Emap; } -SBG::LIB::DirectedSBG buildSCCFromMatching(const SBG::LIB::MatchData& data) +SBG::LIB::DirectedSBG buildLoopDetectionSBG(const SBG::LIB::MatchData& data) { - SBG::Util::Internal::TimeProfiler profiler{"SBG SCC builder: "}; + SBG::Util::Internal::TimeProfiler profiler{"SBG Loop Detection builder: "}; SBG::LIB::Set V = SBG::LIB::SET_FACT.createSet(); SBG::LIB::PWMap Vmap = SBG::LIB::PWMAP_FACT.createPWMap(); @@ -155,12 +155,26 @@ SBG::LIB::DirectedSBG buildSCCFromMatching(const SBG::LIB::MatchData& data) } //////////////////////////////////////////////////////////////////////////////// -// Vertical ordering graph ----------------------------------------------------- +// Algebraic loops breaker graph builder --------------------------------------- //////////////////////////////////////////////////////////////////////////////// -SBG::LIB::DirectedSBG buildSortFromSCC(const SBG::LIB::SCCData& data) +SBG::LIB::DirectedSBG buildTearingSBG(const SBG::LIB::SCCData& data) { - SBG::Util::Internal::TimeProfiler profiler{"SBG Topological Sort builder: "}; + 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) +{ + SBG::Util::Internal::TimeProfiler profiler{"SBG Vertical Sorting builder: "}; const SBG::LIB::DirectedSBG& dsbg = data.dsbg(); SBG::LIB::PWMap rmap = data.rmap(); diff --git a/algorithms/misc/causalization_builders.hpp b/algorithms/misc/causalization_builders.hpp index 1cca970d..407bd685 100644 --- a/algorithms/misc/causalization_builders.hpp +++ b/algorithms/misc/causalization_builders.hpp @@ -34,9 +34,17 @@ namespace misc { -SBG::LIB::DirectedSBG buildSCCFromMatching(const SBG::LIB::MatchData& data); +/** + * @brief Builds the directed SBG used to detect algebraic loops. + */ +SBG::LIB::DirectedSBG buildLoopDetectionSBG(const SBG::LIB::MatchData& data); -SBG::LIB::DirectedSBG buildSortFromSCC(const SBG::LIB::SCCData& data); +/** + * @brief Builds the directed SBG used to identify tearing variables. + */ +SBG::LIB::DirectedSBG buildTearingSBG(const SBG::LIB::SCCData& data); + +SBG::LIB::DirectedSBG buildVerticalSortingSBG(const SBG::LIB::SCCData& data); } // namespace misc diff --git a/eval/visitors/expr_evaluator.cpp b/eval/visitors/expr_evaluator.cpp index b5297fa8..f967109e 100755 --- a/eval/visitors/expr_evaluator.cpp +++ b/eval/visitors/expr_evaluator.cpp @@ -75,6 +75,7 @@ ExprEvaluator::ExprEvaluator(EvalContext& eval_ctx) : _eval_context(eval_ctx) eval_ctx.insertFunction("match", BuiltInFunctions::matchingEvaluator); eval_ctx.insertFunction("scc", BuiltInFunctions::sccEvaluator); eval_ctx.insertFunction("matchSCC", BuiltInFunctions::matchSCCEvaluator); + eval_ctx.insertFunction("mfvs", BuiltInFunctions::mfvsEvaluator); } ExprBaseType ExprEvaluator::operator()(AST::Natural v) const diff --git a/eval/visitors/func_evaluator.cpp b/eval/visitors/func_evaluator.cpp index 75dbb7aa..ae5818e0 100755 --- a/eval/visitors/func_evaluator.cpp +++ b/eval/visitors/func_evaluator.cpp @@ -667,12 +667,12 @@ ExprBaseType BuiltInFunctions::matchSCCEvaluator(const EBTList& args) const auto match_scc_evaluator = Util::Overload { [&match_impl, &scc_impl](LIB::BipartiteSBG a, LIB::NAT b) { LIB::MatchData match_result = match_impl.calculate(copy(b, a)); - LIB::DirectedSBG dsbg = misc::buildSCCFromMatching(match_result); + LIB::DirectedSBG dsbg = misc::buildLoopDetectionSBG(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(copy(b[0], a)); - LIB::DirectedSBG dsbg = misc::buildSCCFromMatching(match_result); + LIB::DirectedSBG dsbg = misc::buildLoopDetectionSBG(match_result); return ExprBaseType{scc_impl.calculate(dsbg).rmap()}; }, [](auto a, auto b) { @@ -729,7 +729,7 @@ ExprBaseType BuiltInFunctions::matchSCCTSEvaluator(const EBTList& args) [](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::SCC scc(misc::buildLoopDetectionSBG(match), c); LIB::PWMap scc_res = scc.calculate(); LIB::DirectedSBG ts_dsbg = misc::buildSortFromSCC(scc, scc_res); LIB::TopoSort ts = LIB::MinVertexTSAF().createTSAlgorithm(ts_dsbg); @@ -740,7 +740,7 @@ ExprBaseType BuiltInFunctions::matchSCCTSEvaluator(const EBTList& args) [](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::SCC scc(misc::buildLoopDetectionSBG(match), c); LIB::PWMap scc_res = scc.calculate(); LIB::DirectedSBG ts_dsbg = misc::buildSortFromSCC(scc, scc_res); LIB::TopoSort ts = LIB::MinVertexTSAF().createTSAlgorithm(ts_dsbg); diff --git a/sbg/directed_sbg.cpp b/sbg/directed_sbg.cpp index 51a3497d..40dd976d 100644 --- a/sbg/directed_sbg.cpp +++ b/sbg/directed_sbg.cpp @@ -103,18 +103,26 @@ void DirectedSBG::addSetEdge(const PWMap& pwB, const PWMap& pwD) } } -void DirectedSBG::eraseVertices(const Set& vs) +void DirectedSBG::eraseVertices(const Set& V) { - _V = _V.difference(vs); + _V = _V.difference(V); _Vmap = _Vmap.restrict(_V); - Set eraseE = _mapB.preImage(vs).cup(_mapD.preImage(vs)); + 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); } +void DirectedSBG::eraseEdges(const Set& E) +{ + _E = _E.difference(E); + _mapB = _mapB.restrict(_E); + _mapD = _mapD.restrict(_E); + _Emap = _Emap.restrict(_E); +} + // Operators ------------------------------------------------------------------- std::ostream& operator<<(std::ostream& out, const DirectedSBG& dg) diff --git a/sbg/directed_sbg.hpp b/sbg/directed_sbg.hpp index d9f545e4..b89d9f4c 100644 --- a/sbg/directed_sbg.hpp +++ b/sbg/directed_sbg.hpp @@ -90,10 +90,12 @@ class DirectedSBG { void addSetEdge(const PWMap& pw1, const PWMap& pw2); /** - * @brief Erase vertices \p vs from the DirectedSBG, together with associated - * edges with \p vs. + * @brief Erase vertices \p vs from the DirectedSBG, together with adjacent + * edges of \p vs. */ - void eraseVertices(const Set& vs); + void eraseVertices(const Set& V); + + void eraseEdges(const Set& E); template void foreachSetVertex(FuncT&& f) const; diff --git a/test/performance/scc_bm.cpp b/test/performance/scc_bm.cpp index c1cb1e52..94a68cda 100644 --- a/test/performance/scc_bm.cpp +++ b/test/performance/scc_bm.cpp @@ -41,7 +41,7 @@ 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::buildSCCFromMatching(match_result); + SBG::LIB::DirectedSBG scc_dsbg = misc::buildLoopDetectionSBG(match_result); SBG::LIB::SCC scc_algorithm = SBG::LIB::SCC_FACT.createSCCAlgorithm(); for (auto _ : state) { @@ -57,7 +57,7 @@ static void BM_SCCWithBuilder(benchmark::State& state, std::string filename) SBG::LIB::SCC scc_algorithm = SBG::LIB::SCC_FACT.createSCCAlgorithm(); for (auto _ : state) { - SBG::LIB::DirectedSBG scc_dsbg = misc::buildSCCFromMatching(match_result); + SBG::LIB::DirectedSBG scc_dsbg = misc::buildLoopDetectionSBG(match_result); benchmark::DoNotOptimize(scc_algorithm.calculate(scc_dsbg)); } state.SetComplexityN(N); @@ -70,7 +70,7 @@ static void BM_SCCCopies(benchmark::State& state, std::string filename) SBG::LIB::SCC scc_algorithm = SBG::LIB::SCC_FACT.createSCCAlgorithm(); for (auto _ : state) { - SBG::LIB::DirectedSBG scc_dsbg = misc::buildSCCFromMatching(match_result); + SBG::LIB::DirectedSBG scc_dsbg = misc::buildLoopDetectionSBG(match_result); benchmark::DoNotOptimize(scc_algorithm.calculate(scc_dsbg)); } state.SetComplexityN(N); diff --git a/test/tearing1.test b/test/tearing1.test index fd7d7c4a..3bfb8aee 100644 --- a/test/tearing1.test +++ b/test/tearing1.test @@ -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|>> From 9105bea7153f3f93e9283ba706a04b92998c80b2 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Mon, 27 Apr 2026 11:39:29 -0300 Subject: [PATCH 48/66] Small changes --- algorithms/cc/cc.cpp | 2 +- algorithms/matching/bfs_matching.cpp | 3 --- algorithms/matching/matching.cpp | 2 ++ algorithms/mfvs/greedy_mfvs.cpp | 3 --- algorithms/mfvs/greedy_mfvs.hpp | 3 ++- algorithms/mfvs/min_feedback_vertex_set.cpp | 2 ++ algorithms/misc/causalization_builders.hpp | 13 +++++++++++-- algorithms/scc/minreach_scc.cpp | 2 -- algorithms/scc/scc.cpp | 3 +++ 9 files changed, 21 insertions(+), 12 deletions(-) diff --git a/algorithms/cc/cc.cpp b/algorithms/cc/cc.cpp index 7df50682..99e73ed3 100644 --- a/algorithms/cc/cc.cpp +++ b/algorithms/cc/cc.cpp @@ -33,7 +33,7 @@ namespace LIB { PWMap connectedComponents(const SBG& sbg) { - Util::Internal::TimeProfiler profiler{"Total CC exec time:"}; + Util::Internal::TimeProfiler profiler{"Total CC execution time:"}; Set V = sbg.V(); if (!V.isEmpty()) { diff --git a/algorithms/matching/bfs_matching.cpp b/algorithms/matching/bfs_matching.cpp index 300c26ee..a4201016 100644 --- a/algorithms/matching/bfs_matching.cpp +++ b/algorithms/matching/bfs_matching.cpp @@ -22,7 +22,6 @@ #include "sbg/pwmap_fact.hpp" #include "sbg/set_fact.hpp" #include "util/logger.hpp" -#include "util/time_profiler.hpp" namespace SBG { @@ -173,8 +172,6 @@ void BFSMatching::init(const BipartiteSBG& bsbg) MatchData BFSMatching::calculate(const BipartiteSBG& bsbg) { - Util::Internal::TimeProfiler profiler{"Total matching exec time: "}; - init(bsbg); Util::SBG_LOG << "Matching bipartite SBG: " << bsbg << "\n\n"; _X = bsbg.X(); diff --git a/algorithms/matching/matching.cpp b/algorithms/matching/matching.cpp index 2f054bcf..ad0375ed 100644 --- a/algorithms/matching/matching.cpp +++ b/algorithms/matching/matching.cpp @@ -66,6 +66,8 @@ Matching::Matching(MatchKind kind) : _kind(kind), _impl() MatchData Matching::calculate(const BipartiteSBG& bsbg) { + Util::Internal::TimeProfiler profiler{"Total matching execution time: "}; + return std::visit([&](auto& a) { return a.calculate(bsbg); }, _impl); } diff --git a/algorithms/mfvs/greedy_mfvs.cpp b/algorithms/mfvs/greedy_mfvs.cpp index a484afa1..437d5f10 100644 --- a/algorithms/mfvs/greedy_mfvs.cpp +++ b/algorithms/mfvs/greedy_mfvs.cpp @@ -24,7 +24,6 @@ #include "sbg/pw_map.hpp" #include "sbg/set_fact.hpp" #include "util/logger.hpp" -#include "util/time_profiler.hpp" #include @@ -70,8 +69,6 @@ MD_NAT maxDegreeVertex(const DirectedSBG& dsbg) Set GreedyMFVS::calculate(const DirectedSBG& input_dsbg) const { - Util::Internal::TimeProfiler profiler{"Total MFVS exec time: "}; - DirectedSBG dsbg = input_dsbg; Util::DEBUG_LOG << "initial mfvs dsbg:\n" << dsbg << "\n"; diff --git a/algorithms/mfvs/greedy_mfvs.hpp b/algorithms/mfvs/greedy_mfvs.hpp index 79f2b473..5a142935 100644 --- a/algorithms/mfvs/greedy_mfvs.hpp +++ b/algorithms/mfvs/greedy_mfvs.hpp @@ -38,7 +38,8 @@ namespace detail { /////////////////////////////////////////////////////////////////////////////// /** - * @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 GreedyMFVS { public: diff --git a/algorithms/mfvs/min_feedback_vertex_set.cpp b/algorithms/mfvs/min_feedback_vertex_set.cpp index 08cc6dc8..f35cbbce 100644 --- a/algorithms/mfvs/min_feedback_vertex_set.cpp +++ b/algorithms/mfvs/min_feedback_vertex_set.cpp @@ -67,6 +67,8 @@ MinFeedbackVertexSet::MinFeedbackVertexSet(MFVSKind kind) : _kind(kind), _impl() Set MinFeedbackVertexSet::calculate(const DirectedSBG& dsbg) { + Util::Internal::TimeProfiler profiler{"Total MFVS exec time: "}; + return std::visit([&](auto& a) { return a.calculate(dsbg); }, _impl); } diff --git a/algorithms/misc/causalization_builders.hpp b/algorithms/misc/causalization_builders.hpp index 407bd685..53593613 100644 --- a/algorithms/misc/causalization_builders.hpp +++ b/algorithms/misc/causalization_builders.hpp @@ -35,15 +35,24 @@ namespace misc { /** - * @brief Builds the directed SBG used to detect algebraic loops. + * @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. + * @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); } // namespace misc diff --git a/algorithms/scc/minreach_scc.cpp b/algorithms/scc/minreach_scc.cpp index 5f482b31..3e3695f3 100644 --- a/algorithms/scc/minreach_scc.cpp +++ b/algorithms/scc/minreach_scc.cpp @@ -23,7 +23,6 @@ #include "sbg/pwmap_fact.hpp" #include "sbg/set_fact.hpp" #include "util/logger.hpp" -#include "util/time_profiler.hpp" namespace SBG { @@ -61,7 +60,6 @@ SCCData MinReachSCC::calculate(const DirectedSBG& dsbg) { Util::DEBUG_LOG << "MinReachSCC dsbg: \n" << dsbg << "\n\n"; - Util::Internal::TimeProfiler profiler{"Total MinReachSCC exec time: "}; init(dsbg); PWMap rmap = PWMAP_FACT.createPWMap(); diff --git a/algorithms/scc/scc.cpp b/algorithms/scc/scc.cpp index 33db31ae..3cec3a1e 100644 --- a/algorithms/scc/scc.cpp +++ b/algorithms/scc/scc.cpp @@ -21,6 +21,7 @@ #include "algorithms/scc/scc.hpp" #include "util/debug.hpp" #include "util/logger.hpp" +#include "util/time_profiler.hpp" namespace SBG { @@ -78,6 +79,8 @@ SCC::SCC(SCCKind kind) : _kind(kind), _impl() SCCData SCC::calculate(const DirectedSBG& dsbg) { + Util::Internal::TimeProfiler profiler{"Total SCC execution time: "}; + return std::visit([&](auto& a) { return a.calculate(dsbg); }, _impl); } From 804a594e5fecb46b9aebca0bfc2fd7a86f549d0c Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Mon, 27 Apr 2026 11:40:28 -0300 Subject: [PATCH 49/66] Redefined topological sorting SBG algorithm [IN PROGRESS] --- algorithms/CMakeLists.txt | 2 +- algorithms/sorting/CMakeLists.txt | 4 + .../topological}/CMakeLists.txt | 2 +- .../sorting/topological/min_vertex_ts.cpp | 157 ++++++++++++++++++ .../topological}/min_vertex_ts.hpp | 38 +++-- .../topological/topological_sorting.cpp} | 51 ++++-- .../topological/topological_sorting.hpp} | 39 +++-- .../topological}/ts_fact.cpp | 47 ++++-- .../topological}/ts_fact.hpp | 59 +++---- algorithms/toposort/min_vertex_ts.cpp | 119 ------------- 10 files changed, 308 insertions(+), 210 deletions(-) create mode 100644 algorithms/sorting/CMakeLists.txt rename algorithms/{toposort => sorting/topological}/CMakeLists.txt (73%) create mode 100644 algorithms/sorting/topological/min_vertex_ts.cpp rename algorithms/{toposort => sorting/topological}/min_vertex_ts.hpp (56%) rename algorithms/{toposort/topo_sort.cpp => sorting/topological/topological_sorting.cpp} (51%) rename algorithms/{toposort/topo_sort.hpp => sorting/topological/topological_sorting.hpp} (63%) rename algorithms/{toposort => sorting/topological}/ts_fact.cpp (59%) rename algorithms/{toposort => sorting/topological}/ts_fact.hpp (50%) delete mode 100644 algorithms/toposort/min_vertex_ts.cpp diff --git a/algorithms/CMakeLists.txt b/algorithms/CMakeLists.txt index 2210e896..d34f7c14 100644 --- a/algorithms/CMakeLists.txt +++ b/algorithms/CMakeLists.txt @@ -5,6 +5,6 @@ add_subdirectory(mfvs) add_subdirectory(misc) #add_subdirectory(partitioner) add_subdirectory(scc) -#add_subdirectory(toposort) +add_subdirectory(sorting) install_lib_headers("${CMAKE_CURRENT_SOURCE_DIR}") 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 73% rename from algorithms/toposort/CMakeLists.txt rename to algorithms/sorting/topological/CMakeLists.txt index 4cde5cc9..10aef656 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 + topological_sorting.cpp ts_fact.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..10114c1e --- /dev/null +++ b/algorithms/sorting/topological/min_vertex_ts.cpp @@ -0,0 +1,157 @@ +/******************************************************************************* + + 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 "sbg/pwmap_fact.hpp" +#include "sbg/set_fact.hpp" +#include "util/debug.hpp" +#include "util/logger.hpp" + +namespace SBG { + +namespace LIB { + +namespace detail { + +//////////////////////////////////////////////////////////////////////////////// +// Minimum Vertex Topological Sort Algorithm ----------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +MinVertexTS::MinVertexTS() + : _smap(PWMAP_FACT.createPWMap()), _dsbg(), _visitedSV(SET_FACT.createSet()) + , _n(0) {} + +Expression calculateExpr(const MD_NAT& old_value, const MD_NAT& new_value) +{ + return Expression{old_value}; +} + +PWMap MinVertexTS::independentRepetition(const Set& independent_V_plus, + const Expression& successor_expr) const +{ + PWMap result = PWMAP_FACT.createPWMap(); + + result.emplace(independent_V_plus, successor_expr); + bool independent_image = result.image().difference(independent_V_plus).isEmpty(); + Util::ERROR_UNLESS(independent_image/*&& result.isInjective()*/ + , "MinVertexTS::independentRepetition: incorrect guessing ", result); + + return result; +} + +PWMap MinVertexTS::dependentRepetition(const Set& init_V) const +{ + PWMap result = PWMAP_FACT.createPWMap(); + + Set Vi = init_V; + Set V = SET_FACT.createSet(); + for (unsigned int j = 0; j < _n; ++j) { + Vi = _smap.image(Vi); + V = std::move(V).disjointCup(std::move(Vi)); + } + PWMap smap_repetition = _smap.restrict(V); + PWMap mapB = _dsbg.mapB(); + PWMap mapD = _dsbg.mapD(); + Set E_repetition = smap_repetition.composition(mapB).equalImage(mapD); + + PWMap Emap = _dsbg.Emap(); + Set E_plus = Emap.preImage(Emap.image(E_repetition)); + PWMap mapB_plus = mapB.restrict(E_plus); + PWMap mapD_plus = mapD.restrict(E_plus); + result = mapB_plus.minAdj(mapD_plus); + + /*TODO: check well-formed result*/ + + return result; +} + +PWMap MinVertexTS::calculate(const DirectedSBG& dsbg + , const PWMap& pmap) +{ + Util::DEBUG_LOG << "Topological sort dsbg:\n" << dsbg << "\n\n"; + + _dsbg = dsbg; + + PWMap _smap = PWMAP_FACT.createPWMap(); + + Set same_SCC = _dsbg.V(); + Set same_SV = _dsbg.V(); + Set visited_SV = SET_FACT.createSet(); + Expression successor_expr{_dsbg.V().arity(), 1, 0}; + MD_NAT old_vi; + do { + Set V = _dsbg.V(); + PWMap mapD = _dsbg.mapD(); + Set independent = V.difference(mapD.image()); + + Set Vi = independent; + if (Vi.isEmpty()) { + Util::ERROR("Topological sorting: the SBG is not acyclic"); + } + Set independent_same_SCC = Vi.intersection(same_SCC); + if (independent_same_SCC.isEmpty()) { + Vi = independent_same_SCC; + } + Set Vi_same_SV = Vi.intersection(same_SV); + if (Vi_same_SV.isEmpty()) { + Vi = Vi_same_SV; + } + + // Handle repetition + PWMap Vmap = _dsbg.Vmap(); + MD_NAT vi = Vi.minElem(); + Set vi_set = SET_FACT.createSet(vi); + Set repeatedSV = _visitedSV.intersection(Vmap.image(vi_set)); + if (!repeatedSV.isEmpty()) { + Set V_plus = Vmap.preImage(Vmap.image(vi_set)); + Set independent_V_plus = independent.intersection(V_plus); + PWMap smap_plus = PWMAP_FACT.createPWMap(); + if (!independent_V_plus.isEmpty()) { + smap_plus = independentRepetition(independent_V_plus, successor_expr); + } else { + smap_plus = dependentRepetition(vi_set); + } + _smap = std::move(smap_plus).combine(std::move(_smap)); + _n = 0; + } else { + _smap.emplace(vi_set, successor_expr); + + _visitedSV = std::move(_visitedSV).disjointCup(Vmap.image(vi_set)); + ++_n; + } + + // Update values for new iteration + _dsbg.eraseVertices(_smap.domain()); + old_vi = vi; + successor_expr = calculateExpr(old_vi, vi); + same_SCC = pmap.preImage(pmap.image(vi_set)); + same_SV = Vmap.preImage(Vmap.image(vi_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/toposort/min_vertex_ts.hpp b/algorithms/sorting/topological/min_vertex_ts.hpp similarity index 56% rename from algorithms/toposort/min_vertex_ts.hpp rename to algorithms/sorting/topological/min_vertex_ts.hpp index 15e70c54..d0d14409 100644 --- a/algorithms/toposort/min_vertex_ts.hpp +++ b/algorithms/sorting/topological/min_vertex_ts.hpp @@ -1,6 +1,6 @@ /** @file min_vertex_ts.hpp - @brief Concrete SBG Minimum Vertex Topological Sort Algorithm + @brief Concrete SBG Minimum Vertex Topological Sorting Algorithm implementation
@@ -22,31 +22,49 @@ ******************************************************************************/ -#ifndef SBG_MIN_VERTEX_TS_HPP -#define SBG_MIN_VERTEX_TS_HPP +#ifndef SBGRAPH_ALGORITHMS_SORTING_TOPOLOGICAL_MIN_VERTEX_TS_HPP_ +#define SBGRAPH_ALGORITHMS_SORTING_TOPOLOGICAL_MIN_VERTEX_TS_HPP_ -#include "algorithms/toposort/topo_sort.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 Sort Algorithm Implementation (concrete strategy) +// Minimum Vertex Topological Sorting Algorithm Implementation ----------------- //////////////////////////////////////////////////////////////////////////////// /** * @brief In each step takes out the minimum vertex without dependencies. */ -class MinVertexTopoSort : public TSStrategy { - public: - MinVertexTopoSort(); +class MinVertexTS { +public: + MinVertexTS(); + + PWMap calculate(const DirectedSBG& dsbg, const PWMap& pmap); + +private: + PWMap independentRepetition(const Set& independent_V_plus + , const Expression& successor_expr) const; - PWMap calculate(const DSBG& dsbg) const override; + PWMap dependentRepetition(const Set& init_V) const; + + PWMap _smap; + DirectedSBG _dsbg; + Set _visitedSV; + unsigned int _n; }; +} // namespace detail + } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_SORTING_TOPOLOGICAL_MIN_VERTEX_TS_HPP_ diff --git a/algorithms/toposort/topo_sort.cpp b/algorithms/sorting/topological/topological_sorting.cpp similarity index 51% rename from algorithms/toposort/topo_sort.cpp rename to algorithms/sorting/topological/topological_sorting.cpp index ee63501a..5bf5bb82 100644 --- a/algorithms/toposort/topo_sort.cpp +++ b/algorithms/sorting/topological/topological_sorting.cpp @@ -17,30 +17,61 @@ ******************************************************************************/ -#include - -#include "algorithms/toposort/topo_sort.hpp" -#include "util/logger.hpp" +#include "algorithms/sorting/topological/topological_sorting.hpp" +#include "util/debug.hpp" +#include "util/time_profiler.hpp" namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Topological Sort Algorithm Abstract Strategy Constructors ------------------- +// Topological Sorting Algorithm implementations ------------------------------- //////////////////////////////////////////////////////////////////////////////// -TSStrategy::TSStrategy() {} +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; +} //////////////////////////////////////////////////////////////////////////////// -// Topological Sort Algorithm Interface ---------------------------------------- +// Topological Sorting Algorithm Interface ------------------------------------- //////////////////////////////////////////////////////////////////////////////// -TopoSort::TopoSort(TSStratPtr strat) : strategy_(std::move(strat)) {} +TopologicalSorting::TopologicalSorting(TSKind kind) : _kind(kind), _impl() +{ + switch (kind) { + case TSKind::kMinVertex: { + _impl = detail::MinVertexTS{}; + break; + } + + default: { + Util::ERROR("TopologicalSorting::operator<<: unsupported topological " + , "sorting algorithm implementation"); + } + } +} -PWMap TopoSort::calculate(const DSBG& dsbg) const +PWMap TopologicalSorting::calculate(const DirectedSBG& dsbg, const PWMap& pmap) { - return strategy_->calculate(dsbg); + 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 diff --git a/algorithms/toposort/topo_sort.hpp b/algorithms/sorting/topological/topological_sorting.hpp similarity index 63% rename from algorithms/toposort/topo_sort.hpp rename to algorithms/sorting/topological/topological_sorting.hpp index 9552cd48..45ceefe8 100644 --- a/algorithms/toposort/topo_sort.hpp +++ b/algorithms/sorting/topological/topological_sorting.hpp @@ -21,48 +21,47 @@ ******************************************************************************/ -#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; +using TSImpl = std::variant; -class TSStrategy { - public: - virtual ~TSStrategy() = default; +} // namespace detail - TSStrategy(); +enum class TSKind { kMinVertex }; - virtual PWMap calculate(const DSBG& dsbg) const = 0; -}; +std::ostream& operator<<(std::ostream& out, const TSKind kind); //////////////////////////////////////////////////////////////////////////////// -// Topological Sort Algorithm Interface (context) ------------------------------ +// Topological Sorting Algorithm ----------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -class TopoSort { - private: - TSStratPtr strategy_; +class TopologicalSorting { +public: + TopologicalSorting(TSKind kind); - public: - TopoSort(TSStratPtr strat); + PWMap calculate(const DirectedSBG& dsbg, const PWMap& pmap); - PWMap calculate(const DSBG& dsbg) const; +private: + TSKind _kind; + detail::TSImpl _impl; }; } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_SORTING_TOPOLOGICAL_TOPOLOGICAL_SORTING_HPP_ diff --git a/algorithms/toposort/ts_fact.cpp b/algorithms/sorting/topological/ts_fact.cpp similarity index 59% rename from algorithms/toposort/ts_fact.cpp rename to algorithms/sorting/topological/ts_fact.cpp index cba4d31e..ea0b2f61 100755 --- a/algorithms/toposort/ts_fact.cpp +++ b/algorithms/sorting/topological/ts_fact.cpp @@ -17,41 +17,58 @@ ******************************************************************************/ -#include "algorithms/toposort/ts_fact.hpp" -#include "algorithms/toposort/min_vertex_ts.hpp" +#include "algorithms/sorting/topological/ts_fact.hpp" +#include "util/debug.hpp" namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Minimum Vertex Topological Sort Factory ------------------------------------- +// Minimum Vertex Topological Sorting Factory ---------------------------------- //////////////////////////////////////////////////////////////////////////////// -TopoSort MinVertexTSFact::createTSAlgorithm() const +TopologicalSorting MinVertexTSFact::createTSAlgorithm() const { - return TopoSort(std::make_unique()); -} - -std::string MinVertexTSFact::prettyPrint() const -{ - return "minimum vertex"; + return TopologicalSorting{TSKind::kMinVertex}; } //////////////////////////////////////////////////////////////////////////////// // Factory for clients --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -TSFactory::TSFactory() : ts_fact_(std::make_unique()) {} +TSFactory::TSFactory() + : _kind(TSKind::kMinVertex), _impl(MinVertexTSFact{}) {} + +TSFactory& TSFactory::instance() +{ + static TSFactory _instance; + return _instance; +} + +const TSKind& TSFactory::kind() const { return _kind; } -TSFact& TSFactory::ts_fact() +void TSFactory::set_ts_fact(TSKind kind) { - return *ts_fact_; + _kind = kind; + switch (kind) { + case TSKind::kMinVertex: { + _impl = MinVertexTSFact{}; + break; + } + + default: { + Util::ERROR("TSFactory::set_ts_fact: unsupported topological sorting ", + "implementation"); + break; + } + } } -void TSFactory::set_ts_fact(TSFactPtr ts_fact) +TopologicalSorting TSFactory::createTSAlgorithm() const { - ts_fact_ = std::move(ts_fact); + return std::visit([](const auto& a) { return a.createTSAlgorithm(); } + , _impl); } } // namespace LIB diff --git a/algorithms/toposort/ts_fact.hpp b/algorithms/sorting/topological/ts_fact.hpp similarity index 50% rename from algorithms/toposort/ts_fact.hpp rename to algorithms/sorting/topological/ts_fact.hpp index b29fa838..3fd7d935 100755 --- a/algorithms/toposort/ts_fact.hpp +++ b/algorithms/sorting/topological/ts_fact.hpp @@ -1,6 +1,6 @@ /** @file ts_fact.hpp - @brief Topological Sort Algorithm Factory + @brief Topological Sorting Algorithm Factory
@@ -21,61 +21,52 @@ ******************************************************************************/ -#ifndef SBG_TS_FACT_HPP -#define SBG_TS_FACT_HPP +#ifndef SBGRAPH_ALGORITHMS_SORTING_TOPOLOGICAL_TS_FACT_HPP_ +#define SBGRAPH_ALGORITHMS_SORTING_TOPOLOGICAL_TS_FACT_HPP_ -#include "topo_sort.hpp" +#include "algorithms/sorting/topological/min_vertex_ts.hpp" +#include "algorithms/sorting/topological/topological_sorting.hpp" namespace SBG { namespace LIB { -#define TS_FACT TSFactory::instance().ts_fact() +#define TS_FACT TSFactory::instance() -class TSFact { - public: - virtual ~TSFact() = default; - TSFact() = default; - - virtual TopoSort createTSAlgorithm() const = 0; - virtual std::string prettyPrint() const = 0; -}; - -class MinVertexTSFact : public TSFact { - public: +class MinVertexTSFact { +public: MinVertexTSFact() = default; - TopoSort createTSAlgorithm() const override; - std::string prettyPrint() const override; + TopologicalSorting createTSAlgorithm() const; }; -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). + * @brief Single instance of topological sorting factory to be used by clients + * in need of creating an instance of a matching algorithm. A client includes + * this file and calls TS_FACT.createTSAlgorithm(args). */ class TSFactory { - public: +public: ~TSFactory() = default; - static TSFactory& instance() { - static TSFactory instance_; - return instance_; - } - TSFact& ts_fact(); - void set_ts_fact(TSFactPtr ts_fact); + static TSFactory& instance(); + const TSKind& kind() const; + + void set_ts_fact(TSKind kind); + + TopologicalSorting createTSAlgorithm() const; + +private: + using TSFactImpl = std::variant; - private: TSFactory(); - TSFactPtr ts_fact_; + TSKind _kind; + TSFactImpl _impl; }; - } // namespace LIB } // namespace SBG -#endif +#endif // SBGRAPH_ALGORITHMS_SORTING_TOPOLOGICAL_TS_FACT_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 From 60369647414982e85c6a2f3abfcc2587dd5da410 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Wed, 29 Apr 2026 15:06:19 -0300 Subject: [PATCH 50/66] Small fixes --- algorithms/matching/bfs_paths.hpp | 4 ++-- algorithms/mfvs/greedy_mfvs.cpp | 1 + algorithms/scc/decreasing_edges_mrv.hpp | 4 ++-- algorithms/scc/minadj_mrv.cpp | 12 ++++++------ algorithms/scc/minadj_mrv.hpp | 2 +- sbg/bipartite_sbg.cpp | 6 ++++-- sbg/dom_ord_pwmap.hpp | 10 ++++++++-- sbg/linear_expr.cpp | 2 ++ sbg/linear_expr.hpp | 2 ++ sbg/ord_pwmap.hpp | 10 ++++++++-- sbg/rational.cpp | 3 +-- sbg/unord_pwmap.hpp | 13 ++++++++++--- test/performance/utils.cpp | 10 +++++----- 13 files changed, 52 insertions(+), 27 deletions(-) diff --git a/algorithms/matching/bfs_paths.hpp b/algorithms/matching/bfs_paths.hpp index cb008fc0..03f7f405 100644 --- a/algorithms/matching/bfs_paths.hpp +++ b/algorithms/matching/bfs_paths.hpp @@ -51,9 +51,9 @@ class BFSPaths : public PathsContext { /** * @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. */ Set calculate(const DirectedSBG& dsbg, const Set& endings); }; diff --git a/algorithms/mfvs/greedy_mfvs.cpp b/algorithms/mfvs/greedy_mfvs.cpp index 437d5f10..f75dfb5b 100644 --- a/algorithms/mfvs/greedy_mfvs.cpp +++ b/algorithms/mfvs/greedy_mfvs.cpp @@ -104,6 +104,7 @@ Set GreedyMFVS::calculate(const DirectedSBG& input_dsbg) const Util::DEBUG_LOG << "new rmap: " << rmap << "\n\n"; } + fvs_result.compact(); return fvs_result; } diff --git a/algorithms/scc/decreasing_edges_mrv.hpp b/algorithms/scc/decreasing_edges_mrv.hpp index c2fb9c81..92772d8d 100644 --- a/algorithms/scc/decreasing_edges_mrv.hpp +++ b/algorithms/scc/decreasing_edges_mrv.hpp @@ -51,7 +51,7 @@ 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 DirectedSBG& dsbg); @@ -65,7 +65,7 @@ class LtEdgesMRV : public MRVContext { Set decreasingRepresentative(const PWMap& rmap) const; /* - * @brief Calculates the MRV for recursive paths. + * @brief Calculates the MRV for repetitive paths. */ PWMap repetitivePaths(const PWMap& rmap, const PWMap& decreasing_smap); diff --git a/algorithms/scc/minadj_mrv.cpp b/algorithms/scc/minadj_mrv.cpp index 8eb11fc3..6b385283 100644 --- a/algorithms/scc/minadj_mrv.cpp +++ b/algorithms/scc/minadj_mrv.cpp @@ -61,9 +61,9 @@ PWMap MinAdjMRV::calculate(const DirectedSBG& dsbg) 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. + // 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(); @@ -74,8 +74,8 @@ PWMap MinAdjMRV::calculate(const DirectedSBG& dsbg) // 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)); @@ -113,7 +113,7 @@ PWMap MinAdjMRV::calculate(const DirectedSBG& dsbg) PWMap smap_plus = rmap.restrict(VR); smap_plus = std::move(smap_plus).combine(auxB.minAdj(auxD)); - // Update rmap for recursion, and leave the rest unchanged + // Update rmap for repetition, and leave the rest unchanged rec_rmap = std::move(smap_plus).combine(rec_rmap); rec_rmap.compact(); diff --git a/algorithms/scc/minadj_mrv.hpp b/algorithms/scc/minadj_mrv.hpp index 0f264088..e7040942 100644 --- a/algorithms/scc/minadj_mrv.hpp +++ b/algorithms/scc/minadj_mrv.hpp @@ -49,7 +49,7 @@ class MinAdjMRV : public MRVContext { * @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 DirectedSBG& dsbg); diff --git a/sbg/bipartite_sbg.cpp b/sbg/bipartite_sbg.cpp index 074d00ad..0ef02ec2 100644 --- a/sbg/bipartite_sbg.cpp +++ b/sbg/bipartite_sbg.cpp @@ -156,14 +156,16 @@ BipartiteSBG copy(unsigned int copies, BipartiteSBG sbg) Expression offset_v; for (std::size_t k = 0; k < max_v.arity(); ++k) { - offset_v = offset_v.cartesianProduct(Expression{1, max_v[k]}); + offset_v = offset_v.cartesianProduct(Expression{RATIONAL{1} + , RATIONAL{max_v[k]}}); } PWMap offset_pw_v = PWMAP_FACT.createPWMap(Map{V, offset_v}); 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{1, max_e[k]}); + offset_e = offset_e.cartesianProduct(Expression{RATIONAL{1} + , RATIONAL{max_e[k]}}); } PWMap offset_pw_e = PWMAP_FACT.createPWMap(Map{E, offset_e}); PWMap inverse_offset_pw_e = offset_pw_e.inverse(); diff --git a/sbg/dom_ord_pwmap.hpp b/sbg/dom_ord_pwmap.hpp index ac8ea5ab..62aa2f67 100644 --- a/sbg/dom_ord_pwmap.hpp +++ b/sbg/dom_ord_pwmap.hpp @@ -154,13 +154,19 @@ class DomOrdPWMap { template inline void DomOrdPWMap::emplace(Args&&... args) { - insert(Map{std::forward(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) { - _pieces.emplace_back(std::forward(args)...); + auto&& domain = std::get<0>(std::forward_as_tuple(args...)); + if (!domain.isEmpty()) { + _pieces.emplace_back(std::forward(args)...); + } } template diff --git a/sbg/linear_expr.cpp b/sbg/linear_expr.cpp index 0d921530..c8b73cb7 100755 --- a/sbg/linear_expr.cpp +++ b/sbg/linear_expr.cpp @@ -19,6 +19,8 @@ #include "sbg/linear_expr.hpp" +#include + namespace SBG { namespace LIB { diff --git a/sbg/linear_expr.hpp b/sbg/linear_expr.hpp index cdff8c87..774d1c17 100755 --- a/sbg/linear_expr.hpp +++ b/sbg/linear_expr.hpp @@ -29,6 +29,8 @@ #include "sbg/rational.hpp" +#include + namespace SBG { namespace LIB { diff --git a/sbg/ord_pwmap.hpp b/sbg/ord_pwmap.hpp index e0934391..c1da4eee 100644 --- a/sbg/ord_pwmap.hpp +++ b/sbg/ord_pwmap.hpp @@ -151,13 +151,19 @@ class OrdPWMap { template inline void OrdPWMap::emplace(Args&&... args) { - insert(Map{std::forward(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) { - _pieces.emplace_back(std::forward(args)...); + auto&& domain = std::get<0>(std::forward_as_tuple(args...)); + if (!domain.isEmpty()) { + _pieces.emplace_back(std::forward(args)...); + } } } // namespace detail diff --git a/sbg/rational.cpp b/sbg/rational.cpp index 3c30995d..40a8b87b 100755 --- a/sbg/rational.cpp +++ b/sbg/rational.cpp @@ -76,8 +76,7 @@ bool RATIONAL::operator>=(const RATIONAL& r) const bool RATIONAL::operator==(const INT& other) const { - RATIONAL aux = *this; - return aux.numerator() == other && aux.denominator() == 1; + return numerator() == other && denominator() == 1; } RATIONAL RATIONAL::operator-() const diff --git a/sbg/unord_pwmap.hpp b/sbg/unord_pwmap.hpp index 2d6d26d3..0a382420 100644 --- a/sbg/unord_pwmap.hpp +++ b/sbg/unord_pwmap.hpp @@ -27,8 +27,9 @@ #include "sbg/map.hpp" #include "sbg/set.hpp" -#include #include +#include +#include namespace SBG { @@ -133,13 +134,19 @@ class UnordPWMap { template inline void UnordPWMap::emplace(Args&&... args) { - _pieces.emplace_back(std::forward(args)...); + auto&& domain = std::get<0>(std::forward_as_tuple(args...)); + if (!domain.isEmpty()) { + _pieces.emplace_back(std::forward(args)...); + } } template inline void UnordPWMap::emplaceBack(Args&&... args) { - _pieces.emplace_back(std::forward(args)...); + auto&& domain = std::get<0>(std::forward_as_tuple(args...)); + if (!domain.isEmpty()) { + _pieces.emplace_back(std::forward(args)...); + } } } // namespace detail diff --git a/test/performance/utils.cpp b/test/performance/utils.cpp index 9510ed09..432cfbe3 100644 --- a/test/performance/utils.cpp +++ b/test/performance/utils.cpp @@ -196,7 +196,7 @@ PWMap denseDom(NAT map_sz) = SBG::LIB::SET_FACT.createSet(i.begin(), i.step(), i.end()); domain = std::move(domain).disjointCup(std::move(jth_domain)); } - Expression id{1, 0}; + Expression id{RATIONAL{1}, RATIONAL{0}}; pw.emplace(domain, id); } @@ -229,8 +229,8 @@ std::pair minAdjMaps(NAT map_sz) domain2 = std::move(domain2).disjointCup(std::move(jth_domain2)); } - Expression id{1, 0}; - Expression minus_one{1, RATIONAL{-1, 1}}; + Expression id{RATIONAL{1}, RATIONAL{0}}; + Expression minus_one{RATIONAL{1}, RATIONAL{-1, 1}}; pw1.emplace(domain1, id); pw2.emplace(domain2, minus_one); @@ -329,8 +329,8 @@ PWMap reducibleMaps(NAT map_sz) } domain = domain.cartesianProduct(second_dim); - Expression plus_one{1, 1}; - Expression id{1, 0}; + Expression plus_one{RATIONAL{1}, RATIONAL{1}}; + Expression id{RATIONAL{1}, RATIONAL{0}}; Expression expr = plus_one.cartesianProduct(id); pw.emplace(domain, expr); From 4aae6b4a7d93d22b4c501e141f6ddc8fd65abc59 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Wed, 29 Apr 2026 15:06:40 -0300 Subject: [PATCH 51/66] Finished redefinition of topological sorting --- algorithms/misc/causalization_builders.cpp | 28 ++-- algorithms/misc/causalization_builders.hpp | 3 +- .../sorting/topological/min_vertex_ts.cpp | 148 +++++++++--------- .../sorting/topological/min_vertex_ts.hpp | 17 +- eval/eval_exec.cpp | 8 +- eval/user_impl_map.cpp | 17 +- eval/user_impl_map.hpp | 5 +- eval/visitors/expr_evaluator.cpp | 11 +- eval/visitors/func_evaluator.cpp | 103 ++++++------ eval/visitors/func_evaluator.hpp | 2 + sbg/expression.cpp | 7 + sbg/expression.hpp | 6 + test/TestRL2.test | 2 +- test/TestRL3.test | 2 +- test/topsort2.test | 4 +- test/topsort3.test | 2 +- test/topsort4.test | 36 ++--- 17 files changed, 206 insertions(+), 195 deletions(-) diff --git a/algorithms/misc/causalization_builders.cpp b/algorithms/misc/causalization_builders.cpp index 92162f54..f7851a76 100644 --- a/algorithms/misc/causalization_builders.cpp +++ b/algorithms/misc/causalization_builders.cpp @@ -148,8 +148,8 @@ SBG::LIB::DirectedSBG buildLoopDetectionSBG(const SBG::LIB::MatchData& data) SBG::LIB::PWMap Emap = SBG::LIB::PWMAP_FACT.createPWMap(); std::tie(mapB, mapD, Emap) = buildSCCEdges(data, Vmap); - SBG::LIB::DirectedSBG dsbg{V, Vmap, mapB, mapD, Emap}; - Emap = partitionEmap(dsbg); + //SBG::LIB::DirectedSBG dsbg{V, Vmap, mapB, mapD, Emap}; + //Emap = partitionEmap(dsbg); return SBG::LIB::DirectedSBG{V, Vmap, mapB, mapD, Emap}; } @@ -172,27 +172,21 @@ SBG::LIB::DirectedSBG buildTearingSBG(const SBG::LIB::SCCData& data) // Vertical sort graph builder ------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -SBG::LIB::DirectedSBG buildVerticalSortingSBG(const SBG::LIB::SCCData& data) +SBG::LIB::DirectedSBG buildVerticalSortingSBG(const SBG::LIB::SCCData& data + , const SBG::LIB::Set& mfvs) { SBG::Util::Internal::TimeProfiler profiler{"SBG Vertical Sorting builder: "}; const SBG::LIB::DirectedSBG& dsbg = data.dsbg(); - SBG::LIB::PWMap rmap = data.rmap(); - SBG::LIB::Set Ediff = data.Ediff(); - SBG::LIB::PWMap mapB = rmap.composition(dsbg.mapB().restrict(Ediff)); - mapB.compact(); - SBG::LIB::PWMap mapD = rmap.composition(dsbg.mapD().restrict(Ediff)); - mapD.compact(); - - rmap.compact(); - SBG::LIB::PWMap aux_rmap = rmap; - SBG::LIB::PWMap reps_rmap = aux_rmap.restrict(aux_rmap.fixedPoints()); - SBG::LIB::Set V = reps_rmap.domain(); - - SBG::LIB::PWMap Vmap = dsbg.Vmap().restrict(V); + SBG::LIB::Set V = dsbg.V(); + SBG::LIB::PWMap Vmap = dsbg.Vmap(); - SBG::LIB::PWMap Emap = dsbg.Emap().restrict(Ediff); + 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 SBG::LIB::DirectedSBG{V, Vmap, mapB, mapD, Emap}; } diff --git a/algorithms/misc/causalization_builders.hpp b/algorithms/misc/causalization_builders.hpp index 53593613..180d39fb 100644 --- a/algorithms/misc/causalization_builders.hpp +++ b/algorithms/misc/causalization_builders.hpp @@ -53,7 +53,8 @@ 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); +SBG::LIB::DirectedSBG buildVerticalSortingSBG(const SBG::LIB::SCCData& data + , const SBG::LIB::Set& mfvs); } // namespace misc diff --git a/algorithms/sorting/topological/min_vertex_ts.cpp b/algorithms/sorting/topological/min_vertex_ts.cpp index 10114c1e..31b97576 100644 --- a/algorithms/sorting/topological/min_vertex_ts.cpp +++ b/algorithms/sorting/topological/min_vertex_ts.cpp @@ -36,50 +36,75 @@ namespace detail { MinVertexTS::MinVertexTS() : _smap(PWMAP_FACT.createPWMap()), _dsbg(), _visitedSV(SET_FACT.createSet()) - , _n(0) {} - -Expression calculateExpr(const MD_NAT& old_value, const MD_NAT& new_value) + , _priority(SET_FACT.createSet()), _same_SV(SET_FACT.createSet()) + , _independent(SET_FACT.createSet()) {} + +/* + * @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) { - return Expression{old_value}; + 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::independentRepetition(const Set& independent_V_plus, - const Expression& successor_expr) const +PWMap MinVertexTS::repetition(const Set& init_V + , const DirectedSBG& dsbg) const { PWMap result = PWMAP_FACT.createPWMap(); - result.emplace(independent_V_plus, successor_expr); - bool independent_image = result.image().difference(independent_V_plus).isEmpty(); - Util::ERROR_UNLESS(independent_image/*&& result.isInjective()*/ - , "MinVertexTS::independentRepetition: incorrect guessing ", result); + PWMap Vmap = dsbg.Vmap(); + Set Vj = init_V; + Set init_SV = Vmap.image(init_V); + bool repetition = true; + do { + PWMap jth_smap = _smap.restrict(Vj); + Set V_plus = Vmap.preImage(Vmap.image(Vj)).difference(_smap.domain()); + result.emplace(V_plus, (*jth_smap.begin()).law()); + Vj = _smap.image(Vj); + repetition = !Vmap.image(Vj).intersection(init_SV).isEmpty(); + } while (!repetition); + + checkSorting(result, dsbg); return result; } -PWMap MinVertexTS::dependentRepetition(const Set& init_V) const +MD_NAT MinVertexTS::getMinVertex() { - PWMap result = PWMAP_FACT.createPWMap(); - - Set Vi = init_V; - Set V = SET_FACT.createSet(); - for (unsigned int j = 0; j < _n; ++j) { - Vi = _smap.image(Vi); - V = std::move(V).disjointCup(std::move(Vi)); - } - PWMap smap_repetition = _smap.restrict(V); - PWMap mapB = _dsbg.mapB(); + Set V = _dsbg.V(); PWMap mapD = _dsbg.mapD(); - Set E_repetition = smap_repetition.composition(mapB).equalImage(mapD); - - PWMap Emap = _dsbg.Emap(); - Set E_plus = Emap.preImage(Emap.image(E_repetition)); - PWMap mapB_plus = mapB.restrict(E_plus); - PWMap mapD_plus = mapD.restrict(E_plus); - result = mapB_plus.minAdj(mapD_plus); + _independent = V.difference(mapD.image()); - /*TODO: check well-formed result*/ + 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 result; + return Vj.minElem(); } PWMap MinVertexTS::calculate(const DirectedSBG& dsbg @@ -89,60 +114,41 @@ PWMap MinVertexTS::calculate(const DirectedSBG& dsbg _dsbg = dsbg; - PWMap _smap = PWMAP_FACT.createPWMap(); + _smap = PWMAP_FACT.createPWMap(); - Set same_SCC = _dsbg.V(); - Set same_SV = _dsbg.V(); + if (dsbg.V().isEmpty()) { + return _smap; + } + + _priority = _dsbg.V(); + _same_SV = _dsbg.V(); Set visited_SV = SET_FACT.createSet(); Expression successor_expr{_dsbg.V().arity(), 1, 0}; - MD_NAT old_vi; + MD_NAT vj; + MD_NAT old_vj = _dsbg.V().difference(_dsbg.mapD().image()).minElem(); do { - Set V = _dsbg.V(); - PWMap mapD = _dsbg.mapD(); - Set independent = V.difference(mapD.image()); - - Set Vi = independent; - if (Vi.isEmpty()) { - Util::ERROR("Topological sorting: the SBG is not acyclic"); - } - Set independent_same_SCC = Vi.intersection(same_SCC); - if (independent_same_SCC.isEmpty()) { - Vi = independent_same_SCC; - } - Set Vi_same_SV = Vi.intersection(same_SV); - if (Vi_same_SV.isEmpty()) { - Vi = Vi_same_SV; - } + // Find new minimum vertex, and add it to the sorting + vj = getMinVertex(); + Set vj_set = SET_FACT.createSet(vj); + successor_expr = Expression{vj, old_vj}; + _smap.emplace(vj_set, successor_expr); // Handle repetition PWMap Vmap = _dsbg.Vmap(); - MD_NAT vi = Vi.minElem(); - Set vi_set = SET_FACT.createSet(vi); - Set repeatedSV = _visitedSV.intersection(Vmap.image(vi_set)); + Set repeatedSV = _visitedSV.intersection(Vmap.image(vj_set)); if (!repeatedSV.isEmpty()) { - Set V_plus = Vmap.preImage(Vmap.image(vi_set)); - Set independent_V_plus = independent.intersection(V_plus); - PWMap smap_plus = PWMAP_FACT.createPWMap(); - if (!independent_V_plus.isEmpty()) { - smap_plus = independentRepetition(independent_V_plus, successor_expr); - } else { - smap_plus = dependentRepetition(vi_set); - } + PWMap smap_plus = repetition(vj_set, dsbg); _smap = std::move(smap_plus).combine(std::move(_smap)); - _n = 0; - } else { - _smap.emplace(vi_set, successor_expr); - - _visitedSV = std::move(_visitedSV).disjointCup(Vmap.image(vi_set)); - ++_n; + vj = _smap.domain().difference(_smap.image()).minElem(); + } else { + _visitedSV = std::move(_visitedSV).disjointCup(Vmap.image(vj_set)); } // Update values for new iteration _dsbg.eraseVertices(_smap.domain()); - old_vi = vi; - successor_expr = calculateExpr(old_vi, vi); - same_SCC = pmap.preImage(pmap.image(vi_set)); - same_SV = Vmap.preImage(Vmap.image(vi_set)); + old_vj = vj; + _priority = pmap.preImage(pmap.image(vj_set)); + _same_SV = Vmap.preImage(Vmap.image(vj_set)); } while (!_dsbg.V().isEmpty()); _smap.compact(); diff --git a/algorithms/sorting/topological/min_vertex_ts.hpp b/algorithms/sorting/topological/min_vertex_ts.hpp index d0d14409..1a0d9242 100644 --- a/algorithms/sorting/topological/min_vertex_ts.hpp +++ b/algorithms/sorting/topological/min_vertex_ts.hpp @@ -40,25 +40,28 @@ namespace detail { // Minimum Vertex Topological Sorting Algorithm Implementation ----------------- //////////////////////////////////////////////////////////////////////////////// -/** - * @brief In each step takes out the minimum vertex without dependencies. - */ 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: - PWMap independentRepetition(const Set& independent_V_plus - , const Expression& successor_expr) const; + MD_NAT getMinVertex(); - PWMap dependentRepetition(const Set& init_V) const; + 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 _n; }; } // namespace detail diff --git a/eval/eval_exec.cpp b/eval/eval_exec.cpp index 72c27b8f..2eeb08fe 100644 --- a/eval/eval_exec.cpp +++ b/eval/eval_exec.cpp @@ -20,7 +20,7 @@ #include "algorithms/matching/matching_fact.hpp" #include "algorithms/mfvs/mfvs_fact.hpp" #include "algorithms/scc/scc_fact.hpp" -//#include "algorithms/toposort/ts_fact.hpp" +#include "algorithms/sorting/topological/ts_fact.hpp" #include "eval/eval_exec.hpp" #include "eval/file_evaluator.hpp" #include "eval/input_translator.hpp" @@ -56,9 +56,9 @@ void printHeader(Util::prog_opts::variables_map vm) std::cout << "-----------------------------------\n"; std::cout << "Matching algorithm: " << LIB::MATCH_FACT.kind() << "\n"; std::cout << "SCC algorithm: " << LIB::SCC_FACT.kind() << "\n"; - std::cout << "MFVS algorithm: " << LIB::MFVS_FACT.kind() << "\n\n"; - //std::cout << "Topological sort algorithm: " << LIB::TS_FACT.kind() - // << "\n"; + std::cout << "MFVS algorithm: " << LIB::MFVS_FACT.kind() << "\n"; + std::cout << "Topological sorting algorithm: " << LIB::TS_FACT.kind() + << "\n"; } std::cout << "-----------------------------------\n"; std::cout << ">>>>>>>>>>> Eval result <<<<<<<<<<<\n"; diff --git a/eval/user_impl_map.cpp b/eval/user_impl_map.cpp index 85cabb28..847eef8a 100755 --- a/eval/user_impl_map.cpp +++ b/eval/user_impl_map.cpp @@ -103,14 +103,13 @@ UserImplMap::StructImplMap mfvsMap() return mfvs_mapping; } -// TODO -//UserImplMap::StructImplMap tsMap() -//{ -// UserImplMap::StructImplMap ts_mapping; -// ts_mapping[0] = []() { return std::make_unique(); }; -// ts_mapping.freeze(); -// return ts_mapping; -//} +UserImplMap::StructImplMap tsMap() +{ + UserImplMap::StructImplMap ts_mapping; + ts_mapping[0] = LIB::TSKind::kMinVertex; + ts_mapping.freeze(); + return ts_mapping; +} //////////////////////////////////////////////////////////////////////////////// // User Implementation Map ----------------------------------------------------- @@ -123,7 +122,7 @@ UserImplMap::UserImplMap() implementations_["match"] = matchMap(); implementations_["scc"] = sccMap(); implementations_["mfvs"] = mfvsMap(); - //implementations_["ts"] = tsMap(); + implementations_["ts"] = tsMap(); } Kind UserImplMap::getFactory(std::string strct, int impl) diff --git a/eval/user_impl_map.hpp b/eval/user_impl_map.hpp index e7e4e749..bf37862b 100755 --- a/eval/user_impl_map.hpp +++ b/eval/user_impl_map.hpp @@ -32,7 +32,7 @@ #include "algorithms/mfvs/min_feedback_vertex_set.hpp" #include "algorithms/matching/matching.hpp" #include "algorithms/scc/scc.hpp" -//#include "algorithms/toposort/ts_fact.hpp" +#include "algorithms/sorting/topological/topological_sorting.hpp" #include "sbg/pw_map.hpp" #include "sbg/set.hpp" @@ -59,7 +59,8 @@ using Kind = std::variant; + , LIB::MFVSKind + , LIB::TSKind>; /** * @brief Mapping for all structures such as Set, PW and algorithms. diff --git a/eval/visitors/expr_evaluator.cpp b/eval/visitors/expr_evaluator.cpp index f967109e..1b36290d 100755 --- a/eval/visitors/expr_evaluator.cpp +++ b/eval/visitors/expr_evaluator.cpp @@ -17,13 +17,6 @@ ******************************************************************************/ -#include "algorithms/cc/cc.hpp" -//#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/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" @@ -76,6 +69,10 @@ ExprEvaluator::ExprEvaluator(EvalContext& eval_ctx) : _eval_context(eval_ctx) eval_ctx.insertFunction("scc", BuiltInFunctions::sccEvaluator); 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 diff --git a/eval/visitors/func_evaluator.cpp b/eval/visitors/func_evaluator.cpp index ae5818e0..e1eddb57 100755 --- a/eval/visitors/func_evaluator.cpp +++ b/eval/visitors/func_evaluator.cpp @@ -21,10 +21,13 @@ #include "algorithms/cc/cc.hpp" #include "algorithms/mfvs/min_feedback_vertex_set.hpp" #include "algorithms/mfvs/mfvs_fact.hpp" +#include "algorithms/matching/matching.hpp" #include "algorithms/matching/matching_fact.hpp" #include "algorithms/misc/causalization_builders.hpp" +#include "algorithms/scc/scc.hpp" #include "algorithms/scc/scc_fact.hpp" -//#include "algorithms/toposort/ts_fact.hpp" +#include "algorithms/sorting/topological/topological_sorting.hpp" +#include "algorithms/sorting/topological/ts_fact.hpp" #include "eval/base_type.hpp" #include "sbg/bipartite_sbg.hpp" #include "sbg/expression.hpp" @@ -35,6 +38,7 @@ #include "sbg/rational.hpp" #include "sbg/set.hpp" #include "sbg/pw_map.hpp" +#include "sbg/pwmap_fact.hpp" #include "util/debug.hpp" #include "util/defs.hpp" @@ -662,27 +666,14 @@ ExprBaseType BuiltInFunctions::matchSCCEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 2 , "matchSCCEvaluator: wrong number of arguments"); - LIB::Matching match_impl = LIB::MATCH_FACT.createMatchAlgorithm(); + 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::SCC_FACT.createSCCAlgorithm(); - const auto match_scc_evaluator = Util::Overload { - [&match_impl, &scc_impl](LIB::BipartiteSBG a, LIB::NAT b) { - LIB::MatchData match_result = match_impl.calculate(copy(b, a)); - LIB::DirectedSBG dsbg = misc::buildLoopDetectionSBG(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(copy(b[0], a)); - LIB::DirectedSBG dsbg = misc::buildLoopDetectionSBG(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{}; - } - }; + LIB::SCCData scc_result = scc_impl.calculate(dsbg); - return std::visit(match_scc_evaluator, args[0], args[1]); + return ExprBaseType{scc_result.rmap()}; } ExprBaseType BuiltInFunctions::mfvsEvaluator(const EBTList& args) @@ -704,16 +695,32 @@ ExprBaseType BuiltInFunctions::mfvsEvaluator(const EBTList& args) 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::SCC_FACT.createSCCAlgorithm(); + LIB::SCCData scc_result = scc_impl.calculate(dsbg); + + dsbg = misc::buildTearingSBG(scc_result); + LIB::MinFeedbackVertexSet mfvs_impl = LIB::MFVS_FACT.createMFVSAlgorithm(); + return ExprBaseType{mfvs_impl.calculate(dsbg)}; +} + ExprBaseType BuiltInFunctions::topoSortEvaluator(const EBTList& args) { Util::ERROR_UNLESS(args.size() == 1 , "topoSortEvaluator: wrong number of arguments\n"); - LIB::TopoSort ts_impl = LIB::TS_FACT.createTSAlgorithm(); + LIB::TopologicalSorting ts_impl = LIB::TS_FACT.createTSAlgorithm(); const auto ts_evaluator = Util::Overload { [&ts_impl](LIB::DirectedSBG a) { - return ExprBaseType{ts_impl.calculate(a)}; + return ExprBaseType{ts_impl.calculate(a, LIB::PWMAP_FACT.createPWMap())}; }, [](auto a) { Util::ERROR("topoSortEvaluator: wrong argument ", a, " for sort\n"); @@ -723,39 +730,27 @@ ExprBaseType BuiltInFunctions::topoSortEvaluator(const EBTList& args) return std::visit(ts_evaluator, args[0]); } -ExprBaseType BuiltInFunctions::matchSCCTSEvaluator(const EBTList& args) +ExprBaseType BuiltInFunctions::causalizationEvaluator(const EBTList& args) { - const auto match_scc_ts_evaluator = Util::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::buildLoopDetectionSBG(match), c); - LIB::PWMap scc_res = scc.calculate(); - LIB::DirectedSBG 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::buildLoopDetectionSBG(match), c); - LIB::PWMap scc_res = scc.calculate(); - LIB::DirectedSBG 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{}; - } - }; + Util::ERROR_UNLESS(args.size() == 2 + , "causalizationEvaluator: 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::SCC_FACT.createSCCAlgorithm(); + LIB::SCCData scc_result = scc_impl.calculate(dsbg); + + dsbg = misc::buildTearingSBG(scc_result); + LIB::MinFeedbackVertexSet mfvs_impl = LIB::MFVS_FACT.createMFVSAlgorithm(); + LIB::Set mfvs_result = mfvs_impl.calculate(dsbg); + + dsbg = misc::buildVerticalSortingSBG(scc_result, mfvs_result); + LIB::TopologicalSorting ts_impl = LIB::TS_FACT.createTSAlgorithm(); + LIB::PWMap ts_result = ts_impl.calculate(dsbg, scc_result.rmap()); + return ExprBaseType{ts_result}; } -*/ } // namespace detail diff --git a/eval/visitors/func_evaluator.hpp b/eval/visitors/func_evaluator.hpp index 62bec04f..d3967e6c 100755 --- a/eval/visitors/func_evaluator.hpp +++ b/eval/visitors/func_evaluator.hpp @@ -96,7 +96,9 @@ class BuiltInFunctions { static ExprBaseType sccEvaluator(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 diff --git a/sbg/expression.cpp b/sbg/expression.cpp index 941cb830..d3113bc4 100755 --- a/sbg/expression.cpp +++ b/sbg/expression.cpp @@ -49,6 +49,13 @@ Expression::Expression(std::size_t n, const RATIONAL& slope } } +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) diff --git a/sbg/expression.hpp b/sbg/expression.hpp index 810ed86b..76441d2f 100755 --- a/sbg/expression.hpp +++ b/sbg/expression.hpp @@ -67,6 +67,12 @@ class Expression { */ 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; diff --git a/test/TestRL2.test b/test/TestRL2.test index ee1c01c1..c7e69fa8 100644 --- a/test/TestRL2.test +++ b/test/TestRL2.test @@ -87,7 +87,7 @@ 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; -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 diff --git a/test/TestRL3.test b/test/TestRL3.test index 3ce50716..e4d714b6 100644 --- a/test/TestRL3.test +++ b/test/TestRL3.test @@ -91,7 +91,7 @@ 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; -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 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|>> ); From 1ce2d6e1f841f93a4590b98fbdefb18d02ca0a89 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 30 Apr 2026 15:59:02 -0300 Subject: [PATCH 52/66] Added smallest set-vertex MFVS implementation --- algorithms/matching/matching.cpp | 1 + algorithms/mfvs/CMakeLists.txt | 3 +- algorithms/mfvs/mfvs_fact.cpp | 19 +++- algorithms/mfvs/mfvs_fact.hpp | 9 +- algorithms/mfvs/min_feedback_vertex_set.cpp | 10 ++ algorithms/mfvs/min_feedback_vertex_set.hpp | 5 +- algorithms/mfvs/smallest_sv_mfvs.cpp | 115 ++++++++++++++++++++ algorithms/mfvs/smallest_sv_mfvs.hpp | 58 ++++++++++ algorithms/misc/causalization_builders.cpp | 13 ++- eval/eval_exec.cpp | 30 +++-- eval/eval_exec.hpp | 7 +- eval/input_translator.cpp | 5 + eval/user_impl_map.cpp | 11 ++ eval/user_impl_map.hpp | 1 + eval/user_input.cpp | 32 +++--- eval/user_input.hpp | 16 +-- 16 files changed, 284 insertions(+), 51 deletions(-) create mode 100644 algorithms/mfvs/smallest_sv_mfvs.cpp create mode 100644 algorithms/mfvs/smallest_sv_mfvs.hpp diff --git a/algorithms/matching/matching.cpp b/algorithms/matching/matching.cpp index ad0375ed..c34bdb09 100644 --- a/algorithms/matching/matching.cpp +++ b/algorithms/matching/matching.cpp @@ -60,6 +60,7 @@ Matching::Matching(MatchKind kind) : _kind(kind), _impl() default: { Util::ERROR("Unsupported matching algorithm implementation"); + break; } } } diff --git a/algorithms/mfvs/CMakeLists.txt b/algorithms/mfvs/CMakeLists.txt index 7dca6f68..2c4f4ed6 100644 --- a/algorithms/mfvs/CMakeLists.txt +++ b/algorithms/mfvs/CMakeLists.txt @@ -1,7 +1,8 @@ target_sources( sbgraph PRIVATE + greedy_mfvs.cpp min_feedback_vertex_set.cpp mfvs_fact.cpp - greedy_mfvs.cpp + smallest_sv_mfvs.cpp ) diff --git a/algorithms/mfvs/mfvs_fact.cpp b/algorithms/mfvs/mfvs_fact.cpp index e7f2961d..7ff2d8ee 100755 --- a/algorithms/mfvs/mfvs_fact.cpp +++ b/algorithms/mfvs/mfvs_fact.cpp @@ -25,7 +25,7 @@ namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Maximum Degree Cut Vertex Factory ------------------------------------------- +// Maximum Degree MFVS Factory ------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// MinFeedbackVertexSet GreedyMFVSFact::createMFVSAlgorithm() const @@ -33,12 +33,21 @@ MinFeedbackVertexSet GreedyMFVSFact::createMFVSAlgorithm() const return MinFeedbackVertexSet{MFVSKind::kGreedy}; } +//////////////////////////////////////////////////////////////////////////////// +// Smallest set-vertex MFVS Factory -------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +MinFeedbackVertexSet SmallSVMFVSFact::createMFVSAlgorithm() const +{ + return MinFeedbackVertexSet{MFVSKind::kSmallSV}; +} + //////////////////////////////////////////////////////////////////////////////// // Factory for clients --------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// MFVSFactory::MFVSFactory() - : _kind(MFVSKind::kGreedy), _impl(GreedyMFVSFact{}) {} + : _kind(MFVSKind::kSmallSV), _impl(SmallSVMFVSFact{}) {} MFVSFactory& MFVSFactory::instance() { @@ -54,6 +63,12 @@ void MFVSFactory::set_mfvs_fact(MFVSKind kind) switch (kind) { case MFVSKind::kGreedy: { _impl = GreedyMFVSFact{}; + break; + } + + case MFVSKind::kSmallSV: { + _impl = SmallSVMFVSFact{}; + break; } default: { diff --git a/algorithms/mfvs/mfvs_fact.hpp b/algorithms/mfvs/mfvs_fact.hpp index fefd4c11..516a5cde 100755 --- a/algorithms/mfvs/mfvs_fact.hpp +++ b/algorithms/mfvs/mfvs_fact.hpp @@ -39,6 +39,13 @@ class GreedyMFVSFact { MinFeedbackVertexSet createMFVSAlgorithm() const; }; +class SmallSVMFVSFact { +public: + SmallSVMFVSFact() = default; + + MinFeedbackVertexSet createMFVSAlgorithm() const; +}; + /** * @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 @@ -56,7 +63,7 @@ class MFVSFactory { MinFeedbackVertexSet createMFVSAlgorithm() const; private: - using MFVSFactImpl = std::variant; + using MFVSFactImpl = std::variant; MFVSFactory(); diff --git a/algorithms/mfvs/min_feedback_vertex_set.cpp b/algorithms/mfvs/min_feedback_vertex_set.cpp index f35cbbce..1d2cda4d 100644 --- a/algorithms/mfvs/min_feedback_vertex_set.cpp +++ b/algorithms/mfvs/min_feedback_vertex_set.cpp @@ -37,6 +37,11 @@ std::ostream& operator<<(std::ostream& out, const MFVSKind kind) break; } + case MFVSKind::kSmallSV: { + out << "smallest set-vertex"; + break; + } + default: { Util::ERROR("MFVSKind::operator<<: unsupported MFVS implementation"); break; @@ -58,6 +63,11 @@ MinFeedbackVertexSet::MinFeedbackVertexSet(MFVSKind kind) : _kind(kind), _impl() break; } + case MFVSKind::kSmallSV: { + _impl = detail::SmallestSVMFVS{}; + break; + } + default: { Util::ERROR("MinFeedbackVertexSet: unsupported MFVS implementation"); break; diff --git a/algorithms/mfvs/min_feedback_vertex_set.hpp b/algorithms/mfvs/min_feedback_vertex_set.hpp index 2471ed12..71f978b3 100644 --- a/algorithms/mfvs/min_feedback_vertex_set.hpp +++ b/algorithms/mfvs/min_feedback_vertex_set.hpp @@ -25,6 +25,7 @@ #define SBGRAPH_ALGORITHMS_MFVS_MIN_FEEDBACK_VERTEX_SET_HPP_ #include "algorithms/mfvs/greedy_mfvs.hpp" +#include "algorithms/mfvs/smallest_sv_mfvs.hpp" #include "sbg/directed_sbg.hpp" #include @@ -40,11 +41,11 @@ namespace detail { // Minimum Feedback Vertex Set Implementations -------------------------------- /////////////////////////////////////////////////////////////////////////////// -using MFVSImpl = std::variant; +using MFVSImpl = std::variant; } -enum class MFVSKind { kGreedy }; +enum class MFVSKind { kGreedy, kSmallSV }; std::ostream& operator<<(std::ostream& out, const MFVSKind kind); diff --git a/algorithms/mfvs/smallest_sv_mfvs.cpp b/algorithms/mfvs/smallest_sv_mfvs.cpp new file mode 100644 index 00000000..2399c3a1 --- /dev/null +++ b/algorithms/mfvs/smallest_sv_mfvs.cpp @@ -0,0 +1,115 @@ +/******************************************************************************* + + 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 "algorithms/scc/scc_fact.hpp" +#include "sbg/natural.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/set_fact.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_FACT.createSet(jth_mult)); + } + + Set small_sv = mmap.preImage(SET_FACT.createSet(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_FACT.createSCCAlgorithm().calculate(dsbg).rmap(); + Set fvs_result = SET_FACT.createSet(); + Set visitedSV = SET_FACT.createSet(); + while (rmap.fixedPoints() != rmap.domain()) { + // Get vertex from smallest set-vertex + MD_NAT smallest_sv_vertex = getVertexFromSmallestSV(dsbg); + Set Vj = SET_FACT.createSet(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_FACT.createSCCAlgorithm().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 f7851a76..4bece21e 100644 --- a/algorithms/misc/causalization_builders.cpp +++ b/algorithms/misc/causalization_builders.cpp @@ -89,14 +89,15 @@ std::tuple buildSCCEdges( return {mapB, mapD, Emap}; } -SBG::LIB::PWMap partitionEmap(const SBG::LIB::DirectedSBG& dsbg) +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 = dsbg.V().arity(); + std::size_t arity = V.arity(); SBG::LIB::NAT j = 1; SBG::LIB::PWMap partitioned_Emap = SBG::LIB::PWMAP_FACT.createPWMap(); dsbg.foreachSetEdge([&](const SBG::LIB::MD_NAT& SE) @@ -132,7 +133,7 @@ SBG::LIB::PWMap partitionEmap(const SBG::LIB::DirectedSBG& dsbg) } }); - return partitioned_Emap; + dsbg = SBG::LIB::DirectedSBG{V, Vmap, mapB, mapD, partitioned_Emap}; } SBG::LIB::DirectedSBG buildLoopDetectionSBG(const SBG::LIB::MatchData& data) @@ -148,10 +149,10 @@ SBG::LIB::DirectedSBG buildLoopDetectionSBG(const SBG::LIB::MatchData& data) SBG::LIB::PWMap Emap = SBG::LIB::PWMAP_FACT.createPWMap(); std::tie(mapB, mapD, Emap) = buildSCCEdges(data, Vmap); - //SBG::LIB::DirectedSBG dsbg{V, Vmap, mapB, mapD, Emap}; - //Emap = partitionEmap(dsbg); + SBG::LIB::DirectedSBG dsbg{V, Vmap, mapB, mapD, Emap}; + partitionEmap(dsbg); - return SBG::LIB::DirectedSBG{V, Vmap, mapB, mapD, Emap}; + return dsbg; } //////////////////////////////////////////////////////////////////////////////// diff --git a/eval/eval_exec.cpp b/eval/eval_exec.cpp index 2eeb08fe..70b30046 100644 --- a/eval/eval_exec.cpp +++ b/eval/eval_exec.cpp @@ -69,23 +69,27 @@ 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_), + ("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)"); + "\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); @@ -105,21 +109,23 @@ detail::EvalUserInput EvalExecutor::chooseImplementation() 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()) { + 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; } diff --git a/eval/eval_exec.hpp b/eval/eval_exec.hpp index 57926879..2c47c238 100644 --- a/eval/eval_exec.hpp +++ b/eval/eval_exec.hpp @@ -40,9 +40,10 @@ class EvalExecutor : public Util::UserInputHandler { 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 diff --git a/eval/input_translator.cpp b/eval/input_translator.cpp index 32614386..8a3b8746 100755 --- a/eval/input_translator.cpp +++ b/eval/input_translator.cpp @@ -51,6 +51,11 @@ void InputTranslator::translate(EvalUserInput& input) if (scc) { setSCCFactory(*scc); } + + EvalUserInput::MaybeInt mfvs = input.mfvs_impl(); + if (mfvs) { + setMFVSFactory(*mfvs); + } } } // namespace detail diff --git a/eval/user_impl_map.cpp b/eval/user_impl_map.cpp index 847eef8a..bfa96fe2 100755 --- a/eval/user_impl_map.cpp +++ b/eval/user_impl_map.cpp @@ -18,6 +18,7 @@ ******************************************************************************/ #include "algorithms/scc/scc_fact.hpp" +#include "algorithms/mfvs/mfvs_fact.hpp" #include "eval/user_impl_map.hpp" #include "sbg/pw_map.hpp" #include "sbg/pwmap_fact.hpp" @@ -99,6 +100,7 @@ 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; } @@ -160,6 +162,15 @@ void setSCCFactory(int scc_impl) return; } +void setMFVSFactory(int mfvs_impl) +{ + LIB::MFVSKind mfvs_fact = std::get( + detail::IMPL_MAP.getFactory("mfvs", mfvs_impl)); + LIB::MFVS_FACT.set_mfvs_fact(mfvs_fact); + + return; +} + } // namespace Eval } // namespace SBG diff --git a/eval/user_impl_map.hpp b/eval/user_impl_map.hpp index bf37862b..8b846fe5 100755 --- a/eval/user_impl_map.hpp +++ b/eval/user_impl_map.hpp @@ -113,6 +113,7 @@ class UserImplMap { void setSetFactory(int set_impl); void setPWFactory(int pw_impl); void setSCCFactory(int scc_impl); +void setMFVSFactory(int mfvs_impl); } // namespace Eval diff --git a/eval/user_input.cpp b/eval/user_input.cpp index b07184df..7d60ece9 100755 --- a/eval/user_input.cpp +++ b/eval/user_input.cpp @@ -33,64 +33,64 @@ 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 diff --git a/eval/user_input.hpp b/eval/user_input.hpp index 6205b40e..e2215f02 100755 --- a/eval/user_input.hpp +++ b/eval/user_input.hpp @@ -46,23 +46,23 @@ 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_; + MaybeInt _set_impl; + MaybeInt _pw_impl; + MaybeInt _match_impl; + MaybeInt _scc_impl; + MaybeInt _ts_impl; + MaybeInt _mfvs_impl; }; } // detail From bb159af9e7fcc3c156d1837f1656ae130d1da90e Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Thu, 7 May 2026 15:08:03 -0300 Subject: [PATCH 53/66] Redefined JSON causalization output --- algorithms/misc/CMakeLists.txt | 2 +- algorithms/misc/causalization_json.cpp | 127 +++++++++---------------- algorithms/misc/causalization_json.hpp | 35 +++++-- eval/visitors/func_evaluator.cpp | 6 ++ sbg/dom_ord_pwmap.cpp | 15 +++ sbg/dom_ord_pwmap.hpp | 7 ++ sbg/expression.cpp | 13 +++ sbg/expression.hpp | 4 + sbg/interval.cpp | 16 ++++ sbg/interval.hpp | 6 ++ sbg/linear_expr.cpp | 21 ++++ sbg/linear_expr.hpp | 9 +- sbg/map.cpp | 12 +++ sbg/map.hpp | 6 ++ sbg/multidim_inter.cpp | 19 ++++ sbg/multidim_inter.hpp | 9 ++ sbg/ord_pwmap.cpp | 14 +++ sbg/ord_pwmap.hpp | 6 ++ sbg/ord_set.cpp | 18 ++++ sbg/ord_set.hpp | 7 ++ sbg/ord_unidim_dense_set.cpp | 47 ++++----- sbg/ord_unidim_dense_set.hpp | 8 +- sbg/pw_map.cpp | 6 ++ sbg/pw_map.hpp | 4 + sbg/set.cpp | 6 ++ sbg/set.hpp | 3 + sbg/unord_pwmap.cpp | 15 +++ sbg/unord_pwmap.hpp | 7 ++ sbg/unord_set.cpp | 19 ++++ sbg/unord_set.hpp | 7 ++ 30 files changed, 352 insertions(+), 122 deletions(-) diff --git a/algorithms/misc/CMakeLists.txt b/algorithms/misc/CMakeLists.txt index c63671cb..059c12aa 100644 --- a/algorithms/misc/CMakeLists.txt +++ b/algorithms/misc/CMakeLists.txt @@ -2,5 +2,5 @@ target_sources( sbgraph PRIVATE causalization_builders.cpp -# causalization_json.cpp + causalization_json.cpp ) diff --git a/algorithms/misc/causalization_json.cpp b/algorithms/misc/causalization_json.cpp index 021fcd02..b2ee1535 100644 --- a/algorithms/misc/causalization_json.cpp +++ b/algorithms/misc/causalization_json.cpp @@ -17,117 +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 result(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); - result.PushBack(mdi_obj, alloc); - } - - return result; -} - -rapidjson::Value expJson(Exp exp, rapidjson::Document::AllocatorType &alloc) -{ - rapidjson::Value result(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) {} - result.PushBack(le_array, alloc); - } - - return result; +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 result(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; +} - result.PushBack(ith, alloc); - } +const SBG::LIB::Set& CausalizationResult::mfvs() const { return _mfvs; } - return result; +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(); - // Create matching information - rapidjson::Value edges = setJson(matching, alloc); - d.AddMember("matching", edges, alloc); + // Save causalization results + document.AddMember("horizontal_sorting" + , causalized.horizontal_sorting().toJSON(alloc), alloc); - // Create SCC information - rapidjson::Value scc_rmap = mapJson(scc, alloc); - d.AddMember("scc", scc_rmap, alloc); + document.AddMember("algebraic_loops" + , causalized.algebraic_loops().toJSON(alloc), alloc); - // Create sort information - rapidjson::Value order_rmap = mapJson(order, alloc); - d.AddMember("sort", order_rmap, alloc); + document.AddMember("mfvs", causalized.mfvs().toJSON(alloc), 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); } -} // 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/eval/visitors/func_evaluator.cpp b/eval/visitors/func_evaluator.cpp index e1eddb57..de869386 100755 --- a/eval/visitors/func_evaluator.cpp +++ b/eval/visitors/func_evaluator.cpp @@ -24,6 +24,7 @@ #include "algorithms/matching/matching.hpp" #include "algorithms/matching/matching_fact.hpp" #include "algorithms/misc/causalization_builders.hpp" +#include "algorithms/misc/causalization_json.hpp" #include "algorithms/scc/scc.hpp" #include "algorithms/scc/scc_fact.hpp" #include "algorithms/sorting/topological/topological_sorting.hpp" @@ -749,6 +750,11 @@ ExprBaseType BuiltInFunctions::causalizationEvaluator(const EBTList& args) dsbg = misc::buildVerticalSortingSBG(scc_result, mfvs_result); LIB::TopologicalSorting ts_impl = LIB::TS_FACT.createTSAlgorithm(); 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}; } diff --git a/sbg/dom_ord_pwmap.cpp b/sbg/dom_ord_pwmap.cpp index 385a65a3..6df36804 100644 --- a/sbg/dom_ord_pwmap.cpp +++ b/sbg/dom_ord_pwmap.cpp @@ -836,6 +836,21 @@ void DomOrdPWMap::compact() _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 diff --git a/sbg/dom_ord_pwmap.hpp b/sbg/dom_ord_pwmap.hpp index 62aa2f67..35bb7fa1 100644 --- a/sbg/dom_ord_pwmap.hpp +++ b/sbg/dom_ord_pwmap.hpp @@ -32,6 +32,8 @@ #include "sbg/map_entry.hpp" #include "sbg/set.hpp" +#include "rapidjson/document.h" + #include #include @@ -172,6 +174,11 @@ inline void DomOrdPWMap::emplaceBack(Args&&... 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 diff --git a/sbg/expression.cpp b/sbg/expression.cpp index d3113bc4..dcabdd2f 100755 --- a/sbg/expression.cpp +++ b/sbg/expression.cpp @@ -225,6 +225,19 @@ Expression Expression::cartesianProduct(const Expression& other) const 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 index 76441d2f..40feee5c 100755 --- a/sbg/expression.hpp +++ b/sbg/expression.hpp @@ -32,6 +32,8 @@ #include "sbg/linear_expr.hpp" #include "sbg/multidim_inter.hpp" +#include "rapidjson/document.h" + #include namespace SBG { @@ -125,6 +127,8 @@ class Expression { */ Expression cartesianProduct(const Expression& other) const; + rapidjson::Value toJSON(rapidjson::Document::AllocatorType& alloc) const; + private: detail::ExpressionImpl _impl; diff --git a/sbg/interval.cpp b/sbg/interval.cpp index e79bf820..75def842 100755 --- a/sbg/interval.cpp +++ b/sbg/interval.cpp @@ -192,6 +192,22 @@ MaybeInterval Interval::compact(const Interval& other) const 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 diff --git a/sbg/interval.hpp b/sbg/interval.hpp index cc052285..1ed623b5 100755 --- a/sbg/interval.hpp +++ b/sbg/interval.hpp @@ -34,6 +34,8 @@ #include "sbg/natural.hpp" #include "sbg/perimeter.hpp" +#include "rapidjson/document.h" + #include #include @@ -105,6 +107,10 @@ 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 diff --git a/sbg/linear_expr.cpp b/sbg/linear_expr.cpp index c8b73cb7..c361747e 100755 --- a/sbg/linear_expr.cpp +++ b/sbg/linear_expr.cpp @@ -20,6 +20,7 @@ #include "sbg/linear_expr.hpp" #include +#include namespace SBG { @@ -136,6 +137,26 @@ 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 diff --git a/sbg/linear_expr.hpp b/sbg/linear_expr.hpp index 774d1c17..a61a5b65 100755 --- a/sbg/linear_expr.hpp +++ b/sbg/linear_expr.hpp @@ -29,6 +29,8 @@ #include "sbg/rational.hpp" +#include "rapidjson/document.h" + #include namespace SBG { @@ -96,7 +98,12 @@ class LinearExpr { RATIONAL _slope; RATIONAL _offset; }; -std::ostream &operator<<(std::ostream &out, const LinearExpr &le); +std::ostream &operator<<(std::ostream &out, const LinearExpr& le); + +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(LinearExpr le + , rapidjson::Document::AllocatorType& alloc); } // namespace detail diff --git a/sbg/map.cpp b/sbg/map.cpp index 5d1a192e..f7f1c8ef 100755 --- a/sbg/map.cpp +++ b/sbg/map.cpp @@ -206,6 +206,18 @@ MaybeMap Map::compact(const Map& other) const 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 7780f027..875eecc1 100755 --- a/sbg/map.hpp +++ b/sbg/map.hpp @@ -33,6 +33,8 @@ #include "sbg/expression.hpp" #include "sbg/set.hpp" +#include "rapidjson/document.h" + #include #include #include @@ -167,6 +169,10 @@ class Map { }; 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 diff --git a/sbg/multidim_inter.cpp b/sbg/multidim_inter.cpp index 6bb69ff6..1f290667 100755 --- a/sbg/multidim_inter.cpp +++ b/sbg/multidim_inter.cpp @@ -254,6 +254,25 @@ MaybeMDI MultiDimInter::compact(const MultiDimInter& other) const return result; } +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(MultiDimInter mdi + , rapidjson::Document::AllocatorType& alloc) +{ + rapidjson::Value result{rapidjson::kArrayType}; + + rapidjson::Value interval_array{rapidjson::kArrayType}; + for (const Interval& i : mdi) { + rapidjson::Value jth = toJSON(i, alloc); + interval_array.PushBack(jth, alloc); + } + rapidjson::Value mdi_obj{rapidjson::kObjectType}; + mdi_obj.AddMember("bounds", interval_array, alloc); + result.PushBack(mdi_obj, alloc); + + return result; +} + } // namespace detail } // namespace LIB diff --git a/sbg/multidim_inter.hpp b/sbg/multidim_inter.hpp index 9f71cdaf..c90a5182 100755 --- a/sbg/multidim_inter.hpp +++ b/sbg/multidim_inter.hpp @@ -32,6 +32,8 @@ #include "sbg/natural.hpp" #include "sbg/perimeter.hpp" +#include "rapidjson/document.h" + #include #include @@ -136,12 +138,19 @@ class MultiDimInter { }; 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); + } // namespace detail } // namespace LIB diff --git a/sbg/ord_pwmap.cpp b/sbg/ord_pwmap.cpp index ff78e465..4aee6612 100644 --- a/sbg/ord_pwmap.cpp +++ b/sbg/ord_pwmap.cpp @@ -802,6 +802,20 @@ void OrdPWMap::compact() _pieces = std::move(result._pieces); } +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(OrdPWMap 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 diff --git a/sbg/ord_pwmap.hpp b/sbg/ord_pwmap.hpp index c1da4eee..088a59b9 100644 --- a/sbg/ord_pwmap.hpp +++ b/sbg/ord_pwmap.hpp @@ -28,6 +28,8 @@ #include "sbg/map_entry.hpp" #include "sbg/set.hpp" +#include "rapidjson/document.h" + #include #include @@ -166,6 +168,10 @@ inline void OrdPWMap::emplaceBack(Args&&... args) } } +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(OrdPWMap pw, rapidjson::Document::AllocatorType& alloc); + } // namespace detail } // namespace LIB diff --git a/sbg/ord_set.cpp b/sbg/ord_set.cpp index 7451850c..7b96a88f 100644 --- a/sbg/ord_set.cpp +++ b/sbg/ord_set.cpp @@ -677,6 +677,24 @@ void OrderedSet::compact() _pieces = std::move(result); } +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(OrderedSet s, rapidjson::Document::AllocatorType& alloc) +{ + rapidjson::Value result{rapidjson::kArrayType}; + + 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 mdi_obj{rapidjson::kObjectType}; + mdi_obj.AddMember("pieces", mdi_array, alloc); + result.PushBack(mdi_obj, alloc); + + return result; +} + } // namespace detail } // namespace LIB diff --git a/sbg/ord_set.hpp b/sbg/ord_set.hpp index f44ae1cd..cd0d2a0f 100644 --- a/sbg/ord_set.hpp +++ b/sbg/ord_set.hpp @@ -31,6 +31,8 @@ #include "sbg/natural.hpp" #include "sbg/perimeter.hpp" +#include "rapidjson/document.h" + #include #include #include @@ -118,6 +120,11 @@ class OrderedSet { friend class SetAccessKey; }; +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(OrderedSet s + , rapidjson::Document::AllocatorType& alloc); + } // namespace detail } // namespace LIB diff --git a/sbg/ord_unidim_dense_set.cpp b/sbg/ord_unidim_dense_set.cpp index a04d6dcc..6ff7edcd 100644 --- a/sbg/ord_unidim_dense_set.cpp +++ b/sbg/ord_unidim_dense_set.cpp @@ -133,34 +133,6 @@ OrdUnidimDenseSet::ConstIt OrdUnidimDenseSet::end() const // Setters --------------------------------------------------------------------- -/* -void OrdUnidimDenseSet::emplace(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.begin(); - auto end = _pieces.end(); - for (; it != end; ++it) { - if (mdi < *it) { - break; - } - } - _pieces.emplace(it, mdi); -} -*/ - void OrdUnidimDenseSet::pushBack(const Interval& i) { if (i.isEmpty()) { @@ -515,6 +487,25 @@ OrdUnidimDenseSet OrdUnidimDenseSet::traverse( return result; } +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(OrdUnidimDenseSet s + , rapidjson::Document::AllocatorType& alloc) +{ + rapidjson::Value result{rapidjson::kArrayType}; + + rapidjson::Value interval_array{rapidjson::kArrayType}; + for (const Interval& i : s) { + rapidjson::Value jth = detail::toJSON(i, alloc); + interval_array.PushBack(jth, alloc); + } + rapidjson::Value mdi_obj{rapidjson::kObjectType}; + mdi_obj.AddMember("pieces", interval_array, alloc); + result.PushBack(mdi_obj, alloc); + + return result; +} + } // namespace detail } // namespace LIB diff --git a/sbg/ord_unidim_dense_set.hpp b/sbg/ord_unidim_dense_set.hpp index 2b190c6e..30ac1b23 100644 --- a/sbg/ord_unidim_dense_set.hpp +++ b/sbg/ord_unidim_dense_set.hpp @@ -34,6 +34,8 @@ #include "sbg/natural.hpp" #include "sbg/perimeter.hpp" +#include "rapidjson/document.h" + #include #include #include @@ -115,12 +117,16 @@ class OrdUnidimDenseSet { OrdUnidimDenseSet traverse(Interval f(const Interval&, const Interval&) , const OrdUnidimDenseSet& other) const; -private: OrdIntervalCollection _pieces; friend class SetAccessKey; }; +// Non-member definitions ------------------------------------------------------ + +rapidjson::Value toJSON(OrdUnidimDenseSet s + , rapidjson::Document::AllocatorType& alloc); + } // namespace detail } // namespace LIB diff --git a/sbg/pw_map.cpp b/sbg/pw_map.cpp index 060c4ae2..b541cb68 100644 --- a/sbg/pw_map.cpp +++ b/sbg/pw_map.cpp @@ -470,6 +470,12 @@ void PWMap::compact() std::visit([](auto& a) { a.compact(); }, _impl); } +rapidjson::Value PWMap::toJSON(rapidjson::Document::AllocatorType& alloc) const +{ + return std::visit([&alloc](auto a) { return detail::toJSON(a, alloc); } + , _impl); +} + } // namespace LIB } // namespace SBG diff --git a/sbg/pw_map.hpp b/sbg/pw_map.hpp index b3dd6856..ab9f5a9f 100644 --- a/sbg/pw_map.hpp +++ b/sbg/pw_map.hpp @@ -40,6 +40,8 @@ #include "sbg/set.hpp" #include "sbg/unord_pwmap.hpp" +#include "rapidjson/document.h" + namespace SBG { namespace LIB { @@ -238,6 +240,8 @@ class PWMap { */ void compact(); + rapidjson::Value toJSON(rapidjson::Document::AllocatorType& alloc) const; + private: PWMap(const detail::PWMapImpl& impl); PWMap(detail::PWMapImpl&& impl); diff --git a/sbg/set.cpp b/sbg/set.cpp index c2ba3275..eb61c7e3 100644 --- a/sbg/set.cpp +++ b/sbg/set.cpp @@ -352,6 +352,12 @@ Perimeter Set::perimeter() const 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 } // namespace SBG diff --git a/sbg/set.hpp b/sbg/set.hpp index 9eb30441..46cdb8ba 100644 --- a/sbg/set.hpp +++ b/sbg/set.hpp @@ -44,6 +44,8 @@ #include "sbg/perimeter.hpp" #include "sbg/unord_set.hpp" +#include "rapidjson/document.h" + #include #include #include @@ -111,6 +113,7 @@ class Set { Set offset(const MD_NAT& off) const; Perimeter perimeter() const; void compact(); + rapidjson::Value toJSON(rapidjson::Document::AllocatorType& alloc) const; private: Set(const detail::SetImpl& impl); diff --git a/sbg/unord_pwmap.cpp b/sbg/unord_pwmap.cpp index 87031df6..ef560326 100644 --- a/sbg/unord_pwmap.cpp +++ b/sbg/unord_pwmap.cpp @@ -544,6 +544,21 @@ void UnordPWMap::compact() _pieces = std::move(result); } +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(UnordPWMap pw + , rapidjson::Document::AllocatorType& alloc) +{ + rapidjson::Value result{rapidjson::kArrayType}; + + for (const Map& m : pw) { + rapidjson::Value jth = toJSON(m, alloc); + result.PushBack(jth, alloc); + } + + return result; +} + } // namespace detail } // namespace LIB diff --git a/sbg/unord_pwmap.hpp b/sbg/unord_pwmap.hpp index 0a382420..549855be 100644 --- a/sbg/unord_pwmap.hpp +++ b/sbg/unord_pwmap.hpp @@ -27,6 +27,8 @@ #include "sbg/map.hpp" #include "sbg/set.hpp" +#include "rapidjson/document.h" + #include #include #include @@ -149,6 +151,11 @@ inline void UnordPWMap::emplaceBack(Args&&... args) } } +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(UnordPWMap pw + , rapidjson::Document::AllocatorType& alloc); + } // namespace detail } // namespace LIB diff --git a/sbg/unord_set.cpp b/sbg/unord_set.cpp index 487f0276..88d9e64a 100644 --- a/sbg/unord_set.cpp +++ b/sbg/unord_set.cpp @@ -479,6 +479,25 @@ void UnorderedSet::compact() _pieces = std::move(result); } +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(UnorderedSet s + , rapidjson::Document::AllocatorType& alloc) +{ + rapidjson::Value result{rapidjson::kArrayType}; + + 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 mdi_obj{rapidjson::kObjectType}; + mdi_obj.AddMember("pieces", mdi_array, alloc); + result.PushBack(mdi_obj, alloc); + + return result; +} + } // namespace detail } // namespace LIB diff --git a/sbg/unord_set.hpp b/sbg/unord_set.hpp index 75f4c0ac..6315b6b1 100644 --- a/sbg/unord_set.hpp +++ b/sbg/unord_set.hpp @@ -31,6 +31,8 @@ #include "sbg/natural.hpp" #include "sbg/perimeter.hpp" +#include "rapidjson/document.h" + #include #include #include @@ -104,6 +106,11 @@ class UnorderedSet { friend class SetAccessKey; }; +// Non-member functions -------------------------------------------------------- + +rapidjson::Value toJSON(UnorderedSet s + , rapidjson::Document::AllocatorType& alloc); + } // namespace detail } // namespace LIB From 3974030bc336f86fca28a32751590caa0928cd4f Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Fri, 22 May 2026 11:43:07 -0300 Subject: [PATCH 54/66] [SBG Map]: debugged Map::minAdj --- sbg/map.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sbg/map.cpp b/sbg/map.cpp index f7f1c8ef..cff9c9ed 100755 --- a/sbg/map.cpp +++ b/sbg/map.cpp @@ -171,13 +171,17 @@ Set Map::lessImage(const Map& other) const Map Map::minAdj(const Map& other) const { - Set result_domain = image(_domain.intersection(other._domain)); + Set this_other_dom = _domain.intersection(other._domain); + if (this_other_dom.isEmpty()) { + return Map{}; + } + Set result_domain = image(this_other_dom); Expression result_expr; - Set image2 = other.image(result_domain); if (_law.isInjective()) { result_expr = other._law.composition(_law.inverse()); } else { + Set image2 = other.image(this_other_dom); result_expr = Expression{image2.minElem()}; } From 5a0481883602b49dd4d249556cad09ae99a23017 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Sat, 23 May 2026 20:23:49 -0300 Subject: [PATCH 55/66] [SBG Set]: added SetImplementation, deleted Set::_kind --- sbg/map.cpp | 13 ++-- sbg/map_detail.cpp | 4 +- sbg/set.cpp | 51 +++++++------- sbg/set.hpp | 14 ++-- sbg/set_fact.cpp | 172 --------------------------------------------- sbg/set_fact.hpp | 103 --------------------------- sbg/set_impl.cpp | 72 +++++++++++++++++++ sbg/set_impl.hpp | 68 ++++++++++++++++++ 8 files changed, 178 insertions(+), 319 deletions(-) delete mode 100644 sbg/set_fact.cpp delete mode 100644 sbg/set_fact.hpp create mode 100644 sbg/set_impl.cpp create mode 100644 sbg/set_impl.hpp diff --git a/sbg/map.cpp b/sbg/map.cpp index cff9c9ed..89d7c149 100755 --- a/sbg/map.cpp +++ b/sbg/map.cpp @@ -19,7 +19,6 @@ #include "sbg/map.hpp" #include "sbg/map_detail.hpp" -#include "sbg/set_fact.hpp" #include @@ -33,10 +32,10 @@ namespace LIB { // Constructors/Destructors ---------------------------------------------------- -Map::Map() : _domain(SET_FACT.createSet()) {} +Map::Map() : _domain() {} Map::Map(const MD_NAT& x, const Expression& expr) - : _domain(SET_FACT.createSet(x)), _law(expr) {} + : _domain(x), _law(expr) {} Map::Map(const Set& s, const Expression& expr) : _domain(s), _law(expr) {} @@ -111,12 +110,12 @@ Set Map::image() const { return image(_domain); } Set Map::image(const Set& subdom) const { if (isEmpty() || subdom.isEmpty()) { - return SET_FACT.createSet(); + return Set{}; } Set domain_subdom = _domain.intersection(subdom); if (domain_subdom.isEmpty()) { - return SET_FACT.createSet(); + return Set{}; } return detail::MapDetail::image(domain_subdom, _law); @@ -143,7 +142,7 @@ Map Map::composition(const Map& other) const Set Map::fixedPoints() const { FixedPointsInfo fixed_points_info = _law.fixedPoints(); - Set universal_fixed = SET_FACT.createSet(fixed_points_info); + Set universal_fixed{fixed_points_info}; return _domain.intersection(std::move(universal_fixed)); } @@ -200,7 +199,7 @@ std::vector Map::imageMultiplicity() const MaybeMap Map::compact(const Map& other) const { - Set result_domain = SET_FACT.createSet(); + Set result_domain; if (_law == other.law()) { Set result_dom = _domain.disjointCup(other.domain()); result_dom.compact(); diff --git a/sbg/map_detail.cpp b/sbg/map_detail.cpp index 1938e2e9..7d6256d0 100755 --- a/sbg/map_detail.cpp +++ b/sbg/map_detail.cpp @@ -22,7 +22,7 @@ #include "sbg/ord_unidim_dense_set.hpp" #include "sbg/rational.hpp" #include "sbg/set_detail.hpp" -#include "sbg/set_fact.hpp" +#include "sbg/set_impl.hpp" #include "sbg/unord_set.hpp" #include "util/debug.hpp" @@ -277,7 +277,7 @@ void lessImage(const Expr& expr1 Set MapDetail::lessImage(const Expression& expr1, const Expression& expr2) { - Set result = SET_FACT.createSet(); + Set result; SetAccessKey key = SetAccess::key(); auto less_image_evaluator = Util::Overload { diff --git a/sbg/set.cpp b/sbg/set.cpp index eb61c7e3..60ab2924 100644 --- a/sbg/set.cpp +++ b/sbg/set.cpp @@ -18,6 +18,7 @@ ******************************************************************************/ #include "sbg/set.hpp" +#include "sbg/set_impl.hpp" #include "util/debug.hpp" #include @@ -27,24 +28,27 @@ namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Set implementations --------------------------------------------------------- +// Set ------------------------------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// -std::ostream& operator<<(std::ostream& out, const SetKind kind) +// Constructors ---------------------------------------------------------------- + +Set::Set() : _impl() { + SetKind kind = SET_IMPL.kind(); switch (kind) { case SetKind::kUnordered: { - out << "unordered"; + _impl = detail::UnorderedSet{}; break; } case SetKind::kOrdered: { - out << "ordered"; + _impl = detail::OrderedSet{}; break; } case SetKind::kOrdUnidimDense: { - out << "uni-dimensional ordered dense"; + _impl = detail::OrdUnidimDenseSet{}; break; } @@ -53,31 +57,24 @@ std::ostream& operator<<(std::ostream& out, const SetKind kind) break; } } - - return out; } -//////////////////////////////////////////////////////////////////////////////// -// Set ------------------------------------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -// Constructors ---------------------------------------------------------------- - -Set::Set(const SetKind kind) : _impl() +Set::Set(const MD_NAT& x) : _impl() { + SetKind kind = SET_IMPL.kind(); switch (kind) { case SetKind::kUnordered: { - _impl = detail::UnorderedSet{}; + _impl = detail::UnorderedSet{x}; break; } case SetKind::kOrdered: { - _impl = detail::OrderedSet{}; + _impl = detail::OrderedSet{x}; break; } case SetKind::kOrdUnidimDense: { - _impl = detail::OrdUnidimDenseSet{}; + _impl = detail::OrdUnidimDenseSet{x[0]}; break; } @@ -88,8 +85,9 @@ Set::Set(const SetKind kind) : _impl() } } -Set::Set(const SetKind kind, const MD_NAT& x) : _impl() +Set::Set(MD_NAT&& x) : _impl() { + SetKind kind = SET_IMPL.kind(); switch (kind) { case SetKind::kUnordered: { _impl = detail::UnorderedSet{x}; @@ -113,9 +111,9 @@ Set::Set(const SetKind kind, const MD_NAT& x) : _impl() } } -Set::Set(const SetKind kind, const NAT lo, const NAT step, const NAT hi) - : _impl() +Set::Set(const NAT lo, const NAT step, const NAT hi) : _impl() { + SetKind kind = SET_IMPL.kind(); switch (kind) { case SetKind::kUnordered: { _impl = detail::UnorderedSet{detail::Interval(lo, step, hi)}; @@ -139,8 +137,9 @@ Set::Set(const SetKind kind, const NAT lo, const NAT step, const NAT hi) } } -Set::Set(const SetKind kind, const FixedPointsInfo& info) : _impl() +Set::Set(const FixedPointsInfo& info) : _impl() { + SetKind kind = SET_IMPL.kind(); switch (kind) { case SetKind::kUnordered: { _impl = detail::UnorderedSet{info}; @@ -224,7 +223,7 @@ Set Set::intersection(const Set& other) const & return Set{a.intersection(b)}; } else { Util::ERROR("Set::intersection: mismatched implementations\n"); - return Set{SetKind::kUnordered}; + return Set{}; } } , _impl, other._impl); @@ -255,7 +254,7 @@ Set Set::cup(Set&& other) && return Set{std::move(a).cup(std::move(b))}; } else { Util::ERROR("Set::cup: mismatched implementations\n"); - return Set{SetKind::kUnordered}; + return Set{}; } } , std::move(_impl), std::move(other._impl)); @@ -278,7 +277,7 @@ Set Set::difference(const Set& other) const return Set{a.difference(b)}; } else { Util::ERROR("Set::difference: mismatched implementations\n"); - return Set{SetKind::kUnordered}; + return Set{}; } } , _impl, other._impl); @@ -294,7 +293,7 @@ Set Set::cartesianProduct(const Set& other) const return Set{a.cartesianProduct(b)}; } else { Util::ERROR("Set::cartesianProduct: mismatched implementations\n"); - return Set{SetKind::kUnordered}; + return Set{}; } } , _impl, other._impl); @@ -332,7 +331,7 @@ Set Set::disjointCup(Set&& other) && return Set{std::move(a).disjointCup(std::move(b))}; } else { Util::ERROR("Set::disjointCup: mismatched implementations\n"); - return Set{SetKind::kUnordered}; + return Set{}; } } , std::move(_impl), std::move(other._impl)); diff --git a/sbg/set.hpp b/sbg/set.hpp index 46cdb8ba..2887c8d6 100644 --- a/sbg/set.hpp +++ b/sbg/set.hpp @@ -68,21 +68,17 @@ class SetAccessKey; } -enum class SetKind { kUnordered, kOrdered, kOrdUnidimDense }; - -std::ostream& operator<<(std::ostream& out, const SetKind kind); - //////////////////////////////////////////////////////////////////////////////// // Set ------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// class Set { public: - Set(const SetKind kind); - Set(const SetKind kind, const MD_NAT& x); - Set(const SetKind kind, MD_NAT&& x); - Set(const SetKind kind, const NAT lo, const NAT st, const NAT hi); - Set(const SetKind kind, const FixedPointsInfo& info); + 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; diff --git a/sbg/set_fact.cpp b/sbg/set_fact.cpp deleted file mode 100644 index 6aa07089..00000000 --- a/sbg/set_fact.cpp +++ /dev/null @@ -1,172 +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/ord_set.hpp" -#include "sbg/ord_unidim_dense_set.hpp" -#include "sbg/set_fact.hpp" -#include "sbg/unord_set.hpp" -#include "util/debug.hpp" - -namespace SBG { - -namespace LIB { - -//////////////////////////////////////////////////////////////////////////////// -// Unordered Set Factory ------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -Set UnordSetFact::createSet() -{ - return Set{SetKind::kUnordered}; -} - -Set UnordSetFact::createSet(const MD_NAT& x) -{ - return Set{SetKind::kUnordered, x}; -} - -Set UnordSetFact::createSet(const NAT lo, const NAT step, const NAT hi) -{ - return Set{SetKind::kUnordered, lo, step, hi}; -} - -Set UnordSetFact::createSet(const FixedPointsInfo& info) -{ - return Set{SetKind::kUnordered, info}; -} - -//////////////////////////////////////////////////////////////////////////////// -// Ordered Set Factory --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -Set OrdSetFact::createSet() -{ - return Set{SetKind::kOrdered}; -} - -Set OrdSetFact::createSet(const MD_NAT& x) -{ - return Set{SetKind::kOrdered, x}; -} - -Set OrdSetFact::createSet(const NAT lo, const NAT step, const NAT hi) -{ - return Set{SetKind::kOrdered, lo, step, hi}; -} - -Set OrdSetFact::createSet(const FixedPointsInfo& info) -{ - return Set{SetKind::kOrdered, info}; -} - -//////////////////////////////////////////////////////////////////////////////// -// Ordered Unidimensional Dense Set Factory ------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -Set OrdUnidimDenseSetFact::createSet() -{ - return Set{SetKind::kOrdUnidimDense}; -} - -Set OrdUnidimDenseSetFact::createSet(const MD_NAT& x) -{ - return Set{SetKind::kOrdUnidimDense, x}; -} - -Set OrdUnidimDenseSetFact::createSet(const NAT lo, const NAT step, const NAT hi) -{ - return Set{SetKind::kOrdUnidimDense, lo, step, hi}; -} - -Set OrdUnidimDenseSetFact::createSet(const FixedPointsInfo& info) -{ - return Set{SetKind::kOrdUnidimDense, info}; -} - -//////////////////////////////////////////////////////////////////////////////// -// Factory for clients --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -SetFactory::SetFactory() : _kind(SetKind::kUnordered), _impl(UnordSetFact{}) {} - -SetFactory& SetFactory::instance() -{ - static SetFactory _instance; - return _instance; -} - -const SetKind& SetFactory::kind() const { return _kind; } - -void SetFactory::set_set_fact(SetKind kind) -{ - _kind = kind; - switch (kind) { - case SetKind::kUnordered: { - _impl = UnordSetFact{}; - break; - } - - case SetKind::kOrdered: { - _impl = OrdSetFact{}; - break; - } - - case SetKind::kOrdUnidimDense: { - _impl = OrdUnidimDenseSetFact{}; - break; - } - - default: { - Util::ERROR("Unsupported ", kind, " Set implementation\n"); - break; - } - } -} - -Set SetFactory::createSet() const -{ - return std::visit( - [](const auto& a) { return a.createSet(); } - , _impl); -} - -Set SetFactory::createSet(const MD_NAT& x) const -{ - return std::visit( - [&x](const auto& a) { return a.createSet(x); } - , _impl); -} - -Set SetFactory::createSet(const NAT lo, const NAT step, const NAT hi) const -{ - return std::visit( - [&](const auto& a) { return a.createSet(lo, step, hi); } - , _impl); -} - -Set SetFactory::createSet(const FixedPointsInfo& info) const -{ - return std::visit( - [&info](const auto& a) { return a.createSet(info); } - , _impl); -} - -} // namespace LIB - -} // namespace SBG diff --git a/sbg/set_fact.hpp b/sbg/set_fact.hpp deleted file mode 100644 index ec2f33de..00000000 --- a/sbg/set_fact.hpp +++ /dev/null @@ -1,103 +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 SBGRAPH_SBG_SET_FACT_HPP_ -#define SBGRAPH_SBG_SET_FACT_HPP_ - -#include "sbg/interval.hpp" -#include "sbg/multidim_inter.hpp" -#include "sbg/natural.hpp" -#include "sbg/set.hpp" - -#include -#include - -namespace SBG { - -namespace LIB { - -#define SET_FACT SetFactory::instance() - -class UnordSetFact { -public: - static Set createSet(); - static Set createSet(const MD_NAT& x); - static Set createSet(const NAT lo, const NAT step, const NAT hi); - static Set createSet(const FixedPointsInfo& info); -}; - -class OrdUnidimDenseSetFact { -public: - static Set createSet(); - static Set createSet(const MD_NAT& x); - static Set createSet(const NAT lo, const NAT step, const NAT hi); - static Set createSet(const FixedPointsInfo& info); -}; - -class OrdSetFact { -public: - static Set createSet(); - static Set createSet(const MD_NAT& x); - static Set createSet(const NAT lo, const NAT step, const NAT hi); - static Set createSet(const FixedPointsInfo& info); -}; - -/** - * @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(); - - void set_set_fact(SetKind kind); - const SetKind& kind() const; - - Set createSet() const; - Set createSet(const MD_NAT& x) const; - Set createSet(const NAT lo, const NAT step, const NAT hi) const; - Set createSet(const FixedPointsInfo& mdi) const; - -private: - using FactImpl = std::variant; - - SetFactory(); - - SetKind _kind; - FactImpl _impl; -}; - -} // namespace LIB - -} // namespace SBG - -#endif // SBGRAPH_SBG_SET_FACT_HPP_ 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_ From 460a01fc0a978996510d921222ff8a48555b2e39 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Sat, 23 May 2026 20:24:16 -0300 Subject: [PATCH 56/66] [SBG PWMap]: added PWMapImplementation, deleted PWMap::_kind --- sbg/CMakeLists.txt | 4 +- sbg/bipartite_sbg.cpp | 18 +++-- sbg/bipartite_sbg.hpp | 5 +- sbg/directed_sbg.cpp | 7 +- sbg/directed_sbg.hpp | 5 +- sbg/dom_ord_pwmap.cpp | 41 +++++------- sbg/dom_ord_pwmap.hpp | 2 +- sbg/ord_pwmap.cpp | 27 ++++---- sbg/pw_map.cpp | 60 +++++------------ sbg/pw_map.hpp | 13 ++-- sbg/pwmap_fact.cpp | 150 ------------------------------------------ sbg/pwmap_fact.hpp | 95 -------------------------- sbg/pwmap_impl.cpp | 75 +++++++++++++++++++++ sbg/pwmap_impl.hpp | 65 ++++++++++++++++++ sbg/sbg.cpp | 6 +- sbg/sbg.hpp | 5 +- sbg/unord_pwmap.cpp | 23 ++++--- 17 files changed, 219 insertions(+), 382 deletions(-) delete mode 100644 sbg/pwmap_fact.cpp delete mode 100644 sbg/pwmap_fact.hpp create mode 100644 sbg/pwmap_impl.cpp create mode 100644 sbg/pwmap_impl.hpp diff --git a/sbg/CMakeLists.txt b/sbg/CMakeLists.txt index 3c549b5f..01a2c1b2 100644 --- a/sbg/CMakeLists.txt +++ b/sbg/CMakeLists.txt @@ -25,12 +25,12 @@ target_sources( perimeter.cpp pw_map.cpp pwmap_detail.cpp - pwmap_fact.cpp + pwmap_impl.cpp rational.cpp sbg.cpp set.cpp set_detail.cpp - set_fact.cpp + set_impl.cpp unord_pwmap.cpp unord_set.cpp ) diff --git a/sbg/bipartite_sbg.cpp b/sbg/bipartite_sbg.cpp index 0ef02ec2..853e4470 100644 --- a/sbg/bipartite_sbg.cpp +++ b/sbg/bipartite_sbg.cpp @@ -19,8 +19,6 @@ #include "sbg/bipartite_sbg.hpp" #include "sbg/natural.hpp" -#include "sbg/pwmap_fact.hpp" -#include "sbg/set_fact.hpp" #include "util/debug.hpp" #include @@ -32,10 +30,10 @@ namespace LIB { // Constructors/Destructors ---------------------------------------------------- BipartiteSBG::BipartiteSBG() - : _V(SET_FACT.createSet()), _Vmap(PWMAP_FACT.createPWMap()) - , _E(SET_FACT.createSet()), _map1(PWMAP_FACT.createPWMap()) - , _map2(PWMAP_FACT.createPWMap()), _Emap(PWMAP_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 @@ -145,7 +143,7 @@ BipartiteSBG copy(unsigned int copies, BipartiteSBG sbg) MD_NAT max_v = sbg.V().maxElem(); Set set_vertices = Vmap.image(); while (!set_vertices.isEmpty()) { - Set min_elem_set = SET_FACT.createSet(set_vertices.minElem()); + 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); @@ -159,7 +157,7 @@ BipartiteSBG copy(unsigned int copies, BipartiteSBG sbg) offset_v = offset_v.cartesianProduct(Expression{RATIONAL{1} , RATIONAL{max_v[k]}}); } - PWMap offset_pw_v = PWMAP_FACT.createPWMap(Map{V, offset_v}); + PWMap offset_pw_v{Map{V, offset_v}}; MD_NAT max_e = sbg.E().maxElem(); Expression offset_e; @@ -167,12 +165,12 @@ BipartiteSBG copy(unsigned int copies, BipartiteSBG sbg) offset_e = offset_e.cartesianProduct(Expression{RATIONAL{1} , RATIONAL{max_e[k]}}); } - PWMap offset_pw_e = PWMAP_FACT.createPWMap(Map{E, offset_e}); + 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_FACT.createSet(set_edges.minElem()); + Set min_elem_set{set_edges.minElem()}; Set edges = Emap.preImage(min_elem_set); PWMap pw1 = map1.restrict(edges); PWMap pw2 = map2.restrict(edges); diff --git a/sbg/bipartite_sbg.hpp b/sbg/bipartite_sbg.hpp index b4e1b5a0..9152e308 100644 --- a/sbg/bipartite_sbg.hpp +++ b/sbg/bipartite_sbg.hpp @@ -29,7 +29,6 @@ #include "sbg/pw_map.hpp" #include "sbg/set.hpp" -#include "sbg/set_fact.hpp" #include @@ -113,7 +112,7 @@ inline void BipartiteSBG::foreachSetVertex(FuncT&& f) const while (!remaining.isEmpty()) { const MD_NAT& x = remaining.minElem(); f(x); - remaining = remaining.difference(SET_FACT.createSet(x)); + remaining = remaining.difference(Set{x}); } } @@ -124,7 +123,7 @@ inline void BipartiteSBG::foreachSetEdge(FuncT&& f) const while (!remaining.isEmpty()) { const MD_NAT& x = remaining.minElem(); f(x); - remaining = remaining.difference(SET_FACT.createSet(x)); + remaining = remaining.difference(Set{x}); } } diff --git a/sbg/directed_sbg.cpp b/sbg/directed_sbg.cpp index 40dd976d..c5ba4f74 100644 --- a/sbg/directed_sbg.cpp +++ b/sbg/directed_sbg.cpp @@ -19,8 +19,6 @@ #include "sbg/natural.hpp" #include "sbg/directed_sbg.hpp" -#include "sbg/pwmap_fact.hpp" -#include "sbg/set_fact.hpp" #include "util/debug.hpp" #include @@ -35,10 +33,7 @@ namespace LIB { // Constructors/Destructors ---------------------------------------------------- -DirectedSBG::DirectedSBG() - : _V(SET_FACT.createSet()), _Vmap(PWMAP_FACT.createPWMap()) - , _E(SET_FACT.createSet()), _mapB(PWMAP_FACT.createPWMap()) - , _mapD(PWMAP_FACT.createPWMap()), _Emap(PWMAP_FACT.createPWMap()) {} +DirectedSBG::DirectedSBG() : _V(), _Vmap(), _E(), _mapB(), _mapD(), _Emap() {} DirectedSBG::DirectedSBG(const Set& V, const PWMap& Vmap , const PWMap& mapB, const PWMap& mapD diff --git a/sbg/directed_sbg.hpp b/sbg/directed_sbg.hpp index b89d9f4c..9100d8d2 100644 --- a/sbg/directed_sbg.hpp +++ b/sbg/directed_sbg.hpp @@ -40,7 +40,6 @@ #define SBGRAPH_SBG_DIRECTED_SBG_HPP_ #include "sbg/set.hpp" -#include "sbg/set_fact.hpp" #include "sbg/pw_map.hpp" #include @@ -123,7 +122,7 @@ inline void DirectedSBG::foreachSetVertex(FuncT&& f) const while (!remaining.isEmpty()) { const MD_NAT& x = remaining.minElem(); f(x); - remaining = remaining.difference(SET_FACT.createSet(x)); + remaining = remaining.difference(Set{x}); } } @@ -134,7 +133,7 @@ inline void DirectedSBG::foreachSetEdge(FuncT&& f) const while (!remaining.isEmpty()) { const MD_NAT& x = remaining.minElem(); f(x); - remaining = remaining.difference(SET_FACT.createSet(x)); + remaining = remaining.difference(Set{x}); } } diff --git a/sbg/dom_ord_pwmap.cpp b/sbg/dom_ord_pwmap.cpp index 6df36804..579e1b3d 100644 --- a/sbg/dom_ord_pwmap.cpp +++ b/sbg/dom_ord_pwmap.cpp @@ -24,7 +24,7 @@ #include "sbg/perimeter.hpp" #include "sbg/pwmap_detail.hpp" #include "sbg/set_detail.hpp" -#include "sbg/set_fact.hpp" +#include "sbg/set_impl.hpp" #include "util/defs.hpp" #include "util/debug.hpp" @@ -176,11 +176,6 @@ Core traverse(const OrdCollection1& lhs, const OrdCollection2& rhs { OrdCollection1 short_collection = lhs; OrdCollection2 long_collection = rhs; - //if (!core_op.orderMatters() - // && long_collection.size() < short_collection.size()) { - // short_collection = rhs; - // long_collection = lhs; - //} // Indexes list corresponding to remaining maps in short_collection std::forward_list indexes; @@ -345,7 +340,7 @@ bool DomOrdPWMap::isEmpty() const { return _pieces.empty(); } Set DomOrdPWMap::domain() const & { - Set result = SET_FACT.createSet(); + Set result; for (const MapEntry& entry : _pieces) { result = std::move(result).disjointCup(entry.map().domain()); @@ -356,7 +351,7 @@ Set DomOrdPWMap::domain() const & Set DomOrdPWMap::domain() && { - Set result = SET_FACT.createSet(); + Set result; for (MapEntry& entry : _pieces) { result = std::move(result).disjointCup(std::move(entry.map()).domain()); @@ -404,24 +399,18 @@ DomOrdPWMap DomOrdPWMap::restrict(const Set& subdom) const }, [&](const auto& impl) { - Util::ERROR("DomOrdPWMap::restrict: unsupported ", SET_FACT.kind() + Util::ERROR("DomOrdPWMap::restrict: unsupported ", SET_IMPL.kind() , " set implementation"); return DomOrdPWMap{}; } }; - //print(std::cout); - //std::cout << "\n"; - //std::cout << subdom << "\n"; - //std::visit(restrict_evaluator, key.impl(subdom)).print(std::cout); - //std::cout << "\n\n"; - return std::visit(restrict_evaluator, key.impl(subdom)); } Set DomOrdPWMap::image() const { - Set result = SET_FACT.createSet(); + Set result; for (const MapEntry& entry : _pieces) { result = std::move(result).cup(entry.map().image()); @@ -437,7 +426,7 @@ Set DomOrdPWMap::image(const Set& subdom) const Set DomOrdPWMap::preImage(const Set& subcodom) const { - Set result = SET_FACT.createSet(); + Set result; for (const MapEntry& entry : _pieces) { result = std::move(result).disjointCup(entry.map().preImage(subcodom)); @@ -515,7 +504,7 @@ DomOrdPWMap DomOrdPWMap::mapInf() const { return mapInf(0); } Set DomOrdPWMap::fixedPoints() const { - Set result = SET_FACT.createSet(); + Set result; for (const MapEntry& entry : _pieces) { result = std::move(result).disjointCup(entry.map().fixedPoints()); @@ -675,7 +664,7 @@ class MinAdjCore { private: DomOrdPWMap _result; - Set _visited = SET_FACT.createSet(); + Set _visited; }; DomOrdPWMap DomOrdPWMap::minAdj(const DomOrdPWMap& other) const @@ -689,8 +678,8 @@ DomOrdPWMap DomOrdPWMap::minAdj(const DomOrdPWMap& other) const Set DomOrdPWMap::sharedImage() const { - Set repeated_image = SET_FACT.createSet(); - Set visited = SET_FACT.createSet(); + Set repeated_image; + Set visited; for (const MapEntry& entry : _pieces) { Set m_image = entry.map().image(); Set image_in_visited = m_image.intersection(visited); @@ -726,13 +715,13 @@ class EqualImageCore { Set result() const { return _result; } private: - Set _result = SET_FACT.createSet(); + Set _result; }; Set DomOrdPWMap::equalImage(const DomOrdPWMap& other) const { if (isEmpty() || other.isEmpty()) { - return SET_FACT.createSet(); + return Set{}; } if (_pieces == other._pieces) { @@ -756,17 +745,17 @@ class LessImageCore { Set result() const { return _result; } private: - Set _result = SET_FACT.createSet(); + Set _result; }; Set DomOrdPWMap::lessImage(const DomOrdPWMap& other) const { if (isEmpty() || other.isEmpty()) { - return SET_FACT.createSet(); + return Set{}; } if (_pieces == other._pieces) { - return SET_FACT.createSet(); + return Set{}; } return traverse(_pieces, other._pieces, LessImageCore{}).result(); diff --git a/sbg/dom_ord_pwmap.hpp b/sbg/dom_ord_pwmap.hpp index 35bb7fa1..be6eefd7 100644 --- a/sbg/dom_ord_pwmap.hpp +++ b/sbg/dom_ord_pwmap.hpp @@ -44,7 +44,7 @@ namespace LIB { namespace detail { //////////////////////////////////////////////////////////////////////////////// -// Ordered PWMap Implementation ---------------------------------------------- +// Domain ordered PWMap Implementation ----------------------------------------- //////////////////////////////////////////////////////////////////////////////// class DomOrdPWMap { diff --git a/sbg/ord_pwmap.cpp b/sbg/ord_pwmap.cpp index 4aee6612..fa7dc85f 100644 --- a/sbg/ord_pwmap.cpp +++ b/sbg/ord_pwmap.cpp @@ -17,7 +17,6 @@ ******************************************************************************/ -#include "sbg/set_fact.hpp" #include "sbg/ord_pwmap.hpp" #include "sbg/perimeter.hpp" @@ -336,7 +335,7 @@ bool OrdPWMap::isEmpty() const { return _pieces.empty(); } Set OrdPWMap::domain() const & { - Set result = SET_FACT.createSet(); + Set result; for (const MapEntry& entry : _pieces) { result = std::move(result).disjointCup(entry.map().domain()); @@ -347,7 +346,7 @@ Set OrdPWMap::domain() const & Set OrdPWMap::domain() && { - Set result = SET_FACT.createSet(); + Set result; for (MapEntry& entry : _pieces) { result = std::move(result).disjointCup(std::move(entry.map()).domain()); @@ -387,7 +386,7 @@ OrdPWMap OrdPWMap::restrict(const Set& subdom) const Set OrdPWMap::image() const { - Set result = SET_FACT.createSet(); + Set result; for (const MapEntry& entry : _pieces) { result = std::move(result).cup(entry.map().image()); @@ -403,7 +402,7 @@ Set OrdPWMap::image(const Set& subdom) const Set OrdPWMap::preImage(const Set& subcodom) const { - Set result = SET_FACT.createSet(); + Set result; for (const MapEntry& entry : _pieces) { result = std::move(result).disjointCup(entry.map().preImage(subcodom)); @@ -481,7 +480,7 @@ OrdPWMap OrdPWMap::mapInf() const { return mapInf(0); } Set OrdPWMap::fixedPoints() const { - Set result = SET_FACT.createSet(); + Set result; for (const MapEntry& entry : _pieces) { result = std::move(result).disjointCup(entry.map().fixedPoints()); @@ -641,7 +640,7 @@ class MinAdjCore { private: OrdPWMap _result; - Set _visited = SET_FACT.createSet(); + Set _visited; }; OrdPWMap OrdPWMap::minAdj(const OrdPWMap& other) const @@ -655,8 +654,8 @@ OrdPWMap OrdPWMap::minAdj(const OrdPWMap& other) const Set OrdPWMap::sharedImage() const { - Set repeated_image = SET_FACT.createSet(); - Set visited = SET_FACT.createSet(); + Set repeated_image; + Set visited; for (const MapEntry& entry : _pieces) { Set m_image = entry.map().image(); Set image_in_visited = m_image.intersection(visited); @@ -692,13 +691,13 @@ class EqualImageCore { Set result() const { return _result; } private: - Set _result = SET_FACT.createSet(); + Set _result; }; Set OrdPWMap::equalImage(const OrdPWMap& other) const { if (isEmpty() || other.isEmpty()) { - return SET_FACT.createSet(); + return Set{}; } if (_pieces == other._pieces) { @@ -722,17 +721,17 @@ class LessImageCore { Set result() const { return _result; } private: - Set _result = SET_FACT.createSet(); + Set _result; }; Set OrdPWMap::lessImage(const OrdPWMap& other) const { if (isEmpty() || other.isEmpty()) { - return SET_FACT.createSet(); + return Set{}; } if (_pieces == other._pieces) { - return SET_FACT.createSet(); + return Set{}; } return traverse(other, LessImageCore{}).result(); diff --git a/sbg/pw_map.cpp b/sbg/pw_map.cpp index b541cb68..51efd902 100644 --- a/sbg/pw_map.cpp +++ b/sbg/pw_map.cpp @@ -18,7 +18,7 @@ ******************************************************************************/ #include "sbg/pw_map.hpp" -#include "sbg/set_fact.hpp" +#include "sbg/pwmap_impl.hpp" #include "util/debug.hpp" #include "util/defs.hpp" @@ -61,45 +61,15 @@ bool PWMap::ConstIt::operator!=(const ConstIt& other) return _it != other._it; } -//////////////////////////////////////////////////////////////////////////////// -// 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; -} - //////////////////////////////////////////////////////////////////////////////// // PWMap ---------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// // Constructors ---------------------------------------------------------------- -PWMap::PWMap(const PWMapKind kind) : _impl() +PWMap::PWMap() : _impl() { + PWMapKind kind = PWMAP_IMPL.kind(); switch (kind) { case PWMapKind::kUnordered: { _impl = detail::UnordPWMap{}; @@ -123,8 +93,9 @@ PWMap::PWMap(const PWMapKind kind) : _impl() } } -PWMap::PWMap(const PWMapKind kind, Set s) : _impl() +PWMap::PWMap(Set s) : _impl() { + PWMapKind kind = PWMAP_IMPL.kind(); switch (kind) { case PWMapKind::kUnordered: { _impl = detail::UnordPWMap{s}; @@ -148,8 +119,9 @@ PWMap::PWMap(const PWMapKind kind, Set s) : _impl() } } -PWMap::PWMap(const PWMapKind kind, Map m) : _impl() -{ +PWMap::PWMap(Map m) : _impl() +{ + PWMapKind kind = PWMAP_IMPL.kind(); switch (kind) { case PWMapKind::kUnordered: { _impl = detail::UnordPWMap{m}; @@ -226,7 +198,7 @@ PWMap PWMap::operator+(const PWMap& other) const return PWMap{a + b}; } else { Util::ERROR("PWMap::operator+: mismatched implementations\n"); - return PWMap{PWMapKind::kUnordered}; + return PWMap{}; } } , _impl, other._impl); @@ -309,7 +281,7 @@ PWMap PWMap::composition(const PWMap& other) const return PWMap{a.composition(b)}; } else { Util::ERROR("PWMap::composition: mismatched implementations\n"); - return PWMap{PWMapKind::kUnordered}; + return PWMap{}; } } , _impl, other._impl); @@ -353,7 +325,7 @@ PWMap PWMap::concatenation(PWMap&& other) && return PWMap{std::move(a).concatenation(std::move(b))}; } else { Util::ERROR("PWMap::concatenation: mismatched implementations\n"); - return PWMap{PWMapKind::kUnordered}; + return PWMap{}; } } , std::move(_impl), std::move(other._impl)); @@ -384,7 +356,7 @@ PWMap PWMap::combine(PWMap&& other) && return PWMap{std::move(a).combine(std::move(b))}; } else { Util::ERROR("PWMap::combine: mismatched implementations\n"); - return PWMap{PWMapKind::kUnordered}; + return PWMap{}; } } , std::move(_impl), std::move(other._impl)); @@ -400,7 +372,7 @@ PWMap PWMap::min(const PWMap& other) const return PWMap{a.min(b)}; } else { Util::ERROR("PWMap::min: mismatched implementations\n"); - return PWMap{PWMapKind::kUnordered}; + return PWMap{}; } } , _impl, other._impl); @@ -416,7 +388,7 @@ PWMap PWMap::minAdj(const PWMap& other) const return PWMap{a.minAdj(b)}; } else { Util::ERROR("PWMap::minAdj: mismatched implementations\n"); - return PWMap{PWMapKind::kUnordered}; + return PWMap{}; } } , _impl, other._impl); @@ -437,7 +409,7 @@ Set PWMap::equalImage(const PWMap& other) const return a.equalImage(b); } else { Util::ERROR("PWMap::equalImage: mismatched implementations\n"); - return SET_FACT.createSet(); + return Set{}; } } , _impl, other._impl); @@ -453,7 +425,7 @@ Set PWMap::lessImage(const PWMap& other) const return a.lessImage(b); } else { Util::ERROR("PWMap::lessImage: mismatched implementations\n"); - return SET_FACT.createSet(); + return Set{}; } } , _impl, other._impl); diff --git a/sbg/pw_map.hpp b/sbg/pw_map.hpp index ab9f5a9f..6e929da9 100644 --- a/sbg/pw_map.hpp +++ b/sbg/pw_map.hpp @@ -58,10 +58,6 @@ class PWMapAccessKey; } // namespace detail -enum class PWMapKind { kUnordered, kOrdered, kDomOrdered }; - -std::ostream& operator<<(std::ostream& out, PWMapKind kind); - //////////////////////////////////////////////////////////////////////////////// // PWMap ----------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// @@ -79,7 +75,8 @@ class PWMap { ConstIt(detail::UnordPWMap::ConstIt it); ConstIt(detail::OrdPWMap::ConstIt it); - std::variant _it; + std::variant _it; friend class PWMap; }; @@ -87,9 +84,9 @@ class PWMap { /** * @brief Constructs an empty domain pw. */ - PWMap(const PWMapKind kind); - PWMap(const PWMapKind kind, Set s); - PWMap(const PWMapKind kind, Map m); + PWMap(); + PWMap(Set s); + PWMap(Map m); ConstIt begin(); ConstIt end(); diff --git a/sbg/pwmap_fact.cpp b/sbg/pwmap_fact.cpp deleted file mode 100644 index 2b3fc85b..00000000 --- a/sbg/pwmap_fact.cpp +++ /dev/null @@ -1,150 +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/pwmap_fact.hpp" -#include "util/debug.hpp" - -namespace SBG { - -namespace LIB { - -//////////////////////////////////////////////////////////////////////////////// -// UnordPWMap Factory ---------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -UnordPWMapFact::UnordPWMapFact() {} - -PWMap UnordPWMapFact::createPWMap() const -{ - return PWMap{PWMapKind::kUnordered}; -} - -PWMap UnordPWMapFact::createPWMap(const Set& s) const -{ - return PWMap{PWMapKind::kUnordered, s}; -} - -PWMap UnordPWMapFact::createPWMap(const Map& m) const -{ - return PWMap{PWMapKind::kUnordered, m}; -} - -//////////////////////////////////////////////////////////////////////////////// -// OrdPWMap Factory ------------------------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -OrdPWMapFact::OrdPWMapFact() {} - -PWMap OrdPWMapFact::createPWMap() const -{ - return PWMap{PWMapKind::kOrdered}; -} - -PWMap OrdPWMapFact::createPWMap(const Set& s) const -{ - return PWMap{PWMapKind::kOrdered, s}; -} - -PWMap OrdPWMapFact::createPWMap(const Map& m) const -{ - return PWMap{PWMapKind::kOrdered, m}; -} - -//////////////////////////////////////////////////////////////////////////////// -// DomOrdPWMap Factory --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -DomOrdPWMapFact::DomOrdPWMapFact() {} - -PWMap DomOrdPWMapFact::createPWMap() const -{ - return PWMap{PWMapKind::kDomOrdered}; -} - -PWMap DomOrdPWMapFact::createPWMap(const Set &s) const -{ - return PWMap{PWMapKind::kDomOrdered, s}; -} - -PWMap DomOrdPWMapFact::createPWMap(const Map &m) const -{ - return PWMap{PWMapKind::kDomOrdered, m}; -} - -//////////////////////////////////////////////////////////////////////////////// -// Factory for clients --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -PWMapFactory::PWMapFactory() : _kind(PWMapKind::kUnordered) - , _impl(UnordPWMapFact{}) {} - -PWMapFactory& PWMapFactory::instance() -{ - static PWMapFactory _instance; - return _instance; -} - -const PWMapKind& PWMapFactory::kind() const { return _kind; } - -void PWMapFactory::set_pwmap_fact(PWMapKind kind) -{ - _kind = kind; - switch (kind) { - case PWMapKind::kUnordered: { - _impl = UnordPWMapFact{}; - break; - } - - case PWMapKind::kOrdered: { - _impl = OrdPWMapFact{}; - break; - } - - case PWMapKind::kDomOrdered: { - _impl = DomOrdPWMapFact{}; - break; - } - - default: { - Util::ERROR("Unsupported ", kind, " PWMap implementation\n"); - break; - } - } -} - -PWMap PWMapFactory::createPWMap() const -{ - return std::visit([](const auto& a) { return a.createPWMap(); }, _impl); -} - -PWMap PWMapFactory::createPWMap(Set s) const -{ - return std::visit([&s](const auto& a) { return a.createPWMap(std::move(s)); } - , _impl); -} - -PWMap PWMapFactory::createPWMap(Map m) const -{ - return std::visit([&m](const auto& a) { return a.createPWMap(std::move(m)); } - , _impl); -} - -} // namespace LIB - -} // namespace SBG diff --git a/sbg/pwmap_fact.hpp b/sbg/pwmap_fact.hpp deleted file mode 100644 index 021c36d2..00000000 --- a/sbg/pwmap_fact.hpp +++ /dev/null @@ -1,95 +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 SBGRAPH_SBG_PWMAP_FACT_HPP_ -#define SBGRAPH_SBG_PWMAP_FACT_HPP_ - -#include "sbg/map.hpp" -#include "sbg/pw_map.hpp" -#include "sbg/set.hpp" - -namespace SBG { - -namespace LIB { - -#define PWMAP_FACT PWMapFactory::instance() - -class UnordPWMapFact { -public: - UnordPWMapFact(); - - PWMap createPWMap() const; - PWMap createPWMap(const Set& s) const; - PWMap createPWMap(const Map& m) const; -}; - -class OrdPWMapFact { -public: - OrdPWMapFact(); - - PWMap createPWMap() const; - PWMap createPWMap(const Set& s) const; - PWMap createPWMap(const Map& m) const; -}; - -class DomOrdPWMapFact { -public: - DomOrdPWMapFact(); - - PWMap createPWMap() const; - PWMap createPWMap(const Set& s) const; - PWMap createPWMap(const Map& m) const; -}; - -/** - * @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 PWMapFactory { -public: - ~PWMapFactory() = default; - - static PWMapFactory& instance(); - const PWMapKind& kind() const; - - void set_pwmap_fact(PWMapKind kind); - - PWMap createPWMap() const; - PWMap createPWMap(Set s) const; - PWMap createPWMap(Map m) const; - -private: - using FactImpl = std::variant; - - PWMapFactory(); - - PWMapKind _kind; - FactImpl _impl; -}; - -} // namespace LIB - -} // namespace SBG - -#endif // SBGRAPH_SBG_PWMAP_FACT_HPP_ 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/sbg.cpp b/sbg/sbg.cpp index 016cebcc..53950b83 100644 --- a/sbg/sbg.cpp +++ b/sbg/sbg.cpp @@ -18,9 +18,7 @@ ******************************************************************************/ #include "sbg/natural.hpp" -#include "sbg/pwmap_fact.hpp" #include "sbg/sbg.hpp" -#include "sbg/set_fact.hpp" #include "util/debug.hpp" #include @@ -36,9 +34,7 @@ namespace LIB { // Constructors/Destructors ---------------------------------------------------- SBG::SBG() - : _V(SET_FACT.createSet()), _Vmap(PWMAP_FACT.createPWMap()) - , _E(SET_FACT.createSet()), _map1(PWMAP_FACT.createPWMap()) - , _map2(PWMAP_FACT.createPWMap()), _Emap(PWMAP_FACT.createPWMap()) {} + : _V(), _Vmap(), _E(), _map1(), _map2(), _Emap() {} SBG::SBG(const Set& V, const PWMap& Vmap , const PWMap& map1, const PWMap& map2 diff --git a/sbg/sbg.hpp b/sbg/sbg.hpp index 3c394032..5a149ae1 100644 --- a/sbg/sbg.hpp +++ b/sbg/sbg.hpp @@ -41,7 +41,6 @@ #include "sbg/pw_map.hpp" #include "sbg/set.hpp" -#include "sbg/set_fact.hpp" #include @@ -119,7 +118,7 @@ inline void SBG::foreachSetVertex(FuncT&& f) const while (!remaining.isEmpty()) { const MD_NAT& x = remaining.minElem(); f(x); - remaining = remaining.difference(SET_FACT.createSet(x)); + remaining = remaining.difference(Set{x}); } } @@ -130,7 +129,7 @@ inline void SBG::foreachSetEdge(FuncT&& f) const while (!remaining.isEmpty()) { const MD_NAT& x = remaining.minElem(); f(x); - remaining = remaining.difference(SET_FACT.createSet(x)); + remaining = remaining.difference(Set{x}); } } diff --git a/sbg/unord_pwmap.cpp b/sbg/unord_pwmap.cpp index ef560326..e9301fcc 100644 --- a/sbg/unord_pwmap.cpp +++ b/sbg/unord_pwmap.cpp @@ -17,7 +17,6 @@ ******************************************************************************/ -#include "sbg/set_fact.hpp" #include "sbg/unord_pwmap.hpp" #include @@ -186,7 +185,7 @@ bool UnordPWMap::isEmpty() const { return _pieces.empty(); } Set UnordPWMap::domain() const & { - Set result = SET_FACT.createSet(); + Set result; for (const Map& m : _pieces) { result = std::move(result).disjointCup(m.domain()); @@ -197,7 +196,7 @@ Set UnordPWMap::domain() const & Set UnordPWMap::domain() && { - Set result = SET_FACT.createSet(); + Set result; for (Map& m : _pieces) { result = std::move(result).disjointCup(std::move(m).domain()); @@ -219,7 +218,7 @@ UnordPWMap UnordPWMap::restrict(const Set& subdom) const Set UnordPWMap::image() const { - Set result = SET_FACT.createSet(); + Set result; for (const Map& m : _pieces) { result = std::move(result).cup(m.image()); @@ -235,7 +234,7 @@ Set UnordPWMap::image(const Set& subdom) const Set UnordPWMap::preImage(const Set& subcodom) const { - Set result = SET_FACT.createSet(); + Set result; for (const Map& m : _pieces) { result = std::move(result).disjointCup(m.preImage(subcodom)); @@ -293,7 +292,7 @@ UnordPWMap UnordPWMap::mapInf() const { return mapInf(0); } Set UnordPWMap::fixedPoints() const { - Set result = SET_FACT.createSet(); + Set result; for (const Map& m : _pieces) { result = std::move(result).disjointCup(m.fixedPoints()); @@ -399,7 +398,7 @@ UnordPWMap UnordPWMap::minAdj(const UnordPWMap& other) const { UnordPWMap result; - Set visited = SET_FACT.createSet(); + Set visited; for (const Map& m1 : _pieces) { for (const Map& m2 : other._pieces) { Map min_adj = m1.minAdj(m2); @@ -427,8 +426,8 @@ UnordPWMap UnordPWMap::minAdj(const UnordPWMap& other) const Set UnordPWMap::sharedImage() const { - Set repeated_image = SET_FACT.createSet(); - Set visited = SET_FACT.createSet(); + Set repeated_image; + Set visited; for (const Map& m : _pieces) { Set image_in_visited = m.image().intersection(visited); if (!image_in_visited.isEmpty()) { @@ -443,7 +442,7 @@ Set UnordPWMap::sharedImage() const Set UnordPWMap::equalImage(const UnordPWMap& other) const { - Set result = SET_FACT.createSet(); + Set result; if (_pieces == other._pieces) { return domain(); @@ -468,10 +467,10 @@ Set UnordPWMap::equalImage(const UnordPWMap& other) const Set UnordPWMap::lessImage(const UnordPWMap& other) const { if (isEmpty() || other.isEmpty()) { - return SET_FACT.createSet(); + return Set{}; } - Set min_in_pw1 = SET_FACT.createSet(); + 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)); From f225e6c259b347f95274abf78997a1a21725e217 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Sat, 23 May 2026 20:28:16 -0300 Subject: [PATCH 57/66] [SBG Matching]: added MatchImplementation, deleted Matching::_kind --- algorithms/matching/CMakeLists.txt | 2 +- algorithms/matching/bfs_matching.cpp | 11 ++--- algorithms/matching/bfs_paths.cpp | 6 +-- algorithms/matching/matching.cpp | 25 ++--------- algorithms/matching/matching.hpp | 7 +-- .../{matching_fact.cpp => matching_impl.cpp} | 45 +++++++------------ .../{matching_fact.hpp => matching_impl.hpp} | 44 ++++++++---------- 7 files changed, 46 insertions(+), 94 deletions(-) rename algorithms/matching/{matching_fact.cpp => matching_impl.cpp} (56%) rename algorithms/matching/{matching_fact.hpp => matching_impl.hpp} (52%) diff --git a/algorithms/matching/CMakeLists.txt b/algorithms/matching/CMakeLists.txt index b8018075..64657b44 100644 --- a/algorithms/matching/CMakeLists.txt +++ b/algorithms/matching/CMakeLists.txt @@ -5,5 +5,5 @@ target_sources( bfs_paths.cpp matching.cpp match_data.cpp - matching_fact.cpp + matching_impl.cpp ) diff --git a/algorithms/matching/bfs_matching.cpp b/algorithms/matching/bfs_matching.cpp index a4201016..452f266f 100644 --- a/algorithms/matching/bfs_matching.cpp +++ b/algorithms/matching/bfs_matching.cpp @@ -19,8 +19,6 @@ #include "algorithms/matching/bfs_matching.hpp" #include "sbg/natural.hpp" -#include "sbg/pwmap_fact.hpp" -#include "sbg/set_fact.hpp" #include "util/logger.hpp" namespace SBG { @@ -47,9 +45,8 @@ bool BFSMatching::ExitCondition::isSatisfied() // Algorithm ------------------------------------------------------------------- -BFSMatching::BFSMatching() : _M(SET_FACT.createSet()), _dsbg() - , _direction(Direction::kForward), _X(SET_FACT.createSet()) - , _Y(SET_FACT.createSet()) {} +BFSMatching::BFSMatching() : _M(), _dsbg() , _direction(Direction::kForward) + , _X(), _Y() {} void BFSMatching::swapEdgesDirection(const Set& E) { @@ -73,14 +70,14 @@ void BFSMatching::swapDirection(const Set& E) PWMap BFSMatching::partitionSubsetEdges() const { - PWMap result = PWMAP_FACT.createPWMap(); + 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_FACT.createSet(SE)); + Set domain_edges = Emap.preImage(Set{SE}); Expression matched_expr{MD_NAT{arity, j}}; result.emplace(_M.intersection(domain_edges), matched_expr); diff --git a/algorithms/matching/bfs_paths.cpp b/algorithms/matching/bfs_paths.cpp index 3189fe86..81cdf46e 100644 --- a/algorithms/matching/bfs_paths.cpp +++ b/algorithms/matching/bfs_paths.cpp @@ -18,8 +18,6 @@ ******************************************************************************/ #include "algorithms/matching/bfs_paths.hpp" -#include "sbg/pwmap_fact.hpp" -#include "sbg/set_fact.hpp" #include "util/logger.hpp" namespace SBG { @@ -44,14 +42,14 @@ Set BFSPaths::calculate(const DirectedSBG& dsbg, const Set& endings) PWMap Emap = dsbg.Emap(); // Successor map to unmatched vertices - PWMap smap = PWMAP_FACT.createPWMap(endings); + PWMap smap{endings}; // A record of allowed edges to keep out cycle edges Set E = dsbg.E(); // Ingoing edges to vertices that reach endings Set ingoing = mapD.preImage(endings); // A record of visited set-edges - Set visitedSE = SET_FACT.createSet(); + Set visitedSE; do { // Calculate successor for ith vertices PWMap ingoingB = auxB.restrict(ingoing); diff --git a/algorithms/matching/matching.cpp b/algorithms/matching/matching.cpp index c34bdb09..9551b2e2 100644 --- a/algorithms/matching/matching.cpp +++ b/algorithms/matching/matching.cpp @@ -18,6 +18,7 @@ ******************************************************************************/ #include "algorithms/matching/matching.hpp" +#include "algorithms/matching/matching_impl.hpp" #include "util/debug.hpp" #include "util/time_profiler.hpp" @@ -25,33 +26,13 @@ namespace SBG { namespace LIB { -//////////////////////////////////////////////////////////////////////////////// -// Matching Algorithm implementations ------------------------------------------ -//////////////////////////////////////////////////////////////////////////////// - -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; -} - //////////////////////////////////////////////////////////////////////////////// // Matching Algorithm Interface ------------------------------------------------ //////////////////////////////////////////////////////////////////////////////// -Matching::Matching(MatchKind kind) : _kind(kind), _impl() +Matching::Matching() : _impl() { + MatchKind kind = MATCH_IMPL.kind(); switch (kind) { case MatchKind::kBFSPaths: { _impl = detail::BFSMatching{}; diff --git a/algorithms/matching/matching.hpp b/algorithms/matching/matching.hpp index 157b667f..bdcc91ff 100644 --- a/algorithms/matching/matching.hpp +++ b/algorithms/matching/matching.hpp @@ -44,22 +44,17 @@ using MatchImpl = std::variant; } // namespace detail -enum class MatchKind { kBFSPaths }; - -std::ostream& operator<<(std::ostream& out, const MatchKind kind); - //////////////////////////////////////////////////////////////////////////////// // Matching Algorithm ---------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// class Matching { public: - Matching(MatchKind kind); + Matching(); MatchData calculate(const BipartiteSBG& bsbg); private: - MatchKind _kind; detail::MatchImpl _impl; }; diff --git a/algorithms/matching/matching_fact.cpp b/algorithms/matching/matching_impl.cpp similarity index 56% rename from algorithms/matching/matching_fact.cpp rename to algorithms/matching/matching_impl.cpp index 0aea1be8..3af58e85 100755 --- a/algorithms/matching/matching_fact.cpp +++ b/algorithms/matching/matching_impl.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include "algorithms/matching/matching_fact.hpp" +#include "algorithms/matching/matching_impl.hpp" #include "util/debug.hpp" namespace SBG { @@ -25,51 +25,38 @@ namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// BFS Paths Matching Factory -------------------------------------------------- +// Matching implementations ---------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -Matching BFSMatchingFact::createMatchAlgorithm() const +std::ostream& operator<<(std::ostream& out, const MatchKind kind) { - return Matching(MatchKind::kBFSPaths); -} - -//////////////////////////////////////////////////////////////////////////////// -// Factory for clients --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -MatchFactory::MatchFactory() - : _kind(MatchKind::kBFSPaths), _impl(BFSMatchingFact{}) {} - -MatchFactory& MatchFactory::instance() -{ - static MatchFactory _instance; - return _instance; -} - -const MatchKind& MatchFactory::kind() const { return _kind; } - -void MatchFactory::set_match_fact(MatchKind kind) -{ - _kind = kind; switch (kind) { case MatchKind::kBFSPaths: { - _impl = BFSMatchingFact{}; + out << "BFS paths"; break; } default: { - Util::ERROR("Unsupported matching implementation"); + Util::ERROR("Unsupported matching algorithm implementation"); break; } } + + return out; } -Matching MatchFactory::createMatchAlgorithm() const +MatchImplementation::MatchImplementation() : _kind(MatchKind::kBFSPaths) {} + +MatchImplementation& MatchImplementation::instance() { - return std::visit([](const auto& a) { return a.createMatchAlgorithm(); } - , _impl); + 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_fact.hpp b/algorithms/matching/matching_impl.hpp similarity index 52% rename from algorithms/matching/matching_fact.hpp rename to algorithms/matching/matching_impl.hpp index 950b69a4..fb1c8a98 100755 --- a/algorithms/matching/matching_fact.hpp +++ b/algorithms/matching/matching_impl.hpp @@ -1,6 +1,6 @@ -/** @file matching_fact.hpp +/** @file matching_impl.hpp - @brief Matching Algorithm Factory + @brief Matching Algorithm Implementation
@@ -21,51 +21,45 @@ ******************************************************************************/ -#ifndef SBGRAPH_ALGORITHMS_MATCHING_MATCHING_FACT_HPP_ -#define SBGRAPH_ALGORITHMS_MATCHING_MATCHING_FACT_HPP_ +#ifndef SBGRAPH_ALGORITHMS_MATCHING_MATCHING_IMPL_HPP_ +#define SBGRAPH_ALGORITHMS_MATCHING_MATCHING_IMPL_HPP_ -#include "algorithms/matching/matching.hpp" +#include namespace SBG { namespace LIB { -#define MATCH_FACT MatchFactory::instance() +//////////////////////////////////////////////////////////////////////////////// +// Matching implementations ---------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// -class BFSMatchingFact { -public: - BFSMatchingFact() = default; +enum class MatchKind { kBFSPaths }; - Matching createMatchAlgorithm() const; -}; +std::ostream& operator<<(std::ostream& out, const MatchKind kind); + +#define MATCH_IMPL MatchImplementation::instance() /** - * @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). + * @brief Singleton that keeps record of the chosen matching implementation. */ -class MatchFactory { +class MatchImplementation { public: - ~MatchFactory() = default; + ~MatchImplementation() = default; - static MatchFactory& instance(); - const MatchKind& kind() const; + static MatchImplementation& instance(); + const MatchKind& kind() const; void set_match_fact(MatchKind kind); - Matching createMatchAlgorithm() const; - private: - using MatchFactImpl = std::variant; - - MatchFactory(); + MatchImplementation(); MatchKind _kind; - MatchFactImpl _impl; }; } // namespace LIB } // namespace SBG -#endif // SBGRAPH_ALGORITHMS_MATCHING_MATCHING_FACT_HPP_ +#endif // SBGRAPH_ALGORITHMS_MATCHING_MATCHING_IMPL_HPP_ From bd762ee8b9894977e8753ac6d1d97ea4a227b265 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Sat, 23 May 2026 20:29:26 -0300 Subject: [PATCH 58/66] [SBG SCC]: added SCCImplementation, deleted SCC::_kind --- algorithms/scc/CMakeLists.txt | 2 +- algorithms/scc/decreasing_edges_mrv.cpp | 17 ++-- algorithms/scc/minadj_mrv.cpp | 15 ++-- algorithms/scc/minreach_scc.cpp | 12 ++- algorithms/scc/scc.cpp | 30 +------ algorithms/scc/scc.hpp | 7 +- algorithms/scc/scc_fact.cpp | 90 ------------------- algorithms/scc/scc_impl.cpp | 67 ++++++++++++++ algorithms/scc/{scc_fact.hpp => scc_impl.hpp} | 51 ++++------- 9 files changed, 109 insertions(+), 182 deletions(-) delete mode 100755 algorithms/scc/scc_fact.cpp create mode 100755 algorithms/scc/scc_impl.cpp rename algorithms/scc/{scc_fact.hpp => scc_impl.hpp} (51%) diff --git a/algorithms/scc/CMakeLists.txt b/algorithms/scc/CMakeLists.txt index 84368bab..d673ae96 100644 --- a/algorithms/scc/CMakeLists.txt +++ b/algorithms/scc/CMakeLists.txt @@ -6,5 +6,5 @@ target_sources( minreach_scc.cpp scc.cpp scc_data.cpp - scc_fact.cpp + scc_impl.cpp ) diff --git a/algorithms/scc/decreasing_edges_mrv.cpp b/algorithms/scc/decreasing_edges_mrv.cpp index 313cdf9c..723c2c0b 100644 --- a/algorithms/scc/decreasing_edges_mrv.cpp +++ b/algorithms/scc/decreasing_edges_mrv.cpp @@ -18,8 +18,6 @@ ******************************************************************************/ #include "algorithms/scc/decreasing_edges_mrv.hpp" -#include "sbg/pwmap_fact.hpp" -#include "sbg/set_fact.hpp" #include "util/logger.hpp" #include @@ -32,8 +30,7 @@ namespace LIB { // Minimum Adjacent MRV Implementation ----------------------------------------- //////////////////////////////////////////////////////////////////////////////// -LtEdgesMRV::LtEdgesMRV() : _dsbg(), _smap(PWMAP_FACT.createPWMap()) - , _visitedSE(SET_FACT.createSet()), _n(0) {} +LtEdgesMRV::LtEdgesMRV() : _dsbg(), _smap(), _visitedSE(), _n(0) {} Set LtEdgesMRV::decreasingRepresentative(const PWMap& rmap) const { @@ -41,7 +38,7 @@ Set LtEdgesMRV::decreasingRepresentative(const PWMap& rmap) const PWMap mapD = _dsbg.mapD(); if (mapB.isEmpty() || mapD.isEmpty()) { - return SET_FACT.createSet(); + return Set{}; } PWMap rmapB = rmap.composition(mapB); @@ -54,7 +51,7 @@ Set LtEdgesMRV::decreasingRepresentative(const PWMap& rmap) const PWMap LtEdgesMRV::repetitivePaths(const PWMap& rmap , const PWMap& decreasing_smap) { - PWMap result = PWMAP_FACT.createPWMap(); + PWMap result; // Calculate edges in paths described by decreasing_smap const PWMap& mapB = _dsbg.mapB(); @@ -106,15 +103,15 @@ PWMap LtEdgesMRV::calculate(const DirectedSBG& dsbg) _dsbg = dsbg; PWMap mapB = _dsbg.mapB(); PWMap mapD = _dsbg.mapD(); - _visitedSE = SET_FACT.createSet(); + _visitedSE; - _smap = PWMAP_FACT.createPWMap(dsbg.V()); + _smap = PWMap{dsbg.V()}; PWMap rmap = _smap; if (!_dsbg.V().isEmpty() && !_dsbg.E().isEmpty()) { _n = 0; - PWMap old_rmap = PWMAP_FACT.createPWMap(); - Set E = SET_FACT.createSet(); + PWMap old_rmap; + Set E; do { old_rmap = rmap; diff --git a/algorithms/scc/minadj_mrv.cpp b/algorithms/scc/minadj_mrv.cpp index 6b385283..5a01773c 100644 --- a/algorithms/scc/minadj_mrv.cpp +++ b/algorithms/scc/minadj_mrv.cpp @@ -18,8 +18,6 @@ ******************************************************************************/ #include "algorithms/scc/minadj_mrv.hpp" -#include "sbg/pwmap_fact.hpp" -#include "sbg/set_fact.hpp" #include "util/logger.hpp" namespace SBG { @@ -41,13 +39,14 @@ PWMap MinAdjMRV::calculate(const DirectedSBG& dsbg) PWMap Emap = dsbg.Emap(); if (!V.isEmpty()) { std::size_t arity = V.arity(); - PWMap rmap = PWMAP_FACT.createPWMap(V), old_rmap = PWMAP_FACT.createPWMap(); + PWMap rmap{V}; + PWMap old_rmap; if (E.isEmpty()) { return rmap; } - Set Vc = SET_FACT.createSet(); + Set Vc; do { old_rmap = rmap; @@ -57,7 +56,7 @@ PWMap MinAdjMRV::calculate(const DirectedSBG& dsbg) rmap = rmap.min(new_rmap).combine(std::move(rmap)); Util::DEBUG_LOG << "rmap before rec: " << rmap << "\n\n"; - PWMap rec_rmap = PWMAP_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 @@ -68,7 +67,7 @@ PWMap MinAdjMRV::calculate(const DirectedSBG& dsbg) PWMap Vmap = dsbg.Vmap(); Set set_vertices = Vmap.image(); while (!set_vertices.isEmpty()) { - Set min_elem_set = SET_FACT.createSet(set_vertices.minElem()); + 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 @@ -87,7 +86,7 @@ PWMap MinAdjMRV::calculate(const DirectedSBG& dsbg) Set ER = ERB.intersection(ERD); if (!end.isEmpty() && !ER.isEmpty()) { // Distance map - PWMap dmap = PWMAP_FACT.createPWMap(); + PWMap dmap; Set ith = end; NAT dist = 0; // Calculate distance for vertices in same_rep that reach reps @@ -142,7 +141,7 @@ PWMap MinAdjMRV::calculate(const DirectedSBG& dsbg) return rmap; } - return PWMAP_FACT.createPWMap(); + return PWMap{}; } } // namespace LIB diff --git a/algorithms/scc/minreach_scc.cpp b/algorithms/scc/minreach_scc.cpp index 3e3695f3..8333c21e 100644 --- a/algorithms/scc/minreach_scc.cpp +++ b/algorithms/scc/minreach_scc.cpp @@ -20,8 +20,6 @@ #include "algorithms/scc/decreasing_edges_mrv.hpp" #include "algorithms/scc/minreach_scc.hpp" #include "algorithms/scc/minadj_mrv.hpp" -#include "sbg/pwmap_fact.hpp" -#include "sbg/set_fact.hpp" #include "util/logger.hpp" namespace SBG { @@ -34,7 +32,7 @@ namespace detail { // Minimum Reachable SCC Algorithm --------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -MinReachSCC::MinReachSCC() : _dsbg(), _E(SET_FACT.createSet()) {} +MinReachSCC::MinReachSCC() : _dsbg(), _E() {} void MinReachSCC::swapEdgesDirection(const Set& E) { @@ -62,17 +60,17 @@ SCCData MinReachSCC::calculate(const DirectedSBG& dsbg) init(dsbg); - PWMap rmap = PWMAP_FACT.createPWMap(); - Set Ediff = SET_FACT.createSet(); + PWMap rmap; + Set Ediff; Set oldE = dsbg.E(); - Set deleted_edges = SET_FACT.createSet(); + Set deleted_edges; do { oldE = _dsbg.E(); rmap = sccStep(); rmap.compact(); Ediff = oldE.difference(_dsbg.E()); deleted_edges = std::move(deleted_edges).disjointCup(Ediff); - } while (Ediff != SET_FACT.createSet()); + } while (Ediff != Set{}); Util::DEBUG_LOG << "MinReachSCC result: " << rmap << "\n\n"; diff --git a/algorithms/scc/scc.cpp b/algorithms/scc/scc.cpp index 3cec3a1e..080fe30b 100644 --- a/algorithms/scc/scc.cpp +++ b/algorithms/scc/scc.cpp @@ -19,6 +19,7 @@ #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" @@ -27,38 +28,13 @@ namespace SBG { namespace LIB { -//////////////////////////////////////////////////////////////////////////////// -// SCC Algorithm implementations ----------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -std::ostream& operator<<(std::ostream& out, const SCCKind kind) -{ - 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; -} - //////////////////////////////////////////////////////////////////////////////// // SCC Algorithm --------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -SCC::SCC(SCCKind kind) : _kind(kind), _impl() +SCC::SCC() : _impl() { + SCCKind kind = SCC_IMPL.kind(); switch (kind) { case SCCKind::kMinReachV1: { _impl = detail::MinReachSCCV1{}; diff --git a/algorithms/scc/scc.hpp b/algorithms/scc/scc.hpp index 6b6e69ea..5da187d3 100644 --- a/algorithms/scc/scc.hpp +++ b/algorithms/scc/scc.hpp @@ -46,22 +46,17 @@ using SCCImpl = std::variant; } // namespace detail -enum class SCCKind { kMinReachV1, kMinReachV2 }; - -std::ostream& operator<<(std::ostream& out, const SCCKind kind); - //////////////////////////////////////////////////////////////////////////////// // SCC Algorithm --------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// class SCC { public: - SCC(SCCKind kind); + SCC(); SCCData calculate(const DirectedSBG& dsbg); private: - SCCKind _kind; detail::SCCImpl _impl; }; diff --git a/algorithms/scc/scc_fact.cpp b/algorithms/scc/scc_fact.cpp deleted file mode 100755 index 9ad0d497..00000000 --- a/algorithms/scc/scc_fact.cpp +++ /dev/null @@ -1,90 +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" -#include "util/debug.hpp" - -namespace SBG { - -namespace LIB { - -//////////////////////////////////////////////////////////////////////////////// -// Minimum Reachable SCC V1 Factory -------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -SCC MinReachSCCV1Fact::createSCCAlgorithm() const -{ - return SCC{SCCKind::kMinReachV1}; -} - -//////////////////////////////////////////////////////////////////////////////// -// Minimum Reachable SCC V2 Factory -------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -SCC MinReachSCCV2Fact::createSCCAlgorithm() const -{ - return SCC{SCCKind::kMinReachV2}; -} - -//////////////////////////////////////////////////////////////////////////////// -// Factory for clients --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -SCCFactory::SCCFactory() - : _kind(SCCKind::kMinReachV2), _impl(MinReachSCCV2Fact{}) {} - -SCCFactory& SCCFactory::instance() -{ - static SCCFactory _instance; - return _instance; -} - -const SCCKind& SCCFactory::kind() const { return _kind; } - -void SCCFactory::set_scc_fact(SCCKind kind) -{ - _kind = kind; - switch (kind) { - case SCCKind::kMinReachV1: { - _impl = MinReachSCCV1Fact{}; - break; - } - - case SCCKind::kMinReachV2: { - _impl = MinReachSCCV2Fact{}; - break; - } - - default: { - Util::ERROR("Unsupported SCC algorithm implementation"); - break; - } - } -} - -SCC SCCFactory::createSCCAlgorithm() const -{ - return std::visit([](const auto& a) { return a.createSCCAlgorithm(); } - , _impl); -} - -} // namespace LIB - -} // namespace SBG diff --git a/algorithms/scc/scc_impl.cpp b/algorithms/scc/scc_impl.cpp new file mode 100755 index 00000000..2a6963fe --- /dev/null +++ b/algorithms/scc/scc_impl.cpp @@ -0,0 +1,67 @@ +/******************************************************************************* + + 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_impl.hpp" +#include "util/debug.hpp" + +namespace SBG { + +namespace LIB { + +//////////////////////////////////////////////////////////////////////////////// +// SCC implementations --------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +std::ostream& operator<<(std::ostream& out, const SCCKind kind) +{ + 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; +} + +SCCImplementation::SCCImplementation() : _kind(SCCKind::kMinReachV2) {} + +SCCImplementation& SCCImplementation::instance() +{ + static SCCImplementation _instance; + return _instance; +} + +const SCCKind& SCCImplementation::kind() const { return _kind; } + +void SCCImplementation::set_scc_fact(SCCKind kind) { _kind = kind; } + +} // namespace LIB + +} // namespace SBG diff --git a/algorithms/scc/scc_fact.hpp b/algorithms/scc/scc_impl.hpp similarity index 51% rename from algorithms/scc/scc_fact.hpp rename to algorithms/scc/scc_impl.hpp index 49ffdee3..fb1f0ee7 100755 --- a/algorithms/scc/scc_fact.hpp +++ b/algorithms/scc/scc_impl.hpp @@ -1,6 +1,6 @@ -/** @file scc_fact.hpp +/** @file scc_impl.hpp - @brief SCC Algorithm Factory + @brief SCC Algorithm Implementation
@@ -21,60 +21,45 @@ ******************************************************************************/ -#ifndef SBGRAPH_ALGORITHMS_SCC_SCC_FACT_HPP_ -#define SBGRAPH_ALGORITHMS_SBG_SCC_FACT_HPP_ +#ifndef SBGRAPH_ALGORITHMS_SCC_SCC_IMPL_HPP_ +#define SBGRAPH_ALGORITHMS_SCC_SCC_IMPL_HPP_ -#include "algorithms/scc/scc.hpp" - -#include +#include namespace SBG { namespace LIB { -#define SCC_FACT SCCFactory::instance() +//////////////////////////////////////////////////////////////////////////////// +// SCC implementations --------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// -class MinReachSCCV1Fact { -public: - MinReachSCCV1Fact() = default; +enum class SCCKind { kMinReachV1, kMinReachV2 }; - SCC createSCCAlgorithm() const; -}; - -class MinReachSCCV2Fact { -public: - MinReachSCCV2Fact() = default; +std::ostream& operator<<(std::ostream& out, const SCCKind kind); - SCC createSCCAlgorithm() const; -}; +#define SCC_IMPL SCCImplementation::instance() /** - * @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). + * @brief Singleton that keeps record of the chosen SCC implementation. */ -class SCCFactory { +class SCCImplementation { public: - ~SCCFactory() = default; + ~SCCImplementation() = default; - static SCCFactory& instance(); - const SCCKind& kind() const; + static SCCImplementation& instance(); + const SCCKind& kind() const; void set_scc_fact(SCCKind kind); - SCC createSCCAlgorithm() const; - private: - using SCCFactImpl = std::variant; - - SCCFactory(); + SCCImplementation(); SCCKind _kind; - SCCFactImpl _impl; }; } // namespace LIB } // namespace SBG -#endif // SBGRAPH_ALGORITHMS_SCC_SCC_FACT_HPP_ +#endif // SBGRAPH_ALGORITHMS_SCC_SCC_IMPL_HPP_ From 49ad9388ab387bd89852b492ab63e09961667849 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Sat, 23 May 2026 20:30:38 -0300 Subject: [PATCH 59/66] [SBG MFVS]: added MFVSImplementation, deleted MinFeedbackVertexSet::_kind --- algorithms/mfvs/CMakeLists.txt | 2 +- algorithms/mfvs/greedy_mfvs.cpp | 16 ++-- algorithms/mfvs/mfvs_fact.cpp | 90 --------------------- algorithms/mfvs/mfvs_fact.hpp | 78 ------------------ algorithms/mfvs/mfvs_impl.cpp | 67 +++++++++++++++ algorithms/mfvs/mfvs_impl.hpp | 65 +++++++++++++++ algorithms/mfvs/min_feedback_vertex_set.cpp | 30 +------ algorithms/mfvs/min_feedback_vertex_set.hpp | 7 +- algorithms/mfvs/smallest_sv_mfvs.cpp | 16 ++-- 9 files changed, 151 insertions(+), 220 deletions(-) delete mode 100755 algorithms/mfvs/mfvs_fact.cpp delete mode 100755 algorithms/mfvs/mfvs_fact.hpp create mode 100755 algorithms/mfvs/mfvs_impl.cpp create mode 100755 algorithms/mfvs/mfvs_impl.hpp diff --git a/algorithms/mfvs/CMakeLists.txt b/algorithms/mfvs/CMakeLists.txt index 2c4f4ed6..1fd3cbb1 100644 --- a/algorithms/mfvs/CMakeLists.txt +++ b/algorithms/mfvs/CMakeLists.txt @@ -3,6 +3,6 @@ target_sources( PRIVATE greedy_mfvs.cpp min_feedback_vertex_set.cpp - mfvs_fact.cpp + mfvs_impl.cpp smallest_sv_mfvs.cpp ) diff --git a/algorithms/mfvs/greedy_mfvs.cpp b/algorithms/mfvs/greedy_mfvs.cpp index f75dfb5b..cd0d2ca4 100644 --- a/algorithms/mfvs/greedy_mfvs.cpp +++ b/algorithms/mfvs/greedy_mfvs.cpp @@ -19,10 +19,8 @@ #include "algorithms/mfvs/greedy_mfvs.hpp" #include "algorithms/scc/scc.hpp" -#include "algorithms/scc/scc_fact.hpp" #include "sbg/natural.hpp" #include "sbg/pw_map.hpp" -#include "sbg/set_fact.hpp" #include "util/logger.hpp" #include @@ -58,10 +56,10 @@ MD_NAT maxDegreeVertex(const DirectedSBG& dsbg) max_mult = jth_mult; } - remaining = remaining.difference(SET_FACT.createSet(jth_mult)); + remaining = remaining.difference(Set{jth_mult}); } - Set max_mult_set = SET_FACT.createSet(max_mult); + Set max_mult_set{max_mult}; Set max_degree_vertices = mmap.preImage(max_mult_set); return max_degree_vertices.minElem(); @@ -73,13 +71,13 @@ Set GreedyMFVS::calculate(const DirectedSBG& input_dsbg) const Util::DEBUG_LOG << "initial mfvs dsbg:\n" << dsbg << "\n"; - PWMap rmap = SCC_FACT.createSCCAlgorithm().calculate(dsbg).rmap(); - Set fvs_result = SET_FACT.createSet(); - Set visitedSV = SET_FACT.createSet(); + 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 = SET_FACT.createSet(max_degree_vertex); + Set Vj{max_degree_vertex}; fvs_result = std::move(fvs_result).disjointCup(Vj); // Handle repetition @@ -98,7 +96,7 @@ Set GreedyMFVS::calculate(const DirectedSBG& input_dsbg) const dsbg.eraseVertices(fvs_result); // Resulting SCC from induced graph - rmap = SCC_FACT.createSCCAlgorithm().calculate(dsbg).rmap(); + rmap = SCC{}.calculate(dsbg).rmap(); Util::DEBUG_LOG << "Vj: " << Vj << "\n"; Util::DEBUG_LOG << "new rmap: " << rmap << "\n\n"; diff --git a/algorithms/mfvs/mfvs_fact.cpp b/algorithms/mfvs/mfvs_fact.cpp deleted file mode 100755 index 7ff2d8ee..00000000 --- a/algorithms/mfvs/mfvs_fact.cpp +++ /dev/null @@ -1,90 +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/mfvs/mfvs_fact.hpp" -#include "util/debug.hpp" - -namespace SBG { - -namespace LIB { - -//////////////////////////////////////////////////////////////////////////////// -// Maximum Degree MFVS Factory ------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -MinFeedbackVertexSet GreedyMFVSFact::createMFVSAlgorithm() const -{ - return MinFeedbackVertexSet{MFVSKind::kGreedy}; -} - -//////////////////////////////////////////////////////////////////////////////// -// Smallest set-vertex MFVS Factory -------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -MinFeedbackVertexSet SmallSVMFVSFact::createMFVSAlgorithm() const -{ - return MinFeedbackVertexSet{MFVSKind::kSmallSV}; -} - -//////////////////////////////////////////////////////////////////////////////// -// Factory for clients --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -MFVSFactory::MFVSFactory() - : _kind(MFVSKind::kSmallSV), _impl(SmallSVMFVSFact{}) {} - -MFVSFactory& MFVSFactory::instance() -{ - static MFVSFactory _instance; - return _instance; -} - -const MFVSKind& MFVSFactory::kind() const { return _kind; } - -void MFVSFactory::set_mfvs_fact(MFVSKind kind) -{ - _kind = kind; - switch (kind) { - case MFVSKind::kGreedy: { - _impl = GreedyMFVSFact{}; - break; - } - - case MFVSKind::kSmallSV: { - _impl = SmallSVMFVSFact{}; - break; - } - - default: { - Util::ERROR("MFVSFactory::set_mfvs_fact: unsupported MFVS ", kind - , " implementation"); - break; - } - } -} - -MinFeedbackVertexSet MFVSFactory::createMFVSAlgorithm() const -{ - return std::visit([](const auto& a) { return a.createMFVSAlgorithm(); } - , _impl); -} - -} // namespace LIB - -} // namespace SBG diff --git a/algorithms/mfvs/mfvs_fact.hpp b/algorithms/mfvs/mfvs_fact.hpp deleted file mode 100755 index 516a5cde..00000000 --- a/algorithms/mfvs/mfvs_fact.hpp +++ /dev/null @@ -1,78 +0,0 @@ -/** @file mfvs_fact.hpp - - @brief Minimum Feedback Vertex 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 SBGRAPH_ALGORITHMS_MFVS_MFVS_FACT_HPP_ -#define SBGRAPH_ALGORITHMS_MFVS_MFVS_FACT_HPP_ - -#include "min_feedback_vertex_set.hpp" - -namespace SBG { - -namespace LIB { - -#define MFVS_FACT MFVSFactory::instance() - -class GreedyMFVSFact { -public: - GreedyMFVSFact() = default; - - MinFeedbackVertexSet createMFVSAlgorithm() const; -}; - -class SmallSVMFVSFact { -public: - SmallSVMFVSFact() = default; - - MinFeedbackVertexSet createMFVSAlgorithm() const; -}; - -/** - * @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 MFVS_FACT.createMFVSAlgorithm(args). - */ -class MFVSFactory { -public: - ~MFVSFactory() = default; - - static MFVSFactory& instance(); - const MFVSKind& kind() const; - - void set_mfvs_fact(MFVSKind kind); - - MinFeedbackVertexSet createMFVSAlgorithm() const; - -private: - using MFVSFactImpl = std::variant; - - MFVSFactory(); - - MFVSKind _kind; - MFVSFactImpl _impl; -}; - -} // namespace LIB - -} // namespace SBG - -#endif // SBGRAPH_ALGORITHMS_MFVS_MFVS_FACT_HPP_ diff --git a/algorithms/mfvs/mfvs_impl.cpp b/algorithms/mfvs/mfvs_impl.cpp new file mode 100755 index 00000000..69f4665a --- /dev/null +++ b/algorithms/mfvs/mfvs_impl.cpp @@ -0,0 +1,67 @@ +/******************************************************************************* + + 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/mfvs_impl.hpp" +#include "util/debug.hpp" + +namespace SBG { + +namespace LIB { + +//////////////////////////////////////////////////////////////////////////////// +// MFVS implementations -------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// + +std::ostream& operator<<(std::ostream& out, const MFVSKind kind) +{ + 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; +} + +MFVSImplementation::MFVSImplementation() : _kind(MFVSKind::kSmallSV) {} + +MFVSImplementation& MFVSImplementation::instance() +{ + static MFVSImplementation _instance; + return _instance; +} + +const MFVSKind& MFVSImplementation::kind() const { return _kind; } + +void MFVSImplementation::set_mfvs_fact(MFVSKind kind) { _kind = kind; } + +} // namespace LIB + +} // namespace SBG 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/mfvs/min_feedback_vertex_set.cpp b/algorithms/mfvs/min_feedback_vertex_set.cpp index 1d2cda4d..015a2541 100644 --- a/algorithms/mfvs/min_feedback_vertex_set.cpp +++ b/algorithms/mfvs/min_feedback_vertex_set.cpp @@ -18,6 +18,7 @@ ******************************************************************************/ #include "algorithms/mfvs/min_feedback_vertex_set.hpp" +#include "algorithms/mfvs/mfvs_impl.hpp" #include "util/debug.hpp" #include "util/time_profiler.hpp" @@ -25,38 +26,13 @@ namespace SBG { namespace LIB { -//////////////////////////////////////////////////////////////////////////////// -// MFVS Algorithm implementations ---------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -std::ostream& operator<<(std::ostream& out, const MFVSKind kind) -{ - 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; -} - //////////////////////////////////////////////////////////////////////////////// // MFVS Algorithm Interface ---------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -MinFeedbackVertexSet::MinFeedbackVertexSet(MFVSKind kind) : _kind(kind), _impl() +MinFeedbackVertexSet::MinFeedbackVertexSet() : _impl() { + MFVSKind kind = MFVS_IMPL.kind(); switch (kind) { case MFVSKind::kGreedy: { _impl = detail::GreedyMFVS{}; diff --git a/algorithms/mfvs/min_feedback_vertex_set.hpp b/algorithms/mfvs/min_feedback_vertex_set.hpp index 71f978b3..0b197efe 100644 --- a/algorithms/mfvs/min_feedback_vertex_set.hpp +++ b/algorithms/mfvs/min_feedback_vertex_set.hpp @@ -45,22 +45,17 @@ using MFVSImpl = std::variant; } -enum class MFVSKind { kGreedy, kSmallSV }; - -std::ostream& operator<<(std::ostream& out, const MFVSKind kind); - /////////////////////////////////////////////////////////////////////////////// // Minimum Feedback Vertex Set Algorithm -------------------------------------- /////////////////////////////////////////////////////////////////////////////// class MinFeedbackVertexSet { public: - MinFeedbackVertexSet(MFVSKind kind); + MinFeedbackVertexSet(); Set calculate(const DirectedSBG& dsbg); private: - MFVSKind _kind; detail::MFVSImpl _impl; }; diff --git a/algorithms/mfvs/smallest_sv_mfvs.cpp b/algorithms/mfvs/smallest_sv_mfvs.cpp index 2399c3a1..44a1ffa5 100644 --- a/algorithms/mfvs/smallest_sv_mfvs.cpp +++ b/algorithms/mfvs/smallest_sv_mfvs.cpp @@ -19,10 +19,8 @@ #include "algorithms/mfvs/smallest_sv_mfvs.hpp" #include "algorithms/scc/scc.hpp" -#include "algorithms/scc/scc_fact.hpp" #include "sbg/natural.hpp" #include "sbg/pw_map.hpp" -#include "sbg/set_fact.hpp" #include "util/logger.hpp" #include @@ -58,10 +56,10 @@ MD_NAT getVertexFromSmallestSV(const DirectedSBG& dsbg) min_mult = jth_mult; } - remaining = remaining.difference(SET_FACT.createSet(jth_mult)); + remaining = remaining.difference(Set{jth_mult}); } - Set small_sv = mmap.preImage(SET_FACT.createSet(min_mult)); + Set small_sv = mmap.preImage(Set{min_mult}); Set vertex = Vmap.preImage(small_sv); return vertex.minElem(); @@ -73,13 +71,13 @@ Set SmallestSVMFVS::calculate(const DirectedSBG& input_dsbg) const Util::DEBUG_LOG << "initial smallest set-vertex mfvs dsbg:\n" << dsbg << "\n"; - PWMap rmap = SCC_FACT.createSCCAlgorithm().calculate(dsbg).rmap(); - Set fvs_result = SET_FACT.createSet(); - Set visitedSV = SET_FACT.createSet(); + 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 = SET_FACT.createSet(smallest_sv_vertex); + Set Vj{smallest_sv_vertex}; fvs_result = std::move(fvs_result).disjointCup(Vj); // Handle repetition @@ -98,7 +96,7 @@ Set SmallestSVMFVS::calculate(const DirectedSBG& input_dsbg) const dsbg.eraseVertices(fvs_result); // Resulting SCC from induced graph - rmap = SCC_FACT.createSCCAlgorithm().calculate(dsbg).rmap(); + rmap = SCC{}.calculate(dsbg).rmap(); Util::DEBUG_LOG << "Vj: " << Vj << "\n"; Util::DEBUG_LOG << "new rmap: " << rmap << "\n\n"; From 1e5add52431defa46491b4dac29fba0e4b5050a4 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Sat, 23 May 2026 20:31:33 -0300 Subject: [PATCH 60/66] [SBG TS]: added TSCImplementation, deleted TopologicalSorting::_kind --- algorithms/sorting/topological/CMakeLists.txt | 2 +- .../sorting/topological/min_vertex_ts.cpp | 36 ++++++---- .../sorting/topological/min_vertex_ts.hpp | 1 + .../topological/topological_sorting.cpp | 26 +------ .../topological/topological_sorting.hpp | 7 +- algorithms/sorting/topological/ts_fact.hpp | 72 ------------------- .../topological/{ts_fact.cpp => ts_impl.cpp} | 47 +++++------- algorithms/sorting/topological/ts_impl.hpp | 65 +++++++++++++++++ 8 files changed, 111 insertions(+), 145 deletions(-) delete mode 100755 algorithms/sorting/topological/ts_fact.hpp rename algorithms/sorting/topological/{ts_fact.cpp => ts_impl.cpp} (54%) create mode 100755 algorithms/sorting/topological/ts_impl.hpp diff --git a/algorithms/sorting/topological/CMakeLists.txt b/algorithms/sorting/topological/CMakeLists.txt index 10aef656..b55a9888 100644 --- a/algorithms/sorting/topological/CMakeLists.txt +++ b/algorithms/sorting/topological/CMakeLists.txt @@ -3,5 +3,5 @@ target_sources( PRIVATE min_vertex_ts.cpp topological_sorting.cpp - ts_fact.cpp + ts_impl.cpp ) diff --git a/algorithms/sorting/topological/min_vertex_ts.cpp b/algorithms/sorting/topological/min_vertex_ts.cpp index 31b97576..3eb60f54 100644 --- a/algorithms/sorting/topological/min_vertex_ts.cpp +++ b/algorithms/sorting/topological/min_vertex_ts.cpp @@ -19,8 +19,6 @@ #include "algorithms/sorting/topological/min_vertex_ts.hpp" #include "sbg/natural.hpp" -#include "sbg/pwmap_fact.hpp" -#include "sbg/set_fact.hpp" #include "util/debug.hpp" #include "util/logger.hpp" @@ -35,9 +33,8 @@ namespace detail { //////////////////////////////////////////////////////////////////////////////// MinVertexTS::MinVertexTS() - : _smap(PWMAP_FACT.createPWMap()), _dsbg(), _visitedSV(SET_FACT.createSet()) - , _priority(SET_FACT.createSet()), _same_SV(SET_FACT.createSet()) - , _independent(SET_FACT.createSet()) {} + : _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 @@ -66,21 +63,32 @@ void checkSorting(const PWMap& result, const DirectedSBG& dsbg) PWMap MinVertexTS::repetition(const Set& init_V , const DirectedSBG& dsbg) const { - PWMap result = PWMAP_FACT.createPWMap(); + 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()); - result.emplace(V_plus, (*jth_smap.begin()).law()); + final_expr = (*jth_smap.begin()).law(); + result.emplace(V_plus, final_expr); Vj = _smap.image(Vj); repetition = !Vmap.image(Vj).intersection(init_SV).isEmpty(); - } while (!repetition); - - checkSorting(result, dsbg); + ++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; + } return result; } @@ -114,7 +122,7 @@ PWMap MinVertexTS::calculate(const DirectedSBG& dsbg _dsbg = dsbg; - _smap = PWMAP_FACT.createPWMap(); + _smap = PWMap{}; if (dsbg.V().isEmpty()) { return _smap; @@ -122,14 +130,14 @@ PWMap MinVertexTS::calculate(const DirectedSBG& dsbg _priority = _dsbg.V(); _same_SV = _dsbg.V(); - Set visited_SV = SET_FACT.createSet(); + 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 = SET_FACT.createSet(vj); + Set vj_set{vj}; successor_expr = Expression{vj, old_vj}; _smap.emplace(vj_set, successor_expr); @@ -140,8 +148,10 @@ PWMap MinVertexTS::calculate(const DirectedSBG& dsbg 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 diff --git a/algorithms/sorting/topological/min_vertex_ts.hpp b/algorithms/sorting/topological/min_vertex_ts.hpp index 1a0d9242..44b807a2 100644 --- a/algorithms/sorting/topological/min_vertex_ts.hpp +++ b/algorithms/sorting/topological/min_vertex_ts.hpp @@ -62,6 +62,7 @@ class MinVertexTS { Set _same_SV; Set _independent; Set _visitedSV; + unsigned int _max_repetition_depth; }; } // namespace detail diff --git a/algorithms/sorting/topological/topological_sorting.cpp b/algorithms/sorting/topological/topological_sorting.cpp index 5bf5bb82..e3f0659d 100644 --- a/algorithms/sorting/topological/topological_sorting.cpp +++ b/algorithms/sorting/topological/topological_sorting.cpp @@ -18,6 +18,7 @@ ******************************************************************************/ #include "algorithms/sorting/topological/topological_sorting.hpp" +#include "algorithms/sorting/topological/ts_impl.hpp" #include "util/debug.hpp" #include "util/time_profiler.hpp" @@ -25,34 +26,13 @@ namespace SBG { namespace LIB { -//////////////////////////////////////////////////////////////////////////////// -// Topological Sorting Algorithm 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; -} - //////////////////////////////////////////////////////////////////////////////// // Topological Sorting Algorithm Interface ------------------------------------- //////////////////////////////////////////////////////////////////////////////// -TopologicalSorting::TopologicalSorting(TSKind kind) : _kind(kind), _impl() +TopologicalSorting::TopologicalSorting() : _impl() { + TSKind kind = TS_IMPL.kind(); switch (kind) { case TSKind::kMinVertex: { _impl = detail::MinVertexTS{}; diff --git a/algorithms/sorting/topological/topological_sorting.hpp b/algorithms/sorting/topological/topological_sorting.hpp index 45ceefe8..7bcefeae 100644 --- a/algorithms/sorting/topological/topological_sorting.hpp +++ b/algorithms/sorting/topological/topological_sorting.hpp @@ -41,22 +41,17 @@ using TSImpl = std::variant; } // namespace detail -enum class TSKind { kMinVertex }; - -std::ostream& operator<<(std::ostream& out, const TSKind kind); - //////////////////////////////////////////////////////////////////////////////// // Topological Sorting Algorithm ----------------------------------------------- //////////////////////////////////////////////////////////////////////////////// class TopologicalSorting { public: - TopologicalSorting(TSKind kind); + TopologicalSorting(); PWMap calculate(const DirectedSBG& dsbg, const PWMap& pmap); private: - TSKind _kind; detail::TSImpl _impl; }; diff --git a/algorithms/sorting/topological/ts_fact.hpp b/algorithms/sorting/topological/ts_fact.hpp deleted file mode 100755 index 3fd7d935..00000000 --- a/algorithms/sorting/topological/ts_fact.hpp +++ /dev/null @@ -1,72 +0,0 @@ -/** @file ts_fact.hpp - - @brief Topological Sorting 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 SBGRAPH_ALGORITHMS_SORTING_TOPOLOGICAL_TS_FACT_HPP_ -#define SBGRAPH_ALGORITHMS_SORTING_TOPOLOGICAL_TS_FACT_HPP_ - -#include "algorithms/sorting/topological/min_vertex_ts.hpp" -#include "algorithms/sorting/topological/topological_sorting.hpp" - -namespace SBG { - -namespace LIB { - -#define TS_FACT TSFactory::instance() - -class MinVertexTSFact { -public: - MinVertexTSFact() = default; - - TopologicalSorting createTSAlgorithm() const; -}; - -/** - * @brief Single instance of topological sorting factory to be used by clients - * in need of creating an instance of a matching algorithm. A client includes - * this file and calls TS_FACT.createTSAlgorithm(args). - */ -class TSFactory { -public: - ~TSFactory() = default; - - static TSFactory& instance(); - const TSKind& kind() const; - - void set_ts_fact(TSKind kind); - - TopologicalSorting createTSAlgorithm() const; - -private: - using TSFactImpl = std::variant; - - TSFactory(); - - TSKind _kind; - TSFactImpl _impl; -}; - -} // namespace LIB - -} // namespace SBG - -#endif // SBGRAPH_ALGORITHMS_SORTING_TOPOLOGICAL_TS_FACT_HPP_ diff --git a/algorithms/sorting/topological/ts_fact.cpp b/algorithms/sorting/topological/ts_impl.cpp similarity index 54% rename from algorithms/sorting/topological/ts_fact.cpp rename to algorithms/sorting/topological/ts_impl.cpp index ea0b2f61..05ecfb17 100755 --- a/algorithms/sorting/topological/ts_fact.cpp +++ b/algorithms/sorting/topological/ts_impl.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include "algorithms/sorting/topological/ts_fact.hpp" +#include "algorithms/sorting/topological/ts_impl.hpp" #include "util/debug.hpp" namespace SBG { @@ -25,52 +25,39 @@ namespace SBG { namespace LIB { //////////////////////////////////////////////////////////////////////////////// -// Minimum Vertex Topological Sorting Factory ---------------------------------- +// Topological Sorting implementations //////////////////////////////////////////////////////////////////////////////// -TopologicalSorting MinVertexTSFact::createTSAlgorithm() const +std::ostream& operator<<(std::ostream& out, const TSKind kind) { - return TopologicalSorting{TSKind::kMinVertex}; -} - -//////////////////////////////////////////////////////////////////////////////// -// Factory for clients --------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// - -TSFactory::TSFactory() - : _kind(TSKind::kMinVertex), _impl(MinVertexTSFact{}) {} - -TSFactory& TSFactory::instance() -{ - static TSFactory _instance; - return _instance; -} - -const TSKind& TSFactory::kind() const { return _kind; } - -void TSFactory::set_ts_fact(TSKind kind) -{ - _kind = kind; switch (kind) { case TSKind::kMinVertex: { - _impl = MinVertexTSFact{}; + out << "minimum vertex"; break; } default: { - Util::ERROR("TSFactory::set_ts_fact: unsupported topological sorting ", - "implementation"); + Util::ERROR("TSKind::operator<<: unsupported topological sorting " + , "algorithm implementation"); break; } } + + return out; } -TopologicalSorting TSFactory::createTSAlgorithm() const +TSImplementation::TSImplementation() : _kind(TSKind::kMinVertex) {} + +TSImplementation& TSImplementation::instance() { - return std::visit([](const auto& a) { return a.createTSAlgorithm(); } - , _impl); + 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_ From 0726f39bd1de78130638f1633dcdbaaa54962197 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Sat, 23 May 2026 20:32:15 -0300 Subject: [PATCH 61/66] [SBG]: deleted remaining factories usages --- algorithms/cc/cc.cpp | 7 +- algorithms/misc/causalization_builders.cpp | 26 +++-- eval/eval_exec.cpp | 24 ++--- eval/user_impl_map.cpp | 12 +-- eval/user_impl_map.hpp | 10 +- eval/visitors/autom_impl_visitor.cpp | 1 - eval/visitors/expr_evaluator.cpp | 10 +- eval/visitors/func_evaluator.cpp | 29 +++--- test/performance/bm_exec.cpp | 16 ++-- .../boost/scalar_graph_builder.cpp | 5 +- test/performance/matching_bm.cpp | 9 +- test/performance/pwmap_bm.cpp | 4 - test/performance/scc_bm.cpp | 7 +- test/performance/set_bm.cpp | 2 - test/performance/utils.cpp | 94 ++++++++----------- 15 files changed, 108 insertions(+), 148 deletions(-) diff --git a/algorithms/cc/cc.cpp b/algorithms/cc/cc.cpp index 99e73ed3..c798d4de 100644 --- a/algorithms/cc/cc.cpp +++ b/algorithms/cc/cc.cpp @@ -18,7 +18,6 @@ ******************************************************************************/ #include "algorithms/cc/cc.hpp" -#include "sbg/pwmap_fact.hpp" #include "sbg/set.hpp" #include "util/logger.hpp" #include "util/time_profiler.hpp" @@ -37,8 +36,8 @@ PWMap connectedComponents(const SBG& sbg) Set V = sbg.V(); if (!V.isEmpty()) { - PWMap rmap = PWMAP_FACT.createPWMap(V); - PWMap old_rmap = PWMAP_FACT.createPWMap(); + PWMap rmap{V}; + PWMap old_rmap; if (sbg.E().isEmpty()) { return rmap; @@ -70,7 +69,7 @@ PWMap connectedComponents(const SBG& sbg) return rmap; } - return PWMAP_FACT.createPWMap(); + return PWMap{}; } } // namespace LIB diff --git a/algorithms/misc/causalization_builders.cpp b/algorithms/misc/causalization_builders.cpp index 4bece21e..6447d57b 100644 --- a/algorithms/misc/causalization_builders.cpp +++ b/algorithms/misc/causalization_builders.cpp @@ -19,11 +19,9 @@ #include "algorithms/misc/causalization_builders.hpp" #include "sbg/bipartite_sbg.hpp" -#include "sbg/set.hpp" -#include "sbg/set_fact.hpp" -#include "sbg/pw_map.hpp" -#include "sbg/pwmap_fact.hpp" #include "sbg/map.hpp" +#include "sbg/pw_map.hpp" +#include "sbg/set.hpp" #include "util/time_profiler.hpp" #include @@ -43,7 +41,7 @@ std::tuple buildSCCVertices( M.compact(); SBG::LIB::Set V = M; SBG::LIB::PWMap auxVmap = data.bsbg().Emap().restrict(M); - SBG::LIB::PWMap Vmap = SBG::LIB::PWMAP_FACT.createPWMap(); + SBG::LIB::PWMap Vmap; for (const SBG::LIB::Map& m : auxVmap) { SBG::LIB::Set domain = m.domain(); domain.compact(); @@ -99,21 +97,21 @@ void partitionEmap(SBG::LIB::DirectedSBG& dsbg) std::size_t arity = V.arity(); SBG::LIB::NAT j = 1; - SBG::LIB::PWMap partitioned_Emap = SBG::LIB::PWMAP_FACT.createPWMap(); + SBG::LIB::PWMap partitioned_Emap; dsbg.foreachSetEdge([&](const SBG::LIB::MD_NAT& SE) { - SBG::LIB::Set E = Emap.preImage(SBG::LIB::SET_FACT.createSet(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_FACT.createSet(remaining1.minElem()); + 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_FACT.createSet(remaining2.minElem()); + 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( @@ -140,13 +138,13 @@ SBG::LIB::DirectedSBG buildLoopDetectionSBG(const SBG::LIB::MatchData& data) { SBG::Util::Internal::TimeProfiler profiler{"SBG Loop Detection builder: "}; - SBG::LIB::Set V = SBG::LIB::SET_FACT.createSet(); - SBG::LIB::PWMap Vmap = SBG::LIB::PWMAP_FACT.createPWMap(); + SBG::LIB::Set V; + SBG::LIB::PWMap Vmap; std::tie(V, Vmap) = buildSCCVertices(data); - SBG::LIB::PWMap mapB = SBG::LIB::PWMAP_FACT.createPWMap(); - SBG::LIB::PWMap mapD = SBG::LIB::PWMAP_FACT.createPWMap(); - SBG::LIB::PWMap Emap = SBG::LIB::PWMAP_FACT.createPWMap(); + SBG::LIB::PWMap mapB; + SBG::LIB::PWMap mapD; + SBG::LIB::PWMap Emap; std::tie(mapB, mapD, Emap) = buildSCCEdges(data, Vmap); SBG::LIB::DirectedSBG dsbg{V, Vmap, mapB, mapD, Emap}; diff --git a/eval/eval_exec.cpp b/eval/eval_exec.cpp index 70b30046..a0a37252 100644 --- a/eval/eval_exec.cpp +++ b/eval/eval_exec.cpp @@ -17,18 +17,18 @@ ******************************************************************************/ -#include "algorithms/matching/matching_fact.hpp" -#include "algorithms/mfvs/mfvs_fact.hpp" -#include "algorithms/scc/scc_fact.hpp" -#include "algorithms/sorting/topological/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/set_fact.hpp" -#include "sbg/pwmap_fact.hpp" +#include "sbg/pwmap_impl.hpp" +#include "sbg/set_impl.hpp" #include "util/debug.hpp" #include "util/logger.hpp" #include "util/time_profiler.hpp" @@ -51,13 +51,13 @@ void printHeader(Util::prog_opts::variables_map vm) { if (vm.count("debug")) { std::cout << "-----------------------------------\n"; - std::cout << "Set implementation: " << LIB::SET_FACT.kind() << "\n"; - std::cout << "PWMap implementation: " << LIB::PWMAP_FACT.kind() << "\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.kind() << "\n"; - std::cout << "SCC algorithm: " << LIB::SCC_FACT.kind() << "\n"; - std::cout << "MFVS algorithm: " << LIB::MFVS_FACT.kind() << "\n"; - std::cout << "Topological sorting algorithm: " << LIB::TS_FACT.kind() + 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"; diff --git a/eval/user_impl_map.cpp b/eval/user_impl_map.cpp index bfa96fe2..00ef5dea 100755 --- a/eval/user_impl_map.cpp +++ b/eval/user_impl_map.cpp @@ -17,13 +17,9 @@ ******************************************************************************/ -#include "algorithms/scc/scc_fact.hpp" -#include "algorithms/mfvs/mfvs_fact.hpp" #include "eval/user_impl_map.hpp" #include "sbg/pw_map.hpp" -#include "sbg/pwmap_fact.hpp" #include "sbg/set.hpp" -#include "sbg/set_fact.hpp" #include "util/debug.hpp" namespace SBG { @@ -143,21 +139,21 @@ void setSetFactory(int set_impl) { LIB::SetKind set_fact = std::get(detail::IMPL_MAP.getFactory( "set", set_impl)); - LIB::SET_FACT.set_set_fact(set_fact); + LIB::SET_IMPL.set_set_fact(set_fact); } void setPWFactory(int pw_impl) { LIB::PWMapKind pwmap_fact = std::get( detail::IMPL_MAP.getFactory("pwmap", pw_impl)); - LIB::PWMAP_FACT.set_pwmap_fact(pwmap_fact); + 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_FACT.set_scc_fact(scc_fact); + LIB::SCC_IMPL.set_scc_fact(scc_fact); return; } @@ -166,7 +162,7 @@ void setMFVSFactory(int mfvs_impl) { LIB::MFVSKind mfvs_fact = std::get( detail::IMPL_MAP.getFactory("mfvs", mfvs_impl)); - LIB::MFVS_FACT.set_mfvs_fact(mfvs_fact); + LIB::MFVS_IMPL.set_mfvs_fact(mfvs_fact); return; } diff --git a/eval/user_impl_map.hpp b/eval/user_impl_map.hpp index 8b846fe5..b2476cc0 100755 --- a/eval/user_impl_map.hpp +++ b/eval/user_impl_map.hpp @@ -29,12 +29,14 @@ #ifndef SBGRAPH_EVAL_USER_IMPL_MAP_HPP_ #define SBGRAPH_EVAL_USER_IMPL_MAP_HPP_ -#include "algorithms/mfvs/min_feedback_vertex_set.hpp" -#include "algorithms/matching/matching.hpp" -#include "algorithms/scc/scc.hpp" -#include "algorithms/sorting/topological/topological_sorting.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 diff --git a/eval/visitors/autom_impl_visitor.cpp b/eval/visitors/autom_impl_visitor.cpp index 042deeaf..18115780 100755 --- a/eval/visitors/autom_impl_visitor.cpp +++ b/eval/visitors/autom_impl_visitor.cpp @@ -21,7 +21,6 @@ #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 { diff --git a/eval/visitors/expr_evaluator.cpp b/eval/visitors/expr_evaluator.cpp index 1b36290d..19b354ee 100755 --- a/eval/visitors/expr_evaluator.cpp +++ b/eval/visitors/expr_evaluator.cpp @@ -22,8 +22,6 @@ #include "eval/visitors/linear_expr_evaluator.hpp" #include "eval/visitors/nat_evaluator.hpp" #include "eval/visitors/rational_evaluator.hpp" -#include "sbg/pwmap_fact.hpp" -#include "sbg/set_fact.hpp" #include "util/debug.hpp" namespace SBG { @@ -143,12 +141,12 @@ ExprBaseType ExprEvaluator::operator()(AST::Interval v) const LIB::NAT s = boost::apply_visitor(nat_evaluator, v.step()); LIB::NAT e = boost::apply_visitor(nat_evaluator, v.end()); - return LIB::SET_FACT.createSet(b, s, e); + return LIB::Set{b, s, e}; } ExprBaseType ExprEvaluator::operator()(AST::MultiDimInter v) const { - LIB::Set result = LIB::SET_FACT.createSet(); + LIB::Set result; int i = 0; for (const AST::Expr& e : v.intervals()) { @@ -171,7 +169,7 @@ ExprBaseType ExprEvaluator::operator()(AST::MultiDimInter v) const ExprBaseType ExprEvaluator::operator()(AST::Set v) const { - LIB::Set result = LIB::SET_FACT.createSet(); + LIB::Set result; for (const AST::Expr& e : v.pieces()) { LIB::Set jth_element = eval(*this, e, "Set"); @@ -228,7 +226,7 @@ ExprBaseType ExprEvaluator::operator()(AST::LinearMap v) const ExprBaseType ExprEvaluator::operator()(AST::PWLMap v) const { - LIB::PWMap result = LIB::PWMAP_FACT.createPWMap(); + LIB::PWMap result; for (const AST::Expr& e : v.maps()) { result.insert(eval(*this, e, "Map")); diff --git a/eval/visitors/func_evaluator.cpp b/eval/visitors/func_evaluator.cpp index de869386..c0896509 100755 --- a/eval/visitors/func_evaluator.cpp +++ b/eval/visitors/func_evaluator.cpp @@ -19,16 +19,12 @@ #include "eval/visitors/func_evaluator.hpp" #include "algorithms/cc/cc.hpp" -#include "algorithms/mfvs/min_feedback_vertex_set.hpp" -#include "algorithms/mfvs/mfvs_fact.hpp" #include "algorithms/matching/matching.hpp" -#include "algorithms/matching/matching_fact.hpp" +#include "algorithms/mfvs/min_feedback_vertex_set.hpp" #include "algorithms/misc/causalization_builders.hpp" #include "algorithms/misc/causalization_json.hpp" #include "algorithms/scc/scc.hpp" -#include "algorithms/scc/scc_fact.hpp" #include "algorithms/sorting/topological/topological_sorting.hpp" -#include "algorithms/sorting/topological/ts_fact.hpp" #include "eval/base_type.hpp" #include "sbg/bipartite_sbg.hpp" #include "sbg/expression.hpp" @@ -39,7 +35,6 @@ #include "sbg/rational.hpp" #include "sbg/set.hpp" #include "sbg/pw_map.hpp" -#include "sbg/pwmap_fact.hpp" #include "util/debug.hpp" #include "util/defs.hpp" @@ -627,7 +622,7 @@ 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(); + LIB::Matching match_impl; const auto matching_evaluator = Util::Overload { [&match_impl](LIB::BipartiteSBG a, LIB::NAT b) { return ExprBaseType{match_impl.calculate(copy(b, a))}; @@ -649,7 +644,7 @@ 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(); + LIB::SCC scc_impl; const auto scc_evaluator = Util::Overload { [&scc_impl](LIB::DirectedSBG a) { return ExprBaseType{scc_impl.calculate(a).rmap()}; @@ -671,7 +666,7 @@ ExprBaseType BuiltInFunctions::matchSCCEvaluator(const EBTList& args) const LIB::MatchData match_result = std::get(match_base_type); LIB::DirectedSBG dsbg = misc::buildLoopDetectionSBG(match_result); - LIB::SCC scc_impl = LIB::SCC_FACT.createSCCAlgorithm(); + LIB::SCC scc_impl; LIB::SCCData scc_result = scc_impl.calculate(dsbg); return ExprBaseType{scc_result.rmap()}; @@ -682,7 +677,7 @@ ExprBaseType BuiltInFunctions::mfvsEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "mfvsEvaluator: wrong number of arguments\n"); - LIB::MinFeedbackVertexSet mfvs_impl = LIB::MFVS_FACT.createMFVSAlgorithm(); + LIB::MinFeedbackVertexSet mfvs_impl; const auto mfvs_evaluator = Util::Overload { [&mfvs_impl](LIB::DirectedSBG a) { return ExprBaseType{mfvs_impl.calculate(a)}; @@ -705,11 +700,11 @@ ExprBaseType BuiltInFunctions::matchSCCMFVSEvaluator(const EBTList& args) const LIB::MatchData match_result = std::get(match_base_type); LIB::DirectedSBG dsbg = misc::buildLoopDetectionSBG(match_result); - LIB::SCC scc_impl = LIB::SCC_FACT.createSCCAlgorithm(); + LIB::SCC scc_impl; LIB::SCCData scc_result = scc_impl.calculate(dsbg); dsbg = misc::buildTearingSBG(scc_result); - LIB::MinFeedbackVertexSet mfvs_impl = LIB::MFVS_FACT.createMFVSAlgorithm(); + LIB::MinFeedbackVertexSet mfvs_impl; return ExprBaseType{mfvs_impl.calculate(dsbg)}; } @@ -718,10 +713,10 @@ ExprBaseType BuiltInFunctions::topoSortEvaluator(const EBTList& args) Util::ERROR_UNLESS(args.size() == 1 , "topoSortEvaluator: wrong number of arguments\n"); - LIB::TopologicalSorting ts_impl = LIB::TS_FACT.createTSAlgorithm(); + LIB::TopologicalSorting ts_impl; const auto ts_evaluator = Util::Overload { [&ts_impl](LIB::DirectedSBG a) { - return ExprBaseType{ts_impl.calculate(a, LIB::PWMAP_FACT.createPWMap())}; + return ExprBaseType{ts_impl.calculate(a, SBG::LIB::PWMap{})}; }, [](auto a) { Util::ERROR("topoSortEvaluator: wrong argument ", a, " for sort\n"); @@ -740,15 +735,15 @@ ExprBaseType BuiltInFunctions::causalizationEvaluator(const EBTList& args) const LIB::MatchData match_result = std::get(match_base_type); LIB::DirectedSBG dsbg = misc::buildLoopDetectionSBG(match_result); - LIB::SCC scc_impl = LIB::SCC_FACT.createSCCAlgorithm(); + LIB::SCC scc_impl; LIB::SCCData scc_result = scc_impl.calculate(dsbg); dsbg = misc::buildTearingSBG(scc_result); - LIB::MinFeedbackVertexSet mfvs_impl = LIB::MFVS_FACT.createMFVSAlgorithm(); + LIB::MinFeedbackVertexSet mfvs_impl; LIB::Set mfvs_result = mfvs_impl.calculate(dsbg); dsbg = misc::buildVerticalSortingSBG(scc_result, mfvs_result); - LIB::TopologicalSorting ts_impl = LIB::TS_FACT.createTSAlgorithm(); + LIB::TopologicalSorting ts_impl; LIB::PWMap ts_result = ts_impl.calculate(dsbg, scc_result.rmap()); misc::CausalizationResult causalized{match_result.M(), scc_result.rmap() diff --git a/test/performance/bm_exec.cpp b/test/performance/bm_exec.cpp index 16fcc2b1..f3c7d8c9 100644 --- a/test/performance/bm_exec.cpp +++ b/test/performance/bm_exec.cpp @@ -18,11 +18,11 @@ ******************************************************************************/ #include "test/performance/bm_exec.hpp" -#include "algorithms/matching/matching_fact.hpp" -#include "algorithms/scc/scc_fact.hpp" +#include "algorithms/matching/matching_impl.hpp" +#include "algorithms/scc/scc_impl.hpp" #include "eval/user_impl_map.hpp" -#include "sbg/pwmap_fact.hpp" -#include "sbg/set_fact.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" @@ -52,11 +52,11 @@ void printHeader(Util::prog_opts::variables_map vm) { if (vm.count("debug")) { std::cout << "-----------------------------------\n"; - std::cout << "Set implementation: " << LIB::SET_FACT.kind() << "\n"; - std::cout << "PWMap implementation: " << LIB::PWMAP_FACT.kind() << "\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.kind() << "\n"; - std::cout << "SCC algorithm: " << LIB::SCC_FACT.kind() << "\n\n"; + std::cout << "Matching algorithm: " << LIB::MATCH_IMPL.kind() << "\n"; + std::cout << "SCC algorithm: " << LIB::SCC_IMPL.kind() << "\n\n"; } } diff --git a/test/performance/boost/scalar_graph_builder.cpp b/test/performance/boost/scalar_graph_builder.cpp index 916355f8..97fcb967 100644 --- a/test/performance/boost/scalar_graph_builder.cpp +++ b/test/performance/boost/scalar_graph_builder.cpp @@ -19,7 +19,6 @@ #include "sbg/multidim_inter.hpp" #include "sbg/set_detail.hpp" -#include "sbg/set_fact.hpp" #include "test/performance/boost/scalar_graph_builder.hpp" #include "util/time_profiler.hpp" @@ -79,7 +78,7 @@ void ScalarGraphBuilder::translateVertices() for (const MD_NAT& v : vertices) { _vertex_map[v] = count; _partition.emplace_back( - SBG::LIB::SET_FACT.createSet(v).intersection(X).isEmpty()); + SBG::LIB::Set{v}.intersection(X).isEmpty()); ++count; } } @@ -99,7 +98,7 @@ EdgeVector ScalarGraphBuilder::getEdgeList() std::vector edges = key.flatten(E); for (const MD_NAT& e : edges) { // Get endings of edge - Set domain = SBG::LIB::SET_FACT.createSet(e); + 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); diff --git a/test/performance/matching_bm.cpp b/test/performance/matching_bm.cpp index 92760965..09160885 100644 --- a/test/performance/matching_bm.cpp +++ b/test/performance/matching_bm.cpp @@ -17,11 +17,10 @@ ******************************************************************************/ +#include "test/performance/matching_bm.hpp" #include "algorithms/matching/matching.hpp" -#include "algorithms/matching/matching_fact.hpp" #include "sbg/bipartite_sbg.hpp" #include "test/performance/utils.hpp" -#include "test/performance/matching_bm.hpp" #include @@ -39,8 +38,7 @@ static void BM_Matching(benchmark::State& state, std::string filename) { int N = state.range(0); - SBG::LIB::Matching match_algorithm - = SBG::LIB::MATCH_FACT.createMatchAlgorithm(); + SBG::LIB::Matching match_algorithm; SBG::LIB::BipartiteSBG match_sbg = generateSBG(filename, N, 1); for (auto _ : state) { benchmark::DoNotOptimize(match_algorithm.calculate(match_sbg)); @@ -54,8 +52,7 @@ static void BM_MatchingCopies(benchmark::State& state, std::string filename) int N = state.range(0); // Calculate Matching - SBG::LIB::Matching match_algorithm - = SBG::LIB::MATCH_FACT.createMatchAlgorithm(); + SBG::LIB::Matching match_algorithm; SBG::LIB::BipartiteSBG match_sbg = generateSBG(filename, 100, N); for (auto _ : state) { diff --git a/test/performance/pwmap_bm.cpp b/test/performance/pwmap_bm.cpp index c9f49efe..377487ec 100644 --- a/test/performance/pwmap_bm.cpp +++ b/test/performance/pwmap_bm.cpp @@ -18,9 +18,7 @@ ******************************************************************************/ #include "sbg/set.hpp" -#include "sbg/set_fact.hpp" #include "sbg/pw_map.hpp" -#include "sbg/pwmap_fact.hpp" #include "sbg/pwmap_detail.hpp" #include "test/performance/utils.hpp" @@ -34,9 +32,7 @@ namespace perf { namespace detail { -using SBG::LIB::SetKind; using SBG::LIB::Set; -using SBG::LIB::PWMapKind; //////////////////////////////////////////////////////////////////////////////// // Benchmarks ------------------------------------------------------------------ diff --git a/test/performance/scc_bm.cpp b/test/performance/scc_bm.cpp index 94a68cda..d39e11b0 100644 --- a/test/performance/scc_bm.cpp +++ b/test/performance/scc_bm.cpp @@ -19,7 +19,6 @@ #include "algorithms/matching/match_data.hpp" #include "algorithms/scc/scc.hpp" -#include "algorithms/scc/scc_fact.hpp" #include "algorithms/misc/causalization_builders.hpp" #include "sbg/directed_sbg.hpp" #include "test/performance/scc_bm.hpp" @@ -42,7 +41,7 @@ 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 = SBG::LIB::SCC_FACT.createSCCAlgorithm(); + SBG::LIB::SCC scc_algorithm; for (auto _ : state) { benchmark::DoNotOptimize(scc_algorithm.calculate(scc_dsbg)); @@ -54,7 +53,7 @@ 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 = SBG::LIB::SCC_FACT.createSCCAlgorithm(); + SBG::LIB::SCC scc_algorithm; for (auto _ : state) { SBG::LIB::DirectedSBG scc_dsbg = misc::buildLoopDetectionSBG(match_result); @@ -67,7 +66,7 @@ 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 = SBG::LIB::SCC_FACT.createSCCAlgorithm(); + SBG::LIB::SCC scc_algorithm; for (auto _ : state) { SBG::LIB::DirectedSBG scc_dsbg = misc::buildLoopDetectionSBG(match_result); diff --git a/test/performance/set_bm.cpp b/test/performance/set_bm.cpp index 6a656c03..565f7116 100644 --- a/test/performance/set_bm.cpp +++ b/test/performance/set_bm.cpp @@ -21,7 +21,6 @@ #include "sbg/multidim_inter.hpp" #include "sbg/natural.hpp" #include "sbg/set.hpp" -#include "sbg/set_fact.hpp" #include "test/performance/utils.hpp" #include @@ -37,7 +36,6 @@ namespace detail { using SBG::LIB::NAT; using SBG::LIB::detail::Interval; -using SBG::LIB::SetKind; using SBG::LIB::Set; //////////////////////////////////////////////////////////////////////////////// diff --git a/test/performance/utils.cpp b/test/performance/utils.cpp index 432cfbe3..56475ee3 100644 --- a/test/performance/utils.cpp +++ b/test/performance/utils.cpp @@ -18,7 +18,6 @@ ******************************************************************************/ #include "algorithms/matching/matching.hpp" -#include "algorithms/matching/matching_fact.hpp" #include "algorithms/matching/match_data.hpp" #include "eval/base_type.hpp" #include "eval/file_evaluator.cpp" @@ -28,10 +27,8 @@ #include "sbg/interval.hpp" #include "sbg/natural.hpp" #include "sbg/pw_map.hpp" -#include "sbg/pwmap_fact.hpp" #include "sbg/rational.hpp" #include "sbg/set.hpp" -#include "sbg/set_fact.hpp" #include #include @@ -115,16 +112,14 @@ BipartiteSBG generateSBG(std::string filename, int N, int copies) std::cout.rdbuf(original_buf); - return g; - //TODO return g.copy(copies); + return copy(copies, g); } MatchData calculateMatching(std::string filename, int N, int copies) { // Calculate matching BipartiteSBG match_sbg = generateSBG(filename, N, copies); - Matching match_algorithm - = SBG::LIB::MATCH_FACT.createMatchAlgorithm(); + Matching match_algorithm; MatchData match_result = match_algorithm.calculate(match_sbg); return match_result; @@ -138,21 +133,20 @@ std::pair nonDisjointPieces(NAT set_sz) { NAT inter_sz = 100; - Set s1 = SBG::LIB::SET_FACT.createSet(); - Set s2 = SBG::LIB::SET_FACT.createSet(); + 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 = SBG::LIB::SET_FACT.createSet(i1.begin(), i1.step() - , i1.end()); + 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 = SBG::LIB::SET_FACT.createSet(i2.begin(), i2.step(), i2.end()); + Set jth_s2{i2.begin(), i2.step(), i2.end()}; s2 = s2.disjointCup(jth_s2); } - Set second_dim = SBG::LIB::SET_FACT.createSet(0, 1, inter_sz - 1); + Set second_dim{0, 1, inter_sz - 1}; s1 = s1.cartesianProduct(second_dim); s2 = s2.cartesianProduct(second_dim); @@ -163,14 +157,12 @@ std::pair interlacedPieces(NAT set_sz) { NAT inter_sz = 100; - Set s1 = SBG::LIB::SET_FACT.createSet(); - Set s2 = SBG::LIB::SET_FACT.createSet(); + Set s1; + Set s2; for (SBG::LIB::NAT j = 0; j < set_sz; j += 2) { - Set jth_s1 = SBG::LIB::SET_FACT.createSet(j*inter_sz, 1 - , (j + 1)*inter_sz - 1); + Set jth_s1{j*inter_sz, 1, (j + 1)*inter_sz - 1}; s1 = std::move(s1.disjointCup(jth_s1)); - Set jth_s2 = SBG::LIB::SET_FACT.createSet((j + 1)*inter_sz, 1 - , (j + 2)*inter_sz - 1); + Set jth_s2{(j + 1)*inter_sz, 1, (j + 2)*inter_sz - 1}; s2 = std::move(s2.disjointCup(jth_s2)); } @@ -186,14 +178,13 @@ PWMap denseDom(NAT map_sz) NAT inter_sz = 100; NAT set_sz = 10; - PWMap pw = SBG::LIB::PWMAP_FACT.createPWMap(); + PWMap pw; for (unsigned int j = 0; j < map_sz; ++j) { - Set domain = SBG::LIB::SET_FACT.createSet(); + 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 - = SBG::LIB::SET_FACT.createSet(i.begin(), i.step(), i.end()); + Set jth_domain{i.begin(), i.step(), i.end()}; domain = std::move(domain).disjointCup(std::move(jth_domain)); } Expression id{RATIONAL{1}, RATIONAL{0}}; @@ -209,23 +200,21 @@ std::pair minAdjMaps(NAT map_sz) NAT inter_sz = 100; NAT set_sz = 10; - Set second_dim = SBG::LIB::SET_FACT.createSet(0, 1, inter_sz - 1); - PWMap pw1 = SBG::LIB::PWMAP_FACT.createPWMap(); - PWMap pw2 = SBG::LIB::PWMAP_FACT.createPWMap(); + Set second_dim{0, 1, inter_sz - 1}; + PWMap pw1; + PWMap pw2; for (unsigned int j = 0; j < map_sz; ++j) { - Set domain1 = SBG::LIB::SET_FACT.createSet(); - Set domain2 = SBG::LIB::SET_FACT.createSet(); + 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 = SBG::LIB::SET_FACT.createSet(i1.begin(), i1.step() - , i1.end()); + 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 = SBG::LIB::SET_FACT.createSet(i2.begin(), i2.step() - , i2.end()); + Set jth_domain2{i2.begin(), i2.step(), i2.end()}; domain2 = std::move(domain2).disjointCup(std::move(jth_domain2)); } @@ -244,23 +233,21 @@ std::pair interlacedMaps(NAT map_sz) NAT inter_sz = 100; NAT set_sz = 10; - Set second_dim = SBG::LIB::SET_FACT.createSet(0, 1, inter_sz - 1); - PWMap pw1 = SBG::LIB::PWMAP_FACT.createPWMap(); - PWMap pw2 = SBG::LIB::PWMAP_FACT.createPWMap(); + Set second_dim{0, 1, inter_sz - 1}; + PWMap pw1; + PWMap pw2; for (unsigned int j = 0; j < map_sz; ++j) { - Set domain1 = SBG::LIB::SET_FACT.createSet(); - Set domain2 = SBG::LIB::SET_FACT.createSet(); + 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 = SBG::LIB::SET_FACT.createSet(i1.begin(), i1.step() - , i1.end()); + 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 = SBG::LIB::SET_FACT.createSet(i2.begin(), i2.step() - , i2.end()); + Set jth_domain2{i2.begin(), i2.step(), i2.end()}; domain2 = std::move(domain2).disjointCup(std::move(jth_domain2)); } domain1 = domain1.cartesianProduct(second_dim); @@ -280,23 +267,21 @@ std::pair nonDisjointMaps(NAT map_sz) NAT inter_sz = 100; NAT set_sz = 10; - Set second_dim = SBG::LIB::SET_FACT.createSet(0, 1, inter_sz - 1); - PWMap pw1 = SBG::LIB::PWMAP_FACT.createPWMap(); - PWMap pw2 = SBG::LIB::PWMAP_FACT.createPWMap(); + Set second_dim{0, 1, inter_sz - 1}; + PWMap pw1; + PWMap pw2; for (unsigned int j = 0; j < map_sz; ++j) { - Set domain1 = SBG::LIB::SET_FACT.createSet(); - Set domain2 = SBG::LIB::SET_FACT.createSet(); + 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 = SBG::LIB::SET_FACT.createSet(i1.begin(), i1.step() - , i1.end()); + 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 = SBG::LIB::SET_FACT.createSet(i2.begin(), i2.step() - , i2.end()); + Set jth_domain2{i2.begin(), i2.step(), i2.end()}; domain2 = std::move(domain2).disjointCup(std::move(jth_domain2)); } domain1 = domain1.cartesianProduct(second_dim); @@ -316,15 +301,14 @@ PWMap reducibleMaps(NAT map_sz) NAT inter_sz = 100; NAT set_sz = 10; - Set second_dim = SBG::LIB::SET_FACT.createSet(0, 1, inter_sz - 1); - PWMap pw = SBG::LIB::PWMAP_FACT.createPWMap(); + Set second_dim{0, 1, inter_sz - 1}; + PWMap pw; for (unsigned int j = 0; j < map_sz; ++j) { - Set domain = SBG::LIB::SET_FACT.createSet(); + 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 - = SBG::LIB::SET_FACT.createSet(i.begin(), i.step(), i.end()); + Set jth_domain{i.begin(), i.step(), i.end()}; domain = std::move(domain).disjointCup(std::move(jth_domain)); } domain = domain.cartesianProduct(second_dim); From 41d2068785aa1c1d7e5ea172f8b8abed1a4747a4 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Mon, 25 May 2026 19:24:27 -0300 Subject: [PATCH 62/66] [PWMap::inverse]: fixed PWMap inverse singleton domain and constant expression --- sbg/dom_ord_pwmap.cpp | 3 +-- sbg/map.cpp | 9 +++++++++ sbg/map.hpp | 8 +++++++- sbg/ord_pwmap.cpp | 3 +-- sbg/unord_pwmap.cpp | 2 +- 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/sbg/dom_ord_pwmap.cpp b/sbg/dom_ord_pwmap.cpp index 579e1b3d..d0444fea 100644 --- a/sbg/dom_ord_pwmap.cpp +++ b/sbg/dom_ord_pwmap.cpp @@ -440,8 +440,7 @@ DomOrdPWMap DomOrdPWMap::inverse() const DomOrdPWMap result; for (const MapEntry& entry : _pieces) { - Map m = entry.map(); - result.emplace(Map{m.image(), m.law().inverse()}); + result.emplace(entry.map().inverse()); } return result; diff --git a/sbg/map.cpp b/sbg/map.cpp index 89d7c149..4ae864ec 100755 --- a/sbg/map.cpp +++ b/sbg/map.cpp @@ -128,6 +128,15 @@ Set Map::preImage(const Set& subcodom) const .intersection(_domain); } +Map Map::inverse() const +{ + if (_domain.cardinal() == 1) { + return Map{image(), _domain.minElem()}; + } + + return Map{image(), _law.inverse()}; +} + Map Map::composition(const Map& other) const { Set result_domain = _domain.intersection(other.image()); diff --git a/sbg/map.hpp b/sbg/map.hpp index 875eecc1..8de564ab 100755 --- a/sbg/map.hpp +++ b/sbg/map.hpp @@ -113,7 +113,13 @@ class Map { * @param subcodom Set of elements in the image of the map for which the * pre image will be calculated. */ - Set preImage(const Set& subcodom) const; // opt + 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. diff --git a/sbg/ord_pwmap.cpp b/sbg/ord_pwmap.cpp index fa7dc85f..5122c6cc 100644 --- a/sbg/ord_pwmap.cpp +++ b/sbg/ord_pwmap.cpp @@ -416,8 +416,7 @@ OrdPWMap OrdPWMap::inverse() const OrdPWMap result; for (const MapEntry& entry : _pieces) { - Map m = entry.map(); - result.emplace(Map{m.image(), m.law().inverse()}); + result.emplace(entry.map().inverse()); } return result; diff --git a/sbg/unord_pwmap.cpp b/sbg/unord_pwmap.cpp index e9301fcc..ddc61023 100644 --- a/sbg/unord_pwmap.cpp +++ b/sbg/unord_pwmap.cpp @@ -248,7 +248,7 @@ UnordPWMap UnordPWMap::inverse() const UnordPWMap result; for (const Map& m : _pieces) { - result.emplaceBack(m.image(), m.law().inverse()); + result.pushBack(m.inverse()); } return result; From a9e3d0867788b49dfe25e7d9fc3bd93be6b8761c Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Tue, 2 Jun 2026 18:02:38 -0300 Subject: [PATCH 63/66] [JSON]: redefined JSON output for Sets --- sbg/multidim_inter.cpp | 7 ++----- sbg/ord_set.cpp | 7 ++----- sbg/ord_unidim_dense_set.cpp | 12 ++++++------ sbg/unord_set.cpp | 7 ++----- 4 files changed, 12 insertions(+), 21 deletions(-) diff --git a/sbg/multidim_inter.cpp b/sbg/multidim_inter.cpp index 1f290667..a788f8d8 100755 --- a/sbg/multidim_inter.cpp +++ b/sbg/multidim_inter.cpp @@ -259,16 +259,13 @@ MaybeMDI MultiDimInter::compact(const MultiDimInter& other) const rapidjson::Value toJSON(MultiDimInter mdi , rapidjson::Document::AllocatorType& alloc) { - rapidjson::Value result{rapidjson::kArrayType}; - rapidjson::Value interval_array{rapidjson::kArrayType}; for (const Interval& i : mdi) { rapidjson::Value jth = toJSON(i, alloc); interval_array.PushBack(jth, alloc); } - rapidjson::Value mdi_obj{rapidjson::kObjectType}; - mdi_obj.AddMember("bounds", interval_array, alloc); - result.PushBack(mdi_obj, alloc); + rapidjson::Value result{rapidjson::kObjectType}; + result.AddMember("bounds", interval_array, alloc); return result; } diff --git a/sbg/ord_set.cpp b/sbg/ord_set.cpp index 7b96a88f..c41e5a9e 100644 --- a/sbg/ord_set.cpp +++ b/sbg/ord_set.cpp @@ -681,16 +681,13 @@ void OrderedSet::compact() rapidjson::Value toJSON(OrderedSet s, rapidjson::Document::AllocatorType& alloc) { - rapidjson::Value result{rapidjson::kArrayType}; - 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 mdi_obj{rapidjson::kObjectType}; - mdi_obj.AddMember("pieces", mdi_array, alloc); - result.PushBack(mdi_obj, alloc); + rapidjson::Value result{rapidjson::kObjectType}; + result.AddMember("pieces", mdi_array, alloc); return result; } diff --git a/sbg/ord_unidim_dense_set.cpp b/sbg/ord_unidim_dense_set.cpp index 6ff7edcd..c04e9122 100644 --- a/sbg/ord_unidim_dense_set.cpp +++ b/sbg/ord_unidim_dense_set.cpp @@ -492,16 +492,16 @@ OrdUnidimDenseSet OrdUnidimDenseSet::traverse( rapidjson::Value toJSON(OrdUnidimDenseSet s , rapidjson::Document::AllocatorType& alloc) { - rapidjson::Value result{rapidjson::kArrayType}; - rapidjson::Value interval_array{rapidjson::kArrayType}; for (const Interval& i : s) { - rapidjson::Value jth = detail::toJSON(i, alloc); + 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 mdi_obj{rapidjson::kObjectType}; - mdi_obj.AddMember("pieces", interval_array, alloc); - result.PushBack(mdi_obj, alloc); + rapidjson::Value result{rapidjson::kObjectType}; + result.AddMember("pieces", interval_array, alloc); return result; } diff --git a/sbg/unord_set.cpp b/sbg/unord_set.cpp index 88d9e64a..2ee04511 100644 --- a/sbg/unord_set.cpp +++ b/sbg/unord_set.cpp @@ -484,16 +484,13 @@ void UnorderedSet::compact() rapidjson::Value toJSON(UnorderedSet s , rapidjson::Document::AllocatorType& alloc) { - rapidjson::Value result{rapidjson::kArrayType}; - 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 mdi_obj{rapidjson::kObjectType}; - mdi_obj.AddMember("pieces", mdi_array, alloc); - result.PushBack(mdi_obj, alloc); + rapidjson::Value result{rapidjson::kObjectType}; + result.AddMember("pieces", mdi_array, alloc); return result; } From 60b5705f618d9154972870149ed52222aa4fc794 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Mon, 8 Jun 2026 15:15:38 -0300 Subject: [PATCH 64/66] [SCC]: execute at least twice sccStep --- algorithms/scc/minreach_scc.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/algorithms/scc/minreach_scc.cpp b/algorithms/scc/minreach_scc.cpp index 8333c21e..aa8aadf5 100644 --- a/algorithms/scc/minreach_scc.cpp +++ b/algorithms/scc/minreach_scc.cpp @@ -60,10 +60,11 @@ SCCData MinReachSCC::calculate(const DirectedSBG& dsbg) init(dsbg); - PWMap rmap; - Set Ediff; + PWMap rmap = sccStep(); + rmap.compact(); Set oldE = dsbg.E(); - Set deleted_edges; + Set Ediff = oldE.difference(_dsbg.E()); + Set deleted_edges = Ediff; do { oldE = _dsbg.E(); rmap = sccStep(); From 4c36265c72030d031558e6ae93c861eb0adf7a74 Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Tue, 9 Jun 2026 18:22:18 -0300 Subject: [PATCH 65/66] [Topological sorting]: debugged empty repetition in MinVertexTS::repetition --- algorithms/sorting/topological/min_vertex_ts.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/algorithms/sorting/topological/min_vertex_ts.cpp b/algorithms/sorting/topological/min_vertex_ts.cpp index 3eb60f54..2889b68c 100644 --- a/algorithms/sorting/topological/min_vertex_ts.cpp +++ b/algorithms/sorting/topological/min_vertex_ts.cpp @@ -87,7 +87,7 @@ PWMap MinVertexTS::repetition(const Set& init_V checkSorting(result, dsbg); } } else { - result; + result = PWMap{}; } return result; From 8ab706e8c64d1dbdc5a72559acd6895dde547e8f Mon Sep 17 00:00:00 2001 From: kalashnikovni Date: Mon, 29 Jun 2026 19:25:45 -0300 Subject: [PATCH 66/66] [Time profiler]: printing of only one function time --- util/time_profiler.cpp | 12 +++++++++++- util/time_profiler.hpp | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/util/time_profiler.cpp b/util/time_profiler.cpp index fb99fa21..75c8e140 100644 --- a/util/time_profiler.cpp +++ b/util/time_profiler.cpp @@ -28,7 +28,7 @@ void time_profiler_results() Internal::TimeProfiler::print_execution_time(); } -namespace Internal{ +namespace Internal { std::unordered_map TimeProfiler::_execution_time = {}; @@ -62,8 +62,18 @@ void TimeProfiler::print_execution_time() { } } +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 01e3bcf9..b658689d 100644 --- a/util/time_profiler.hpp +++ b/util/time_profiler.hpp @@ -43,6 +43,7 @@ struct TimeProfiler { ~TimeProfiler(); static void print_execution_time(); + static void print_execution_time(std::string function_name); private: std::string _function_name;