All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sri.ai.grinder.sgdpllt.library.SyntacticSubstitute Maven / Gradle / Ivy

Go to download

SRI International's AIC Symbolic Manipulation and Evaluation Library (for Java 1.8+)

The newest version!
/*
 * Copyright (c) 2013, SRI International
 * All rights reserved.
 * Licensed under the The BSD 3-Clause License;
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 * 
 * http://opensource.org/licenses/BSD-3-Clause
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * Neither the name of the aic-expresso nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.sri.ai.grinder.sgdpllt.library;

import static com.sri.ai.util.Util.mapIntoList;

import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.common.annotations.Beta;
import com.google.common.base.Function;
import com.sri.ai.expresso.api.Expression;
import com.sri.ai.expresso.helper.Expressions;
import com.sri.ai.expresso.helper.GetFunctorOrSymbol;
import com.sri.ai.expresso.helper.MapReplacementFunction;
import com.sri.ai.grinder.api.Registry;
import com.sri.ai.grinder.core.PruningPredicate;
import com.sri.ai.grinder.sgdpllt.api.Context;
import com.sri.ai.util.Util;
import com.sri.ai.util.base.ReplaceByIfEqualTo;

/**
 * A class providing a static method for substituting symbols or function applications in an expression
 * by another expression (not subject itself to the same substitution, which would either not occur or lead to an infinite recursion).
 * 
 * This is a simpler, less exhaustive version of {@link SemanticSubstitute} that takes into account only syntactic information,
 * that is, it only replaces an expression by a value if the expression is represented with the same symbols
 * as the originally searched ones. Here are a few examples to make this more clear:
 * 
 * Replacing a symbol works as one would expect:
 * 
 * Replacing X by 99 in foo returns foo
 * Replacing X by 99 in X returns 99
 * 
 * However, quantifications need to be taken into account:
 * replacing X by 99 in X + if there exists X : X = 9 then X else 0 returns 99 + if there exists X : X = 9 then 99 else 0
 * because the quantified X works as a distinct variable. Its scope is limited to the if's condition,
 * so the X in the then branch corresponds to the original X.
 * 
 * When replacing a function substitution, the function's corresponding "cell" has its value replaced.
 * Here are some examples:
 * 
 * Replacing f(10) by 99 in f(9) returns f(9)
 * Replacing f(Y) by 99 in f(Y) returns 99
 * Replacing f(10) by 99 in f(X) returns f(X)
 * even though, semantically speaking, X could be equal to 10.
 * Semantic substitution would have returned if X = 10 then 99 else f(X)
 * Replacing f(Y) by 99 in f(X) returns if X = Y then 99 else f(X)
 *
 * When replacing a function application, quantification of either the function symbol or the arguments will prevent
 * further replacement down the expression:
 * 
 * Replacing f(X) by 99 in f(X) + (for all g : g(f(X))) + (for all f : f(X)) + (for all X : f(X))
 * returns 99 + (for all g : g(99)) + (for all f : f(X)) + (for all X : f(X))
 * 
 * @author braz
 *
 */
@Beta
public class SyntacticSubstitute {

	public static Expression replace(Expression expression, Expression replaced, Expression replacement, Context context) {
		Expression result =
				expression.replaceAllOccurrences(
						new ReplaceByIfEqualTo(replacement, replaced), null,
						new SubstitutePruningPredicate(replaced, replacement, context), null,
						context);
		return result;
	}

	public static Expression replaceAll(Expression expression, Map fromReplacedToReplacements, Context context) {
		Expression result = expression.replaceAllOccurrences(new MapReplacementFunction(fromReplacedToReplacements), context);
		return result;

//		// Used to be as below but that is incorrect as one of the new variables may be replaced by another new variable coming later.
//		for (Map.Entry entry : fromReplacedToReplacements.entrySet()) {
//			expression = replace(expression, entry.getKey(), entry.getValue(), context);
//		}
//		return expression;
	}

	private static class SubstitutePruningPredicate implements PruningPredicate {
		List allSymbolsInReplacedAndReplacement;
		
		public SubstitutePruningPredicate(Expression replaced, Expression replacement, Registry registry) {
			Set freeSymbolsInReplaced    = Expressions.freeSymbols(replaced, registry);
			Set freeSymbolsInReplacement = Expressions.freeSymbols(replacement, registry);
			this.allSymbolsInReplacedAndReplacement =
					Util.union(
							freeSymbolsInReplacement,
							freeSymbolsInReplaced);
		}
		@Override
		public boolean apply(Expression expression, Function replacementFunctionFunction, Registry registry) {
			List locallyScopedSymbols = mapIntoList(expression.getScopedExpressions(registry), new GetFunctorOrSymbol());
			boolean result = Util.intersect(allSymbolsInReplacedAndReplacement, locallyScopedSymbols);
			return result;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy