/*
* BackwardChainerUTest.cxxtest
*
* Created on: Oct 20, 2014
* Authors: misgana
^ : Nil Geisweiller (2015-2016)
*/
#include <opencog/ure/backwardchainer/BackwardChainer.h>
#include <opencog/guile/SchemeEval.h>
#include <opencog/atomspace/AtomSpace.h>
#include <opencog/atoms/pattern/PatternLink.h>
#include <opencog/util/mt19937ar.h>
#include <opencog/ure/URELogger.h>
#include <cxxtest/TestSuite.h>
using namespace std;
using namespace opencog;
//#define DEBUG 1
#define al _as->add_link
#define an _as->add_node
class BackwardChainerUTest: public CxxTest::TestSuite
{
private:
AtomSpacePtr _as;
SchemeEval _eval;
BackwardChainer* _bc;
string load_from_path(const string& filename);
void reset_bc();
public:
BackwardChainerUTest();
~BackwardChainerUTest();
void setUp();
void tearDown();
void test_select_rule_1();
void test_select_rule_2();
void test_select_rule_3();
void test_deduction();
void test_deduction_tv_query();
void test_modus_ponens_tv_query();
void test_conjunction_fuzzy_evaluation_tv_query();
void test_conditional_instantiation_1();
void test_conditional_instantiation_2();
void test_conditional_instantiation_tv_query();
void test_conditional_partial_instantiation();
void test_impossible_criminal();
void test_criminal();
void test_no_exec_output();
// TODO: re-enable when GlobNode is supported
void xtest_green_balls();
// TODO: re-enable when meta rule is supported
void xtest_induction();
// TODO: re-enable when focus set is supported (if ever)
void xtest_focus_set();
};
BackwardChainerUTest::BackwardChainerUTest() : _as(createAtomSpace()),_eval(_as)
{
logger().set_level(Logger::DEBUG);
logger().set_timestamp_flag(false);
// logger().set_sync_flag(true);
logger().set_print_to_stdout_flag(true);
ure_logger().set_level(Logger::INFO);
ure_logger().set_timestamp_flag(false);
// ure_logger().set_sync_flag(true);
ure_logger().set_print_to_stdout_flag(true);
randGen().seed(0);
string cur_ppp_dir = string(PROJECT_SOURCE_DIR),
cur_pp_dir = cur_ppp_dir + "/tests",
cur_p_dir = cur_pp_dir + "/ure",
cur_dir = cur_p_dir + "/backwardchainer",
scm_dir = cur_dir + "/scm";
vector<string> load_paths = {cur_ppp_dir,
cur_pp_dir,
cur_p_dir,
cur_dir,
scm_dir};
for (string& p : load_paths)
{
string eval_str = string("(add-to-load-path \"") + p + string("\")");
_eval.eval(eval_str);
}
_eval.eval("(use-modules (opencog))");
_eval.eval("(use-modules (opencog ure))");
_eval.eval("(use-modules (opencog logger))");
}
BackwardChainerUTest::~BackwardChainerUTest()
{
delete _bc;
}
void BackwardChainerUTest::setUp()
{
}
void BackwardChainerUTest::tearDown()
{
_as->clear();
}
string BackwardChainerUTest::load_from_path(const string& filename)
{
return _eval.eval((string("(load-from-path \"") + filename + "\")").c_str());
}
void BackwardChainerUTest::reset_bc()
{
delete(_bc);
string eval_result = load_from_path("bc-config.scm");
// std::cout << "eval_result = " << eval_result << std::endl;
Handle top_rbs = _as->get_node(CONCEPT_NODE,
std::move(std::string(UREConfig::top_rbs_name)));
_bc = new BackwardChainer(*_as.get(), top_rbs, Handle::UNDEFINED);
}
// Test select rule with a target with no variable
void BackwardChainerUTest::test_select_rule_1()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
// TODO: move that in setUp
reset_bc();
Handle target_h = _eval.eval_h("(Inheritance"
" (Concept \"A\")"
" (Concept \"B\"))");
BITNode target(target_h);
AndBIT andbit;
RuleSelection selected_rule =
_bc->_control.select_rule(andbit, target);
TS_ASSERT_EQUALS(selected_rule.first.first.get_name(), "bc-deduction-rule");
}
// Test select rule with a target with variables
void BackwardChainerUTest::test_select_rule_2()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
reset_bc();
Handle target_h = _eval.eval_h("(Inheritance"
" (Concept \"A\")"
" (Variable \"$X\"))");
BITNode target(target_h);
AndBIT andbit;
RuleSelection selected_rule =
_bc->_control.select_rule(andbit, target);
TS_ASSERT_EQUALS(selected_rule.first.first.get_name(), "bc-deduction-rule");
}
// Test select rule with a target with variables with the same name as
// the variable in the rule.
void BackwardChainerUTest::test_select_rule_3()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
reset_bc();
Handle target_h = _eval.eval_h("(Variable \"$C\")"),
vardecl_h = _eval.eval_h("(TypedVariable"
" (Variable \"$C\")"
" (Type \"InheritanceLink\"))");
BITNode target(target_h);
AndBIT andbit(*_as.get(), target_h, vardecl_h);
RuleSelection selected_rule =
_bc->_control.select_rule(andbit, target);
TS_ASSERT_EQUALS(selected_rule.first.first.get_name(), "bc-deduction-rule");
}
void BackwardChainerUTest::test_deduction()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
load_from_path("bc-deduction-config.scm");
load_from_path("bc-transitive-closure.scm");
randGen().seed(0);
Handle top_rbs = _as->get_node(CONCEPT_NODE,
std::move(std::string(UREConfig::top_rbs_name)));
Handle X = an(VARIABLE_NODE, "$X"),
D = an(CONCEPT_NODE, "D"),
target = al(INHERITANCE_LINK, X, D);
BackwardChainer bc(*_as.get(), top_rbs, target);
bc.get_config().set_maximum_iterations(10);
bc.do_chain();
Handle results = bc.get_results(),
A = an(CONCEPT_NODE, "A"),
B = an(CONCEPT_NODE, "B"),
C = an(CONCEPT_NODE, "C"),
CD = al(INHERITANCE_LINK, C, D),
BD = al(INHERITANCE_LINK, B, D),
AD = al(INHERITANCE_LINK, A, D),
expected = al(SET_LINK, CD, BD, AD);
logger().debug() << "results = " << results->to_string();
logger().debug() << "expected = " << expected->to_string();
TS_ASSERT_EQUALS(results, expected);
}
void BackwardChainerUTest::test_deduction_tv_query()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
load_from_path("bc-deduction-config.scm");
load_from_path("bc-transitive-closure.scm");
randGen().seed(0);
Handle top_rbs = _as->get_node(CONCEPT_NODE,
std::move(std::string(UREConfig::top_rbs_name)));
Handle target = _eval.eval_h("(Inheritance"
" (Concept \"A\")"
" (Concept \"D\"))");
BackwardChainer bc(*_as.get(), top_rbs, target);
bc.get_config().set_maximum_iterations(10);
bc.do_chain();
TS_ASSERT_DELTA(TruthValueCast(target->getValue(truth_key()))->get_mean(), 1, 1e-10);
TS_ASSERT_DELTA(TruthValueCast(target->getValue(truth_key()))->get_confidence(), 1, 1e-10);
}
void BackwardChainerUTest::test_modus_ponens_tv_query()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
load_from_path("bc-modus-ponens-config.scm");
load_from_path("modus-ponens-example.scm");
randGen().seed(0);
Handle top_rbs = _as->get_node(CONCEPT_NODE,
std::move(std::string(UREConfig::top_rbs_name)));
Handle target = an(PREDICATE_NODE, "T");
BackwardChainer bc(*_as.get(), top_rbs, target);
bc.get_config().set_maximum_iterations(40);
bc.do_chain();
TS_ASSERT_DELTA(TruthValueCast(target->getValue(truth_key()))->get_mean(), 1, 1e-10);
TS_ASSERT_DELTA(TruthValueCast(target->getValue(truth_key()))->get_confidence(), 1, 1e-10);
}
void BackwardChainerUTest::test_conjunction_fuzzy_evaluation_tv_query()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
string result = load_from_path("fuzzy-conjunction-introduction-config.scm");
logger().debug() << "result = " << result;
result = load_from_path("simple-conjunction.scm");
randGen().seed(0);
Handle top_rbs = _as->get_node(CONCEPT_NODE,
std::move(std::string(UREConfig::top_rbs_name)));
Handle P = an(PREDICATE_NODE, "P"),
Q = an(PREDICATE_NODE, "Q"),
A = an(CONCEPT_NODE, "A"),
B = an(CONCEPT_NODE, "B"),
P_A = al(EVALUATION_LINK, P, A),
Q_B = al(EVALUATION_LINK, Q, B),
target = al(AND_LINK, P_A, Q_B);
BackwardChainer bc(*_as.get(), top_rbs, target);
bc.get_config().set_maximum_iterations(2);
bc.do_chain();
TS_ASSERT_DELTA(TruthValueCast(target->getValue(truth_key()))->get_mean(), 0.4, 1e-6);
TS_ASSERT_DELTA(TruthValueCast(target->getValue(truth_key()))->get_confidence(), 0.2, 1e-6);
}
void BackwardChainerUTest::test_conditional_instantiation_1()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
string result = load_from_path("conditional-instantiation-config.scm");
logger().debug() << "result = " << result;
result = load_from_path("friends.scm");
randGen().seed(0);
Handle top_rbs = _as->get_node(CONCEPT_NODE,
std::move(std::string(UREConfig::top_rbs_name)));
Handle are_friends = an(PREDICATE_NODE, "are-friends"),
john = an(CONCEPT_NODE, "John"),
mary = an(CONCEPT_NODE, "Mary"),
edward = an(CONCEPT_NODE, "Edward"),
cyril = an(CONCEPT_NODE, "Cyril");
auto friend_with_john = [&](const Handle& h) {
return al(EVALUATION_LINK, are_friends, al(LIST_LINK, h, john));
};
Handle target_var = an(VARIABLE_NODE, "$who"),
target = friend_with_john(target_var),
vardecl = al(VARIABLE_LIST,
al(TYPED_VARIABLE_LINK,
target_var, an(TYPE_NODE, "ConceptNode")));
BackwardChainer bc(*_as.get(), top_rbs, target, vardecl);
bc.get_config().set_maximum_iterations(500);
bc.do_chain();
Handle results = bc.get_results(),
expected = al(SET_LINK,
friend_with_john(mary),
friend_with_john(edward),
friend_with_john(cyril));
logger().debug() << "results = " << results->to_string();
logger().debug() << "expected = " << expected->to_string();
TS_ASSERT_EQUALS(results, expected);
}
void BackwardChainerUTest::test_conditional_instantiation_2()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
string result = load_from_path("conditional-instantiation-config.scm");
logger().debug() << "result = " << result;
load_from_path("animals.scm");
randGen().seed(0);
Handle top_rbs = _as->get_node(CONCEPT_NODE,
std::move(std::string(UREConfig::top_rbs_name)));
Handle green = an(CONCEPT_NODE, "green"),
Fritz = an(CONCEPT_NODE, "Fritz"),
what = an(VARIABLE_NODE, "$what"),
target = al(INHERITANCE_LINK, what, green),
concept = an(TYPE_NODE, "ConceptNode"),
vardecl = al(TYPED_VARIABLE_LINK, what, concept);
BackwardChainer bc(*_as.get(), top_rbs, target, vardecl);
bc.get_config().set_maximum_iterations(20);
bc.do_chain();
Handle results = bc.get_results(),
expected = al(SET_LINK, al(INHERITANCE_LINK, Fritz, green));
logger().debug() << "results = " << results->to_string();
logger().debug() << "expected = " << expected->to_string();
TS_ASSERT_EQUALS(results, expected);
}
void BackwardChainerUTest::test_conditional_instantiation_tv_query()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
load_from_path("conditional-instantiation-config.scm");
load_from_path("animals.scm");
randGen().seed(500);
Handle top_rbs = _as->get_node(CONCEPT_NODE,
std::move(std::string(UREConfig::top_rbs_name)));
Handle target =
_eval.eval_h("(InheritanceLink"
" (ConceptNode \"Fritz\")"
" (ConceptNode \"green\"))");
BackwardChainer bc(*_as.get(), top_rbs, target);
bc.get_config().set_maximum_iterations(20);
bc.do_chain();
TS_ASSERT_DELTA(TruthValueCast(target->getValue(truth_key()))->get_mean(), 1, .1);
TS_ASSERT_DELTA(TruthValueCast(target->getValue(truth_key()))->get_confidence(), 1, .1);
}
// This test is for rules that requires the pattern matcher to look
// inside a variable declaration, to for instance extract the type of
// some variable. For instance if you have the grounded data
//
// ImplicationScopeLink
// VariableList
// TypedVariable
// Variable "$X"
// Type "ConceptNode"
// TypedVariable
// Variable "$Y"
// Type "PredicateNode"
// <implicant>
// <implicand>
//
// the conditional-partial-instantiation-meta-rule will want to look
// inside the scope link's vardecl and know that $X is of type
// ConceptNode and $Y is of type PredicateNode. In order to do that it
// requires to write a pattern describing the variable declaration,
// thus having the type itself be a variable, like
//
// BindLink
// VariableSet
// TypedVariable
// Variable "$XVar"
// Type "VariableNode"
// TypedVariable
// Variable "$XType"
// Type "TypeNode"
// Quote
// ScopeLink
// Unquote
// VariableList
// TypedVariable
// Variable "$XVar"
// Variable "$XType"
// ...
void BackwardChainerUTest::test_conditional_partial_instantiation()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
string result = load_from_path("conditional-partial-instantiation-config.scm");
logger().debug() << "result = " << result;
result = load_from_path("friends.scm");
randGen().seed(0);
Handle top_rbs = _as->get_node(CONCEPT_NODE,
std::move(std::string(UREConfig::top_rbs_name)));
Handle target = _eval.eval_h("(ImplicationScope"
" (TypedVariable"
" (Variable \"$X\")"
" (Type \"ConceptNode\"))"
" (And"
" (Evaluation"
" (Predicate \"are-friends\")"
" (List"
" (Variable \"$X\")"
" (Concept \"John\")))"
" (Evaluation"
" (Predicate \"are-friends\")"
" (List"
" (Concept \"John\")"
" (Concept \"Mary\")))"
" (Evaluation"
" (Predicate \"is-musician\")"
" (Variable \"$X\"))"
" (Evaluation"
" (Predicate \"is-musician\")"
" (Concept \"John\"))"
" (Evaluation"
" (Predicate \"is-musician\")"
" (Concept \"Mary\")))"
" (Evaluation"
" (Predicate \"are-friends\")"
" (List"
" (Variable \"$X\")"
" (Concept \"Mary\"))))");
BackwardChainer bc(*_as.get(), top_rbs, target);
bc.get_config().set_maximum_iterations(5);
bc.do_chain();
TS_ASSERT_DELTA(TruthValueCast(target->getValue(truth_key()))->get_mean(), 1, 1e-10);
TS_ASSERT_DELTA(TruthValueCast(target->getValue(truth_key()))->get_confidence(), 1, 1e-10);
}
void BackwardChainerUTest::test_impossible_criminal()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
load_from_path("bc-criminal-without-deduction-config.scm");
load_from_path("criminal.scm");
randGen().seed(0);
Handle top_rbs = _as->get_node(CONCEPT_NODE,
std::move(std::string(UREConfig::top_rbs_name)));
Handle target =
_eval.eval_h("(InheritanceLink"
" (VariableNode \"$who\")"
" (ConceptNode \"criminal\"))");
Handle vardecl =
_eval.eval_h("(TypedVariable"
" (VariableNode \"$who\")"
" (Type \"ConceptNode\"))");
Handle soln = _eval.eval_h("(ConceptNode \"West\")");
// Should NOT be possible to find the solution without deduction
// rule, as it won't be able to tell that missile@123 is a weapon.
BackwardChainer bc(*_as.get(), top_rbs, target, vardecl);
// See bc-criminal-config.scm to change the number of iterations
bc.do_chain();
Handle results = bc.get_results(),
expected = al(SET_LINK, HandleSeq());
logger().debug() << "results = " << results->to_string();
logger().debug() << "expected = " << expected->to_string();
TS_ASSERT_EQUALS(results, expected);
}
void BackwardChainerUTest::test_criminal()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
load_from_path("bc-criminal-config.scm");
load_from_path("criminal.scm");
randGen().seed(0);
Handle top_rbs = _as->get_node(CONCEPT_NODE,
std::move(std::string(UREConfig::top_rbs_name)));
Handle target_var = _eval.eval_h("(VariableNode \"$who\")");
Handle target =
_eval.eval_h("(InheritanceLink"
" (VariableNode \"$who\")"
" (ConceptNode \"criminal\"))");
Handle vardecl =
_eval.eval_h("(TypedVariable"
" (VariableNode \"$who\")"
" (Type \"ConceptNode\"))");
Handle soln = _eval.eval_h("(ConceptNode \"West\")");
// To record the trace of the inference
AtomSpacePtr trace_as = createAtomSpace();
BackwardChainer bc(*_as.get(), top_rbs, target, vardecl, trace_as.get());
// See bc-criminal-config.scm to change the number of iterations
bc.do_chain();
Handle results = bc.get_results(),
expected_target = _eval.eval_h("(InheritanceLink"
" (ConceptNode \"West\")"
" (ConceptNode \"criminal\"))"),
expected = al(SET_LINK, expected_target);
logger().debug() << "results = " << oc_to_string(results);
logger().debug() << "expected = " << oc_to_string(expected);
TS_ASSERT_EQUALS(results, expected);
TS_ASSERT_LESS_THAN(0.9, expected_TruthValueCast(target->getValue(truth_key()))->get_mean());
TS_ASSERT_LESS_THAN(0.9, expected_TruthValueCast(target->getValue(truth_key()))->get_confidence());
// Extract traces and return the backward chainer with these
// traces, which should greatly speed it up.
HandleSeqSet traces = bc._trace_recorder.traces();
// Log traces
std::stringstream ss;
ss << "Traces:" << std::endl << "size = " << traces.size();
int i = 0;
for (const auto& trace : traces) {
ss << endl << "trace[" << i++ << "] =";
for (const Handle& h : trace) {
ContentHash ch = h.value();
ss << " " << ch;
}
}
logger().debug() << ss.str();
// Make sure at least one trace has been recorded
TS_ASSERT_LESS_THAN(0, traces.size());
// Clear the atomspace and reload the problem
_as->clear();
load_from_path("bc-criminal-config.scm");
load_from_path("criminal.scm");
randGen().seed(0);
target_var = _eval.eval_h("(VariableNode \"$who\")");
target = _eval.eval_h("(InheritanceLink"
" (VariableNode \"$who\")"
" (ConceptNode \"criminal\"))");
vardecl = _eval.eval_h("(TypedVariable"
" (VariableNode \"$who\")"
" (Type \"ConceptNode\"))");
soln = _eval.eval_h("(ConceptNode \"West\")");
// Extract the first trace, as understandable by the trace fitness
std::set<ContentHash> trace;
for (const Handle& h : *(traces.begin()))
trace.insert(h.value());
AndBITFitness trace_fitness(AndBITFitness::Trace, trace);
BackwardChainer tr_bc(*_as.get(), top_rbs, target, vardecl, nullptr, nullptr,
Handle::UNDEFINED, BITNodeFitness(), trace_fitness);
tr_bc.get_config().set_maximum_iterations(100);
tr_bc.do_chain();
results = tr_bc.get_results();
expected_target = _eval.eval_h("(InheritanceLink"
" (ConceptNode \"West\")"
" (ConceptNode \"criminal\"))");
expected = al(SET_LINK, expected_target);
logger().debug() << "results = " << oc_to_string(results);
logger().debug() << "expected = " << oc_to_string(expected);
TS_ASSERT_EQUALS(results, expected);
TS_ASSERT_LESS_THAN(0.9, expected_TruthValueCast(target->getValue(truth_key()))->get_mean());
TS_ASSERT_LESS_THAN(0.9, expected_TruthValueCast(target->getValue(truth_key()))->get_confidence());
}
// Test showing we no longer need the ExecutionOutputLink
void BackwardChainerUTest::test_no_exec_output()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
load_from_path("no-exec-output.scm");
randGen().seed(0);
Handle rbs = _eval.eval_h("Einstein-rbs");
Handle target = _eval.eval_h("target");
Handle vardecl = _eval.eval_h("vd");
BackwardChainer bc(*_as.get(), rbs, target, vardecl);
// See no-exec-output.scm to change the number of iterations
bc.do_chain();
Handle results = bc.get_results(),
expected = al(SET_LINK, al(EVALUATION_LINK,
an(PREDICATE_NODE, "keep-pet"),
al(LIST_LINK,
an(CONCEPT_NODE, "American"),
an(CONCEPT_NODE, "cat"))));
logger().debug() << "results = " << oc_to_string(results);
logger().debug() << "expected = " << oc_to_string(expected);
TS_ASSERT_EQUALS(results, expected);
}
void BackwardChainerUTest::xtest_green_balls()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
load_from_path("green-balls-kb.scm");
load_from_path("green-balls-rb.scm");
load_from_path("green-balls-targets.scm");
randGen().seed(0);
Handle top_rbs = _as->get_node(CONCEPT_NODE,
std::move(std::string(UREConfig::top_rbs_name)));
Handle target = _eval.eval_h("target-known-evidence");
BackwardChainer bc(*_as.get(), top_rbs, target);
// See green-balls-rb.scm to change the number of iterations and
// other parameters
bc.do_chain();
Handle results = bc.get_results(),
top_result = results->getOutgoingAtom(0);
logger().debug() << "results = " << oc_to_string(results);
TS_ASSERT_LESS_THAN(0.9, TruthValueCast(top_result->getValue(truth_key()))->get_mean());
TS_ASSERT_LESS_THAN(0.9, TruthValueCast(top_result->getValue(truth_key()))->get_confidence());
}
void BackwardChainerUTest::xtest_induction()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
string load_bc_induction_config_result =
load_from_path("bc-induction-config.scm");
string load_bc_induction_result =
load_from_path("bc-induction.scm");
randGen().seed(500);
Handle top_rbs = _as->get_node(CONCEPT_NODE,
std::move(std::string(UREConfig::top_rbs_name)));
Handle target = _eval.eval_h("bc-induction-target");
BackwardChainer bc(*_as.get(), top_rbs, target);
bc.get_config().set_maximum_iterations(100);
bc.do_chain();
// TODO: fixme, for that we need to support BIT expansion over meta rule
TS_ASSERT_DELTA(TruthValueCast(target->getValue(truth_key()))->get_mean(), 1, 1e-10);
// TODO: determine the expected confidence, which depends on the
// number of instances the induction is based on
TS_ASSERT_DELTA(TruthValueCast(target->getValue(truth_key()))->get_confidence(), 1, 1e-10);
}
void BackwardChainerUTest::xtest_focus_set()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
load_from_path("conditional-instantiation-config.scm");
load_from_path("animals.scm");
randGen().seed(500);
Handle top_rbs = _as->get_node(CONCEPT_NODE,
std::move(std::string(UREConfig::top_rbs_name)));
Handle green = an(CONCEPT_NODE, "green"),
Fritz = an(CONCEPT_NODE, "Fritz"),
what = an(VARIABLE_NODE, "$what"),
target = al(INHERITANCE_LINK, what, green),
concept = an(TYPE_NODE, "ConceptNode"),
vardecl = al(TYPED_VARIABLE_LINK, what, concept);
Handle focus_set =
_eval.eval_h("(SetLink"
" (InheritanceLink"
" (ConceptNode \"tree\")"
" (ConceptNode \"plant\"))"
" (ImplicationLink"
" (InheritanceLink"
" (VariableNode \"$P\")"
" (ConceptNode \"plant\")"
" )"
" (InheritanceLink"
" (VariableNode \"$P\")"
" (ConceptNode \"green\")"
" )"
" )"
")");
BackwardChainer bc(*_as.get(), top_rbs, target, vardecl, nullptr, nullptr, focus_set);
Handle soln1 = _eval.eval_h("(InheritanceLink"
" (ConceptNode \"tree\")"
" (ConceptNode \"green\"))");
// should not be able to find this solution outside the focus set
Handle soln2 = _eval.eval_h("(InheritanceLink"
" (ConceptNode \"Fritz\")"
" (ConceptNode \"green\"))");
bc.get_config().set_maximum_iterations(300);
bc.do_chain();
Handle results = bc.get_results(),
expected = al(SET_LINK, soln1);
// Re-enable when focus set is supported
TS_ASSERT_EQUALS(results, expected);
}
#undef al
#undef an