OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-atomspace / tests / atoms / flow / ValueOfUTest.cxxtest

408 lines · cxxtest ref:
/*
 * 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__);
}