diff --git a/Makefile.in b/Makefile.in index 3be39aa..f918c7f 100755 --- a/Makefile.in +++ b/Makefile.in @@ -20,7 +20,7 @@ libdir ?= $(exec_prefix)/lib # Flags, Libraries and Includes INCLUDES := -I. -CXXFLAGS := -std=c++17 -Wall -Werror -Wno-reorder -O3 +CXXFLAGS := -std=c++17 -Wall -Werror -Wno-reorder -O3 -D BOOST_PHOENIX_STL_TUPLE_H_ ifeq ($(MODE),Debug) CXXFLAGS += -ggdb endif diff --git a/README.md b/README.md index e6367b8..75c2bdd 100755 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ In order to be able to install and compile SBG Library, the following dependencies must be installed: * autoconf 2.69 (avoid 2.71) - * boost1.71 + * boost1.81 (or later) * cmake * g++ * make diff --git a/ast/expr.cpp b/ast/expr.cpp index 01d2725..d4821d0 100755 --- a/ast/expr.cpp +++ b/ast/expr.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "ast/expr.hpp" namespace SBG { @@ -25,11 +25,42 @@ namespace AST { // Arithmetic expressions ------------------------------------------------------ -const char *OpNames[] = {"+", "-", "*", "^"}; +std::ostream &operator<<(std::ostream &out, const UnOp &op) +{ + switch (op) { + case UnOp::neg: + out << "-"; + break; + + default: + break; + } + + return out; +} std::ostream &operator<<(std::ostream &out, const Op &op) { - out << OpNames[op]; + switch (op) { + case Op::add: + out << "+"; + break; + + case Op::sub: + out << "-"; + break; + + case Op::mult: + out << "*"; + break; + + case Op::expo: + out << "^"; + break; + + default: + break; + } return out; } @@ -42,6 +73,24 @@ std::ostream &operator<<(std::ostream &out, const ExprList &el) return out; } +UnaryOp::UnaryOp() : op_(), expr_() {} +UnaryOp::UnaryOp(UnOp op, Expr expr) : op_(op), expr_(expr) {} + +member_imp(UnaryOp, UnOp, op); +member_imp(UnaryOp, Expr, expr); + +bool UnaryOp::operator==(const UnaryOp &other) const +{ + return op() == other.op() && expr() == other.expr(); +} + +std::ostream &operator<<(std::ostream &out, const UnaryOp &uop) +{ + out << uop.op() << uop.expr(); + + return out; +} + BinOp::BinOp() : left_(), op_(), right_() {} BinOp::BinOp(Expr left, Op op, Expr right) : left_(left), op_(op), right_(right) {} @@ -83,7 +132,7 @@ std::ostream &operator<<(std::ostream &out, const Call &c) if (sz > 0) { unsigned int i = 0; for (; i < sz - 1; i++) - out << c.args()[i] << ","; + out << c.args()[i] << ", "; out << c.args()[i]; } out << ")"; @@ -93,19 +142,47 @@ std::ostream &operator<<(std::ostream &out, const Call &c) // SBG Structures -------------------------------------------------------------- -const char *ContUOpNames[] = {"#", "\'"}; -const char *ContOpNames[] = {"/\\", "\\", "<", "==", "\\/"}; - std::ostream &operator<<(std::ostream &out, const ContainerUOp &op) { - out << ContUOpNames[op]; + switch (op) { + case ContainerUOp::card: + out << "#"; + break; + + case ContainerUOp::comp: + out << "\'"; + break; + } return out; } std::ostream &operator<<(std::ostream &out, const ContainerOp &op) { - out << ContOpNames[op]; + switch (op) { + case ContainerOp::eq: + out << "=="; + break; + + case ContainerOp::less: + out << "<"; + break; + + case ContainerOp::cap: + out << "/\\"; + break; + + case ContainerOp::diff: + out << "\\"; + break; + + case ContainerOp::cup: + out << "\\/"; + break; + + default: + break; + } return out; } @@ -271,11 +348,33 @@ std::ostream &operator<<(std::ostream &out, const LinearExp &le) return out; } +std::ostream &operator<<(std::ostream &out, const ExpOp &op) +{ + switch (op) { + case ExpOp::eq: + out << "=="; + break; + + case ExpOp::add: + out << "+"; + break; + + case ExpOp::sub: + out << "-"; + break; + + default: + break; + } + + return out; +} + LExpBinOp::LExpBinOp() : left_(), op_(), right_() {} -LExpBinOp::LExpBinOp(Expr left, Op op, Expr right) : left_(left), op_(op), right_(right) {} +LExpBinOp::LExpBinOp(Expr left, ExpOp op, Expr right) : left_(left), op_(op), right_(right) {} member_imp(LExpBinOp, Expr, left); -member_imp(LExpBinOp, Op, op); +member_imp(LExpBinOp, ExpOp, op); member_imp(LExpBinOp, Expr, right); bool LExpBinOp::operator==(const LExpBinOp &other) const @@ -310,6 +409,34 @@ std::ostream &operator<<(std::ostream &out, const LinearMap &lmap) return out; } +// Piecewise linear map -------------------------------------------------------- + +PWLMap::PWLMap() : maps_() {} +PWLMap::PWLMap(ExprList maps) : maps_(maps) {} + +member_imp(PWLMap, ExprList, maps); + +bool PWLMap::operator==(const PWLMap &other) const { return maps() == other.maps(); } + +std::ostream &operator<<(std::ostream &out, const PWLMap &pwl) +{ + PWLMap aux = pwl; + unsigned int sz = aux.maps_ref().size(); + + out << "<<"; + if (sz > 0) { + auto it = aux.maps_ref().begin(); + for (unsigned int i = 0; i < sz - 1; ++i) { + out << *it << ", "; + ++it; + } + out << *it; + } + out << ">>"; + + return out; +} + } // namespace AST } // namespace SBG diff --git a/ast/expr.hpp b/ast/expr.hpp index 4b7d22c..7b9e396 100755 --- a/ast/expr.hpp +++ b/ast/expr.hpp @@ -28,7 +28,7 @@ #include #include -#include +#include "util/defs.hpp" namespace SBG { @@ -40,19 +40,22 @@ typedef std::string Name; typedef Util::NAT Natural; typedef Util::RATIONAL Rational; typedef bool Boolean; +struct UnaryOp; +struct BinOp; struct Interval; struct InterUnaryOp; struct InterBinOp; struct Set; struct SetUnaryOp; struct SetBinOp; -struct BinOp; struct LinearExp; struct LExpBinOp; struct LinearMap; +struct PWLMap; struct Call; typedef boost::variant, boost::recursive_wrapper, boost::recursive_wrapper, boost::recursive_wrapper, @@ -63,15 +66,29 @@ typedef boost::variant, boost::recursive_wrapper, boost::recursive_wrapper, - boost::recursive_wrapper> Expr; + boost::recursive_wrapper, + boost::recursive_wrapper> Expr; typedef std::vector ExprList; std::ostream &operator<<(std::ostream &out, const ExprList &el); template inline bool is(Expr e) { return e.type() == typeid(T); } -typedef enum { add, sub, mult, expo } Op; -extern const char* OpNames[]; +enum class UnOp { neg }; +std::ostream &operator<<(std::ostream &out, const UnOp &op); + +struct UnaryOp { + member_class(UnOp, op); + member_class(Expr, expr); + + UnaryOp(); + UnaryOp(UnOp op, Expr expr); + + eq_class(UnaryOp); +}; +std::ostream &operator<<(std::ostream &out, const UnaryOp &uop); + +enum class Op { add, sub, mult, expo }; std::ostream &operator<<(std::ostream &out, const Op &op); struct BinOp { @@ -100,12 +117,10 @@ std::ostream &operator<<(std::ostream &out, const Call &c); // SBG structures -------------------------------------------------------------- -typedef enum { card, comp } ContainerUOp; -extern const char* ContUOpNames[]; +enum class ContainerUOp { card, comp }; std::ostream &operator<<(std::ostream &out, const ContainerUOp &op); -typedef enum { cap, diff, less, eq, cup } ContainerOp; -extern const char* ContOpNames[]; +enum class ContainerOp { eq, less, cap, diff, cup }; std::ostream &operator<<(std::ostream &out, const ContainerOp &op); // Intervals ------------------------------------------------------------------- @@ -193,13 +208,16 @@ struct LinearExp { }; std::ostream &operator<<(std::ostream &out, const LinearExp &le); +enum class ExpOp { eq, add, sub }; +std::ostream &operator<<(std::ostream &out, const ExpOp &op); + struct LExpBinOp { member_class(Expr, left); - member_class(Op, op); + member_class(ExpOp, op); member_class(Expr, right); LExpBinOp(); - LExpBinOp(Expr left, Op op, Expr right); + LExpBinOp(Expr left, ExpOp op, Expr right); eq_class(LExpBinOp); }; @@ -218,6 +236,18 @@ struct LinearMap { }; std::ostream &operator<<(std::ostream &out, const LinearMap &lm); +// Piecewise linear map -------------------------------------------------------- + +struct PWLMap { + member_class(ExprList, maps); + + PWLMap(); + PWLMap(ExprList maps); + + eq_class(PWLMap); +}; +std::ostream &operator<<(std::ostream &out, const PWLMap &pwl); + } // namespace AST } // namespace SBG diff --git a/ast/sbg_program.cpp b/ast/sbg_program.cpp index f43e329..1b15db2 100755 --- a/ast/sbg_program.cpp +++ b/ast/sbg_program.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "ast/sbg_program.hpp" namespace SBG { diff --git a/ast/sbg_program.hpp b/ast/sbg_program.hpp index b33a4a2..8f292eb 100755 --- a/ast/sbg_program.hpp +++ b/ast/sbg_program.hpp @@ -24,7 +24,7 @@ #ifndef PARSER_PROGRAM_AST_HPP #define PARSER_PROGRAM_AST_HPP -#include +#include "ast/statement.hpp" namespace SBG { diff --git a/ast/statement.cpp b/ast/statement.cpp index 9180ba5..04d7711 100755 --- a/ast/statement.cpp +++ b/ast/statement.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "ast/statement.hpp" namespace SBG { diff --git a/ast/statement.hpp b/ast/statement.hpp index 9ed6cd5..7276377 100755 --- a/ast/statement.hpp +++ b/ast/statement.hpp @@ -24,7 +24,7 @@ #ifndef PARSER_STATEMENT_AST_HPP #define PARSER_STATEMENT_AST_HPP -#include +#include "ast/expr.hpp" namespace SBG { diff --git a/eval/Makefile.include b/eval/Makefile.include index a38d82c..b5103df 100755 --- a/eval/Makefile.include +++ b/eval/Makefile.include @@ -27,13 +27,15 @@ EVAL_SRC := \ $(VISIT_DIR)/eval_set.cpp \ $(VISIT_DIR)/eval_le.cpp \ $(VISIT_DIR)/eval_map.cpp \ + $(VISIT_DIR)/eval_pwmap.cpp \ $(VISIT_DIR)/eval_expr.cpp \ $(VISIT_DIR)/stm_visitor.cpp \ $(VISIT_DIR)/program_visitor.cpp \ $(SBG_DIR)/interval.cpp \ $(SBG_DIR)/pw_inter.cpp \ $(SBG_DIR)/lexp.cpp \ - $(SBG_DIR)/map.cpp + $(SBG_DIR)/map.cpp \ + $(SBG_DIR)/pw_map.cpp # Objects EVAL_OBJ=$(addprefix $(BUILD_DIR)/, $(EVAL_SRC:.cpp=.o)) diff --git a/eval/defs.cpp b/eval/defs.cpp index c0c293b..3874270 100755 --- a/eval/defs.cpp +++ b/eval/defs.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "eval/defs.hpp" namespace SBG { @@ -58,7 +58,7 @@ MaybeVValue VarEnv::operator[](VKey k) const FuncEnv::FuncEnv() {} FuncEnvType FuncEnv::mapping_ = {{"isEmpty", 0}, {"isMember", 1}, {"minElem", 2}, {"maxElem", 3}, {"lt", 4}, - {"compose", 5}, {"inv", 6}, {"image", 7}, {"preImage", 8}}; + {"compose", 5}, {"inv", 6}, {"image", 7}, {"preImage", 8}, {"dom", 9}, {"minAdj", 10}}; MaybeFValue FuncEnv::operator[](FKey k) const { diff --git a/eval/defs.hpp b/eval/defs.hpp index 18853c6..d02bbf7 100755 --- a/eval/defs.hpp +++ b/eval/defs.hpp @@ -30,11 +30,11 @@ #include #include -#include -#include -#include -#include -#include +#include "ast/expr.hpp" +#include "ast/statement.hpp" +#include "sbg/pw_map.hpp" +#include "util/debug.hpp" +#include "util/defs.hpp" namespace SBG { @@ -42,7 +42,7 @@ namespace Eval { // Type definitions ------------------------------------------------------------ -typedef std::variant ExprBaseType; +typedef std::variant ExprBaseType; typedef std::optional MaybeEBT; template @@ -115,7 +115,7 @@ struct FuncEnv{ static FuncEnvType mapping_; }; -typedef enum { empty, member, min, max, lt, comp, inv, im, preim } Func; +typedef enum { empty, member, min, max, lt, comp, inv, im, preim, dom, min_adj } Func; /** @struct Overload * diff --git a/eval/main.cpp b/eval/main.cpp index e4fe045..089acde 100755 --- a/eval/main.cpp +++ b/eval/main.cpp @@ -27,8 +27,8 @@ #include -#include -#include +#include "parser/sbg_program.hpp" +#include "eval/visitors/program_visitor.hpp" void parseEvalProgramFromFile(std::string str) { diff --git a/eval/visitors/eval_expr.cpp b/eval/visitors/eval_expr.cpp index 1e58bf0..c7f3eb6 100755 --- a/eval/visitors/eval_expr.cpp +++ b/eval/visitors/eval_expr.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "eval/visitors/eval_expr.hpp" namespace SBG { @@ -70,10 +70,11 @@ auto lt_visitor_ = Overload{ }; auto compose_visitor_ = Overload{ - [](LIB::LExp a, LIB::LExp b) { return composition(a, b); }, + [](LIB::LExp a, LIB::LExp b) { return ExprBaseType(composition(a, b)); }, + [](LIB::PWMap a, LIB::PWMap b) { return ExprBaseType(composition(a, b)); }, [](auto a, auto b) { Util::ERROR("Wrong arguments for composition"); - return LIB::LExp(); } + return ExprBaseType(); } }; auto inverse_visitor_ = Overload{ @@ -85,37 +86,60 @@ auto inverse_visitor_ = Overload{ }; auto image_visitor1_ = Overload{ - [](LIB::SBGMap a) { return image(a); }, + [](LIB::SBGMap a) { return ExprBaseType(image(a)); }, + [](LIB::PWMap a) { return ExprBaseType(image(a)); }, [](auto a) { Util::ERROR("Wrong arguments for image 1"); - return LIB::SetPiece(); + return ExprBaseType(); } }; auto image_visitor2_ = Overload{ - [](LIB::SetPiece a, LIB::SBGMap b) { return image(a, b); }, + [](LIB::SetPiece a, LIB::SBGMap b) { return ExprBaseType(image(a, b)); }, + [](LIB::Set a, LIB::PWMap b) { return ExprBaseType(image(a, b)); }, [](auto a, auto b) { Util::ERROR("Wrong arguments for image 2"); - return LIB::SetPiece(); + return ExprBaseType(); } }; auto pre_image_visitor1_ = Overload{ - [](LIB::SBGMap a) { return preImage(a); }, + [](LIB::SBGMap a) { return ExprBaseType(preImage(a)); }, + [](LIB::PWMap a) { return ExprBaseType(preImage(a)); }, [](auto a) { Util::ERROR("Wrong arguments for pre image 1"); - return LIB::SetPiece(); + return ExprBaseType(); } }; auto pre_image_visitor2_ = Overload{ - [](LIB::SetPiece a, LIB::SBGMap b) { return preImage(a, b); }, + [](LIB::SetPiece a, LIB::SBGMap b) { return ExprBaseType(preImage(a, b)); }, + [](LIB::Set a, LIB::PWMap b) { return ExprBaseType(preImage(a, b)); }, [](auto a, auto b) { Util::ERROR("Wrong arguments for pre image 2"); - return LIB::SetPiece(); + return ExprBaseType(); } }; +auto dom_visitor_ = Overload{ + [](LIB::PWMap a) { return LIB::dom(a); }, + [](auto a) { + Util::ERROR("Wrong arguments for dom"); + return LIB::Set(); + } +}; + +/* +auto min_adj_visitor_ = Overload{ + [](LIB::SBGMap a, LIB::SBGMap b) { return ExprBaseType(minAdjMap(a, b)); }, + [](LIB::PWMap a, LIB::PWMap b) { return ExprBaseType(minAdjMap(a, b)); }, + [](auto a, auto b) { + Util::ERROR("Wrong arguments for minAdjMap"); + return ExprBaseType(); + } +}; +*/ + // Expression evaluator -------------------------------------------------------- EvalExpression::EvalExpression() : env_() {} @@ -137,30 +161,9 @@ ExprBaseType EvalExpression::operator()(Util::VariableName v) const return 0; } -ExprBaseType EvalExpression::operator()(AST::BinOp v) const -{ - AST::Expr l = v.left(), r = v.right(); +ExprBaseType EvalExpression::operator()(AST::UnaryOp v) const { return Apply(EvalRat(env_), AST::Expr(v)); } - EvalRat eval_rat(env_); - Util::RATIONAL l_result = Apply(eval_rat, l), r_result = Apply(eval_rat, r); - switch (v.op()) { - case AST::Op::add: - return l_result + r_result; - - case AST::Op::sub: - return l_result - r_result; - - case AST::Op::mult: - return l_result * r_result; - - default: - Util::ERROR("EvalExpression: BinOp %s not supported.", AST::OpNames[v.op()]); - return 0; - } - - Util::ERROR("EvalExpression: BinOp %s not supported.", AST::OpNames[v.op()]); - return 0; -} +ExprBaseType EvalExpression::operator()(AST::BinOp v) const { return Apply(EvalRat(env_), AST::Expr(v)); } ExprBaseType EvalExpression::operator()(AST::Call v) const { @@ -229,7 +232,7 @@ ExprBaseType EvalExpression::operator()(AST::Call v) const arity_ok = true; ExprBaseType lexp1 = eval_args[0], lexp2 = eval_args[1]; - LIB::LExp result = std::visit(compose_visitor_, lexp1, lexp2); + ExprBaseType result = std::visit(compose_visitor_, lexp1, lexp2); return result; } break; @@ -249,7 +252,7 @@ ExprBaseType EvalExpression::operator()(AST::Call v) const arity_ok = true; ExprBaseType sbgmap = eval_args[0]; - LIB::SetPiece result = std::visit(image_visitor1_, sbgmap); + ExprBaseType result = std::visit(image_visitor1_, sbgmap); return result; } @@ -257,7 +260,7 @@ ExprBaseType EvalExpression::operator()(AST::Call v) const arity_ok = true; ExprBaseType subdom = eval_args[0], sbgmap = eval_args[1]; - LIB::SetPiece result = std::visit(image_visitor2_, subdom, sbgmap); + ExprBaseType result = std::visit(image_visitor2_, subdom, sbgmap); return result; } @@ -268,20 +271,43 @@ ExprBaseType EvalExpression::operator()(AST::Call v) const arity_ok = true; ExprBaseType sbgmap = eval_args[0]; - LIB::SetPiece result = std::visit(pre_image_visitor1_, sbgmap); + ExprBaseType result = std::visit(pre_image_visitor1_, sbgmap); return result; } else if (eval_args.size() == 2) { arity_ok = true; - ExprBaseType subdom = eval_args[0], sbgmap = eval_args[1]; - LIB::SetPiece result = std::visit(pre_image_visitor2_, subdom, sbgmap); + ExprBaseType subdom = eval_args[0], map = eval_args[1]; + ExprBaseType result = std::visit(pre_image_visitor2_, subdom, map); return result; } break; + + case Eval::Func::dom: + if (eval_args.size() == 1) { + arity_ok = true; + + ExprBaseType pw = eval_args[0]; + LIB::Set result = std::visit(dom_visitor_, pw); + return result; + } + break; + + /* + case Eval::Func::min_adj: + if (eval_args.size() == 2) { + arity_ok = true; + + ExprBaseType map1 = eval_args[0], map2 = eval_args[1]; + ExprBaseType result = std::visit(min_adj_visitor_, map1, map2); + return result; + } + break; + */ + default: Util::ERROR("EvalExpression: function %s not implemented", vname.c_str()); return 0; @@ -308,7 +334,9 @@ ExprBaseType EvalExpression::operator()(AST::InterUnaryOp v) const return cardinal(Apply(eval_interval, exp)); default: - Util::ERROR("EvalExpression: InterUnaryOp %s not supported.", AST::ContUOpNames[v.op()]); + std::stringstream ss; + ss << v.op(); + Util::ERROR("EvalExpression: InterUnaryOp %s not supported.", ss.str().c_str()); return 0; } } @@ -328,7 +356,9 @@ ExprBaseType EvalExpression::operator()(AST::InterBinOp v) const return Apply(eval_interval, l) == Apply(eval_interval, r); default: - Util::ERROR("EvalExpression: InterBinOp %s not supported.", AST::ContOpNames[v.op()]); + std::stringstream ss; + ss << v.op(); + Util::ERROR("EvalExpression: InterBinOp %s not supported.", ss.str().c_str()); return 0; } } @@ -339,15 +369,18 @@ ExprBaseType EvalExpression::operator()(AST::SetUnaryOp v) const { AST::Expr exp = v.e(); EvalSet eval_set(env_); + LIB::Set eval_exp = Apply(eval_set, exp); switch (v.op()) { case AST::ContainerUOp::card: - return cardinal(Apply(eval_set, exp)); + return cardinal(eval_exp); case AST::ContainerUOp::comp: - return complement(Apply(eval_set, exp)); + return complement(eval_exp); default: - Util::ERROR("EvalExpression: SetUnaryOp %s not supported.", AST::ContUOpNames[v.op()]); + std::stringstream ss; + ss << v.op(); + Util::ERROR("EvalExpression: SetUnaryOp %s not supported.", ss.str().c_str()); return 0; } } @@ -370,7 +403,9 @@ ExprBaseType EvalExpression::operator()(AST::SetBinOp v) const return cup(Apply(eval_set, l), Apply(eval_set, r)); default: - Util::ERROR("EvalExpression: SetBinOp %s not supported.", AST::ContOpNames[v.op()]); + std::stringstream ss; + ss << v.op(); + Util::ERROR("EvalExpression: SetBinOp %s not supported.", ss.str().c_str()); return 0; } } @@ -381,21 +416,29 @@ ExprBaseType EvalExpression::operator()(AST::LExpBinOp v) const { AST::Expr l = v.left(), r = v.right(); EvalLE visit_le(env_); + LIB::LExp lexp = Apply(visit_le, l), rexp = Apply(visit_le, r); switch (v.op()) { - case AST::Op::add: - return Apply(visit_le, l) + Apply(visit_le, r); + case AST::ExpOp::eq: + return lexp == rexp; - case AST::Op::sub: - return Apply(visit_le, l) - Apply(visit_le, r); + case AST::ExpOp::add: + return lexp + rexp; + + case AST::ExpOp::sub: + return lexp - rexp; default: - Util::ERROR("EvalExpression: LExpBinOp %s not supported.", AST::OpNames[v.op()]); + std::stringstream ss; + ss << v.op(); + Util::ERROR("EvalExpression: LExpBinOp %s not supported.", ss.str().c_str()); return 0; } } ExprBaseType EvalExpression::operator()(AST::LinearMap v) const { return Apply(EvalMap(env_), AST::Expr(v)); } +ExprBaseType EvalExpression::operator()(AST::PWLMap v) const { return Apply(EvalPWMap(env_), AST::Expr(v)); } + } // namespace Eval } // namespace SBG diff --git a/eval/visitors/eval_expr.hpp b/eval/visitors/eval_expr.hpp index a4aed19..031af83 100755 --- a/eval/visitors/eval_expr.hpp +++ b/eval/visitors/eval_expr.hpp @@ -24,8 +24,8 @@ #ifndef AST_VISITOR_EVALEXP #define AST_VISITOR_EVALEXP -#include -#include +#include "eval/visitors/eval_set.hpp" +#include "eval/visitors/eval_pwmap.hpp" namespace SBG { @@ -40,6 +40,7 @@ struct EvalExpression : public boost::static_visitor { ExprBaseType operator()(AST::Rational v) const; ExprBaseType operator()(AST::Boolean v) const; ExprBaseType operator()(Util::VariableName v) const; + ExprBaseType operator()(AST::UnaryOp v) const; ExprBaseType operator()(AST::BinOp v) const; ExprBaseType operator()(AST::Call v) const; ExprBaseType operator()(AST::Interval v) const; @@ -51,6 +52,7 @@ struct EvalExpression : public boost::static_visitor { ExprBaseType operator()(AST::LinearExp v) const; ExprBaseType operator()(AST::LExpBinOp v) const; ExprBaseType operator()(AST::LinearMap v) const; + ExprBaseType operator()(AST::PWLMap v) const; private: mutable VarEnv env_; diff --git a/eval/visitors/eval_interval.cpp b/eval/visitors/eval_interval.cpp index 720ad3f..d96ce20 100755 --- a/eval/visitors/eval_interval.cpp +++ b/eval/visitors/eval_interval.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "eval/visitors/eval_interval.hpp" namespace SBG { @@ -62,6 +62,12 @@ LIB::Interval EvalInterval::operator()(Util::VariableName v) const return LIB::Interval(); } +LIB::Interval EvalInterval::operator()(AST::UnaryOp v) const +{ + Util::ERROR("EvalInterval: trying to evaluate an arithmetic UnaryOp"); + return LIB::Interval(); +} + LIB::Interval EvalInterval::operator()(AST::BinOp v) const { Util::ERROR("EvalInterval: trying to evaluate an arithmetic BinOp"); @@ -89,7 +95,9 @@ LIB::Interval EvalInterval::operator()(AST::InterUnaryOp v) const AST::Expr exp = v.e(); switch (v.op()) { default: - Util::ERROR("EvalInterval: InterUnaryOp %s not supported.", AST::ContUOpNames[v.op()]); + std::stringstream ss; + ss << v.op(); + Util::ERROR("EvalInterval: InterUnaryOp %s not supported.", ss.str().c_str()); return LIB::Interval(); } } @@ -102,14 +110,18 @@ LIB::Interval EvalInterval::operator()(AST::InterBinOp v) const return intersection(ApplyThis(l), ApplyThis(r)); default: - Util::ERROR("EvalInterval: InterBinOp %s not supported.", AST::ContOpNames[v.op()]); + std::stringstream ss; + ss << v.op(); + Util::ERROR("EvalInterval: InterBinOp %s not supported.", ss.str().c_str()); return LIB::Interval(); } } LIB::Interval EvalInterval::operator()(AST::Set v) const { - Util::ERROR("EvalInterval: trying to evaluate a Set"); + std::stringstream ss; + ss << v; + Util::ERROR("EvalInterval: trying to evaluate the Set %s", ss.str().c_str()); return LIB::Interval(); } @@ -143,6 +155,12 @@ LIB::Interval EvalInterval::operator()(AST::LinearMap v) const return LIB::Interval(); } +LIB::Interval EvalInterval::operator()(AST::PWLMap v) const +{ + Util::ERROR("EvalInterval: trying to evaluate a PWLMap"); + return LIB::Interval(); +} + } // namespace Eval } // namespace SBG diff --git a/eval/visitors/eval_interval.hpp b/eval/visitors/eval_interval.hpp index c3e7c81..9b4b372 100755 --- a/eval/visitors/eval_interval.hpp +++ b/eval/visitors/eval_interval.hpp @@ -24,8 +24,8 @@ #ifndef AST_VISITOR_EVALINTERVAL #define AST_VISITOR_EVALINTERVAL -#include -#include +#include "ast/expr.hpp" +#include "eval/visitors/eval_nat.hpp" namespace SBG { @@ -40,6 +40,7 @@ struct EvalInterval : public boost::static_visitor { LIB::Interval operator()(AST::Rational v) const; LIB::Interval operator()(AST::Boolean v) const; LIB::Interval operator()(Util::VariableName v) const; + LIB::Interval operator()(AST::UnaryOp v) const; LIB::Interval operator()(AST::BinOp v) const; LIB::Interval operator()(AST::Call v) const; LIB::Interval operator()(AST::Interval v) const; @@ -51,6 +52,7 @@ struct EvalInterval : public boost::static_visitor { LIB::Interval operator()(AST::LinearExp v) const; LIB::Interval operator()(AST::LExpBinOp v) const; LIB::Interval operator()(AST::LinearMap v) const; + LIB::Interval operator()(AST::PWLMap v) const; private: mutable VarEnv env_; diff --git a/eval/visitors/eval_le.cpp b/eval/visitors/eval_le.cpp index d856c5c..8a18717 100755 --- a/eval/visitors/eval_le.cpp +++ b/eval/visitors/eval_le.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "eval/visitors/eval_le.hpp" namespace SBG { @@ -58,6 +58,12 @@ LIB::LExp EvalLE::operator()(Util::VariableName v) const { return LIB::LExp(); } +LIB::LExp EvalLE::operator()(AST::UnaryOp v) const +{ + Util::ERROR("EvalLE: trying to evaluate an arithmetic UnaryOp"); + return LIB::LExp(); +} + LIB::LExp EvalLE::operator()(AST::BinOp v) const { Util::ERROR("EvalLE: trying to evaluate an arithmetic BinOp"); @@ -119,14 +125,16 @@ LIB::LExp EvalLE::operator()(AST::LExpBinOp v) const { AST::Expr l = v.left(), r = v.right(); switch (v.op()) { - case AST::Op::add: + case AST::ExpOp::add: return ApplyThis(l) + ApplyThis(r); - case AST::Op::sub: - return ApplyThis(l) + ApplyThis(r); + case AST::ExpOp::sub: + return ApplyThis(l) - ApplyThis(r); default: - Util::ERROR("EvalLE: LExpBinOp %s not supported.", AST::OpNames[v.op()]); + std::stringstream ss; + ss << v.op(); + Util::ERROR("EvalLE: LExpBinOp %s not supported.", ss.str().c_str()); return LIB::LExp(); } } @@ -137,6 +145,12 @@ LIB::LExp EvalLE::operator()(AST::LinearMap v) const return LIB::LExp(); } +LIB::LExp EvalLE::operator()(AST::PWLMap v) const +{ + Util::ERROR("EvalLE: trying to evaluate a PWLMap"); + return LIB::LExp(); +} + } // namespace Eval } // namespace SBG diff --git a/eval/visitors/eval_le.hpp b/eval/visitors/eval_le.hpp index 9264100..b0f2459 100755 --- a/eval/visitors/eval_le.hpp +++ b/eval/visitors/eval_le.hpp @@ -26,9 +26,8 @@ #include -#include -#include -#include +#include "eval/visitors/eval_rat.hpp" +#include "sbg/lexp.hpp" namespace SBG { @@ -43,6 +42,7 @@ struct EvalLE : public boost::static_visitor { LIB::LExp operator()(AST::Rational v) const; LIB::LExp operator()(AST::Boolean v) const; LIB::LExp operator()(Util::VariableName 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; @@ -54,6 +54,7 @@ struct EvalLE : public boost::static_visitor { LIB::LExp operator()(AST::LinearExp v) const; LIB::LExp operator()(AST::LExpBinOp v) const; LIB::LExp operator()(AST::LinearMap v) const; + LIB::LExp operator()(AST::PWLMap v) const; private: mutable VarEnv env_; diff --git a/eval/visitors/eval_map.cpp b/eval/visitors/eval_map.cpp index d934b8c..2a5fe3c 100755 --- a/eval/visitors/eval_map.cpp +++ b/eval/visitors/eval_map.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "eval/visitors/eval_map.hpp" namespace SBG { @@ -58,6 +58,12 @@ LIB::SBGMap EvalMap::operator()(Util::VariableName v) const { return LIB::SBGMap(); } +LIB::SBGMap EvalMap::operator()(AST::UnaryOp v) const +{ + Util::ERROR("EvalMap: trying to evaluate an arithmetic UnaryOp"); + return LIB::SBGMap(); +} + LIB::SBGMap EvalMap::operator()(AST::BinOp v) const { Util::ERROR("EvalMap: trying to evaluate an arithmetic BinOp"); @@ -120,10 +126,16 @@ LIB::SBGMap EvalMap::operator()(AST::LExpBinOp v) const LIB::SBGMap EvalMap::operator()(AST::LinearMap v) const { - EvalInterval visit_inter(env_); + EvalSet visit_set(env_); EvalLE visit_le(env_); - return LIB::SBGMap(Apply(visit_inter, v.dom()), Apply(visit_le, v.lexp())); + return LIB::SBGMap(Apply(visit_set, v.dom()), Apply(visit_le, v.lexp())); +} + +LIB::SBGMap EvalMap::operator()(AST::PWLMap v) const +{ + Util::ERROR("EvalMap: trying to evaluate a PWLMap"); + return LIB::SBGMap(); } } // namespace Eval diff --git a/eval/visitors/eval_map.hpp b/eval/visitors/eval_map.hpp index d59c544..2682a07 100755 --- a/eval/visitors/eval_map.hpp +++ b/eval/visitors/eval_map.hpp @@ -26,10 +26,9 @@ #include -#include -#include -#include -#include +#include "eval/visitors/eval_le.hpp" +#include "eval/visitors/eval_set.hpp" +#include "sbg/map.hpp" namespace SBG { @@ -44,6 +43,7 @@ struct EvalMap : public boost::static_visitor { LIB::SBGMap operator()(AST::Rational v) const; LIB::SBGMap operator()(AST::Boolean v) const; LIB::SBGMap operator()(Util::VariableName v) const; + LIB::SBGMap operator()(AST::UnaryOp v) const; LIB::SBGMap operator()(AST::BinOp v) const; LIB::SBGMap operator()(AST::Call v) const; LIB::SBGMap operator()(AST::Interval v) const; @@ -55,6 +55,7 @@ struct EvalMap : public boost::static_visitor { LIB::SBGMap operator()(AST::LinearExp v) const; LIB::SBGMap operator()(AST::LExpBinOp v) const; LIB::SBGMap operator()(AST::LinearMap v) const; + LIB::SBGMap operator()(AST::PWLMap v) const; private: mutable VarEnv env_; diff --git a/eval/visitors/eval_nat.cpp b/eval/visitors/eval_nat.cpp index 3bf407a..971e519 100755 --- a/eval/visitors/eval_nat.cpp +++ b/eval/visitors/eval_nat.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "eval/visitors/eval_nat.hpp" namespace SBG { @@ -57,6 +57,12 @@ Util::NAT EvalNat::operator()(Util::VariableName v) const return 0; } +Util::NAT EvalNat::operator()(AST::UnaryOp v) const +{ + Util::ERROR("EvalNat: trying to evaluate an arithmetic UnaryOp"); + return 0; +} + Util::NAT EvalNat::operator()(AST::BinOp v) const { AST::Expr l = v.left(), r = v.right(); @@ -74,7 +80,9 @@ Util::NAT EvalNat::operator()(AST::BinOp v) const return pow(ApplyThis(l), ApplyThis(r)); default: - Util::ERROR("EvalNat: BinOp %s not supported.", AST::OpNames[v.op()]); + std::stringstream ss; + ss << v.op(); + Util::ERROR("EvalNat: BinOp %s not supported.", ss.str().c_str()); return 0; } } @@ -139,6 +147,12 @@ Util::NAT EvalNat::operator()(AST::LinearMap v) const return 0; } +Util::NAT EvalNat::operator()(AST::PWLMap v) const +{ + Util::ERROR("EvalNat: trying to evaluate a PWLMap"); + return 0; +} + } // namespace Eval } // namespace SBG diff --git a/eval/visitors/eval_nat.hpp b/eval/visitors/eval_nat.hpp index 974fa64..f81df28 100755 --- a/eval/visitors/eval_nat.hpp +++ b/eval/visitors/eval_nat.hpp @@ -26,8 +26,8 @@ #include -#include -#include +#include "ast/expr.hpp" +#include "eval/defs.hpp" namespace SBG { @@ -42,6 +42,7 @@ struct EvalNat : public boost::static_visitor { Util::NAT operator()(AST::Rational v) const; Util::NAT operator()(AST::Boolean v) const; Util::NAT operator()(Util::VariableName v) const; + Util::NAT operator()(AST::UnaryOp v) const; Util::NAT operator()(AST::BinOp v) const; Util::NAT operator()(AST::Call v) const; Util::NAT operator()(AST::Interval v) const; @@ -53,6 +54,7 @@ struct EvalNat : public boost::static_visitor { Util::NAT operator()(AST::LinearExp v) const; Util::NAT operator()(AST::LExpBinOp v) const; Util::NAT operator()(AST::LinearMap v) const; + Util::NAT operator()(AST::PWLMap v) const; private: mutable VarEnv env_; diff --git a/eval/visitors/eval_pwmap.cpp b/eval/visitors/eval_pwmap.cpp new file mode 100755 index 0000000..b822f49 --- /dev/null +++ b/eval/visitors/eval_pwmap.cpp @@ -0,0 +1,146 @@ +/******************************************************************************* + + 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/visitors/eval_pwmap.hpp" + +namespace SBG { + +namespace Eval { + +EvalPWMap::EvalPWMap() : env_() {} +EvalPWMap::EvalPWMap(VarEnv env) : env_(env) {} + +LIB::PWMap EvalPWMap::operator()(AST::Natural v) const { + Util::ERROR("EvalPWMap: trying to evaluate a Natural"); + return LIB::PWMap(); +} + +LIB::PWMap EvalPWMap::operator()(AST::Rational v) const { + Util::ERROR("EvalPWMap: trying to evaluate a Rational"); + return LIB::PWMap(); +} + +LIB::PWMap EvalPWMap::operator()(AST::Boolean v) const { + Util::ERROR("EvalPWMap: trying to evaluate a Boolean"); + return LIB::PWMap(); +} + +LIB::PWMap EvalPWMap::operator()(Util::VariableName v) const { + MaybeEBT v_opt = env_[v]; + if (v_opt) { + ExprBaseType value = *v_opt; + if (std::holds_alternative(value)) + return std::get(value); + + else { + Util::ERROR("EvalPWMap: variable %s is not a PWMap", v.c_str()); + return LIB::PWMap(); + } + } + + Util::ERROR("EvalPWMap: variable %s not defined", v.c_str()); + return LIB::PWMap(); +} + +LIB::PWMap EvalPWMap::operator()(AST::UnaryOp v) const +{ + Util::ERROR("EvalPWMap: trying to evaluate an arithmetic UnaryOp"); + return LIB::PWMap(); +} + +LIB::PWMap EvalPWMap::operator()(AST::BinOp v) const +{ + Util::ERROR("EvalPWMap: trying to evaluate an arithmetic BinOp"); + return LIB::PWMap(); +} + +LIB::PWMap EvalPWMap::operator()(AST::Call v) const +{ + Util::ERROR("EvalPWMap: trying to evaluate a Call"); + return LIB::PWMap(); +} + +LIB::PWMap EvalPWMap::operator()(AST::Interval v) const +{ + Util::ERROR("EvalPWMap: trying to evaluate an Interval"); + return LIB::PWMap(); +} + +LIB::PWMap EvalPWMap::operator()(AST::InterUnaryOp v) const +{ + Util::ERROR("EvalPWMap: trying to evaluate an InterUnaryOp"); + return LIB::PWMap(); +} + +LIB::PWMap EvalPWMap::operator()(AST::InterBinOp v) const +{ + Util::ERROR("EvalPWMap: trying to evaluate an InterBinOp"); + return LIB::PWMap(); +} + +LIB::PWMap EvalPWMap::operator()(AST::Set v) const +{ + Util::ERROR("EvalPWMap: trying to evaluate a Set"); + return LIB::PWMap(); +} + +LIB::PWMap EvalPWMap::operator()(AST::SetUnaryOp v) const +{ + Util::ERROR("EvalPWMap: trying to evaluate a SetUnaryOp"); + return LIB::PWMap(); +} + +LIB::PWMap EvalPWMap::operator()(AST::SetBinOp v) const +{ + Util::ERROR("EvalPWMap: trying to evaluate a SetBinOp"); + return LIB::PWMap(); +} + +LIB::PWMap EvalPWMap::operator()(AST::LinearExp le) const +{ + Util::ERROR("EvalPWMap: trying to evaluate a LinearExp"); + return LIB::PWMap(); +} + +LIB::PWMap EvalPWMap::operator()(AST::LExpBinOp v) const +{ + Util::ERROR("EvalPWMap: trying to evaluate a LExpBinOp"); + return LIB::PWMap(); +} + +LIB::PWMap EvalPWMap::operator()(AST::LinearMap v) const +{ + Util::ERROR("EvalPWMap: trying to evaluate a LinearMap"); + return LIB::PWMap(); +} + +LIB::PWMap EvalPWMap::operator()(AST::PWLMap v) const +{ + LIB::MapSet res; + + EvalMap visit_map(env_); + BOOST_FOREACH (AST::Expr e, v.maps()) + res.emplace(Apply(visit_map, e)); + + return LIB::PWMap(res); +} + +} // namespace Eval + +} // namespace SBG diff --git a/eval/visitors/eval_pwmap.hpp b/eval/visitors/eval_pwmap.hpp new file mode 100755 index 0000000..9c0128b --- /dev/null +++ b/eval/visitors/eval_pwmap.hpp @@ -0,0 +1,67 @@ +/** @file eval_pwmap.hpp + + @brief Piecewise linear map expression evaluator + +
+ + 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 AST_VISITOR_EVAL_PWMAP +#define AST_VISITOR_EVAL_PWMAP + +#include + +#include "eval/visitors/eval_map.hpp" +#include "sbg/pw_map.hpp" + +namespace SBG { + +namespace Eval { + +struct EvalPWMap : public boost::static_visitor { + public: + EvalPWMap(); + EvalPWMap(VarEnv env); + + LIB::PWMap operator()(AST::Natural v) const; + LIB::PWMap operator()(AST::Rational v) const; + LIB::PWMap operator()(AST::Boolean v) const; + LIB::PWMap operator()(Util::VariableName v) const; + LIB::PWMap operator()(AST::UnaryOp v) const; + LIB::PWMap operator()(AST::BinOp v) const; + LIB::PWMap operator()(AST::Call v) const; + LIB::PWMap operator()(AST::Interval v) const; + LIB::PWMap operator()(AST::InterUnaryOp v) const; + LIB::PWMap operator()(AST::InterBinOp v) const; + LIB::PWMap operator()(AST::Set v) const; + LIB::PWMap operator()(AST::SetUnaryOp v) const; + LIB::PWMap operator()(AST::SetBinOp v) const; + LIB::PWMap operator()(AST::LinearExp v) const; + LIB::PWMap operator()(AST::LExpBinOp v) const; + LIB::PWMap operator()(AST::LinearMap v) const; + LIB::PWMap operator()(AST::PWLMap v) const; + + private: + mutable VarEnv env_; +}; + +} // namespace Eval + +} // namespace SBG + +#endif diff --git a/eval/visitors/eval_rat.cpp b/eval/visitors/eval_rat.cpp index 1430f8c..02a46ee 100755 --- a/eval/visitors/eval_rat.cpp +++ b/eval/visitors/eval_rat.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "eval/visitors/eval_rat.hpp" namespace SBG { @@ -56,8 +56,31 @@ Util::RATIONAL EvalRat::operator()(Util::VariableName v) const return Util::RATIONAL(0, 1); } +Util::RATIONAL EvalRat::operator()(AST::UnaryOp v) const +{ + std::stringstream ss; + ss << v.op(); + + EvalRat visit_rat(env_); + Util::RATIONAL result = Apply(visit_rat, v.expr()); + switch (v.op()) { + case AST::UnOp::neg: + return -result; + + default: + Util::ERROR("EvalExpression: UnaryOp %s not supported.", ss.str().c_str()); + return 0; + } + + Util::ERROR("EvalExpression: UnaryOp %s not supported.", ss.str().c_str()); + return 0; +} + Util::RATIONAL EvalRat::operator()(AST::BinOp v) const { + std::stringstream ss; + ss << v.op(); + AST::Expr l = v.left(), r = v.right(); switch (v.op()) { case AST::Op::add: @@ -70,9 +93,12 @@ Util::RATIONAL EvalRat::operator()(AST::BinOp v) const return ApplyThis(l) * ApplyThis(r); default: - Util::ERROR("EvalRat: BinOp %s not supported.", AST::OpNames[v.op()]); + Util::ERROR("EvalRat: BinOp %s not supported.", ss.str().c_str()); return Util::RATIONAL(0, 1); } + + Util::ERROR("EvalExpression: BinOp %s not supported.", ss.str().c_str()); + return 0; } Util::RATIONAL EvalRat::operator()(AST::Call v) const @@ -135,6 +161,12 @@ Util::RATIONAL EvalRat::operator()(AST::LinearMap v) const return Util::RATIONAL(0, 1); } +Util::RATIONAL EvalRat::operator()(AST::PWLMap v) const +{ + Util::ERROR("EvalRat: trying to evaluate an PWLMap"); + return Util::RATIONAL(0, 1); +} + } // namespace Eval } // namespace SBG diff --git a/eval/visitors/eval_rat.hpp b/eval/visitors/eval_rat.hpp index 3018ea3..b47fa5b 100755 --- a/eval/visitors/eval_rat.hpp +++ b/eval/visitors/eval_rat.hpp @@ -26,8 +26,8 @@ #include -#include -#include +#include "ast/expr.hpp" +#include "eval/defs.hpp" namespace SBG { @@ -42,6 +42,7 @@ struct EvalRat : public boost::static_visitor { Util::RATIONAL operator()(AST::Rational v) const; Util::RATIONAL operator()(AST::Boolean v) const; Util::RATIONAL operator()(Util::VariableName v) const; + Util::RATIONAL operator()(AST::UnaryOp v) const; Util::RATIONAL operator()(AST::BinOp v) const; Util::RATIONAL operator()(AST::Call v) const; Util::RATIONAL operator()(AST::Interval v) const; @@ -53,6 +54,7 @@ struct EvalRat : public boost::static_visitor { Util::RATIONAL operator()(AST::LinearExp v) const; Util::RATIONAL operator()(AST::LExpBinOp v) const; Util::RATIONAL operator()(AST::LinearMap v) const; + Util::RATIONAL operator()(AST::PWLMap v) const; private: mutable VarEnv env_; diff --git a/eval/visitors/eval_set.cpp b/eval/visitors/eval_set.cpp index 2f2c624..32f8d7c 100755 --- a/eval/visitors/eval_set.cpp +++ b/eval/visitors/eval_set.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "eval/visitors/eval_set.hpp" namespace SBG { @@ -58,6 +58,12 @@ LIB::Set EvalSet::operator()(Util::VariableName v) const { return LIB::Set(); } +LIB::Set EvalSet::operator()(AST::UnaryOp v) const +{ + Util::ERROR("EvalSet: trying to evaluate an arithmetic UnaryOp"); + return LIB::Set(); +} + LIB::Set EvalSet::operator()(AST::BinOp v) const { Util::ERROR("EvalSet: trying to evaluate an arithmetic BinOp"); @@ -104,7 +110,9 @@ LIB::Set EvalSet::operator()(AST::SetUnaryOp v) const AST::Expr e = v.e(); switch (v.op()) { default: - Util::ERROR("EvalSet: SetUnaryOp %s not supported.", AST::ContUOpNames[v.op()]); + std::stringstream ss; + ss << v.op(); + Util::ERROR("EvalSet: SetUnaryOp %s not supported.", ss.str().c_str()); return LIB::Set(); } } @@ -120,7 +128,9 @@ LIB::Set EvalSet::operator()(AST::SetBinOp v) const return difference(ApplyThis(l), ApplyThis(r)); default: - Util::ERROR("EvalSet: SetBinOp %s not supported.", AST::ContOpNames[v.op()]); + std::stringstream ss; + ss << v.op(); + Util::ERROR("EvalSet: SetBinOp %s not supported.", ss.str().c_str()); return LIB::Set(); } } @@ -143,6 +153,12 @@ LIB::Set EvalSet::operator()(AST::LinearMap v) const return LIB::Set(); } +LIB::Set EvalSet::operator()(AST::PWLMap v) const +{ + Util::ERROR("EvalSet: trying to evaluate a PWLMap"); + return LIB::Set(); +} + } // namespace Eval } // namespace SBG diff --git a/eval/visitors/eval_set.hpp b/eval/visitors/eval_set.hpp index 344ccf9..4f8ee21 100755 --- a/eval/visitors/eval_set.hpp +++ b/eval/visitors/eval_set.hpp @@ -24,7 +24,7 @@ #ifndef AST_VISITOR_EVALSET #define AST_VISITOR_EVALSET -#include +#include "eval/visitors/eval_interval.hpp" namespace SBG { @@ -39,6 +39,7 @@ struct EvalSet : public boost::static_visitor { LIB::Set operator()(AST::Rational v) const; LIB::Set operator()(AST::Boolean v) const; LIB::Set operator()(Util::VariableName v) const; + LIB::Set operator()(AST::UnaryOp v) const; LIB::Set operator()(AST::BinOp v) const; LIB::Set operator()(AST::Call v) const; LIB::Set operator()(AST::Interval v) const; @@ -50,6 +51,7 @@ struct EvalSet : public boost::static_visitor { LIB::Set operator()(AST::LinearExp v) const; LIB::Set operator()(AST::LExpBinOp v) const; LIB::Set operator()(AST::LinearMap v) const; + LIB::Set operator()(AST::PWLMap v) const; private: mutable VarEnv env_; diff --git a/eval/visitors/program_visitor.cpp b/eval/visitors/program_visitor.cpp index 58794ae..b1d99a3 100755 --- a/eval/visitors/program_visitor.cpp +++ b/eval/visitors/program_visitor.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "eval/visitors/program_visitor.hpp" namespace SBG { diff --git a/eval/visitors/program_visitor.hpp b/eval/visitors/program_visitor.hpp index 51ef23a..1a020bf 100755 --- a/eval/visitors/program_visitor.hpp +++ b/eval/visitors/program_visitor.hpp @@ -27,8 +27,8 @@ #ifndef AST_VISITOR_PROGRAM #define AST_VISITOR_PROGRAM -#include -#include +#include "ast/sbg_program.hpp" +#include "eval/visitors/stm_visitor.hpp" namespace SBG { diff --git a/eval/visitors/stm_visitor.cpp b/eval/visitors/stm_visitor.cpp index 6800c44..ec23abd 100755 --- a/eval/visitors/stm_visitor.cpp +++ b/eval/visitors/stm_visitor.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "eval/visitors/stm_visitor.hpp" namespace SBG { diff --git a/eval/visitors/stm_visitor.hpp b/eval/visitors/stm_visitor.hpp index d37562d..0e64044 100755 --- a/eval/visitors/stm_visitor.hpp +++ b/eval/visitors/stm_visitor.hpp @@ -26,8 +26,8 @@ #ifndef AST_VISITOR_STATEMENT #define AST_VISITOR_STATEMENT -#include -#include +#include "ast/statement.hpp" +#include "eval/visitors/eval_expr.hpp" namespace SBG { diff --git a/parser/Makefile.include b/parser/Makefile.include index a689bc4..361de30 100755 --- a/parser/Makefile.include +++ b/parser/Makefile.include @@ -15,6 +15,7 @@ PARSER_SRC := \ $(AST_DIR)/sbg_program.cpp \ $(PARSER_DIR)/sbg_program.cpp \ $(PARSER_DIR)/skipper.cpp \ + $(UTIL_DIR)/debug.cpp \ $(UTIL_DIR)/defs.cpp # Objects diff --git a/parser/expr.cpp b/parser/expr.cpp index 8103361..a345f1f 100755 --- a/parser/expr.cpp +++ b/parser/expr.cpp @@ -17,12 +17,14 @@ ******************************************************************************/ -#include +#include "parser/expr.hpp" // Adapt structures ------------------------------------------------------------ BOOST_FUSION_ADAPT_STRUCT(SBG::Util::RATIONAL, (boost::rational, value_)) +BOOST_FUSION_ADAPT_STRUCT(SBG::AST::UnaryOp, (SBG::AST::UnOp, op_)(SBG::AST::Expr, expr_)) + BOOST_FUSION_ADAPT_STRUCT(SBG::AST::BinOp, (SBG::AST::Expr, left_)(SBG::AST::Op, op_)(SBG::AST::Expr, right_)) BOOST_FUSION_ADAPT_STRUCT(SBG::AST::Call, (SBG::AST::Name, name_)(SBG::AST::ExprList, args_)) @@ -41,10 +43,12 @@ BOOST_FUSION_ADAPT_STRUCT(SBG::AST::SetBinOp, (SBG::AST::Expr, left_)(SBG::AST:: BOOST_FUSION_ADAPT_STRUCT(SBG::AST::LinearExp, (SBG::AST::Expr, slope_)(SBG::AST::Expr, offset_)) -BOOST_FUSION_ADAPT_STRUCT(SBG::AST::LExpBinOp, (SBG::AST::Expr, left_)(SBG::AST::Op, op_)(SBG::AST::Expr, right_)) +BOOST_FUSION_ADAPT_STRUCT(SBG::AST::LExpBinOp, (SBG::AST::Expr, left_)(SBG::AST::ExpOp, op_)(SBG::AST::Expr, right_)) BOOST_FUSION_ADAPT_STRUCT(SBG::AST::LinearMap, (SBG::AST::Expr, dom_)(SBG::AST::Expr, lexp_)) +BOOST_FUSION_ADAPT_STRUCT(SBG::AST::PWLMap, (SBG::AST::ExprList, maps_)) + // Expression parser ----------------------------------------------------------- namespace SBG { @@ -69,6 +73,12 @@ struct expo_symbol_struct : qi::symbols { } } expo_symbol; +struct unary_symbol_struct : qi::symbols { + unary_symbol_struct() { + add("-", AST::UnOp::neg); + } +} unary_symbol; + struct inter_unary_struct : qi::symbols { inter_unary_struct(){ add("#", AST::ContainerUOp::card); @@ -93,9 +103,9 @@ struct set_bin_struct : qi::symbols { } } set_bin; -struct lexp_bin_struct : qi::symbols { +struct lexp_bin_struct : qi::symbols { lexp_bin_struct(){ - add("+", AST::Op::add)("-", AST::Op::sub); + add("==", AST::ExpOp::eq)("+", AST::ExpOp::add)("-", AST::ExpOp::sub); } } lexp_bin; @@ -114,7 +124,9 @@ ExprRule::ExprRule(Iterator &it) : COMA(","), TRUE("true"), FALSE("false"), - ARROW("->") + ARROW("->"), + OANGLE("<<"), + CANGLE(">>") { ident = qi::lexeme[(qi::char_('_') | qi::alpha) >> *(qi::alnum | qi::char_('_'))] | qi::lexeme[qi::char_('\'') >> *(qi::alnum | qi::char_('_')) > qi::char_('\'')]; @@ -138,7 +150,10 @@ ExprRule::ExprRule(Iterator &it) : term = factor[qi::_val = qi::_1] >> *(mult_symbol >> factor)[qi::_val = phx::construct(qi::_val, qi::_1, qi::_2)]; - arithmetic_expr = term[qi::_val = qi::_1] >> *(add_symbols > term)[qi::_val = phx::construct(qi::_val, qi::_1, qi::_2)]; + arithmetic_expr = (term[qi::_val = qi::_1] >> *(add_symbols > term)[qi::_val = phx::construct(qi::_val, qi::_1, qi::_2)]) + | (unary_symbol >> term)[qi::_val = phx::construct(qi::_1, qi::_2)]; + + // ------------ // interval = (OBRACKET >> arithmetic_expr >> COLON @@ -158,9 +173,11 @@ ExprRule::ExprRule(Iterator &it) : inter_list = interval[phx::push_back(qi::_val, qi::_1)] >> *(COMA >> interval)[phx::push_back(qi::_val, qi::_1)]; + // ------------ // + set = (OBRACE >> inter_list >> CBRACE)[qi::_val = phx::construct(qi::_1)] | (OBRACE >> CBRACE)[qi::_val = phx::construct()] - | ident[qi::_val = phx::construct(qi::_1)]; + | ident[qi::_val = qi::_1]; set_unary = (set_un >> set_expr)[qi::_val = phx::construct(qi::_1, qi::_2)]; @@ -172,10 +189,14 @@ ExprRule::ExprRule(Iterator &it) : | set_binary[qi::_val = qi::_1] | set[qi::_val = qi::_1]; + // ------------ // + numeric = rational[qi::_val = qi::_1] | qi::lexeme[qi::ulong_long][qi::_val = phx::construct(qi::_1)]; lexp = (numeric >> qi::char_('*') >> qi::char_('x') - >> qi::char_('+') >> arithmetic_expr)[qi::_val = phx::construct(qi::_1, qi::_5)]; + >> qi::char_('+') >> arithmetic_expr)[qi::_val = phx::construct(qi::_1, qi::_5)] + | (numeric >> qi::char_('*') >> qi::char_('x') + >> arithmetic_expr)[qi::_val = phx::construct(qi::_1, qi::_4)]; lexp_binary = OPAREN >> lexp[qi::_val = qi::_1] >> CPAREN >> *(lexp_bin > OPAREN >> lexp >> CPAREN)[qi::_val = phx::construct(qi::_val, qi::_1, qi::_2)]; @@ -183,11 +204,24 @@ ExprRule::ExprRule(Iterator &it) : lexp_expr = lexp[qi::_val = qi::_1] | lexp_binary[qi::_val = qi::_1]; - sbgmap = (interval >> ARROW >> lexp)[qi::_val = phx::construct(qi::_1, qi::_2)]; + // ------------ // + + sbgmap = (set_expr >> ARROW >> lexp)[qi::_val = phx::construct(qi::_1, qi::_2)]; map_expr = sbgmap; - expr = map_expr | lexp_expr | arithmetic_expr | interval_expr | set_expr; + map_list = sbgmap[phx::push_back(qi::_val, qi::_1)] >> *(COMA >> sbgmap)[phx::push_back(qi::_val, qi::_1)]; + + // ------------ // + + pwl = (OANGLE >> map_list >> CANGLE)[qi::_val = phx::construct(qi::_1)] + | (OANGLE >> CANGLE)[qi::_val = phx::construct()]; + + pwl_expr = pwl; + + // ------------ // + + expr = pwl_expr | map_expr | lexp_expr | arithmetic_expr | interval_expr | set_expr; expr_list = expr[phx::push_back(qi::_val, qi::_1)] >> *(COMA >> expr)[phx::push_back(qi::_val, qi::_1)]; diff --git a/parser/expr.hpp b/parser/expr.hpp index 12a576e..c66234e 100755 --- a/parser/expr.hpp +++ b/parser/expr.hpp @@ -28,15 +28,18 @@ #define BOOST_SPIRIT_DEBUG +#include #include -#include -#include +#include "ast/expr.hpp" +#include "parser/skipper.hpp" namespace SBG { namespace Parser { +namespace phx = boost::phoenix; + template struct ExprRule : qi::grammar, AST::ExprList()> { ExprRule(Iterator &it); @@ -47,7 +50,7 @@ struct ExprRule : qi::grammar, AST::ExprList()> { qi::rule boolean; // Operators tokens - qi::rule OPAREN, CPAREN, OBRACKET, CBRACKET, OBRACE, CBRACE, COLON, RAT, COMA, ARROW; + qi::rule OPAREN, CPAREN, OBRACKET, CBRACKET, OBRACE, CBRACE, COLON, RAT, COMA, ARROW, OANGLE, CANGLE; // Other rules qi::rule, Util::RATIONAL()> rational; @@ -76,6 +79,10 @@ struct ExprRule : qi::grammar, AST::ExprList()> { qi::rule, AST::Expr()> sbgmap; qi::rule, AST::Expr()> map_expr; + qi::rule, AST::ExprList()> map_list; + + qi::rule, AST::Expr()> pwl; + qi::rule, AST::Expr()> pwl_expr; qi::rule, AST::Expr()> expr; qi::rule, AST::ExprList()> expr_list; diff --git a/parser/main.cpp b/parser/main.cpp index a89faa2..f3950fb 100755 --- a/parser/main.cpp +++ b/parser/main.cpp @@ -19,7 +19,7 @@ #include -#include +#include "parser/sbg_program.hpp" void parseExprsFromFile(std::string str) { diff --git a/parser/sbg_program.cpp b/parser/sbg_program.cpp index e370b3d..20dd55d 100755 --- a/parser/sbg_program.cpp +++ b/parser/sbg_program.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "parser/sbg_program.hpp" // Adapt structures ------------------------------------------------------------ diff --git a/parser/sbg_program.hpp b/parser/sbg_program.hpp index b682c5d..c4cdd07 100755 --- a/parser/sbg_program.hpp +++ b/parser/sbg_program.hpp @@ -26,8 +26,8 @@ #ifndef PROGRAM_PARSER_HPP #define PROGRAM_PARSER_HPP -#include -#include +#include "ast/sbg_program.hpp" +#include "parser/statement.hpp" namespace SBG { diff --git a/parser/skipper.cpp b/parser/skipper.cpp index bf00fa9..9ad7f47 100755 --- a/parser/skipper.cpp +++ b/parser/skipper.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "parser/skipper.hpp" namespace SBG { diff --git a/parser/skipper.hpp b/parser/skipper.hpp index 25e3ebf..fd83df1 100755 --- a/parser/skipper.hpp +++ b/parser/skipper.hpp @@ -28,15 +28,12 @@ #define SKIPPER_HPP #include -#include -#include namespace SBG { namespace Parser { namespace asc = boost::spirit::ascii; -namespace phx = boost::phoenix; namespace qi = boost::spirit::qi; typedef std::string::const_iterator StrIt; diff --git a/parser/statement.cpp b/parser/statement.cpp index dd61b72..c4b0d54 100755 --- a/parser/statement.cpp +++ b/parser/statement.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "parser/statement.hpp" // Adapt structures ------------------------------------------------------------ diff --git a/parser/statement.hpp b/parser/statement.hpp index b389f3b..9f22400 100755 --- a/parser/statement.hpp +++ b/parser/statement.hpp @@ -26,8 +26,8 @@ #ifndef STATEMENT_PARSER_HPP #define STATEMENT_PARSER_HPP -#include -#include +#include "ast/statement.hpp" +#include "parser/expr.hpp" namespace SBG { diff --git a/sbg/Makefile.include b/sbg/Makefile.include index 52368f8..1bc708f 100755 --- a/sbg/Makefile.include +++ b/sbg/Makefile.include @@ -8,7 +8,8 @@ SBG_ROOT := sbg $(SBG_ROOT)/interval.cpp \ $(SBG_ROOT)/pw_inter.cpp \ $(SBG_ROOT)/lexp.cpp \ - $(SBG_ROOT)/map.cpp + $(SBG_ROOT)/map.cpp \ + $(SBG_ROOT)/pw_map.cpp # Objects SBG_OBJ=$(addprefix $(BUILD_DIR)/, $(SBG_SRC:.cpp=.o)) diff --git a/sbg/interval.cpp b/sbg/interval.cpp index 0907a54..32e9493 100755 --- a/sbg/interval.cpp +++ b/sbg/interval.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "sbg/interval.hpp" namespace SBG { @@ -124,6 +124,16 @@ MaybeInterval canonize(Interval i1, Interval i2) return {}; } +std::size_t hash_value(const Interval &i) +{ + std::size_t seed = 0; + boost::hash_combine(seed, i.begin()); + boost::hash_combine(seed, i.step()); + boost::hash_combine(seed, i.end()); + + return seed; +} + } // namespace LIB } // namespace SBG diff --git a/sbg/interval.hpp b/sbg/interval.hpp index e6a7fa1..d5cc8b0 100755 --- a/sbg/interval.hpp +++ b/sbg/interval.hpp @@ -31,12 +31,14 @@ #ifndef SBG_INTERVAL_HPP #define SBG_INTERVAL_HPP -#include #include #include #include -#include +#include +#include + +#include "util/defs.hpp" namespace SBG { @@ -77,6 +79,8 @@ Interval least(Interval i1, Interval i2); typedef std::optional MaybeInterval; MaybeInterval canonize(Interval i1, Interval i2); +std::size_t hash_value(const Interval &i); + typedef Interval SetPiece; } // namespace LIB diff --git a/sbg/lexp.cpp b/sbg/lexp.cpp index e9eccee..71a428b 100755 --- a/sbg/lexp.cpp +++ b/sbg/lexp.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "sbg/lexp.hpp" namespace SBG { @@ -35,6 +35,13 @@ LExp LExp::operator-(const LExp &r) { return LExp(slope() - r.slope(), offset() bool LExp::operator==(const LExp &other) const { return slope() == other.slope() && offset() == other.offset(); } +bool LExp::operator<(const LExp &other) const +{ + if (slope() < other.slope()) return true; + + return offset() < other.offset(); +} + std::ostream &operator<<(std::ostream &out, const LExp &le) { RAT zero, one(1), slo = le.slope(); @@ -53,7 +60,7 @@ std::ostream &operator<<(std::ostream &out, const LExp &le) if (slo == one) out << "x"; if (le.offset() != zero) { - if (le.offset() > 0) + if (le.offset() > 0 && le.slope() != 0) out << "+" << le.offset(); else @@ -93,6 +100,21 @@ LExp inverse(LExp le) return LExp(new_slope, new_offset); } +bool isId(LExp le) { return le.slope() == 1 && le.offset() == 0;} + +bool isConstant(LExp le) { return le.slope() == 0; } + +std::size_t hash_value(const LExp &le) +{ + std::size_t seed = 0; + boost::hash_combine(seed, le.slope().numerator()); + boost::hash_combine(seed, le.slope().denominator()); + boost::hash_combine(seed, le.offset().numerator()); + boost::hash_combine(seed, le.offset().denominator()); + + return seed; +} + } // namespace LIB } // namespace SBG diff --git a/sbg/lexp.hpp b/sbg/lexp.hpp index cccead2..8d4f1a9 100755 --- a/sbg/lexp.hpp +++ b/sbg/lexp.hpp @@ -29,7 +29,9 @@ #include -#include +#include + +#include "util/defs.hpp" namespace SBG { @@ -48,6 +50,7 @@ struct LExp { LExp operator-(const LExp &le); eq_class(LExp); + lt_class(LExp); }; std::ostream &operator<<(std::ostream &out, const LExp &le); @@ -63,10 +66,17 @@ std::ostream &operator<<(std::ostream &out, const LExp &le); LExp composition(LExp le1, LExp le2); LExp inverse(LExp le); + /** * @brief Extra operations. */ +bool isId(LExp le); +bool isConstant(LExp le); +std::size_t hash_value(const LExp &le); + +typedef LExp Exp; + } // namespace LIB } // namespace SBG diff --git a/sbg/map.cpp b/sbg/map.cpp index 483575e..1b94ecc 100755 --- a/sbg/map.cpp +++ b/sbg/map.cpp @@ -17,29 +17,35 @@ ******************************************************************************/ -#include +#include "sbg/map.hpp" namespace SBG { namespace LIB { SBGMap::SBGMap() : dom_(), exp_() {} -SBGMap::SBGMap(SetPiece dom, LExp lexp) : dom_(dom), exp_(lexp) { - Util::RATIONAL im_step = dom.step() * lexp.slope(), im_begin = minElem(dom) * lexp.slope() + lexp.offset(); - if (im_step.denominator() != 1 || im_begin.denominator() != 1) { - Util::ERROR("Ill-formed SBGMap"); +SBGMap::SBGMap(Set dom, Exp lexp) : dom_(dom), exp_(lexp) { + BOOST_FOREACH (SetPiece atom, dom.pieces()) { + Util::RATIONAL im_step = atom.step() * lexp.slope(), im_begin = minElem(atom) * lexp.slope() + lexp.offset(); + if (im_step.denominator() != 1 || im_begin.denominator() != 1) + Util::ERROR("Ill-formed SBGMap"); } } -member_imp(SBGMap, SetPiece, dom); -member_imp(SBGMap, LExp, exp); +member_imp(SBGMap, Set, dom); +member_imp(SBGMap, Exp, exp); bool SBGMap::operator==(const SBGMap &other) const { - return dom() == other.dom() && exp() == other.exp(); + if (!(exp() == other.exp())) return false; + + return dom() == other.dom(); } -bool SBGMap::operator<(const SBGMap &other) const { return dom() < other.dom(); } +bool SBGMap::operator!=(const SBGMap &other) const +{ + return !(*this == other); +} std::ostream &operator<<(std::ostream &out, const SBGMap &sbgmap) { @@ -50,32 +56,106 @@ std::ostream &operator<<(std::ostream &out, const SBGMap &sbgmap) // SBGMap functions ------------------------------------------------------------ -SetPiece image(SBGMap sbgmap) { return image(sbgmap.dom(), sbgmap);} +SBGMap restrict(Set subdom, SBGMap sbgmap) +{ + Set restricted_dom = intersection(sbgmap.dom(), subdom); + return SBGMap(restricted_dom, sbgmap.exp()); +} + +Set image(SBGMap sbgmap) { return image(sbgmap.dom(), sbgmap);} -SetPiece image(SetPiece subdom, SBGMap sbgmap) +Set image(Set subdom, SBGMap sbgmap) { - SetPiece capdom = intersection(sbgmap.dom(), subdom); - if (isEmpty(capdom)) return SetPiece(); + InterSet res; - Util::RATIONAL m = sbgmap.exp().slope(), h = sbgmap.exp().offset(); + Exp le = sbgmap.exp(); - Util::RATIONAL new_begin = m * minElem(capdom) + h; - Util::RATIONAL new_step = m * capdom.step(); - Util::RATIONAL new_end = m * maxElem(capdom) + h; + if (isId(le)) return subdom; - return SetPiece(new_begin.numerator(), new_step.numerator(), new_end.numerator()); + if (isConstant(le)) { + Util::NAT off = toNat(le.offset()); + return Set(SetPiece(off, 1, off)); + } + + Set capdom = intersection(sbgmap.dom(), subdom); + if (isEmpty(capdom)) return Set(); + + else { + Util::RATIONAL m = le.slope(), h = le.offset(); + + if (m == 0) { + SetPiece ith(toNat(h), 1, toNat(h)); + res.emplace_hint(res.cend(), ith); + } + + // Non-decreasing expression + else if (m > 0) { + BOOST_FOREACH (SetPiece atom, capdom.pieces()) { + Util::RATIONAL new_begin = m * minElem(atom) + h; + Util::RATIONAL new_step = m * atom.step(); + Util::RATIONAL new_end = m * maxElem(atom) + h; + + SetPiece ith(new_begin.numerator(), new_step.numerator(), new_end.numerator()); + res.emplace_hint(res.cend(), ith); + } + } + + // Decreasing expression + else { + BOOST_REVERSE_FOREACH (SetPiece atom, capdom.pieces()) { + Util::RATIONAL new_begin = m * minElem(atom) + h; + Util::RATIONAL new_step = m * atom.step(); + Util::RATIONAL new_end = m * maxElem(atom) + h; + + SetPiece ith(new_begin.numerator(), new_step.numerator(), new_end.numerator()); + res.emplace_hint(res.cend(), ith); + } + } + } + + return Set(res); } -SetPiece preImage(SBGMap sbgmap) { return sbgmap.dom(); } +Set preImage(SBGMap sbgmap) { return sbgmap.dom(); } -SetPiece preImage(SetPiece subcodom, SBGMap sbgmap) +Set preImage(Set subcodom, SBGMap sbgmap) { SBGMap inv(image(sbgmap), inverse(sbgmap.exp())); - SetPiece cap_subcodom = intersection(image(sbgmap), subcodom); + Set cap_subcodom = intersection(image(sbgmap), subcodom); return intersection(sbgmap.dom(), image(cap_subcodom, inv)); } +SBGMap composition(SBGMap sbgmap1, SBGMap sbgmap2) +{ + Set res_dom = intersection(image(sbgmap2), sbgmap1.dom()); + res_dom = preImage(res_dom, sbgmap2); + Exp res_exp = composition(sbgmap1.exp(), sbgmap2.exp()); + + return SBGMap(Set(res_dom), res_exp); +} + +// Extra functions ------------------------------------------------------------- + +MaybeMap canonize(SBGMap sbgmap1, SBGMap sbgmap2) +{ + if (sbgmap1.exp() == sbgmap2.exp()) { + Set new_dom = concatenation(sbgmap1.dom(), sbgmap2.dom()); + return SBGMap(new_dom, sbgmap1.exp()); + } + + return {}; +} + +std::size_t hash_value(const SBGMap &sbgmap) +{ + std::size_t seed = 0; + boost::hash_combine(seed, sbgmap.dom()); + boost::hash_combine(seed, sbgmap.exp()); + + return seed; +} + } // namespace LIB } // namespace SBG diff --git a/sbg/map.hpp b/sbg/map.hpp index b6f9ed6..219f5d9 100755 --- a/sbg/map.hpp +++ b/sbg/map.hpp @@ -27,35 +27,45 @@ #ifndef SBG_MAP_HPP #define SBG_MAP_HPP -#include - -#include -#include -#include +#include "sbg/lexp.hpp" +#include "sbg/pw_inter.hpp" +#include "util/debug.hpp" namespace SBG { namespace LIB { struct SBGMap { - member_class(SetPiece, dom); - member_class(LExp, exp); + member_class(Set, dom); + member_class(Exp, exp); SBGMap(); - SBGMap(SetPiece dom, LExp exp); + SBGMap(Set dom, Exp exp); eq_class(SBGMap); - lt_class(SBGMap); + neq_class(SBGMap); }; std::ostream &operator<<(std::ostream &out, const SBGMap &sbgmap); /** * @brief Traditional map operations. */ -SetPiece image(SBGMap sbgmap); -SetPiece image(SetPiece subdom, SBGMap sbgmap); -SetPiece preImage(SBGMap sbgmap); -SetPiece preImage(SetPiece subcodom, SBGMap sbgmap); + +SBGMap restrict(Set subdom, SBGMap sbgmap); +Set image(SBGMap sbgmap); +Set image(Set subdom, SBGMap sbgmap); +Set preImage(SBGMap sbgmap); +Set preImage(Set subcodom, SBGMap sbgmap); +SBGMap composition(SBGMap sbgmap1, SBGMap sbgmap2); + +/** + * @brief Extra operations. + */ + +typedef std::optional MaybeMap; +MaybeMap canonize(SBGMap sbgmap1, SBGMap sbgmap2); + +std::size_t hash_value(const SBGMap &sbgmap); } // namespace LIB diff --git a/sbg/pw_inter.cpp b/sbg/pw_inter.cpp index 5173991..c4deb56 100755 --- a/sbg/pw_inter.cpp +++ b/sbg/pw_inter.cpp @@ -16,8 +16,8 @@ along with SBG Library. If not, see . ******************************************************************************/ - -#include +#include +#include "sbg/pw_inter.hpp" namespace SBG { @@ -25,6 +25,8 @@ namespace LIB { // Type definitions ------------------------------------------------------------ +LTInter::LTInter() {} + bool LTInter::operator()(const SetPiece &x, const SetPiece &y) const { return x < y; } std::ostream &operator<<(std::ostream &out, const InterSet &ii) @@ -36,10 +38,12 @@ std::ostream &operator<<(std::ostream &out, const InterSet &ii) if (sz > 0) { auto it = aux.begin(); for (int i = 0; i < sz - 1; ++i) { - out << *it << ", "; + if (!isEmpty(*it)) + out << *it << ", "; ++it; } - out << *it; + if (!isEmpty(*it)) + out << *it; } out << "}"; @@ -50,18 +54,26 @@ std::ostream &operator<<(std::ostream &out, const InterSet &ii) PWInterval::PWInterval() : pieces_() {} PWInterval::PWInterval(SetPiece i) : pieces_() { pieces_ref().insert(i); } -PWInterval::PWInterval(InterSet ii) : pieces_(ii) {} +PWInterval::PWInterval(InterSet ii) : pieces_(canonize(ii)) {} member_imp(PWInterval, InterSet, pieces); bool PWInterval::operator==(const PWInterval &other) const { + InterSet aux1 = this->pieces(), aux2 = other.pieces(); + if (optConds(aux1) && optConds(aux2)) { + InterSet ii1 = canonize(aux1), ii2 = canonize(aux2); + return ii1 == ii2; + } + PWInterval pwi1 = *this, pwi2 = other; if (pwi1.pieces_ref() == pwi2.pieces_ref()) return true; return isEmpty(difference(*this, other)) && isEmpty(difference(other, *this)); } +bool PWInterval::operator<(const PWInterval &other) const { return minElem(*this) < minElem(other); } + std::ostream &operator<<(std::ostream &out, const PWInterval &pwi) { out << pwi.pieces(); @@ -133,7 +145,6 @@ PWInterval intersection(PWInterval pwi1, PWInterval pwi2) return PWInterval(cap); } -// TODO: choose better lt/gt pieces PWInterval cup(PWInterval pwi1, PWInterval pwi2) { InterSet un; @@ -186,8 +197,8 @@ PWInterval cup(PWInterval pwi1, PWInterval pwi2) } PWInterval diff = difference(gt_pieces, lt_pieces); - if (isCompact(lt_pieces) && isCompact(gt_pieces)) - un = traverse(lt_pieces, diff, &least); + if (optConds(lt_pieces.pieces()) && optConds(gt_pieces.pieces())) + return concatenation(lt_pieces, diff); else { BOOST_FOREACH (SetPiece i, lt_pieces.pieces_ref()) @@ -255,22 +266,60 @@ PWInterval difference(PWInterval pwi1, PWInterval pwi2) { return intersection(pw // Extra operations ------------------------------------------------------------ -bool isCompact(PWInterval pwi) +bool isCompact(InterSet ii) { - BOOST_FOREACH (SetPiece i, pwi.pieces_ref()) + BOOST_FOREACH (SetPiece i, ii) if (i.step() != 1) return false; return true; } +bool optConds(InterSet ii) { return isCompact(ii); } + +InterSet canonize(InterSet ii) +{ + InterSet res; + + unsigned int sz = ii.size(); + if (sz == 1) res = ii; + + if (optConds(ii) && sz > 1) { + InterSetIt it = ii.begin(), next_it = it; + ++next_it; + SetPiece ith = *it; + for (unsigned int j = 0; j < sz - 1; ++j) { + MaybeInterval i = canonize(ith, *next_it); + if (i) ith = *i; + + else { + if (!isEmpty(ith)) res.emplace_hint(res.cend(), ith); + + if (j < (sz-2)) ith = *next_it; + + else ith = *next_it; + } + + ++next_it; + ++it; + } + if (!isEmpty(ith)) res.emplace_hint(res.cend(), ith); + } + + else res = ii; + + return res; +} + +PWInterval concatenation(PWInterval pwi1, PWInterval pwi2) { return PWInterval(traverse(pwi1.pieces(), pwi2.pieces(), &least)); } + InterSet boundedTraverse(PWInterval pwi1, PWInterval pwi2, SetPiece (*func)(SetPiece, SetPiece)) { InterSet result; if (isEmpty(pwi1) || isEmpty(pwi2)) return result; - if (isCompact(pwi1) && isCompact(pwi2)) { + if (optConds(pwi1.pieces()) && optConds(pwi2.pieces())) { InterSetIt it1 = pwi1.pieces_ref().begin(), it2 = pwi2.pieces_ref().begin(); InterSetIt end1 = pwi1.pieces_ref().end(), end2 = pwi2.pieces_ref().end(); @@ -280,8 +329,7 @@ InterSet boundedTraverse(PWInterval pwi1, PWInterval pwi2, SetPiece (*func)(SetP i2 = *it2; SetPiece funci = func(i1, i2); - if (!isEmpty(funci)) - result.emplace_hint(result.cend(), funci); + if (!isEmpty(funci)) result.emplace_hint(result.cend(), funci); if (maxElem(i1) < maxElem(i2)) ++it1; @@ -305,40 +353,56 @@ InterSet traverse(PWInterval pwi1, PWInterval pwi2, SetPiece (*func)(SetPiece, S { InterSet result; - if (isEmpty(pwi1) || isEmpty(pwi2)) return result; + if (isEmpty(pwi1)) return pwi2.pieces(); + + if (isEmpty(pwi2)) return pwi1.pieces(); + + if (optConds(pwi1.pieces()) && optConds(pwi2.pieces())) { + InterSetIt it1 = pwi1.pieces_ref().begin(), it2 = pwi2.pieces_ref().begin(); + InterSetIt end1 = pwi1.pieces_ref().end(), end2 = pwi2.pieces_ref().end(); - InterSetIt it1 = pwi1.pieces_ref().begin(), it2 = pwi2.pieces_ref().begin(); - InterSetIt end1 = pwi1.pieces_ref().end(), end2 = pwi2.pieces_ref().end(); + SetPiece i1, i2; + for (; it1 != end1 && it2 != end2;) { + i1 = *it1; + i2 = *it2; - SetPiece i1, i2; - for (; it1 != end1 && it2 != end2;) { - i1 = *it1; - i2 = *it2; + SetPiece funci = func(i1, i2); + if (!isEmpty(funci)) result.emplace_hint(result.cend(), funci); - SetPiece funci = func(i1, i2); - if (!isEmpty(funci)) - result.emplace_hint(result.cend(), funci); + if (maxElem(i1) < maxElem(i2)) ++it1; - if (maxElem(i1) < maxElem(i2)) - ++it1; + else ++it2; + } - else - ++it2; - } + for (; it1 != end1; ++it1) { + i1 = *it1; + result.emplace_hint(result.cend(), i1); + } - for (; it1 != end1; ++it1) { - i1 = *it1; - result.emplace_hint(result.cend(), i1); + for (; it2 != end2; ++it2) { + i2 = *it2; + result.emplace_hint(result.cend(), i2); + } } - for (; it2 != end2; ++it2) { - i2 = *it2; - result.emplace_hint(result.cend(), i2); + else { + BOOST_FOREACH (SetPiece i1, pwi1.pieces_ref()) + BOOST_FOREACH (SetPiece i2, pwi2.pieces_ref()) { + SetPiece funci = func(i1, i2); + if (!isEmpty(funci)) + result.emplace(funci); + } } return result; } +std::size_t hash_value(const PWInterval &pwi) +{ + PWInterval aux_pwi = pwi; + return boost::hash_range(aux_pwi.pieces_ref().begin(), aux_pwi.pieces_ref().end()); +} + } // namespace LIB } // namespace SBG diff --git a/sbg/pw_inter.hpp b/sbg/pw_inter.hpp index e5bf4ab..95fb142 100755 --- a/sbg/pw_inter.hpp +++ b/sbg/pw_inter.hpp @@ -28,11 +28,9 @@ #ifndef SBG_PW_INTERVAL_HPP #define SBG_PW_INTERVAL_HPP -#include - #include -#include +#include "sbg/interval.hpp" namespace SBG { @@ -49,10 +47,9 @@ namespace LIB { * SetPieces, is not used). */ struct LTInter { + LTInter(); + bool operator()(const SetPiece &x, const SetPiece &y) const; - typedef SetPiece first_argument_type; - typedef SetPiece second_argument_type; - typedef bool result_type; }; typedef boost::container::flat_set> InterSet; @@ -70,6 +67,7 @@ struct PWInterval { PWInterval(InterSet pieces); eq_class(PWInterval); + lt_class(PWInterval); }; std::ostream &operator<<(std::ostream &out, const PWInterval &i); @@ -82,7 +80,7 @@ bool isEmpty(PWInterval i); bool isMember(NAT x, PWInterval i); Util::NAT minElem(PWInterval pwi); Util::NAT maxElem(PWInterval pwi); -PWInterval intersection(PWInterval i1, PWInterval i2); +PWInterval intersection(PWInterval pwi1, PWInterval pwi2); PWInterval cup(PWInterval i1, PWInterval i2); PWInterval complement(Interval i); PWInterval complement(PWInterval i); @@ -97,8 +95,27 @@ PWInterval difference(PWInterval i1, PWInterval i2); * @brief This function determines if a pwi is compact (composed only by compact * intervals). */ +bool isCompact(InterSet ii); -bool isCompact(PWInterval pwi); +/** @function optCond + * + * @brief Check if the InterSet satisfies the conditions to use optimizations. + */ +bool optConds(InterSet ii); + +/* @function canonize + * + * @brief Tries to convert the argument to canonical form. Currently works only + * with compact InterSet. + */ +InterSet canonize(InterSet ii); + +/** @function concatenation + * + * @brief Function useful to unite two pwis in the case these are known to be + * disjoint. + */ +PWInterval concatenation(PWInterval pwi1, PWInterval pwi2); /** @function boundedTraverse * @@ -109,11 +126,13 @@ InterSet boundedTraverse(PWInterval pwi1, PWInterval pwi2, SetPiece (*func)(SetP /** @function traverse * - * @brief Traverse pwis in order reaching both ends, obtaining an orderedresult. + * @brief Traverse pwis in order reaching both ends, obtaining an ordered result. * !!! Both pwis should be compact (not checked in this function). */ InterSet traverse(PWInterval pwi1, PWInterval pwi2, SetPiece (*func)(SetPiece, SetPiece)); +std::size_t hash_value(const PWInterval &pwi); + typedef PWInterval Set; } // namespace LIB diff --git a/sbg/pw_map.cpp b/sbg/pw_map.cpp index 203cc31..cd4d14c 100755 --- a/sbg/pw_map.cpp +++ b/sbg/pw_map.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "sbg/pw_map.hpp" namespace SBG { @@ -25,7 +25,14 @@ namespace LIB { // Type definitions ------------------------------------------------------------ -bool LTMap::operator()(const SBGMap &x, const SBGMap &y) const { return LTInter(x.dom(), y.dom()); } +LTMap::LTMap() {} + +bool LTMap::operator()(const SBGMap &x, const SBGMap &y) const +{ + if (x.exp() < y.exp()) return true; + + return x.dom() < y.dom(); +} std::ostream &operator<<(std::ostream &out, const MapSet &ms) { @@ -36,10 +43,12 @@ std::ostream &operator<<(std::ostream &out, const MapSet &ms) if (sz > 0) { auto it = aux.begin(); for (int i = 0; i < sz - 1; ++i) { - out << *it << ", "; + if (!isEmpty(it->dom())) + out << *it << ", "; ++it; } - out << *it; + if (!isEmpty(it->dom())) + out << *it; } out << ">>"; @@ -49,18 +58,45 @@ std::ostream &operator<<(std::ostream &out, const MapSet &ms) // PWMap ----------------------------------------------------------------------- PWMap::PWMap() : maps_() {} -PWMap::PWMap(SBGMap sm) : maps_() { maps_ref().insert(sm); } -PWMap::PWMap(MapSet maps) : maps_(maps) {} +PWMap::PWMap(SBGMap sm) : maps_() { maps_ref().emplace(sm); } +PWMap::PWMap(MapSet maps) : maps_(canonize(maps)) {} member_imp(PWMap, MapSet, maps); -// TODO bool PWMap::operator==(const PWMap &other) const { + if (!(dom(*this) == dom(other))) return false; + + if (maps() == other.maps()) return true; + + BOOST_FOREACH (SBGMap sbgmap1, maps()) { + BOOST_FOREACH (SBGMap sbgmap2, other.maps()) { + Set cap_dom = intersection(sbgmap1.dom(), sbgmap2.dom()); + + // Here we check by image because the same image can be obtained through + // two different lexps. + // Example: [1:1:1] -> 10 and [1:1:1] -> x+9 + if (cardinal(cap_dom) == 1) { + SBGMap map1(cap_dom, sbgmap1.exp()), map2(cap_dom, sbgmap2.exp()); + if (!(image(map1) == image(map2))) return false; + } + + // When there is more than one element we can't check equality on the + // image because there are at least two linear maps with the same + // domain and image. + // Example: [1:1:10] -> x and [1:1:10] -> -x+10 + else { + if (!(sbgmap1.exp() == sbgmap2.exp())) return false; + } + } + } + return true; } -std::ostream &operator(std::ostream &out, const PWMap &pw) +bool PWMap::operator!=(const PWMap &other) const { return !(*this == other); } + +std::ostream &operator<<(std::ostream &out, const PWMap &pw) { out << pw.maps(); @@ -69,6 +105,319 @@ std::ostream &operator(std::ostream &out, const PWMap &pw) // PWMap functions ------------------------------------------------------------- +Set dom(PWMap pw) +{ + Set res; + + BOOST_FOREACH (SBGMap sbgmap, pw.maps()) + res = concatenation(res, sbgmap.dom()); + + return res; +} + +PWMap restrict(Set subdom, PWMap pw) +{ + MapSet res; + + BOOST_FOREACH (SBGMap sbgmap, pw.maps()) + res.emplace(restrict(subdom, sbgmap)); + + return PWMap(res); +} + +Set image(PWMap pw) +{ + Set res; + + BOOST_FOREACH (SBGMap sbgmap, pw.maps()) { + Set ith = image(sbgmap); + res = cup(res, ith); + } + + return res; +} + +Set image(Set subdom, PWMap pw) +{ + PWMap restricted = restrict(subdom, pw); + return image(restricted); +} + +Set preImage(PWMap pw) { return dom(pw); } + +Set preImage(Set subcodom, PWMap pw) +{ + Set res; + + BOOST_FOREACH (SBGMap sbgmap, pw.maps()) { + Set ith = preImage(subcodom, sbgmap); + res = cup(res, ith); + } + + return res; +} + +PWMap composition(PWMap pwi1, PWMap pwi2) +{ + MapSet res; + + Set im = image(pwi2), new_dom = preImage(im, pwi2); + PWMap map2 = restrict(new_dom, pwi2); + + BOOST_FOREACH (SBGMap sbgmap1, pwi1.maps()) { + BOOST_FOREACH (SBGMap sbgmap2, map2.maps()) { + SBGMap ith = composition(sbgmap1, sbgmap2); + if (!isEmpty(ith.dom())) + res.emplace(ith); + } + } + + return PWMap(res); +} + +PWMap mapInf(PWMap pw) +{ + PWMap res = pw; + + if (!isEmpty(dom(pw))) { + PWMap og_res = res, old_res; + + res = reduce(res); + do { + old_res = res; + std::cout << res << "\n"; + res = composition(og_res, res); + std::cout << res << "\n"; + + res = reduce(res); + std::cout << res << "\n\n"; + } while (old_res != res); + } + + return res; +} + +// Extra operations ------------------------------------------------------------ + +bool optConds(MapSet mm) { return true; } + +MapSet canonize(MapSet mm) +{ + MapSet res; + + unsigned int sz = mm.size(); + if (sz == 1) res = mm; + + if (optConds(mm) && sz > 1) { + MapSetIt it = mm.begin(), next_it = it; + ++next_it; + SBGMap ith = *it; + for (unsigned int j = 0; j < sz - 1; ++j) { + MaybeMap m = canonize(ith, *next_it); + if (m) ith = *m; + + else { + if (!isEmpty(ith.dom())) res.emplace_hint(res.cend(), ith); + + if (j < (sz-2)) ith = *next_it; + + else ith = *next_it; + } + + ++next_it; + ++it; + } + if (!isEmpty(ith.dom())) res.emplace_hint(res.cend(), ith); + } + + else res = mm; + + return res; +} + +// !!! pw1 and pw2 should be domain-disjoint +PWMap concat(PWMap pw1, PWMap pw2) +{ + MapSetIt beg = pw1.maps_ref().begin(), end = pw1.maps_ref().end(); + MapSet res(beg, end); + + BOOST_FOREACH (SBGMap sbgmap2, pw2.maps()) res.emplace(sbgmap2); + + return PWMap(res); +} + +PWMap minMap(SetPiece dom_piece, Exp e1, Exp e2) +{ + MapSet res; + + Util::RATIONAL m1 = e1.slope(), h1 = e1.offset(), m2 = e2.slope(), h2 = e2.offset(); + + // Parallel lines + if (m1 == m2) { + if (h1 < h2) res.emplace(SBGMap(Set(dom_piece), e1)); + + else res.emplace(SBGMap(Set(dom_piece), e2)); + } + + // Non parallel lines + Util::RATIONAL cap_point = (e2.offset() - e1.offset()) / (e1.slope() - e2.slope()); + Interval before, after; + if (cap_point < 0) after = dom_piece; + + else { + Util::NAT beg = dom_piece.begin(), st = dom_piece.step(), end = dom_piece.end(); + double double_cap_point = cap_point.numerator() / cap_point.denominator(); + before = Interval(beg, st, (Util::NAT) floor(double_cap_point)); + before = intersection(before, dom_piece); + after = Interval((Util::NAT) ceil(double_cap_point), st, end); + after = intersection(after, dom_piece); + } + + // Before intersection + if (!isEmpty(before)) { + if (m1 > m2) res.emplace(SBGMap(Set(before), e1)); + + else res.emplace(SBGMap(Set(before), e2)); + } + + // After intersection + if (!isEmpty(after)) { + if (m1 > m2) res.emplace(SBGMap(Set(before), e2)); + + else res.emplace(SBGMap(Set(before), e1)); + } + + return PWMap(res); +} + +//TODO +PWMap minMap(Set dom, Exp e1, Exp e2) +{ + PWMap res; + + return res; +} + +//TODO +PWMap minMap() +{ + PWMap res; + + return res; +} + +PWMap reduce(SetPiece dom_piece, Exp e) +{ + PWMap res; + + Set d(dom_piece); + + Util::RATIONAL zero(0, 1), one(1, 1); + if (e.slope() == one && e.offset() != zero) { + Util::INT h = toInt(e.offset()); + + Util::NAT st = dom_piece.step(); + if (h == (Util::INT) st) { + Util::NAT hi = dom_piece.end(); + if (st < Util::Inf - hi) res = PWMap(SBGMap(d, Exp(0, hi + st))); + } + + if (h == (Util::INT) -st) { + Util::NAT lo = dom_piece.begin(); + if (lo >= st) res = PWMap(SBGMap(d, Exp(0, lo - st))); + } + + if (h % (Util::INT) st == 0) { + // Is convenient the partition of the piece? + if ((Util::INT) cardinal(dom_piece) > h*h) { + Util::INT absh = std::abs(h); + MapSet sm; + + for (int k = 1; k <= absh; ++k) { + Util::NAT new_begin = dom_piece.begin() + k - 1; + SetPiece kth_piece(new_begin, (Util::NAT) absh, dom_piece.end()); + + Exp kth_exp(0, 0); + if (h > 0) kth_exp.set_offset(kth_piece.end() + h); + + else kth_exp.set_offset(kth_piece.begin() + h); + + SBGMap kth_map(Set(kth_piece), kth_exp); + sm.emplace_hint(sm.cend(), kth_map); + } + + if (!sm.empty()) return PWMap(sm); + } + } + } + + return PWMap(SBGMap(Set(d), e)); +} + +PWMap reduce(SBGMap sbgmap) +{ + PWMap res; + + BOOST_FOREACH (SetPiece dom_piece, sbgmap.dom().pieces()) { + PWMap ith = reduce(dom_piece, sbgmap.exp()); + res = concat(ith, res); + } + + return res; +} + +PWMap reduce(PWMap pw) +{ + PWMap res; + + BOOST_FOREACH (SBGMap sbgmap, pw.maps()) { + PWMap ith = reduce(sbgmap); + res = concat(ith, res); + } + + return res; +} + +/* +SBGMap minAdjMap(SBGMap sbgmap1, PWMap pw2) +{ + SBGMap res; + + Set d1 = sbgmap1.dom(), d2 = sbgmap2.dom(); + Exp e1 = sbgmap1.exp(), e2 = sbgmap2.exp(); + if (d1 == d2) { + Exp e; + if (isConstant(sbgmap1.exp())) e = Exp(0, minElem(image(sbgmap2))); + + else e = composition(e2, inverse(e1)); + + res = SBGMap(d1, e); + } + + else Util::ERROR("map/minAdjMap: maps should have the same domain"); + + return res; +} + +PWMap minAdjMap(PWMap pw1, PWMap pw2) +{ + MapSet res; + + Set dom1 = dom(pw1), dom2 = dom(pw2); + if (dom1 == dom2) { + BOOST_FOREACH (SBGMap sbgmap1, pw1.maps()) { + BOOST_FOREACH (SBGMap sbgmap2, pw2.maps()) { + SBGMap ith_min_adj = minAdjMap(sbgmap1, sbgmap2); + } + } + } + + else Util::ERROR("pw_map/minAdjMap: maps should have the same domain"); + + return PWMap(res); +} +*/ + } // namespace LIB } // namespace SBG diff --git a/sbg/pw_map.hpp b/sbg/pw_map.hpp index ca2885c..5076ac1 100755 --- a/sbg/pw_map.hpp +++ b/sbg/pw_map.hpp @@ -24,32 +24,27 @@ #ifndef SBG_PWMAP_HPP #define SBG_PWMAP_HPP -#include +#include + +#include "sbg/map.hpp" namespace SBG { namespace LIB { /** - * @brief Ordered collection of maps. + * @brief Unordered collection of maps. */ -/* @struct LTMap - * - * @brief This function is defined to be used by the MapSet definition. The - * two inputs are disjoint (that's why the operator<, that compares any sort of - * Maps, is not used). - */ struct LTMap { + LTMap(); + bool operator()(const SBGMap &x, const SBGMap &y) const; - typedef SBGMap first_argument_type; - typedef SBGMap second_argument_type; - typedef bool result_type; }; -typedef boost::container::set, void> MapSet; -typedef boost::container::set::iterator MapSetIt; -std::ostream &operator<<(std::ostream &out, const MapSet &ii); +typedef boost::container::flat_set> MapSet; +typedef MapSet::iterator MapSetIt; +std::ostream &operator<<(std::ostream &out, const MapSet &ms); struct PWMap { member_class(MapSet, maps); @@ -58,13 +53,63 @@ struct PWMap { PWMap(SBGMap m); PWMap(MapSet maps); + // Two maps are equal iff they satisfy the extensional principle eq_class(PWMap); + neq_class(PWMap); }; std::ostream &operator<<(std::ostream &out, const PWMap &pw); /** * @brief Traditional map operations. */ +Set dom(PWMap pw); +PWMap restrict(Set subdom, PWMap pw); +Set image(PWMap pw); +Set image(Set subdom, PWMap pw); +Set preImage(PWMap pw); +Set preImage(Set subcodom, PWMap pw); +PWMap mapInf(PWMap pw); + +/** @function composition + * + * @brief Apply first pw2, then pw1 (i.e. pw1(pw2(x)) is calculated). + */ +PWMap composition(PWMap pw1, PWMap pw2); + +/** + * @brief Extra operations. + */ + +bool isCompact(MapSet mm); +bool optConds(MapSet mm); +MapSet canonize(MapSet mm); + +/** @function concat + * + * @brief Concatenation of two pwis. + * !!! Result is correct iff pw1 and pw2 are domain-disjoint. + */ +PWMap concat(PWMap pw1, PWMap pw2); + +PWMap minMap(SetPiece dom_piece, Exp e1, Exp e2); +PWMap minMap(Set dom, Exp e1, Exp e2); +PWMap minMap(PWMap pw1, PWMap pw2); + +/** @function reduce + * + * @brief The reduce function calculates (if possible) the resulting map of + * composing the argument with itself up to convergence. + * + * Currently, the only expressions that can be efficiently reduced are: + * - x+h + * - x-h + * - h + */ +PWMap reduce(SetPiece dom_piece, Exp e); +PWMap reduce(SBGMap sbgmap); +PWMap reduce(PWMap pw); + +PWMap minAdjMap(PWMap pw1, PWMap pw2); } // namespace LIB diff --git a/test/eval/gt_data/arithmetic/arithmetic.cpp b/test/eval/gt_data/arithmetic/arithmetic.cpp index 7294fd8..697e772 100755 --- a/test/eval/gt_data/arithmetic/arithmetic.cpp +++ b/test/eval/gt_data/arithmetic/arithmetic.cpp @@ -19,9 +19,9 @@ #include -#include -#include -#include +#include "eval/visitors/program_visitor.hpp" +#include "parser/sbg_program.hpp" +#include "util/logger.hpp" void parseProgramFromFile(std::string str) { diff --git a/test/eval/gt_data/interval/SBG.log b/test/eval/gt_data/interval/SBG.log index 8f11034..4aec528 100755 --- a/test/eval/gt_data/interval/SBG.log +++ b/test/eval/gt_data/interval/SBG.log @@ -21,10 +21,10 @@ isEmpty([100:1:200]) isEmpty([100:1:5]) --> 1 -isMember(201,[201:2:399]) +isMember(201, [201:2:399]) --> 1 -isMember(201,[200:4:400]) +isMember(201, [200:4:400]) --> 0 [1:1:0]/\[100:1:500] diff --git a/test/eval/gt_data/interval/interval.cpp b/test/eval/gt_data/interval/interval.cpp index 109bdc8..59db86d 100755 --- a/test/eval/gt_data/interval/interval.cpp +++ b/test/eval/gt_data/interval/interval.cpp @@ -19,9 +19,9 @@ #include -#include -#include -#include +#include "eval/visitors/program_visitor.hpp" +#include "parser/sbg_program.hpp" +#include "util/logger.hpp" void parseProgramFromFile(std::string str) { diff --git a/test/eval/gt_data/lexp/SBG.log b/test/eval/gt_data/lexp/SBG.log index 4d38308..f0b4211 100644 --- a/test/eval/gt_data/lexp/SBG.log +++ b/test/eval/gt_data/lexp/SBG.log @@ -30,10 +30,10 @@ Visit result = inv((3)x+2) --> x/3-2/3 -compose((1)x+0,(1)x+0) +compose((1)x+0, (1)x+0) --> x -compose((2)x+3,(1)x+5) +compose((2)x+3, (1)x+5) --> 2x+13 ------------------------- diff --git a/test/eval/gt_data/lexp/lexp.cpp b/test/eval/gt_data/lexp/lexp.cpp index d100086..cee1a4e 100755 --- a/test/eval/gt_data/lexp/lexp.cpp +++ b/test/eval/gt_data/lexp/lexp.cpp @@ -19,9 +19,9 @@ #include -#include -#include -#include +#include "eval/visitors/program_visitor.hpp" +#include "parser/sbg_program.hpp" +#include "util/logger.hpp" void parseProgramFromFile(std::string str) { diff --git a/test/eval/gt_data/map/SBG.log b/test/eval/gt_data/map/SBG.log index e2fe27c..495e045 100644 --- a/test/eval/gt_data/map/SBG.log +++ b/test/eval/gt_data/map/SBG.log @@ -6,35 +6,35 @@ Parsing succeeded Visit result = -[1:1:10] ↦ (1)x+0 - --> [1:10] ↦ x +{[1:1:10]} ↦ (1)x+0 + --> {[1:10]} ↦ x -[1:2:10] ↦ (1/2)x+1/2 - --> [1:2:9] ↦ x/2+1/2 +{[1:2:10]} ↦ (1/2)x+1/2 + --> {[1:2:9]} ↦ x/2+1/2 -image([1:1:10] ↦ (1)x+0) - --> [1:10] +image({[1:1:10]} ↦ (1)x+0) + --> {[1:10]} -image([1:2:50] ↦ (2)x+1) - --> [3:4:99] +image({[1:2:50]} ↦ (2)x+1) + --> {[3:4:99]} -image([1:1:0] ↦ (1)x+0) - --> [1:0] +image({[1:1:0]} ↦ (1)x+0) + --> {} -image([1:3:50],[2:2:100] ↦ (2)x+1) - --> [9:12:93] +image({[1:3:50], [2:3:100]} ↦ (2)x+1) + --> {[3:6:99], [5:6:197]} -preImage([1:1:10] ↦ (1)x+0) - --> [1:10] +preImage({[1:1:10]} ↦ (1)x+0) + --> {[1:10]} -preImage([1:2:50] ↦ (2)x+1) - --> [1:2:49] +preImage({[1:2:50]} ↦ (2)x+1) + --> {[1:2:49]} -preImage([1:1:0] ↦ (1)x+0) - --> [1:0] +preImage({[1:1:0]} ↦ (1)x+0) + --> {} -preImage([20:5:100],[2:2:100] ↦ (2)x+1) - --> [12:10:42] +preImage({[20:5:100], [200:2:300]} ↦ (2)x+1) + --> {[20:5:100], [200:2:300]} ------------------------- Bye... :-) diff --git a/test/eval/gt_data/map/map.cpp b/test/eval/gt_data/map/map.cpp index f22be80..727a038 100755 --- a/test/eval/gt_data/map/map.cpp +++ b/test/eval/gt_data/map/map.cpp @@ -19,9 +19,9 @@ #include -#include -#include -#include +#include "eval/visitors/program_visitor.hpp" +#include "parser/sbg_program.hpp" +#include "util/logger.hpp" void parseProgramFromFile(std::string str) { diff --git a/test/eval/gt_data/set/SBG.log b/test/eval/gt_data/set/SBG.log index 0a26c51..0da1f48 100644 --- a/test/eval/gt_data/set/SBG.log +++ b/test/eval/gt_data/set/SBG.log @@ -15,10 +15,10 @@ isEmpty({[1:1:100]}) isEmpty({}) --> 1 -isMember(1,{[50:3:100], [500:10:1000], [1:1:25]}) +isMember(1, {[50:3:100], [500:10:1000], [1:1:25]}) --> 1 -isMember(51,{[50:3:100], [500:10:1000], [1:1:25]}) +isMember(51, {[50:3:100], [500:10:1000], [1:1:25]}) --> 0 minElem({}) @@ -55,10 +55,10 @@ maxElem({[500:3:1000], [1:1:100]}) --> {[1:100], [200:400]} {[1:3:100], [2:3:100]}/\{[0:1:2]} - --> {[1:1], [2:2]} + --> {[1:2]} {[1:10:100], [2:10:100], [3:10:100], [4:10:100], [5:10:100], [6:10:100], [7:10:100], [8:10:100]}/\{[3:1:5], [7:1:8]} - --> {[3:3], [4:4], [5:5], [7:7], [8:8]} + --> {[3:5], [7:8]} {[1:3:100], [2:3:100]}/\{[0:1:2], [4:6:94], [5:6:95], [6:6:96], [7:6:97], [8:6:98], [100:1:10000]} --> {[1:1], [2:2], [4:6:94], [5:6:95], [7:6:97], [8:6:98], [100:100]} @@ -103,7 +103,7 @@ maxElem({[500:3:1000], [1:1:100]}) --> {[1:100], [50:2:150], [101:2:299], [300:500]} {[1:1:100], [150:1:250], [450:1:600]}\/{[200:1:300], [425:1:430], [550:1:1000]} - --> {[1:100], [150:199], [200:300], [425:430], [450:549], [550:1000]} + --> {[1:100], [150:300], [425:430], [450:1000]} {}=={} --> 1 diff --git a/test/eval/gt_data/set/set.cpp b/test/eval/gt_data/set/set.cpp index 895099b..f8d6f2d 100755 --- a/test/eval/gt_data/set/set.cpp +++ b/test/eval/gt_data/set/set.cpp @@ -19,9 +19,9 @@ #include -#include -#include -#include +#include "eval/visitors/program_visitor.hpp" +#include "parser/sbg_program.hpp" +#include "util/logger.hpp" void parseProgramFromFile(std::string str) { diff --git a/test/map.test b/test/map.test index 6b2e8ad..0be3e2e 100644 --- a/test/map.test +++ b/test/map.test @@ -2,15 +2,15 @@ // !!! If this file is modified the corresponding SBG.log file // in all the gt_data directories should be modified. -[1:1:10] -> 1*x+0 -[1:2:10] -> r(1, 2)*x+r(1, 2) +{[1:1:10]} -> 1*x+0 +{[1:2:10]} -> r(1, 2)*x+r(1, 2) -image([1:1:10] -> 1*x+0) -image([1:2:50] -> 2*x+1) -image([1:1:0] -> 1*x+0) -image([1:3:50], [2:2:100] -> 2*x+1) +image({[1:1:10]} -> 1*x+0) +image({[1:2:50]} -> 2*x+1) +image({[1:1:0]} -> 1*x+0) +image({[1:3:50], [2:3:100]} -> 2*x+1) -preImage([1:1:10] -> 1*x+0) -preImage([1:2:50] -> 2*x+1) -preImage([1:1:0] -> 1*x+0) -preImage([20:5:100], [2:2:100] -> 2*x+1) +preImage({[1:1:10]} -> 1*x+0) +preImage({[1:2:50]} -> 2*x+1) +preImage({[1:1:0]} -> 1*x+0) +preImage({[20:5:100], [200:2:300]} -> 2*x+1) diff --git a/test/parser/gt_data/arithmetic/arithmetic.cpp b/test/parser/gt_data/arithmetic/arithmetic.cpp index 2c771bb..866faa8 100755 --- a/test/parser/gt_data/arithmetic/arithmetic.cpp +++ b/test/parser/gt_data/arithmetic/arithmetic.cpp @@ -19,8 +19,8 @@ #include -#include -#include +#include "parser/expr.hpp" +#include "util/logger.hpp" void parseExprsFromFile(std::string str) { diff --git a/test/parser/gt_data/interval/SBG.log b/test/parser/gt_data/interval/SBG.log index e065451..0e44736 100755 --- a/test/parser/gt_data/interval/SBG.log +++ b/test/parser/gt_data/interval/SBG.log @@ -7,8 +7,8 @@ result = isEmpty([1:0:0]) isEmpty([100:1:200]) isEmpty([100:1:5]) -isMember(201,[201:2:399]) -isMember(201,[200:4:400]) +isMember(201, [201:2:399]) +isMember(201, [200:4:400]) [1:1:0]/\[100:1:500] [100:1:500]/\[1:1:0] [1:2:20]/\[4:3:20] diff --git a/test/parser/gt_data/interval/interval.cpp b/test/parser/gt_data/interval/interval.cpp index 7c8f71c..88e6640 100755 --- a/test/parser/gt_data/interval/interval.cpp +++ b/test/parser/gt_data/interval/interval.cpp @@ -19,8 +19,8 @@ #include -#include -#include +#include "parser/expr.hpp" +#include "util/logger.hpp" void parseExprsFromFile(std::string str) { diff --git a/test/parser/gt_data/lexp/SBG.log b/test/parser/gt_data/lexp/SBG.log index 53ca132..494140e 100644 --- a/test/parser/gt_data/lexp/SBG.log +++ b/test/parser/gt_data/lexp/SBG.log @@ -10,8 +10,8 @@ result = ((1)x+2)+((2)x+5) ((1)x+2)-((2)x+5) inv((3)x+2) -compose((1)x+0,(1)x+0) -compose((2)x+3,(1)x+5) +compose((1)x+0, (1)x+0) +compose((2)x+3, (1)x+5) ------------------------- diff --git a/test/parser/gt_data/lexp/lexp.cpp b/test/parser/gt_data/lexp/lexp.cpp index 4d4d5f1..014b56f 100755 --- a/test/parser/gt_data/lexp/lexp.cpp +++ b/test/parser/gt_data/lexp/lexp.cpp @@ -19,8 +19,8 @@ #include -#include -#include +#include "parser/expr.hpp" +#include "util/logger.hpp" void parseExprsFromFile(std::string str) { diff --git a/test/parser/gt_data/map/SBG.log b/test/parser/gt_data/map/SBG.log index d6e53ee..2384208 100644 --- a/test/parser/gt_data/map/SBG.log +++ b/test/parser/gt_data/map/SBG.log @@ -2,16 +2,16 @@ Parsing succeeded result = -[1:1:10] ↦ (1)x+0 -[1:2:10] ↦ (1/2)x+1/2 -image([1:1:10] ↦ (1)x+0) -image([1:2:50] ↦ (2)x+1) -image([1:1:0] ↦ (1)x+0) -image([1:3:50],[2:2:100] ↦ (2)x+1) -preImage([1:1:10] ↦ (1)x+0) -preImage([1:2:50] ↦ (2)x+1) -preImage([1:1:0] ↦ (1)x+0) -preImage([20:5:100],[2:2:100] ↦ (2)x+1) +{[1:1:10]} ↦ (1)x+0 +{[1:2:10]} ↦ (1/2)x+1/2 +image({[1:1:10]} ↦ (1)x+0) +image({[1:2:50]} ↦ (2)x+1) +image({[1:1:0]} ↦ (1)x+0) +image({[1:3:50], [2:3:100]} ↦ (2)x+1) +preImage({[1:1:10]} ↦ (1)x+0) +preImage({[1:2:50]} ↦ (2)x+1) +preImage({[1:1:0]} ↦ (1)x+0) +preImage({[20:5:100], [200:2:300]} ↦ (2)x+1) ------------------------- diff --git a/test/parser/gt_data/map/map.cpp b/test/parser/gt_data/map/map.cpp index e4e1bd4..d66acf5 100755 --- a/test/parser/gt_data/map/map.cpp +++ b/test/parser/gt_data/map/map.cpp @@ -19,8 +19,8 @@ #include -#include -#include +#include "parser/expr.hpp" +#include "util/logger.hpp" void parseExprsFromFile(std::string str) { diff --git a/test/parser/gt_data/set/SBG.log b/test/parser/gt_data/set/SBG.log index 92ba08a..12d83fd 100644 --- a/test/parser/gt_data/set/SBG.log +++ b/test/parser/gt_data/set/SBG.log @@ -5,8 +5,8 @@ result = #{[1:1:100], [200:3:500]} isEmpty({[1:1:100]}) isEmpty({}) -isMember(1,{[50:3:100], [500:10:1000], [1:1:25]}) -isMember(51,{[50:3:100], [500:10:1000], [1:1:25]}) +isMember(1, {[50:3:100], [500:10:1000], [1:1:25]}) +isMember(51, {[50:3:100], [500:10:1000], [1:1:25]}) minElem({}) minElem({[500:3:1000], [1:1:100]}) maxElem({}) diff --git a/test/parser/gt_data/set/set.cpp b/test/parser/gt_data/set/set.cpp index 9982d6d..9c450e1 100755 --- a/test/parser/gt_data/set/set.cpp +++ b/test/parser/gt_data/set/set.cpp @@ -19,8 +19,8 @@ #include -#include -#include +#include "parser/expr.hpp" +#include "util/logger.hpp" void parseExprsFromFile(std::string str) { diff --git a/test/performance/Makefile b/test/performance/Makefile index f6e8a04..0862c9d 100755 --- a/test/performance/Makefile +++ b/test/performance/Makefile @@ -23,7 +23,8 @@ RUN_TESTS := sbg-performance # Source files. MAIN_SRC = $(SRC_DIR)/main.cpp -TEST_SRC = $(TEST_DIR)/set_perf.cpp +TEST_SRC = $(TEST_DIR)/set_perf.cpp \ + $(TEST_DIR)/pw_map_perf.cpp # Objects TEST_OBJ=$(addprefix $(BUILD_DIR)/test_, $(notdir $(TEST_SRC:.cpp=.o))) diff --git a/test/performance/pw_map_perf.cpp b/test/performance/pw_map_perf.cpp new file mode 100644 index 0000000..427f812 --- /dev/null +++ b/test/performance/pw_map_perf.cpp @@ -0,0 +1,107 @@ +/***************************************************************************** + + 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 + +#include "sbg/pw_map.hpp" + +TEST(PWMapPerf, Composition) +{ + unsigned int inter_sz = 100; + unsigned int set_sz = 100; + unsigned int map_sz = 100; + + SBG::LIB::MapSet ms1; + for (unsigned int k = 0; k < map_sz; k++) { + SBG::LIB::LExp le1(1, k); + SBG::LIB::InterSet is1; + int map_offset = k * inter_sz * set_sz; + for (unsigned int j = 0; j < set_sz; j++) { + SBG::LIB::Interval i(map_offset + (j*inter_sz) + 1, 1, map_offset + (j+1)*inter_sz); + is1.emplace_hint(is1.cend(), i); + } + SBG::LIB::Set s1(is1); + ms1.emplace(SBG::LIB::SBGMap(s1, le1)); + } + SBG::LIB::PWMap pw1(ms1); + + auto start = std::chrono::high_resolution_clock::now(); + SBG::LIB::PWMap res = composition(pw1, pw1); + auto end = std::chrono::high_resolution_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + std::cout << "PWL MAP COMPOSITION TEST elapsed time: " << elapsed.count() << "ms\n"; + + //std::cout << pw1 << "\n"; + //std::cout << res << "\n"; + + SUCCEED(); +} + +TEST(PWMapPerf, MapInf) { + int N = 600; + int sz = 10; + + SBG::LIB::MapSet aux; + for (int i = 0; i < N; i += 6) { + SBG::LIB::Interval i1(i * sz + 1, 1, (i + 1) * sz); + SBG::LIB::Interval i2((i + 1) * sz + 1, 1, (i + 2) * sz); + SBG::LIB::Interval i3((i + 2) * sz + 1, 1, (i + 3) * sz); + SBG::LIB::Interval i4((i + 3) * sz + 1, 1, (i + 4) * sz); + SBG::LIB::Interval i5((i + 4) * sz + 1, 1, (i + 5) * sz); + SBG::LIB::Interval i6((i + 5) * sz + 1, 1, (i + 6) * sz); + + SBG::LIB::Set s1(i1); + SBG::LIB::Set s2(i2); + SBG::LIB::Set s3(i3); + SBG::LIB::Set s4(i4); + SBG::LIB::Set s5(i5); + SBG::LIB::Set s6(i6); + + SBG::LIB::LExp le1(1, sz); + SBG::LIB::LExp le2(1, sz); + SBG::LIB::LExp le3(1, sz); + SBG::LIB::LExp le4(1, sz); + SBG::LIB::LExp le5(1, sz); + SBG::LIB::LExp le6(1, sz); + + SBG::LIB::SBGMap sm1(s1, le1); + aux.emplace(sm1); + SBG::LIB::SBGMap sm2(s2, le2); + aux.emplace(sm2); + SBG::LIB::SBGMap sm3(s3, le3); + aux.emplace(sm3); + SBG::LIB::SBGMap sm4(s4, le4); + aux.emplace(sm4); + SBG::LIB::SBGMap sm5(s5, le5); + aux.emplace(sm5); + SBG::LIB::SBGMap sm6(s6, le6); + aux.emplace(sm6); + } + SBG::LIB::PWMap pw(aux); + + auto start = std::chrono::high_resolution_clock::now(); + SBG::LIB::PWMap res = mapInf(pw); + auto end = std::chrono::high_resolution_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start); + std::cout << "PWL MAP MAPINF TEST elapsed time: " << elapsed.count() << "ms\n"; + + std::cout << pw << "\n"; + std::cout << res << "\n"; +} diff --git a/test/performance/set_perf.cpp b/test/performance/set_perf.cpp index 2b1cce5..19fc8c1 100644 --- a/test/performance/set_perf.cpp +++ b/test/performance/set_perf.cpp @@ -20,7 +20,7 @@ #include #include -#include +#include "sbg/pw_inter.hpp" TEST(SetPerf, Intersection) { diff --git a/test/pw_map.test b/test/pw_map.test new file mode 100644 index 0000000..9bfee5e --- /dev/null +++ b/test/pw_map.test @@ -0,0 +1,12 @@ +// Test consisting of only piecewise linear maps +// !!! If this file is modified the corresponding SBG.log file +// in all the gt_data directories should be modified. + +<<>> +<<{[1:1:10], [100:10:200]} -> 1*x-3>> +<<{[1:1:10], [100:10:200]} -> 1*x-3, {[500:1:600]} -> 1*x-3>> + +<<{[1:1:10]} -> 1*x+10, {[100:1:200], [250:1:300]} -> 1*x+10>> + +//minAdj(<<{[1:1:5]} -> 1*x+0, {[10:1:20]} -> 0*x+7, {[25:1:30]} -> 1*x-20>>, <<{[]} -> >>) +image(<<{[1:1:5]} -> 1*x+0, {[10:1:20]} -> 0*x+7, {[25:1:27]} -> 1*x-24>>) diff --git a/util/debug.cpp b/util/debug.cpp index 135fa35..b15bb43 100755 --- a/util/debug.cpp +++ b/util/debug.cpp @@ -19,7 +19,7 @@ #include -#include +#include "util/defs.hpp" namespace SBG { diff --git a/util/defs.cpp b/util/defs.cpp index 512653c..92f8cc7 100755 --- a/util/defs.cpp +++ b/util/defs.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "util/defs.hpp" namespace SBG { @@ -39,6 +39,22 @@ INT RATIONAL::numerator() { return value().numerator(); } INT RATIONAL::denominator() { return value().denominator(); } +NAT toNat(RATIONAL r) +{ + if (r.denominator() == 1 && 0 <= r.value()) return r.numerator(); + + ERROR("toNat: RATIONAL is not NAT"); + return 0; +} + +INT toInt(RATIONAL r) +{ + if (r.denominator() == 1) return r.numerator(); + + ERROR("toInt: RATIONAL is not INT"); + return 0; +} + RATIONAL RATIONAL::operator+=(const RATIONAL &r) { value_ref() += r.value(); @@ -91,6 +107,12 @@ RATIONAL operator/(const RATIONAL &r1, const RATIONAL &r2) return res; } +bool RATIONAL::operator==(const INT &r) const +{ + RATIONAL aux = *this; + return aux.numerator() == r && aux.denominator() == 1; +} + bool RATIONAL::operator==(const RATIONAL &r) const { return value() == r.value(); } bool RATIONAL::operator<(const RATIONAL &r) const { return value() < r.value(); } diff --git a/util/defs.hpp b/util/defs.hpp index 95bd95e..87a1d8f 100755 --- a/util/defs.hpp +++ b/util/defs.hpp @@ -31,6 +31,8 @@ #include #include +#include "util/debug.hpp" + namespace SBG { namespace Util { @@ -119,11 +121,15 @@ struct RATIONAL{ RATIONAL operator*=(const RATIONAL &r); RATIONAL operator/=(const RATIONAL &r); + bool operator==(const INT &other) const; + eq_class(RATIONAL); lt_class(RATIONAL); gt_class(RATIONAL); neq_class(RATIONAL); }; +NAT toNat(RATIONAL r); +INT toInt(RATIONAL r); RATIONAL operator+(const RATIONAL &r1, const RATIONAL &r2); RATIONAL operator-(const RATIONAL &r1, const RATIONAL &r2); RATIONAL operator*(const RATIONAL &r1, const RATIONAL &r2); diff --git a/util/env.cpp b/util/env.cpp index 6b64656..86fafe8 100755 --- a/util/env.cpp +++ b/util/env.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include "util/env.hpp" namespace SBG { diff --git a/util/env.hpp b/util/env.hpp index 4f46297..ffcb075 100755 --- a/util/env.hpp +++ b/util/env.hpp @@ -31,7 +31,7 @@ #include #include -#include +#include "util/defs.hpp" namespace SBG {