Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
733d43b
Add general implementation for retrieving the 2 interpolation groups …
baierd Apr 7, 2025
8d35e69
Add the new interpolation options to the ProverOptions
baierd Apr 7, 2025
eab70d4
Add a prover delegate for solver-independent interpolation to Prover …
baierd Apr 16, 2025
4d77924
Add options enum for interpolation
baierd May 16, 2025
e2119ad
Extend parameterized tests with possibility for second parameter for …
baierd May 16, 2025
f9d735c
Remove options for interpolation from ProverOptions
baierd May 16, 2025
8f87aec
Add InterpolatingProverDelegate that allows to use interpolation API …
baierd May 16, 2025
a4769a4
Add IndependentInterpolatingSolverDelegate that allows to use indepen…
baierd May 16, 2025
993f400
Merge branch 'master' into solver_independent_interpolation2_arm64
juliusbrehme Nov 23, 2025
c256db9
First changes to get the independent interpolation method working
juliusbrehme Nov 28, 2025
d78e284
added requirements for tests
juliusbrehme Dec 13, 2025
23ae59a
small fixes for independent interpolation
juliusbrehme Dec 13, 2025
2404f5c
update independent interpolation logic and tests
juliusbrehme Dec 14, 2025
05864d6
Remove redundant variable present in super class in ParameterizedInte…
baierd Dec 18, 2025
a8eb472
Add TODO about restricting independent interpolation solver creation
baierd Dec 18, 2025
9d74f92
add comments for interpolation options
juliusbrehme Dec 20, 2025
a3e98de
updated code style
juliusbrehme Dec 20, 2025
a587a83
updated example for indepented interpolation
juliusbrehme Dec 20, 2025
70ccc55
updated requireInterpolation
juliusbrehme Dec 20, 2025
d20c5f8
updated to resolve spotbugs
juliusbrehme Dec 20, 2025
a29d671
added supresswarning for building project successfully
juliusbrehme Dec 20, 2025
74424f6
add trivial test for independent interpolation
juliusbrehme Dec 27, 2025
89acfea
update requireInterpolation
juliusbrehme Dec 27, 2025
6d7d488
use class variable
juliusbrehme Dec 27, 2025
2fa4562
remove isTrivialFalse
juliusbrehme Dec 27, 2025
56168b4
Add CVC4 to interpolation test for invalid tokens, as it supports ind…
baierd Jan 29, 2026
788b408
Extend PackageSanityTest for basicimpl package with a default SolverC…
baierd Jan 29, 2026
52e6134
us Immutablelist instead of Collection
juliusbrehme Jan 31, 2026
e4f245c
resolve checkstyle and check-format
juliusbrehme Jan 31, 2026
316b747
Merge branch 'master' into solver_independent_interpolation2_arm64
juliusbrehme Jan 31, 2026
4b04456
format code
juliusbrehme Jan 31, 2026
995fa72
resolved some comments from the pull request
juliusbrehme Jan 31, 2026
d2601d6
Merge branch 'solver_independent_interpolation2_arm64' of github.com:…
juliusbrehme Jan 31, 2026
82b5d78
Merge branch 'master' of github.com:sosy-lab/java-smt into solver_ind…
juliusbrehme Feb 6, 2026
02ce3f3
Refactor independent interpolation logic into separate strategy classes
juliusbrehme Feb 17, 2026
9abf0e0
delete unused import and use logger.logf in example
juliusbrehme Feb 17, 2026
2bfbe5d
Add isValidInterpolant assertion to BooleanFormulaSubject
juliusbrehme Feb 17, 2026
64c13db
add assertThat
juliusbrehme Feb 17, 2026
a4fd707
Correct invalid usage of logf in IndependentInterpolation example
juliusbrehme Feb 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
* @param <T> The type of the objects which can be used to select formulas for interpolant creation.
*/
public interface InterpolatingProverEnvironment<T> extends BasicProverEnvironment<T> {

/**
* Get an interpolant for two groups of formulas. This should be called only immediately after an
* {@link #isUnsat()} call that returned <code>true</code>.
Expand Down
33 changes: 31 additions & 2 deletions src/org/sosy_lab/java_smt/api/SolverContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kfriedberger @PhilippWendler do you guys have feedback/ideas/proposals for how we want the user to be able to switch in between native and solver independent interpolation techniques? Currently we just ProverOptions, which is not ideal, as they can't be switched once a prover has been created.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would I want to switch the interpolation implementation for a prover instance and why would it be a problem to create a new prover instance instead? I don't really see a use case.

What I am interested in is to have the following 3 possibilities:

  1. create an interpolating prover that guarantees that native solver interpolation is used (and creation fails if this is not possible)
  2. create an interpolating prover that always uses the specific strategy implemented here
  3. create an interpolating prover that prefers the solver native interpolation but falls back to a general implementation if the solver does not support interpolation

The third method could be done by catching the exception from the first case, but why not let JavaSMT provide it as well for the benefit of all its users?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK that seems reasonable.

I thought it might be good to decide about a interpolation technique when asking for interpolants, as users can implement point 3 themselves (potentially even with more than one fallback.

Also interpolation is (usually) only possible after UNSAT has been returned. If a user wants to generate interpolants with multiple techniques in sequence, that would not be possible. E.g.: start with a technique like projection based interpolants that tends to return interpolants fast, but they also tend to be weak -> then use a stronger technique if that first interpolant is not useful. In your approach, a user would need to build a second (or n) new provers and then check satisfiability again.

(Just some thoughts. I want to provide the best possible API. I don't have a preference at the moment.)

@leventeBajczi you also use interpolation, maybe you have some thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really have any further input to this -- as long as it's clear how I'm getting the interpolants, I don't mind if I need to create separate solver instances. We would probably always use point 3 if it was available, especially if it also handled the case when a solver returns an error for the interpolation query (although I'm not sure if the resulting solver state always stays usable). Failing that, we already have some support for using a portfolio of solvers, so we could easily implement the switching ourselves.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might not be a good idea to add options that are only relevant for interpolating provers to the general ProverOptions class? What happens if I create a regular prover environment and tell it to generate interpolants?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this as a quick dummy. Hence the question about how we want to do it properly ;D


/**
* 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
}

/**
Expand All @@ -68,7 +98,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
Expand Down
50 changes: 50 additions & 0 deletions src/org/sosy_lab/java_smt/basicimpl/AbstractProver.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
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;
Expand Down Expand Up @@ -227,6 +228,28 @@ protected ImmutableSet<BooleanFormula> 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<T> nativeFormulasOfA) {
ImmutableSet.Builder<BooleanFormula> formulasOfA = ImmutableSet.builder();
ImmutableSet.Builder<BooleanFormula> formulasOfB = ImmutableSet.builder();
for (Multimap<BooleanFormula, T> assertedFormulasPerLevel : assertedFormulas) {
for (Entry<BooleanFormula, T> 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<T> getAssertedConstraintIds() {
ImmutableSet.Builder<T> builder = ImmutableSet.builder();
for (Multimap<BooleanFormula, T> level : assertedFormulas) {
Expand Down Expand Up @@ -276,4 +299,31 @@ public void close() {
closeAllEvaluators();
closed = true;
}

/** Provides the set of BooleanFormulas to interpolate on. */
public static final class InterpolationGroups {
private final Collection<BooleanFormula> formulasOfA;
private final Collection<BooleanFormula> formulasOfB;

private InterpolationGroups(
Collection<BooleanFormula> pFormulasOfA, Collection<BooleanFormula> pFormulasOfB) {
Preconditions.checkNotNull(pFormulasOfA);
Preconditions.checkNotNull(pFormulasOfB);
formulasOfA = pFormulasOfA;
formulasOfB = pFormulasOfB;
}

public static InterpolationGroups of(
Collection<BooleanFormula> pFormulasOfA, Collection<BooleanFormula> pFormulasOfB) {
return new InterpolationGroups(pFormulasOfA, pFormulasOfB);
}

public Collection<BooleanFormula> getFormulasOfA() {
return formulasOfA;
}

public Collection<BooleanFormula> getFormulasOfB() {
return formulasOfB;
}
}
}
68 changes: 67 additions & 1 deletion src/org/sosy_lab/java_smt/basicimpl/AbstractSolverContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@

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;
Expand Down Expand Up @@ -54,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
Expand All @@ -63,6 +67,32 @@ public final InterpolatingProverEnvironment<?> newProverEnvironmentWithInterpola
return out;
}

@SuppressWarnings({"ResultOfMethodCallIgnored", "resource"})
private InterpolatingProverEnvironment<?> newProverEnvironmentWithInterpolation1(
Set<ProverOptions> options) {
InterpolatingProverEnvironment<?> out;
// Try to get a new prover environment w native interpolation with the current options
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);
// TODO: only allow this if there is a quantified formula manager available!
out = new InterpolatingSolverDelegate(normalProver, options);
}

// TODO: do we need the assumptions inside of the interpolation delegate?
return new IndependentInterpolatingSolverDelegate<>(this, out, options);
}

protected abstract InterpolatingProverEnvironment<?> newProverEnvironmentWithInterpolation0(
Set<ProverOptions> pSet);

Expand Down Expand Up @@ -93,6 +123,42 @@ protected abstract OptimizationProverEnvironment newOptimizationProverEnvironmen
*/
protected abstract boolean supportsAssumptionSolving();

private static final Set<ProverOptions> 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<ProverOptions> options) {
return getIndependentInterpolationStrategy(options) == null;
}

@SuppressWarnings("CheckReturnValue")
protected @Nullable ProverOptions getIndependentInterpolationStrategy(
Set<ProverOptions> options) {
List<ProverOptions> 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<ProverOptions> toSet(ProverOptions... options) {
Set<ProverOptions> opts = EnumSet.noneOf(ProverOptions.class);
Collections.addAll(opts, options);
Expand Down
Loading
Loading