OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-ure / tests / ure / backwardchainer / BackwardChainerUTest.cxxtest

761 lines · cxxtest ref:
/*
 * 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