OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-atomspace / tests / atoms / reduct / ReductUTest.cxxtest

626 lines · cxxtest ref:
/*
 * tests/atoms/ReductUTest.cxxtest
 *
 * Copyright (C) 2015 Linas Vepstas
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <opencog/guile/SchemeEval.h>
#include <opencog/atomspace/AtomSpace.h>
#include <opencog/atoms/core/NumberNode.h>
#include <opencog/util/Logger.h>

using namespace opencog;

class ReductUTest: public CxxTest::TestSuite
{
private:
	AtomSpacePtr as;
	SchemeEval* eval;

public:
	ReductUTest(void)
	{
		logger().set_level(Logger::DEBUG);
		logger().set_print_to_stdout_flag(true);

		as = createAtomSpace();
		eval = SchemeEval::get_scheme_evaluator(as);
	}

	~ReductUTest()
	{
		// Erase the log file if no assertions failed.
		if (!CxxTest::TestTracker::tracker().suiteFailed())
			std::remove(logger().get_filename().c_str());
	}

	void setUp(void);
	void tearDown(void);

	void test_arithmetic(void);
	void test_arithmetic_inf(void);
	void test_arithmetic_nan(void);
	void test_setlink(void);
	void test_minus(void);
	void test_plus_minus(void);
	void test_execution(void);
	void test_recursion(void);
};

void ReductUTest::tearDown(void)
{
	as->clear();
}

void ReductUTest::setUp(void)
{
	as->clear();
}

/*
 * ReductLink unit test.  Test Plus, Times arithmetic.
 */
void ReductUTest::test_arithmetic(void)
{
	logger().debug("BEGIN TEST: %s", __FUNCTION__);

	// ---------
	Handle zero = eval->eval_h(
		"(cog-execute! (PlusLink (NumberNode 0)))"
	);
	printf("expecting zero: %s\n", zero->to_short_string().c_str());

	Handle ezero = eval->eval_h("(NumberNode 0)");
	TS_ASSERT_EQUALS(zero, ezero);

	// ---------
	Handle two = eval->eval_h(
		"(cog-execute! (PlusLink (NumberNode 2)))"
	);
	printf("expecting two: %s\n", two->to_short_string().c_str());

	Handle etwo = eval->eval_h("(NumberNode 2)");
	TS_ASSERT_EQUALS(two, etwo);

	// ---------
	Handle four = eval->eval_h(
		"(cog-execute! (PlusLink (NumberNode 2) (NumberNode 2)))"
	);
	printf("expecting four: %s\n", four->to_short_string().c_str());

	Handle efour = eval->eval_h("(NumberNode 4)");
	TS_ASSERT_EQUALS(four, efour);

	// ---------
	zero = eval->eval_h(
		"(cog-execute! (PlusLink (NumberNode 2) (NumberNode -2)))"
	);
	printf("expecting zero: %s\n", zero->to_short_string().c_str());

	ezero = eval->eval_h("(NumberNode 0)");
	TS_ASSERT_EQUALS(zero, ezero);

	// ---------
	Handle xplus0 = eval->eval_h(
		"(cog-execute! (PlusLink "
		"	(VariableNode \"$x\") (NumberNode 0)))"
	);
	printf("expecting x: %s\n", xplus0->to_short_string().c_str());

	Handle ex = eval->eval_h("(VariableNode \"$x\")");
	TS_ASSERT_EQUALS(xplus0, ex);

	// ---------
	Handle Oplusx = eval->eval_h(
		"(cog-execute! (PlusLink "
		"	(NumberNode 0) (VariableNode \"$x\")))"
	);
	printf("expecting x: %s\n", Oplusx->to_short_string().c_str());
	TS_ASSERT_EQUALS(Oplusx, ex);

	// ---------
	Handle xplus5 = eval->eval_h(
		"(cog-execute! (PlusLink "
		"	(NumberNode 2) (VariableNode \"$x\") (NumberNode 3)))"
	);
	printf("expecting x+5: %s\n", xplus5->to_short_string().c_str());

	Handle explus5 = eval->eval_h(
		"(PlusLink (VariableNode \"$x\") (NumberNode 5))");
	TS_ASSERT_EQUALS(xplus5, explus5);

	// ---------
	Handle x = eval->eval_h(
		"(cog-execute! (PlusLink "
		"	(NumberNode 2) (VariableNode \"$x\") (NumberNode -2)))"
	);
	printf("expecting $x: %s\n", x->to_short_string().c_str());
	TS_ASSERT_EQUALS(x, ex);

	// ---------
	Handle twox = eval->eval_h(
		"(cog-execute! (PlusLink "
		"	(VariableNode \"$x\") (VariableNode \"$x\")))"
	);
	printf("expecting 2x: %s\n", twox->to_short_string().c_str());

	Handle etwox = eval->eval_h(
		"(TimesLink (VariableNode \"$x\") (NumberNode 2))");
	TS_ASSERT_EQUALS(twox, etwox);

	// ---------
	Handle threex = eval->eval_h(
		"(cog-execute! (PlusLink (VariableNode \"$x\") "
		"	(VariableNode \"$x\") (VariableNode \"$x\")))"
	);
	printf("expecting 3x: %s\n", threex->to_short_string().c_str());

	Handle ethreex = eval->eval_h(
		"(TimesLink (VariableNode \"$x\") (NumberNode 3))");
	TS_ASSERT_EQUALS(threex, ethreex);

	// ---------

	Handle xtimes42 = eval->eval_h(
		"(cog-execute! (PlusLink "
		"	(VariableNode \"$x\")"
		"	(TimesLink (NumberNode 38) (VariableNode \"$x\"))"
		"	(TimesLink (VariableNode \"$x\") (NumberNode 3))))"
	);
	printf("expecting x*42: %s\n", xtimes42->to_short_string().c_str());

	Handle extimes42 = eval->eval_h(
		"(TimesLink (VariableNode \"$x\") (NumberNode 42))");
	TS_ASSERT_EQUALS(xtimes42, extimes42);

	// ---------
	Handle six = eval->eval_h(
		"(cog-execute! (TimesLink (NumberNode 2) (NumberNode 3)))"
	);
	printf("expecting six: %s\n", six->to_short_string().c_str());

	Handle esix = eval->eval_h("(NumberNode 6)");
	TS_ASSERT_EQUALS(six, esix);

	// ---------

	Handle sixex = eval->eval_h(
		"(cog-execute! (TimesLink "
		"	(NumberNode 2) (VariableNode \"$x\") (NumberNode 3)))"
	);
	printf("expecting x * 6: %s\n", sixex->to_short_string().c_str());

	Handle esixex = eval->eval_h(
		"(TimesLink (VariableNode \"$x\") (NumberNode 6))");
	TS_ASSERT_EQUALS(sixex, esixex);

	// ---------
	logger().debug("END TEST: %s", __FUNCTION__);
}

/*
 * Test Plus inf.
 */
void ReductUTest::test_arithmetic_inf(void)
{
	logger().debug("BEGIN TEST: %s", __FUNCTION__);

	// ---------
	Handle inf = eval->eval_h(
			"(cog-execute! (PlusLink (NumberNode 0) (NumberNode \"inf\")))"
	);
	printf("expecting inf: %s\n", inf->to_short_string().c_str());

	Handle einf = eval->eval_h("(NumberNode \"inf\")");
	TS_ASSERT_EQUALS(inf, einf)

	// ---------
	Handle pninf4 = eval->eval_h(
			"(cog-execute! "
			"   (PlusLink"
			"      (NumberNode \"inf 0 3.0\")"
			"      (NumberNode \"inf -inf 1.0\")))"
	);
	printf("expecting inf: %s\n", pninf4->to_short_string().c_str());

	Handle epninf4 = eval->eval_h("(NumberNode \"inf -inf 4.0\")");
	TS_ASSERT_EQUALS(pninf4, epninf4)

	// ---------
	logger().debug("END TEST: %s", __FUNCTION__);
}

/*
 * Test Plus nan.
 */
void ReductUTest::test_arithmetic_nan(void)
{
	logger().debug("BEGIN TEST: %s", __FUNCTION__);

	// ---------
	Handle nan = eval->eval_h(
			"(cog-execute! (PlusLink (NumberNode 0) (NumberNode \"nan\")))"
	);
	printf("expecting nan: %s\n", nan->to_short_string().c_str());

	Handle enan = eval->eval_h("(NumberNode \"nan\")");
	TS_ASSERT_EQUALS(nan, enan)

	// ---------
	Handle nn4 = eval->eval_h(
			"(cog-execute! "
			"   (PlusLink"
			"      (NumberNode \"nan nan 3.0\")"
			"      (NumberNode \"inf -inf 1.0\")))"
	);
	printf("expecting nan-nan-4: %s\n", nn4->to_short_string().c_str());

	Handle enn4 = eval->eval_h("(NumberNode \"nan nan 4.0\")");
	TS_ASSERT_EQUALS(nn4, enn4)

	// ---------
	logger().debug("END TEST: %s", __FUNCTION__);
}

