OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-atomspace / opencog / atoms / pattern / PatternJit.cc

104 lines · cc ref:
/*
 * PatternJit.cc
 *
 * Copyright (C) 2015 Linas Vepstas
 *
 * Author: Linas Vepstas <linasvepstas@gmail.com>  April 2015
 *
 * 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/atoms/grant/DefineLink.h>
#include <opencog/atoms/scope/LambdaLink.h>
#include <opencog/atoms/pattern/PatternLink.h>

using namespace opencog;

/* ======================================================== */
/**
 * Just-In-Time analysis of patterns. Patterns we could not unpack
 * earlier, because the definitions for them might not have been
 * present, or may have changed since the pattern was initially created.
 */
PatternLinkPtr PatternLink::jit_analyze(void)
{
	PatternLinkPtr jit = PatternLinkCast(get_handle());

	// If there are no definitions, there is nothing to do.
	if (0 == _pat.defined_terms.size()) return jit;

	// Now is the time to look up the definitions!
	// We loop here, so that all recursive definitions are expanded
	// as well.  XXX Except that this is wrong, if any of the
	// definitions are actually recursive. That is, this will be
	// an infinite loop if a definition is self-referencing; so
	// really we need to expand, one level at a time, during
	// evaluation, and only expand if really, really needed. (Which
	// then brings up ideas like tail recursion, etc.)  Anyway, most
	// of this code should probably be moved to PatternLink::jit_expand()
	while (0 < jit->_pat.defined_terms.size())
	{
		Variables vset;
		GroundingMap defnmap;
		for (const Handle& name : jit->_pat.defined_terms)
		{
			Handle defn = DefineLink::get_definition(name);
			if (not defn) continue;

			// Extract the variables in the definition.
			// Either they are given in a LambdaLink, or, if absent,
			// we just hunt down and bind all of them.
			if (nameserver().isA(LAMBDA_LINK, defn->get_type()))
			{
				LambdaLinkPtr lam = LambdaLinkCast(defn);
				vset.extend(lam->get_variables());
				defn = lam->get_body();
			}
			else
			{
				Variables freevars;
				freevars.find_variables(defn);
				vset.extend(freevars);
			}

			defnmap.insert({name, defn});
		}

		// Rebuild the pattern, expanding all DefinedPredicateNodes
		// to one level. Note that `newbody` is not being placed in
		// any atomspace; but I think that is OK...
		Handle newbody = Replacement::replace_nocheck(jit->_pat.body, defnmap);

		// We need to let both the PME know about the new clauses
		// and variables, and also let master callback class know,
		// too, since we are just one mixin in the callback class;
		// the other mixins need to be updated as well.
		vset.extend(jit->_variables);

		jit = createPatternLink(vset, newbody);
	}

#ifdef QDEBUG
	jit->debug_log("JIT expanded!");
#endif

	return jit;
}

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