Search in sources :

Example 1 with ContextSplitting

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;
}
Also used : Expression(com.sri.ai.expresso.api.Expression) ContextSplitting(com.sri.ai.grinder.core.constraint.ContextSplitting)

Example 2 with ContextSplitting

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;
}
Also used : Context(com.sri.ai.grinder.api.Context) AssignmentMapsIterator(com.sri.ai.grinder.helper.AssignmentMapsIterator) BruteForceCommonInterpreter(com.sri.ai.grinder.interpreter.BruteForceCommonInterpreter) Expression(com.sri.ai.expresso.api.Expression) ExpressionLiteralSplitterStepSolver(com.sri.ai.grinder.api.ExpressionLiteralSplitterStepSolver) SingleQuantifierEliminationProblem(com.sri.ai.grinder.api.SingleQuantifierEliminationProblem) ContextSplitting(com.sri.ai.grinder.core.constraint.ContextSplitting)

Example 3 with ContextSplitting

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;
}
Also used : Expression(com.sri.ai.expresso.api.Expression) ExpressionLiteralSplitterStepSolver(com.sri.ai.grinder.api.ExpressionLiteralSplitterStepSolver) ContextSplitting(com.sri.ai.grinder.core.constraint.ContextSplitting)

Example 4 with ContextSplitting

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);
}
Also used : Expression(com.sri.ai.expresso.api.Expression) Constraint(com.sri.ai.grinder.api.Constraint) ContextSplitting(com.sri.ai.grinder.core.constraint.ContextSplitting)

Example 5 with ContextSplitting

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;
}
Also used : TrueContext(com.sri.ai.grinder.core.TrueContext) Context(com.sri.ai.grinder.api.Context) Step(com.sri.ai.grinder.api.StepSolver.Step) ContextSplitting(com.sri.ai.grinder.core.constraint.ContextSplitting)

Aggregations

ContextSplitting (com.sri.ai.grinder.core.constraint.ContextSplitting)20 Expression (com.sri.ai.expresso.api.Expression)16 ExpressionLiteralSplitterStepSolver (com.sri.ai.grinder.api.ExpressionLiteralSplitterStepSolver)6 Context (com.sri.ai.grinder.api.Context)5 TrueContext (com.sri.ai.grinder.core.TrueContext)4 Solution (com.sri.ai.grinder.api.ExpressionLiteralSplitterStepSolver.Solution)3 Test (org.junit.Test)3 Rewriter (com.sri.ai.grinder.rewriter.api.Rewriter)2 Constraint (com.sri.ai.grinder.api.Constraint)1 ItDependsOn (com.sri.ai.grinder.api.ExpressionLiteralSplitterStepSolver.ItDependsOn)1 ExpressionStepSolver (com.sri.ai.grinder.api.ExpressionStepSolver)1 SingleQuantifierEliminationProblem (com.sri.ai.grinder.api.SingleQuantifierEliminationProblem)1 StepSolver (com.sri.ai.grinder.api.StepSolver)1 Step (com.sri.ai.grinder.api.StepSolver.Step)1 AssignmentMapsIterator (com.sri.ai.grinder.helper.AssignmentMapsIterator)1 BruteForceCommonInterpreter (com.sri.ai.grinder.interpreter.BruteForceCommonInterpreter)1 RewriterFromStepMaker (com.sri.ai.grinder.rewriter.api.RewriterFromStepMaker)1 ConstantExpressionStepSolver (com.sri.ai.grinder.theory.base.ConstantExpressionStepSolver)1 ArrayList (java.util.ArrayList)1