/*
* 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__);
}