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

com.sri.ai.grinder.sgdpllt.library.boole.BooleanUtil Maven / Gradle / Ivy

/*
 * 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.boole;

import static com.sri.ai.grinder.sgdpllt.library.FunctorConstants.AND;
import static com.sri.ai.grinder.sgdpllt.library.FunctorConstants.DISEQUALITY;
import static com.sri.ai.grinder.sgdpllt.library.FunctorConstants.EQUALITY;
import static com.sri.ai.grinder.sgdpllt.library.FunctorConstants.EQUIVALENCE;
import static com.sri.ai.grinder.sgdpllt.library.FunctorConstants.IMPLICATION;
import static com.sri.ai.grinder.sgdpllt.library.FunctorConstants.NOT;
import static com.sri.ai.grinder.sgdpllt.library.FunctorConstants.OR;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import com.google.common.annotations.Beta;
import com.google.common.collect.Lists;
import com.sri.ai.expresso.api.Expression;
import com.sri.ai.expresso.api.FunctionApplication;
import com.sri.ai.expresso.helper.Expressions;
import com.sri.ai.grinder.sgdpllt.library.Equality;

/**
 * A collection of utility routines related to handling boolean expressions.
 * 
 * @author saadati
 *
 */
@Beta
public class BooleanUtil {

	/**
	 * 
	 * @param expression
	 * @return removes any duplicates from expression
	 */
	public static Expression removeUnnecessary(Expression expression) {
		if (expression.getSyntacticFormType().equals(FunctionApplication.SYNTACTIC_FORM_TYPE)) {
			Expression functor = expression.getFunctor();
			if ( And.isConjunction(expression) || Or.isDisjunction(expression) ) {
				boolean isConjunction = And.isConjunction(expression);
				List arguments = expression.getArguments();
				ArrayList newArguments = new ArrayList();
				for (Expression arg: arguments) {
					if ( (isConjunction && arg.equals(Expressions.TRUE)) || (!isConjunction && arg.equals(Expressions.FALSE)) ) {
						continue;
					}
					boolean isDuplicate = false;
					Expression arg2 = removeUnnecessary(arg);
					for (Expression nArg: newArguments) {
						if ( areEquivalent(arg2, nArg) ) {
							isDuplicate = true;
							break;
						}
					}
					if ( !isDuplicate ) {
						newArguments.add(arg2);
					}
				}
				if ( newArguments.size() == 1 ) {
					return newArguments.get(0);
				} 
				else {
					return Expressions.makeExpressionOnSyntaxTreeWithLabelAndSubTrees(functor, newArguments);
				}
			} 
			else if ( functor.equals(NOT) ) {
				return Expressions.apply(functor, removeUnnecessary(expression.get(0)));
			}
		}
		return expression;
	}
		
	private static boolean areEquivalent(Expression literal1, Expression literal2) {
		if ( literal1.hasFunctor(NOT) ) {
			if ( literal2.hasFunctor(NOT) ) {
				return areEquivalent(literal1.get(0), literal2.get(0));
			} 
			else if ( literal2.hasFunctor(DISEQUALITY) ) {
				return areEquivalent(literal1.get(0), Expressions.apply(EQUALITY, literal2.get(0), literal2.get(1)));
			}
		} 
		else if ( literal2.hasFunctor(NOT) ) {
			if ( literal1.hasFunctor(DISEQUALITY) ) {
				return areEquivalent(literal2.get(0), Expressions.apply(EQUALITY, literal1.get(0), literal1.get(1)));
			}
		} 
		else if ( literal1.hasFunctor(DISEQUALITY) && literal2.hasFunctor(DISEQUALITY) ) {
			return pairwiseEquivalent(literal1.get(0), literal1.get(1), literal2.get(0), literal2.get(1));
		}
		else if ( literal1.hasFunctor(EQUALITY) && literal2.hasFunctor(EQUALITY) ) {
			for (Expression term1: literal1.getArguments()) {
				boolean conjunction = true;
				for (Expression term2: literal2.getArguments()) {
					conjunction = conjunction && term1.equals(term2);
					if ( !conjunction ) {
						break;
					}
				}
				if ( conjunction ) {
					return true;
				}
			}
			// return pairwiseEquivalent(literal1.get(0), literal1.get(1), literal2.get(0), literal2.get(1));
		}
		return false;
	}

