![JAR search and dependency download from the Maven repository](/logo.png)
com.sri.ai.grinder.sgdpllt.theory.numeric.AbstractSingleVariableNumericConstraint Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aic-expresso Show documentation
Show all versions of aic-expresso Show documentation
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.theory.numeric;
import static com.sri.ai.expresso.helper.Expressions.FALSE;
import static com.sri.ai.expresso.helper.Expressions.ONE;
import static com.sri.ai.expresso.helper.Expressions.apply;
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.GREATER_THAN;
import static com.sri.ai.grinder.sgdpllt.library.FunctorConstants.GREATER_THAN_OR_EQUAL_TO;
import static com.sri.ai.grinder.sgdpllt.library.FunctorConstants.LESS_THAN;
import static com.sri.ai.grinder.sgdpllt.library.FunctorConstants.LESS_THAN_OR_EQUAL_TO;
import static com.sri.ai.grinder.sgdpllt.library.FunctorConstants.MINUS;
import static com.sri.ai.grinder.sgdpllt.library.FunctorConstants.PLUS;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import com.google.common.annotations.Beta;
import com.sri.ai.expresso.api.Expression;
import com.sri.ai.grinder.sgdpllt.api.Context;
import com.sri.ai.grinder.sgdpllt.api.Theory;
import com.sri.ai.grinder.sgdpllt.core.constraint.AbstractSingleVariableConstraint;
import com.sri.ai.grinder.sgdpllt.library.boole.Not;
import com.sri.ai.grinder.sgdpllt.theory.base.AbstractSingleVariableConstraintWithBinaryAtomsIncludingEquality;
import com.sri.ai.util.Util;
/**
* An abstract numeric single-variable constraint solver.
*
* @author braz
*
*/
@Beta
public abstract class AbstractSingleVariableNumericConstraint extends AbstractSingleVariableConstraintWithBinaryAtomsIncludingEquality {
private static final long serialVersionUID = 1L;
private static final Collection normalFunctors = Util.set(EQUALITY, LESS_THAN, GREATER_THAN);
private static final Map flipFunctor =
Util.map(
EQUALITY, EQUALITY,
DISEQUALITY, DISEQUALITY,
LESS_THAN, GREATER_THAN,
LESS_THAN_OR_EQUAL_TO, GREATER_THAN_OR_EQUAL_TO,
GREATER_THAN, LESS_THAN,
GREATER_THAN_OR_EQUAL_TO, LESS_THAN_OR_EQUAL_TO
);
public AbstractSingleVariableNumericConstraint(
Expression variable,
boolean propagateAllLiteralsWhenVariableIsBound,
Theory theory) {
super(variable, propagateAllLiteralsWhenVariableIsBound, theory);
}
protected AbstractSingleVariableNumericConstraint(
Expression variable,
ArrayList positiveNormalizedAtoms,
ArrayList negativeNormalizedAtoms,
List externalLiterals,
boolean propagateAllLiteralsWhenVariableIsBound,
Theory theory) {
super(variable, positiveNormalizedAtoms, negativeNormalizedAtoms, externalLiterals, propagateAllLiteralsWhenVariableIsBound, theory);
}
public AbstractSingleVariableNumericConstraint(AbstractSingleVariableNumericConstraint other) {
super(other);
}
@Override
protected Collection getNormalFunctors() {
return normalFunctors;
}
@Override
protected String getNegationFunctor(String functor) {
String result = AbstractNumericTheory.getNegationFunctor(functor);
return result;
}
@Override
protected String getFlipFunctor(String functor) {
String result = flipFunctor.get(functor);
return result;
}
@Override
abstract protected Expression isolateVariable(Expression atom, Context context);
@Override
protected boolean conjoiningRedundantSignAndNormalizedAtomNeverChangesConstraintInstance() {
boolean result = ! getPropagateAllLiteralsWhenVariableIsBound();
return result;
// Explanation: once we propagate incoming literals,
// they are stored as external literals and are no further analysed at this constraint's level
// (other than being eventually provided as splitters).
// Therefore, under propagation we may produce multiple external literals that may be redundant between themselves
// but whose redundancies will only be detected when they are themselves analysed
// in their own constraints.
}
@Override
public Expression getVariableFreeLiteralEquivalentToSign1Atom1ImpliesSign2Atom2(boolean sign1, Expression atom1, boolean sign2, Expression atom2, Context context) {
Expression result;
if (sign1) {
result = getVariableFreeFormulaEquivalentToSign1Atom1ImpliesSign2Atom2PositiveAtom1Cases(atom1, sign2, atom2, context);
}
else {
result = getVariableFreeFormulaEquivalentToSign1Atom1ImpliesSign2Atom2NegativeAtom1Cases(atom1, sign2, atom2, context);
}
return result;
}
/**
* Indicates whether variable is integer-typed (as opposed to real-typed).
* @return
*/
abstract public boolean variableIsIntegerTyped();
private Expression getVariableFreeFormulaEquivalentToSign1Atom1ImpliesSign2Atom2PositiveAtom1Cases(Expression atom1, boolean sign2, Expression atom2, Context context) throws Error {
Expression result;
Expression a = atom1.get(1);
Expression b = atom2.get(1);
switch (atom1.getFunctor().toString()) {
case EQUALITY:
// X = a implies:
// X = b, iff a = b
// X < b, iff a < b
// X > b, iff a > b
// not (X = b), iff not (a = b)
// not (X < b), iff not (a < b)
// not (X > b), iff not (a > b)
// That is, X = a implies sign2 (X op b) iff sign2 (a op b)
Expression atom = applyAndSimplify(atom2.getFunctor(), a, b, context);
result = sign2? atom : Not.make(atom);
break;
case LESS_THAN:
// X < a implies:
// X = b, iff false (never implies a =)
// X < b, iff a < b
// X > b, iff false (never implies a >)
// not (X = b), iff b >= a
// not (X < b), that is, X >= b, iff false (never implies >=)
// not (X > b), that is, X <= b, iff b >= a - [type is integers? 1 : 0]
if (sign2) {
if (atom2.hasFunctor(LESS_THAN)) {
result = applyAndSimplify(LESS_THAN, a, b, context);
}
else {
result = FALSE;
}
}
else {
switch (atom2.getFunctor().toString()) {
case EQUALITY:
result = applyAndSimplify(GREATER_THAN_OR_EQUAL_TO, b, a, context);
break;
case LESS_THAN:
result = FALSE;
break;
case GREATER_THAN:
Expression aMinusWhetherVariableIsInteger = variableIsIntegerTyped()? apply(MINUS, a, ONE) : a;
result = applyAndSimplify(GREATER_THAN_OR_EQUAL_TO, b, aMinusWhetherVariableIsInteger, context);
break;
default:
throw notNormalized(atom2);
}
}
break;
case GREATER_THAN:
// Mirror image of LESS_THAN:
if (sign2) {
if (atom2.hasFunctor(GREATER_THAN)) {
result = applyAndSimplify(GREATER_THAN, a, b, context);
}
else {
result = FALSE;
}
}
else {
switch (atom2.getFunctor().toString()) {
case EQUALITY:
result = applyAndSimplify(LESS_THAN_OR_EQUAL_TO, b, a, context);
break;
case GREATER_THAN:
result = FALSE;
break;
case LESS_THAN:
Expression aPlusWhetherVariableIsIntegerTyped = variableIsIntegerTyped()? apply(PLUS, a, ONE) : a;
result = applyAndSimplify(LESS_THAN_OR_EQUAL_TO, b, aPlusWhetherVariableIsIntegerTyped, context);
break;
default:
throw notNormalized(atom2);
}
}
break;
default:
throw notNormalized(atom1);
}
return result;
}
/**
* @param functor
* @param first
* @param second
* @param context
* @return
*/
private Expression applyAndSimplify(Object functor, Expression first, Expression second, Context context) {
Expression result;
result = apply(functor, first, second);
result = getTheory().simplify(result, context);
return result;
}
private Expression getVariableFreeFormulaEquivalentToSign1Atom1ImpliesSign2Atom2NegativeAtom1Cases(Expression atom1, boolean sign2, Expression atom2, Context context) {
Expression result;
Expression a = atom1.get(1);
Expression b = atom2.get(1);
switch (atom1.getFunctor().toString()) {
case EQUALITY: // sign1 is false, therefore sign1 atom1 is a DISEQUALITY
// X != a implies:
// X = b, iff false (does not imply)
// X < b, iff false (does not imply)
// X > b, iff false (does not imply)
// not (X = b), iff a = b
// not (X < b), iff false (does not imply)
// not (X > b), iff false (does not imply)
// That is, X != a implies not (X = b) iff a = b
Expression aEqualsB = applyAndSimplify(atom1.getFunctor(), a, b, context);
result = !sign2 && atom2.hasFunctor(EQUALITY)? aEqualsB : FALSE;
break;
case LESS_THAN: // sign1 is false, therefore sign1 atom1 is GREATER_THAN_OR_EQUAL_TO
// X >= a implies:
// X = b, iff false
// X < b, iff false
// X > b, iff b < a
// not (X = b), iff b < a
// not (X < b), that is, X >= b, iff b <= a
// not (X > b), that is, X <= b, iff false
if (sign2) {
if (atom2.hasFunctor(GREATER_THAN)) {
result = applyAndSimplify(LESS_THAN, b, a, context);
}
else {
result = FALSE;
}
}
else {
switch (atom2.getFunctor().toString()) {
case EQUALITY:
result = applyAndSimplify(LESS_THAN, b, a, context);
break;
case LESS_THAN:
result = applyAndSimplify(LESS_THAN_OR_EQUAL_TO, b, a, context);
break;
case GREATER_THAN:
result = FALSE;
break;
default:
throw notNormalized(atom2);
}
}
break;
case GREATER_THAN:
// Mirror image of LESS_THAN:
if (sign2) {
if (atom2.hasFunctor(LESS_THAN)) {
result = applyAndSimplify(GREATER_THAN, b, a, context);
}
else {
result = FALSE;
}
}
else {
switch (atom2.getFunctor().toString()) {
case EQUALITY:
result = applyAndSimplify(GREATER_THAN, b, a, context);
break;
case GREATER_THAN:
result = applyAndSimplify(GREATER_THAN_OR_EQUAL_TO, b, a, context);
break;
case LESS_THAN:
result = FALSE;
break;
default:
throw notNormalized(atom2);
}
}
break;
default:
throw notNormalized(atom1);
}
return result;
}
private Error notNormalized(Expression atom) {
return new Error(getClass().getSimpleName() + ": got atom that is not normalized: " + atom);
}
@Override
/**
* Implementation simply returns this
,
* since typically implementations will have nothing to do besides pairwise atom contradiction checks.
*/
public AbstractSingleVariableConstraint destructiveUpdateOrNullAfterConjoiningNewNormalizedAtom(boolean sign, Expression atom, Context context) {
return this;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy