
org.sosy_lab.java_smt.basicimpl.AbstractProverWithAllSat Maven / Gradle / Ivy
Show all versions of java-smt Show documentation
// This file is part of JavaSMT,
// an API wrapper for a collection of SMT solvers:
// https://github.com/sosy-lab/java-smt
//
// SPDX-FileCopyrightText: 2020 Dirk Beyer
//
// SPDX-License-Identifier: Apache-2.0
package org.sosy_lab.java_smt.basicimpl;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.Set;
import org.sosy_lab.common.ShutdownNotifier;
import org.sosy_lab.java_smt.api.BooleanFormula;
import org.sosy_lab.java_smt.api.BooleanFormulaManager;
import org.sosy_lab.java_smt.api.Evaluator;
import org.sosy_lab.java_smt.api.SolverContext.ProverOptions;
import org.sosy_lab.java_smt.api.SolverException;
/**
* This class is a utility-class to avoid repeated implementation of the AllSAT computation.
*
* If a solver does not support direct AllSAT computation, please inherit from this class.
*/
public abstract class AbstractProverWithAllSat extends AbstractProver {
protected final ShutdownNotifier shutdownNotifier;
private final BooleanFormulaManager bmgr;
protected AbstractProverWithAllSat(
Set pOptions,
BooleanFormulaManager pBmgr,
ShutdownNotifier pShutdownNotifier) {
super(pOptions);
bmgr = pBmgr;
shutdownNotifier = pShutdownNotifier;
}
@Override
public R allSat(AllSatCallback callback, List importantPredicates)
throws InterruptedException, SolverException {
Preconditions.checkState(!closed);
checkGenerateAllSat();
push();
try {
// try model-based computation of ALLSAT
iterateOverAllModels(callback, importantPredicates);
} catch (SolverException e) {
// fallback to direct SAT/UNSAT-based computation of ALLSAT
iterateOverAllPredicateCombinations(callback, importantPredicates, new ArrayDeque<>());
// TODO should we completely switch to the second method?
}
pop();
return callback.getResult();
}
/**
* This method computes all satisfiable assignments for the given predicates by iterating over all
* models. The SMT solver can choose the ordering of variables and shortcut model generation.
*/
private void iterateOverAllModels(
AllSatCallback callback, List importantPredicates)
throws SolverException, InterruptedException {
while (!isUnsat()) {
shutdownNotifier.shutdownIfNecessary();
ImmutableList.Builder valuesOfModel = ImmutableList.builder();
try (Evaluator evaluator = getEvaluatorWithoutChecks()) {
for (BooleanFormula formula : importantPredicates) {
Boolean value = evaluator.evaluate(formula);
if (value == null) {
// This is a legal return value for evaluation.
// The value doesn't matter. We ignore this assignment.
// This step aim for shortcutting the ALLSAT-loop.
} else if (value) {
valuesOfModel.add(formula);
} else {
valuesOfModel.add(bmgr.not(formula));
}
}
}
final ImmutableList values = valuesOfModel.build();
callback.apply(values);
shutdownNotifier.shutdownIfNecessary();
BooleanFormula negatedModel = bmgr.not(bmgr.and(values));
addConstraint(negatedModel);
shutdownNotifier.shutdownIfNecessary();
}
}
/**
* This method computes all satisfiable assignments for the given predicates by (recursively)
* traversing the decision tree over the given variables. The ordering of variables is fixed, and
* we can only ignore unsatisfiable subtrees.
*
* In contrast to {@link #iterateOverAllModels} we do not use model generation here, which is a
* benefit for some solvers or theory combinations.
*
* @param predicates remaining predicates in the decision tree.
* @param valuesOfModel already chosen predicate values, ordered as appearing in the tree.
*/
private void iterateOverAllPredicateCombinations(
AllSatCallback callback,
List predicates,
Deque valuesOfModel)
throws SolverException, InterruptedException {
shutdownNotifier.shutdownIfNecessary();
if (isUnsat()) {
return;
} else if (predicates.isEmpty()) {
// we aim at providing the same order of predicates as given as parameter, thus reverse.
callback.apply(ImmutableList.copyOf(valuesOfModel).reverse());
} else {
// positive predicate
final BooleanFormula predicate = predicates.get(0);
valuesOfModel.push(predicate);
push(predicate);
iterateOverAllPredicateCombinations(
callback, predicates.subList(1, predicates.size()), valuesOfModel);
pop();
valuesOfModel.pop();
// negated predicate
final BooleanFormula notPredicate = bmgr.not(predicates.get(0));
valuesOfModel.push(notPredicate);
push(notPredicate);
iterateOverAllPredicateCombinations(
callback, predicates.subList(1, predicates.size()), valuesOfModel);
pop();
valuesOfModel.pop();
}
}
/**
* Get an evaluator instance for model evaluation without executing checks for prover options.
*
* This method allows model evaluation without explicitly enabling the prover-option {@link
* ProverOptions#GENERATE_MODELS}. We only use this method internally, when we know about a valid
* solver state. The returned evaluator does not have caching or any direct optimization for user
* interaction.
*
* @throws SolverException if model can not be constructed.
*/
protected abstract Evaluator getEvaluatorWithoutChecks()
throws SolverException, InterruptedException;
}