// Test SetLink, which the pattern matcher gives to us.
void ReductUTest::test_setlink(void)
{
	logger().debug("BEGIN TEST: %s", __FUNCTION__);

	// ---------
	Handle one = eval->eval_h(
		"(cog-execute! (Plus (Set (NumberNode 0)) (NumberNode  1)))"
	);
	printf("expecting one: %s\n", one->to_short_string().c_str());

	Handle eone = eval->eval_h("(NumberNode 1)");
	TS_ASSERT_EQUALS(one, eone);

	// ---------
	Handle four = eval->eval_h(
		"(cog-execute! (Plus "
		"   (Set (NumberNode 1) (NumberNode 1) (NumberNode 1))"
		"   (NumberNode  1)))"
	);
	printf("expecting four: %s\n", four->to_short_string().c_str());

	Handle efour = eval->eval_h("(NumberNode 4)");
	TS_ASSERT_EQUALS(four, efour);

	// ---------
	logger().debug("END TEST: %s", __FUNCTION__);
}

/*
 * ReductLink unit test.  Test Minus Divide.
 */
void ReductUTest::test_minus(void)
{
	logger().debug("BEGIN TEST: %s", __FUNCTION__);

	// ---------
	Handle zero = eval->eval_h(
		"(cog-execute! (Minus (Number 0)))"
	);
	printf("expecting zero: %s\n", zero->to_short_string().c_str());

	Handle ezero = eval->eval_h("(Number 0)");
	TS_ASSERT_EQUALS(zero, ezero);

	// ---------
	Handle mone = eval->eval_h(
		"(cog-execute! (Minus (Number 1)))"
	);
	printf("expecting minus one: %s\n", mone->to_short_string().c_str());

	Handle emone = eval->eval_h("(Number -1)");
	TS_ASSERT_EQUALS(mone, emone);

	// ---------
	mone = eval->eval_h(
		"(cog-execute! (Minus (Number 0) (Number 1)))"
	);
	printf("expecting minus one: %s\n", mone->to_short_string().c_str());
	TS_ASSERT_EQUALS(mone, emone);

	// ---------
	Handle x = eval->eval_h(
		"(cog-execute! (Minus (Variable \"$x\") (Number 0)))"
	);
	printf("expecting x: %s\n", x->to_short_string().c_str());

	Handle ex = eval->eval_h("(Variable \"$x\")");
	TS_ASSERT_EQUALS(x, ex);

	// ---------
	Handle mx = eval->eval_h(
		"(cog-execute! (Minus (Number 0) (Variable \"$x\")))"
	);
	printf("expecting minus x: %s\n", mx->to_string().c_str());

	Handle emx = eval->eval_h(
		"(Minus (Number 0) (Variable \"$x\"))"
	);
	TS_ASSERT_EQUALS(mx, emx);

	// ---------
	x = eval->eval_h(
		"(cog-execute! (Divide (Variable \"$x\") (Number 1)))"
	);
	printf("expecting x: %s\n", x->to_short_string().c_str());
	TS_ASSERT_EQUALS(x, ex);

	// ---------
	Handle dx = eval->eval_h(
		"(cog-execute! (Divide (Number 1) (Variable \"$x\")))"
	);
	printf("expecting 1/x: %s\n", dx->to_short_string().c_str());

	Handle edx = eval->eval_h(
		"(Divide (Number 1) (Variable \"$x\"))"
	);
	TS_ASSERT_EQUALS(dx, edx);

	// ---------
	logger().debug("END TEST: %s", __FUNCTION__);
}

/*
 * ReductLink unit test.  Test Plus with Minus.
 */
void ReductUTest::test_plus_minus(void)
{
	logger().debug("BEGIN TEST: %s", __FUNCTION__);

	// ---------
	Handle p43m1 = eval->eval_h(
		"(cog-execute! (Plus (Number 43) (Minus (Variable \"x\") (Number 1))))"
	);
	printf("expecting x+42: %s\n", p43m1->to_short_string().c_str());

	Handle p42 = eval->eval_h("(Plus (Variable \"x\") (Number 42))");
	TS_ASSERT_EQUALS(p43m1, p42);

	// ---------
	Handle p41p1 = eval->eval_h(
		"(cog-execute! (Plus (Number 41) (Minus (Number 1) (Variable \"x\"))))"
	);
	printf("expecting 42-x: %s\n", p41p1->to_short_string().c_str());

	Handle m42 = eval->eval_h("(Minus (Number 42) (Variable \"x\"))");
	TS_ASSERT_EQUALS(p41p1, m42);

	// ---------
	Handle zero = eval->eval_h(
		"(cog-execute! (Plus (Number 2) (Minus (Variable \"x\") (Number 2))))"
	);
	printf("expecting x: %s\n", zero->to_short_string().c_str());

	Handle ezero = eval->eval_h("(Variable \"x\")");
	TS_ASSERT_EQUALS(zero, ezero);

	// ========================================================

	Handle m43p1 = eval->eval_h(
		"(cog-execute! (Minus (Number 43) (Plus (Variable \"x\") (Number 1))))"
	);
	printf("expecting 42-x: %s\n", m43p1->to_short_string().c_str());

	Handle m42x = eval->eval_h("(Minus (Number 42) (Variable \"x\"))");
	TS_ASSERT_EQUALS(m43p1, m42x);

	// ---------
	Handle p1m43 = eval->eval_h(
		"(cog-execute! (Minus (Plus (Number 1) (Variable \"x\")) (Number 43)))"
	);
	printf("expecting x-42: %s\n", p1m43->to_short_string().c_str());

	Handle mx42 = eval->eval_h("(Plus (Variable \"x\") (Number -42))");
	TS_ASSERT_EQUALS(p1m43, mx42);

	// ---------
	Handle mpzero = eval->eval_h(
		"(cog-execute! (Minus (Plus (Variable \"x\") (Number 2)) (Number 2)))"
	);
	printf("expecting x: %s\n", mpzero->to_short_string().c_str());

	Handle emp = eval->eval_h("(Variable \"x\")");
	TS_ASSERT_EQUALS(mpzero, emp);

	// ========================================================
	Handle t6d2 = eval->eval_h(
		"(cog-execute! (Times (Number 6) (Divide (Variable \"x\") (Number 2))))"
	);
	printf("expecting 3x: %s\n", t6d2->to_short_string().c_str());

	Handle t3 = eval->eval_h("(Times (Variable \"x\") (Number 3))");
	TS_ASSERT_EQUALS(t6d2, t3);

	// ---------
	Handle t6t2 = eval->eval_h(
		"(cog-execute! (Times (Number 6) (Divide (Number 2) (Variable \"x\"))))"
	);
	printf("expecting 12/x: %s\n", t6t2->to_short_string().c_str());

	Handle d12 = eval->eval_h("(Divide (Number 12) (Variable \"x\"))");
	TS_ASSERT_EQUALS(t6t2, d12);

	// ---------
	Handle one = eval->eval_h(
		"(cog-execute! (Times (Number 5) (Divide (Variable \"x\") (Number 5))))"
	);
	printf("expecting x: %s\n", one->to_short_string().c_str());

	Handle eone = eval->eval_h("(Variable \"x\")");
	TS_ASSERT_EQUALS(one, eone);

	// ========================================================
	Handle d6t2 = eval->eval_h(
		"(cog-execute! (Divide (Number 6) (Times (Variable \"x\") (Number 2))))"
	);
	printf("expecting 3/x: %s\n", d6t2->to_short_string().c_str());

	Handle d3 = eval->eval_h("(Divide (Number 3) (Variable \"x\"))");
	TS_ASSERT_EQUALS(d6t2, d3);

	// ---------
	Handle d6x2 = eval->eval_h(
		"(cog-execute! (Divide (Times (Number 6) (Variable \"x\")) (Number 2)))"
	);
	printf("expecting 3x: %s\n", d6x2->to_short_string().c_str());

	Handle x3 = eval->eval_h("(Times (Variable \"x\") (Number 3))");
	TS_ASSERT_EQUALS(d6x2, x3);

	// ---------
	Handle done = eval->eval_h(
		"(cog-execute! (Divide (Times (Variable \"x\") (Number 5)) (Number 5)))"
	);
	printf("expecting x: %s\n", done->to_short_string().c_str());

	Handle edone = eval->eval_h("(Variable \"x\")");
	TS_ASSERT_EQUALS(done, edone);

	// ---------
	logger().debug("END TEST: %s", __FUNCTION__);
}

/*
 * ReductLink unit test.  Test exuction of arguments.
 */
