OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-matrix / tests / matrix / VectorAPIUTest.cxxtest

790 lines · cxxtest ref:
/*
 * tests/matrix/VectorAPIUTest.cxxtest
 *
 * Verifies that assorted matrix functions work as claimed.
 * Copyright (C) 2018 Linas Vepstas <linasvepstas@gmail.com>
 * 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 <math.h>

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

#include "test-types.h"

using namespace opencog;
using namespace std;

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

	public:

	VectorAPIUTest(void)
	{
		logger().set_level(Logger::DEBUG);
		logger().set_print_to_stdout_flag(true);
#include "test-types.cc"
	}

	~VectorAPIUTest()
	{
		// 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);

	double mmt_trop(std::string, std::string);
	double mtm_trop(std::string, std::string);

	void test_basic(void);
	void test_marginals(void);
	void test_fast(void);
	void test_cosines(void);
	void test_dynamic(void);
	void test_fold(void);
	void test_transpose(void);
	void test_symmetric_mi(void);
};

#define CHKERR \
	TSM_ASSERT("Caught scm error during eval", \
		(false == eval->eval_error()));

#define CHKPRT(X) printf("Got >>%s<<\n", X.c_str()); CHKERR;

#define CHKNUM(MSG,X,VAL) \
	printf("Expect %s=%d got=%s", MSG, VAL, X.c_str()); \
	CHKERR; \
	TSM_ASSERT_EQUALS(MSG, atoi(X.c_str()), VAL);

#define EPS 1.0e-9

#define CHKFLT(MSG,X,VAL) \
	printf("Expect %s=%f got=%s", MSG, VAL, X.c_str()); \
	CHKERR; \
	TSM_ASSERT_LESS_THAN(MSG, atof(X.c_str()), VAL+EPS); \
	TSM_ASSERT_LESS_THAN(MSG, VAL-EPS, atof(X.c_str()));

#define CHKCMP(MSG,X,Y) \
	CHKFLT(MSG, X, atof(Y.c_str()))

/*
 * This is called once before each test, for each test (!!)
 */
void VectorAPIUTest::setUp(void)
{
	as = createAtomSpace();
	eval = SchemeEval::get_scheme_evaluator(as);

	// Proper UTF-8 behaviour requires the right locale.
	// Do not use LC_ALL, as otherwise the printing of the numeric
	// quantities (immediately below) get commas, not decimal points,
	// in the majority of European locales. Unfortunately, guile number
	// parsing is not locale dependent...
	// eval->eval("(setlocale LC_ALL \"\")");
	eval->eval("(setlocale LC_CTYPE \"\")");
	eval->clear_pending();

	eval->eval("(add-to-load-path \"" PROJECT_SOURCE_DIR "\")");
	CHKERR;
	
	eval->eval("(load-from-path \"tests/matrix/test_types.scm\")");
	CHKERR;
	eval->eval("(load-from-path \"tests/matrix/basic-api.scm\")");
	CHKERR;

	// XXX FIXME not needed, but get a weird link bug without this
	eval->eval("(use-modules (opencog exec))");
	CHKERR;
}

void VectorAPIUTest::tearDown(void)
{
}

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

