Commit 5afe8a45 authored by asuarez's avatar asuarez
Browse files

refactored queries

parent 4e1e85eb
# driver source files # driver source files
SET(sources types.cpp) # queries.cpp effects.cpp domains.cpp parsing.cpp imagine-planner.cpp) SET(sources types.cpp queries.cpp) # effects.cpp domains.cpp parsing.cpp imagine-planner.cpp)
# application header files # application header files
SET(headers types.h) # queries.h effects.h domains.h parsing.h imagine-planner.h) SET(headers types.h) # queries.h effects.h domains.h parsing.h imagine-planner.h)
# Ades # Ades
......
...@@ -17,70 +17,107 @@ using namespace imagine_planner; ...@@ -17,70 +17,107 @@ using namespace imagine_planner;
#define INFO(x) #define INFO(x)
#endif #endif
BOOST_AUTO_TEST_CASE(comparison_query_test_sat)
{
TermFactory T;
PlanState dummy;
ComparisonQuery query1(Predicate("<", "X", "Y"));
ComparisonQuery query2(Predicate(">", "X", "Y"));
ComparisonQuery query3(Predicate("!=", "X", "Y"));
ComparisonQuery query4(Predicate("==", "X", "Y"));
INFO("query1: " << query1);
INFO("query2: " << query2);
INFO("query3: " << query3);
INFO("query4: " << query4);
Substitution sigma0_1{{"X",T(1)}, {"Y",T(10)}};
Substitution sigma0_2{{"X",T(1)}, {"Y",T(-1)}};
Substitution sigma0_3{{"X",T("a")}, {"Y",T("b")}};
Substitution sigma0_4{{"X",T("b")}, {"Y",T("b")}};
BOOST_CHECK(not query1.exists(dummy));
BOOST_CHECK(query1.exists(dummy, sigma0_1));
BOOST_CHECK(not query1.exists(dummy, sigma0_2));
BOOST_CHECK(not query2.exists(dummy, sigma0_1));
BOOST_CHECK(query2.exists(dummy, sigma0_2));
BOOST_CHECK(query3.exists(dummy, sigma0_3));
BOOST_CHECK(not query3.exists(dummy, sigma0_4));
BOOST_CHECK(query4.exists(dummy, sigma0_4));
//PlanState state({Predicate("p","a","b"), Predicate("p","a","c"),
//Predicate("p", "e", "d"), Predicate("p","d","a"), Predicate("q","b")});
//INFO("state: " << state);
//SimpleQuery* q1 = new SimpleQuery(state, Predicate("p", "X", "Y"));
//ComparisonQuery* q2 = new ComparisonQuery(state, Predicate("<", "X", "Y"));
//AndQuery* and1 = new AndQuery(q1, q2);
//INFO("and1: " << *and1);
//BOOST_REQUIRE(and1->next_solution());
//BOOST_CHECK_EQUAL(and1->get_solution().to_str(), "{\n X -> a,\n Y -> b\n}");
//BOOST_REQUIRE(and1->next_solution());
//BOOST_CHECK_EQUAL(and1->get_solution().to_str(), "{\n X -> a,\n Y -> c\n}");
//BOOST_REQUIRE(not and1->next_solution());
//delete and1;
}
BOOST_AUTO_TEST_CASE(simple_query_test_sat) BOOST_AUTO_TEST_CASE(simple_query_test_sat)
{ {
PlanState state({Predicate("p","a","b"), Predicate("p","a","c"), PlanState state({Predicate("p","a","b"), Predicate("p","a","c"),
Predicate("p","d","a"), Predicate("q","w"), Predicate("q", "s")}); Predicate("p","d","a"), Predicate("q","w"), Predicate("q", "s")});
INFO(state); INFO(state);
SimpleQuery q1(state, Predicate("p", "a", "X")); SimpleQuery q1(Predicate("p", "a", "X"));
SimpleQuery q2(state, Predicate("q", "w")); SimpleQuery q2(Predicate("q", "w"));
INFO("q1: " << q1 << ", " << q2); INFO("q1: " << q1 << ", q2: " << q2);
BOOST_REQUIRE(q1.next_solution()); std::vector<Substitution> results1, results2;
BOOST_CHECK_EQUAL(q1.get_solution().to_str(), "{\n X -> b\n}"); q1(state, results1);
BOOST_REQUIRE(q1.next_solution()); BOOST_REQUIRE_EQUAL(results1.size(), 2);
BOOST_CHECK_EQUAL(q1.get_solution().to_str(), "{\n X -> c\n}"); BOOST_CHECK_EQUAL(results1[0].to_str(), "{\n X -> b\n}");
BOOST_REQUIRE(not q1.next_solution()); BOOST_CHECK_EQUAL(results1[1].to_str(), "{\n X -> c\n}");
BOOST_REQUIRE(q2.next_solution()); q2(state, results2);
BOOST_CHECK_EQUAL(q2.get_solution().to_str(), "{}"); BOOST_REQUIRE_EQUAL(results2.size(), 1);
BOOST_CHECK(not q1.next_solution()); BOOST_CHECK_EQUAL(results2[0].to_str(), "{}");
} }
BOOST_AUTO_TEST_CASE(simple_query_test_unsat) BOOST_AUTO_TEST_CASE(not_query_test)
{ {
PlanState state({Predicate("p","a","b"), Predicate("p","a","c"), PlanState state({Predicate("p","a","b"), Predicate("p","a","c"),
Predicate("p","d","a"), Predicate("q","w"), Predicate("q", "s")}); Predicate("p","d","a"), Predicate("q","w"), Predicate("q", "s")});
INFO(state); INFO(state);
SimpleQuery q1(state, Predicate("p", "c", "X")); Query::Ptr q1 = std::make_shared<SimpleQuery>(Predicate("p", "a", "X"));
SimpleQuery q2(state, Predicate("p", "a", "d")); Query::Ptr q1_ = std::make_shared<SimpleQuery>(Predicate("p", "Z", "d"));
INFO("q1: " << q1 << ", " << q2); NotQuery q2(q1);
BOOST_REQUIRE(not q1.next_solution()); NotQuery q2_(q1_);
BOOST_REQUIRE(not q2.next_solution()); INFO("q2: " << q2 << ", q2_: " << q2_);
BOOST_CHECK(not q2.exists(state));
BOOST_CHECK(q2_.exists(state));
} }
BOOST_AUTO_TEST_CASE(and_query_test_sat) //BOOST_AUTO_TEST_CASE(simple_query_test_unsat)
{ //{
PlanState state({Predicate("p","a","b"), Predicate("p","a","c"), //PlanState state({Predicate("p","a","b"), Predicate("p","a","c"),
Predicate("p", "b", "d"), Predicate("p","d","a"), Predicate("q","b")}); //Predicate("p","d","a"), Predicate("q","w"), Predicate("q", "s")});
INFO("state: " << state); //INFO(state);
SimpleQuery* q1 = new SimpleQuery(state, Predicate("p", "X", "Y")); //SimpleQuery q1(state, Predicate("p", "c", "X"));
SimpleQuery* q2 = new SimpleQuery(state, Predicate("q", "X")); //SimpleQuery q2(state, Predicate("p", "a", "d"));
NotQuery* not1 = new NotQuery(q2); //INFO("q1: " << q1 << ", " << q2);
AndQuery* and1 = new AndQuery(q1, not1); //BOOST_REQUIRE(not q1.next_solution());
INFO("and1: " << *and1); //BOOST_REQUIRE(not q2.next_solution());
BOOST_REQUIRE(and1->next_solution()); //}
BOOST_CHECK_EQUAL(and1->get_solution().to_str(), "{\n X -> a,\n Y -> b\n}");
BOOST_REQUIRE(and1->next_solution());
BOOST_CHECK_EQUAL(and1->get_solution().to_str(), "{\n X -> a,\n Y -> c\n}");
BOOST_REQUIRE(and1->next_solution());
BOOST_CHECK_EQUAL(and1->get_solution().to_str(), "{\n X -> d,\n Y -> a\n}");
BOOST_REQUIRE(not and1->next_solution());
delete and1;
}
BOOST_AUTO_TEST_CASE(comparison_query_test_sat) //BOOST_AUTO_TEST_CASE(and_query_test_sat)
{ //{
PlanState state({Predicate("p","a","b"), Predicate("p","a","c"), //PlanState state({Predicate("p","a","b"), Predicate("p","a","c"),
Predicate("p", "e", "d"), Predicate("p","d","a"), Predicate("q","b")}); //Predicate("p", "b", "d"), Predicate("p","d","a"), Predicate("q","b")});
INFO("state: " << state); //INFO("state: " << state);
SimpleQuery* q1 = new SimpleQuery(state, Predicate("p", "X", "Y")); //SimpleQuery* q1 = new SimpleQuery(state, Predicate("p", "X", "Y"));
ComparisonQuery* q2 = new ComparisonQuery(state, Predicate("<", "X", "Y")); //SimpleQuery* q2 = new SimpleQuery(state, Predicate("q", "X"));
AndQuery* and1 = new AndQuery(q1, q2); //NotQuery* not1 = new NotQuery(q2);
INFO("and1: " << *and1); //AndQuery* and1 = new AndQuery(q1, not1);
BOOST_REQUIRE(and1->next_solution()); //INFO("and1: " << *and1);
BOOST_CHECK_EQUAL(and1->get_solution().to_str(), "{\n X -> a,\n Y -> b\n}"); //BOOST_REQUIRE(and1->next_solution());
BOOST_REQUIRE(and1->next_solution()); //BOOST_CHECK_EQUAL(and1->get_solution().to_str(), "{\n X -> a,\n Y -> b\n}");
BOOST_CHECK_EQUAL(and1->get_solution().to_str(), "{\n X -> a,\n Y -> c\n}"); //BOOST_REQUIRE(and1->next_solution());
BOOST_REQUIRE(not and1->next_solution()); //BOOST_CHECK_EQUAL(and1->get_solution().to_str(), "{\n X -> a,\n Y -> c\n}");
delete and1; //BOOST_REQUIRE(and1->next_solution());
} //BOOST_CHECK_EQUAL(and1->get_solution().to_str(), "{\n X -> d,\n Y -> a\n}");
//BOOST_REQUIRE(not and1->next_solution());
//delete and1;
//}
...@@ -233,8 +233,8 @@ BOOST_AUTO_TEST_CASE(substitution_test) ...@@ -233,8 +233,8 @@ BOOST_AUTO_TEST_CASE(substitution_test)
Predicate p4("q", "Y"); Predicate p4("q", "Y");
Predicate p5("q", "Z"); Predicate p5("q", "Z");
Predicate p6("r"); Predicate p6("r");
Substitution sigma({{"X", T("a")}, {"Y", T("b")}}); Substitution sigma{{"X", T("a")}, {"Y", T("b")}};
Substitution sigma_({{"W", T("c")}}); Substitution sigma_{{"W", T("c")}};
INFO("p1 = " << p1); INFO("p1 = " << p1);
INFO("p2 = " << p2); INFO("p2 = " << p2);
INFO("p3 = " << p3); INFO("p3 = " << p3);
...@@ -260,7 +260,7 @@ BOOST_AUTO_TEST_CASE(substitution_test) ...@@ -260,7 +260,7 @@ BOOST_AUTO_TEST_CASE(substitution_test)
BOOST_AUTO_TEST_CASE(planstate_test) BOOST_AUTO_TEST_CASE(planstate_test)
{ {
PlanState state({Predicate("p", "x", "y"), Predicate("q", "y"), Predicate("r")}); PlanState state{Predicate("p", "x", "y"), Predicate("q", "y"), Predicate("r")};
PlanState state_(state), state__(state); PlanState state_(state), state__(state);
PlanState state2(state); PlanState state2(state);
state__.remove(Predicate("p", "x", "y")); state__.remove(Predicate("p", "x", "y"));
...@@ -278,3 +278,17 @@ BOOST_AUTO_TEST_CASE(planstate_test) ...@@ -278,3 +278,17 @@ BOOST_AUTO_TEST_CASE(planstate_test)
BOOST_CHECK(not state2.subset_of(state)); BOOST_CHECK(not state2.subset_of(state));
} }
BOOST_AUTO_TEST_CASE(goal_condition)
{
PlanState state{Predicate("p", "x", "y"), Predicate("q", "y"), Predicate("r")};
GoalCondition goal_condition1({Predicate("q", "y")}, {Predicate("p", "x", "y")});
GoalCondition goal_condition2({Predicate("q", "y")}, {Predicate("q", "x")});
GoalCondition goal_condition3({Predicate("r")}, {});
INFO("goal_condition1: " << goal_condition1);
INFO("goal_condition2: " << goal_condition2);
INFO("goal_condition3: " << goal_condition3);
BOOST_CHECK(not goal_condition1(state));
BOOST_CHECK(goal_condition2(state));
BOOST_CHECK(goal_condition3(state));
}
...@@ -3,284 +3,289 @@ ...@@ -3,284 +3,289 @@
namespace imagine_planner namespace imagine_planner
{ {
// ComparisonQuery methods // Query members
ComparisonQuery::ComparisonQuery(const PlanState&, const Predicate& op,
const Substitution& sigma0) : op_(op), sigma0_(sigma0) {}
std::string ComparisonQuery::to_str() const bool Query::exists(const PlanState& state, const Substitution& sigma0) const
{ {
return op_.to_str(); std::vector<Substitution> dont_care;
return (*this)(state, dont_care, sigma0);
} }
bool ComparisonQuery::next_solution() // ComparisonQuery methods
ComparisonQuery::ComparisonQuery(const Predicate& cmp) : cmp_(cmp)
{ {
if (done_) return false; if (cmp.arity() != 2)
done_ = true; {
Predicate op_sub = sigma0_(op_); throw ImaginePlannerException("Arity of comparison query should be 2");
if (not op_sub.is_ground() or op_sub.arity() != 2) return false; }
const TermWrapper& arg1 = op_sub.get_arguments()[0]; std::string op = cmp.get_name();
const TermWrapper& arg2 = op_sub.get_arguments()[1]; if (op != "<" and op != "<=" and op != "==" and
if (op_sub.get_name() == "==") return arg1 == arg2; op != ">" and op != ">=" and op != "!=")
else if (op_sub.get_name() == "!=") return arg1 != arg2; {
else if (op_sub.get_name() == "<") return arg1 < arg2; throw ImaginePlannerException("Non valid comparison");
else if (op_sub.get_name() == ">") return arg1 > arg2; }
else if (op_sub.get_name() == "=<") return arg1 <= arg2;
else if (op_sub.get_name() == ">=") return arg1 >= arg2;
return false;
} }
void ComparisonQuery::reset(const Substitution& sigma0)
std::string ComparisonQuery::to_str() const
{ {
sigma0_ = sigma0; const Term::Ptr& arg1 = cmp_.get_arguments()[0];
done_ = false; const Term::Ptr& arg2 = cmp_.get_arguments()[1];
return arg1->to_str() + cmp_.get_name() + arg2->to_str();
} }
// Simple query methods bool ComparisonQuery::operator()(const PlanState& state,
std::vector<Substitution>& results, const Substitution& sigma0) const
bool SimpleQuery::unify(const Predicate& goal)
{ {
if (goal.arity() != pattern_.arity()) return false; bool ans = false;
if (goal.get_name() != pattern_.get_name()) return false; Predicate cmp = sigma0(cmp_);
sigma_ = sigma0_; if (cmp.is_ground())
for (int idx = 0; idx < goal.arity(); ++idx)
{ {
const TermWrapper& term1 = pattern_.get_arguments()[idx]; const Term& arg1 = *cmp.get_arguments()[0];
const TermWrapper& term2 = goal.get_arguments()[idx]; const Term& arg2 = *cmp.get_arguments()[1];
if (term1.is_ground()) std::string op = cmp.get_name();
{ if (op == "==") ans = arg1 == arg2;
if (term1 != term2) return false; else if (op == "!=") ans = arg1 != arg2;
} else if (op == "<") ans = arg1 < arg2;
else if (const Term* assig = sigma_.get(term1.to_str())) else if (op == ">") ans = arg1 > arg2;
{ else if (op == "=<") ans = arg1 <= arg2;
if (*assig != *term2.get_term()) return false; else ans = arg1 >= arg2; // op = ">="
}
else
{
sigma_.put(term1.to_str(), term2);
}
} }
return true; if (ans) results.push_back(sigma0);
return ans;
} }
SimpleQuery::SimpleQuery(const PlanState& state, const Predicate& pattern,
const Substitution& sigma0) : // Simple query methods
state_(state), pattern_(pattern), sigma0_(sigma0)
{
cursor_ = state_.begin();
}
std::string SimpleQuery::to_str() const std::string SimpleQuery::to_str() const
{ {
return pattern_.to_str(); return pattern_.to_str();
} }
bool SimpleQuery::next_solution() bool SimpleQuery::operator()(const PlanState& state,
std::vector<Substitution>& results, const Substitution& sigma0) const
{ {
if (cursor_ != state_.end() and pattern_.is_ground()) bool found = false;
for (const Predicate& p : state)
{ {
cursor_ = state_.end(); Substitution sigma(sigma0);
return state_.has(pattern_); if (unify(p, sigma))
{
results.push_back(std::move(sigma));
found = true;
}
} }
return found;
}
while (cursor_ != state_.end()) bool SimpleQuery::unify(const Predicate& goal, Substitution& sigma) const
{
if (goal.arity() != pattern_.arity()) return false;
if (goal.get_name() != pattern_.get_name()) return false;
for (int idx = 0; idx < goal.arity(); ++idx)
{ {
if (unify(*cursor_)) const Term::Ptr& term1 = pattern_.get_arguments()[idx];
const Term::Ptr& term2 = goal.get_arguments()[idx];
if (term1->is_ground())
{
if (*term1 != *term2) return false;
}
else if (Term::Ptr assig = sigma.get(term1->to_str()))
{ {
++cursor_; if (*assig != *term2) return false;
return true; }
else
{
sigma.put(term1->to_str(), term2);
} }
++cursor_;
} }
return false; return true;
} }
void SimpleQuery::reset(const Substitution& sigma0)
{
sigma0_ = sigma0;
cursor_ = state_.begin();
}
// NotQuery methods // NotQuery methods
NotQuery::NotQuery(Query* q) : query_(q), done_(false) {}
std::string NotQuery::to_str() const std::string NotQuery::to_str() const
{ {
if (dynamic_cast<const AndQuery*>(query_)) if (std::dynamic_pointer_cast<const AndQuery>(query_))
{ {
return std::string("\\+(") + query_->to_str() + ')'; return std::string("\\+(") + query_->to_str() + ')';
} }
return std::string("\\+") + query_->to_str(); return std::string("\\+") + query_->to_str();
} }
bool NotQuery::next_solution() bool NotQuery::operator()(const PlanState& state,
{ std::vector<Substitution>& results, const Substitution& sigma0) const
if (done_) return false;
done_ = true;
return not query_->next_solution();
}
void NotQuery::reset(const Substitution& sigma0)
{ {
query_->reset(sigma0); bool ans = not query_->exists(state);
done_ = false; if (ans) results.push_back(sigma0);
return ans;
} }
NotQuery::~NotQuery()
{
delete query_;
}
// AndQuery methods // AndQuery methods
AndQuery::AndQuery(Query* q1, Query* q2) :
q1_(q1), q2_(q2), first_fixed_(false) {}
std::string AndQuery::to_str() const std::string AndQuery::to_str() const
{ {
return q1_->to_str() + ',' + q2_->to_str(); return q1_->to_str() + ',' + q2_->to_str();
} }
bool AndQuery::next_solution() bool AndQuery::operator()(const PlanState& state,
{ std::vector<Substitution>& results, const Substitution& sigma0) const
if (first_fixed_ and q2_->next_solution())
{
return true;
}
first_fixed_ = false;
while (q1_->next_solution())
{
q2_->reset(q1_->get_solution());
if (q2_->next_solution())
{
first_fixed_ = true;
return true;
}
}
return false;
}
AndQuery::~AndQuery()
{
delete q1_;
delete q2_;
}
// ComparisonQuerySpecification methods
std::string ComparisonQuerySpecification::to_str() const
{
return op_.to_str();
}
ComparisonQuerySpecification::ComparisonQuerySpecification(
const Predicate& op) : op_(op) {}
Query* ComparisonQuerySpecification::operator()(const PlanState& state,
const Substitution& sigma0) const
{
return new ComparisonQuery(state, op_, sigma0);
}
// SimpleQuerySpecification methods
std::string SimpleQuerySpecification::to_str() const
{
return pattern_.to_str();
}
SimpleQuerySpecification::SimpleQuerySpecification(const Predicate& pattern)
: pattern_(pattern) {}
Query* SimpleQuerySpecification::operator()(const PlanState& state,
const Substitution& sigma0) const
{
return new SimpleQuery(state, pattern_, sigma0);
}
// NotQuerySpecification methods
void NotQuerySpecification::copy_other(const NotQuerySpecification& other)
{
query_ = other.query_->clone();
}
NotQuerySpecification::NotQuerySpecification(const NotQuerySpecification& other)
{
copy_other(other);
}
NotQuerySpecification::NotQuerySpecification(QuerySpecification* query)
: query_(query) {}
NotQuerySpecification& NotQuerySpecification::operator=(
const NotQuerySpecification& other)
{
copy_other(other);
return *this;
}
std::string NotQuerySpecification::to_str() const
{ {
if (dynamic_cast<const AndQuerySpecification*>(query_)) bool ans = false;
std::vector<Substitution> results1;
(*q1_)(state, results1, sigma0);
for (const Substitution& sigma1 : results1)
{ {
return std::string("\\+(") + query_->to_str() + ')'; std::vector<Substitution> results2;
ans = ans or (*q2_)(state, results2, sigma1);
} }
return std::string("\\+") + query_->to_str(); return ans;
} }
Query* NotQuerySpecification::operator()(const PlanState& state, //bool AndQuery::next_solution()
const Substitution& sigma0) const //{
{ //if (first_fixed_ and q2_->next_solution())
return new NotQuery((*query_)(state, sigma0)); //{
} //return true;
//}
NotQuerySpecification::~NotQuerySpecification() //first_fixed_ = false;
{ //while (q1_->next_solution())
delete query_; //{
} //q2_->reset(q1_->get_solution());
//if (q2_->next_solution())
// AndQuerySpecification methods //{
//first_fixed_ = true;
void AndQuerySpecification::copy_other(const AndQuerySpecification& other) //return true;