void ReductUTest::test_execution(void)
{
	logger().debug("BEGIN TEST: %s", __FUNCTION__);

	// ---------
	Handle fife = eval->eval_h(
		"(cog-execute! (Plus (Number 10) "
		"    (RandomNumber (Number 5) (Number 9))))"
	);
	printf("expecting 15 to 19: %s\n", fife->to_short_string().c_str());

	Type tfife = fife->get_type();
	TS_ASSERT_EQUALS(tfife, NUMBER_NODE);

	NumberNodePtr nn(NumberNodeCast(fife));
	double val = nn->get_value();
	TS_ASSERT_LESS_THAN_EQUALS(15.0, val);
	TS_ASSERT_LESS_THAN_EQUALS(val, 19.0);

	// ---------
	logger().debug("END TEST: %s", __FUNCTION__);
}

/*
 * ReductLink unit test.  Test fix for infinite recursion in
 * https://github.com/opencog/atomspace/issues/2603
 */
void ReductUTest::test_recursion(void)
{
	logger().debug("BEGIN TEST: %s", __FUNCTION__);

	// ---------
	Handle sxp5 = eval->eval_h(
		"(cog-execute! (Plus"
		"   (Times (Variable \"$x\") (Number 3))"
		"   (Times (Variable \"$x\") (Number 4))"
		"   (Number 5)))"
	);
	Handle esxp = eval->eval_h(
		"(Plus"
		"   (Times (Variable \"$x\") (Number 7))"
		"   (Number 5))"
	);
	printf("expect: %s\n", esxp->to_short_string().c_str());
	printf("   got: %s\n", sxp5->to_short_string().c_str());

	TS_ASSERT_EQUALS(sxp5, esxp);

	// ---------
	sxp5 = eval->eval_h(
		"(cog-execute! (Plus"
		"   (Times (Variable \"$x\") (Number 3))"
		"   (Times (Variable \"$x\") (Number 4))"
		"   (Times (Variable \"$y\") (Number 6))"
		"   (Number 5)))"
	);
	esxp = eval->eval_h(
		"(Plus"
		"   (Times (Variable \"$x\") (Number 7))"
		"   (Times (Variable \"$y\") (Number 6))"
		"   (Number 5))"
	);
	printf("expect: %s\n", esxp->to_short_string().c_str());
	printf("   got: %s\n", sxp5->to_short_string().c_str());

	TS_ASSERT_EQUALS(sxp5, esxp);

	// ---------
	sxp5 = eval->eval_h(
		"(cog-execute! (Plus"
		"   (Times (Variable \"$y\") (Number 6))"
		"   (Times (Variable \"$x\") (Number 3))"
		"   (Times (Variable \"$x\") (Number 4))"
		"   (Number 5)))"
	);
	esxp = eval->eval_h(
		"(Plus"
		"   (Times (Variable \"$y\") (Number 6))"
		"   (Times (Variable \"$x\") (Number 7))"
		"   (Number 5))"
	);
	printf("expect: %s\n", esxp->to_short_string().c_str());
	printf("   got: %s\n", sxp5->to_short_string().c_str());

	TS_ASSERT_EQUALS(sxp5, esxp);

	// ---------
	sxp5 = eval->eval_h(
		"(cog-execute! (Plus"
		"   (Times (Variable \"$x\") (Number 3))"
		"   (Times (Variable \"$y\") (Number 6))"
		"   (Times (Variable \"$x\") (Number 4))"
		"   (Number 5)))"
	);
	esxp = sxp5;

	printf("expect: %s\n", esxp->to_short_string().c_str());
	printf("   got: %s\n", sxp5->to_short_string().c_str());

	TSM_ASSERT_EQUALS("Maybe you made reduct smarter??", sxp5, esxp);

	// ---------
	sxp5 = eval->eval_h(
			"(cog-execute! (Times"
					"   (Plus (Variable \"$x\") (Number 3))"
					"   (Plus (Variable \"$y\") (Number 6))"
					"   (Plus (Variable \"$x\") (Number 4))"
					"   (Number 5)))"
	);
	esxp = sxp5;

	printf("expect: %s\n", esxp->to_short_string().c_str());
	printf("   got: %s\n", sxp5->to_short_string().c_str());

	TSM_ASSERT_EQUALS("Maybe you made reduct smarter??", sxp5, esxp);

	// ---------
	logger().debug("END TEST: %s", __FUNCTION__);
}