From 733d43bad7a314afb382dd07bc0c79eb60435a17 Mon Sep 17 00:00:00 2001 From: BaierD Date: Mon, 7 Apr 2025 15:36:38 +0200 Subject: [PATCH 01/20] Add general implementation for retrieving the 2 interpolation groups of asserted formulas from our tracking of asserted formulas --- .../java_smt/basicimpl/AbstractProver.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/org/sosy_lab/java_smt/basicimpl/AbstractProver.java b/src/org/sosy_lab/java_smt/basicimpl/AbstractProver.java index 72c894c56f..8f805ddc0b 100644 --- a/src/org/sosy_lab/java_smt/basicimpl/AbstractProver.java +++ b/src/org/sosy_lab/java_smt/basicimpl/AbstractProver.java @@ -17,8 +17,10 @@ import com.google.common.collect.Multimap; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.ArrayList; +import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map.Entry; import java.util.Set; import org.checkerframework.checker.nullness.qual.Nullable; import org.sosy_lab.java_smt.api.BasicProverEnvironment; @@ -125,6 +127,28 @@ protected ImmutableSet getAssertedFormulas() { return builder.build(); } + /** + * @param nativeFormulasOfA a group of formulas that has been asserted and is to be interpolated + * against. + * @return The de-duplicated collection of the 2 interpolation groups currently asserted as {@link + * BooleanFormula}s. + */ + protected InterpolationGroups getInterpolationGroups(Collection nativeFormulasOfA) { + ImmutableSet.Builder formulasOfA = ImmutableSet.builder(); + ImmutableSet.Builder formulasOfB = ImmutableSet.builder(); + for (Multimap assertedFormulasPerLevel : assertedFormulas) { + for (Entry assertedFormulaAndItpPoint : + assertedFormulasPerLevel.entries()) { + if (nativeFormulasOfA.contains(assertedFormulaAndItpPoint.getValue())) { + formulasOfA.add(assertedFormulaAndItpPoint.getKey()); + } else { + formulasOfB.add(assertedFormulaAndItpPoint.getKey()); + } + } + } + return InterpolationGroups.of(formulasOfA.build(), formulasOfB.build()); + } + protected ImmutableSet getAssertedConstraintIds() { ImmutableSet.Builder builder = ImmutableSet.builder(); for (Multimap level : assertedFormulas) { @@ -157,4 +181,31 @@ public void close() { closeAllEvaluators(); closed = true; } + + /** Provides the set of BooleanFormulas to interpolate on. */ + public static class InterpolationGroups { + private final Collection formulasOfA; + private final Collection formulasOfB; + + private InterpolationGroups( + Collection pFormulasOfA, Collection pFormulasOfB) { + Preconditions.checkNotNull(pFormulasOfA); + Preconditions.checkNotNull(pFormulasOfB); + formulasOfA = pFormulasOfA; + formulasOfB = pFormulasOfB; + } + + protected static InterpolationGroups of( + Collection pFormulasOfA, Collection pFormulasOfB) { + return new InterpolationGroups(pFormulasOfA, pFormulasOfB); + } + + protected Collection getFormulasOfA() { + return formulasOfA; + } + + protected Collection getFormulasOfB() { + return formulasOfB; + } + } } From 8d35e6913967b7f32d49bf86026c3fa5f9e217d4 Mon Sep 17 00:00:00 2001 From: BaierD Date: Mon, 7 Apr 2025 15:54:47 +0200 Subject: [PATCH 02/20] Add the new interpolation options to the ProverOptions --- .../sosy_lab/java_smt/api/SolverContext.java | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/api/SolverContext.java b/src/org/sosy_lab/java_smt/api/SolverContext.java index 3fbd476c77..2908627d49 100644 --- a/src/org/sosy_lab/java_smt/api/SolverContext.java +++ b/src/org/sosy_lab/java_smt/api/SolverContext.java @@ -53,7 +53,37 @@ enum ProverOptions { GENERATE_UNSAT_CORE_OVER_ASSUMPTIONS, /** Whether the solver should enable support for formulae build in SL theory. */ - ENABLE_SEPARATION_LOGIC + ENABLE_SEPARATION_LOGIC, + + /** + * Enables Craig interpolation, using the model-based interpolation strategy. This strategy + * constructs interpolants based on the model provided by a solver, i.e. model generation must + * be enabled. This interpolation strategy is only usable for solvers supporting quantified + * solving over the theories interpolated upon. The solver does not need to support + * interpolation itself. + */ + GENERATE_PROJECTION_BASED_INTERPOLANTS, + + /** + * Enables (uniform) Craig interpolation, using the quantifier-based interpolation strategy + * utilizing quantifier-elimination in the forward direction. Forward means, that the set of + * formulas A, used to interpolate, interpolates towards the set of formulas B (B == all + * formulas that are currently asserted, but not in the given set of formulas A used to + * interpolate). This interpolation strategy is only usable for solvers supporting + * quantifier-elimination over the theories interpolated upon. The solver does not need to + * support interpolation itself. + */ + GENERATE_UNIFORM_FORWARD_INTERPOLANTS, + + /** + * Enables (uniform) Craig interpolation, using the quantifier-based interpolation strategy + * utilizing quantifier-elimination in the backward direction. Backward means, that the set of + * formulas B (B == all formulas that are currently asserted, but not in the given set of + * formulas A used to interpolate) interpolates towards the set of formulas A. This + * interpolation strategy is only usable for solvers supporting quantifier-elimination over the + * theories interpolated upon. The solver does not need to support interpolation itself. + */ + GENERATE_UNIFORM_BACKWARD_INTERPOLANTS } /** From eab70d4d6c7335bcbe7814de4e8c19bcd4c8807c Mon Sep 17 00:00:00 2001 From: BaierD Date: Wed, 16 Apr 2025 11:18:05 +0200 Subject: [PATCH 03/20] Add a prover delegate for solver-independent interpolation to Prover creation in AbstractSolverContext --- .../basicimpl/AbstractSolverContext.java | 94 ++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java b/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java index ab49b14cfc..7a5733ae23 100644 --- a/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java +++ b/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java @@ -8,17 +8,22 @@ package org.sosy_lab.java_smt.basicimpl; +import com.google.common.base.Joiner; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSet; +import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Set; import java.util.function.Consumer; +import org.checkerframework.checker.nullness.qual.Nullable; import org.sosy_lab.java_smt.api.FormulaManager; import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment; import org.sosy_lab.java_smt.api.OptimizationProverEnvironment; import org.sosy_lab.java_smt.api.ProverEnvironment; import org.sosy_lab.java_smt.api.SolverContext; +import org.sosy_lab.java_smt.api.SolverException; import org.sosy_lab.java_smt.basicimpl.withAssumptionsWrapper.InterpolatingProverWithAssumptionsWrapper; import org.sosy_lab.java_smt.basicimpl.withAssumptionsWrapper.ProverWithAssumptionsWrapper; @@ -53,7 +58,7 @@ public final ProverEnvironment newProverEnvironment(ProverOptions... options) { public final InterpolatingProverEnvironment newProverEnvironmentWithInterpolation( ProverOptions... options) { - InterpolatingProverEnvironment out = newProverEnvironmentWithInterpolation0(toSet(options)); + InterpolatingProverEnvironment out = newProverEnvironmentWithInterpolation1(toSet(options)); if (!supportsAssumptionSolving()) { // In the case we do not already have a prover environment with assumptions, // we add a wrapper to it @@ -62,6 +67,57 @@ public final InterpolatingProverEnvironment newProverEnvironmentWithInterpola return out; } + // TODO: would it be better to add the option for interpolation procedure based on the call to + // getInterpolant() and always use the wrapper as long as there is a option? + // If this remains, clean it up! + @SuppressWarnings({"CheckReturnValue", "resource"}) + private InterpolatingProverEnvironment newProverEnvironmentWithInterpolation1( + Set options) { + InterpolatingProverEnvironment out; + // Try to get a new prover environment w native interpolation with the current options + try { + out = newProverEnvironmentWithInterpolation0(options); + } catch (UnsupportedOperationException e) { + // If native interpolation fails, we check the options for independent interpolation and + // return a wrapped normal prover with independent interpolation, as long as the prover + // supports the option chosen. + String additionalMsg = ". You can try to use a independent interpolation strategy."; + try { + if (!useNativeInterpolation(options)) { + if (getIndependentInterpolationStrategy(options) + == ProverOptions.GENERATE_UNIFORM_FORWARD_INTERPOLANTS + || getIndependentInterpolationStrategy(options) + == ProverOptions.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS) { + fmgr.getQuantifiedFormulaManager() + .eliminateQuantifiers(fmgr.getBooleanFormulaManager().makeTrue()); + } + return new IndependentInterpolatingSolverDelegate( + this, newProverEnvironment0(options), options); + } + } catch (UnsupportedOperationException e2) { + // Solver does not support independent interpolation + additionalMsg = + ". Interpolation strategy " + + getIndependentInterpolationStrategy(options) + + " is not " + + "available " + + "due to: " + + e2.getMessage(); + } catch (SolverException | InterruptedException pE) { + // Should never happen as we only run the solver briefly to determine feature availability + throw new RuntimeException(pE); + } + // Build a nice message with additional info + throw new UnsupportedOperationException(e.getMessage() + additionalMsg); + } + + if (!useNativeInterpolation(options)) { + // The user may choose to use independent interpolation on top of native + out = new IndependentInterpolatingSolverDelegate(this, out, options); + } + return out; + } + protected abstract InterpolatingProverEnvironment newProverEnvironmentWithInterpolation0( Set pSet); @@ -92,6 +148,42 @@ protected abstract OptimizationProverEnvironment newOptimizationProverEnvironmen */ protected abstract boolean supportsAssumptionSolving(); + private static final Set ALL_INDEPENDENT_INTERPOLATION_STRATEGIES = + ImmutableSet.of( + ProverOptions.GENERATE_PROJECTION_BASED_INTERPOLANTS, + ProverOptions.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, + ProverOptions.GENERATE_UNIFORM_FORWARD_INTERPOLANTS); + + protected boolean useNativeInterpolation(Set options) { + return getIndependentInterpolationStrategy(options) == null; + } + + @SuppressWarnings("CheckReturnValue") + protected @Nullable ProverOptions getIndependentInterpolationStrategy( + Set options) { + List itpStrat = new ArrayList<>(options); + itpStrat.retainAll(ALL_INDEPENDENT_INTERPOLATION_STRATEGIES); + + if (itpStrat.isEmpty()) { + return null; + } else if (itpStrat.size() != 1) { + throw new IllegalArgumentException( + "Only a single independent interpolation strategy can be" + + " chosen for a prover, but chosen were: " + + Joiner.on(", ").join(options)); + } + + ProverOptions interpolationOption = itpStrat.get(0); + try { + fmgr.getQuantifiedFormulaManager(); + } catch (UnsupportedOperationException e) { + throw new UnsupportedOperationException( + "Solver does not support independent interpolation based on the current strategy, as" + + " it is lacking quantifier support."); + } + return interpolationOption; + } + private static Set toSet(ProverOptions... options) { Set opts = EnumSet.noneOf(ProverOptions.class); Collections.addAll(opts, options); From 4d7792401a559e3ec9447064f3a927e1248b9e42 Mon Sep 17 00:00:00 2001 From: BaierD Date: Fri, 16 May 2025 11:45:29 +0200 Subject: [PATCH 04/20] Add options enum for interpolation --- .../api/InterpolatingProverEnvironment.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/org/sosy_lab/java_smt/api/InterpolatingProverEnvironment.java b/src/org/sosy_lab/java_smt/api/InterpolatingProverEnvironment.java index 7c4d7ecff0..882170efbc 100644 --- a/src/org/sosy_lab/java_smt/api/InterpolatingProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/api/InterpolatingProverEnvironment.java @@ -25,6 +25,45 @@ */ public interface InterpolatingProverEnvironment extends BasicProverEnvironment { + enum InterpolationOption { + + /** + * The chosen solvers native interpolation. Additional options have to be selected when creating + * the solver or prover. + */ + NATIVE, + + /** + * Enables Craig interpolation, using the model-based interpolation strategy. This strategy + * constructs interpolants based on the model provided by a solver, i.e. model generation must + * be enabled. This interpolation strategy is only usable for solvers supporting quantified + * solving over the theories interpolated upon. The solver does not need to support + * interpolation itself. + */ + GENERATE_PROJECTION_BASED_INTERPOLANTS, + + /** + * Enables (uniform) Craig interpolation, using the quantifier-based interpolation strategy + * utilizing quantifier-elimination in the forward direction. Forward means, that the set of + * formulas A, used to interpolate, interpolates towards the set of formulas B (B == all + * formulas that are currently asserted, but not in the given set of formulas A used to + * interpolate). This interpolation strategy is only usable for solvers supporting + * quantifier-elimination over the theories interpolated upon. The solver does not need to + * support interpolation itself. + */ + GENERATE_UNIFORM_FORWARD_INTERPOLANTS, + + /** + * Enables (uniform) Craig interpolation, using the quantifier-based interpolation strategy + * utilizing quantifier-elimination in the backward direction. Backward means, that the set of + * formulas B (B == all formulas that are currently asserted, but not in the given set of + * formulas A used to interpolate) interpolates towards the set of formulas A. This + * interpolation strategy is only usable for solvers supporting quantifier-elimination over the + * theories interpolated upon. The solver does not need to support interpolation itself. + */ + GENERATE_UNIFORM_BACKWARD_INTERPOLANTS + } + /** * Get an interpolant for two groups of formulas. This should be called only immediately after an * {@link #isUnsat()} call that returned true. @@ -45,6 +84,14 @@ public interface InterpolatingProverEnvironment extends BasicProverEnvironmen BooleanFormula getInterpolant(Collection formulasOfA) throws SolverException, InterruptedException; + default BooleanFormula getInterpolant(Collection formulasOfA, InterpolationOption option) + throws SolverException, InterruptedException { + if (option == InterpolationOption.NATIVE) { + return getInterpolant(formulasOfA); + } + throw new UnsupportedOperationException("Interpolation option " + option + " not supported"); + } + /** * This method returns interpolants of an 'inductive sequence'. This property must be supported by * the interpolation-strategy of the underlying SMT-solver! Depending on the underlying SMT-solver From e2119ad1e6120bdfa0b0f17aac40ba2149a744c6 Mon Sep 17 00:00:00 2001 From: BaierD Date: Fri, 16 May 2025 11:45:57 +0200 Subject: [PATCH 05/20] Extend parameterized tests with possibility for second parameter for interpolation --- .../java_smt/test/SolverBasedTest0.java | 111 +++++++++++++++++- 1 file changed, 109 insertions(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java b/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java index f38248560d..08f18f185d 100644 --- a/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java +++ b/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java @@ -8,13 +8,24 @@ package org.sosy_lab.java_smt.test; +import static com.google.common.base.Preconditions.checkState; import static com.google.common.truth.TruthJUnit.assume; +import static org.sosy_lab.java_smt.api.InterpolatingProverEnvironment.InterpolationOption.GENERATE_PROJECTION_BASED_INTERPOLANTS; +import static org.sosy_lab.java_smt.api.InterpolatingProverEnvironment.InterpolationOption.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS; +import static org.sosy_lab.java_smt.api.InterpolatingProverEnvironment.InterpolationOption.GENERATE_UNIFORM_FORWARD_INTERPOLANTS; +import static org.sosy_lab.java_smt.api.InterpolatingProverEnvironment.InterpolationOption.NATIVE; import static org.sosy_lab.java_smt.test.BooleanFormulaSubject.assertUsing; import static org.sosy_lab.java_smt.test.ProverEnvironmentSubject.assertThat; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; import com.google.common.truth.Truth; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; +import java.util.Set; import org.checkerframework.checker.nullness.qual.Nullable; import org.junit.After; import org.junit.Before; @@ -40,6 +51,7 @@ import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaManager; import org.sosy_lab.java_smt.api.IntegerFormulaManager; +import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment.InterpolationOption; import org.sosy_lab.java_smt.api.Model; import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula; import org.sosy_lab.java_smt.api.NumeralFormula.RationalFormula; @@ -288,9 +300,9 @@ protected final void requireOptimization() { } } - protected final void requireInterpolation() { + protected final void requireInterpolation(ProverOptions... options) { try { - context.newProverEnvironmentWithInterpolation().close(); + context.newProverEnvironmentWithInterpolation(options).close(); } catch (UnsupportedOperationException e) { assume() .withMessage("Solver %s does not support interpolation", solverToUse()) @@ -299,6 +311,21 @@ protected final void requireInterpolation() { } } + protected final void requireSeqItp(InterpolationOption... options) { + assume() + .withMessage( + "Solver independent interpolation strategy %s does not support sequential " + + "or tree interpolation", + solverToUse()) + .that(options) + .asList() + .containsNoneIn( + ImmutableList.of( + GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, + GENERATE_PROJECTION_BASED_INTERPOLANTS, + GENERATE_UNIFORM_FORWARD_INTERPOLANTS)); + } + protected void requireParser() { assume() .withMessage("Solver %s does not support parsing formulae", solverToUse()) @@ -364,6 +391,54 @@ protected final BooleanFormulaSubject assertThatFormula(BooleanFormula formula) return assertUsing(context).that(formula); } + /** Check that the interpolant in the subject is valid fot the formulas A and B. */ + public void isValidInterpolant(BooleanFormula interpolant, BooleanFormula a, BooleanFormula b) + throws SolverException, InterruptedException { + // TODO: move into assertion framework + isValidInterpolant(interpolant, ImmutableList.of(a), ImmutableList.of(b)); + } + + /** Check that the interpolant in the subject is valid fot the formulas A and B. */ + public void isValidInterpolant( + BooleanFormula interpolant, + List formulasOfA, + List formulasOfB) + throws SolverException, InterruptedException { + // TODO: move into assertion framework + + BooleanFormula conjugatedFormulasOfA = bmgr.and(formulasOfA); + BooleanFormula conjugatedFormulasOfB = bmgr.and(formulasOfB); + + // checks that every Symbol of the interpolant appears either in A or B + Set interpolantSymbols = mgr.extractVariablesAndUFs(interpolant).keySet(); + Set interpolASymbols = mgr.extractVariablesAndUFs(conjugatedFormulasOfA).keySet(); + Set interpolBSymbols = mgr.extractVariablesAndUFs(conjugatedFormulasOfB).keySet(); + Set intersection = Sets.intersection(interpolASymbols, interpolBSymbols); + // TODO: assertThat is not available with message + checkState( + intersection.containsAll(interpolantSymbols), + "Interpolant contains symbols %s that are not part of both input formula groups A and B.", + Sets.difference(interpolantSymbols, intersection)); + + try (ProverEnvironment validationProver = context.newProverEnvironment()) { + validationProver.push(); + validationProver.addConstraint(bmgr.implication(conjugatedFormulasOfA, interpolant)); + // TODO: assertThat is not available with message + checkState( + !validationProver.isUnsat(), + "Invalid Craig interpolation: formula group A does not imply the interpolant."); + validationProver.pop(); + + validationProver.push(); + validationProver.addConstraint(bmgr.and(interpolant, conjugatedFormulasOfB)); + // TODO: assertThat is not available with message + checkState( + validationProver.isUnsat(), + "Invalid Craig interpolation: interpolant does not contradict formula group B."); + validationProver.pop(); + } + } + /** * Use this for checking assertions about ProverEnvironments with Truth: * assertThatEnvironment(stack).is...(). @@ -438,4 +513,36 @@ protected Solvers solverToUse() { return solver; } } + + @RunWith(Parameterized.class) + public abstract static class ParameterizedInterpolatingSolverBasedTest0 + extends ParameterizedSolverBasedTest0 { + + // GENERATE_MODELS as stand-in for native + private static final Set ALL_INTERPOLATION_STRATEGIES = + ImmutableSet.of( + NATIVE, + GENERATE_PROJECTION_BASED_INTERPOLANTS, + GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, + GENERATE_UNIFORM_FORWARD_INTERPOLANTS); + + @Parameters(name = "solver {0} with interpolation strategy {1}") + public static List getAllSolversAndItpStrategies() { + List lst = new ArrayList<>(); + for (Solvers solver : Solvers.values()) { + // No arg for no option (== solver native interpolation) + for (InterpolationOption itpStrat : ALL_INTERPOLATION_STRATEGIES) { + lst.add(new Object[] {solver, itpStrat}); + } + } + return lst; + } + + @Parameter(1) + public ProverOptions interpolationStrategy; + + protected ProverOptions itpStrategyToUse() { + return interpolationStrategy; + } + } } From f9d735c3afe3c63d65fd6407e1ceb36ff1f5059e Mon Sep 17 00:00:00 2001 From: BaierD Date: Fri, 16 May 2025 11:46:31 +0200 Subject: [PATCH 06/20] Remove options for interpolation from ProverOptions --- .../sosy_lab/java_smt/api/SolverContext.java | 32 +------------------ 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/src/org/sosy_lab/java_smt/api/SolverContext.java b/src/org/sosy_lab/java_smt/api/SolverContext.java index 2908627d49..3fbd476c77 100644 --- a/src/org/sosy_lab/java_smt/api/SolverContext.java +++ b/src/org/sosy_lab/java_smt/api/SolverContext.java @@ -53,37 +53,7 @@ enum ProverOptions { GENERATE_UNSAT_CORE_OVER_ASSUMPTIONS, /** Whether the solver should enable support for formulae build in SL theory. */ - ENABLE_SEPARATION_LOGIC, - - /** - * Enables Craig interpolation, using the model-based interpolation strategy. This strategy - * constructs interpolants based on the model provided by a solver, i.e. model generation must - * be enabled. This interpolation strategy is only usable for solvers supporting quantified - * solving over the theories interpolated upon. The solver does not need to support - * interpolation itself. - */ - GENERATE_PROJECTION_BASED_INTERPOLANTS, - - /** - * Enables (uniform) Craig interpolation, using the quantifier-based interpolation strategy - * utilizing quantifier-elimination in the forward direction. Forward means, that the set of - * formulas A, used to interpolate, interpolates towards the set of formulas B (B == all - * formulas that are currently asserted, but not in the given set of formulas A used to - * interpolate). This interpolation strategy is only usable for solvers supporting - * quantifier-elimination over the theories interpolated upon. The solver does not need to - * support interpolation itself. - */ - GENERATE_UNIFORM_FORWARD_INTERPOLANTS, - - /** - * Enables (uniform) Craig interpolation, using the quantifier-based interpolation strategy - * utilizing quantifier-elimination in the backward direction. Backward means, that the set of - * formulas B (B == all formulas that are currently asserted, but not in the given set of - * formulas A used to interpolate) interpolates towards the set of formulas A. This - * interpolation strategy is only usable for solvers supporting quantifier-elimination over the - * theories interpolated upon. The solver does not need to support interpolation itself. - */ - GENERATE_UNIFORM_BACKWARD_INTERPOLANTS + ENABLE_SEPARATION_LOGIC } /** From 8f87aec9d7d7a131811a9bb5b40ce338f2750eb9 Mon Sep 17 00:00:00 2001 From: BaierD Date: Fri, 16 May 2025 11:48:50 +0200 Subject: [PATCH 07/20] Add InterpolatingProverDelegate that allows to use interpolation API for solvers that do not allow interpolation --- .../InterpolatingSolverDelegate.java | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 src/org/sosy_lab/java_smt/basicimpl/InterpolatingSolverDelegate.java diff --git a/src/org/sosy_lab/java_smt/basicimpl/InterpolatingSolverDelegate.java b/src/org/sosy_lab/java_smt/basicimpl/InterpolatingSolverDelegate.java new file mode 100644 index 0000000000..59f78ea8e9 --- /dev/null +++ b/src/org/sosy_lab/java_smt/basicimpl/InterpolatingSolverDelegate.java @@ -0,0 +1,116 @@ +/* + * This file is part of JavaSMT, + * an API wrapper for a collection of SMT solvers: + * https://github.com/sosy-lab/java-smt + * + * SPDX-FileCopyrightText: 2024 Dirk Beyer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.sosy_lab.java_smt.basicimpl; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static org.sosy_lab.java_smt.basicimpl.IndependentInterpolatingSolverDelegate.generateTermName; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import org.sosy_lab.java_smt.api.BasicProverEnvironment; +import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment; +import org.sosy_lab.java_smt.api.Model; +import org.sosy_lab.java_smt.api.SolverContext.ProverOptions; +import org.sosy_lab.java_smt.api.SolverException; + +/** Delegate that wraps non-interpolating provers, allowing them to return itp tracking points. */ +public class InterpolatingSolverDelegate extends AbstractProver + implements InterpolatingProverEnvironment { + + private final BasicProverEnvironment delegate; + + protected InterpolatingSolverDelegate( + BasicProverEnvironment pDelegate, Set pOptions) { + super(checkNotNull(pOptions)); + // TODO: is the delegate also saving all info of AbstractProver additionally, or does VOID + // prevent that? + delegate = checkNotNull(pDelegate); + } + + @Override + public BooleanFormula getInterpolant(Collection formulasOfA) + throws SolverException, InterruptedException { + throw new UnsupportedOperationException("Solver does not support native interpolation."); + } + + @Override + public List getTreeInterpolants( + List> partitionedFormulas, int[] startOfSubTree) + throws SolverException, InterruptedException { + throw new UnsupportedOperationException( + "Tree interpolants are currently not supported using " + "independent interpolation"); + } + + @Override + protected void popImpl() { + delegate.pop(); + } + + @Override + protected String addConstraintImpl(BooleanFormula constraint) throws InterruptedException { + checkState(!closed); + delegate.addConstraint(constraint); + String termName = generateTermName(); + return termName; + } + + @Override + protected void pushImpl() throws InterruptedException { + delegate.push(); + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isUnsat() throws SolverException, InterruptedException { + return delegate.isUnsat(); + } + + @Override + public boolean isUnsatWithAssumptions(Collection assumptions) + throws SolverException, InterruptedException { + return delegate.isUnsatWithAssumptions(assumptions); + } + + @Override + public Model getModel() throws SolverException { + return delegate.getModel(); + } + + @Override + public List getUnsatCore() { + return delegate.getUnsatCore(); + } + + @Override + public Optional> unsatCoreOverAssumptions( + Collection assumptions) throws SolverException, InterruptedException { + return delegate.unsatCoreOverAssumptions(assumptions); + } + + @Override + public void close() { + delegate.close(); + } + + @Override + public R allSat(AllSatCallback callback, List important) + throws InterruptedException, SolverException { + return delegate.allSat(callback, important); + } +} From a4769a46f0a2c96ca5c84a9d08a0fecd4be1a3f0 Mon Sep 17 00:00:00 2001 From: BaierD Date: Fri, 16 May 2025 11:49:50 +0200 Subject: [PATCH 08/20] Add IndependentInterpolatingSolverDelegate that allows to use independent interpolation (or native) depending on an option when asking for an interpolant (the techniques are unfinished!) --- .../basicimpl/AbstractSolverContext.java | 60 +-- ...ndependentInterpolatingSolverDelegate.java | 410 ++++++++++++++++++ 2 files changed, 425 insertions(+), 45 deletions(-) create mode 100644 src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java diff --git a/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java b/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java index 7a5733ae23..9b772afbac 100644 --- a/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java +++ b/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java @@ -8,6 +8,10 @@ package org.sosy_lab.java_smt.basicimpl; +import static org.sosy_lab.java_smt.api.InterpolatingProverEnvironment.InterpolationOption.GENERATE_PROJECTION_BASED_INTERPOLANTS; +import static org.sosy_lab.java_smt.api.InterpolatingProverEnvironment.InterpolationOption.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS; +import static org.sosy_lab.java_smt.api.InterpolatingProverEnvironment.InterpolationOption.GENERATE_UNIFORM_FORWARD_INTERPOLANTS; + import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; @@ -20,10 +24,10 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.sosy_lab.java_smt.api.FormulaManager; import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment; +import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment.InterpolationOption; import org.sosy_lab.java_smt.api.OptimizationProverEnvironment; import org.sosy_lab.java_smt.api.ProverEnvironment; import org.sosy_lab.java_smt.api.SolverContext; -import org.sosy_lab.java_smt.api.SolverException; import org.sosy_lab.java_smt.basicimpl.withAssumptionsWrapper.InterpolatingProverWithAssumptionsWrapper; import org.sosy_lab.java_smt.basicimpl.withAssumptionsWrapper.ProverWithAssumptionsWrapper; @@ -67,10 +71,6 @@ public final InterpolatingProverEnvironment newProverEnvironmentWithInterpola return out; } - // TODO: would it be better to add the option for interpolation procedure based on the call to - // getInterpolant() and always use the wrapper as long as there is a option? - // If this remains, clean it up! - @SuppressWarnings({"CheckReturnValue", "resource"}) private InterpolatingProverEnvironment newProverEnvironmentWithInterpolation1( Set options) { InterpolatingProverEnvironment out; @@ -78,44 +78,14 @@ private InterpolatingProverEnvironment newProverEnvironmentWithInterpolation1 try { out = newProverEnvironmentWithInterpolation0(options); } catch (UnsupportedOperationException e) { - // If native interpolation fails, we check the options for independent interpolation and - // return a wrapped normal prover with independent interpolation, as long as the prover - // supports the option chosen. - String additionalMsg = ". You can try to use a independent interpolation strategy."; - try { - if (!useNativeInterpolation(options)) { - if (getIndependentInterpolationStrategy(options) - == ProverOptions.GENERATE_UNIFORM_FORWARD_INTERPOLANTS - || getIndependentInterpolationStrategy(options) - == ProverOptions.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS) { - fmgr.getQuantifiedFormulaManager() - .eliminateQuantifiers(fmgr.getBooleanFormulaManager().makeTrue()); - } - return new IndependentInterpolatingSolverDelegate( - this, newProverEnvironment0(options), options); - } - } catch (UnsupportedOperationException e2) { - // Solver does not support independent interpolation - additionalMsg = - ". Interpolation strategy " - + getIndependentInterpolationStrategy(options) - + " is not " - + "available " - + "due to: " - + e2.getMessage(); - } catch (SolverException | InterruptedException pE) { - // Should never happen as we only run the solver briefly to determine feature availability - throw new RuntimeException(pE); - } - // Build a nice message with additional info - throw new UnsupportedOperationException(e.getMessage() + additionalMsg); + // If native interpolation is not available, we wrap a normal prover such that it returns + // interpolation points + ProverEnvironment normalProver = newProverEnvironment0(options); + out = new InterpolatingSolverDelegate(normalProver, options); } - if (!useNativeInterpolation(options)) { - // The user may choose to use independent interpolation on top of native - out = new IndependentInterpolatingSolverDelegate(this, out, options); - } - return out; + // TODO: do we need the assumptions inside of the interpolation delegate? + return new IndependentInterpolatingSolverDelegate<>(this, out, options); } protected abstract InterpolatingProverEnvironment newProverEnvironmentWithInterpolation0( @@ -148,11 +118,11 @@ protected abstract OptimizationProverEnvironment newOptimizationProverEnvironmen */ protected abstract boolean supportsAssumptionSolving(); - private static final Set ALL_INDEPENDENT_INTERPOLATION_STRATEGIES = + private static final Set ALL_INDEPENDENT_INTERPOLATION_STRATEGIES = ImmutableSet.of( - ProverOptions.GENERATE_PROJECTION_BASED_INTERPOLANTS, - ProverOptions.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, - ProverOptions.GENERATE_UNIFORM_FORWARD_INTERPOLANTS); + GENERATE_PROJECTION_BASED_INTERPOLANTS, + GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, + GENERATE_UNIFORM_FORWARD_INTERPOLANTS); protected boolean useNativeInterpolation(Set options) { return getIndependentInterpolationStrategy(options) == null; diff --git a/src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java b/src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java new file mode 100644 index 0000000000..379cea995d --- /dev/null +++ b/src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java @@ -0,0 +1,410 @@ +/* + * This file is part of JavaSMT, + * an API wrapper for a collection of SMT solvers: + * https://github.com/sosy-lab/java-smt + * + * SPDX-FileCopyrightText: 2024 Dirk Beyer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.sosy_lab.java_smt.basicimpl; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static org.sosy_lab.java_smt.api.FormulaType.BooleanType; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Sets; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import org.sosy_lab.common.UniqueIdGenerator; +import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.BooleanFormulaManager; +import org.sosy_lab.java_smt.api.Formula; +import org.sosy_lab.java_smt.api.FormulaManager; +import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment; +import org.sosy_lab.java_smt.api.Model; +import org.sosy_lab.java_smt.api.ProverEnvironment; +import org.sosy_lab.java_smt.api.QuantifiedFormulaManager; +import org.sosy_lab.java_smt.api.QuantifiedFormulaManager.Quantifier; +import org.sosy_lab.java_smt.api.SolverContext; +import org.sosy_lab.java_smt.api.SolverContext.ProverOptions; +import org.sosy_lab.java_smt.api.SolverException; +import org.sosy_lab.java_smt.api.UFManager; +import org.sosy_lab.java_smt.api.visitors.DefaultFormulaVisitor; +import org.sosy_lab.java_smt.api.visitors.TraversalProcess; + +public class IndependentInterpolatingSolverDelegate extends AbstractProver + implements InterpolatingProverEnvironment { + + private final SolverContext solverContext; + + private final InterpolatingProverEnvironment delegate; + + private final FormulaManager mgr; + private final BooleanFormulaManager bmgr; + private final UFManager ufmgr; + + private static final String PREFIX = "javasmt_itp_term_"; // for term-names + private static final UniqueIdGenerator termIdGenerator = + new UniqueIdGenerator(); // for different term-names + + Map itpPointsMap = new HashMap<>(); + + protected IndependentInterpolatingSolverDelegate( + AbstractSolverContext pSourceContext, + InterpolatingProverEnvironment pDelegate, + Set pOptions) { + super(checkNotNull(pOptions)); + solverContext = checkNotNull(pSourceContext); + delegate = checkNotNull(pDelegate); + mgr = pSourceContext.getFormulaManager(); + bmgr = mgr.getBooleanFormulaManager(); + ufmgr = mgr.getUFManager(); + } + + // TODO: also present in SMTInterpol, generalize + protected static String generateTermName() { + return PREFIX + termIdGenerator.getFreshId(); + } + + @Override + public BooleanFormula getInterpolant(Collection identifiersForA, InterpolationOption option) + throws SolverException, InterruptedException { + Preconditions.checkState(!closed); + checkArgument( + getAssertedConstraintIds().containsAll(identifiersForA), + "Interpolation can only be performed over previously asserted formulas."); + + if (identifiersForA.isEmpty()) { + return bmgr.makeTrue(); + } + + InterpolationGroups interpolationGroups = super.getInterpolationGroups(identifiersForA); + Collection formulasOfA = interpolationGroups.getFormulasOfA(); + Collection formulasOfB = interpolationGroups.getFormulasOfB(); + + if (formulasOfB.isEmpty()) { + return bmgr.makeFalse(); + } + + BooleanFormula conjugatedFormulasOfA = bmgr.and(formulasOfA); + BooleanFormula conjugatedFormulasOfB = bmgr.and(formulasOfB); + + List variablesInA = getAllVariables(conjugatedFormulasOfA); + List variablesInB = getAllVariables(conjugatedFormulasOfB); + List sharedVariables = getCommonFormulas(variablesInA, variablesInB); + List exclusiveVariablesInA = removeVariablesFrom(variablesInA, sharedVariables); + List exclusiveVariablesInB = removeVariablesFrom(variablesInB, sharedVariables); + + BooleanFormula interpolant; + switch (checkNotNull(option)) { + case NATIVE: + interpolant = getInterpolant(identifiersForA); + break; + case GENERATE_PROJECTION_BASED_INTERPOLANTS: + // Will generate CHC based constraints that are very hard to solve without a CHC solver + if (sharedVariables.isEmpty()) { + return bmgr.makeFalse(); + } + interpolant = + getModelBasedProjectionInterpolant( + conjugatedFormulasOfA, + conjugatedFormulasOfB, + variablesInA, + variablesInB, + sharedVariables); + break; + case GENERATE_UNIFORM_FORWARD_INTERPOLANTS: + // Will generate interpolants based on quantifier elimination + if (exclusiveVariablesInA.isEmpty()) { + return bmgr.makeFalse(); + } + interpolant = getUniformForwardInterpolant(conjugatedFormulasOfA, exclusiveVariablesInA); + break; + case GENERATE_UNIFORM_BACKWARD_INTERPOLANTS: + // Will generate interpolants based on quantifier elimination + if (exclusiveVariablesInB.isEmpty()) { + return bmgr.makeFalse(); + } + // Note: uses the A -> i -> B is valid definition for Craig-Interpolants, so we negate B + interpolant = + getUniformBackwardInterpolant(bmgr.not(conjugatedFormulasOfB), exclusiveVariablesInB); + break; + default: + throw new AssertionError("Unknown interpolation strategy " + option); + } + + assert satisfiesInterpolationCriteria( + interpolant, conjugatedFormulasOfA, conjugatedFormulasOfB); + + return interpolant; + } + + @Override + public BooleanFormula getInterpolant(Collection formulasOfA) + throws SolverException, InterruptedException { + return delegate.getInterpolant(formulasOfA); + } + + /** + * Extracts all variables (not UFs) from the given formula. There are no duplicates in the list. * + */ + private List getAllVariables(BooleanFormula formula) { + return mgr.extractVariables(formula).values().asList(); + } + + /** + * Checks the following 3 criteria for Craig interpolants: + * + *

1. the implication A ⇒ interpolant holds, + * + *

2. the conjunction interpolant ∧ B is unsatisfiable, and + * + *

3. interpolant only contains symbols that occur in both A and B. + */ + private boolean satisfiesInterpolationCriteria( + BooleanFormula interpolant, + BooleanFormula conjugatedFormulasOfA, + BooleanFormula conjugatedFormulasOfB) + throws InterruptedException, SolverException { + + // checks that every Symbol of the interpolant appears either in A or B + Set interpolantSymbols = mgr.extractVariablesAndUFs(interpolant).keySet(); + Set interpolASymbols = mgr.extractVariablesAndUFs(conjugatedFormulasOfA).keySet(); + Set interpolBSymbols = mgr.extractVariablesAndUFs(conjugatedFormulasOfB).keySet(); + Set intersection = Sets.intersection(interpolASymbols, interpolBSymbols); + checkState( + intersection.containsAll(interpolantSymbols), + "Interpolant contains symbols %s that are not part of both input formula groups A and B.", + Sets.difference(interpolantSymbols, intersection)); + + try (ProverEnvironment validationSolver = getDistinctProver()) { + validationSolver.push(); + // A -> interpolant is SAT + validationSolver.addConstraint(bmgr.implication(conjugatedFormulasOfA, interpolant)); + checkState( + !validationSolver.isUnsat(), + "Invalid Craig interpolation: formula group A does not imply the interpolant."); + validationSolver.pop(); + + validationSolver.push(); + // interpolant AND B is UNSAT + validationSolver.addConstraint(bmgr.and(interpolant, conjugatedFormulasOfB)); + checkState( + validationSolver.isUnsat(), + "Invalid Craig interpolation: interpolant does not contradict formula group B."); + validationSolver.pop(); + } + return true; + } + + /** interpolate(A(x,y),B(y,z))=∀z.¬B(y,z) */ + private BooleanFormula getUniformBackwardInterpolant( + BooleanFormula formulasOfB, List exclusiveVariables) + throws SolverException, InterruptedException { + + QuantifiedFormulaManager qfmgr = mgr.getQuantifiedFormulaManager(); + BooleanFormula itpBackwardQuantified = qfmgr.forall(exclusiveVariables, bmgr.not(formulasOfB)); + BooleanFormula itpBackward = qfmgr.eliminateQuantifiers(itpBackwardQuantified); + // Check that the top-level quantifier has been eliminated + if (isQuantifiedFormula(itpBackwardQuantified)) { + throw new SolverException( + "Error when calculating uniform interpolant, quantifier elimination failed."); + } + + return itpBackward; + } + + /** Checks the formula for a quantifier at an arbitrary position/depth. */ + private boolean isQuantifiedFormula(BooleanFormula maybeQuantifiedFormula) { + final AtomicBoolean isQuantified = new AtomicBoolean(false); + mgr.visitRecursively( + maybeQuantifiedFormula, + new DefaultFormulaVisitor<>() { + + @Override + protected TraversalProcess visitDefault(Formula pF) { + return TraversalProcess.CONTINUE; + } + + @Override + public TraversalProcess visitQuantifier( + BooleanFormula pF, + Quantifier pQ, + List pBoundVariables, + BooleanFormula pBody) { + isQuantified.set(true); + return TraversalProcess.ABORT; + } + }); + return isQuantified.get(); + } + + /** + * Computes the uniform Craig interpolant, utilizing quantifier-elimination in the forward + * direction with: interpolate(A(x,y),B(y,z)) = ∃x.A(x,y) + * + *

Forward means, that the set of formulas A interpolates towards the set of formulas B. + * + * @param conjugatedFormulasOfA The set of formulas A, combined into one {@link BooleanFormula}. + * @param exclusiveVariables A list of shared variables found in both sets of formulas A and B. + * @return a uniform Craig interpolant or an exception is thrown. + */ + private BooleanFormula getUniformForwardInterpolant( + BooleanFormula conjugatedFormulasOfA, List exclusiveVariables) + throws SolverException, InterruptedException { + + QuantifiedFormulaManager qfmgr = mgr.getQuantifiedFormulaManager(); + BooleanFormula itpForwardQuantified = qfmgr.exists(exclusiveVariables, conjugatedFormulasOfA); + BooleanFormula itpForward = qfmgr.eliminateQuantifiers(itpForwardQuantified); + // Check that the top-level quantifier has been eliminated + if (isQuantifiedFormula(itpForward)) { + throw new SolverException( + "Error when calculating uniform interpolant, quantifier elimination failed."); + } + + return itpForward; + } + + private BooleanFormula getModelBasedProjectionInterpolant( + BooleanFormula conjugatedFormulasOfA, + BooleanFormula conjugatedFormulasOfB, + List variablesInA, + List variablesInB, + List sharedVars) + throws InterruptedException, SolverException { + + QuantifiedFormulaManager qfmgr = mgr.getQuantifiedFormulaManager(); + + BooleanFormula itp = + ufmgr.declareAndCallUF( + "__itp_internal_javasmt_" + termIdGenerator.getFreshId(), BooleanType, sharedVars); + BooleanFormula left = qfmgr.forall(variablesInA, bmgr.implication(conjugatedFormulasOfA, itp)); + BooleanFormula right = + qfmgr.forall(variablesInB, bmgr.implication(itp, bmgr.not(conjugatedFormulasOfB))); + + BooleanFormula interpolant = bmgr.makeFalse(); + try (ProverEnvironment itpProver = getDistinctProver()) { + + itpProver.push(left); + itpProver.push(right); + + if (!itpProver.isUnsat()) { + try (Model model = itpProver.getModel()) { + interpolant = model.eval(itp); + } + checkNotNull(interpolant); + } + } + return interpolant; + } + + /** + * Create a new, distinct prover to interpolate on. Will be able to generate models. + * + * @return A new {@link ProverEnvironment} configured to generate models. + */ + private ProverEnvironment getDistinctProver() { + // TODO: we should include the possibility to choose from options here. E.g. CHC/Horn solvers. + return solverContext.newProverEnvironment(ProverOptions.GENERATE_MODELS); + } + + /** Returns common {@link org.sosy_lab.java_smt.api.Formula}s of the 2 given lists. * */ + private List getCommonFormulas( + List variables1, List variables2) { + HashSet set = new HashSet<>(variables1); + set.retainAll(variables2); + return ImmutableList.copyOf(set); + } + + /** + * Removes variablesToRemove from variablesToRemoveFrom and returns a new list without modifying + * the old lists. + */ + private List removeVariablesFrom( + List variablesToRemoveFrom, List variablesToRemove) { + ImmutableList.Builder builder = ImmutableList.builder(); + for (Formula var : variablesToRemoveFrom) { + if (!variablesToRemove.contains(var)) { + builder.add(var); + } + } + return builder.build(); + } + + @Override + public List getTreeInterpolants( + List> partitionedFormulas, int[] startOfSubTree) + throws SolverException, InterruptedException { + throw new UnsupportedOperationException( + "Tree interpolants are currently not supported using " + "independent interpolation"); + } + + @Override + protected void popImpl() { + delegate.pop(); + } + + @Override + protected T addConstraintImpl(BooleanFormula constraint) throws InterruptedException { + return delegate.addConstraint(constraint); + } + + @Override + protected void pushImpl() throws InterruptedException { + delegate.push(); + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isUnsat() throws SolverException, InterruptedException { + return delegate.isUnsat(); + } + + @Override + public boolean isUnsatWithAssumptions(Collection assumptions) + throws SolverException, InterruptedException { + return delegate.isUnsatWithAssumptions(assumptions); + } + + @Override + public Model getModel() throws SolverException { + return delegate.getModel(); + } + + @Override + public List getUnsatCore() { + return delegate.getUnsatCore(); + } + + @Override + public Optional> unsatCoreOverAssumptions( + Collection assumptions) throws SolverException, InterruptedException { + return delegate.unsatCoreOverAssumptions(assumptions); + } + + @Override + public void close() { + delegate.close(); + } + + @Override + public R allSat(AllSatCallback callback, List important) + throws InterruptedException, SolverException { + return delegate.allSat(callback, important); + } +} From c256db97422ca4241ec2d4315205bab505d5bcb4 Mon Sep 17 00:00:00 2001 From: Julius Brehme Date: Fri, 28 Nov 2025 13:37:19 +0100 Subject: [PATCH 09/20] First changes to get the independent interpolation method working --- .../api/InterpolatingProverEnvironment.java | 14 +- .../sosy_lab/java_smt/api/SolverContext.java | 6 +- .../basicimpl/AbstractSolverContext.java | 8 +- ...ndependentInterpolatingSolverDelegate.java | 152 +++++++++++----- .../example/IndependentInterpolation.java | 170 ++++++++++++++++++ .../test/InterpolatingProverTest.java | 10 +- .../java_smt/test/SolverBasedTest0.java | 27 ++- 7 files changed, 318 insertions(+), 69 deletions(-) create mode 100644 src/org/sosy_lab/java_smt/example/IndependentInterpolation.java diff --git a/src/org/sosy_lab/java_smt/api/InterpolatingProverEnvironment.java b/src/org/sosy_lab/java_smt/api/InterpolatingProverEnvironment.java index 4187e1072e..cf687b43cb 100644 --- a/src/org/sosy_lab/java_smt/api/InterpolatingProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/api/InterpolatingProverEnvironment.java @@ -84,13 +84,13 @@ enum InterpolationOption { BooleanFormula getInterpolant(Collection formulasOfA) throws SolverException, InterruptedException; - default BooleanFormula getInterpolant(Collection formulasOfA, InterpolationOption option) - throws SolverException, InterruptedException { - if (option == InterpolationOption.NATIVE) { - return getInterpolant(formulasOfA); - } - throw new UnsupportedOperationException("Interpolation option " + option + " not supported"); - } +// default BooleanFormula getInterpolant(Collection formulasOfA, InterpolationOption option) +// throws SolverException, InterruptedException { +// if (option == InterpolationOption.NATIVE) { +// return getInterpolant(formulasOfA); +// } +// throw new UnsupportedOperationException("Interpolation option " + option + " not supported"); +// } /** * This method returns interpolants of an 'inductive sequence'. This property must be supported by diff --git a/src/org/sosy_lab/java_smt/api/SolverContext.java b/src/org/sosy_lab/java_smt/api/SolverContext.java index 3fbd476c77..9ee09e00d1 100644 --- a/src/org/sosy_lab/java_smt/api/SolverContext.java +++ b/src/org/sosy_lab/java_smt/api/SolverContext.java @@ -53,7 +53,10 @@ enum ProverOptions { GENERATE_UNSAT_CORE_OVER_ASSUMPTIONS, /** Whether the solver should enable support for formulae build in SL theory. */ - ENABLE_SEPARATION_LOGIC + ENABLE_SEPARATION_LOGIC, + GENERATE_PROJECTION_BASED_INTERPOLANTS, + GENERATE_UNIFORM_FORWARD_INTERPOLANTS, + GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, } /** @@ -68,7 +71,6 @@ enum ProverOptions { /** * Create a fresh new {@link InterpolatingProverEnvironment} which encapsulates an assertion stack * and allows generating and retrieve interpolants for unsatisfiable formulas. If the SMT solver - * is able to handle satisfiability tests with assumptions please consider implementing the {@link * InterpolatingProverEnvironment} interface, and return an Object of this type here. * * @param options Options specified for the prover environment. All the options specified in diff --git a/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java b/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java index 4e56d2ea9e..41571b44a5 100644 --- a/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java +++ b/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java @@ -119,11 +119,11 @@ protected abstract OptimizationProverEnvironment newOptimizationProverEnvironmen */ protected abstract boolean supportsAssumptionSolving(); - private static final Set ALL_INDEPENDENT_INTERPOLATION_STRATEGIES = + private static final Set ALL_INDEPENDENT_INTERPOLATION_STRATEGIES = ImmutableSet.of( - GENERATE_PROJECTION_BASED_INTERPOLANTS, - GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, - GENERATE_UNIFORM_FORWARD_INTERPOLANTS); + ProverOptions.GENERATE_PROJECTION_BASED_INTERPOLANTS, + ProverOptions.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, + ProverOptions.GENERATE_UNIFORM_FORWARD_INTERPOLANTS); protected boolean useNativeInterpolation(Set options) { return getIndependentInterpolationStrategy(options) == null; diff --git a/src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java b/src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java index 379cea995d..06e76109fe 100644 --- a/src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java +++ b/src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java @@ -18,6 +18,7 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; +import edu.umd.cs.findbugs.annotations.Nullable; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -50,6 +51,8 @@ public class IndependentInterpolatingSolverDelegate extends AbstractProver private final InterpolatingProverEnvironment delegate; + private final @Nullable ProverOptions interpolationStrategy; + private final FormulaManager mgr; private final BooleanFormulaManager bmgr; private final UFManager ufmgr; @@ -67,6 +70,7 @@ protected IndependentInterpolatingSolverDelegate( super(checkNotNull(pOptions)); solverContext = checkNotNull(pSourceContext); delegate = checkNotNull(pDelegate); + interpolationStrategy = pSourceContext.getIndependentInterpolationStrategy(pOptions); mgr = pSourceContext.getFormulaManager(); bmgr = mgr.getBooleanFormulaManager(); ufmgr = mgr.getUFManager(); @@ -78,7 +82,7 @@ protected static String generateTermName() { } @Override - public BooleanFormula getInterpolant(Collection identifiersForA, InterpolationOption option) + public BooleanFormula getInterpolant(Collection identifiersForA) throws SolverException, InterruptedException { Preconditions.checkState(!closed); checkArgument( @@ -107,53 +111,115 @@ public BooleanFormula getInterpolant(Collection identifiersForA, Interpolatio List exclusiveVariablesInB = removeVariablesFrom(variablesInB, sharedVariables); BooleanFormula interpolant; - switch (checkNotNull(option)) { - case NATIVE: - interpolant = getInterpolant(identifiersForA); - break; - case GENERATE_PROJECTION_BASED_INTERPOLANTS: - // Will generate CHC based constraints that are very hard to solve without a CHC solver - if (sharedVariables.isEmpty()) { - return bmgr.makeFalse(); - } - interpolant = - getModelBasedProjectionInterpolant( - conjugatedFormulasOfA, - conjugatedFormulasOfB, - variablesInA, - variablesInB, - sharedVariables); - break; - case GENERATE_UNIFORM_FORWARD_INTERPOLANTS: - // Will generate interpolants based on quantifier elimination - if (exclusiveVariablesInA.isEmpty()) { - return bmgr.makeFalse(); - } - interpolant = getUniformForwardInterpolant(conjugatedFormulasOfA, exclusiveVariablesInA); - break; - case GENERATE_UNIFORM_BACKWARD_INTERPOLANTS: - // Will generate interpolants based on quantifier elimination - if (exclusiveVariablesInB.isEmpty()) { - return bmgr.makeFalse(); - } - // Note: uses the A -> i -> B is valid definition for Craig-Interpolants, so we negate B - interpolant = - getUniformBackwardInterpolant(bmgr.not(conjugatedFormulasOfB), exclusiveVariablesInB); - break; - default: - throw new AssertionError("Unknown interpolation strategy " + option); + if (interpolationStrategy == null) { + interpolant = delegate.getInterpolant(identifiersForA); + } else if (interpolationStrategy.equals(ProverOptions.GENERATE_PROJECTION_BASED_INTERPOLANTS)) { + if (sharedVariables.isEmpty()) { + return bmgr.makeFalse(); + } + interpolant = + getModelBasedProjectionInterpolant( + conjugatedFormulasOfA, + conjugatedFormulasOfB, + variablesInA, + variablesInB, + sharedVariables); + } else if (interpolationStrategy.equals(ProverOptions.GENERATE_UNIFORM_FORWARD_INTERPOLANTS)) { + // Will generate interpolants based on quantifier elimination + if (exclusiveVariablesInA.isEmpty()) { + return bmgr.makeFalse(); + } + interpolant = getUniformForwardInterpolant(conjugatedFormulasOfA, exclusiveVariablesInA); + } else if (interpolationStrategy.equals(ProverOptions.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS)) { + if (exclusiveVariablesInB.isEmpty()) { + return bmgr.makeFalse(); + } + // Note: uses the A -> i -> B is valid definition for Craig-Interpolants, so we negate B + interpolant = + getUniformBackwardInterpolant(conjugatedFormulasOfB, exclusiveVariablesInB); + } else { + throw new AssertionError("Unknown interpolation strategy."); } assert satisfiesInterpolationCriteria( interpolant, conjugatedFormulasOfA, conjugatedFormulasOfB); return interpolant; + +// switch (checkNotNull(option)) { +// case NATIVE: +// interpolant = getInterpolant(identifiersForA); +// break; +// case GENERATE_PROJECTION_BASED_INTERPOLANTS: +// // Will generate CHC based constraints that are very hard to solve without a CHC solver +// if (sharedVariables.isEmpty()) { +// return bmgr.makeFalse(); +// } +// interpolant = +// getModelBasedProjectionInterpolant( +// conjugatedFormulasOfA, +// conjugatedFormulasOfB, +// variablesInA, +// variablesInB, +// sharedVariables); +// break; +// case GENERATE_UNIFORM_FORWARD_INTERPOLANTS: +// // Will generate interpolants based on quantifier elimination +// if (exclusiveVariablesInA.isEmpty()) { +// return bmgr.makeFalse(); +// } +// interpolant = getUniformForwardInterpolant(conjugatedFormulasOfA, exclusiveVariablesInA); +// break; +// case GENERATE_UNIFORM_BACKWARD_INTERPOLANTS: +// // Will generate interpolants based on quantifier elimination +// if (exclusiveVariablesInB.isEmpty()) { +// return bmgr.makeFalse(); +// } +// // Note: uses the A -> i -> B is valid definition for Craig-Interpolants, so we negate B +// interpolant = +// getUniformBackwardInterpolant(bmgr.not(conjugatedFormulasOfB), exclusiveVariablesInB); +// break; +// default: +// throw new AssertionError("Unknown interpolation strategy " + option); +// } +// +// assert satisfiesInterpolationCriteria( +// interpolant, conjugatedFormulasOfA, conjugatedFormulasOfB); +// +// return interpolant; + } + +// @Override +// public BooleanFormula getInterpolant(Collection formulasOfA) +// throws SolverException, InterruptedException { +// return delegate.getInterpolant(formulasOfA); +// } + + + @Override + public List getTreeInterpolants( + List> partitionedFormulas, int[] startOfSubTree) + throws SolverException, InterruptedException { + if (interpolationStrategy == null) { + // Use native solver interpolation + return ((InterpolatingProverEnvironment) delegate) + .getTreeInterpolants(partitionedFormulas, startOfSubTree); + } + throw new UnsupportedOperationException( + "Tree interpolants are not supported for independent interpolation currently."); } + @Override - public BooleanFormula getInterpolant(Collection formulasOfA) + public List getSeqInterpolants(List> pPartitionedFormulas) throws SolverException, InterruptedException { - return delegate.getInterpolant(formulasOfA); + if (interpolationStrategy == null) { + // Use native solver interpolation + return ((InterpolatingProverEnvironment) delegate) + .getSeqInterpolants(pPartitionedFormulas); + } + throw new UnsupportedOperationException( + "Sequential interpolants are not supported for independent interpolation currently."); } /** @@ -217,7 +283,7 @@ private BooleanFormula getUniformBackwardInterpolant( BooleanFormula itpBackwardQuantified = qfmgr.forall(exclusiveVariables, bmgr.not(formulasOfB)); BooleanFormula itpBackward = qfmgr.eliminateQuantifiers(itpBackwardQuantified); // Check that the top-level quantifier has been eliminated - if (isQuantifiedFormula(itpBackwardQuantified)) { + if (isQuantifiedFormula(itpBackward)) { throw new SolverException( "Error when calculating uniform interpolant, quantifier elimination failed."); } @@ -342,14 +408,6 @@ private List removeVariablesFrom( return builder.build(); } - @Override - public List getTreeInterpolants( - List> partitionedFormulas, int[] startOfSubTree) - throws SolverException, InterruptedException { - throw new UnsupportedOperationException( - "Tree interpolants are currently not supported using " + "independent interpolation"); - } - @Override protected void popImpl() { delegate.pop(); diff --git a/src/org/sosy_lab/java_smt/example/IndependentInterpolation.java b/src/org/sosy_lab/java_smt/example/IndependentInterpolation.java new file mode 100644 index 0000000000..9be329d8b2 --- /dev/null +++ b/src/org/sosy_lab/java_smt/example/IndependentInterpolation.java @@ -0,0 +1,170 @@ +/* + * This file is part of JavaSMT, + * an API wrapper for a collection of SMT solvers: + * https://github.com/sosy-lab/java-smt + * + * SPDX-FileCopyrightText: 2024 Dirk Beyer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.sosy_lab.java_smt.example; + +import static org.sosy_lab.java_smt.test.ProverEnvironmentSubject.assertThat; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import java.util.List; +import java.util.logging.Level; +import org.sosy_lab.common.ShutdownNotifier; +import org.sosy_lab.common.configuration.Configuration; +import org.sosy_lab.common.configuration.InvalidConfigurationException; +import org.sosy_lab.common.log.BasicLogManager; +import org.sosy_lab.common.log.LogManager; +import org.sosy_lab.java_smt.SolverContextFactory; +import org.sosy_lab.java_smt.SolverContextFactory.Solvers; +import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.BooleanFormulaManager; +import org.sosy_lab.java_smt.api.IntegerFormulaManager; +import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment; +import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula; +import org.sosy_lab.java_smt.api.SolverContext; +import org.sosy_lab.java_smt.api.SolverContext.ProverOptions; +import org.sosy_lab.java_smt.api.SolverException; + +public class IndependentInterpolation { + + public static void main(String[] args) + throws InvalidConfigurationException, SolverException, InterruptedException { + + Configuration config = Configuration.defaultConfiguration(); + LogManager logger = BasicLogManager.create(config); + ShutdownNotifier notifier = ShutdownNotifier.createDummy(); + + Solvers solver = Solvers.Z3; + + try (SolverContext context = + SolverContextFactory.createSolverContext(config, logger, notifier, solver); + InterpolatingProverEnvironment prover = + context.newProverEnvironmentWithInterpolation(ProverOptions.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS)) { + logger.log(Level.WARNING, "Using solver " + solver + " in version " + context.getVersion()); + + BooleanFormulaManager bmgr = context.getFormulaManager().getBooleanFormulaManager(); + IntegerFormulaManager imgr = context.getFormulaManager().getIntegerFormulaManager(); + + // example + prover.push(); + interpolateExample(prover, bmgr, imgr, logger); + prover.pop(); + + } catch (InvalidConfigurationException | UnsatisfiedLinkError e) { + + // on some machines we support only some solvers, + // thus we can ignore these errors. + logger.logUserException(Level.INFO, e, "Solver " + solver + " is not available."); + + } catch (UnsupportedOperationException e) { + logger.logUserException(Level.INFO, e, e.getMessage()); + } + } + + private static void interpolateExample( + InterpolatingProverEnvironment prover, + BooleanFormulaManager bmgr, + IntegerFormulaManager imgr, + LogManager logger) + throws InterruptedException, SolverException { + + // A: x = 1 && x = y + // B: y = z && z = 2 + // -> y = 1, y != 2 + + + // create some variables + IntegerFormula x = imgr.makeVariable("x"); + IntegerFormula y = imgr.makeVariable("y"); + IntegerFormula z = imgr.makeVariable("z"); + IntegerFormula one = imgr.makeNumber(1); + IntegerFormula two = imgr.makeNumber(2); + + // create and assert some formulas + // instead of 'named' formulas, we return a 'handle' (of generic type T) + + T ip0 = + prover.push( + bmgr.and( + imgr.equal(y, z), imgr.equal(z, two) + )); + T ip1 = prover.push(bmgr.and(imgr.equal(x, one), imgr.equal(y, x))); + + + // check for satisfiability + boolean unsat = prover.isUnsat(); + Preconditions.checkState(unsat, "The example for interpolation should be UNSAT"); + + BooleanFormula itp = prover.getInterpolant(ImmutableList.of(ip1)); + logger.log(Level.INFO, "Interpolants are:", itp); + } + + private static void interpolateExample2( + InterpolatingProverEnvironment prover, + BooleanFormulaManager bmgr, + IntegerFormulaManager imgr, + LogManager logger) + throws InterruptedException, SolverException { + + // A: x > 0 && y = x + 1 + // B: y < 0 + // -> y > 0 + + // create some variables + IntegerFormula x = imgr.makeVariable("x"); + IntegerFormula y = imgr.makeVariable("y"); + IntegerFormula one = imgr.makeNumber(1); + IntegerFormula zero = imgr.makeNumber(0); + + T ip0 = + prover.push(imgr.lessThan(y, zero)); + T ip1 = prover.push(bmgr.and(imgr.greaterThan(x, zero), imgr.equal(y, imgr.add(x, one)))); + + + // check for satisfiability + boolean unsat = prover.isUnsat(); + Preconditions.checkState(unsat, "The example for interpolation should be UNSAT"); + + BooleanFormula itp = prover.getInterpolant(ImmutableList.of(ip1)); + logger.log(Level.INFO, "Interpolants are:", itp); + } + + private static void interpolateExample3( + InterpolatingProverEnvironment prover, + BooleanFormulaManager bmgr, + IntegerFormulaManager imgr, + LogManager logger) + throws InterruptedException, SolverException { + + IntegerFormula zero = imgr.makeNumber(0); + IntegerFormula one = imgr.makeNumber(1); + IntegerFormula thousand = imgr.makeNumber(1000); + + IntegerFormula i3 = imgr.makeVariable("i3"); + IntegerFormula i4 = imgr.makeVariable("i4"); + + BooleanFormula A = imgr.equal(i3, zero); + BooleanFormula B = bmgr.and(imgr.lessThan(i3, thousand), imgr.equal(i4, imgr.add(i3, one))); + BooleanFormula C = imgr.greaterThan(i4, thousand); + + T TA = prover.push(A); + T TB = prover.push(B); + T TC = prover.push(C); + + assertThat(prover).isUnsatisfiable(); + + List itpSeq = prover.getSeqInterpolants0(ImmutableList.of(TA, TB, TC)); + + BooleanFormula itp1 = prover.getInterpolant(ImmutableList.of(TA)); + BooleanFormula itp2 = prover.getInterpolant(ImmutableList.of(TA, TB)); + } +} + + diff --git a/src/org/sosy_lab/java_smt/test/InterpolatingProverTest.java b/src/org/sosy_lab/java_smt/test/InterpolatingProverTest.java index 9287b00f67..45cf640269 100644 --- a/src/org/sosy_lab/java_smt/test/InterpolatingProverTest.java +++ b/src/org/sosy_lab/java_smt/test/InterpolatingProverTest.java @@ -28,13 +28,14 @@ import org.sosy_lab.java_smt.api.BooleanFormula; import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment; import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula; +import org.sosy_lab.java_smt.api.SolverContext.ProverOptions; import org.sosy_lab.java_smt.api.SolverException; import org.sosy_lab.java_smt.solvers.cvc5.CVC5BooleanFormulaManager; import org.sosy_lab.java_smt.solvers.opensmt.Logics; /** This class contains some simple Junit-tests to check the interpolation-API of our solvers. */ @SuppressWarnings({"resource", "LocalVariableName"}) -public class InterpolatingProverTest extends SolverBasedTest0.ParameterizedSolverBasedTest0 { +public class InterpolatingProverTest extends SolverBasedTest0.ParameterizedInterpolatingSolverBasedTest0 { // INFO: OpenSmt only support interpolation for QF_LIA, QF_LRA and QF_UF @Override @@ -46,7 +47,12 @@ protected Logics logicToUse() { @SuppressWarnings("unchecked") private InterpolatingProverEnvironment newEnvironmentForTest() { requireInterpolation(); - return (InterpolatingProverEnvironment) context.newProverEnvironmentWithInterpolation(); + ProverOptions itpStrat = itpStrategyToUse(); + if (itpStrat == null) { + return (InterpolatingProverEnvironment) context.newProverEnvironmentWithInterpolation(); + } else { + return (InterpolatingProverEnvironment) context.newProverEnvironmentWithInterpolation(itpStrat); + } } private static final UniqueIdGenerator index = new UniqueIdGenerator(); // to get different names diff --git a/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java b/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java index fe2d8dcbc2..2e97ad9ee2 100644 --- a/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java +++ b/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java @@ -24,6 +24,7 @@ import com.google.common.truth.Truth; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Set; @@ -345,7 +346,11 @@ protected final void requireOptimization() { protected final void requireInterpolation(ProverOptions... options) { try { - context.newProverEnvironmentWithInterpolation(options).close(); + if (Arrays.stream(options).anyMatch(p -> p == null)) { + context.newProverEnvironmentWithInterpolation().close(); + } else { + context.newProverEnvironmentWithInterpolation(options).close(); + } } catch (UnsupportedOperationException e) { assume() .withMessage("Solver %s does not support interpolation", solverToUse()) @@ -561,28 +566,36 @@ public abstract static class ParameterizedInterpolatingSolverBasedTest0 extends ParameterizedSolverBasedTest0 { // GENERATE_MODELS as stand-in for native - private static final Set ALL_INTERPOLATION_STRATEGIES = + private static final Set ALL_INTERPOLATION_STRATEGIES = ImmutableSet.of( - NATIVE, - GENERATE_PROJECTION_BASED_INTERPOLANTS, - GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, - GENERATE_UNIFORM_FORWARD_INTERPOLANTS); + ProverOptions.GENERATE_PROJECTION_BASED_INTERPOLANTS, + ProverOptions.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, + ProverOptions.GENERATE_UNIFORM_FORWARD_INTERPOLANTS); @Parameters(name = "solver {0} with interpolation strategy {1}") public static List getAllSolversAndItpStrategies() { List lst = new ArrayList<>(); for (Solvers solver : Solvers.values()) { // No arg for no option (== solver native interpolation) - for (InterpolationOption itpStrat : ALL_INTERPOLATION_STRATEGIES) { + lst.add(new Object[] {solver, null}); + for (ProverOptions itpStrat : ALL_INTERPOLATION_STRATEGIES) { lst.add(new Object[] {solver, itpStrat}); } } return lst; } + @Parameter(0) + public Solvers solver; + @Parameter(1) public ProverOptions interpolationStrategy; + @Override + protected Solvers solverToUse() { + return solver; + } + protected ProverOptions itpStrategyToUse() { return interpolationStrategy; } From d78e284e3cf274899ef153074a4404ab46db4935 Mon Sep 17 00:00:00 2001 From: Julius Brehme Date: Sat, 13 Dec 2025 10:51:31 +0100 Subject: [PATCH 10/20] added requirements for tests --- .../test/InterpolatingProverTest.java | 50 +++++----- .../java_smt/test/SolverBasedTest0.java | 98 +++++++++++++------ 2 files changed, 94 insertions(+), 54 deletions(-) diff --git a/src/org/sosy_lab/java_smt/test/InterpolatingProverTest.java b/src/org/sosy_lab/java_smt/test/InterpolatingProverTest.java index 45cf640269..a4c3adf14d 100644 --- a/src/org/sosy_lab/java_smt/test/InterpolatingProverTest.java +++ b/src/org/sosy_lab/java_smt/test/InterpolatingProverTest.java @@ -46,7 +46,7 @@ protected Logics logicToUse() { /** Generate a prover environment depending on the parameter above. */ @SuppressWarnings("unchecked") private InterpolatingProverEnvironment newEnvironmentForTest() { - requireInterpolation(); + requireInterpolation(itpStrategyToUse()); ProverOptions itpStrat = itpStrategyToUse(); if (itpStrat == null) { return (InterpolatingProverEnvironment) context.newProverEnvironmentWithInterpolation(); @@ -250,16 +250,9 @@ public void binaryBVInterpolation1() throws SolverException, InterruptedExce checkItpSequence(ImmutableList.of(D, C, B, A), ImmutableList.of(itpD, itpDC, itpDCB)); } - private void requireTreeItp() { - requireInterpolation(); - assume() - .withMessage("Solver does not support tree-interpolation.") - .that(solver) - .isAnyOf(Solvers.SMTINTERPOL, Solvers.PRINCESS); - } - @Test public void sequentialInterpolation() throws SolverException, InterruptedException { + requireSeqItp(itpStrategyToUse()); InterpolatingProverEnvironment stack = newEnvironmentForTest(); requireIntegers(); @@ -312,6 +305,7 @@ public void sequentialInterpolation() throws SolverException, InterruptedExc public void sequentialInterpolationIsNotRepeatedIndividualInterpolation() throws SolverException, InterruptedException { InterpolatingProverEnvironment stack = newEnvironmentForTest(); + requireSeqItp(itpStrategyToUse()); requireIntegers(); IntegerFormula zero = imgr.makeNumber(0); @@ -347,6 +341,7 @@ public void sequentialInterpolationIsNotRepeatedIndividualInterpolation() public void sequentialInterpolationWithoutPartition() throws SolverException, InterruptedException { requireIntegers(); + requireSeqItp(itpStrategyToUse()); InterpolatingProverEnvironment stack = newEnvironmentForTest(); stack.push(imgr.equal(imgr.makeNumber(0), imgr.makeNumber(1))); @@ -361,6 +356,7 @@ public void sequentialInterpolationWithoutPartition() public void sequentialInterpolationWithOnePartition() throws SolverException, InterruptedException { requireIntegers(); + requireSeqItp(itpStrategyToUse()); InterpolatingProverEnvironment stack = newEnvironmentForTest(); int i = index.getFreshId(); @@ -389,6 +385,7 @@ public void sequentialInterpolationWithOnePartition() public void sequentialInterpolationWithFewPartitions() throws SolverException, InterruptedException { requireIntegers(); + requireSeqItp(itpStrategyToUse()); InterpolatingProverEnvironment stack = newEnvironmentForTest(); int i = index.getFreshId(); @@ -421,6 +418,7 @@ public void sequentialInterpolationWithFewPartitions() @Test public void sequentialBVInterpolation() throws SolverException, InterruptedException { requireBitvectors(); + requireSeqItp(itpStrategyToUse()); InterpolatingProverEnvironment stack = newEnvironmentForTest(); @@ -470,7 +468,7 @@ public void sequentialBVInterpolation() throws SolverException, InterruptedE @Test public void treeInterpolation() throws SolverException, InterruptedException { - requireTreeItp(); + requireTreeItp(itpStrategyToUse()); int i = index.getFreshId(); @@ -640,7 +638,7 @@ private void testTreeInterpolants2( @Test public void treeInterpolation2() throws SolverException, InterruptedException { - requireTreeItp(); + requireTreeItp(itpStrategyToUse()); InterpolatingProverEnvironment stack = newEnvironmentForTest(); @@ -699,7 +697,7 @@ public void treeInterpolation2() throws SolverException, InterruptedExceptio @Test public void treeInterpolation3() throws SolverException, InterruptedException { - requireTreeItp(); + requireTreeItp(itpStrategyToUse()); InterpolatingProverEnvironment stack = newEnvironmentForTest(); @@ -755,7 +753,7 @@ public void treeInterpolation3() throws SolverException, InterruptedExceptio @Test public void treeInterpolation4() throws SolverException, InterruptedException { - requireTreeItp(); + requireTreeItp(itpStrategyToUse()); InterpolatingProverEnvironment stack = newEnvironmentForTest(); @@ -802,7 +800,7 @@ public void treeInterpolation4() throws SolverException, InterruptedExceptio @Test public void treeInterpolationForSequence() throws SolverException, InterruptedException { - requireTreeItp(); + requireTreeItp(itpStrategyToUse()); InterpolatingProverEnvironment stack = newEnvironmentForTest(); @@ -827,7 +825,7 @@ public void treeInterpolationForSequence() throws SolverException, Interrupt @Test public void treeInterpolationBranching() throws SolverException, InterruptedException { - requireTreeItp(); + requireTreeItp(itpStrategyToUse()); InterpolatingProverEnvironment stack = newEnvironmentForTest(); @@ -868,7 +866,7 @@ public void treeInterpolationBranching() throws SolverException, Interrupted @SuppressWarnings({"unchecked", "varargs"}) public void treeInterpolationMalFormed1() throws SolverException, InterruptedException { - requireTreeItp(); + requireTreeItp(itpStrategyToUse()); InterpolatingProverEnvironment stack = newEnvironmentForTest(); BooleanFormula A = imgr.equal(imgr.makeNumber(0), imgr.makeNumber(1)); @@ -884,7 +882,7 @@ public void treeInterpolationMalFormed1() throws SolverException, Interrupte @SuppressWarnings({"unchecked", "varargs"}) public void treeInterpolationMalFormed2() throws SolverException, InterruptedException { - requireTreeItp(); + requireTreeItp(itpStrategyToUse()); InterpolatingProverEnvironment stack = newEnvironmentForTest(); BooleanFormula A = imgr.equal(imgr.makeNumber(0), imgr.makeNumber(1)); @@ -900,7 +898,7 @@ public void treeInterpolationMalFormed2() throws SolverException, Interrupte @SuppressWarnings({"unchecked", "varargs"}) public void treeInterpolationMalFormed3() throws SolverException, InterruptedException { - requireTreeItp(); + requireTreeItp(itpStrategyToUse()); InterpolatingProverEnvironment stack = newEnvironmentForTest(); BooleanFormula A = imgr.equal(imgr.makeNumber(0), imgr.makeNumber(1)); @@ -915,7 +913,7 @@ public void treeInterpolationMalFormed3() throws SolverException, Interrupte @Test public void treeInterpolationMalFormed4() throws SolverException, InterruptedException { - requireTreeItp(); + requireTreeItp(itpStrategyToUse()); InterpolatingProverEnvironment stack = newEnvironmentForTest(); BooleanFormula A = imgr.equal(imgr.makeNumber(0), imgr.makeNumber(1)); @@ -930,7 +928,7 @@ public void treeInterpolationMalFormed4() throws SolverException, Interrupte @Test public void treeInterpolationMalFormed5() throws SolverException, InterruptedException { - requireTreeItp(); + requireTreeItp(itpStrategyToUse()); InterpolatingProverEnvironment stack = newEnvironmentForTest(); BooleanFormula A = imgr.equal(imgr.makeNumber(0), imgr.makeNumber(1)); @@ -945,7 +943,7 @@ public void treeInterpolationMalFormed5() throws SolverException, Interrupte @Test public void treeInterpolationMalFormed6() throws SolverException, InterruptedException { - requireTreeItp(); + requireTreeItp(itpStrategyToUse()); InterpolatingProverEnvironment stack = newEnvironmentForTest(); BooleanFormula A = imgr.equal(imgr.makeNumber(0), imgr.makeNumber(1)); @@ -959,7 +957,7 @@ public void treeInterpolationMalFormed6() throws SolverException, Interrupte @Test public void treeInterpolationWithoutPartition() throws SolverException, InterruptedException { - requireTreeItp(); + requireTreeItp(itpStrategyToUse()); InterpolatingProverEnvironment stack = newEnvironmentForTest(); @@ -974,8 +972,7 @@ public void treeInterpolationWithoutPartition() throws SolverException, Inte @Test public void treeInterpolationWithOnePartition() throws SolverException, InterruptedException { - requireTreeItp(); - + requireTreeItp(itpStrategyToUse()); InterpolatingProverEnvironment stack = newEnvironmentForTest(); int i = index.getFreshId(); @@ -1005,6 +1002,7 @@ public void treeInterpolationWithOnePartition() throws SolverException, Inte public void bigSeqInterpolationTest() throws InterruptedException, SolverException { requireBitvectors(); requireInterpolation(); + requireSeqItp(itpStrategyToUse()); assume() .withMessage("Solver %s runs into timeout on this test", solverToUse()) @@ -1074,7 +1072,6 @@ public void bigSeqInterpolationTest() throws InterruptedException, SolverExc @Test public void testTrivialInterpolation() throws InterruptedException, SolverException { - requireInterpolation(); InterpolatingProverEnvironment stack = newEnvironmentForTest(); IntegerFormula zero = imgr.makeNumber(0); IntegerFormula one = imgr.makeNumber(1); @@ -1121,7 +1118,6 @@ private void checkItpSequence(List formulas, List void testInvalidToken() throws InterruptedException, SolverException { - requireInterpolation(); InterpolatingProverEnvironment stack = newEnvironmentForTest(); // create and push formulas and solve them @@ -1171,6 +1167,7 @@ public void testInvalidToken() throws InterruptedException, SolverException */ @Test public void issue381InterpolationTest1() throws InterruptedException, SolverException { + requireSeqItp(itpStrategyToUse()); try (InterpolatingProverEnvironment prover = newEnvironmentForTest()) { var x = imgr.makeVariable("x"); var one = imgr.makeNumber(1); @@ -1197,6 +1194,7 @@ public void issue381InterpolationTest1() throws InterruptedException, Solver */ @Test public void issue381InterpolationTest2() throws InterruptedException, SolverException { + requireSeqItp(itpStrategyToUse()); try (InterpolatingProverEnvironment prover = newEnvironmentForTest()) { var x = imgr.makeVariable("x"); var one = imgr.makeNumber(1); diff --git a/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java b/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java index 2e97ad9ee2..5733184f73 100644 --- a/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java +++ b/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java @@ -10,11 +10,10 @@ import static com.google.common.base.Preconditions.checkState; import static com.google.common.truth.TruthJUnit.assume; -import static org.sosy_lab.java_smt.api.InterpolatingProverEnvironment.InterpolationOption.GENERATE_PROJECTION_BASED_INTERPOLANTS; -import static org.sosy_lab.java_smt.api.InterpolatingProverEnvironment.InterpolationOption.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS; -import static org.sosy_lab.java_smt.api.InterpolatingProverEnvironment.InterpolationOption.GENERATE_UNIFORM_FORWARD_INTERPOLANTS; -import static org.sosy_lab.java_smt.api.InterpolatingProverEnvironment.InterpolationOption.NATIVE; import static org.sosy_lab.java_smt.api.FormulaType.getSinglePrecisionFloatingPointType; +import static org.sosy_lab.java_smt.api.SolverContext.ProverOptions.GENERATE_PROJECTION_BASED_INTERPOLANTS; +import static org.sosy_lab.java_smt.api.SolverContext.ProverOptions.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS; +import static org.sosy_lab.java_smt.api.SolverContext.ProverOptions.GENERATE_UNIFORM_FORWARD_INTERPOLANTS; import static org.sosy_lab.java_smt.test.BooleanFormulaSubject.assertUsing; import static org.sosy_lab.java_smt.test.ProverEnvironmentSubject.assertThat; @@ -22,12 +21,13 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import com.google.common.truth.Truth; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; import org.checkerframework.checker.nullness.qual.Nullable; import org.junit.After; import org.junit.Before; @@ -92,7 +92,7 @@ * } * * - * + *

* {@link #assertThatFormula(BooleanFormula)} can be used to easily write assertions about formulas * using Truth. * @@ -132,7 +132,9 @@ protected Solvers solverToUse() { return Solvers.SMTINTERPOL; } - /** This method is only called, if OpenSMT is called. OpenSMT needs to know the logic upfront. */ + /** + * This method is only called, if OpenSMT is called. OpenSMT needs to know the logic upfront. + */ protected Logics logicToUse() { return Logics.QF_AUFLIRA; } @@ -146,6 +148,12 @@ protected ConfigurationBuilder createTestConfigBuilder() { return newConfig; } + private static final ImmutableList INDEPENDENT_INTERPOLATION_STRATEGIES = + ImmutableList.of( + GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, + GENERATE_PROJECTION_BASED_INTERPOLANTS, + GENERATE_UNIFORM_FORWARD_INTERPOLANTS); + @Before public final void initSolver() throws InvalidConfigurationException { config = createTestConfigBuilder().build(); @@ -220,7 +228,9 @@ public final void closeSolver() { } } - /** Skip test if the solver does not support integers. */ + /** + * Skip test if the solver does not support integers. + */ protected final void requireIntegers() { assume() .withMessage("Solver %s does not support the theory of integers", solverToUse()) @@ -228,7 +238,9 @@ protected final void requireIntegers() { .isNotNull(); } - /** Skip test if the solver does not support rationals. */ + /** + * Skip test if the solver does not support rationals. + */ protected final void requireRationals() { assume() .withMessage("Solver %s does not support the theory of rationals", solverToUse()) @@ -243,7 +255,9 @@ protected final void requireRationalFloor() { .isNotEqualTo(Solvers.OPENSMT); } - /** Skip test if the solver does not support bitvectors. */ + /** + * Skip test if the solver does not support bitvectors. + */ protected final void requireBitvectors() { assume() .withMessage("Solver %s does not support the theory of bitvectors", solverToUse()) @@ -273,7 +287,9 @@ protected final void requireFPToBitvector() { } } - /** Skip test if the solver does not support quantifiers. */ + /** + * Skip test if the solver does not support quantifiers. + */ protected final void requireQuantifiers() { assume() .withMessage("Solver %s does not support quantifiers", solverToUse()) @@ -290,7 +306,9 @@ protected final void requireQuantifierElimination() { .isNoneOf(Solvers.BOOLECTOR, Solvers.MATHSAT5, Solvers.YICES2, Solvers.BITWUZLA); } - /** Skip test if the solver does not support arrays. */ + /** + * Skip test if the solver does not support arrays. + */ protected final void requireArrays() { assume() .withMessage("Solver %s does not support the theory of arrays", solverToUse()) @@ -305,7 +323,9 @@ protected final void requireFloats() { .isNotNull(); } - /** Skip test if the solver does not support strings. */ + /** + * Skip test if the solver does not support strings. + */ protected final void requireStrings() { assume() .withMessage("Solver %s does not support the theory of strings", solverToUse()) @@ -317,7 +337,9 @@ protected final void requireStrings() { .isNotNull(); } - /** Skip test if the solver does not support enumeration theory. */ + /** + * Skip test if the solver does not support enumeration theory. + */ protected final void requireEnumeration() { assume() .withMessage("Solver %s does not support the theory of enumerations", solverToUse()) @@ -332,7 +354,9 @@ protected final void requireSeparationLogic() { .isNotNull(); } - /** Skip test if the solver does not support optimization. */ + /** + * Skip test if the solver does not support optimization. + */ protected final void requireOptimization() { try { context.newOptimizationProverEnvironment().close(); @@ -359,19 +383,33 @@ protected final void requireInterpolation(ProverOptions... options) { } } - protected final void requireSeqItp(InterpolationOption... options) { + protected final void requireSeqItp(ProverOptions... options) { assume() .withMessage( "Solver independent interpolation strategy %s does not support sequential " - + "or tree interpolation", + + "interpolation", solverToUse()) .that(options) .asList() .containsNoneIn( - ImmutableList.of( - GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, - GENERATE_PROJECTION_BASED_INTERPOLANTS, - GENERATE_UNIFORM_FORWARD_INTERPOLANTS)); + INDEPENDENT_INTERPOLATION_STRATEGIES); + } + + protected final void requireTreeItp(ProverOptions... options) { + requireInterpolation(); + var test = Arrays.asList(options); + assume() + .withMessage("Solver does not support tree-interpolation.") + .that(solverToUse()) + .isAnyOf(Solvers.SMTINTERPOL, Solvers.PRINCESS); + + assume() + .withMessage( + "Strategy %s does not support tree interpolation", + Arrays.toString(options)) // Optional: print the options for clarity + .that(options) + .asList() + .contains(INDEPENDENT_INTERPOLATION_STRATEGIES); } protected void requireParser() { @@ -438,14 +476,18 @@ protected final BooleanFormulaSubject assertThatFormula(BooleanFormula formula) return assertUsing(context).that(formula); } - /** Check that the interpolant in the subject is valid fot the formulas A and B. */ + /** + * Check that the interpolant in the subject is valid fot the formulas A and B. + */ public void isValidInterpolant(BooleanFormula interpolant, BooleanFormula a, BooleanFormula b) throws SolverException, InterruptedException { // TODO: move into assertion framework isValidInterpolant(interpolant, ImmutableList.of(a), ImmutableList.of(b)); } - /** Check that the interpolant in the subject is valid fot the formulas A and B. */ + /** + * Check that the interpolant in the subject is valid fot the formulas A and B. + */ public void isValidInterpolant( BooleanFormula interpolant, List formulasOfA, @@ -568,18 +610,18 @@ public abstract static class ParameterizedInterpolatingSolverBasedTest0 // GENERATE_MODELS as stand-in for native private static final Set ALL_INTERPOLATION_STRATEGIES = ImmutableSet.of( - ProverOptions.GENERATE_PROJECTION_BASED_INTERPOLANTS, - ProverOptions.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, - ProverOptions.GENERATE_UNIFORM_FORWARD_INTERPOLANTS); + GENERATE_PROJECTION_BASED_INTERPOLANTS, + GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, + GENERATE_UNIFORM_FORWARD_INTERPOLANTS); @Parameters(name = "solver {0} with interpolation strategy {1}") public static List getAllSolversAndItpStrategies() { List lst = new ArrayList<>(); for (Solvers solver : Solvers.values()) { // No arg for no option (== solver native interpolation) - lst.add(new Object[] {solver, null}); + lst.add(new Object[]{solver, null}); for (ProverOptions itpStrat : ALL_INTERPOLATION_STRATEGIES) { - lst.add(new Object[] {solver, itpStrat}); + lst.add(new Object[]{solver, itpStrat}); } } return lst; From 23ae59a7ce18de7cfdd81b1c9cc9bb9779bcdc2f Mon Sep 17 00:00:00 2001 From: Julius Brehme Date: Sat, 13 Dec 2025 10:52:35 +0100 Subject: [PATCH 11/20] small fixes for independent interpolation --- ...ndependentInterpolatingSolverDelegate.java | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java b/src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java index 06e76109fe..a53fe796ec 100644 --- a/src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java +++ b/src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java @@ -32,6 +32,7 @@ import org.sosy_lab.java_smt.api.BooleanFormulaManager; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaManager; +import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment; import org.sosy_lab.java_smt.api.Model; import org.sosy_lab.java_smt.api.ProverEnvironment; @@ -111,12 +112,18 @@ public BooleanFormula getInterpolant(Collection identifiersForA) List exclusiveVariablesInB = removeVariablesFrom(variablesInB, sharedVariables); BooleanFormula interpolant; + + if (bmgr.isFalse(conjugatedFormulasOfA)) { + return bmgr.makeFalse(); + } else if (bmgr.isFalse(conjugatedFormulasOfB)) { + return bmgr.makeTrue(); + } else if (sharedVariables.isEmpty()) { + return bmgr.makeFalse(); + } + if (interpolationStrategy == null) { interpolant = delegate.getInterpolant(identifiersForA); } else if (interpolationStrategy.equals(ProverOptions.GENERATE_PROJECTION_BASED_INTERPOLANTS)) { - if (sharedVariables.isEmpty()) { - return bmgr.makeFalse(); - } interpolant = getModelBasedProjectionInterpolant( conjugatedFormulasOfA, @@ -127,12 +134,12 @@ public BooleanFormula getInterpolant(Collection identifiersForA) } else if (interpolationStrategy.equals(ProverOptions.GENERATE_UNIFORM_FORWARD_INTERPOLANTS)) { // Will generate interpolants based on quantifier elimination if (exclusiveVariablesInA.isEmpty()) { - return bmgr.makeFalse(); + return bmgr.makeTrue(); } interpolant = getUniformForwardInterpolant(conjugatedFormulasOfA, exclusiveVariablesInA); } else if (interpolationStrategy.equals(ProverOptions.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS)) { if (exclusiveVariablesInB.isEmpty()) { - return bmgr.makeFalse(); + return bmgr.makeTrue(); } // Note: uses the A -> i -> B is valid definition for Craig-Interpolants, so we negate B interpolant = @@ -354,7 +361,8 @@ private BooleanFormula getModelBasedProjectionInterpolant( BooleanFormula itp = ufmgr.declareAndCallUF( - "__itp_internal_javasmt_" + termIdGenerator.getFreshId(), BooleanType, sharedVars); + "__itp_internal_javasmt_" + termIdGenerator.getFreshId(), FormulaType.BooleanType, + sharedVars); BooleanFormula left = qfmgr.forall(variablesInA, bmgr.implication(conjugatedFormulasOfA, itp)); BooleanFormula right = qfmgr.forall(variablesInB, bmgr.implication(itp, bmgr.not(conjugatedFormulasOfB))); From 2404f5c813277a86666dde00a8d90f9b54ebe490 Mon Sep 17 00:00:00 2001 From: Julius Brehme Date: Sun, 14 Dec 2025 19:12:32 +0100 Subject: [PATCH 12/20] update independent interpolation logic and tests --- ...ndependentInterpolatingSolverDelegate.java | 52 +++-- .../test/InterpolatingProverTest.java | 90 ++++++--- .../java_smt/test/SolverBasedTest0.java | 191 ++++++------------ 3 files changed, 156 insertions(+), 177 deletions(-) diff --git a/src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java b/src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java index a53fe796ec..046c9cb181 100644 --- a/src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java +++ b/src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java @@ -13,7 +13,6 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; -import static org.sosy_lab.java_smt.api.FormulaType.BooleanType; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; @@ -104,7 +103,6 @@ public BooleanFormula getInterpolant(Collection identifiersForA) BooleanFormula conjugatedFormulasOfA = bmgr.and(formulasOfA); BooleanFormula conjugatedFormulasOfB = bmgr.and(formulasOfB); - List variablesInA = getAllVariables(conjugatedFormulasOfA); List variablesInB = getAllVariables(conjugatedFormulasOfB); List sharedVariables = getCommonFormulas(variablesInA, variablesInB); @@ -115,14 +113,14 @@ public BooleanFormula getInterpolant(Collection identifiersForA) if (bmgr.isFalse(conjugatedFormulasOfA)) { return bmgr.makeFalse(); - } else if (bmgr.isFalse(conjugatedFormulasOfB)) { + } else if (bmgr.isFalse(conjugatedFormulasOfB)) { return bmgr.makeTrue(); - } else if (sharedVariables.isEmpty()) { - return bmgr.makeFalse(); } + if (interpolationStrategy == null) { interpolant = delegate.getInterpolant(identifiersForA); + } else if (interpolationStrategy.equals(ProverOptions.GENERATE_PROJECTION_BASED_INTERPOLANTS)) { interpolant = getModelBasedProjectionInterpolant( @@ -134,12 +132,12 @@ public BooleanFormula getInterpolant(Collection identifiersForA) } else if (interpolationStrategy.equals(ProverOptions.GENERATE_UNIFORM_FORWARD_INTERPOLANTS)) { // Will generate interpolants based on quantifier elimination if (exclusiveVariablesInA.isEmpty()) { - return bmgr.makeTrue(); + return conjugatedFormulasOfA; } interpolant = getUniformForwardInterpolant(conjugatedFormulasOfA, exclusiveVariablesInA); } else if (interpolationStrategy.equals(ProverOptions.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS)) { if (exclusiveVariablesInB.isEmpty()) { - return bmgr.makeTrue(); + return bmgr.not(conjugatedFormulasOfB); } // Note: uses the A -> i -> B is valid definition for Craig-Interpolants, so we negate B interpolant = @@ -281,7 +279,9 @@ private boolean satisfiesInterpolationCriteria( return true; } - /** interpolate(A(x,y),B(y,z))=∀z.¬B(y,z) */ + /** + * interpolate(A(x,y),B(y,z))=∀z.¬B(y,z) + */ private BooleanFormula getUniformBackwardInterpolant( BooleanFormula formulasOfB, List exclusiveVariables) throws SolverException, InterruptedException { @@ -295,10 +295,12 @@ private BooleanFormula getUniformBackwardInterpolant( "Error when calculating uniform interpolant, quantifier elimination failed."); } - return itpBackward; + return mgr.simplify(itpBackward); } - /** Checks the formula for a quantifier at an arbitrary position/depth. */ + /** + * Checks the formula for a quantifier at an arbitrary position/depth. + */ private boolean isQuantifiedFormula(BooleanFormula maybeQuantifiedFormula) { final AtomicBoolean isQuantified = new AtomicBoolean(false); mgr.visitRecursively( @@ -330,7 +332,7 @@ public TraversalProcess visitQuantifier( *

Forward means, that the set of formulas A interpolates towards the set of formulas B. * * @param conjugatedFormulasOfA The set of formulas A, combined into one {@link BooleanFormula}. - * @param exclusiveVariables A list of shared variables found in both sets of formulas A and B. + * @param exclusiveVariables A list of shared variables found in both sets of formulas A and B. * @return a uniform Craig interpolant or an exception is thrown. */ private BooleanFormula getUniformForwardInterpolant( @@ -346,7 +348,7 @@ private BooleanFormula getUniformForwardInterpolant( "Error when calculating uniform interpolant, quantifier elimination failed."); } - return itpForward; + return mgr.simplify(itpForward); } private BooleanFormula getModelBasedProjectionInterpolant( @@ -363,9 +365,23 @@ private BooleanFormula getModelBasedProjectionInterpolant( ufmgr.declareAndCallUF( "__itp_internal_javasmt_" + termIdGenerator.getFreshId(), FormulaType.BooleanType, sharedVars); - BooleanFormula left = qfmgr.forall(variablesInA, bmgr.implication(conjugatedFormulasOfA, itp)); - BooleanFormula right = - qfmgr.forall(variablesInB, bmgr.implication(itp, bmgr.not(conjugatedFormulasOfB))); + BooleanFormula left; + BooleanFormula right; + if (variablesInA.isEmpty()) { + left = bmgr.implication(conjugatedFormulasOfA, itp); + } else { + left = qfmgr.forall(variablesInA, bmgr.implication(conjugatedFormulasOfA, itp)); + } + //BooleanFormula left = qfmgr.forall(variablesInA, bmgr.implication(conjugatedFormulasOfA, + // itp)); + if (variablesInB.isEmpty()) { + right = bmgr.implication(itp, bmgr.not(conjugatedFormulasOfB)); + } else { + right = + qfmgr.forall(variablesInB, bmgr.implication(itp, bmgr.not(conjugatedFormulasOfB))); + } +// BooleanFormula right = +// qfmgr.forall(variablesInB, bmgr.implication(itp, bmgr.not(conjugatedFormulasOfB))); BooleanFormula interpolant = bmgr.makeFalse(); try (ProverEnvironment itpProver = getDistinctProver()) { @@ -380,7 +396,7 @@ private BooleanFormula getModelBasedProjectionInterpolant( checkNotNull(interpolant); } } - return interpolant; + return mgr.simplify(interpolant); } /** @@ -393,7 +409,9 @@ private ProverEnvironment getDistinctProver() { return solverContext.newProverEnvironment(ProverOptions.GENERATE_MODELS); } - /** Returns common {@link org.sosy_lab.java_smt.api.Formula}s of the 2 given lists. * */ + /** + * Returns common {@link org.sosy_lab.java_smt.api.Formula}s of the 2 given lists. * + */ private List getCommonFormulas( List variables1, List variables2) { HashSet set = new HashSet<>(variables1); diff --git a/src/org/sosy_lab/java_smt/test/InterpolatingProverTest.java b/src/org/sosy_lab/java_smt/test/InterpolatingProverTest.java index a4c3adf14d..4c3fc0948c 100644 --- a/src/org/sosy_lab/java_smt/test/InterpolatingProverTest.java +++ b/src/org/sosy_lab/java_smt/test/InterpolatingProverTest.java @@ -33,9 +33,12 @@ import org.sosy_lab.java_smt.solvers.cvc5.CVC5BooleanFormulaManager; import org.sosy_lab.java_smt.solvers.opensmt.Logics; -/** This class contains some simple Junit-tests to check the interpolation-API of our solvers. */ +/** + * This class contains some simple Junit-tests to check the interpolation-API of our solvers. + */ @SuppressWarnings({"resource", "LocalVariableName"}) -public class InterpolatingProverTest extends SolverBasedTest0.ParameterizedInterpolatingSolverBasedTest0 { +public class InterpolatingProverTest + extends SolverBasedTest0.ParameterizedInterpolatingSolverBasedTest0 { // INFO: OpenSmt only support interpolation for QF_LIA, QF_LRA and QF_UF @Override @@ -43,7 +46,9 @@ protected Logics logicToUse() { return Logics.QF_LIA; } - /** Generate a prover environment depending on the parameter above. */ + /** + * Generate a prover environment depending on the parameter above. + */ @SuppressWarnings("unchecked") private InterpolatingProverEnvironment newEnvironmentForTest() { requireInterpolation(itpStrategyToUse()); @@ -51,7 +56,8 @@ private InterpolatingProverEnvironment newEnvironmentForTest() { if (itpStrat == null) { return (InterpolatingProverEnvironment) context.newProverEnvironmentWithInterpolation(); } else { - return (InterpolatingProverEnvironment) context.newProverEnvironmentWithInterpolation(itpStrat); + return (InterpolatingProverEnvironment) context.newProverEnvironmentWithInterpolation( + itpStrat); } } @@ -60,10 +66,11 @@ private InterpolatingProverEnvironment newEnvironmentForTest() { @Test @SuppressWarnings("CheckReturnValue") public void simpleInterpolation() throws SolverException, InterruptedException { + requireIntegers(); assume() .withMessage("Solver %s runs into timeout on this test", solverToUse()) .that(solverToUse()) - .isNotEqualTo(Solvers.CVC5); + .isNotIn(ImmutableList.of(Solvers.CVC5, Solvers.Z3)); try (InterpolatingProverEnvironment prover = newEnvironmentForTest()) { IntegerFormula x = imgr.makeVariable("x"); @@ -94,6 +101,7 @@ public void simpleInterpolation() throws SolverException, InterruptedExcepti @SuppressWarnings("unchecked") public void emptyInterpolationGroup() throws SolverException, InterruptedException { try (InterpolatingProverEnvironment prover = newEnvironmentForTest()) { + requireIntegers(); IntegerFormula x = imgr.makeVariable("x"); IntegerFormula y = imgr.makeVariable("y"); /* INFO: Due to limitations in OpenSMT we need to use a simpler formula for this solver @@ -120,8 +128,11 @@ public void emptyInterpolationGroup() throws SolverException, InterruptedExc @Test public void binaryInterpolation() throws SolverException, InterruptedException { + requireBitvectors(); + requireIntegers(); InterpolatingProverEnvironment stack = newEnvironmentForTest(); + int i = index.getFreshId(); IntegerFormula zero = imgr.makeNumber(0); @@ -184,16 +195,16 @@ public void binaryInterpolationWithConstantFalse() assertThat(stack.getInterpolant(ImmutableList.of())).isEqualTo(bmgr.makeBoolean(true)); // some interpolant needs to be FALSE, however, it can be at arbitrary position. assertThat( - ImmutableList.of( - stack.getInterpolant(ImmutableList.of(TA)), - stack.getInterpolant(ImmutableList.of(TB)), - stack.getInterpolant(ImmutableList.of(TC)))) + ImmutableList.of( + stack.getInterpolant(ImmutableList.of(TA)), + stack.getInterpolant(ImmutableList.of(TB)), + stack.getInterpolant(ImmutableList.of(TC)))) .contains(bmgr.makeBoolean(false)); assertThat( - ImmutableList.of( - stack.getInterpolant(ImmutableList.of(TA, TB)), - stack.getInterpolant(ImmutableList.of(TB, TC)), - stack.getInterpolant(ImmutableList.of(TC, TA)))) + ImmutableList.of( + stack.getInterpolant(ImmutableList.of(TA, TB)), + stack.getInterpolant(ImmutableList.of(TB, TC)), + stack.getInterpolant(ImmutableList.of(TC, TA)))) .contains(bmgr.makeBoolean(false)); assertThat(stack.getInterpolant(ImmutableList.of(TA, TB, TC))) .isEqualTo(bmgr.makeBoolean(false)); @@ -203,6 +214,15 @@ public void binaryInterpolationWithConstantFalse() @Test public void binaryBVInterpolation1() throws SolverException, InterruptedException { + assume() + .withMessage("Solver %s with strategy %s is not supported or times out", solverToUse(), + itpStrategyToUse()) + .that( + (solverToUse() == Solvers.BITWUZLA) + || (solverToUse() == Solvers.Z3 + && itpStrategyToUse() == ProverOptions.GENERATE_PROJECTION_BASED_INTERPOLANTS) + ) + .isFalse(); requireBitvectors(); InterpolatingProverEnvironment stack = newEnvironmentForTest(); @@ -419,6 +439,7 @@ public void sequentialInterpolationWithFewPartitions() public void sequentialBVInterpolation() throws SolverException, InterruptedException { requireBitvectors(); requireSeqItp(itpStrategyToUse()); + requireTreeItp(itpStrategyToUse()); InterpolatingProverEnvironment stack = newEnvironmentForTest(); @@ -553,7 +574,7 @@ private void testTreeInterpolants0( List itps = stack.getTreeInterpolants0( ImmutableList.of(TA, TB, TD, TE, TC), // post-order - new int[] {0, 0, 2, 2, 0}); // left-most node in current subtree + new int[]{0, 0, 2, 2, 0}); // left-most node in current subtree stack.close(); @@ -585,7 +606,7 @@ private void testTreeInterpolants1( List itps = stack.getTreeInterpolants0( ImmutableList.of(TA, TB, TC, TD, TE), // post-order - new int[] {0, 1, 2, 3, 0}); // left-most node in current subtree + new int[]{0, 1, 2, 3, 0}); // left-most node in current subtree stack.close(); @@ -624,7 +645,7 @@ private void testTreeInterpolants2( List itps = stack.getTreeInterpolants0( ImmutableList.of(TA, TB, TC, TD, TE), // post-order - new int[] {0, 0, 0, 0, 0}); // left-most node in current subtree + new int[]{0, 0, 0, 0, 0}); // left-most node in current subtree stack.close(); @@ -681,7 +702,7 @@ public void treeInterpolation2() throws SolverException, InterruptedExceptio List itps = stack.getTreeInterpolants0( ImmutableList.of(TA, TB, TC, TR1, TD, TR2), // post-order - new int[] {0, 0, 2, 0, 4, 0}); // left-most node in current subtree + new int[]{0, 0, 2, 0, 4, 0}); // left-most node in current subtree stack.close(); @@ -737,7 +758,7 @@ public void treeInterpolation3() throws SolverException, InterruptedExceptio List itps = stack.getTreeInterpolants( ImmutableList.of(TB, TC, TR1, TD, TR2), // post-order - new int[] {0, 1, 0, 3, 0}); // left-most node in current subtree + new int[]{0, 1, 0, 3, 0}); // left-most node in current subtree assertThat(itps).hasSize(4); @@ -785,7 +806,7 @@ public void treeInterpolation4() throws SolverException, InterruptedExceptio List itps = stack.getTreeInterpolants0( ImmutableList.of(TbEquals1, TcEquals2, TbPlusCEqualsA, TaEquals9), // post-order - new int[] {0, 1, 0, 0}); // left-most node in current subtree + new int[]{0, 1, 0, 0}); // left-most node in current subtree assertThat(itps).hasSize(3); @@ -818,7 +839,7 @@ public void treeInterpolationForSequence() throws SolverException, Interrupt assertThat(stack).isUnsatisfiable(); - List itp = stack.getTreeInterpolants0(formulas, new int[] {0, 0}); + List itp = stack.getTreeInterpolants0(formulas, new int[]{0, 0}); assertThat(itp).hasSize(1); } @@ -858,7 +879,7 @@ public void treeInterpolationBranching() throws SolverException, Interrupted assertThat(stack).isUnsatisfiable(); - List itp = stack.getTreeInterpolants0(formulas, new int[] {0, 1, 2, 3, 4, 0}); + List itp = stack.getTreeInterpolants0(formulas, new int[]{0, 1, 2, 3, 4, 0}); assertThat(itp).hasSize(5); } @@ -875,7 +896,7 @@ public void treeInterpolationMalFormed1() throws SolverException, Interrupte assertThrows( IllegalArgumentException.class, - () -> stack.getTreeInterpolants(ImmutableList.of(TA), new int[] {0, 0})); + () -> stack.getTreeInterpolants(ImmutableList.of(TA), new int[]{0, 0})); } @Test @@ -891,7 +912,7 @@ public void treeInterpolationMalFormed2() throws SolverException, Interrupte assertThrows( IllegalArgumentException.class, - () -> stack.getTreeInterpolants(ImmutableList.of(TA), new int[] {4})); + () -> stack.getTreeInterpolants(ImmutableList.of(TA), new int[]{4})); } @Test @@ -907,7 +928,7 @@ public void treeInterpolationMalFormed3() throws SolverException, Interrupte assertThrows( IllegalArgumentException.class, - () -> stack.getTreeInterpolants(ImmutableList.of(TA, TA), new int[] {1, 0})); + () -> stack.getTreeInterpolants(ImmutableList.of(TA, TA), new int[]{1, 0})); } @Test @@ -922,7 +943,7 @@ public void treeInterpolationMalFormed4() throws SolverException, Interrupte assertThrows( IllegalArgumentException.class, - () -> stack.getTreeInterpolants0(ImmutableList.of(TA, TA, TA), new int[] {0, 1, 1})); + () -> stack.getTreeInterpolants0(ImmutableList.of(TA, TA, TA), new int[]{0, 1, 1})); } @Test @@ -937,7 +958,7 @@ public void treeInterpolationMalFormed5() throws SolverException, Interrupte assertThrows( IllegalArgumentException.class, - () -> stack.getTreeInterpolants0(ImmutableList.of(TA, TA, TA), new int[] {0, 1, 2})); + () -> stack.getTreeInterpolants0(ImmutableList.of(TA, TA, TA), new int[]{0, 1, 2})); } @Test @@ -952,7 +973,7 @@ public void treeInterpolationMalFormed6() throws SolverException, Interrupte assertThrows( IllegalArgumentException.class, - () -> stack.getTreeInterpolants0(ImmutableList.of(TA, TA, TA), new int[] {0, 2, 0})); + () -> stack.getTreeInterpolants0(ImmutableList.of(TA, TA, TA), new int[]{0, 2, 0})); } @Test @@ -967,7 +988,7 @@ public void treeInterpolationWithoutPartition() throws SolverException, Inte // empty list of partition assertThrows( IllegalArgumentException.class, - () -> stack.getTreeInterpolants(ImmutableList.of(), new int[] {})); + () -> stack.getTreeInterpolants(ImmutableList.of(), new int[]{})); } @Test @@ -994,7 +1015,7 @@ public void treeInterpolationWithOnePartition() throws SolverException, Inte // list of one partition List partition = ImmutableList.of(TA, TB); List itps = - stack.getTreeInterpolants(ImmutableList.of(partition), new int[] {0}); + stack.getTreeInterpolants(ImmutableList.of(partition), new int[]{0}); assertThat(itps).isEmpty(); } @@ -1003,6 +1024,7 @@ public void bigSeqInterpolationTest() throws InterruptedException, SolverExc requireBitvectors(); requireInterpolation(); requireSeqItp(itpStrategyToUse()); + requireTreeItp(itpStrategyToUse()); assume() .withMessage("Solver %s runs into timeout on this test", solverToUse()) @@ -1072,6 +1094,7 @@ public void bigSeqInterpolationTest() throws InterruptedException, SolverExc @Test public void testTrivialInterpolation() throws InterruptedException, SolverException { + requireIntegers(); InterpolatingProverEnvironment stack = newEnvironmentForTest(); IntegerFormula zero = imgr.makeNumber(0); IntegerFormula one = imgr.makeNumber(1); @@ -1101,7 +1124,7 @@ private void checkItpSequence(List formulas, List formulas, List void testInvalidToken() throws InterruptedException, SolverException { + requireIntegers(); InterpolatingProverEnvironment stack = newEnvironmentForTest(); // create and push formulas and solve them @@ -1151,6 +1175,9 @@ public void testInvalidToken() throws InterruptedException, SolverException case SMTINTERPOL: p3 = "some string"; break; + case Z3: + p3 = 12345; + break; default: p3 = null; // unexpected solver for interpolation } @@ -1167,6 +1194,7 @@ public void testInvalidToken() throws InterruptedException, SolverException */ @Test public void issue381InterpolationTest1() throws InterruptedException, SolverException { + requireIntegers(); requireSeqItp(itpStrategyToUse()); try (InterpolatingProverEnvironment prover = newEnvironmentForTest()) { var x = imgr.makeVariable("x"); @@ -1194,6 +1222,7 @@ public void issue381InterpolationTest1() throws InterruptedException, Solver */ @Test public void issue381InterpolationTest2() throws InterruptedException, SolverException { + requireIntegers(); requireSeqItp(itpStrategyToUse()); try (InterpolatingProverEnvironment prover = newEnvironmentForTest()) { var x = imgr.makeVariable("x"); @@ -1221,6 +1250,7 @@ public void issue381InterpolationTest2() throws InterruptedException, Solver */ @Test public void issue381InterpolationTest3() throws InterruptedException, SolverException { + requireIntegers(); try (InterpolatingProverEnvironment prover = newEnvironmentForTest()) { var x = imgr.makeVariable("x"); var one = imgr.makeNumber(1); diff --git a/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java b/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java index 5733184f73..573e2e7050 100644 --- a/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java +++ b/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java @@ -25,9 +25,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.Objects; import java.util.Set; -import java.util.stream.Collectors; import org.checkerframework.checker.nullness.qual.Nullable; import org.junit.After; import org.junit.Before; @@ -53,7 +51,6 @@ import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaManager; import org.sosy_lab.java_smt.api.IntegerFormulaManager; -import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment.InterpolationOption; import org.sosy_lab.java_smt.api.Model; import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula; import org.sosy_lab.java_smt.api.NumeralFormula.RationalFormula; @@ -149,10 +146,8 @@ protected ConfigurationBuilder createTestConfigBuilder() { } private static final ImmutableList INDEPENDENT_INTERPOLATION_STRATEGIES = - ImmutableList.of( - GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, - GENERATE_PROJECTION_BASED_INTERPOLANTS, - GENERATE_UNIFORM_FORWARD_INTERPOLANTS); + ImmutableList.of(GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, + GENERATE_PROJECTION_BASED_INTERPOLANTS, GENERATE_UNIFORM_FORWARD_INTERPOLANTS); @Before public final void initSolver() throws InvalidConfigurationException { @@ -162,10 +157,7 @@ public final void initSolver() throws InvalidConfigurationException { try { context = factory.generateContext(); } catch (InvalidConfigurationException e) { - assume() - .withMessage(e.getMessage()) - .that(e) - .hasCauseThat() + assume().withMessage(e.getMessage()).that(e).hasCauseThat() .isNotInstanceOf(UnsatisfiedLinkError.class); throw e; } @@ -232,46 +224,35 @@ public final void closeSolver() { * Skip test if the solver does not support integers. */ protected final void requireIntegers() { - assume() - .withMessage("Solver %s does not support the theory of integers", solverToUse()) - .that(imgr) - .isNotNull(); + assume().withMessage("Solver %s does not support the theory of integers", solverToUse()) + .that(imgr).isNotNull(); } /** * Skip test if the solver does not support rationals. */ protected final void requireRationals() { - assume() - .withMessage("Solver %s does not support the theory of rationals", solverToUse()) - .that(rmgr) - .isNotNull(); + assume().withMessage("Solver %s does not support the theory of rationals", solverToUse()) + .that(rmgr).isNotNull(); } protected final void requireRationalFloor() { - assume() - .withMessage("Solver %s does not support floor for rationals", solverToUse()) - .that(solverToUse()) - .isNotEqualTo(Solvers.OPENSMT); + assume().withMessage("Solver %s does not support floor for rationals", solverToUse()) + .that(solverToUse()).isNotEqualTo(Solvers.OPENSMT); } /** * Skip test if the solver does not support bitvectors. */ protected final void requireBitvectors() { - assume() - .withMessage("Solver %s does not support the theory of bitvectors", solverToUse()) - .that(bvmgr) - .isNotNull(); + assume().withMessage("Solver %s does not support the theory of bitvectors", solverToUse()) + .that(bvmgr).isNotNull(); } protected final void requireBitvectorToInt() { - assume() - .withMessage( - "Solver %s does not yet support the conversion between bitvectors and integers", - solverToUse()) - .that(solverToUse()) - .isNotEqualTo(Solvers.YICES2); + assume().withMessage( + "Solver %s does not yet support the conversion between bitvectors and integers", + solverToUse()).that(solverToUse()).isNotEqualTo(Solvers.YICES2); } @SuppressWarnings("CheckReturnValue") @@ -280,10 +261,8 @@ protected final void requireFPToBitvector() { try { fpmgr.toIeeeBitvector(fpmgr.makeNumber(0, getSinglePrecisionFloatingPointType())); } catch (UnsupportedOperationException e) { - assume() - .withMessage("Solver %s does not yet support FP-to-BV conversion", solverToUse()) - .that(solverToUse()) - .isNull(); + assume().withMessage("Solver %s does not yet support FP-to-BV conversion", solverToUse()) + .that(solverToUse()).isNull(); } } @@ -291,17 +270,14 @@ protected final void requireFPToBitvector() { * Skip test if the solver does not support quantifiers. */ protected final void requireQuantifiers() { - assume() - .withMessage("Solver %s does not support quantifiers", solverToUse()) - .that(qmgr) + assume().withMessage("Solver %s does not support quantifiers", solverToUse()).that(qmgr) .isNotNull(); } @SuppressWarnings("unused") protected final void requireQuantifierElimination() { requireQuantifiers(); - assume() - .withMessage("Solver %s does not support quantifier elimination", solverToUse()) + assume().withMessage("Solver %s does not support quantifier elimination", solverToUse()) .that(solverToUse()) .isNoneOf(Solvers.BOOLECTOR, Solvers.MATHSAT5, Solvers.YICES2, Solvers.BITWUZLA); } @@ -310,48 +286,36 @@ protected final void requireQuantifierElimination() { * Skip test if the solver does not support arrays. */ protected final void requireArrays() { - assume() - .withMessage("Solver %s does not support the theory of arrays", solverToUse()) - .that(amgr) - .isNotNull(); + assume().withMessage("Solver %s does not support the theory of arrays", solverToUse()) + .that(amgr).isNotNull(); } protected final void requireFloats() { - assume() - .withMessage("Solver %s does not support the theory of floats", solverToUse()) - .that(fpmgr) - .isNotNull(); + assume().withMessage("Solver %s does not support the theory of floats", solverToUse()) + .that(fpmgr).isNotNull(); } /** * Skip test if the solver does not support strings. */ protected final void requireStrings() { - assume() - .withMessage("Solver %s does not support the theory of strings", solverToUse()) - .that(smgr) - .isNotNull(); - assume() - .withMessage("Solver %s does not support the theory of arrays", solverToUse()) - .that(amgr) - .isNotNull(); + assume().withMessage("Solver %s does not support the theory of strings", solverToUse()) + .that(smgr).isNotNull(); + assume().withMessage("Solver %s does not support the theory of arrays", solverToUse()) + .that(amgr).isNotNull(); } /** * Skip test if the solver does not support enumeration theory. */ protected final void requireEnumeration() { - assume() - .withMessage("Solver %s does not support the theory of enumerations", solverToUse()) - .that(emgr) - .isNotNull(); + assume().withMessage("Solver %s does not support the theory of enumerations", solverToUse()) + .that(emgr).isNotNull(); } protected final void requireSeparationLogic() { - assume() - .withMessage("Solver %s does not support the theory of separation logic", solverToUse()) - .that(slmgr) - .isNotNull(); + assume().withMessage("Solver %s does not support the theory of separation logic", solverToUse()) + .that(slmgr).isNotNull(); } /** @@ -361,9 +325,7 @@ protected final void requireOptimization() { try { context.newOptimizationProverEnvironment().close(); } catch (UnsupportedOperationException e) { - assume() - .withMessage("Solver %s does not support optimization", solverToUse()) - .that(e) + assume().withMessage("Solver %s does not support optimization", solverToUse()).that(e) .isNull(); } } @@ -371,59 +333,45 @@ protected final void requireOptimization() { protected final void requireInterpolation(ProverOptions... options) { try { if (Arrays.stream(options).anyMatch(p -> p == null)) { + if (solverToUse() == Solvers.Z3) { + throw new UnsupportedOperationException(); + } context.newProverEnvironmentWithInterpolation().close(); } else { context.newProverEnvironmentWithInterpolation(options).close(); } } catch (UnsupportedOperationException e) { - assume() - .withMessage("Solver %s does not support interpolation", solverToUse()) - .that(e) + assume().withMessage("Solver %s does not support interpolation", solverToUse()).that(e) .isNull(); } } protected final void requireSeqItp(ProverOptions... options) { - assume() - .withMessage( - "Solver independent interpolation strategy %s does not support sequential " - + "interpolation", - solverToUse()) - .that(options) - .asList() - .containsNoneIn( - INDEPENDENT_INTERPOLATION_STRATEGIES); + assume().withMessage("Solver independent interpolation strategy %s does not support sequential " + + "interpolation", solverToUse()).that(options).asList() + .containsNoneIn(INDEPENDENT_INTERPOLATION_STRATEGIES); } protected final void requireTreeItp(ProverOptions... options) { requireInterpolation(); var test = Arrays.asList(options); - assume() - .withMessage("Solver does not support tree-interpolation.") - .that(solverToUse()) + assume().withMessage("Solver does not support tree-interpolation.").that(solverToUse()) .isAnyOf(Solvers.SMTINTERPOL, Solvers.PRINCESS); - assume() - .withMessage( - "Strategy %s does not support tree interpolation", + assume().withMessage("Strategy %s does not support tree interpolation", Arrays.toString(options)) // Optional: print the options for clarity - .that(options) - .asList() - .contains(INDEPENDENT_INTERPOLATION_STRATEGIES); + .that(options).asList().containsNoneIn(INDEPENDENT_INTERPOLATION_STRATEGIES); } protected void requireParser() { - assume() - .withMessage("Solver %s does not support parsing formulae", solverToUse()) + assume().withMessage("Solver %s does not support parsing formulae", solverToUse()) .that(solverToUse()) .isNoneOf(Solvers.CVC4, Solvers.BOOLECTOR, Solvers.YICES2, Solvers.CVC5); } protected void requireArrayModel() { - assume() - .withMessage("Solver %s does not support model generation for arrays", solverToUse()) - .that(solverToUse()) - .isNotEqualTo(Solvers.OPENSMT); + assume().withMessage("Solver %s does not support model generation for arrays", solverToUse()) + .that(solverToUse()).isNotEqualTo(Solvers.OPENSMT); } protected void requireModel() { @@ -434,38 +382,28 @@ protected void requireModel() { } protected void requireVisitor() { - assume() - .withMessage("Solver %s does not support formula visitor", solverToUse()) - .that(solverToUse()) - .isNotEqualTo(Solvers.BOOLECTOR); + assume().withMessage("Solver %s does not support formula visitor", solverToUse()) + .that(solverToUse()).isNotEqualTo(Solvers.BOOLECTOR); } protected void requireUnsatCore() { - assume() - .withMessage("Solver %s does not support unsat core generation", solverToUse()) - .that(solverToUse()) - .isNotEqualTo(Solvers.BOOLECTOR); + assume().withMessage("Solver %s does not support unsat core generation", solverToUse()) + .that(solverToUse()).isNotEqualTo(Solvers.BOOLECTOR); } protected void requireUnsatCoreOverAssumptions() { - assume() - .withMessage("Solver %s does not support unsat core generation", solverToUse()) - .that(solverToUse()) - .isNotEqualTo(Solvers.PRINCESS); + assume().withMessage("Solver %s does not support unsat core generation", solverToUse()) + .that(solverToUse()).isNotEqualTo(Solvers.PRINCESS); } protected void requireSubstitution() { - assume() - .withMessage("Solver %s does not support formula substitution", solverToUse()) - .that(solverToUse()) - .isNotEqualTo(Solvers.BOOLECTOR); + assume().withMessage("Solver %s does not support formula substitution", solverToUse()) + .that(solverToUse()).isNotEqualTo(Solvers.BOOLECTOR); } protected void requireUserPropagators() { - assume() - .withMessage("Solver %s does not support user propagation", solverToUse()) - .that(solverToUse()) - .isEqualTo(Solvers.Z3); + assume().withMessage("Solver %s does not support user propagation", solverToUse()) + .that(solverToUse()).isEqualTo(Solvers.Z3); } /** @@ -491,8 +429,7 @@ public void isValidInterpolant(BooleanFormula interpolant, BooleanFormula a, Boo public void isValidInterpolant( BooleanFormula interpolant, List formulasOfA, - List formulasOfB) - throws SolverException, InterruptedException { + List formulasOfB) throws SolverException, InterruptedException { // TODO: move into assertion framework BooleanFormula conjugatedFormulasOfA = bmgr.and(formulasOfA); @@ -504,8 +441,7 @@ public void isValidInterpolant( Set interpolBSymbols = mgr.extractVariablesAndUFs(conjugatedFormulasOfB).keySet(); Set intersection = Sets.intersection(interpolASymbols, interpolBSymbols); // TODO: assertThat is not available with message - checkState( - intersection.containsAll(interpolantSymbols), + checkState(intersection.containsAll(interpolantSymbols), "Interpolant contains symbols %s that are not part of both input formula groups A and B.", Sets.difference(interpolantSymbols, intersection)); @@ -513,16 +449,14 @@ public void isValidInterpolant( validationProver.push(); validationProver.addConstraint(bmgr.implication(conjugatedFormulasOfA, interpolant)); // TODO: assertThat is not available with message - checkState( - !validationProver.isUnsat(), + checkState(!validationProver.isUnsat(), "Invalid Craig interpolation: formula group A does not imply the interpolant."); validationProver.pop(); validationProver.push(); validationProver.addConstraint(bmgr.and(interpolant, conjugatedFormulasOfB)); // TODO: assertThat is not available with message - checkState( - validationProver.isUnsat(), + checkState(validationProver.isUnsat(), "Invalid Craig interpolation: interpolant does not contradict formula group B."); validationProver.pop(); } @@ -543,8 +477,7 @@ protected void evaluateInModel( BooleanFormula constraint, Formula formula, Collection possibleExpectedValues, - Collection possibleExpectedFormulas) - throws SolverException, InterruptedException { + Collection possibleExpectedFormulas) throws SolverException, InterruptedException { try (ProverEnvironment prover = context.newProverEnvironment(ProverOptions.GENERATE_MODELS)) { prover.push(constraint); @@ -609,10 +542,8 @@ public abstract static class ParameterizedInterpolatingSolverBasedTest0 // GENERATE_MODELS as stand-in for native private static final Set ALL_INTERPOLATION_STRATEGIES = - ImmutableSet.of( - GENERATE_PROJECTION_BASED_INTERPOLANTS, - GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, - GENERATE_UNIFORM_FORWARD_INTERPOLANTS); + ImmutableSet.of(GENERATE_PROJECTION_BASED_INTERPOLANTS, + GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, GENERATE_UNIFORM_FORWARD_INTERPOLANTS); @Parameters(name = "solver {0} with interpolation strategy {1}") public static List getAllSolversAndItpStrategies() { From 05864d6b207c4018190b38180589c82868b927db Mon Sep 17 00:00:00 2001 From: BaierD Date: Thu, 18 Dec 2025 10:56:02 +0100 Subject: [PATCH 13/20] Remove redundant variable present in super class in ParameterizedInterpolatingSolverBasedTest0 and block independent interpolation for tree interpolants properly for now --- src/org/sosy_lab/java_smt/test/SolverBasedTest0.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java b/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java index 573e2e7050..8d7cca04f2 100644 --- a/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java +++ b/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java @@ -354,7 +354,9 @@ protected final void requireSeqItp(ProverOptions... options) { protected final void requireTreeItp(ProverOptions... options) { requireInterpolation(); - var test = Arrays.asList(options); + assume().withMessage("Solver independent interpolation strategy %s does not support tree " + + "interpolation", solverToUse()).that(options).asList() + .containsNoneIn(INDEPENDENT_INTERPOLATION_STRATEGIES); assume().withMessage("Solver does not support tree-interpolation.").that(solverToUse()) .isAnyOf(Solvers.SMTINTERPOL, Solvers.PRINCESS); @@ -558,17 +560,9 @@ public static List getAllSolversAndItpStrategies() { return lst; } - @Parameter(0) - public Solvers solver; - @Parameter(1) public ProverOptions interpolationStrategy; - @Override - protected Solvers solverToUse() { - return solver; - } - protected ProverOptions itpStrategyToUse() { return interpolationStrategy; } From a8eb472e65f056382313d97ff5286e8ef3cce8b4 Mon Sep 17 00:00:00 2001 From: BaierD Date: Thu, 18 Dec 2025 11:06:33 +0100 Subject: [PATCH 14/20] Add TODO about restricting independent interpolation solver creation --- src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java b/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java index 41571b44a5..13dac5f2f8 100644 --- a/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java +++ b/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java @@ -82,6 +82,7 @@ private InterpolatingProverEnvironment newProverEnvironmentWithInterpolation1 // If native interpolation is not available, we wrap a normal prover such that it returns // interpolation points ProverEnvironment normalProver = newProverEnvironment0(options); + // TODO: only allow this if there is a quantified formula manager available! out = new InterpolatingSolverDelegate(normalProver, options); } From 9d74f9287d7676d7070e2c02692ba378d984d426 Mon Sep 17 00:00:00 2001 From: Julius Brehme Date: Sat, 20 Dec 2025 17:09:43 +0100 Subject: [PATCH 15/20] add comments for interpolation options --- .../sosy_lab/java_smt/api/SolverContext.java | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/api/SolverContext.java b/src/org/sosy_lab/java_smt/api/SolverContext.java index 9ee09e00d1..c697550852 100644 --- a/src/org/sosy_lab/java_smt/api/SolverContext.java +++ b/src/org/sosy_lab/java_smt/api/SolverContext.java @@ -54,9 +54,36 @@ enum ProverOptions { /** Whether the solver should enable support for formulae build in SL theory. */ ENABLE_SEPARATION_LOGIC, + + /** + * Enables Craig interpolation, using the model-based interpolation strategy. This strategy + * constructs interpolants based on the model provided by a solver, i.e. model generation must + * be enabled. This interpolation strategy is only usable for solvers supporting quantified + * solving over the theories interpolated upon. The solver does not need to support + * interpolation itself. + */ GENERATE_PROJECTION_BASED_INTERPOLANTS, + + /** + * Enables (uniform) Craig interpolation, using the quantifier-based interpolation strategy + * utilizing quantifier-elimination in the forward direction. Forward means, that the set of + * formulas A, used to interpolate, interpolates towards the set of formulas B (B == all + * formulas that are currently asserted, but not in the given set of formulas A used to + * interpolate). This interpolation strategy is only usable for solvers supporting + * quantifier-elimination over the theories interpolated upon. The solver does not need to + * support interpolation itself. + */ GENERATE_UNIFORM_FORWARD_INTERPOLANTS, - GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, + + /** + * Enables (uniform) Craig interpolation, using the quantifier-based interpolation strategy + * utilizing quantifier-elimination in the backward direction. Backward means, that the set of + * formulas B (B == all formulas that are currently asserted, but not in the given set of + * formulas A used to interpolate) interpolates towards the set of formulas A. This + * interpolation strategy is only usable for solvers supporting quantifier-elimination over the + * theories interpolated upon. The solver does not need to support interpolation itself. + */ + GENERATE_UNIFORM_BACKWARD_INTERPOLANTS } /** From a3e98de66587cf733076197645127f6a0a8069a5 Mon Sep 17 00:00:00 2001 From: Julius Brehme Date: Sat, 20 Dec 2025 17:10:13 +0100 Subject: [PATCH 16/20] updated code style --- .../api/InterpolatingProverEnvironment.java | 48 --- .../java_smt/basicimpl/AbstractProver.java | 8 +- .../basicimpl/AbstractSolverContext.java | 13 +- ...ndependentInterpolatingSolverDelegate.java | 90 +----- .../test/InterpolatingProverTest.java | 71 +++-- .../java_smt/test/SolverBasedTest0.java | 280 +++++++++++------- 6 files changed, 238 insertions(+), 272 deletions(-) diff --git a/src/org/sosy_lab/java_smt/api/InterpolatingProverEnvironment.java b/src/org/sosy_lab/java_smt/api/InterpolatingProverEnvironment.java index cf687b43cb..6ac45b33e5 100644 --- a/src/org/sosy_lab/java_smt/api/InterpolatingProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/api/InterpolatingProverEnvironment.java @@ -24,46 +24,6 @@ * @param The type of the objects which can be used to select formulas for interpolant creation. */ public interface InterpolatingProverEnvironment extends BasicProverEnvironment { - - enum InterpolationOption { - - /** - * The chosen solvers native interpolation. Additional options have to be selected when creating - * the solver or prover. - */ - NATIVE, - - /** - * Enables Craig interpolation, using the model-based interpolation strategy. This strategy - * constructs interpolants based on the model provided by a solver, i.e. model generation must - * be enabled. This interpolation strategy is only usable for solvers supporting quantified - * solving over the theories interpolated upon. The solver does not need to support - * interpolation itself. - */ - GENERATE_PROJECTION_BASED_INTERPOLANTS, - - /** - * Enables (uniform) Craig interpolation, using the quantifier-based interpolation strategy - * utilizing quantifier-elimination in the forward direction. Forward means, that the set of - * formulas A, used to interpolate, interpolates towards the set of formulas B (B == all - * formulas that are currently asserted, but not in the given set of formulas A used to - * interpolate). This interpolation strategy is only usable for solvers supporting - * quantifier-elimination over the theories interpolated upon. The solver does not need to - * support interpolation itself. - */ - GENERATE_UNIFORM_FORWARD_INTERPOLANTS, - - /** - * Enables (uniform) Craig interpolation, using the quantifier-based interpolation strategy - * utilizing quantifier-elimination in the backward direction. Backward means, that the set of - * formulas B (B == all formulas that are currently asserted, but not in the given set of - * formulas A used to interpolate) interpolates towards the set of formulas A. This - * interpolation strategy is only usable for solvers supporting quantifier-elimination over the - * theories interpolated upon. The solver does not need to support interpolation itself. - */ - GENERATE_UNIFORM_BACKWARD_INTERPOLANTS - } - /** * Get an interpolant for two groups of formulas. This should be called only immediately after an * {@link #isUnsat()} call that returned true. @@ -84,14 +44,6 @@ enum InterpolationOption { BooleanFormula getInterpolant(Collection formulasOfA) throws SolverException, InterruptedException; -// default BooleanFormula getInterpolant(Collection formulasOfA, InterpolationOption option) -// throws SolverException, InterruptedException { -// if (option == InterpolationOption.NATIVE) { -// return getInterpolant(formulasOfA); -// } -// throw new UnsupportedOperationException("Interpolation option " + option + " not supported"); -// } - /** * This method returns interpolants of an 'inductive sequence'. This property must be supported by * the interpolation-strategy of the underlying SMT-solver! Depending on the underlying SMT-solver diff --git a/src/org/sosy_lab/java_smt/basicimpl/AbstractProver.java b/src/org/sosy_lab/java_smt/basicimpl/AbstractProver.java index 0096b52022..d0127335ae 100644 --- a/src/org/sosy_lab/java_smt/basicimpl/AbstractProver.java +++ b/src/org/sosy_lab/java_smt/basicimpl/AbstractProver.java @@ -184,7 +184,7 @@ public void close() { } /** Provides the set of BooleanFormulas to interpolate on. */ - public static class InterpolationGroups { + public static final class InterpolationGroups { private final Collection formulasOfA; private final Collection formulasOfB; @@ -196,16 +196,16 @@ private InterpolationGroups( formulasOfB = pFormulasOfB; } - protected static InterpolationGroups of( + public static InterpolationGroups of( Collection pFormulasOfA, Collection pFormulasOfB) { return new InterpolationGroups(pFormulasOfA, pFormulasOfB); } - protected Collection getFormulasOfA() { + public Collection getFormulasOfA() { return formulasOfA; } - protected Collection getFormulasOfB() { + public Collection getFormulasOfB() { return formulasOfB; } } diff --git a/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java b/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java index 13dac5f2f8..e06ee03e37 100644 --- a/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java +++ b/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java @@ -8,10 +8,6 @@ package org.sosy_lab.java_smt.basicimpl; -import static org.sosy_lab.java_smt.api.InterpolatingProverEnvironment.InterpolationOption.GENERATE_PROJECTION_BASED_INTERPOLANTS; -import static org.sosy_lab.java_smt.api.InterpolatingProverEnvironment.InterpolationOption.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS; -import static org.sosy_lab.java_smt.api.InterpolatingProverEnvironment.InterpolationOption.GENERATE_UNIFORM_FORWARD_INTERPOLANTS; - import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; @@ -24,7 +20,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.sosy_lab.java_smt.api.FormulaManager; import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment; -import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment.InterpolationOption; import org.sosy_lab.java_smt.api.OptimizationProverEnvironment; import org.sosy_lab.java_smt.api.ProverEnvironment; import org.sosy_lab.java_smt.api.SolverContext; @@ -72,6 +67,7 @@ public final InterpolatingProverEnvironment newProverEnvironmentWithInterpola return out; } + @SuppressWarnings("ResultOfMethodCallIgnored") private InterpolatingProverEnvironment newProverEnvironmentWithInterpolation1( Set options) { InterpolatingProverEnvironment out; @@ -79,6 +75,13 @@ private InterpolatingProverEnvironment newProverEnvironmentWithInterpolation1 try { out = newProverEnvironmentWithInterpolation0(options); } catch (UnsupportedOperationException e) { + // Check if QuantifiedFormulaManager is available before attempting independent interpolation + try { + getFormulaManager().getQuantifiedFormulaManager(); + } catch (UnsupportedOperationException error) { + e.addSuppressed(error); + throw e; + } // If native interpolation is not available, we wrap a normal prover such that it returns // interpolation points ProverEnvironment normalProver = newProverEnvironment0(options); diff --git a/src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java b/src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java index 046c9cb181..e5c1530728 100644 --- a/src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java +++ b/src/org/sosy_lab/java_smt/basicimpl/IndependentInterpolatingSolverDelegate.java @@ -17,15 +17,15 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; -import edu.umd.cs.findbugs.annotations.Nullable; import java.util.Collection; import java.util.HashMap; -import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import org.checkerframework.checker.nullness.qual.Nullable; import org.sosy_lab.common.UniqueIdGenerator; import org.sosy_lab.java_smt.api.BooleanFormula; import org.sosy_lab.java_smt.api.BooleanFormulaManager; @@ -117,7 +117,6 @@ public BooleanFormula getInterpolant(Collection identifiersForA) return bmgr.makeTrue(); } - if (interpolationStrategy == null) { interpolant = delegate.getInterpolant(identifiersForA); @@ -140,8 +139,7 @@ public BooleanFormula getInterpolant(Collection identifiersForA) return bmgr.not(conjugatedFormulasOfB); } // Note: uses the A -> i -> B is valid definition for Craig-Interpolants, so we negate B - interpolant = - getUniformBackwardInterpolant(conjugatedFormulasOfB, exclusiveVariablesInB); + interpolant = getUniformBackwardInterpolant(conjugatedFormulasOfB, exclusiveVariablesInB); } else { throw new AssertionError("Unknown interpolation strategy."); } @@ -150,78 +148,26 @@ assert satisfiesInterpolationCriteria( interpolant, conjugatedFormulasOfA, conjugatedFormulasOfB); return interpolant; - -// switch (checkNotNull(option)) { -// case NATIVE: -// interpolant = getInterpolant(identifiersForA); -// break; -// case GENERATE_PROJECTION_BASED_INTERPOLANTS: -// // Will generate CHC based constraints that are very hard to solve without a CHC solver -// if (sharedVariables.isEmpty()) { -// return bmgr.makeFalse(); -// } -// interpolant = -// getModelBasedProjectionInterpolant( -// conjugatedFormulasOfA, -// conjugatedFormulasOfB, -// variablesInA, -// variablesInB, -// sharedVariables); -// break; -// case GENERATE_UNIFORM_FORWARD_INTERPOLANTS: -// // Will generate interpolants based on quantifier elimination -// if (exclusiveVariablesInA.isEmpty()) { -// return bmgr.makeFalse(); -// } -// interpolant = getUniformForwardInterpolant(conjugatedFormulasOfA, exclusiveVariablesInA); -// break; -// case GENERATE_UNIFORM_BACKWARD_INTERPOLANTS: -// // Will generate interpolants based on quantifier elimination -// if (exclusiveVariablesInB.isEmpty()) { -// return bmgr.makeFalse(); -// } -// // Note: uses the A -> i -> B is valid definition for Craig-Interpolants, so we negate B -// interpolant = -// getUniformBackwardInterpolant(bmgr.not(conjugatedFormulasOfB), exclusiveVariablesInB); -// break; -// default: -// throw new AssertionError("Unknown interpolation strategy " + option); -// } -// -// assert satisfiesInterpolationCriteria( -// interpolant, conjugatedFormulasOfA, conjugatedFormulasOfB); -// -// return interpolant; } -// @Override -// public BooleanFormula getInterpolant(Collection formulasOfA) -// throws SolverException, InterruptedException { -// return delegate.getInterpolant(formulasOfA); -// } - - @Override public List getTreeInterpolants( List> partitionedFormulas, int[] startOfSubTree) throws SolverException, InterruptedException { if (interpolationStrategy == null) { // Use native solver interpolation - return ((InterpolatingProverEnvironment) delegate) - .getTreeInterpolants(partitionedFormulas, startOfSubTree); + return delegate.getTreeInterpolants(partitionedFormulas, startOfSubTree); } throw new UnsupportedOperationException( "Tree interpolants are not supported for independent interpolation currently."); } - @Override public List getSeqInterpolants(List> pPartitionedFormulas) throws SolverException, InterruptedException { if (interpolationStrategy == null) { // Use native solver interpolation - return ((InterpolatingProverEnvironment) delegate) - .getSeqInterpolants(pPartitionedFormulas); + return delegate.getSeqInterpolants(pPartitionedFormulas); } throw new UnsupportedOperationException( "Sequential interpolants are not supported for independent interpolation currently."); @@ -279,9 +225,7 @@ private boolean satisfiesInterpolationCriteria( return true; } - /** - * interpolate(A(x,y),B(y,z))=∀z.¬B(y,z) - */ + /** interpolate(A(x,y),B(y,z))=∀z.¬B(y,z). */ private BooleanFormula getUniformBackwardInterpolant( BooleanFormula formulasOfB, List exclusiveVariables) throws SolverException, InterruptedException { @@ -298,9 +242,7 @@ private BooleanFormula getUniformBackwardInterpolant( return mgr.simplify(itpBackward); } - /** - * Checks the formula for a quantifier at an arbitrary position/depth. - */ + /** Checks the formula for a quantifier at an arbitrary position/depth. */ private boolean isQuantifiedFormula(BooleanFormula maybeQuantifiedFormula) { final AtomicBoolean isQuantified = new AtomicBoolean(false); mgr.visitRecursively( @@ -332,7 +274,7 @@ public TraversalProcess visitQuantifier( *

Forward means, that the set of formulas A interpolates towards the set of formulas B. * * @param conjugatedFormulasOfA The set of formulas A, combined into one {@link BooleanFormula}. - * @param exclusiveVariables A list of shared variables found in both sets of formulas A and B. + * @param exclusiveVariables A list of shared variables found in both sets of formulas A and B. * @return a uniform Craig interpolant or an exception is thrown. */ private BooleanFormula getUniformForwardInterpolant( @@ -363,7 +305,8 @@ private BooleanFormula getModelBasedProjectionInterpolant( BooleanFormula itp = ufmgr.declareAndCallUF( - "__itp_internal_javasmt_" + termIdGenerator.getFreshId(), FormulaType.BooleanType, + "__itp_internal_javasmt_" + termIdGenerator.getFreshId(), + FormulaType.BooleanType, sharedVars); BooleanFormula left; BooleanFormula right; @@ -372,16 +315,13 @@ private BooleanFormula getModelBasedProjectionInterpolant( } else { left = qfmgr.forall(variablesInA, bmgr.implication(conjugatedFormulasOfA, itp)); } - //BooleanFormula left = qfmgr.forall(variablesInA, bmgr.implication(conjugatedFormulasOfA, + // BooleanFormula left = qfmgr.forall(variablesInA, bmgr.implication(conjugatedFormulasOfA, // itp)); if (variablesInB.isEmpty()) { right = bmgr.implication(itp, bmgr.not(conjugatedFormulasOfB)); } else { - right = - qfmgr.forall(variablesInB, bmgr.implication(itp, bmgr.not(conjugatedFormulasOfB))); + right = qfmgr.forall(variablesInB, bmgr.implication(itp, bmgr.not(conjugatedFormulasOfB))); } -// BooleanFormula right = -// qfmgr.forall(variablesInB, bmgr.implication(itp, bmgr.not(conjugatedFormulasOfB))); BooleanFormula interpolant = bmgr.makeFalse(); try (ProverEnvironment itpProver = getDistinctProver()) { @@ -409,12 +349,10 @@ private ProverEnvironment getDistinctProver() { return solverContext.newProverEnvironment(ProverOptions.GENERATE_MODELS); } - /** - * Returns common {@link org.sosy_lab.java_smt.api.Formula}s of the 2 given lists. * - */ + /** Returns common {@link org.sosy_lab.java_smt.api.Formula}s of the 2 given lists. * */ private List getCommonFormulas( List variables1, List variables2) { - HashSet set = new HashSet<>(variables1); + Set set = new LinkedHashSet<>(variables1); set.retainAll(variables2); return ImmutableList.copyOf(set); } diff --git a/src/org/sosy_lab/java_smt/test/InterpolatingProverTest.java b/src/org/sosy_lab/java_smt/test/InterpolatingProverTest.java index 4c3fc0948c..820127722d 100644 --- a/src/org/sosy_lab/java_smt/test/InterpolatingProverTest.java +++ b/src/org/sosy_lab/java_smt/test/InterpolatingProverTest.java @@ -33,9 +33,7 @@ import org.sosy_lab.java_smt.solvers.cvc5.CVC5BooleanFormulaManager; import org.sosy_lab.java_smt.solvers.opensmt.Logics; -/** - * This class contains some simple Junit-tests to check the interpolation-API of our solvers. - */ +/** This class contains some simple Junit-tests to check the interpolation-API of our solvers. */ @SuppressWarnings({"resource", "LocalVariableName"}) public class InterpolatingProverTest extends SolverBasedTest0.ParameterizedInterpolatingSolverBasedTest0 { @@ -46,9 +44,7 @@ protected Logics logicToUse() { return Logics.QF_LIA; } - /** - * Generate a prover environment depending on the parameter above. - */ + /** Generate a prover environment depending on the parameter above. */ @SuppressWarnings("unchecked") private InterpolatingProverEnvironment newEnvironmentForTest() { requireInterpolation(itpStrategyToUse()); @@ -56,8 +52,8 @@ private InterpolatingProverEnvironment newEnvironmentForTest() { if (itpStrat == null) { return (InterpolatingProverEnvironment) context.newProverEnvironmentWithInterpolation(); } else { - return (InterpolatingProverEnvironment) context.newProverEnvironmentWithInterpolation( - itpStrat); + return (InterpolatingProverEnvironment) + context.newProverEnvironmentWithInterpolation(itpStrat); } } @@ -132,7 +128,6 @@ public void binaryInterpolation() throws SolverException, InterruptedExcepti requireIntegers(); InterpolatingProverEnvironment stack = newEnvironmentForTest(); - int i = index.getFreshId(); IntegerFormula zero = imgr.makeNumber(0); @@ -195,16 +190,16 @@ public void binaryInterpolationWithConstantFalse() assertThat(stack.getInterpolant(ImmutableList.of())).isEqualTo(bmgr.makeBoolean(true)); // some interpolant needs to be FALSE, however, it can be at arbitrary position. assertThat( - ImmutableList.of( - stack.getInterpolant(ImmutableList.of(TA)), - stack.getInterpolant(ImmutableList.of(TB)), - stack.getInterpolant(ImmutableList.of(TC)))) + ImmutableList.of( + stack.getInterpolant(ImmutableList.of(TA)), + stack.getInterpolant(ImmutableList.of(TB)), + stack.getInterpolant(ImmutableList.of(TC)))) .contains(bmgr.makeBoolean(false)); assertThat( - ImmutableList.of( - stack.getInterpolant(ImmutableList.of(TA, TB)), - stack.getInterpolant(ImmutableList.of(TB, TC)), - stack.getInterpolant(ImmutableList.of(TC, TA)))) + ImmutableList.of( + stack.getInterpolant(ImmutableList.of(TA, TB)), + stack.getInterpolant(ImmutableList.of(TB, TC)), + stack.getInterpolant(ImmutableList.of(TC, TA)))) .contains(bmgr.makeBoolean(false)); assertThat(stack.getInterpolant(ImmutableList.of(TA, TB, TC))) .isEqualTo(bmgr.makeBoolean(false)); @@ -215,13 +210,13 @@ public void binaryInterpolationWithConstantFalse() @Test public void binaryBVInterpolation1() throws SolverException, InterruptedException { assume() - .withMessage("Solver %s with strategy %s is not supported or times out", solverToUse(), - itpStrategyToUse()) + .withMessage( + "Solver %s with strategy %s is not supported or times out", + solverToUse(), itpStrategyToUse()) .that( (solverToUse() == Solvers.BITWUZLA) || (solverToUse() == Solvers.Z3 - && itpStrategyToUse() == ProverOptions.GENERATE_PROJECTION_BASED_INTERPOLANTS) - ) + && itpStrategyToUse() == ProverOptions.GENERATE_PROJECTION_BASED_INTERPOLANTS)) .isFalse(); requireBitvectors(); @@ -574,7 +569,7 @@ private void testTreeInterpolants0( List itps = stack.getTreeInterpolants0( ImmutableList.of(TA, TB, TD, TE, TC), // post-order - new int[]{0, 0, 2, 2, 0}); // left-most node in current subtree + new int[] {0, 0, 2, 2, 0}); // left-most node in current subtree stack.close(); @@ -606,7 +601,7 @@ private void testTreeInterpolants1( List itps = stack.getTreeInterpolants0( ImmutableList.of(TA, TB, TC, TD, TE), // post-order - new int[]{0, 1, 2, 3, 0}); // left-most node in current subtree + new int[] {0, 1, 2, 3, 0}); // left-most node in current subtree stack.close(); @@ -645,7 +640,7 @@ private void testTreeInterpolants2( List itps = stack.getTreeInterpolants0( ImmutableList.of(TA, TB, TC, TD, TE), // post-order - new int[]{0, 0, 0, 0, 0}); // left-most node in current subtree + new int[] {0, 0, 0, 0, 0}); // left-most node in current subtree stack.close(); @@ -702,7 +697,7 @@ public void treeInterpolation2() throws SolverException, InterruptedExceptio List itps = stack.getTreeInterpolants0( ImmutableList.of(TA, TB, TC, TR1, TD, TR2), // post-order - new int[]{0, 0, 2, 0, 4, 0}); // left-most node in current subtree + new int[] {0, 0, 2, 0, 4, 0}); // left-most node in current subtree stack.close(); @@ -758,7 +753,7 @@ public void treeInterpolation3() throws SolverException, InterruptedExceptio List itps = stack.getTreeInterpolants( ImmutableList.of(TB, TC, TR1, TD, TR2), // post-order - new int[]{0, 1, 0, 3, 0}); // left-most node in current subtree + new int[] {0, 1, 0, 3, 0}); // left-most node in current subtree assertThat(itps).hasSize(4); @@ -806,7 +801,7 @@ public void treeInterpolation4() throws SolverException, InterruptedExceptio List itps = stack.getTreeInterpolants0( ImmutableList.of(TbEquals1, TcEquals2, TbPlusCEqualsA, TaEquals9), // post-order - new int[]{0, 1, 0, 0}); // left-most node in current subtree + new int[] {0, 1, 0, 0}); // left-most node in current subtree assertThat(itps).hasSize(3); @@ -839,7 +834,7 @@ public void treeInterpolationForSequence() throws SolverException, Interrupt assertThat(stack).isUnsatisfiable(); - List itp = stack.getTreeInterpolants0(formulas, new int[]{0, 0}); + List itp = stack.getTreeInterpolants0(formulas, new int[] {0, 0}); assertThat(itp).hasSize(1); } @@ -879,7 +874,7 @@ public void treeInterpolationBranching() throws SolverException, Interrupted assertThat(stack).isUnsatisfiable(); - List itp = stack.getTreeInterpolants0(formulas, new int[]{0, 1, 2, 3, 4, 0}); + List itp = stack.getTreeInterpolants0(formulas, new int[] {0, 1, 2, 3, 4, 0}); assertThat(itp).hasSize(5); } @@ -896,7 +891,7 @@ public void treeInterpolationMalFormed1() throws SolverException, Interrupte assertThrows( IllegalArgumentException.class, - () -> stack.getTreeInterpolants(ImmutableList.of(TA), new int[]{0, 0})); + () -> stack.getTreeInterpolants(ImmutableList.of(TA), new int[] {0, 0})); } @Test @@ -912,7 +907,7 @@ public void treeInterpolationMalFormed2() throws SolverException, Interrupte assertThrows( IllegalArgumentException.class, - () -> stack.getTreeInterpolants(ImmutableList.of(TA), new int[]{4})); + () -> stack.getTreeInterpolants(ImmutableList.of(TA), new int[] {4})); } @Test @@ -928,7 +923,7 @@ public void treeInterpolationMalFormed3() throws SolverException, Interrupte assertThrows( IllegalArgumentException.class, - () -> stack.getTreeInterpolants(ImmutableList.of(TA, TA), new int[]{1, 0})); + () -> stack.getTreeInterpolants(ImmutableList.of(TA, TA), new int[] {1, 0})); } @Test @@ -943,7 +938,7 @@ public void treeInterpolationMalFormed4() throws SolverException, Interrupte assertThrows( IllegalArgumentException.class, - () -> stack.getTreeInterpolants0(ImmutableList.of(TA, TA, TA), new int[]{0, 1, 1})); + () -> stack.getTreeInterpolants0(ImmutableList.of(TA, TA, TA), new int[] {0, 1, 1})); } @Test @@ -958,7 +953,7 @@ public void treeInterpolationMalFormed5() throws SolverException, Interrupte assertThrows( IllegalArgumentException.class, - () -> stack.getTreeInterpolants0(ImmutableList.of(TA, TA, TA), new int[]{0, 1, 2})); + () -> stack.getTreeInterpolants0(ImmutableList.of(TA, TA, TA), new int[] {0, 1, 2})); } @Test @@ -973,7 +968,7 @@ public void treeInterpolationMalFormed6() throws SolverException, Interrupte assertThrows( IllegalArgumentException.class, - () -> stack.getTreeInterpolants0(ImmutableList.of(TA, TA, TA), new int[]{0, 2, 0})); + () -> stack.getTreeInterpolants0(ImmutableList.of(TA, TA, TA), new int[] {0, 2, 0})); } @Test @@ -988,7 +983,7 @@ public void treeInterpolationWithoutPartition() throws SolverException, Inte // empty list of partition assertThrows( IllegalArgumentException.class, - () -> stack.getTreeInterpolants(ImmutableList.of(), new int[]{})); + () -> stack.getTreeInterpolants(ImmutableList.of(), new int[] {})); } @Test @@ -1015,7 +1010,7 @@ public void treeInterpolationWithOnePartition() throws SolverException, Inte // list of one partition List partition = ImmutableList.of(TA, TB); List itps = - stack.getTreeInterpolants(ImmutableList.of(partition), new int[]{0}); + stack.getTreeInterpolants(ImmutableList.of(partition), new int[] {0}); assertThat(itps).isEmpty(); } @@ -1124,7 +1119,7 @@ private void checkItpSequence(List formulas, List * - *

- * {@link #assertThatFormula(BooleanFormula)} can be used to easily write assertions about formulas - * using Truth. + * + *

{@link #assertThatFormula(BooleanFormula)} can be used to easily write assertions about + * formulas using Truth. * *

Test that rely on a theory that not all solvers support should call one of the {@code require} * methods at the beginning. @@ -129,9 +130,7 @@ protected Solvers solverToUse() { return Solvers.SMTINTERPOL; } - /** - * This method is only called, if OpenSMT is called. OpenSMT needs to know the logic upfront. - */ + /** This method is only called, if OpenSMT is called. OpenSMT needs to know the logic upfront. */ protected Logics logicToUse() { return Logics.QF_AUFLIRA; } @@ -146,8 +145,10 @@ protected ConfigurationBuilder createTestConfigBuilder() { } private static final ImmutableList INDEPENDENT_INTERPOLATION_STRATEGIES = - ImmutableList.of(GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, - GENERATE_PROJECTION_BASED_INTERPOLANTS, GENERATE_UNIFORM_FORWARD_INTERPOLANTS); + ImmutableList.of( + GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, + GENERATE_PROJECTION_BASED_INTERPOLANTS, + GENERATE_UNIFORM_FORWARD_INTERPOLANTS); @Before public final void initSolver() throws InvalidConfigurationException { @@ -157,7 +158,10 @@ public final void initSolver() throws InvalidConfigurationException { try { context = factory.generateContext(); } catch (InvalidConfigurationException e) { - assume().withMessage(e.getMessage()).that(e).hasCauseThat() + assume() + .withMessage(e.getMessage()) + .that(e) + .hasCauseThat() .isNotInstanceOf(UnsatisfiedLinkError.class); throw e; } @@ -220,39 +224,44 @@ public final void closeSolver() { } } - /** - * Skip test if the solver does not support integers. - */ + /** Skip test if the solver does not support integers. */ protected final void requireIntegers() { - assume().withMessage("Solver %s does not support the theory of integers", solverToUse()) - .that(imgr).isNotNull(); + assume() + .withMessage("Solver %s does not support the theory of integers", solverToUse()) + .that(imgr) + .isNotNull(); } - /** - * Skip test if the solver does not support rationals. - */ + /** Skip test if the solver does not support rationals. */ protected final void requireRationals() { - assume().withMessage("Solver %s does not support the theory of rationals", solverToUse()) - .that(rmgr).isNotNull(); + assume() + .withMessage("Solver %s does not support the theory of rationals", solverToUse()) + .that(rmgr) + .isNotNull(); } protected final void requireRationalFloor() { - assume().withMessage("Solver %s does not support floor for rationals", solverToUse()) - .that(solverToUse()).isNotEqualTo(Solvers.OPENSMT); + assume() + .withMessage("Solver %s does not support floor for rationals", solverToUse()) + .that(solverToUse()) + .isNotEqualTo(Solvers.OPENSMT); } - /** - * Skip test if the solver does not support bitvectors. - */ + /** Skip test if the solver does not support bitvectors. */ protected final void requireBitvectors() { - assume().withMessage("Solver %s does not support the theory of bitvectors", solverToUse()) - .that(bvmgr).isNotNull(); + assume() + .withMessage("Solver %s does not support the theory of bitvectors", solverToUse()) + .that(bvmgr) + .isNotNull(); } protected final void requireBitvectorToInt() { - assume().withMessage( - "Solver %s does not yet support the conversion between bitvectors and integers", - solverToUse()).that(solverToUse()).isNotEqualTo(Solvers.YICES2); + assume() + .withMessage( + "Solver %s does not yet support the conversion between bitvectors and integers", + solverToUse()) + .that(solverToUse()) + .isNotEqualTo(Solvers.YICES2); } @SuppressWarnings("CheckReturnValue") @@ -261,119 +270,175 @@ protected final void requireFPToBitvector() { try { fpmgr.toIeeeBitvector(fpmgr.makeNumber(0, getSinglePrecisionFloatingPointType())); } catch (UnsupportedOperationException e) { - assume().withMessage("Solver %s does not yet support FP-to-BV conversion", solverToUse()) - .that(solverToUse()).isNull(); + assume() + .withMessage("Solver %s does not yet support FP-to-BV conversion", solverToUse()) + .that(solverToUse()) + .isNull(); } } - /** - * Skip test if the solver does not support quantifiers. - */ + /** Skip test if the solver does not support quantifiers. */ protected final void requireQuantifiers() { - assume().withMessage("Solver %s does not support quantifiers", solverToUse()).that(qmgr) + assume() + .withMessage("Solver %s does not support quantifiers", solverToUse()) + .that(qmgr) .isNotNull(); } @SuppressWarnings("unused") protected final void requireQuantifierElimination() { requireQuantifiers(); - assume().withMessage("Solver %s does not support quantifier elimination", solverToUse()) + assume() + .withMessage("Solver %s does not support quantifier elimination", solverToUse()) .that(solverToUse()) .isNoneOf(Solvers.BOOLECTOR, Solvers.MATHSAT5, Solvers.YICES2, Solvers.BITWUZLA); } - /** - * Skip test if the solver does not support arrays. - */ + /** Skip test if the solver does not support arrays. */ protected final void requireArrays() { - assume().withMessage("Solver %s does not support the theory of arrays", solverToUse()) - .that(amgr).isNotNull(); + assume() + .withMessage("Solver %s does not support the theory of arrays", solverToUse()) + .that(amgr) + .isNotNull(); } protected final void requireFloats() { - assume().withMessage("Solver %s does not support the theory of floats", solverToUse()) - .that(fpmgr).isNotNull(); + assume() + .withMessage("Solver %s does not support the theory of floats", solverToUse()) + .that(fpmgr) + .isNotNull(); } - /** - * Skip test if the solver does not support strings. - */ + /** Skip test if the solver does not support strings. */ protected final void requireStrings() { - assume().withMessage("Solver %s does not support the theory of strings", solverToUse()) - .that(smgr).isNotNull(); - assume().withMessage("Solver %s does not support the theory of arrays", solverToUse()) - .that(amgr).isNotNull(); + assume() + .withMessage("Solver %s does not support the theory of strings", solverToUse()) + .that(smgr) + .isNotNull(); + assume() + .withMessage("Solver %s does not support the theory of arrays", solverToUse()) + .that(amgr) + .isNotNull(); } - /** - * Skip test if the solver does not support enumeration theory. - */ + /** Skip test if the solver does not support enumeration theory. */ protected final void requireEnumeration() { - assume().withMessage("Solver %s does not support the theory of enumerations", solverToUse()) - .that(emgr).isNotNull(); + assume() + .withMessage("Solver %s does not support the theory of enumerations", solverToUse()) + .that(emgr) + .isNotNull(); } protected final void requireSeparationLogic() { - assume().withMessage("Solver %s does not support the theory of separation logic", solverToUse()) - .that(slmgr).isNotNull(); + assume() + .withMessage("Solver %s does not support the theory of separation logic", solverToUse()) + .that(slmgr) + .isNotNull(); } - /** - * Skip test if the solver does not support optimization. - */ + /** Skip test if the solver does not support optimization. */ protected final void requireOptimization() { try { context.newOptimizationProverEnvironment().close(); } catch (UnsupportedOperationException e) { - assume().withMessage("Solver %s does not support optimization", solverToUse()).that(e) + assume() + .withMessage("Solver %s does not support optimization", solverToUse()) + .that(e) .isNull(); } } protected final void requireInterpolation(ProverOptions... options) { + List optionList = + (options == null) ? Collections.emptyList() : Arrays.asList(options); + if (optionList.contains(null)) { + assume() + .withMessage("Solver %s does not support native interpolation", solverToUse()) + .that(solverToUse()) + .isAnyOf( + Solvers.SMTINTERPOL, + Solvers.PRINCESS, + Solvers.OPENSMT, + Solvers.MATHSAT5, + Solvers.BOOLECTOR, + Solvers.CVC4, + Solvers.CVC5, + Solvers.BITWUZLA, + Solvers.YICES2); + } else if (optionList.contains(GENERATE_PROJECTION_BASED_INTERPOLANTS)) { + assume() + .withMessage("Only Z3 is enabled for projection-based interpolation") + .that(solverToUse()) + .isEqualTo(Solvers.Z3); + } else if (optionList.contains(GENERATE_UNIFORM_FORWARD_INTERPOLANTS) + || optionList.contains(GENERATE_UNIFORM_BACKWARD_INTERPOLANTS)) { + assume() + .withMessage("Solver %s does not support Quantifier Elimination", solverToUse()) + .that(solverToUse()) + .isNoneOf(Solvers.OPENSMT, Solvers.SMTINTERPOL); + } try { - if (Arrays.stream(options).anyMatch(p -> p == null)) { - if (solverToUse() == Solvers.Z3) { - throw new UnsupportedOperationException(); - } + if (optionList.contains(null)) { context.newProverEnvironmentWithInterpolation().close(); } else { context.newProverEnvironmentWithInterpolation(options).close(); } } catch (UnsupportedOperationException e) { - assume().withMessage("Solver %s does not support interpolation", solverToUse()).that(e) + assume() + .withMessage( + "Solver %s threw UnsupportedOperationException for options %s", + solverToUse(), Arrays.toString(options)) + .that(e) .isNull(); } } protected final void requireSeqItp(ProverOptions... options) { - assume().withMessage("Solver independent interpolation strategy %s does not support sequential " - + "interpolation", solverToUse()).that(options).asList() + assume() + .withMessage( + "Solver independent interpolation strategy %s does not support sequential " + + "interpolation", + solverToUse()) + .that(options) + .asList() .containsNoneIn(INDEPENDENT_INTERPOLATION_STRATEGIES); } protected final void requireTreeItp(ProverOptions... options) { requireInterpolation(); - assume().withMessage("Solver independent interpolation strategy %s does not support tree " - + "interpolation", solverToUse()).that(options).asList() + assume() + .withMessage( + "Solver independent interpolation strategy %s does not support tree " + "interpolation", + solverToUse()) + .that(options) + .asList() .containsNoneIn(INDEPENDENT_INTERPOLATION_STRATEGIES); - assume().withMessage("Solver does not support tree-interpolation.").that(solverToUse()) + assume() + .withMessage("Solver does not support tree-interpolation.") + .that(solverToUse()) .isAnyOf(Solvers.SMTINTERPOL, Solvers.PRINCESS); - assume().withMessage("Strategy %s does not support tree interpolation", + assume() + .withMessage( + "Strategy %s does not support tree interpolation", Arrays.toString(options)) // Optional: print the options for clarity - .that(options).asList().containsNoneIn(INDEPENDENT_INTERPOLATION_STRATEGIES); + .that(options) + .asList() + .containsNoneIn(INDEPENDENT_INTERPOLATION_STRATEGIES); } protected void requireParser() { - assume().withMessage("Solver %s does not support parsing formulae", solverToUse()) + assume() + .withMessage("Solver %s does not support parsing formulae", solverToUse()) .that(solverToUse()) .isNoneOf(Solvers.CVC4, Solvers.BOOLECTOR, Solvers.YICES2, Solvers.CVC5); } protected void requireArrayModel() { - assume().withMessage("Solver %s does not support model generation for arrays", solverToUse()) - .that(solverToUse()).isNotEqualTo(Solvers.OPENSMT); + assume() + .withMessage("Solver %s does not support model generation for arrays", solverToUse()) + .that(solverToUse()) + .isNotEqualTo(Solvers.OPENSMT); } protected void requireModel() { @@ -384,28 +449,38 @@ protected void requireModel() { } protected void requireVisitor() { - assume().withMessage("Solver %s does not support formula visitor", solverToUse()) - .that(solverToUse()).isNotEqualTo(Solvers.BOOLECTOR); + assume() + .withMessage("Solver %s does not support formula visitor", solverToUse()) + .that(solverToUse()) + .isNotEqualTo(Solvers.BOOLECTOR); } protected void requireUnsatCore() { - assume().withMessage("Solver %s does not support unsat core generation", solverToUse()) - .that(solverToUse()).isNotEqualTo(Solvers.BOOLECTOR); + assume() + .withMessage("Solver %s does not support unsat core generation", solverToUse()) + .that(solverToUse()) + .isNotEqualTo(Solvers.BOOLECTOR); } protected void requireUnsatCoreOverAssumptions() { - assume().withMessage("Solver %s does not support unsat core generation", solverToUse()) - .that(solverToUse()).isNotEqualTo(Solvers.PRINCESS); + assume() + .withMessage("Solver %s does not support unsat core generation", solverToUse()) + .that(solverToUse()) + .isNotEqualTo(Solvers.PRINCESS); } protected void requireSubstitution() { - assume().withMessage("Solver %s does not support formula substitution", solverToUse()) - .that(solverToUse()).isNotEqualTo(Solvers.BOOLECTOR); + assume() + .withMessage("Solver %s does not support formula substitution", solverToUse()) + .that(solverToUse()) + .isNotEqualTo(Solvers.BOOLECTOR); } protected void requireUserPropagators() { - assume().withMessage("Solver %s does not support user propagation", solverToUse()) - .that(solverToUse()).isEqualTo(Solvers.Z3); + assume() + .withMessage("Solver %s does not support user propagation", solverToUse()) + .that(solverToUse()) + .isEqualTo(Solvers.Z3); } /** @@ -416,22 +491,19 @@ protected final BooleanFormulaSubject assertThatFormula(BooleanFormula formula) return assertUsing(context).that(formula); } - /** - * Check that the interpolant in the subject is valid fot the formulas A and B. - */ + /** Check that the interpolant in the subject is valid fot the formulas A and B. */ public void isValidInterpolant(BooleanFormula interpolant, BooleanFormula a, BooleanFormula b) throws SolverException, InterruptedException { // TODO: move into assertion framework isValidInterpolant(interpolant, ImmutableList.of(a), ImmutableList.of(b)); } - /** - * Check that the interpolant in the subject is valid fot the formulas A and B. - */ + /** Check that the interpolant in the subject is valid fot the formulas A and B. */ public void isValidInterpolant( BooleanFormula interpolant, List formulasOfA, - List formulasOfB) throws SolverException, InterruptedException { + List formulasOfB) + throws SolverException, InterruptedException { // TODO: move into assertion framework BooleanFormula conjugatedFormulasOfA = bmgr.and(formulasOfA); @@ -443,7 +515,8 @@ public void isValidInterpolant( Set interpolBSymbols = mgr.extractVariablesAndUFs(conjugatedFormulasOfB).keySet(); Set intersection = Sets.intersection(interpolASymbols, interpolBSymbols); // TODO: assertThat is not available with message - checkState(intersection.containsAll(interpolantSymbols), + checkState( + intersection.containsAll(interpolantSymbols), "Interpolant contains symbols %s that are not part of both input formula groups A and B.", Sets.difference(interpolantSymbols, intersection)); @@ -451,14 +524,16 @@ public void isValidInterpolant( validationProver.push(); validationProver.addConstraint(bmgr.implication(conjugatedFormulasOfA, interpolant)); // TODO: assertThat is not available with message - checkState(!validationProver.isUnsat(), + checkState( + !validationProver.isUnsat(), "Invalid Craig interpolation: formula group A does not imply the interpolant."); validationProver.pop(); validationProver.push(); validationProver.addConstraint(bmgr.and(interpolant, conjugatedFormulasOfB)); // TODO: assertThat is not available with message - checkState(validationProver.isUnsat(), + checkState( + validationProver.isUnsat(), "Invalid Craig interpolation: interpolant does not contradict formula group B."); validationProver.pop(); } @@ -479,7 +554,8 @@ protected void evaluateInModel( BooleanFormula constraint, Formula formula, Collection possibleExpectedValues, - Collection possibleExpectedFormulas) throws SolverException, InterruptedException { + Collection possibleExpectedFormulas) + throws SolverException, InterruptedException { try (ProverEnvironment prover = context.newProverEnvironment(ProverOptions.GENERATE_MODELS)) { prover.push(constraint); @@ -544,17 +620,19 @@ public abstract static class ParameterizedInterpolatingSolverBasedTest0 // GENERATE_MODELS as stand-in for native private static final Set ALL_INTERPOLATION_STRATEGIES = - ImmutableSet.of(GENERATE_PROJECTION_BASED_INTERPOLANTS, - GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, GENERATE_UNIFORM_FORWARD_INTERPOLANTS); + ImmutableSet.of( + GENERATE_PROJECTION_BASED_INTERPOLANTS, + GENERATE_UNIFORM_BACKWARD_INTERPOLANTS, + GENERATE_UNIFORM_FORWARD_INTERPOLANTS); @Parameters(name = "solver {0} with interpolation strategy {1}") public static List getAllSolversAndItpStrategies() { List lst = new ArrayList<>(); for (Solvers solver : Solvers.values()) { // No arg for no option (== solver native interpolation) - lst.add(new Object[]{solver, null}); + lst.add(new Object[] {solver, null}); for (ProverOptions itpStrat : ALL_INTERPOLATION_STRATEGIES) { - lst.add(new Object[]{solver, itpStrat}); + lst.add(new Object[] {solver, itpStrat}); } } return lst; From a587a83b03fc2d48a032469a44e742f74932c7ef Mon Sep 17 00:00:00 2001 From: Julius Brehme Date: Sat, 20 Dec 2025 17:30:42 +0100 Subject: [PATCH 17/20] updated example for indepented interpolation --- .../example/IndependentInterpolation.java | 71 ++++++------------- 1 file changed, 21 insertions(+), 50 deletions(-) diff --git a/src/org/sosy_lab/java_smt/example/IndependentInterpolation.java b/src/org/sosy_lab/java_smt/example/IndependentInterpolation.java index 9be329d8b2..eea70c62ab 100644 --- a/src/org/sosy_lab/java_smt/example/IndependentInterpolation.java +++ b/src/org/sosy_lab/java_smt/example/IndependentInterpolation.java @@ -10,11 +10,8 @@ package org.sosy_lab.java_smt.example; -import static org.sosy_lab.java_smt.test.ProverEnvironmentSubject.assertThat; - import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; -import java.util.List; import java.util.logging.Level; import org.sosy_lab.common.ShutdownNotifier; import org.sosy_lab.common.configuration.Configuration; @@ -32,21 +29,29 @@ import org.sosy_lab.java_smt.api.SolverContext.ProverOptions; import org.sosy_lab.java_smt.api.SolverException; -public class IndependentInterpolation { +public final class IndependentInterpolation { + + private IndependentInterpolation() { + // never called + } public static void main(String[] args) throws InvalidConfigurationException, SolverException, InterruptedException { + // set up a basic environment Configuration config = Configuration.defaultConfiguration(); LogManager logger = BasicLogManager.create(config); ShutdownNotifier notifier = ShutdownNotifier.createDummy(); + // choose solver Solvers solver = Solvers.Z3; + // setup context try (SolverContext context = SolverContextFactory.createSolverContext(config, logger, notifier, solver); InterpolatingProverEnvironment prover = - context.newProverEnvironmentWithInterpolation(ProverOptions.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS)) { + context.newProverEnvironmentWithInterpolation( + ProverOptions.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS)) { logger.log(Level.WARNING, "Using solver " + solver + " in version " + context.getVersion()); BooleanFormulaManager bmgr = context.getFormulaManager().getBooleanFormulaManager(); @@ -57,6 +62,11 @@ public static void main(String[] args) interpolateExample(prover, bmgr, imgr, logger); prover.pop(); + // another example + prover.push(); + interpolateExample2(prover, bmgr, imgr, logger); + prover.pop(); + } catch (InvalidConfigurationException | UnsatisfiedLinkError e) { // on some machines we support only some solvers, @@ -79,7 +89,6 @@ private static void interpolateExample( // B: y = z && z = 2 // -> y = 1, y != 2 - // create some variables IntegerFormula x = imgr.makeVariable("x"); IntegerFormula y = imgr.makeVariable("y"); @@ -89,14 +98,9 @@ private static void interpolateExample( // create and assert some formulas // instead of 'named' formulas, we return a 'handle' (of generic type T) - - T ip0 = - prover.push( - bmgr.and( - imgr.equal(y, z), imgr.equal(z, two) - )); - T ip1 = prover.push(bmgr.and(imgr.equal(x, one), imgr.equal(y, x))); - + @SuppressWarnings("unused") + T ip0 = prover.addConstraint(bmgr.and(imgr.equal(y, z), imgr.equal(z, two))); + T ip1 = prover.addConstraint(bmgr.and(imgr.equal(x, one), imgr.equal(y, x))); // check for satisfiability boolean unsat = prover.isUnsat(); @@ -123,10 +127,9 @@ private static void interpolateExample2( IntegerFormula one = imgr.makeNumber(1); IntegerFormula zero = imgr.makeNumber(0); - T ip0 = - prover.push(imgr.lessThan(y, zero)); - T ip1 = prover.push(bmgr.and(imgr.greaterThan(x, zero), imgr.equal(y, imgr.add(x, one)))); - + @SuppressWarnings("unused") + T ip0 = prover.addConstraint(imgr.lessThan(y, zero)); + T ip1 = prover.addConstraint(bmgr.and(imgr.greaterThan(x, zero), imgr.equal(y, imgr.add(x, one)))); // check for satisfiability boolean unsat = prover.isUnsat(); @@ -135,36 +138,4 @@ private static void interpolateExample2( BooleanFormula itp = prover.getInterpolant(ImmutableList.of(ip1)); logger.log(Level.INFO, "Interpolants are:", itp); } - - private static void interpolateExample3( - InterpolatingProverEnvironment prover, - BooleanFormulaManager bmgr, - IntegerFormulaManager imgr, - LogManager logger) - throws InterruptedException, SolverException { - - IntegerFormula zero = imgr.makeNumber(0); - IntegerFormula one = imgr.makeNumber(1); - IntegerFormula thousand = imgr.makeNumber(1000); - - IntegerFormula i3 = imgr.makeVariable("i3"); - IntegerFormula i4 = imgr.makeVariable("i4"); - - BooleanFormula A = imgr.equal(i3, zero); - BooleanFormula B = bmgr.and(imgr.lessThan(i3, thousand), imgr.equal(i4, imgr.add(i3, one))); - BooleanFormula C = imgr.greaterThan(i4, thousand); - - T TA = prover.push(A); - T TB = prover.push(B); - T TC = prover.push(C); - - assertThat(prover).isUnsatisfiable(); - - List itpSeq = prover.getSeqInterpolants0(ImmutableList.of(TA, TB, TC)); - - BooleanFormula itp1 = prover.getInterpolant(ImmutableList.of(TA)); - BooleanFormula itp2 = prover.getInterpolant(ImmutableList.of(TA, TB)); - } } - - From 70ccc55e10ed5b8be941a5e870314016476de1c1 Mon Sep 17 00:00:00 2001 From: Julius Brehme Date: Sat, 20 Dec 2025 17:55:19 +0100 Subject: [PATCH 18/20] updated requireInterpolation --- src/org/sosy_lab/java_smt/test/SolverBasedTest0.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java b/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java index c659a68456..31975367db 100644 --- a/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java +++ b/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java @@ -361,10 +361,8 @@ protected final void requireInterpolation(ProverOptions... options) { Solvers.OPENSMT, Solvers.MATHSAT5, Solvers.BOOLECTOR, - Solvers.CVC4, Solvers.CVC5, - Solvers.BITWUZLA, - Solvers.YICES2); + Solvers.BITWUZLA); } else if (optionList.contains(GENERATE_PROJECTION_BASED_INTERPOLANTS)) { assume() .withMessage("Only Z3 is enabled for projection-based interpolation") @@ -375,7 +373,7 @@ protected final void requireInterpolation(ProverOptions... options) { assume() .withMessage("Solver %s does not support Quantifier Elimination", solverToUse()) .that(solverToUse()) - .isNoneOf(Solvers.OPENSMT, Solvers.SMTINTERPOL); + .isNoneOf(Solvers.OPENSMT, Solvers.SMTINTERPOL, Solvers.YICES2); } try { if (optionList.contains(null)) { From d20c5f84a156be050e75e1335e5dbd3bea29ee74 Mon Sep 17 00:00:00 2001 From: Julius Brehme Date: Sat, 20 Dec 2025 17:55:36 +0100 Subject: [PATCH 19/20] updated to resolve spotbugs --- .../example/IndependentInterpolation.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/org/sosy_lab/java_smt/example/IndependentInterpolation.java b/src/org/sosy_lab/java_smt/example/IndependentInterpolation.java index eea70c62ab..e802219603 100644 --- a/src/org/sosy_lab/java_smt/example/IndependentInterpolation.java +++ b/src/org/sosy_lab/java_smt/example/IndependentInterpolation.java @@ -48,10 +48,10 @@ public static void main(String[] args) // setup context try (SolverContext context = - SolverContextFactory.createSolverContext(config, logger, notifier, solver); - InterpolatingProverEnvironment prover = - context.newProverEnvironmentWithInterpolation( - ProverOptions.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS)) { + SolverContextFactory.createSolverContext(config, logger, notifier, solver); + InterpolatingProverEnvironment prover = + context.newProverEnvironmentWithInterpolation( + ProverOptions.GENERATE_UNIFORM_BACKWARD_INTERPOLANTS)) { logger.log(Level.WARNING, "Using solver " + solver + " in version " + context.getVersion()); BooleanFormulaManager bmgr = context.getFormulaManager().getBooleanFormulaManager(); @@ -98,8 +98,7 @@ private static void interpolateExample( // create and assert some formulas // instead of 'named' formulas, we return a 'handle' (of generic type T) - @SuppressWarnings("unused") - T ip0 = prover.addConstraint(bmgr.and(imgr.equal(y, z), imgr.equal(z, two))); + prover.addConstraint(bmgr.and(imgr.equal(y, z), imgr.equal(z, two))); T ip1 = prover.addConstraint(bmgr.and(imgr.equal(x, one), imgr.equal(y, x))); // check for satisfiability @@ -127,9 +126,9 @@ private static void interpolateExample2( IntegerFormula one = imgr.makeNumber(1); IntegerFormula zero = imgr.makeNumber(0); - @SuppressWarnings("unused") - T ip0 = prover.addConstraint(imgr.lessThan(y, zero)); - T ip1 = prover.addConstraint(bmgr.and(imgr.greaterThan(x, zero), imgr.equal(y, imgr.add(x, one)))); + prover.addConstraint(imgr.lessThan(y, zero)); + T ip1 = + prover.addConstraint(bmgr.and(imgr.greaterThan(x, zero), imgr.equal(y, imgr.add(x, one)))); // check for satisfiability boolean unsat = prover.isUnsat(); From a29d671462c590185cade35ec7a8a294e76939c3 Mon Sep 17 00:00:00 2001 From: Julius Brehme Date: Sat, 20 Dec 2025 18:33:10 +0100 Subject: [PATCH 20/20] added supresswarning for building project successfully --- src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java b/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java index e06ee03e37..ae367bce61 100644 --- a/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java +++ b/src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java @@ -67,7 +67,7 @@ public final InterpolatingProverEnvironment newProverEnvironmentWithInterpola return out; } - @SuppressWarnings("ResultOfMethodCallIgnored") + @SuppressWarnings({"ResultOfMethodCallIgnored", "resource"}) private InterpolatingProverEnvironment newProverEnvironmentWithInterpolation1( Set options) { InterpolatingProverEnvironment out;