	private static boolean pairwiseEquivalent(Expression x1, Expression y1, Expression x2, Expression y2) {
		return (x1.equals(x2) && y1.equals(y2)) || (x1.equals(y2) && y1.equals(x2));
		
	}

	/**
	 * 
	 * @param expression
	 * @return true if expression is of the form "x=y" or "not (x != y)"
	 */
	public static boolean isEquality(Expression expression) {
		return (expression.hasFunctor(EQUALITY) && expression.getArguments().size() == 2) || 
				(expression.hasFunctor(NOT) && isNotEquality(expression.get(0)));
	}
	
	/**
	 * 
	 * @param expression
	 * @return true if expression is of the form x=y=...=z"
	 */
	public static boolean isMultiEquality(Expression expression) {
		return (expression.hasFunctor(EQUALITY) && expression.getArguments().size()>2);
	}

	public static Expression expandMultiEquality(Expression expression, Expression mainVar) {
		Expression result = expression;
		if ( isMultiEquality(expression) && expression.getArguments().contains(mainVar) ) {
			ArrayList newEqualities = new ArrayList();
			for (Expression var: expression.getArguments()) {
				if ( !var.equals(mainVar) ) {
					Expression newEq = Equality.make(mainVar, var);
					newEqualities.add(newEq);
				}
			}
			result = And.make(newEqualities);
		}
		return result;
	}
	
	/**
	 * 
	 * @param expression
	 * @return true if expression is either an equality or a disequality
	 */
	public static boolean isLiteral(Expression expression) {
		return isEquality(expression) || isNotEquality(expression);
	}

	/**
	 * 
	 * @param expression
	 * @return true if expression is either of the form "x=y" or "not (x != y)"
	 */
	public static boolean isNotEquality(Expression expression) {
		return (expression.hasFunctor(NOT) && isEquality(expression.get(0))) || expression.hasFunctor(DISEQUALITY);
	}

	/**
	 * 
	 * @param expression
	 * @return true if expression is a conjunction
	 */
	public static boolean isConjunction(Expression expression) {
		return expression.hasFunctor(AND);
	}

	/**
	 * 
	 * @param expression
	 * @return true if expression is a disjunction
	 */
	public static boolean isDisjunction(Expression expression) {
		return expression.hasFunctor(OR);
	}

	/**
	 * 
	 * @param expression
	 * @return true if expression is an implication
	 */
	public static boolean isImplication(Expression expression) {
		return expression.hasFunctor(IMPLICATION);
	}

	/**
	 * 
	 * @param expression
	 * @return true if expression is an Equivalence
	 */
	public static boolean isEquivalence(Expression expression) {
		return expression.hasFunctor(EQUIVALENCE);
	}

	/**
	 * 
	 * @param expression
	 * @return true if expression is a disjunction
	 */
	public static boolean isNegation(Expression expression) {
		return expression.hasFunctor(NOT);
	}

	/**
	 * 
	 * @param expression
	 * @param element
	 * @return true if element occurs in expression
	 */
	public static boolean occurs(Expression expression, Expression element) {
		return Expressions.containsAnyOfGivenCollectionAsSubExpression(expression, Lists.newArrayList(element));
	}

	public static Set getTerms(Expression expression) {
		Set set = new LinkedHashSet();
		if ( expression.hasFunctor(EQUALITY) || expression.hasFunctor(DISEQUALITY) ) {
			set.add(expression.get(0));
			set.add(expression.get(1));
		} 
		else if ( expression.hasFunctor(NOT) ) {
			set.addAll(getTerms(expression.get(0)));
		}
		else if ( expression.hasFunctor(OR) || expression.hasFunctor(AND) || expression.hasFunctor(IMPLICATION)) {
			for (Expression arg: expression.getArguments()) {
			set.addAll(getTerms(arg));
			}
		}
		return set;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy