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

refactored queries

parent 4e1e85eb
# 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
SET(headers types.h) # queries.h effects.h domains.h parsing.h imagine-planner.h)
# Ades
......
......@@ -17,70 +17,107 @@ using namespace imagine_planner;
#define INFO(x)
#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)
{
PlanState state({Predicate("p","a","b"), Predicate("p","a","c"),
Predicate("p","d","a"), Predicate("q","w"), Predicate("q", "s")});
INFO(state);
SimpleQuery q1(state, Predicate("p", "a", "X"));
SimpleQuery q2(state, Predicate("q", "w"));
INFO("q1: " << q1 << ", " << q2);
BOOST_REQUIRE(q1.next_solution());
BOOST_CHECK_EQUAL(q1.get_solution().to_str(), "{\n X -> b\n}");
BOOST_REQUIRE(q1.next_solution());
BOOST_CHECK_EQUAL(q1.get_solution().to_str(), "{\n X -> c\n}");
BOOST_REQUIRE(not q1.next_solution());
BOOST_REQUIRE(q2.next_solution());
BOOST_CHECK_EQUAL(q2.get_solution().to_str(), "{}");
BOOST_CHECK(not q1.next_solution());
SimpleQuery q1(Predicate("p", "a", "X"));
SimpleQuery q2(Predicate("q", "w"));
INFO("q1: " << q1 << ", q2: " << q2);
std::vector<Substitution> results1, results2;
q1(state, results1);
BOOST_REQUIRE_EQUAL(results1.size(), 2);
BOOST_CHECK_EQUAL(results1[0].to_str(), "{\n X -> b\n}");
BOOST_CHECK_EQUAL(results1[1].to_str(), "{\n X -> c\n}");
q2(state, results2);
BOOST_REQUIRE_EQUAL(results2.size(), 1);
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"),
Predicate("p","d","a"), Predicate("q","w"), Predicate("q", "s")});
INFO(state);
SimpleQuery q1(state, Predicate("p", "c", "X"));
SimpleQuery q2(state, Predicate("p", "a", "d"));
INFO("q1: " << q1 << ", " << q2);
BOOST_REQUIRE(not q1.next_solution());
BOOST_REQUIRE(not q2.next_solution());
Query::Ptr q1 = std::make_shared<SimpleQuery>(Predicate("p", "a", "X"));
Query::Ptr q1_ = std::make_shared<SimpleQuery>(Predicate("p", "Z", "d"));
NotQuery q2(q1);
NotQuery q2_(q1_);
INFO("q2: " << q2 << ", q2_: " << q2_);
BOOST_CHECK(not q2.exists(state));
BOOST_CHECK(q2_.exists(state));
}
BOOST_AUTO_TEST_CASE(and_query_test_sat)
{
PlanState state({Predicate("p","a","b"), Predicate("p","a","c"),
Predicate("p", "b", "d"), Predicate("p","d","a"), Predicate("q","b")});
INFO("state: " << state);
SimpleQuery* q1 = new SimpleQuery(state, Predicate("p", "X", "Y"));
SimpleQuery* q2 = new SimpleQuery(state, Predicate("q", "X"));
NotQuery* not1 = new NotQuery(q2);
AndQuery* and1 = new AndQuery(q1, not1);
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(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(simple_query_test_unsat)
//{
//PlanState state({Predicate("p","a","b"), Predicate("p","a","c"),
//Predicate("p","d","a"), Predicate("q","w"), Predicate("q", "s")});
//INFO(state);
//SimpleQuery q1(state, Predicate("p", "c", "X"));
//SimpleQuery q2(state, Predicate("p", "a", "d"));
//INFO("q1: " << q1 << ", " << q2);
//BOOST_REQUIRE(not q1.next_solution());
//BOOST_REQUIRE(not q2.next_solution());
//}
BOOST_AUTO_TEST_CASE(comparison_query_test_sat)
{
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(and_query_test_sat)
//{
//PlanState state({Predicate("p","a","b"), Predicate("p","a","c"),
//Predicate("p", "b", "d"), Predicate("p","d","a"), Predicate("q","b")});
//INFO("state: " << state);
//SimpleQuery* q1 = new SimpleQuery(state, Predicate("p", "X", "Y"));
//SimpleQuery* q2 = new SimpleQuery(state, Predicate("q", "X"));
//NotQuery* not1 = new NotQuery(q2);
//AndQuery* and1 = new AndQuery(q1, not1);
//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(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)
Predicate p4("q", "Y");
Predicate p5("q", "Z");
Predicate p6("r");
Substitution sigma({{"X", T("a")}, {"Y", T("b")}});
Substitution sigma_({{"W", T("c")}});
Substitution sigma{{"X", T("a")}, {"Y", T("b")}};
Substitution sigma_{{"W", T("c")}};
INFO("p1 = " << p1);
INFO("p2 = " << p2);
INFO("p3 = " << p3);
......@@ -260,7 +260,7 @@ BOOST_AUTO_TEST_CASE(substitution_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 state2(state);
state__.remove(Predicate("p", "x", "y"));
......@@ -278,3 +278,17 @@ BOOST_AUTO_TEST_CASE(planstate_test)
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 @@
namespace imagine_planner
{
// ComparisonQuery methods
ComparisonQuery::ComparisonQuery(const PlanState&, const Predicate& op,
const Substitution& sigma0) : op_(op), sigma0_(sigma0) {}
// Query members
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;
done_ = true;
Predicate op_sub = sigma0_(op_);
if (not op_sub.is_ground() or op_sub.arity() != 2) return false;
const TermWrapper& arg1 = op_sub.get_arguments()[0];
const TermWrapper& arg2 = op_sub.get_arguments()[1];
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;
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;
if (cmp.arity() != 2)
{
throw ImaginePlannerException("Arity of comparison query should be 2");
}
std::string op = cmp.get_name();
if (op != "<" and op != "<=" and op != "==" and
op != ">" and op != ">=" and op != "!=")
{
throw ImaginePlannerException("Non valid comparison");
}
}
void ComparisonQuery::reset(const Substitution& sigma0)
std::string ComparisonQuery::to_str() const
{
sigma0_ = sigma0;
done_ = false;
const Term::Ptr& arg1 = cmp_.get_arguments()[0];
const Term::Ptr& arg2 = cmp_.get_arguments()[1];
return arg1->to_str() + cmp_.get_name() + arg2->to_str();
}
// Simple query methods
bool SimpleQuery::unify(const Predicate& goal)
bool ComparisonQuery::operator()(const PlanState& state,
std::vector<Substitution>& results, const Substitution& sigma0) const
{
if (goal.arity() != pattern_.arity()) return false;
if (goal.get_name() != pattern_.get_name()) return false;
sigma_ = sigma0_;
for (int idx = 0; idx < goal.arity(); ++idx)
bool ans = false;
Predicate cmp = sigma0(cmp_);
if (cmp.is_ground())
{
const TermWrapper& term1 = pattern_.get_arguments()[idx];
const TermWrapper& term2 = goal.get_arguments()[idx];
if (term1.is_ground())
{
if (term1 != term2) return false;
}
else if (const Term* assig = sigma_.get(term1.to_str()))
{
if (*assig != *term2.get_term()) return false;
}
else
{
sigma_.put(term1.to_str(), term2);
}
const Term& arg1 = *cmp.get_arguments()[0];
const Term& arg2 = *cmp.get_arguments()[1];
std::string op = cmp.get_name();
if (op == "==") ans = arg1 == arg2;
else if (op == "!=") ans = arg1 != arg2;
else if (op == "<") ans = arg1 < arg2;
else if (op == ">") ans = arg1 > arg2;
else if (op == "=<") ans = arg1 <= arg2;
else ans = arg1 >= arg2; // op = ">="
}
return true;
if (ans) results.push_back(sigma0);
return ans;
}
SimpleQuery::SimpleQuery(const PlanState& state, const Predicate& pattern,
const Substitution& sigma0) :
state_(state), pattern_(pattern), sigma0_(sigma0)
{
cursor_ = state_.begin();
}
// Simple query methods
std::string SimpleQuery::to_str() const
{
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();
return state_.has(pattern_);
Substitution sigma(sigma0);
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_;
return true;
if (*assig != *term2) return false;
}
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::NotQuery(Query* q) : query_(q), done_(false) {}
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();
}
bool NotQuery::next_solution()
{
if (done_) return false;
done_ = true;
return not query_->next_solution();
}
void NotQuery::reset(const Substitution& sigma0)
bool NotQuery::operator()(const PlanState& state,
std::vector<Substitution>& results, const Substitution& sigma0) const
{
query_->reset(sigma0);
done_ = false;
bool ans = not query_->exists(state);
if (ans) results.push_back(sigma0);
return ans;
}
NotQuery::~NotQuery()
{
delete query_;
}
// AndQuery methods
AndQuery::AndQuery(Query* q1, Query* q2) :
q1_(q1), q2_(q2), first_fixed_(false) {}
std::string AndQuery::to_str() const
{
return q1_->to_str() + ',' + q2_->to_str();
}
bool AndQuery::next_solution()
{
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
bool AndQuery::operator()(const PlanState& state,
std::vector<Substitution>& results, const Substitution& sigma0) 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();
}
Query* NotQuerySpecification::operator()(const PlanState& state,
const Substitution& sigma0) const
{
return new NotQuery((*query_)(state, sigma0));
}
NotQuerySpecification::~NotQuerySpecification()
{
delete query_;
}
// AndQuerySpecification methods
void AndQuerySpecification::copy_other(const AndQuerySpecification& other)
{
q1_ = other.q1_->clone();
q2_ = other.q2_->clone();
}
AndQuerySpecification::AndQuerySpecification(const AndQuerySpecification& other)
{
copy_other(other);
}
AndQuerySpecification& AndQuerySpecification::operator=(
const AndQuerySpecification& other)
{
copy_other(other);
return *this;
}
AndQuerySpecification::AndQuerySpecification(QuerySpecification* q1,
QuerySpecification* q2) : q1_(q1), q2_(q2) {}
std::string AndQuerySpecification::to_str() const
{
return q1_->to_str() + ',' + q2_->to_str();
}
Query* AndQuerySpecification::operator()(const PlanState& state,
const Substitution& sigma0) const
{
return new AndQuery((*q1_)(state, sigma0), (*q2_)(state, sigma0));
}
AndQuerySpecification::~AndQuerySpecification()
{
delete q1_;
delete q2_;
}
return ans;
}
//bool AndQuery::next_solution()
//{
//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();