void VectorAPIUTest::test_basic(void)
{
	logger().debug("BEGIN TEST: %s", __FUNCTION__);

	std::string rc = eval->eval("(load-from-path \"tests/matrix/basic-data.scm\")");
	printf("Load of data >>>%s", rc.c_str());
	CHKERR;

	std::string tru = eval->eval("(eq? 'WordNode (bapi 'left-type))");
	printf ("L Got >>>%s", tru.c_str());
	CHKERR; TSM_ASSERT_EQUALS("Expecting #t", tru, "#t\n");

	tru = eval->eval("(eq? 'WordNode (bapi 'right-type))");
	CHKERR; TSM_ASSERT_EQUALS("Expecting #t", tru, "#t\n");

	tru = eval->eval("(equal? \"unit-test-demo\" (bapi 'id))");
	CHKERR; TSM_ASSERT_EQUALS("Expecting #t", tru, "#t\n");

	tru = eval->eval(
		"(equal? chicken-legs (bapi 'get-pair (Word \"chicken\") (Word \"legs\")))");
	CHKERR; TSM_ASSERT_EQUALS("Expecting #t", tru, "#t\n");

	tru = eval->eval(
		"(equal? 3.0 (sapi 'pair-count (Word \"chicken\") (Word \"legs\")))");
	printf ("P Got >>>%s", tru.c_str());
	CHKERR; TSM_ASSERT_EQUALS("Expecting #t", tru, "#t\n");

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

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

void VectorAPIUTest::test_marginals(void)
{
#ifdef HAVE_ROCKS_STORAGE
	logger().debug("BEGIN TEST: %s", __FUNCTION__);

	std::string rc = eval->eval("(load-from-path \"tests/matrix/basic-data.scm\")");
	printf("Load of data >>>%s", rc.c_str());
	CHKERR;

	// -------------------------------------------------------------
	// Where the data will go
	rc = eval->eval("(use-modules (opencog persist-rocks))");
	CHKERR;

	rc = eval->eval("(define rsn (RocksStorageNode \"rocks:///tmp/vector-api-utest-marginals/\"))");
	CHKERR;

	rc = eval->eval("(cog-open rsn)");
	CHKERR;

	// Compute and store all marginals
	rc = eval->eval("(batch-all-pair-mi bapi)");
	printf("Batch >>>%s", rc.c_str());
	CHKERR;

	rc = eval->eval("(cog-close rsn)");
	CHKERR;

	printf("---------------------------------------------------------\n");
	// Verify that the marginals were correctly computed
	std::string num = eval->eval("(papi 'left-basis-size)");
	CHKNUM("Left size", num, 3);

	num = eval->eval("(papi 'right-basis-size)");
	CHKNUM("Right size", num, 4);

	num = eval->eval("(papi 'total-sum-left)");
	CHKNUM("Wild-wild count-left", num, 22);
	num = eval->eval("(papi 'total-sum-right)");
	CHKNUM("Wild-wild count-right", num, 22);

	num = eval->eval("(papi 'total-count-left)");
	CHKNUM("Wild-wild count-left", num, 22);
	num = eval->eval("(papi 'total-count-right)");
	CHKNUM("Wild-wild count-right", num, 22);

	num = eval->eval("(length (papi 'right-stars (Word \"chicken\")))");
	CHKNUM("chicken stars", num, 3);

	num = eval->eval("(length (papi 'right-stars (Word \"dog\")))");
	CHKNUM("dog stars", num, 3);

	num = eval->eval("(length (papi 'right-stars (Word \"table\")))");
	CHKNUM("table stars", num, 1);

	num = eval->eval("(length (papi 'left-stars (Word \"legs\")))");
	CHKNUM("legs stars", num, 3);

	num = eval->eval("(length (papi 'left-stars (Word \"eyes\")))");
	CHKNUM("eyes stars", num, 2);

	num = eval->eval("(length (papi 'left-stars (Word \"wings\")))");
	CHKNUM("wings stars", num, 1);

	num = eval->eval("(length (papi 'left-stars (Word \"snouts\")))");
	CHKNUM("snouts stars", num, 1);

	printf("---------------------------------------------------------\n");
	// Verify that the support API is not insane
	num = eval->eval("(papi 'right-support (Word \"chicken\"))");
	CHKNUM("chicken support", num, 3);

	num = eval->eval("(papi 'right-support (Word \"dog\"))");
	CHKNUM("dog support", num, 3);

	num = eval->eval("(papi 'right-support (Word \"table\"))");
	CHKNUM("table support", num, 1);

	num = eval->eval("(papi 'left-support (Word \"legs\"))");
	CHKNUM("legs support", num, 3);

	num = eval->eval("(papi 'left-support (Word \"eyes\"))");
	CHKNUM("eyes support", num, 2);

	num = eval->eval("(papi 'left-support (Word \"wings\"))");
	CHKNUM("wings support", num, 1);

	num = eval->eval("(papi 'left-support (Word \"snouts\"))");
	CHKNUM("snouts support", num, 1);

	printf("---------------------------------------------------------\n");
	// Verify that the count API is not insane
	num = eval->eval("(papi 'right-count (Word \"chicken\"))");
	CHKNUM("chicken count", num, 11);

	num = eval->eval("(papi 'right-count (Word \"dog\"))");
	CHKNUM("dog count", num, 7);

	num = eval->eval("(papi 'right-count (Word \"table\"))");
	CHKNUM("table count", num, 4);

	num = eval->eval("(papi 'left-count (Word \"legs\"))");
	CHKNUM("legs count", num, 11);

	num = eval->eval("(papi 'left-count (Word \"eyes\"))");
	CHKNUM("eyes count", num, 4);

	num = eval->eval("(papi 'left-count (Word \"wings\"))");
	CHKNUM("wings count", num, 6);

	num = eval->eval("(papi 'left-count (Word \"snouts\"))");
	CHKNUM("snouts count", num, 1);

	printf("---------------------------------------------------------\n");
	// Verify that the compute-support object functions correctly
	num = eval->eval("(length (pcmp 'right-support-set (Word \"chicken\")))");
	CHKNUM("chicken support set size", num, 3);

	num = eval->eval("(pcmp 'right-support (Word \"chicken\"))");
	CHKNUM("chicken support", num, 3);

	num = eval->eval("(pcmp 'right-support (Word \"dog\"))");
	CHKNUM("dog support", num, 3);

	num = eval->eval("(pcmp 'right-support (Word \"table\"))");
	CHKNUM("table support", num, 1);

	num = eval->eval("(pcmp 'left-support (Word \"legs\"))");
	CHKNUM("legs stars", num, 3);

	num = eval->eval("(pcmp 'left-support (Word \"wings\"))");
	CHKNUM("wings stars", num, 1);

	num = eval->eval("(pcmp 'left-support (Word \"eyes\"))");
	CHKNUM("eyes stars", num, 2);

	num = eval->eval("(pcmp 'left-support (Word \"snouts\"))");
	CHKNUM("snouts stars", num, 1);

	eval->eval("(pcmp 'left-marginals)");
	eval->eval("(pcmp 'right-marginals)");

	num = eval->eval("(pcmp 'total-support-left)");
	CHKNUM("total support left", num, 7);

	num = eval->eval("(pcmp 'total-support-right)");
	CHKNUM("total support right", num, 7);

	num = eval->eval("(pcmp 'total-count-left)");
	CHKNUM("total count left", num, 22);

	num = eval->eval("(pcmp 'total-count-right)");
	CHKNUM("total count right", num, 22);

	printf("---------------------------------------------------------\n");
	// Verify marginal frequencies
	num = eval->eval("(fapi 'right-wild-freq (Word \"chicken\"))");
	CHKFLT("chicken wild-freq", num, 11.0/22.0);

	num = eval->eval("(fapi 'right-wild-freq (Word \"dog\"))");
	CHKFLT("dog wild-freq", num, 7.0/22.0);

	num = eval->eval("(fapi 'right-wild-freq (Word \"table\"))");
	CHKFLT("table wild-freq", num, 4.0/22.0);

	printf("---------------------------------------------------------\n");
	// Verify that the central-compute object computes stuff correctly

	// 3 3 1 are the chicken,dog,table supports while 11 7 4 are the counts.
	num = eval->eval("(cent 'right-support)");
	CHKFLT("total right support", num, (3.0*(11.0/22) + 3.0*(7.0/22.0) + (4.0/22.0)));

	// 3 2 1 1 are the legs,eyes,wings,snouts supports while 11 4 6 1 are the counts
	num = eval->eval("(cent 'left-support)");
	CHKFLT("total left support", num,
		(3.0*(11.0/22.0) + 2.0*(4.0/22.0) + (6.0/22.0) + (1.0/22.0)));

	num = eval->eval("(cent 'right-count)");
	CHKFLT("total right count", num, (11.0*(11.0/22) + 7.0*(7.0/22.0) + 4.0*(4.0/22.0)));

	num = eval->eval("(cent 'left-count)");
	CHKFLT("total left count", num,
		(11.0*(11.0/22.0) + 4.0*(4.0/22.0) + 6.0*(6.0/22.0) + (1.0/22.0)));

	printf("---------------------------------------------------------\n");
	// Verify that the report objects reports the marginals correctly
	num = eval->eval("(rapi 'left-dim)");
	CHKNUM("left dimension", num, 3);

	num = eval->eval("(rapi 'right-dim)");
	CHKNUM("right dimension", num, 4);

	num = eval->eval("(rapi 'num-pairs)");
	CHKNUM("num-pairs", num, 7);

	num = eval->eval("(rapi 'total-count)");
	CHKNUM("total-count", num, 22);

	// See above for explanation of magic formula
	num = eval->eval("(rapi 'right-support)");
	CHKFLT("report right support", num, (3.0*(11.0/22) + 3.0*(7.0/22.0) + (4.0/22.0)));

	num = eval->eval("(rapi 'left-support)");
	CHKFLT("report left support", num,
		(3.0*(11.0/22.0) + 2.0*(4.0/22.0) + (6.0/22.0) + (1.0/22.0)));

	num = eval->eval("(rapi 'right-count)");
	CHKFLT("report right count", num, (11.0*(11.0/22) + 7.0*(7.0/22.0) + 4.0*(4.0/22.0)));

	num = eval->eval("(rapi 'left-count)");
	CHKFLT("report left count", num,
		(11.0*(11.0/22.0) + 4.0*(4.0/22.0) + 6.0*(6.0/22.0) + (1.0/22.0)));

	printf("---------------------------------------------------------\n");
	// Verify marginal mutual information
	double chmi = 0.0;
	chmi += (3.0/22.0) * log((3.0 * 22.0)/(11.0 * 11.0));  // chicken-legs=3   chicken-*=11 *-legs=11
	chmi += (6.0/22.0) * log((6.0 * 22.0)/(11.0 *  6.0));  // chicken-wings=6  chicken-*=11 *-wings=6
	chmi += (2.0/22.0) * log((2.0 * 22.0)/(11.0 *  4.0));  // chicken-eyes=2   chicken-*=11 *-eyes=4
	// chmi += (0.0/22.0) * log((0.0 * 22.0)/(11.0 *  1.0));  // chicken-snouts=0 chicken-*=11 *-snouts=1
	chmi /= log(2.0);
	num = eval->eval("(fapi 'right-wild-mi (Word \"chicken\"))");
	CHKFLT("chicken wild-mi", num, chmi);

	double domi = 0.0;
	domi += (4.0/22.0) * log((4.0 * 22.0)/(7.0 * 11.0));  // dog-legs=4   dog-*=7 *-legs=11
	// mi += (0.0/22.0) * log((0.0 * 22.0)/(7.0 *  6.0));  // dog-wings=0  dog-*=7 *-wings=6
	domi += (2.0/22.0) * log((2.0 * 22.0)/(7.0 *  4.0));  // dog-eyes=2   dog-*=7 *-eyes=4
	domi += (1.0/22.0) * log((1.0 * 22.0)/(7.0 *  1.0));  // dog-snouts=1 dog-*=7 *-snouts=1
	domi /= log(2.0);

	num = eval->eval("(fapi 'right-wild-mi (Word \"dog\"))");
	CHKFLT("dog wild-mi", num, domi);

	double tami = 0.0;
	tami += (4.0/22.0) * log((4.0 * 22.0)/(4.0 * 11.0));  // table-legs=4   table-*=4 *-legs=11
	// tami += (0.0/22.0) * log((0.0 * 22.0)/(4.0 *  6.0));  // table-wings=0  table-*=4 *-wings=6
	// tami += (0.0/22.0) * log((0.0 * 22.0)/(4.0 *  4.0));  // table-eyes=0   table-*=4 *-eyes=4
	// tami += (0.0/22.0) * log((0.0 * 22.0)/(4.0 *  1.0));  // table-snouts=0 table-*=4 *-snouts=1
	tami /= log(2.0);

	num = eval->eval("(fapi 'right-wild-mi (Word \"table\"))");
	CHKFLT("table wild-mi", num, tami);

	num = eval->eval("(rapi 'total-mi)");
	CHKFLT("report total mi", num, chmi+domi+tami);

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

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

void VectorAPIUTest::test_fast(void)
{
	logger().debug("BEGIN TEST: %s", __FUNCTION__);

	std::string rc = eval->eval("(load-from-path \"tests/matrix/basic-data.scm\")");
	printf("Load of data >>>%s", rc.c_str());
	CHKERR;

	std::string num, nut, nuf;
	num = eval->eval("(cosi 'right-product (Word \"table\") (Word \"dog\"))");
	nut = eval->eval("(prod-t 'right-count (list (Word \"table\") (Word \"dog\")))");
	nuf = eval->eval("(prod-f 'right-count (list (Word \"table\") (Word \"dog\")))");

	CHKCMP("tuple-product(table,dog)", num, nut);
	CHKCMP("fast-product (table,dog)", num, nuf);
	// --------------

	num = eval->eval("(cosi 'right-product (Word \"chicken\") (Word \"dog\"))");
	nut = eval->eval("(prod-t 'right-count (list (Word \"chicken\") (Word \"dog\")))");
	nuf = eval->eval("(prod-f 'right-count (list (Word \"chicken\") (Word \"dog\")))");

	CHKCMP("tuple-product(chicken,dog)", num, nut);
	CHKCMP("fast-product (chicken,dog)", num, nuf);
	// --------------

	num = eval->eval("(cosi 'right-product (Word \"table\") (Word \"chicken\"))");
	nut = eval->eval("(prod-t 'right-count (list (Word \"table\") (Word \"chicken\")))");
	nuf = eval->eval("(prod-f 'right-count (list (Word \"table\") (Word \"chicken\")))");

	CHKCMP("tuple-product(table,chicken)", num, nut);
	CHKCMP("fast-product (table,chicken)", num, nuf);
	// --------------

#define LEFT_PROD(A,B)\
	num = eval->eval("(cosi 'left-product (Word \"" A "\") (Word \"" B "\"))");\
	nut = eval->eval("(prod-t 'left-count (list (Word \"" A "\") (Word \"" B "\")))");\
	nuf = eval->eval("(prod-f 'left-count (list (Word \"" A "\") (Word \"" B "\")))");\
	CHKCMP("tuple-product(" A "," B ")", num, nut);\
	CHKCMP("fast-product (" A "," B ")", num, nuf);

	LEFT_PROD("wings", "wings")
	LEFT_PROD("wings", "eyes")
	LEFT_PROD("wings", "legs")
	LEFT_PROD("wings", "snouts")

	LEFT_PROD("eyes", "eyes")
	LEFT_PROD("eyes", "legs")
	LEFT_PROD("eyes", "snouts")

	LEFT_PROD("legs", "legs")
	LEFT_PROD("legs", "snouts")

	LEFT_PROD("snouts", "snouts")

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

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

void VectorAPIUTest::test_cosines(void)
{
	logger().debug("BEGIN TEST: %s", __FUNCTION__);

	std::string rc = eval->eval("(load-from-path \"tests/matrix/basic-data.scm\")");
	printf("Load of data >>>%s", rc.c_str());
	CHKERR;

	std::string num = eval->eval("(cosi 'right-product (Word \"table\") (Word \"dog\"))");
	double ptado = 4.0*4.0;
	CHKFLT("product (table,dog)", num, ptado);

	num = eval->eval("(cosi 'right-cosine (Word \"table\") (Word \"dog\"))");
	double ctado = (4.0*4.0) / (sqrt(4.0*4.0) * sqrt(4.0*4.0 + 2.0*2.0 + 1.0*1.0));
	CHKFLT("cosine (table,dog)", num, ctado);

	num = eval->eval("(cosi 'right-product (Word \"chicken\") (Word \"table\"))");
	double pchta = 3.0*4.0;
	CHKFLT("product (chicken,table)", num, pchta);

	num = eval->eval("(cosi 'right-cosine (Word \"chicken\") (Word \"table\"))");
	double cchta = (3.0*4.0) / (sqrt(3.0*3.0 + 6.0*6.0 + 2.0*2.0) * sqrt(4.0*4.0));
	CHKFLT("cosine (chicken,table)", num, cchta);

	num = eval->eval("(cosi 'right-product (Word \"chicken\") (Word \"dog\"))");
	double pchdo = 3.0*4.0 + 2.0*2.0;
	CHKFLT("product (chicken,dog)", num, pchdo);

	num = eval->eval("(cosi 'right-cosine (Word \"chicken\") (Word \"dog\"))");
	double cchdo = (3.0*4.0 + 2.0*2.0) / (sqrt(3.0*3.0 + 6.0*6.0 + 2.0*2.0) * sqrt(4.0*4.0 + 2.0*2.0 + 1.0*1.0));
	CHKFLT("cosine (chicken,dog)", num, cchdo);

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

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

// Make sure data can be fetched from RocksStorage
void VectorAPIUTest::test_dynamic(void)
{
#ifdef HAVE_ROCKS_STORAGE
	logger().debug("BEGIN TEST: %s", __FUNCTION__);

	// Load the test data first
	std::string rc = eval->eval("(load-from-path \"tests/matrix/basic-data.scm\")");
	CHKERR;

	// Where the data will be stored
	rc = eval->eval("(use-modules (opencog persist-rocks))");
	CHKERR;

	rc = eval->eval("(define rsn (RocksStorageNode \"rocks:///tmp/vector-api-utest-dynamic/\"))");
	CHKERR;

	rc = eval->eval("(cog-open rsn)");
	CHKERR;

	// Store the atomspace to RocksStorage
	rc = eval->eval("(store-atomspace rsn)");
	CHKERR;

	std::string num = eval->eval("(dosi 'right-product (Word \"table\") (Word \"dog\"))");
	double ptado = 4.0*4.0;
	CHKFLT("dynamic product (table,dog)", num, ptado);

	num = eval->eval("(dosi 'right-product (Word \"chicken\") (Word \"table\"))");
	double pchta = 3.0*4.0;
	CHKFLT("dynamic product (chicken,table)", num, pchta);

	num = eval->eval("(dosi 'right-product (Word \"chicken\") (Word \"dog\"))");
	double pchdo = 3.0*4.0 + 2.0*2.0;
	CHKFLT("dynamic product (chicken,dog)", num, pchdo);

	rc = eval->eval("(cog-close rsn)");
	CHKERR;

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

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

// Make sure the fold API works
void VectorAPIUTest::test_fold(void)
{
	logger().debug("BEGIN TEST: %s", __FUNCTION__);

	std::string rc = eval->eval("(load-from-path \"tests/matrix/basic-data.scm\")");
	printf("Load of data >>>%s", rc.c_str());
	CHKERR;

	std::string num = eval->eval("(norm 'right-length (list (Word \"table\") (Word \"dog\")))");
	double ta_do = sqrt(2.0*2.0 + 1.0*1.0);
	CHKFLT("length (table - dog)", num, ta_do);

	num = eval->eval("(norm 'right-length (list (Word \"chicken\") (Word \"dog\")))");
	double ch_do = sqrt(1.0*1.0 + 6.0*6.0 + 1.0*1.0);
	CHKFLT("length (chicken - dog)", num, ch_do);

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

// Make sure the transpose API works
void VectorAPIUTest::test_transpose(void)
{
	logger().debug("BEGIN TEST: %s", __FUNCTION__);

	std::string rc = eval->eval("(load-from-path \"tests/matrix/basic-data.scm\")");
	printf("Load of data >>>%s", rc.c_str());
	CHKERR;

	rc = eval->eval("(pcmp 'cache-all)");
	printf("Support compute >>>%s", rc.c_str());
	CHKERR;

	rc = eval->eval("(tcom 'cache-all)");
	printf("Transpose compute >>>%s", rc.c_str());
	CHKERR;

	std::string num = eval->eval("(tcom 'mmt-count (Word \"chicken\"))");
	double chick = 3*11 + 6*6 + 2*4;
	CHKFLT("mmt chicken ", num, chick);

	num = eval->eval("(tcom 'mmt-count (Word \"dog\"))");
	double dog = 4*11 + 2*4 + 1*1;
	CHKFLT("mmt dog ", num, dog);

	num = eval->eval("(tcom 'mmt-count (Word \"table\"))");
	double table = 4*11;
	CHKFLT("mmt table ", num, table);

	num = eval->eval("(tcom 'mtm-count (Word \"legs\"))");
	double legs = 3*11 + 4*7 + 4*4;
	CHKFLT("mtm legs ", num, legs);

	num = eval->eval("(tcom 'mtm-count (Word \"eyes\"))");
	double eyes = 2*11 + 2*7 + 0*4;
	CHKFLT("mtm eyes ", num, eyes);

	num = eval->eval("(tcom 'mtm-count (Word \"wings\"))");
	double wings = 6*11 + 0*7 + 0*4;
	CHKFLT("mtm wings ", num, wings);

	num = eval->eval("(tcom 'mtm-count (Word \"snouts\"))");
	double snouts = 0*11 + 1*7 + 0*4;
	CHKFLT("mtm snouts ", num, snouts);

	// ------------------------------------------------
	// And again, with tapi.

	num = eval->eval("(tapi 'mmt-count (Word \"chicken\"))");
	CHKFLT("api mmt chicken ", num, chick);

	num = eval->eval("(tapi 'mmt-count (Word \"dog\"))");
	CHKFLT("api mmt dog ", num, dog);

	num = eval->eval("(tapi 'mmt-count (Word \"table\"))");
	CHKFLT("api mmt table ", num, table);

	num = eval->eval("(tapi 'mtm-count (Word \"legs\"))");
	CHKFLT("api mtm legs ", num, legs);

	num = eval->eval("(tapi 'mtm-count (Word \"eyes\"))");
	CHKFLT("api mtm eyes ", num, eyes);

	num = eval->eval("(tapi 'mtm-count (Word \"wings\"))");
	CHKFLT("api mtm wings ", num, wings);

	num = eval->eval("(tapi 'mtm-count (Word \"snouts\"))");
	CHKFLT("api mtm snouts ", num, snouts);

	// ------------------------------------------------
	// totals
	num = eval->eval("(tcom 'total-mmt-count)");
	double totmmt = chick + dog + table;
	CHKFLT("total-mmt ", num, totmmt);

	num = eval->eval("(tcom 'total-mtm-count)");
	double totmtm = legs + eyes + wings + snouts;
	CHKFLT("total-mtm ", num, totmtm);

	num = eval->eval("(tapi 'total-mmt-count)");
	CHKFLT("total-mmt ", num, totmmt);

	num = eval->eval("(tapi 'total-mtm-count)");
	CHKFLT("total-mtm ", num, totmtm);

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

double VectorAPIUTest::mmt_trop(std::string lef, std::string rig)
{
	std::string num;
	num = eval->eval("(cosi 'right-product (Word \""
		+ lef + "\") (Word \"" + rig + "\"))");
	double prod = atof(num.c_str());

	num = eval->eval("(tcom 'mmt-count (Word \"" + lef + "\"))");
	double margl = atof(num.c_str());

	num = eval->eval("(tcom 'mmt-count (Word \"" + rig + "\"))");
	double margr = atof(num.c_str());

	num = eval->eval("(tcom 'total-mmt-count)");
	double tot = atof(num.c_str());

	return log(prod * tot / (margl * margr)) / log(2.0);
}

double VectorAPIUTest::mtm_trop(std::string lef, std::string rig)
{
	std::string num;
	num = eval->eval("(cosi 'left-product (Word \""
		+ lef + "\") (Word \"" + rig + "\"))");
	double prod = atof(num.c_str());

	num = eval->eval("(tcom 'mtm-count (Word \"" + lef + "\"))");
	double margl = atof(num.c_str());

	num = eval->eval("(tcom 'mtm-count (Word \"" + rig + "\"))");
	double margr = atof(num.c_str());

	num = eval->eval("(tcom 'total-mtm-count)");
	double tot = atof(num.c_str());

	return log(prod * tot / (margl * margr)) / log(2.0);
}

// Make sure the symmetric-MI API works
void VectorAPIUTest::test_symmetric_mi(void)
{
	logger().debug("BEGIN TEST: %s", __FUNCTION__);

	std::string rc = eval->eval("(load-from-path \"tests/matrix/basic-data.scm\")");
	printf("Load of data >>>%s", rc.c_str());
	CHKERR;

	rc = eval->eval("(pcmp 'cache-all)");
	printf("Support compute >>>%s", rc.c_str());
	CHKERR;

	rc = eval->eval("(tcom 'cache-all)");
	printf("Transpose compute >>>%s", rc.c_str());
	CHKERR;

	std::string num;
	num = eval->eval("(symc 'mmt-fmi (Word \"chicken\") (Word \"dog\"))");
	double chidog = log( 174 * 16 / (53.0 * 77.0)) / log(2.0);
	CHKFLT("chicken-dog fmi", num, chidog);

	chidog = mmt_trop("chicken", "dog");
	CHKFLT("chicken-dog fmi again", num, chidog);

	num = eval->eval("(symc 'mmt-fmi (Word \"chicken\") (Word \"table\"))");
	double chitable = mmt_trop("chicken", "table");
	CHKFLT("chicken-table fmi", num, chitable);

	num = eval->eval("(symc 'mmt-fmi (Word \"table\") (Word \"dog\"))");
	double dogtab = mmt_trop("table", "dog");
	CHKFLT("dog-table fmi", num, dogtab);

	num = eval->eval("(symc 'mmt-fmi (Word \"chicken\") (Word \"chicken\"))");
	double chichi = mmt_trop("chicken", "chicken");
	CHKFLT("chicken-chicken fmi", num, chichi);

	num = eval->eval("(symc 'mmt-fmi (Word \"dog\") (Word \"dog\"))");
	double dogdog = mmt_trop("dog", "dog");
	CHKFLT("dog-dog fmi", num, dogdog);

	num = eval->eval("(symc 'mmt-fmi (Word \"table\") (Word \"table\"))");
	double tabtab = mmt_trop("table", "table");
	CHKFLT("table-table fmi", num, tabtab);

   // --------
	num = eval->eval("(symc 'mtm-fmi (Word \"wings\") (Word \"eyes\"))");
	double weyes = mtm_trop("wings", "eyes");
	CHKFLT("wings-eyes fmi", num, weyes);

	num = eval->eval("(symc 'mtm-fmi (Word \"eyes\") (Word \"wings\"))");
	double ew = mtm_trop("eyes", "wings");
	CHKFLT("eyes-wings", num, ew);
	CHKFLT("wings-eyes fmi", num, weyes);

	num = eval->eval("(symc 'mtm-fmi (Word \"eyes\") (Word \"legs\"))");
	double elegs = mtm_trop("eyes", "legs");
	CHKFLT("eyes-legs fmi", num, elegs);

	num = eval->eval("(symc 'mtm-fmi (Word \"eyes\") (Word \"snouts\"))");
	double esnouts = mtm_trop("eyes", "snouts");
	CHKFLT("eyes-snouts fmi", num, esnouts);

	num = eval->eval("(symc 'mtm-fmi (Word \"wings\") (Word \"wings\"))");
	double ww = mtm_trop("wings", "wings");
	CHKFLT("wings-wings fmi", num, ww);

	num = eval->eval("(symc 'mtm-fmi (Word \"wings\") (Word \"legs\"))");
	double wlegs = mtm_trop("wings", "legs");
	CHKFLT("wings-legs fmi", num, wlegs);

	num = eval->eval("(symc 'mtm-fmi (Word \"legs\") (Word \"legs\"))");
	double leglegs = mtm_trop("legs", "legs");
	CHKFLT("legs-legs fmi", num, leglegs);

	num = eval->eval("(symc 'mtm-fmi (Word \"legs\") (Word \"snouts\"))");
	double lesnouts = mtm_trop("legs", "snouts");
	CHKFLT("legs-snouts fmi", num, lesnouts);

	num = eval->eval("(symc 'mtm-fmi (Word \"snouts\") (Word \"snouts\"))");
	double sno = mtm_trop("snouts", "snouts");
	CHKFLT("snouts-snouts fmi", num, sno);

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

/* ============================= END OF FILE ================= */