OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-atomspace / tests / query / BiggerPatternUTest.cxxtest

324 lines · cxxtest ref:
/*
 * tests/query/BiggerPatternUTest.cxxtest
 *
 * Copyright (C) 2009,2011 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 <opencog/atomspace/AtomSpace.h>
#include <opencog/util/Logger.h>

#include "imply.h"
#include "test-types.h"

using namespace opencog;

class BiggerPatternUTest :  public CxxTest::TestSuite
{
	private:
		AtomSpacePtr as;

		Handle clauses, implicand;
		Handle hbenode, hvar0, hvar1, hvar2, hvar2_france;
		Handle hword0, hprep, hphrase;

	public:

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

		~BiggerPatternUTest()
		{
			// 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 do_tst_prep(void);
		void test_prep_rw(void);
		void test_prep_overlay(void);
};

#define an as->add_node
#define al as->add_link
#define getarity(hand) hand->get_arity()
#define getlink(hand,pos) hand->getOutgoingAtom(pos)
#define prtnode(str,hand) \
	printf("%s %s\n", str, hand->get_name().c_str());

/*
 * This function sets up both the implication link, and the
 * input data, for a typical, real-world preposition deduction.
 *
 * The supplied data is:
 *   _subj (<<be>>, <<capital>>)
 *   _obj (<<be>>, <<Berlin>>)
 *   of (<<capital>>, <<Germany>>)
 *   of (<<capital>>, <<France>>)
 * Note that, for this test case, we've made Berlin the capital of both
 * Germany and France. This sounds crazy, but that's what we want this
 * test case to do.
 *
 * The actual rule encoded below is
 *
 * # IF _subj($cop,$var0)                 ; subject is now $var0
 *       ^ _obj($cop,$var1)               ; object is $var1
 *       ^ %LemmaLink($cop,be)            ; copula verb must be 'be'
 *       ^ $prep($var0,$var2)             ; preposition
 *       ^ %LemmaLink($var0,$word0)       ; word of word instance.
 *       ^ $phrase($word0, $prep)         ; convert to phrase
 *       THEN ^3_$phrase($var2, $var1)
 *
 * Note that there is an implicit LemmaLink created for 'be'.
 */
