diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 667ae89df52eecaa4006b2170751b26e895147ae..fc6028e63608820626adef5c62284151bcc2127c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ # driver source files -SET(sources imagine-planner.cpp types.cpp queries.cpp effects.cpp domains.cpp parsing.cpp) +SET(sources types.cpp) # queries.cpp effects.cpp domains.cpp parsing.cpp imagine-planner.cpp) # application header files -SET(headers imagine-planner.h types.h queries.h effects.h domains.h parsing.h) +SET(headers types.h) # queries.h effects.h domains.h parsing.h imagine-planner.h) # Ades SET(CMAKE_MODULE_PATH /usr/local/lib/cmake/ades) FIND_PACKAGE(ADES) diff --git a/src/examples/types_test.cpp b/src/examples/types_test.cpp index e220a3be4ef6ea33c1116118b156d6f63a491be6..3d2ad7153f5acb7696eac1c98e1d15384e897938 100644 --- a/src/examples/types_test.cpp +++ b/src/examples/types_test.cpp @@ -47,80 +47,99 @@ std::ostream& operator<<(std::ostream& os, const std::unordered_set<Predicate, CONTAINER_TO_STREAM(ctn, os); } +BOOST_AUTO_TEST_CASE(dummy) +{ + BOOST_CHECK(true); +} + BOOST_AUTO_TEST_CASE(literal_test) { - TermWrapper l1("atom1"); - TermWrapper l1_("atom1"); - TermWrapper l2("atom2"); - TermWrapper l3("Var1"); - TermWrapper l4("_"); - INFO("l1=" << l1); - INFO("l1_=" << l1_); - INFO("l2=" << l2); - INFO("l3=" << l3); - BOOST_CHECK_EQUAL(l1, l1_); - BOOST_CHECK_LE(l1, l1_); - BOOST_CHECK_NE(l1, l2); - BOOST_CHECK_LT(l1, l2); - BOOST_CHECK_LE(l1, l2); - BOOST_CHECK_GT(l2, l1); - BOOST_CHECK_GE(l2, l1); - BOOST_CHECK(l1.is_ground()); - BOOST_CHECK(l2.is_ground()); - BOOST_CHECK(not l3.is_ground()); - BOOST_CHECK(not l4.is_ground()); - BOOST_CHECK_EQUAL(l1.hash(), l1_.hash()); - BOOST_WARN_NE(l1.hash(), l2.hash()); // Very likely the hashes are different + TermFactory T; + auto l1 = T("atom1"); + auto l1_ = T("atom1"); + auto l2 = T("atom2"); + auto l3 = T("Var1"); + auto l4 = T("_"); + INFO("l1=" << *l1); + INFO("l1_=" << *l1_); + INFO("l2=" << *l2); + INFO("l3=" << *l3); + BOOST_CHECK_EQUAL(*l1, *l1_); + BOOST_CHECK_LE(*l1, *l1_); + BOOST_CHECK_NE(*l1, *l2); + BOOST_CHECK_LT(*l1, *l2); + BOOST_CHECK_LE(*l1, *l2); + BOOST_CHECK_GT(*l2, *l1); + BOOST_CHECK_GE(*l2, *l1); + BOOST_CHECK(l1->is_ground()); + BOOST_CHECK(l2->is_ground()); + BOOST_CHECK(not l3->is_ground()); + BOOST_CHECK(not l4->is_ground()); + BOOST_CHECK_EQUAL(l1->hash(), l1_->hash()); + BOOST_WARN_NE(l1->hash(), l2->hash()); // Very likely the hashes are different } BOOST_AUTO_TEST_CASE(number_test) { - TermWrapper n1(0.5); - TermWrapper n1_(0.5+2e-10); - TermWrapper n1__(0.5+5e-9); - TermWrapper n2(1); - TermWrapper n2_(1+2e-10); - TermWrapper n2__(1+5e-9); - INFO("n1=" << n1); - INFO("n1_=" << n1_); - INFO("n1__=" << n1__); - INFO("n2=" << n2); - INFO("n2_=" << n2_); - INFO("n2__=" << n2__); + TermFactory T; + auto n1 = T(0.5); + auto n1_ = T(0.5+2e-10); + auto n1__ = T(0.5+5e-9); + auto n2 = T(1); + auto n2_ = T(1+2e-10); + auto n2__ = T(1+5e-9); + INFO("n1=" << *n1); + INFO("n1_=" << *n1_); + INFO("n1__=" << *n1__); + INFO("n2=" << *n2); + INFO("n2_=" << *n2_); + INFO("n2__=" << *n2__); // Check number specific method's - BOOST_CHECK_CLOSE(n1.get_number_term()->get_number(), 0.5, 0.00001); - BOOST_CHECK_CLOSE(n2.get_number_term()->get_number(), 1, 0.00001); - BOOST_CHECK(not n1.get_number_term()->is_int()); - BOOST_CHECK(not n2__.get_number_term()->is_int()); - BOOST_CHECK(n2.get_number_term()->is_int()); - BOOST_CHECK(n2_.get_number_term()->is_int()); + BOOST_CHECK_CLOSE(n1->get_number(), 0.5, 0.00001); + BOOST_CHECK_CLOSE(n2->get_number(), 1, 0.00001); + BOOST_CHECK(not n1->is_int()); + BOOST_CHECK(not n2__->is_int()); + BOOST_CHECK(n2->is_int()); + BOOST_CHECK(n2_->is_int()); // Check == operator - BOOST_CHECK_EQUAL(n1, n1_); - BOOST_CHECK_EQUAL(n2, n2_); - BOOST_CHECK_NE(n1, n1__); - BOOST_CHECK_NE(n2, n2__); - BOOST_CHECK_NE(n1, n2); + BOOST_CHECK_EQUAL(*n1, *n1_); + BOOST_CHECK_EQUAL(*n2, *n2_); + BOOST_CHECK_NE(*n1, *n1__); + BOOST_CHECK_NE(*n2, *n2__); + BOOST_CHECK_NE(*n1, *n2); // Check < operator - BOOST_CHECK_LT(n1, n2); - BOOST_CHECK_LT(n1, n1__); - BOOST_CHECK_GE(n1_, n1); - BOOST_CHECK_GT(n2, n1); + BOOST_CHECK_LT(*n1, *n2); + BOOST_CHECK_LT(*n1, *n1__); + BOOST_CHECK_GE(*n1_, *n1); + BOOST_CHECK_GT(*n2, *n1); // Check hash correctness - BOOST_CHECK_EQUAL(n1.hash(), n1.hash()); // non-ints should have the same hash - BOOST_CHECK_EQUAL(n2.hash(), n2_.hash()); - BOOST_WARN_NE(n2.hash(), n2__.hash()); // Very likely the hashes are - // different + BOOST_CHECK_EQUAL(n1->hash(), n1->hash()); // non-ints should have the same hash + BOOST_CHECK_EQUAL(n2->hash(), n2_->hash()); + BOOST_WARN_NE(n2->hash(), n2__->hash()); // Very likely the hashes are + // different } BOOST_AUTO_TEST_CASE(mixed_test) { - TermWrapper t1(0); - TermWrapper t2("atom"); - INFO("t1=" << t1); - INFO("t2=" << t2); - BOOST_CHECK_NE(t1, t2); - BOOST_CHECK_LT(t2, t1); - BOOST_WARN_NE(t1.hash(), t2.hash()); + TermFactory T; + auto t1 = T(0); + auto t2 = T("atom"); + INFO("t1=" << *t1); + INFO("t2=" << *t2); + BOOST_CHECK_NE(*t1, *t2); + BOOST_CHECK_LT(*t2, *t1); + BOOST_WARN_NE(t1->hash(), t2->hash()); +} + +BOOST_AUTO_TEST_CASE(term_v) +{ + TermFactory T; + TermV v1 = T.vector(); + TermV v2 = T.vector("a", "b"); + for (auto& t : v1) + INFO(*t); + for (auto& t : v2) + INFO(*t); } BOOST_AUTO_TEST_CASE(predicate_test) @@ -207,14 +226,15 @@ BOOST_AUTO_TEST_CASE(unordered_set_test) BOOST_AUTO_TEST_CASE(substitution_test) { + TermFactory T; Predicate p1("p", "X", "a"); Predicate p2("p", "x", "y"); Predicate p3("p", "X", "Y"); Predicate p4("q", "Y"); Predicate p5("q", "Z"); Predicate p6("r"); - Substitution sigma({{"X", TermWrapper("a")}, {"Y", TermWrapper("b")}}); - Substitution sigma_({{"W", TermWrapper("c")}}); + Substitution sigma({{"X", T("a")}, {"Y", T("b")}}); + Substitution sigma_({{"W", T("c")}}); INFO("p1 = " << p1); INFO("p2 = " << p2); INFO("p3 = " << p3); diff --git a/src/types.cpp b/src/types.cpp index 8295ed0746c1c54de30c461883689426009d3ae4..ba18032b1223ba90ad88ecaec201fabd03972258 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -41,9 +41,8 @@ bool LiteralTerm::operator<(const Term& term) const return type() < term.type(); } -// NumberTerm -double NumberTerm::EPSILON_ = 1E-9; +// NumberTerm NumberTerm::NumberTerm(double number) : number_(number) {} @@ -76,51 +75,16 @@ bool NumberTerm::operator<(const Term& term) const return type() < term.type(); } -// TermWrapper - -TermWrapper::TermWrapper(const TermWrapper& term) : term_(term.term_->clone()) {} - -TermWrapper::TermWrapper(const Term& term) : term_(term.clone()) {} - -TermWrapper::TermWrapper(const std::string& literal) : - term_(new LiteralTerm(literal)) {} - -TermWrapper::TermWrapper(double number) : term_(new NumberTerm(number)) {} - -const LiteralTerm* TermWrapper::get_literal_term() const -{ - return dynamic_cast<const LiteralTerm*>(term_); -} - -const NumberTerm* TermWrapper::get_number_term() const -{ - return dynamic_cast<const NumberTerm*>(term_); -} - -TermWrapper& TermWrapper::operator=(const TermWrapper& term) -{ - delete term_; - term_ = term.term_->clone(); - return *this; -} - -TermWrapper::~TermWrapper() -{ - delete term_; -} +double NumberTerm::EPSILON_ = 1E-9; -TermV create_term_v() { return TermV(); } // Predicate -Predicate::Predicate(const std::string& name, const TermV& arguments) : - name_(name), arguments_(arguments) {} - bool Predicate::is_ground() const { - for (const TermWrapper& term : arguments_) + for (const Term::Ptr& term : arguments_) { - if (not term.is_ground()) return false; + if (not term->is_ground()) return false; } return true; } @@ -137,10 +101,10 @@ std::string Predicate::to_str() const std::ostringstream oss; oss << name_ << '('; bool first = true; - for (const TermWrapper& term : arguments_) + for (const Term::Ptr& term : arguments_) { if (not first) oss << ','; - oss << term; + oss << *term; first = false; } oss << ')'; @@ -152,9 +116,9 @@ std::size_t Predicate::hash() const std::hash<std::string> hasher_s; std::hash<Hashable> hasher_h; std::size_t acc = hasher_s(name_); - for (const TermWrapper& term : arguments_) + for (const Term::Ptr& term : arguments_) { - acc ^= hasher_h(term) + 0x9e3779b9 + (acc<<6) + (acc>>2); + acc ^= hasher_h(*term) + 0x9e3779b9 + (acc<<6) + (acc>>2); } return acc; } @@ -165,7 +129,7 @@ bool Predicate::operator==(const Predicate& predicate) const if (arguments_.size() != predicate.arguments_.size()) return false; for (std::size_t idx = 0; idx < arguments_.size(); ++idx) { - if (arguments_[idx] != predicate.arguments_[idx]) return false; + if (*arguments_[idx] != *predicate.arguments_[idx]) return false; } return true; } @@ -178,18 +142,14 @@ bool Predicate::operator<(const Predicate& predicate) const if (arguments_.size() > predicate.arguments_.size()) return false; for (std::size_t idx = 0; idx < arguments_.size(); ++idx) { - if (arguments_[idx] < predicate.arguments_[idx]) return true; - if (arguments_[idx] > predicate.arguments_[idx]) return false; + if (*arguments_[idx] < *predicate.arguments_[idx]) return true; + if (*arguments_[idx] > *predicate.arguments_[idx]) return false; } return false; } -// Implementation of Substitution - -Substitution::Substitution() {} -Substitution::Substitution(const std::map<std::string, TermWrapper>& sigma) - : sigma_(sigma) {} +// Implementation of Substitution std::string Substitution::to_str() const { @@ -199,11 +159,11 @@ std::string Substitution::to_str() const { oss << '{'; bool first = true; - for (auto entry : sigma_) + for (const auto& entry : sigma_) { if (not first) oss << ','; oss << "\n "; - oss << entry.first << " -> " << entry.second; + oss << entry.first << " -> " << *entry.second; first = false; } oss << "\n}"; @@ -216,16 +176,16 @@ bool Substitution::has(const std::string& varname) const return (bool)sigma_.count(varname); } -const Term* Substitution::get(const std::string& varname) const +Term::Ptr Substitution::get(const std::string& varname) const { auto it = sigma_.find(varname); - if (it != sigma_.end()) return it->second.get_term(); + if (it != sigma_.end()) return it->second; return nullptr; } -void Substitution::put(const std::string& varname, const TermWrapper& term) +void Substitution::put(const std::string& varname, const Term::Ptr& value) { - sigma_.insert(std::make_pair(varname, term)); + sigma_.insert(std::make_pair(varname, value)); } void Substitution::remove(const std::string& varname) @@ -235,7 +195,7 @@ void Substitution::remove(const std::string& varname) void Substitution::operator+=(const Substitution& other) { - for (auto entry : other) + for (const auto& entry : other) { sigma_.insert(entry); } @@ -243,7 +203,7 @@ void Substitution::operator+=(const Substitution& other) void Substitution::operator-=(const Substitution& other) { - for (auto entry : other) + for (const auto& entry : other) { sigma_.erase(entry.first); } @@ -258,7 +218,7 @@ Substitution Substitution::operator+(const Substitution& other) const Substitution Substitution::operator-(const Substitution& other) const { - Substitution ret; + Substitution ret(*this); ret -= other; return ret; } @@ -267,34 +227,17 @@ Predicate Substitution::operator()(const Predicate& predicate) const { TermV arguments; arguments.reserve(predicate.arity()); - for (const TermWrapper& term : predicate.get_arguments()) + for (const Term::Ptr& term : predicate.get_arguments()) { - const Term* value = get(term.to_str()); - if (not value) value = term.get_term(); - arguments.push_back(TermWrapper(*value)); + Term::Ptr value = get(term->to_str()); + if (not value) value = term; + arguments.push_back(value); } return Predicate(predicate.get_name(), arguments); } -// Implementation of PlanState - -PlanState::PlanState() {} - -PlanState::PlanState(const std::set<Predicate>& predicates) : - predicates_(predicates) {} -std::set<TermWrapper> PlanState::symbols() const -{ - std::set<TermWrapper> sym; - for (const Predicate& pred : predicates_) - { - for (const TermWrapper& arg : pred.get_arguments()) - { - if (arg.get_literal_term()) sym.insert(arg); - } - } - return sym; -} +// Implementation of PlanState std::string PlanState::to_str() const { @@ -313,12 +256,24 @@ std::string PlanState::to_str() const std::size_t PlanState::hash() const { - std::size_t acc = 0; - for (const Predicate& pred : predicates_) + if (not hash_cached_) { - acc += pred.hash(); + std::size_t acc = 0; + for (const Predicate& pred : predicates_) + { + // since we are using an ordered set, two equal sets result in the same + // iteration order, so we can use this hash combination. + acc ^= pred.hash() + 0x9e3779b9 + (acc<<6) + (acc>>2); + // for unordered sets... + //acc += pred.hash(); + } + // The use of const_cast here is appropriate since we are just storing the + // hash value for faster retrieval in the future. + PlanState* modifiable = const_cast<PlanState*>(this); + modifiable->hash_cached_ = true; + modifiable->hash_ = acc; } - return acc; + return hash_; } bool PlanState::subset_of(const PlanState& other) const @@ -331,15 +286,10 @@ bool PlanState::subset_of(const PlanState& other) const return true; } -// Implementation of GoalSpecification's methods - -GoalSpecification::GoalSpecification() {} -GoalSpecification::GoalSpecification(const std::vector<Predicate>& must_appear, - const std::vector<Predicate>& cannot_appear) - : must_appear_(must_appear), cannot_appear_(cannot_appear) {} +// Implementation of GoalCondition's methods -std::string GoalSpecification::to_str() const +std::string GoalCondition::to_str() const { std::ostringstream oss; bool first = true; @@ -362,7 +312,7 @@ std::string GoalSpecification::to_str() const return oss.str(); } -bool GoalSpecification::operator()(const PlanState& state) const +bool GoalCondition::operator()(const PlanState& state) const { for (const Predicate& pred : must_appear_) { diff --git a/src/types.h b/src/types.h index 01a53079b72fb7e20ee2e2c12374bd533d0df2c8..29d8b7d90617682486089c89d0ff87c6cb0c7f92 100644 --- a/src/types.h +++ b/src/types.h @@ -1,12 +1,6 @@ #ifndef _LIBIMAGINE_PLANNER_TYPES_H_ #define _LIBIMAGINE_PLANNER_TYPES_H_ -// Let's group some functions and typedefs that are common to all the Types -// defined here in a macro for convenience. -#define TYPES_COMMON(Class)\ - virtual std::string type() const override { return #Class; }\ - virtual Term* clone() const override { return new Class(*this); }; - #include <exception> #include <functional> #include <map> @@ -25,7 +19,6 @@ class Hashable; class Term; class LiteralTerm; class NumberTerm; -class TermWrapper; class Predicate; class Substitution; class PlanState; @@ -33,13 +26,15 @@ class GoalSpecification; class ImaginePlannerException : public std::exception { - private: - std::string msg_; - public: + explicit ImaginePlannerException(const std::string& msg) : msg_(msg) {} virtual const char* what() const throw() { return msg_.c_str(); } + + private: + + std::string msg_; }; /** @@ -60,6 +55,10 @@ class Stringifiable virtual ~Stringifiable() {} }; + +/** + * @brief Abstract class (interface-like) that declares the hash method. + */ class Hashable { public: @@ -68,11 +67,17 @@ class Hashable virtual ~Hashable() {} }; + +/** + * @brief General term (Either a Literal or a Number) + */ class Term : public Stringifiable, public Hashable { public: + typedef std::shared_ptr<const Term> Ptr; + virtual std::string type() const =0; virtual bool is_ground() const =0; @@ -95,19 +100,25 @@ class Term : public Stringifiable, virtual bool operator>=(const Term& term) const { return term <= *this; } - virtual Term* clone() const =0; + virtual Ptr clone() const =0; virtual ~Term() {} }; + +/** + * @brief A string Atom + */ class LiteralTerm : public Term { - private: - std::string literal_; - public: + + typedef std::shared_ptr<LiteralTerm> Ptr; + LiteralTerm(const std::string& literal); + virtual std::string type() const override { return "LiteralTerm"; } + virtual std::string to_str() const override { return literal_; } virtual std::size_t hash() const override; @@ -120,19 +131,27 @@ class LiteralTerm : public Term virtual bool operator<(const Term& term) const override; - TYPES_COMMON(LiteralTerm) + virtual Term::Ptr clone() const override { return Term::Ptr(new LiteralTerm(literal_)); } + + private: + std::string literal_; }; + +/** + * @brief A numeric (double) atom + */ class NumberTerm : public Term { - private: - static double EPSILON_; - double number_; - public: + + typedef std::shared_ptr<NumberTerm> Ptr; + NumberTerm(double number); + virtual std::string type() const override { return "NumberTerm"; } + std::string to_str() const override { return std::to_string(number_); } virtual std::size_t hash() const override; @@ -147,98 +166,61 @@ class NumberTerm : public Term virtual bool operator<(const Term& term) const override; - TYPES_COMMON(NumberTerm) -}; + virtual Term::Ptr clone() const override { return Term::Ptr(new NumberTerm(number_)); } -class TermWrapper : public Stringifiable, - public Hashable -{ private: - const Term* term_; - - public: - - TermWrapper(const TermWrapper& term); - - TermWrapper(const Term& term); - - TermWrapper(const std::string& literal); - - TermWrapper(double number); - - const Term* get_term() const { return term_; } - - const LiteralTerm* get_literal_term() const; - - const NumberTerm* get_number_term() const; - - bool is_ground() const { return term_->is_ground(); } - - virtual std::string to_str() const override { return term_->to_str(); } + static double EPSILON_; + double number_; +}; - virtual std::size_t hash() const override { return term_->hash(); } - TermWrapper& operator=(const TermWrapper& term); +typedef std::vector<Term::Ptr> TermV; - bool operator==(const TermWrapper& term) const - { - return *term_ == *(term.term_); - } - bool operator<(const TermWrapper& term) const - { - return *term_ < *(term.term_); - } +class TermFactory +{ + public: - bool operator<=(const TermWrapper& term) const + LiteralTerm::Ptr operator()(const std::string& literal) const { - return *term_ <= *(term.term_); + return std::make_shared<LiteralTerm>(literal); } - bool operator!=(const TermWrapper& term) const + NumberTerm::Ptr operator()(double number) const { - return *term_ != *(term.term_); + return std::make_shared<NumberTerm>(number); } - bool operator>(const TermWrapper& term) const - { - return *term_ > *(term.term_); - } + TermV vector() const { return TermV(); } - bool operator>=(const TermWrapper& term) const + template <typename First, typename... Args> + TermV vector(const First& fst, Args... args) const { - return *term_ >= *(term.term_); + const TermFactory& T = *this; + TermV tail = T.vector(args...); + TermV term_v{T(fst)}; + term_v.insert(term_v.end(), tail.begin(), tail.end()); + return term_v; } - ~TermWrapper(); }; -typedef std::vector<TermWrapper> TermV; - -TermV create_term_v(); - -template <typename First, typename... Args> -TermV create_term_v(const First& fst, Args... args) -{ - TermV term_v{TermWrapper(fst)}; - TermV tail = create_term_v(args...); - term_v.insert(term_v.end(), tail.begin(), tail.end()); - return term_v; -} class Predicate : public Stringifiable, public Hashable { - private: - std::string name_; - TermV arguments_; - public: + template <typename... Args> Predicate(const std::string& name, Args... args) : - name_(name), arguments_(create_term_v(args...)) {} + name_(name) + { + TermFactory T; + arguments_ = T.vector(args...); + } - Predicate(const std::string& name, const TermV& arguments); + Predicate(const std::string& name, const TermV& arguments) : + name_(name), arguments_(arguments) {} bool is_ground() const; @@ -258,30 +240,39 @@ class Predicate : public Stringifiable, bool operator<(const Predicate& predicate) const; + private: + + std::string name_; + TermV arguments_; + }; class Substitution : public Stringifiable { - private: - typedef std::map<std::string,TermWrapper> Container; - - Container sigma_; public: + typedef std::map<std::string, Term::Ptr> Container; typedef Container::const_iterator CIter; - Substitution(); + Substitution() {} - Substitution(const std::map<std::string, TermWrapper>& sigma); + Substitution(const Container& sigma) : sigma_(sigma) {} std::string to_str() const override; bool has(const std::string& varname) const; - const Term* get(const std::string& varname) const; + Term::Ptr get(const std::string& varname) const; + + template <typename Value> + void put(const std::string& varname, const Value& value) + { + TermFactory T; + put(varname, T(value)); + } - void put(const std::string& varname, const TermWrapper& value); + void put(const std::string& varname, const Term::Ptr& value); void remove(const std::string& varname); @@ -303,22 +294,25 @@ class Substitution : public Stringifiable CIter end() const { return sigma_.end(); } + private: + + Container sigma_; + }; + class PlanState : public Stringifiable, public Hashable { - private: - std::set<Predicate> predicates_; - public: - typedef std::set<Predicate>::const_iterator CIter; - PlanState(); + typedef std::set<Predicate> Container; + typedef Container::const_iterator CIter; - PlanState(const std::set<Predicate>& predicates); + PlanState() : hash_cached_(false) {} - std::set<TermWrapper> symbols() const; + PlanState(const Container& predicates) + : predicates_(predicates), hash_cached_(false) {} virtual std::string to_str() const override; @@ -331,6 +325,11 @@ class PlanState : public Stringifiable, bool subset_of(const PlanState& other) const; + bool superset_of(const PlanState& other) const + { + return other.subset_of(*this); + } + bool has(const Predicate& predicate) const { return (bool)predicates_.count(predicate); @@ -354,18 +353,27 @@ class PlanState : public Stringifiable, CIter end() const { return predicates_.end(); } + private: + + Container predicates_; + + bool hash_cached_; + std::size_t hash_; + }; -class GoalSpecification : public Stringifiable + +class GoalCondition : public Stringifiable { private: std::vector<Predicate> must_appear_, cannot_appear_; public: - GoalSpecification(); + GoalCondition() {} - GoalSpecification(const std::vector<Predicate>& must_appear, - const std::vector<Predicate>& cannot_appear); + GoalCondition(const std::vector<Predicate>& must_appear, + const std::vector<Predicate>& cannot_appear) + : must_appear_(must_appear), cannot_appear_(cannot_appear) {} std::string to_str() const override; @@ -373,6 +381,7 @@ class GoalSpecification : public Stringifiable }; + /** * @brief Stream operator that conveniently puts a Stringifiable object into * an output stream.