use of com.sri.ai.grinder.core.constraint.ContextSplitting in project aic-expresso by aic-sri-international.
the class AbstractSingleQuantifierEliminationStepSolver method combine.
protected Expression combine(Expression solution1, Expression solution2, Context context) {
Expression result;
if (isIfThenElse(solution1)) {
// (if C1 then A1 else A2) op solution2 ---> if C1 then (A1 op solution2) else (A2 op solution2)
ContextSplitting split = new ContextSplitting(condition(solution1), context);
switch(split.getResult()) {
case CONSTRAINT_IS_CONTRADICTORY:
result = null;
break;
case LITERAL_IS_UNDEFINED:
Expression subSolution1 = combine(thenBranch(solution1), solution2, split.getContextAndLiteral());
Expression subSolution2 = combine(elseBranch(solution1), solution2, split.getContextAndLiteralNegation());
result = IfThenElse.make(condition(solution1), subSolution1, subSolution2, true);
break;
case LITERAL_IS_TRUE:
result = combine(thenBranch(solution1), solution2, split.getContextAndLiteral());
break;
case LITERAL_IS_FALSE:
result = combine(elseBranch(solution1), solution2, split.getContextAndLiteralNegation());
break;
default:
throw new Error("Unrecognized result for " + ContextSplitting.class + ": " + split.getResult());
}
} else if (isIfThenElse(solution2)) {
// solution1 op (if C2 then B1 else B2) ---> if C2 then (solution1 op B2) else (solution1 op B2)
ContextSplitting split = new ContextSplitting(condition(solution2), context);
switch(split.getResult()) {
case CONSTRAINT_IS_CONTRADICTORY:
result = null;
break;
case LITERAL_IS_UNDEFINED:
Expression subSolution1 = combine(solution1, thenBranch(solution2), split.getContextAndLiteral());
Expression subSolution2 = combine(solution1, elseBranch(solution2), split.getContextAndLiteralNegation());
result = IfThenElse.make(condition(solution2), subSolution1, subSolution2, true);
break;
case LITERAL_IS_TRUE:
result = combine(solution1, thenBranch(solution2), split.getContextAndLiteral());
break;
case LITERAL_IS_FALSE:
result = combine(solution1, elseBranch(solution2), split.getContextAndLiteralNegation());
break;
default:
throw new Error("Unrecognized result for " + ContextSplitting.class + ": " + split.getResult());
}
} else {
result = getGroup().add(solution1, solution2, context);
}
return result;
}
use of com.sri.ai.grinder.core.constraint.ContextSplitting in project aic-expresso by aic-sri-international.
the class AbstractSingleQuantifierEliminationStepSolver method step.
@Override
public Step step(Context context) {
Step result;
Context contextForBody = getContextForBody(context);
if (contextForBody.isContradiction()) {
result = new Solution(getGroup().additiveIdentityElement());
} else {
ExpressionLiteralSplitterStepSolver bodyStepSolver = getInitialBodyStepSolver(context.getTheory());
ExpressionLiteralSplitterStepSolver.Step bodyStep = bodyStepSolver.step(contextForBody);
// Check (**) in this file to see where this happens
if (!bodyStep.itDepends()) {
ExpressionLiteralSplitterStepSolver evaluatorStepSolver = context.getTheory().makeEvaluatorStepSolver(bodyStep.getValue());
bodyStep = evaluatorStepSolver.step(context);
}
if (bodyStep.itDepends()) {
// "intercept" literals containing the index and split the quantifier based on it
if (isSubExpressionOf(getIndex(), bodyStep.getSplitterLiteral())) {
Expression literalOnIndex = bodyStep.getSplitterLiteral();
result = resultIfLiteralContainsIndex(literalOnIndex, bodyStep, contextForBody, context);
} else {
// not on index, just pass the expression on which we depend on, but with appropriate sub-step solvers (this, for now)
AbstractSingleQuantifierEliminationStepSolver ifTrue = clone();
AbstractSingleQuantifierEliminationStepSolver ifFalse = clone();
ifTrue.initialBodyEvaluationStepSolver = bodyStep.getStepSolverForWhenSplitterIsTrue();
ifFalse.initialBodyEvaluationStepSolver = bodyStep.getStepSolverForWhenSplitterIsFalse();
ifTrue.initialContextForBody = bodyStep.getContextSplittingWhenSplitterIsLiteral().getContextAndLiteral();
ifFalse.initialContextForBody = bodyStep.getContextSplittingWhenSplitterIsLiteral().getContextAndLiteralNegation();
// to compute the result's constraint splitting,
// we cannot directly re-use bodyStep.getConstraintSplitting() because it was not obtained from
// the context it is returning to,
// but from the context conjoined with the index constraint.
// In order to provide two contexts to work with the sequel step solvers,
// we calculate the splittings here.
// TODO: In the future, we expect it possible to efficiently extract the contextForBody component relative
// to the original context only, excluding the index.
ContextSplitting split = new ContextSplitting(bodyStep.getSplitterLiteral(), context);
result = new ItDependsOn(bodyStep.getSplitterLiteral(), split, ifTrue, ifFalse);
}
} else {
// body is already literal free
Expression literalFreeBody = bodyStep.getValue();
result = eliminateQuantifierForLiteralFreeBody(literalFreeBody, context);
boolean solutionToQuantifiedLiteralFreeBodyIsNotConditionalItself = !result.itDepends();
if (solutionToQuantifiedLiteralFreeBodyIsNotConditionalItself) {
IntegrationRecording.registerGroupIntegration(problem, literalFreeBody, result, context);
}
}
}
if (context.getGlobalObject(BRUTE_FORCE_CHECKING_OF_NON_CONDITIONAL_PROBLEMS) != null) {
if (!result.itDepends()) {
Expression indexType = context.getTypeExpressionOfRegisteredSymbol(getIndex());
SingleQuantifierEliminationProblem problem = new DefaultSingleQuantifierEliminationProblem(getGroup(), getIndex(), indexType, getIndexConstraint(), getBody());
Expression problemExpression = problem.toExpression();
Set<Expression> freeVariables = Expressions.freeVariables(problemExpression, context);
AssignmentMapsIterator assignments = new AssignmentMapsIterator(freeVariables, context);
for (Map<Expression, Expression> assignment : in(assignments)) {
BruteForceCommonInterpreter bruteForceCommonInterpreter = new BruteForceCommonInterpreter();
Context extendedContext = Assignment.extendAssignments(assignment, context);
// Only go on if the assignment satisfies the context:
if (bruteForceCommonInterpreter.apply(context, extendedContext).equals(Expressions.TRUE)) {
Expression bruteForceResult = bruteForceCommonInterpreter.apply(problemExpression, extendedContext);
Expression resultGivenAssignment = bruteForceCommonInterpreter.apply(result.getValue(), extendedContext);
Expression evaluatedProblem = bruteForceCommonInterpreter.apply(problemExpression, extendedContext);
if (!bruteForceResult.equals(resultGivenAssignment)) {
String message = "Disagreement on " + problemExpression + "\nunder " + assignment + ".\n" + "Context: " + context + ".\n" + "Evaluated problem: " + evaluatedProblem + ".\n" + "Brute force says " + bruteForceResult + ", symbolic says " + resultGivenAssignment;
println(message);
throw new Error(message);
} else {
String message = "Agreement on " + problemExpression + "\nunder " + assignment + ".\n" + "Context: " + context + ".\n" + "Evaluated problem: " + evaluatedProblem + ".\n" + "Brute force says " + bruteForceResult + ", symbolic says " + resultGivenAssignment;
println(message);
}
}
}
}
}
return result;
}
use of com.sri.ai.grinder.core.constraint.ContextSplitting in project aic-expresso by aic-sri-international.
the class ContextDependentExpressionProblemSolver method solve.
/**
* Returns the solution for a problem using a step solver.
* @param stepSolver
* @param context
* @return
*/
public Expression solve(ExpressionLiteralSplitterStepSolver stepSolver, Context context) {
if (interrupted) {
throw new Error("Solver interrupted.");
}
Expression result;
ExpressionLiteralSplitterStepSolver.Step step = stepSolver.step(context);
if (step.itDepends()) {
Expression splitter = step.getSplitter();
ContextSplitting split = (ContextSplitting) step.getContextSplittingWhenSplitterIsLiteral();
myAssert(() -> split.isUndefined(), () -> "Undefined " + ContextSplitting.class + " result value: " + split.getResult());
Expression subSolution1 = solve(step.getStepSolverForWhenSplitterIsTrue(), split.getConstraintAndLiteral());
Expression subSolution2 = solve(step.getStepSolverForWhenSplitterIsFalse(), split.getConstraintAndLiteralNegation());
result = IfThenElse.make(splitter, subSolution1, subSolution2, true);
} else {
result = step.getValue();
}
return result;
}
use of com.sri.ai.grinder.core.constraint.ContextSplitting in project aic-expresso by aic-sri-international.
the class AbstractExpressionWithPropagatedLiteralsStepSolver method cnfIsSatisfied.
/**
* A convenience method for testing whether a CNF, represented as an iterable of iterables of Expressions,
* is satisfied by a context.
* @param cnf
* @param context
* @return <code>null</code> if the context is found to be self-contradictory,
* an instance of {@link ItDependsOn} with a literal, if whether the CNF is satisfied or not depends on that literal,
* or an instance of {@link Solution} with expression {@link Expressions#TRUE} or {@link Expressions#FALSE}
* if whether the CNF is satisfied is already determined positively or negatively, respectively.
*/
protected Step cnfIsSatisfied(ArrayList<ArrayList<Expression>> cnf, Context context) {
// note the very unusual initialization of literalIndex
// this is due to our wanting to be initialized to initialLiteralToConsiderInInitialClauseToConsiderInPropagatedCNF,
// but only the first time the loop is executed (that is, inside the first clause loop)
// We therefore start the method by initializing it to initialLiteralToConsiderInInitialClauseToConsiderInPropagatedCNF,
// and then initialize it to 0 when clauseIndex is iterated.
int literalIndex = initialLiteralToConsiderInInitialClauseToConsiderInPropagatedCNF;
for (int clauseIndex = initialClauseToConsiderInPropagatedCNF; clauseIndex != cnf.size(); clauseIndex++, literalIndex = 0) {
// unusual! See above
ArrayList<Expression> clause = cnf.get(clauseIndex);
boolean clauseIsSatisfied = false;
for (; /* literalIndex already initialized at this point */
literalIndex != clause.size(); literalIndex++) {
Expression literal = clause.get(literalIndex);
ContextSplitting split = new ContextSplitting(literal, context);
switch(split.getResult()) {
case LITERAL_IS_UNDEFINED:
AbstractExpressionWithPropagatedLiteralsStepSolver subStepSolver = MAKE_SUB_STEP_SOLVERS_THAT_START_TO_CHECK_PROPAGATED_CNF_FROM_WHERE_THIS_ONE_LEFT_OFF ? makeCopyConsideringPropagatedCNFFromNowOn(clauseIndex, literalIndex) : this;
// literal is necessary, but undefined
return new ItDependsOn(literal, split, subStepSolver, subStepSolver);
// OPTIMIZATION: instead of returning the first undefined literal, we could look whether some clause is already unsatisfied
case LITERAL_IS_TRUE:
clauseIsSatisfied = true;
context = split.getContextAndLiteral();
break;
case LITERAL_IS_FALSE:
context = split.getContextAndLiteralNegation();
break;
case CONSTRAINT_IS_CONTRADICTORY:
return null;
}
if (clauseIsSatisfied) {
// no need to examine remaining literals in clause
break;
}
}
if (!clauseIsSatisfied) {
// clause is false, so the whole CNF is false
return new Solution(FALSE);
}
// else move on to next clause
}
return new Solution(TRUE);
}
use of com.sri.ai.grinder.core.constraint.ContextSplitting in project aic-expresso by aic-sri-international.
the class IfThenElseStepSolverTest method evaluateByRecursivelyTakingSteps.
// A method for tracing the steps (and results of the steps) the step solver takes
private String evaluateByRecursivelyTakingSteps(StepSolver stepSolver, Context context, AtomicInteger stepCount, int nestingOfStep) {
String result;
Step step = stepSolver.step(context);
stepCount.incrementAndGet();
if (step.itDepends()) {
ContextSplitting splitting = step.getContextSplittingWhenSplitterIsLiteral();
String nestingString = createNestingString(nestingOfStep);
// println(nestingString + "[" + stepCount + "] split on: " + splitting.getLiteral());
result = nestingString + "[" + stepCount + "] split on: " + splitting.getLiteral() + System.lineSeparator();
Context trueContext = splitting.getContextAndLiteral();
Context falseContext = splitting.getContextAndLiteralNegation();
int nestingOfNextStep = nestingOfStep + 1;
result += evaluateByRecursivelyTakingSteps(step.getStepSolverForWhenSplitterIs(true), trueContext, stepCount, nestingOfNextStep);
result += evaluateByRecursivelyTakingSteps(step.getStepSolverForWhenSplitterIs(false), falseContext, stepCount, nestingOfNextStep);
} else {
String nestingString = createNestingString(nestingOfStep);
// println(nestingString + "[" + stepCount + "] < " + step.getValue() + " >");
result = nestingString + "[" + stepCount + "] < " + step.getValue() + " >" + System.lineSeparator();
}
return result;
}
Aggregations