<commit_before>/*
 * PatternUtils.cc
 *
 * Copyright (C) 2008,2009,2011,2014 <NAME>
 *
 * Author: <NAME> <<EMAIL>>  February 2008
 *
 * 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 <boost/range/algorithm/find.hpp>

#include <opencog/atoms/core/FindUtils.h>
#include "PatternUtils.h"

using namespace opencog;

namespace opencog {

/**
 * Remove constant clauses from the list of clauses. Every clause
 * should contain at least one variable, or it should be evaluatable.
 * If does not, or is not, remove the clause from the list of clauses.
 *
 * The core idea is that pattern matching against a constant expression
 * "doesn't make sense" -- the constant expression will always match to
 * itself and is thus "trivial".  In principle, the programmer should
 * never include constants in the list of clauses ... but, due to
 * programmer error, this can happen, and will lead to failures during
 * pattern matching. Thus, the routine below can be used to clean up
 * the pattern-matcher input.
 *
 * Terms that contain GroundedSchema or GroundedPredicate nodes can
 * have side-effects, and are thus are not constants, even if they
 * don't contain any variables. They must be kept around, and must be
 * evaluated during the pattern search.  The definitions of
 * DefinedPredicate or DefinedSchema nodes cannot be accessed until
 * runtime evaluation/execution, so these too must be kept.
 *
 * The match for EvaluatableLink's is meant to solve the problem of
 * evaluating (SatisfactionLink (AndLink (TrueLink))) vs. evaluating
 * (SatisfactionLink (AndLink (FalseLink))), with the first returning
 * TRUE_TV, and the second returning FALSE_TV. Removing these 'constant'
 * terms would alter the result of the evaluation, potentially even
 * leaving an empty (undefined) AndLink. So we cannot really remove
 * them.
 *
 * Returns true if the list of clauses was modified, else returns false.
 */
bool remove_constants(const HandleSet& vars,
                      Pattern& pat,
                      HandleSeqSeq& components,
                      HandleSeq& component_patterns)
{
	bool modified = false;

	// Caution: this loop modifies the clauses list!
	HandleSeq::iterator i;
	for (i = pat.clauses.begin(); i != pat.clauses.end();)
	{
		Handle clause(*i);

		if (not is_constant(vars, clause))
		{
			++i; continue;
		}

		i = pat.clauses.erase(i);

		// remove the clause from components and component_patterns
		auto j = boost::find(components, HandleSeq{clause});
		if (j != components.end())
		{
			components.erase(j);
			if (not component_patterns.empty())
			{
				auto cpj = std::next(component_patterns.begin(),
				                     std::distance(components.begin(), j));
				component_patterns.erase(cpj);
			}
		}

		// remove the clause from _pattern_mandatory.
		auto m = boost::find(pat.mandatory, clause);
		if (m != pat.mandatory.end())
			pat.mandatory.erase(m);

		// remove the clause from _cnf_clauses.
		auto c = boost::find(pat.cnf_clauses, clause);
		if (c != pat.cnf_clauses.end())
			pat.cnf_clauses.erase(c);

		modified = true;
	}

	return modified;
}

bool is_constant(const HandleSet& vars, const Handle& clause)
{
	Type ct = clause->get_type();
	bool constant =
		not (any_unquoted_unscoped_in_tree(clause, vars)
		     or contains_atomtype(clause, DEFINED_PREDICATE_NODE)
		     or contains_atomtype(clause, DEFINED_SCHEMA_NODE)
		     or contains_atomtype(clause, GROUNDED_PREDICATE_NODE)
		     or contains_atomtype(clause, GROUNDED_SCHEMA_NODE)<commit_msg>Avoid using boost<commit_after>/*
 * PatternUtils.cc
 *
 * Copyright (C) 2008,2009,2011,2014 <NAME>
 *
 * Author: <NAME> <<EMAIL>>  February 2008
 *
 * 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/core/FindUtils.h>
#include "PatternUtils.h"

using namespace opencog;

namespace opencog {

/**
 * Remove constant clauses from the list of clauses. Every clause
 * should contain at least one variable, or it should be evaluatable.
 * If does not, or is not, remove the clause from the list of clauses.
 *
 * The core idea is that pattern matching against a constant expression
 * "doesn't make sense" -- the constant expression will always match to
 * itself and is thus "trivial".  In principle, the programmer should
 * never include constants in the list of clauses ... but, due to
 * programmer error, this can happen, and will lead to failures during
 * pattern matching. Thus, the routine below can be used to clean up
 * the pattern-matcher input.
 *
 * Terms that contain GroundedSchema or GroundedPredicate nodes can
 * have side-effects, and are thus are not constants, even if they
 * don't contain any variables. They must be kept around, and must be
 * evaluated during the pattern search.  The definitions of
 * DefinedPredicate or DefinedSchema nodes cannot be accessed until
 * runtime evaluation/execution, so these too must be kept.
 *
 * The match for EvaluatableLink's is meant to solve the problem of
 * evaluating (SatisfactionLink (AndLink (TrueLink))) vs. evaluating
 * (SatisfactionLink (AndLink (FalseLink))), with the first returning
 * TRUE_TV, and the second returning FALSE_TV. Removing these 'constant'
 * terms would alter the result of the evaluation, potentially even
 * leaving an empty (undefined) AndLink. So we cannot really remove
 * them.
 *
 * Returns true if the list of clauses was modified, else returns false.
 */
bool remove_constants(const HandleSet& vars,
                      Pattern& pat,
                      HandleSeqSeq& components,
                      HandleSeq& component_patterns)
{
	bool modified = false;

	// Caution: this loop modifies the clauses list!
	HandleSeq::iterator i;
	for (i = pat.clauses.begin(); i != pat.clauses.end();)
	{
		Handle clause(*i);

		if (not is_constant(vars, clause))
		{
			++i; continue;
		}

		i = pat.clauses.erase(i);

		// remove the clause from components and component_patterns
		auto j = std::find(components.begin(), components.end(),
		                   HandleSeq{clause});
		if (j != components.end())
		{
			components.erase(j);
			if (not component_patterns.empty())
			{
				auto cpj = std::next(component_patterns.begin(),
				                     std::distance(components.begin(), j));
				component_patterns.erase(cpj);
			}
		}

		// remove the clause from _pattern_mandatory.
		auto m = std::find(pat.mandatory.begin(), pat.mandatory.end(), clause);
		if (m != pat.mandatory.end())
			pat.mandatory.erase(m);

		// remove the clause from _cnf_clauses.
		auto c = std::find(pat.cnf_clauses.begin(), pat.cnf_clauses.end(), clause);
		if (c != pat.cnf_clauses.end())
			pat.cnf_clauses.erase(c);

		modified = true;
	}

	return modified;
}

bool is_constant(const HandleSet& vars, const Handle& clause)
{
	Type ct = clause->get_type();
	bool constant =
		not (any_unquoted_unscoped_in_tree(clause, vars)
		     or contains_atomtype(clause, DEFINED_PREDICATE_NODE)
		     or contains_atomtype(clause, DEFINED_SCHEMA_NODE)
		     or contains_atomtype(clause, GROUNDED_PREDICATE_NODE)
		     or contains_atomtype(clause, GROUNDED_SCHEMA_NODE)
{'fraction_non_alphanumeric': 0.08953102794883941, 'fraction_numerical': 0.007579346281383231, 'mean_word_length': 3.6503303964757707, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3815794', 'n_tokens_mistral': 2607, 'n_tokens_neox': 2390, 'n_words': 950}