/*
* tests/atoms/flow/ValueOfUTest.cxxtest
*
* Copyright (C) 2018 Linas Vepstas
* All Rights Reserved
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include <opencog/atoms/core/NumberNode.h>
#include <opencog/atoms/flow/ValueOfLink.h>
#include <opencog/atoms/reduct/PlusLink.h>
#include <opencog/atoms/value/FloatValue.h>
#include <opencog/atomspace/AtomSpace.h>
#include <opencog/util/Logger.h>
#include <cxxtest/TestSuite.h>
using namespace opencog;
#define al _as.add_link
#define an _as.add_node
class ValueOfUTest : public CxxTest::TestSuite
{
private:
AtomSpace _as;
ValuePtr value;
Handle key;
Handle atom;
public:
ValueOfUTest(void);
void setUp(void);
void check(void);
void test_basic();
void test_basic_value();
void test_times();
void test_plus();
void test_times_plus();
void test_minus();
void test_divide();
void test_number();
};
ValueOfUTest::ValueOfUTest(void)
{
logger().set_level(Logger::DEBUG);
logger().set_print_to_stdout_flag(true);
// Hack to force library to load to work around linking bug.
createPlusLink(HandleSeq());
}
void ValueOfUTest::setUp(void)
{
value = createFloatValue(std::vector<double>{0.0, 1.0, 2.0});
key = an(PREDICATE_NODE, "my key");
atom = an(CONCEPT_NODE, "some atom");
atom->setValue(key, value);
}
void ValueOfUTest::check(void)
{
// value must not get corrupted.
FloatValuePtr orig_value = createFloatValue(std::vector<double>{0.0, 1.0, 2.0});
ValuePtr check_value = atom->getValue(key);
TS_ASSERT(*orig_value == *FloatValueCast(check_value));
}
// ====================================================================
// Make sure ValueOf actually fetches the value.
void ValueOfUTest::test_basic()
{
logger().debug("BEGIN TEST: %s", __FUNCTION__);
value = an(CONCEPT_NODE, "my value");
atom->setValue(key, value);
Handle valof = al(VALUE_OF_LINK, atom, key);
Handle result = HandleCast(valof->execute(&_as));
printf("expect: %s\n", value->to_string().c_str());
printf("result: %s\n", result->to_string().c_str());
TS_ASSERT_EQUALS(value, result);
logger().debug("END TEST: %s", __FUNCTION__);
}
// ====================================================================
// Make sure FloatValues work.
void ValueOfUTest::test_basic_value()
{
logger().debug("BEGIN TEST: %s", __FUNCTION__);
Handle valof = al(VALUE_OF_LINK, atom, key);
ValuePtr result = FunctionLinkCast(valof)->execute();
printf("expect: %s\n", value->to_string().c_str());
printf("result: %s\n", result->to_string().c_str());
TS_ASSERT_EQUALS(value, result);
logger().debug("END TEST: %s", __FUNCTION__);
}
// ====================================================================
// Make sure TimesLink works
void ValueOfUTest::test_times()
{
logger().debug("BEGIN TEST: %s", __FUNCTION__);
Handle valof = al(FLOAT_VALUE_OF_LINK, atom, key);
// scalar times vector --------------------------------------------
Handle times = al(TIMES_LINK, an(NUMBER_NODE, "3"), valof);
ValuePtr result = FunctionLinkCast(times)->execute();
FloatValuePtr expect = createFloatValue(std::vector<double>{0.0, 3.0, 6.0});
printf("expect: %s", expect->to_string().c_str());
printf("result: %s\n", result->to_string().c_str());
TS_ASSERT(*expect == *FloatValueCast(result));
// value must not get corrupted.
check();
// vector times scalar --------------------------------------------
times = al(TIMES_LINK, valof, an(NUMBER_NODE, "7"));
result = FunctionLinkCast(times)->execute();
expect = createFloatValue(std::vector<double>{0.0, 7.0, 14.0});
printf("expect: %s", expect->to_string().c_str());
printf("result: %s\n", result->to_string().c_str());
TS_ASSERT(*expect == *FloatValueCast(result));
// value must not get corrupted.
check();
// vector times vector ----------------------------------------------
times = al(TIMES_LINK, valof, valof);
result = FunctionLinkCast(times)->execute();
expect = createFloatValue(std::vector<double>{0.0, 1.0, 4.0});
printf("expect: %s", expect->to_string().c_str());
printf("result: %s\n", result->to_string().c_str());
TS_ASSERT(*expect == *FloatValueCast(result));
// value must not get corrupted.
check();
logger().debug("END TEST: %s", __FUNCTION__);
}
// ====================================================================
// Make sure PlusLink works
void ValueOfUTest::test_plus()
{
logger().debug("BEGIN TEST: %s", __FUNCTION__);
Handle valof = al(FLOAT_VALUE_OF_LINK, atom, key);
// scalar plus vector --------------------------------------------
Handle plus = al(PLUS_LINK, an(NUMBER_NODE, "3"), valof);
ValuePtr result = FunctionLinkCast(plus)->execute();
FloatValuePtr expect = createFloatValue(std::vector<double>{3.0, 4.0, 5.0});
printf("expect: %s", expect->to_string().c_str());
printf("result: %s\n", result->to_string().c_str());
TS_ASSERT(*expect == *FloatValueCast(result));
// value must not get corrupted.
check();
// vector plus scalar --------------------------------------------
plus = al(PLUS_LINK, valof, an(NUMBER_NODE, "7"));
result = FunctionLinkCast(plus)->execute();
expect = createFloatValue(std::vector<double>{7.0, 8.0, 9.0});
printf("expect: %s", expect->to_string().c_str());
printf("result: %s\n", result->to_string().c_str());
TS_ASSERT(*expect == *FloatValueCast(result));
// value must not get corrupted.
check();
// vector plus vector ----------------------------------------------
plus = al(PLUS_LINK, valof, valof);
result = FunctionLinkCast(plus)->execute();
expect = createFloatValue(std::vector<double>{0.0, 2.0, 4.0});
printf("expect: %s", expect->to_string().c_str());
printf("result: %s\n", result->to_string().c_str());
TS_ASSERT(*expect == *FloatValueCast(result));
// value must not get corrupted.
check();
logger().debug("END TEST: %s", __FUNCTION__);
}
// ====================================================================
// Make sure complex expressions work.
void ValueOfUTest::test_times_plus()
{
logger().debug("BEGIN TEST: %s", __FUNCTION__);
Handle valof = al(FLOAT_VALUE_OF_LINK, atom, key);
// 5+3x --------------------------------------------
Handle times = al(PLUS_LINK, an(NUMBER_NODE, "5"),
al(TIMES_LINK, an(NUMBER_NODE, "3"), valof));
ValuePtr result = FunctionLinkCast(times)->execute();
FloatValuePtr expect = createFloatValue(std::vector<double>{5.0, 8.0, 11.0});
printf("expect: %s", expect->to_string().c_str());
printf("result: %s\n", result->to_string().c_str());
TS_ASSERT(*expect == *FloatValueCast(result));
// value must not get corrupted.
check();
// 5(3+x) --------------------------------------------
times = al(TIMES_LINK, an(NUMBER_NODE, "5"),
al(PLUS_LINK, an(NUMBER_NODE, "3"), valof));
result = FunctionLinkCast(times)->execute();
expect = createFloatValue(std::vector<double>{15.0, 20.0, 25.0});
printf("expect: %s", expect->to_string().c_str());
printf("result: %s\n", result->to_string().c_str());
TS_ASSERT(*expect == *FloatValueCast(result));
// value must not get corrupted.
check();
// (x+3)5 --------------------------------------------
times = al(TIMES_LINK,
al(PLUS_LINK, valof, an(NUMBER_NODE, "3")),
an(NUMBER_NODE, "5"));
result = FunctionLinkCast(times)->execute();
expect = createFloatValue(std::vector<double>{15.0, 20.0, 25.0});
printf("expect: %s", expect->to_string().c_str());
printf("result: %s\n", result->to_string().c_str());
TS_ASSERT(*expect == *FloatValueCast(result));
// value must not get corrupted.
check();
logger().debug("END TEST: %s", __FUNCTION__);
}
// ====================================================================
// Make sure MinusLink works
void ValueOfUTest::test_minus()
{
logger().debug("BEGIN TEST: %s", __FUNCTION__);
Handle valof = al(FLOAT_VALUE_OF_LINK, atom, key);
// 3-x --------------------------------------------
Handle minus = al(MINUS_LINK, an(NUMBER_NODE, "3"), valof);
ValuePtr result = FunctionLinkCast(minus)->execute();
FloatValuePtr expect = createFloatValue(std::vector<double>{3.0, 2.0, 1.0});
printf("expect: %s", expect->to_string().c_str());
printf("result: %s\n", result->to_string().c_str());
TS_ASSERT(*expect == *FloatValueCast(result));
// value must not get corrupted.
check();
// x-7 --------------------------------------------
minus = al(MINUS_LINK, valof, an(NUMBER_NODE, "7"));
result = FunctionLinkCast(minus)->execute();
expect = createFloatValue(std::vector<double>{-7.0, -6.0, -5.0});
printf("expect: %s", expect->to_string().c_str());
printf("result: %s\n", result->to_string().c_str());
TS_ASSERT(*expect == *FloatValueCast(result));
// value must not get corrupted.
check();
// vector minus vector ----------------------------------------------
minus = al(MINUS_LINK, valof, valof);
result = FunctionLinkCast(minus)->execute();
expect = createFloatValue(std::vector<double>{0.0, 0.0, 0.0});
printf("expect: %s", expect->to_string().c_str());
printf("result: %s\n", result->to_string().c_str());
TS_ASSERT(*expect == *FloatValueCast(result));
// value must not get corrupted.
check();
logger().debug("END TEST: %s", __FUNCTION__);
}
// ====================================================================
// Make sure DivideLink works
void ValueOfUTest::test_divide()
{
logger().debug("BEGIN TEST: %s", __FUNCTION__);
Handle valof = al(FLOAT_VALUE_OF_LINK, atom, key);
// x/4 --------------------------------------------
Handle divide = al(DIVIDE_LINK, valof, an(NUMBER_NODE, "4 4 4"));
ValuePtr result = FunctionLinkCast(divide)->execute();
FloatValuePtr expect = createFloatValue(std::vector<double>{0.0, 0.25, 0.5});
printf("expect: %s", expect->to_string().c_str());
printf("result: %s\n", result->to_string().c_str());
TS_ASSERT(*expect == *FloatValueCast(result));
// value must not get corrupted.
check();
// 3/(x+1) --------------------------------------------
divide = al(DIVIDE_LINK, an(NUMBER_NODE, "3 3 3"),
al(PLUS_LINK, valof, an(NUMBER_NODE, "1 1 1")));
result = FunctionLinkCast(divide)->execute();
expect = createFloatValue(std::vector<double>{3.0, 3.0/2.0, 3.0/3.0});
printf("expect: %s", expect->to_string().c_str());
printf("result: %s\n", result->to_string().c_str());
TS_ASSERT(*expect == *FloatValueCast(result));
// value must not get corrupted.
check();
// vector divide vector ----------------------------------------------
divide = al(DIVIDE_LINK, {
al(PLUS_LINK, {valof, an(NUMBER_NODE, "7")}),
al(PLUS_LINK, {valof, an(NUMBER_NODE, "7")})});
result = FunctionLinkCast(divide)->execute();
expect = createFloatValue(std::vector<double>{1.0, 1.0, 1.0});
printf("expect: %s", expect->to_string().c_str());
printf("result: %s\n", result->to_string().c_str());
TS_ASSERT(*expect == *FloatValueCast(result));
// value must not get corrupted.
check();
logger().debug("END TEST: %s", __FUNCTION__);
}
// ====================================================================
// Make sure that NumberNodes can be used as values.
//
void ValueOfUTest::test_number()
{
logger().debug("BEGIN TEST: %s", __FUNCTION__);
value = an(NUMBER_NODE, "3");
atom->setValue(key, value);
Handle valof = al(FLOAT_VALUE_OF_LINK, atom, key);
// 3/4 --------------------------------------------
Handle divide = al(DIVIDE_LINK, {valof, an(NUMBER_NODE, "4")});
ValuePtr result = FunctionLinkCast(divide)->execute();
NumberNodePtr expect = NumberNodeCast(an(NUMBER_NODE, "0.75"));
printf("expect: %s\n", expect->to_string().c_str());
printf("result: %s\n", result->to_string().c_str());
TS_ASSERT(*expect == *NumberNodeCast(result));
logger().debug("END TEST: %s", __FUNCTION__);
}