/*
* tests/atoms/join/TrueJoinUTest.cxxtest
*
* Copyright (C) 2020 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/atoms/value/LinkValue.h>
#include <opencog/atomspace/AtomSpace.h>
#include <opencog/guile/SchemeEval.h>
#include <opencog/util/Logger.h>
using namespace opencog;
class TrueJoinUTest: public CxxTest::TestSuite
{
private:
AtomSpacePtr _as;
SchemeEval* eval;
public:
TrueJoinUTest(void)
{
logger().set_level(Logger::INFO);
logger().set_print_to_stdout_flag(true);
logger().set_timestamp_flag(false);
logger().set_sync_flag(true);
_as = createAtomSpace();
eval = SchemeEval::get_scheme_evaluator(_as);
eval->eval("(add-to-load-path \"" PROJECT_SOURCE_DIR "\")");
}
~TrueJoinUTest()
{
// 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);
// Test the examples on the wiki page
// https://wiki.opencog.org/w/JoinLink
void test_filter(void);
void test_filter_again(void);
void test_top_type(void);
void test_const(void);
void test_upper(void);
};
void TrueJoinUTest::tearDown(void)
{
_as->clear();
}
void TrueJoinUTest::setUp(void)
{
_as->clear();
}
#define N _as->add_node
#define L _as->add_link
/*
* Wiki page "Filter intersection"
*/
void TrueJoinUTest::test_filter(void)
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
eval->eval("(load-from-path \"tests/atoms/join/true-join.scm\")");
// ----------------------------------
ValuePtr vp = eval->eval_v("(cog-execute! min-filter-ab)");
printf("min-filter-ab = %s\n", vp->to_string().c_str());
TS_ASSERT(nameserver().isA(vp->get_type(), LINK_VALUE));
HandleSeq results = LinkValueCast(vp)->to_handle_seq();
TS_ASSERT_EQUALS(results.size(), 2);
Handle X = N(VARIABLE_NODE, "X");
Handle Y = N(VARIABLE_NODE, "Y");
Handle C = N(CONCEPT_NODE, "C");
Handle LAB = L(LIST_LINK, X, Y);
Handle LABC = L(LIST_LINK, X, Y, C);
if (results[0] == LAB)
{
TS_ASSERT_EQUALS(results[0], LAB);
TS_ASSERT_EQUALS(results[1], LABC);
}
else
{
TS_ASSERT_EQUALS(results[1], LAB);
TS_ASSERT_EQUALS(results[0], LABC);
}
// ----------------------------------
vp = eval->eval_v("(cog-execute! max-filter-ab)");
printf("max-filter-ab = %s\n", vp->to_string().c_str());
TS_ASSERT(nameserver().isA(vp->get_type(), LINK_VALUE));
results = LinkValueCast(vp)->to_handle_seq();
TS_ASSERT_EQUALS(results.size(), 2);
Handle PAB = L(EVALUATION_LINK, N(PREDICATE_NODE, "Pab"), LAB);
Handle PABC = L(EVALUATION_LINK, N(PREDICATE_NODE, "Pabc"), LABC);
if (results[0] == PAB)
{
TS_ASSERT_EQUALS(results[0], PAB);
TS_ASSERT_EQUALS(results[1], PABC);
}
else
{
TS_ASSERT_EQUALS(results[1], PAB);
TS_ASSERT_EQUALS(results[0], PABC);
}
// ------------
logger().info("END TEST: %s", __FUNCTION__);
}
/*
* Wiki page "Filter intersection, again"
*/
void TrueJoinUTest::test_filter_again(void)
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
eval->eval("(load-from-path \"tests/atoms/join/true-join.scm\")");
// ----------------------------------
ValuePtr vp = eval->eval_v("(cog-execute! min-filter-ap)");
printf("min-filter-ap = %s\n", vp->to_string().c_str());
TS_ASSERT(nameserver().isA(vp->get_type(), LINK_VALUE));
HandleSeq results = LinkValueCast(vp)->to_handle_seq();
TS_ASSERT_EQUALS(results.size(), 2);
Handle A = N(CONCEPT_NODE, "A");
Handle Y = N(VARIABLE_NODE, "Y");
Handle P = N(VARIABLE_NODE, "P");
Handle C = N(CONCEPT_NODE, "C");
Handle LAB = L(LIST_LINK, A, Y);
Handle LABC = L(LIST_LINK, A, Y, C);
Handle PAB = L(EVALUATION_LINK, P, LAB);
Handle PABC = L(EVALUATION_LINK, P, LABC);
if (results[0] == PAB)
{
TS_ASSERT_EQUALS(results[0], PAB);
TS_ASSERT_EQUALS(results[1], PABC);
}
else
{
TS_ASSERT_EQUALS(results[1], PAB);
TS_ASSERT_EQUALS(results[0], PABC);
}
// ----------------------------------
vp = eval->eval_v("(cog-execute! max-filter-ap)");
printf("max-filter-ap = %s\n", vp->to_string().c_str());
TS_ASSERT(nameserver().isA(vp->get_type(), LINK_VALUE));
results = LinkValueCast(vp)->to_handle_seq();
TS_ASSERT_EQUALS(results.size(), 2);
if (results[0] == PAB)
{
TS_ASSERT_EQUALS(results[0], PAB);
TS_ASSERT_EQUALS(results[1], PABC);
}
else
{
TS_ASSERT_EQUALS(results[1], PAB);
TS_ASSERT_EQUALS(results[0], PABC);
}
// ------------
logger().info("END TEST: %s", __FUNCTION__);
}
/*
* Wiki page "Container type"
*/
void TrueJoinUTest::test_top_type(void)
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
eval->eval("(load-from-path \"tests/atoms/join/true-container.scm\")");
// ----------------------------------
ValuePtr vp = eval->eval_v("(cog-execute! min-top)");
printf("min-top = %s\n", vp->to_string().c_str());
TS_ASSERT(nameserver().isA(vp->get_type(), LINK_VALUE));
HandleSeq results = LinkValueCast(vp)->to_handle_seq();
TS_ASSERT_EQUALS(results.size(), 0);
// ----------------------------------
vp = eval->eval_v("(cog-execute! max-top)");
printf("max-top = %s\n", vp->to_string().c_str());
TS_ASSERT(nameserver().isA(vp->get_type(), LINK_VALUE));
results = LinkValueCast(vp)->to_handle_seq();
TS_ASSERT_EQUALS(results.size(), 1);
Handle E = L(EVALUATION_LINK, N(PREDICATE_NODE, "P"),
L(LIST_LINK, N(VARIABLE_NODE, "X")));
TS_ASSERT_EQUALS(results[0], E);
// ------------
logger().info("END TEST: %s", __FUNCTION__);
}
/*
* constant tests. Not on the wiki page, but follows almost trivially.
*/
void TrueJoinUTest::test_const(void)
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
eval->eval("(load-from-path \"tests/atoms/join/true-join.scm\")");
// ----------------------------------
ValuePtr vp = eval->eval_v("(cog-execute! min-const-ab)");
printf("min-const-ab = %s\n", vp->to_string().c_str());
TS_ASSERT(nameserver().isA(vp->get_type(), LINK_VALUE));
HandleSeq results = LinkValueCast(vp)->to_handle_seq();
TS_ASSERT_EQUALS(results.size(), 2);
Handle A = N(CONCEPT_NODE, "A");
Handle B = N(CONCEPT_NODE, "B");
Handle C = N(CONCEPT_NODE, "C");
Handle LAB = L(LIST_LINK, A, B);
Handle LABC = L(LIST_LINK, A, B, C);
if (results[0] == LAB)
{
TS_ASSERT_EQUALS(results[0], LAB);
TS_ASSERT_EQUALS(results[1], LABC);
}
else
{
TS_ASSERT_EQUALS(results[1], LAB);
TS_ASSERT_EQUALS(results[0], LABC);
}
// ----------------------------------
vp = eval->eval_v("(cog-execute! max-const-ab)");
printf("max-const-ab = %s\n", vp->to_string().c_str());
TS_ASSERT(nameserver().isA(vp->get_type(), LINK_VALUE));
results = LinkValueCast(vp)->to_handle_seq();
TS_ASSERT_EQUALS(results.size(), 2);
Handle PAB = L(EVALUATION_LINK, N(PREDICATE_NODE, "Pab"), LAB);
Handle PABC = L(EVALUATION_LINK, N(PREDICATE_NODE, "Pabc"), LABC);
if (results[0] == PAB)
{
TS_ASSERT_EQUALS(results[0], PAB);
TS_ASSERT_EQUALS(results[1], PABC);
}
else
{
TS_ASSERT_EQUALS(results[1], PAB);
TS_ASSERT_EQUALS(results[0], PABC);
}
// ----------------------------------
vp = eval->eval_v("(cog-execute! min-const-ap)");
printf("min-const-ap = %s\n", vp->to_string().c_str());
TS_ASSERT(nameserver().isA(vp->get_type(), LINK_VALUE));
results = LinkValueCast(vp)->to_handle_seq();
TS_ASSERT_EQUALS(results.size(), 1);
TS_ASSERT_EQUALS(results[0], B);
// ----------------------------------
vp = eval->eval_v("(cog-execute! max-const-ap)");
printf("max-const-ap = %s\n", vp->to_string().c_str());
TS_ASSERT(nameserver().isA(vp->get_type(), LINK_VALUE));
results = LinkValueCast(vp)->to_handle_seq();
TS_ASSERT_EQUALS(results.size(), 2);
Handle P = N(VARIABLE_NODE, "P");
Handle VPAB = L(EVALUATION_LINK, P, LAB);
Handle VPABC = L(EVALUATION_LINK, P, LABC);
if (results[0] == VPAB)
{
TS_ASSERT_EQUALS(results[0], VPAB);
TS_ASSERT_EQUALS(results[1], VPABC);
}
else
{
TS_ASSERT_EQUALS(results[1], VPAB);
TS_ASSERT_EQUALS(results[0], VPABC);
}
// ------------
logger().info("END TEST: %s", __FUNCTION__);
}
/*
* Wiki page "Minimal vs. Upper vs. Maximal"
*/
void TrueJoinUTest::test_upper(void)
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
eval->eval("(load-from-path \"tests/atoms/join/true-upper.scm\")");
// ----------------------------------
ValuePtr vp = eval->eval_v("(cog-execute! min-join)");
printf("min-join = %s\n", vp->to_string().c_str());
TS_ASSERT(nameserver().isA(vp->get_type(), LINK_VALUE));
HandleSeq results = LinkValueCast(vp)->to_handle_seq();
TS_ASSERT_EQUALS(results.size(), 1);
Handle B = N(CONCEPT_NODE, "bird");
Handle C = N(CONCEPT_NODE, "crow");
Handle M = L(MEMBER_LINK, C, B);
TS_ASSERT_EQUALS(results[0], M);
// ----------------------------------
vp = eval->eval_v("(cog-execute! max-join)");
printf("max-join = %s\n", vp->to_string().c_str());
TS_ASSERT(nameserver().isA(vp->get_type(), LINK_VALUE));
results = LinkValueCast(vp)->to_handle_seq();
TS_ASSERT_EQUALS(results.size(), 1);
Handle R = L(LIST_LINK, N(CONCEPT_NODE, "class"), M);
Handle E = L(EVALUATION_LINK, N(PREDICATE_NODE, "ontology"), R);
TS_ASSERT_EQUALS(results[0], E);
// ----------------------------------
vp = eval->eval_v("(cog-execute! upper-set)");
printf("max-join = %s\n", vp->to_string().c_str());
TS_ASSERT(nameserver().isA(vp->get_type(), LINK_VALUE));
results = LinkValueCast(vp)->to_handle_seq();
TS_ASSERT_EQUALS(results.size(), 3);
bool m=false, r=false, e=false;
for (const Handle& hr : results)
{
if (hr == M) m=true;
if (hr == R) r=true;
if (hr == E) e=true;
}
TSM_ASSERT(m and r and e, "failed to find all three!");
// ------------
logger().info("END TEST: %s", __FUNCTION__);
}