void BiggerPatternUTest::tearDown(void)
{
}
void BiggerPatternUTest::setUp(void)
{
	as = createAtomSpace();

	// Create an implication link that will be tested.
	clauses =
		al(AND_LINK,
			// _subj(be,$var0)
			al(EVALUATION_LINK,
				an(DEFINED_LINGUISTIC_RELATIONSHIP_NODE, "_subj"),
				al(LIST_LINK,
					an(VARIABLE_NODE, "$benode"),
					an(VARIABLE_NODE, "$var0")
				)
			),
			// _obj(be,$var1)
			al(EVALUATION_LINK,
				an(DEFINED_LINGUISTIC_RELATIONSHIP_NODE, "_obj"),
				al(LIST_LINK,
					an(VARIABLE_NODE, "$benode"),
					an(VARIABLE_NODE, "$var1")
				)
			),
			al(LEMMA_LINK,
				an(VARIABLE_NODE, "$benode"),
				an(WORD_NODE, "be")
			),

			//  $prep($var0,$var2)
			al(EVALUATION_LINK,
				an(VARIABLE_NODE, "$prep"),
				al(LIST_LINK,
					an(VARIABLE_NODE, "$var0"),
					an(VARIABLE_NODE, "$var2")
				)
			),
			al(LEMMA_LINK,
				an(VARIABLE_NODE, "$var0"),
				an(VARIABLE_NODE, "$word0")
			),

			//  $phrase($word0, $prep)
			al(EVALUATION_LINK,
				an(VARIABLE_NODE, "$phrase"),
				al(LIST_LINK,
					an(VARIABLE_NODE, "$word0"),
					an(VARIABLE_NODE, "$prep")
				)
			)
		);
	implicand =
		al(LIST_LINK,
			an(VARIABLE_NODE, "$benode"),
			an(VARIABLE_NODE, "$var0"),
			an(VARIABLE_NODE, "$word0"),
			an(VARIABLE_NODE, "$var1"),
			an(VARIABLE_NODE, "$var2"),
			an(VARIABLE_NODE, "$prep"),
			an(VARIABLE_NODE, "$phrase")
		);

	// Create data on which the above pattern should match
	al(LEMMA_LINK,
		an(WORD_INSTANCE_NODE, "capital@14601ec7-4b6a-4739-b2d6-0213d43be682"),
		hword0 = an(WORD_NODE, "capital")
	);
	al(LEMMA_LINK,
		hbenode = an(WORD_INSTANCE_NODE, "is@a085b454-0d49-414c-b1d1-98d8c5e2cffb"),
		an(WORD_NODE, "be")
	);

	// of (<<capital>>, <<Germany>>)
	al(EVALUATION_LINK,
		hprep = an(DEFINED_LINGUISTIC_RELATIONSHIP_NODE, "of"),
		al(LIST_LINK,
			an(WORD_INSTANCE_NODE, "capital@14601ec7-4b6a-4739-b2d6-0213d43be682"),
			hvar2 = an(WORD_INSTANCE_NODE, "Germany@372c7cd3-a9c9-44bb-bc7b-5bb356dda358")
		)
	);

	// of (<<capital>>, <<France>>)
	al(EVALUATION_LINK,
		hprep = an(DEFINED_LINGUISTIC_RELATIONSHIP_NODE, "of"),
		al(LIST_LINK,
			an(WORD_INSTANCE_NODE, "capital@14601ec7-4b6a-4739-b2d6-0213d43be682"),
			hvar2_france = an(WORD_INSTANCE_NODE, "France@11223344-a9c9-44bb-bc7b-5bb356dda358")
		)
	);

	// ; _subj (<<be>>, <<capital>>)
	al(EVALUATION_LINK,
		an(DEFINED_LINGUISTIC_RELATIONSHIP_NODE, "_subj"),
		al(LIST_LINK,
			an(WORD_INSTANCE_NODE, "is@a085b454-0d49-414c-b1d1-98d8c5e2cffb"),
			hvar0 = an(WORD_INSTANCE_NODE, "capital@14601ec7-4b6a-4739-b2d6-0213d43be682")
		)
	);

	// _obj (<<be>>, <<Berlin>>)
	al(EVALUATION_LINK,
		an(DEFINED_LINGUISTIC_RELATIONSHIP_NODE, "_obj"),
		al(LIST_LINK,
			an(WORD_INSTANCE_NODE, "is@a085b454-0d49-414c-b1d1-98d8c5e2cffb"),
			hvar1 = an(WORD_INSTANCE_NODE, "Berlin@614f9e08-42c7-451f-8dea-0e73d5018029")
		)
	);

	// prep map
	al(EVALUATION_LINK,
		hphrase = an(DEFINED_LINGUISTIC_RELATIONSHIP_NODE, "capital_of"),
		al(LIST_LINK,
			an(WORD_NODE, "capital"),
			an(DEFINED_LINGUISTIC_RELATIONSHIP_NODE, "of")
		)
	);

}

/*
 * Preposition reasoning test.
 *
 * Expect to get the following result, given the above data:
 *
 *   ListLink
 *      $benode = WordInstanceNode "is@a085b454-0d49-414c-b1d1-98d8c5e2cffb"
 *      $var0   = WordInstanceNode "capital@14601ec7-4b6a-4739-b2d6-0213d43be682"
 *      $word0  = WordNode "capital"
 *      $var1   = WordInstanceNode "Berlin@614f9e08-42c7-451f-8dea-0e73d5018029"
 *      $var2   = WordInstanceNode "Germany@372c7cd3-a9c9-44bb-bc7b-5bb356dda358"
 *      $prep   = DefinedLinguisticRelationshipNode "of"
 *      $phrase = DefinedLinguisticRelationshipNode "capital_of"
 */
void BiggerPatternUTest::do_tst_prep(void)
{
	logger().debug("BEGIN TEST: %s", __FUNCTION__);

	// Result should be a ListLink
	Handle imlist = imply(as.get(), clauses, implicand);

	// Expect two answers: Berlin is the capital of Germany,
	// and of France. (just for this test case :-)
	int arity = getarity(imlist);
	TSM_ASSERT_EQUALS("incorrect arity", arity, 2);

	// 0 has France, 1 has Germany
	Handle result_france = getlink(imlist, 0);
	Handle result = getlink(imlist, 1);

	// Actually, changes to atomspace internals can cause this
	// to flip-flop.  In fact, either order is valid. So just make
	// this a run-time flip-flop, not a compile-time one.
	// (For a fixed atomspace & pattern matcher, these won't change).
	if (hvar2_france != getlink(result_france, 4))
	{
		result_france = getlink(imlist,1 );
		result = getlink(imlist, 0);
	}

	Handle vbenode = getlink(result, 0);
	Handle vvar0 = getlink(result, 1);
	Handle vword0 = getlink(result, 2);
	Handle vvar1 = getlink(result, 3);
	Handle vvar2 = getlink(result, 4);
	Handle vprep = getlink(result, 5);
	Handle vphrase = getlink(result, 6);

#if 0
	prtnode("hbenode is", hbenode);
	prtnode("vbenode is", vbenode);
	prtnode("hvar0 is", hvar0);
	prtnode("vvar0 is", vvar0);
	prtnode("hword0 is", hword0);
	prtnode("vword0 is", vword0);
	prtnode("hvar1 is", hvar1);
	prtnode("vvar1 is", vvar1);
	prtnode("hvar2 is", hvar2);
	prtnode("vvar2 is", vvar2);
	prtnode("hprep is", hprep);
	prtnode("vprep is", vprep);
	prtnode("hphrase is", hphrase);
	prtnode("vphrase is", vphrase);
#endif

	TSM_ASSERT_EQUALS("incorrect benode", hbenode, vbenode);
	TSM_ASSERT_EQUALS("incorrect var0", hvar0, vvar0);
	TSM_ASSERT_EQUALS("incorrect word0", hword0, vword0);
	TSM_ASSERT_EQUALS("incorrect var1", hvar1, vvar1);
	TSM_ASSERT_EQUALS("incorrect var2 - Germany", hvar2, vvar2);
	TSM_ASSERT_EQUALS("incorrect prep", hprep, vprep);
	TSM_ASSERT_EQUALS("incorrect phrase", hphrase, vphrase);

	Handle france_benode = getlink(result_france, 0);
	Handle france_var0 = getlink(result_france, 1);
	Handle france_word0 = getlink(result_france, 2);
	Handle france_var1 = getlink(result_france, 3);
	Handle france_var2 = getlink(result_france, 4);
	Handle france_prep = getlink(result_france, 5);
	Handle france_phrase = getlink(result_france, 6);

	TSM_ASSERT_EQUALS("incorrect benode", hbenode, france_benode);
	TSM_ASSERT_EQUALS("incorrect var0", hvar0, france_var0);
	TSM_ASSERT_EQUALS("incorrect word0", hword0, france_word0);
	TSM_ASSERT_EQUALS("incorrect var1", hvar1, france_var1);
	TSM_ASSERT_EQUALS("incorrect var2 - France", hvar2_france, france_var2);
	TSM_ASSERT_EQUALS("incorrect prep", hprep, france_prep);
	TSM_ASSERT_EQUALS("incorrect phrase", hphrase, france_phrase);

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

void BiggerPatternUTest::test_prep_rw(void)
{
	do_tst_prep();
}

void BiggerPatternUTest::test_prep_overlay(void)
{
	// Mark base-space as readonly; create a read-write overlay.
	as->set_read_only();
	AtomSpacePtr save = as;
	as = createAtomSpace(as);
	do_tst_prep();
	as = save;
	as->set_read_write();
}