Skip to content

Add Proper Yices2 Quantifier Support #447

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 29 commits into from
Apr 15, 2025
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
acaf7da
Rework setup of QuantifierManagerTest so that the setup does not bloc…
Mar 6, 2025
3e318c0
Implement a method for Yices2 that allows the creation of bound varia…
Mar 6, 2025
3d4b036
Rework Yices2 quantifier creation with bound variables
Mar 6, 2025
25be000
Add Yices2 quantifier support in the manager
Mar 6, 2025
64a70f7
Add bound variables to Yices2 visitor
Mar 6, 2025
9a256e9
Disable quantifier tests that Yices2 can't handle
Mar 6, 2025
a787c54
Add visitor case for Yices2 quantifiers
Mar 6, 2025
d84820f
Use full import list instead of * in Yices2FormulaCreator
Mar 6, 2025
efc25cf
Move Yices2 free variable creation method to native test class and di…
Mar 6, 2025
96aeb4d
Move Yices2 free and bound variable creation method to creator and ca…
Mar 6, 2025
ac51adb
Extend native API doc for Yices2
Mar 7, 2025
3f456a8
Refactor Yices2 native tests to assertions from printouts
Mar 7, 2025
5dcc40d
Add Yices2 native tests for quantifiers and thread safety
Mar 7, 2025
6f8c6c6
Add documentation about free/bound variables in the Yices2FormulaCreator
Mar 7, 2025
c08797a
Add more documentation about free/bound variables in the Yices2Formul…
Mar 7, 2025
dbdd97a
Add suppression for warning that a return value is ignored in Yices2 …
Apr 2, 2025
95daa09
Add a visitor test for negated quantifiers to check that they are not…
Apr 3, 2025
fd268cc
Disallow Princess in new quantifier negation visitor test as it does …
Apr 3, 2025
025c460
Merge remote-tracking branch 'origin/master' into fix_yices2_quantifier
kfriedberger Apr 12, 2025
62ab126
Yices: simplify test assumption.
kfriedberger Apr 13, 2025
72728c0
Yices: fix visitor for FORALL and EXISTS.
kfriedberger Apr 13, 2025
fb94b95
fix code style.
kfriedberger Apr 13, 2025
9faf82d
fix code style.
kfriedberger Apr 13, 2025
af010b6
Yices2: simplify conditional checks by using preconditions.
kfriedberger Apr 14, 2025
1a09bf6
Yices2: simplify conditional checks by using preconditions.
kfriedberger Apr 14, 2025
09ac268
improve tests on quantified formulas.
kfriedberger Apr 14, 2025
e700fb7
Yices2 and Z3: provide a clean body for formula-visitor.
kfriedberger Apr 14, 2025
43d0140
Yices2 and Z3: fix array initialization
kfriedberger Apr 14, 2025
fb5d3e5
Z3: fix memory management
kfriedberger Apr 14, 2025
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
89 changes: 86 additions & 3 deletions src/org/sosy_lab/java_smt/solvers/yices2/Yices2FormulaCreator.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_DIVIDES_ATOM;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_EQ_TERM;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_FLOOR;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_FORALL_TERM;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_IDIV;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_IMOD;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_IS_INT_ATOM;
Expand Down Expand Up @@ -81,6 +82,7 @@
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_eq;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_floor;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_function_type;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_get_term_by_name;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_get_term_name;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_idiv;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_imod;
Expand All @@ -89,7 +91,8 @@
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_is_int_atom;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_ite;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_mul;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_named_variable;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_new_uninterpreted_term;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_new_variable;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_not;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_or;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_parse_rational;
Expand All @@ -100,6 +103,7 @@
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_proj_index;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_rational_const_value;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_real_type;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_set_term_name;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_sum;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_sum_component;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_term_bitsize;
Expand All @@ -120,9 +124,11 @@
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.Collections2;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Table;
import com.google.common.primitives.Ints;
import java.math.BigInteger;
import java.util.ArrayList;
Expand All @@ -135,6 +141,7 @@
import org.sosy_lab.java_smt.api.FormulaType;
import org.sosy_lab.java_smt.api.FormulaType.FloatingPointType;
import org.sosy_lab.java_smt.api.FunctionDeclarationKind;
import org.sosy_lab.java_smt.api.QuantifiedFormulaManager.Quantifier;
import org.sosy_lab.java_smt.api.visitors.FormulaVisitor;
import org.sosy_lab.java_smt.basicimpl.FormulaCreator;
import org.sosy_lab.java_smt.basicimpl.FunctionDeclarationImpl;
Expand All @@ -153,6 +160,12 @@ public class Yices2FormulaCreator extends FormulaCreator<Integer, Integer, Long,
YICES_VARIABLE,
YICES_UNINTERPRETED_TERM);

/**
* Maps a name and a free variable or function type to a concrete formula node. We allow only 1
* type per var name, meaning there is only 1 column per row!
*/
private final Table<String, Integer, Integer> formulaCache = HashBasedTable.create();

protected Yices2FormulaCreator() {
super(null, yices_bool_type(), yices_int_type(), yices_real_type(), null, null);
}
Expand All @@ -174,7 +187,7 @@ public Integer getArrayType(Integer pIndexType, Integer pElementType) {

@Override
public Integer makeVariable(Integer pType, String pVarName) {
return yices_named_variable(pType, pVarName);
return createNamedVariable(pType, pVarName);
}

@Override
Expand Down Expand Up @@ -246,6 +259,60 @@ public FormulaType<?> getFormulaType(Integer pFormula) {
yices_type_to_string(yices_type_of_term(pFormula)), yices_term_to_string(pFormula)));
}

/** Creates a named, free variable. Might retrieve it from the cache if created prior. */
protected int createNamedVariable(int type, String name) {
Integer maybeFormula = formulaCache.get(name, type);
if (maybeFormula != null) {
return maybeFormula;
}
if (formulaCache.containsRow(name)) {
throw new IllegalArgumentException(
"Symbol " + name + " already used for a variable of type " + formulaCache.row(name));
}
int var = yices_new_uninterpreted_term(type);
// Names in Yices2 behave like a stack. The last variable named is retrieved when asking for
// a term with a specific name. Since we substitute free vars with bound for quantifiers,
// this sometimes mixes them up, hence we track them ourselves.
yices_set_term_name(var, name);
formulaCache.put(name, type, var);
return var;
}

protected int createBoundVariableFromFreeVariable(int unboundVar) {
int type = yices_type_of_term(unboundVar);
String name = yices_get_term_name(unboundVar);

int termFromName = yices_get_term_by_name(name);
if (termFromName != -1) {
int termFromNameType = yices_type_of_term(termFromName);
if (type == termFromNameType) {
int constructor = yices_term_constructor(termFromName);
if (constructor == YICES_VARIABLE) {
// Already a bound var
return termFromName;
}
} else {
throw new IllegalArgumentException(
String.format(
"Can't create variable with name '%s' and type '%s' "
+ "as it would omit a variable with type '%s'",
name, yices_type_to_string(type), yices_type_to_string(termFromNameType)));
}
}
Copy link
Member

Choose a reason for hiding this comment

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

it looks like some ELSE-cases are missing. Is this intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is intentional. I added documentation for it.

Essentially: Names work like a stack in Yices2. If we associate a term with a name, we get that term if we ask yices_get_term_by_name(). However, if we create bound variables, we associate them with the same name as the free variable (so that it has the same name). This pushes the name stack, and we get the bound var when asking yices_get_term_by_name(). That's why i added a cache for free vars. So this way we can re-use bound variables, and don't clash with free vars.

// reset term name binding
// TODO: add yices_remove_term_name();
int bound = yices_new_variable(type);
// Names in Yices2 behave like a stack. The last variable named is retrieved when asking for
// a term with a specific name. Since we substitute free vars with bound for quantifiers,
// this sometimes mixes them up, hence we track them ourselves.
// This overrides the naming, but the old is cached.
// Meaning that if we remove the new name, the old term gets its name back.
// Since we just want to retrieve the same var for the quantifier we are currently building,
// this is fine.
yices_set_term_name(bound, name);
return bound;
}

@Override
public <R> R visit(FormulaVisitor<R> pVisitor, Formula pFormula, Integer pF) {
int constructor = yices_term_constructor(pF);
Expand All @@ -258,6 +325,22 @@ public <R> R visit(FormulaVisitor<R> pVisitor, Formula pFormula, Integer pF) {
return pVisitor.visitConstant(pFormula, convertValue(pF, pF));
case YICES_UNINTERPRETED_TERM:
return pVisitor.visitFreeVariable(pFormula, yices_get_term_name(pF));
case YICES_VARIABLE:
return pVisitor.visitBoundVariable(pFormula, 0);
case YICES_FORALL_TERM:
int children = yices_term_num_children(pF);
ImmutableList.Builder<Formula> boundVars = ImmutableList.builder();
for (int i = 0; i < children - 1; i++) {
int boundVar = yices_term_child(pF, i);
boundVars.add(encapsulateWithTypeOf(boundVar));
}
BooleanFormula body = encapsulateBoolean(yices_term_child(pF, children - 1));
Quantifier quant = Quantifier.EXISTS;
if (yices_term_to_string(pF).startsWith("(forall")) {
Copy link
Member

Choose a reason for hiding this comment

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

Yices is open source. We could find out, how Yices computes the string and check for the flag that tells the difference from FORALL to EXISTS:

Copy link
Contributor

Choose a reason for hiding this comment

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

Yices does not seem to have a separate term for exists:

term_t mk_exists(term_manager_t *manager, uint32_t n, const term_t var[], term_t body) {
  if (body == true_term) return body;
  if (body == false_term) return body;

  // (not (forall ... (not body))
  return opposite_term(forall_term(manager->terms, n, var, opposite_term(body)));
}

To see if we have a forall or an exists we'd have to check the polarity of the term. Yices does this internally with a simple bitmask:

static inline uint32_t polarity_of(term_t x) {
  return ((uint32_t) x) & 1;
}

I couldn't find any public API for this, but we could probably just keep track of the polarity in the visitor.

Copy link
Contributor Author

@baierd baierd Mar 7, 2025

Choose a reason for hiding this comment

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

No actually that is the solution! Thank you very much!
exists is negated and we can check that.

This opens another questions however: do we traverse and/or rebuild terms correctly with this?
Do we have a test for exists that manipulates the formula? If not, we need to add one!

Copy link
Contributor Author

@baierd baierd Mar 7, 2025

Choose a reason for hiding this comment

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

(I fear that the visitor might rebuild a formula exists x x=y into not(forall x x=y), which is not equal.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Exactly as i expected, this happens. I added a test that should work for all solvers that checks this for both types of quantifiers.

Copy link
Contributor Author

@baierd baierd Apr 3, 2025

Choose a reason for hiding this comment

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

OK so Yices2 does simply transform the formula on-the-fly while traversing it.
Example: If we traverse the formula EXISTS x . OR(x, y) we first get a negation and the child of that is FORALL x . NOT(NOT x, NOT y), which is correct of course, but it still transforms the formula unexpectedly. Note: the string representation is EXISTS x . OR(x, y) until we get the child from the negation, then the string of the child looks like FORALL x . NOT(NOT x, NOT y).

Do we want to accept this behavior @kfriedberger ?
It does lead to unexpected behavior when trying to substitute quantified formulas.
But also, it would be hard for us to circumvent this.

// TODO: this is stupid, but i could not find a way of discerning between the quantifiers
quant = Quantifier.FORALL;
}
return pVisitor.visitQuantifier((BooleanFormula) pFormula, quant, boundVars.build(), body);
default:
return visitFunctionApplication(pVisitor, pFormula, pF, constructor);
}
Expand Down Expand Up @@ -696,7 +779,7 @@ public Integer declareUFImpl(String pName, Integer pReturnType, List<Integer> pA
} else {
yicesFuncType = yices_function_type(size, argTypeArray, pReturnType);
}
int uf = yices_named_variable(yicesFuncType, pName);
int uf = createNamedVariable(yicesFuncType, pName);
return uf;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ protected Yices2FormulaManager(
Yices2BooleanFormulaManager pBooleanManager,
Yices2IntegerFormulaManager pIntegerManager,
Yices2RationalFormulaManager pRationalManager,
Yices2BitvectorFormulaManager pBitvectorManager) {
Yices2BitvectorFormulaManager pBitvectorManager,
Yices2QuantifiedFormulaManager pQuantifiedFormulaManager) {
super(
pFormulaCreator,
pFunctionManager,
Expand All @@ -57,7 +58,7 @@ protected Yices2FormulaManager(
pRationalManager,
pBitvectorManager,
null,
null,
pQuantifiedFormulaManager,
null,
null,
null,
Expand Down
19 changes: 0 additions & 19 deletions src/org/sosy_lab/java_smt/solvers/yices2/Yices2NativeApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -783,25 +783,6 @@ public static String yices_model_to_string(long m) {

public static native int yices_subst_term(int size, int[] from, int[] to, int t);

public static int yices_named_variable(int type, String name) {
int termFromName = yices_get_term_by_name(name);
if (termFromName != -1) {
int termFromNameType = yices_type_of_term(termFromName);
if (type == termFromNameType) {
return termFromName;
} else {
throw new IllegalArgumentException(
String.format(
"Can't create variable with name '%s' and type '%s' "
+ "as it would omit a variable with type '%s'",
name, yices_type_to_string(type), yices_type_to_string(termFromNameType)));
}
}
int var = yices_new_uninterpreted_term(type);
yices_set_term_name(var, name);
return var;
}

/**
* @return int 1 if the Yices2-lib is compiled thread-safe and 0 otherwise
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_free_config;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_free_context;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_function_type;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_get_term_by_name;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_get_term_name;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_idiv;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_iff;
Expand All @@ -54,7 +55,6 @@
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_int64;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_int_type;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_mul;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_named_variable;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_new_config;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_new_context;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_new_uninterpreted_term;
Expand All @@ -81,6 +81,8 @@
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_term_num_children;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_term_to_string;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_true;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_type_of_term;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_type_to_string;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_zero_extend;

import com.google.common.base.Joiner;
Expand All @@ -95,6 +97,7 @@
import org.junit.AssumptionViolatedException;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.sosy_lab.common.NativeLibraries;
import org.sosy_lab.common.rationals.Rational;
Expand Down Expand Up @@ -201,6 +204,8 @@ public void rationalError() {
System.out.println(rat); // "use" variable
}

// TODO: what is this test supposed to be doing? And remove print.
@Ignore
Copy link
Member

Choose a reason for hiding this comment

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

Most of those tests are simply tests for loading and running Yices. They serves as examples and were helpful for debugging initial issues. If the tests do no longer bring benefit, please remove them, and do not just disable them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I reworked all tests with printouts into assertions and re-enabled all. I also found some issues and fixed them, added documentation and 2 more native tests.

@Test
public void negativeRationalError() {
// TODO negative unsigned integer causes no error. Need to ensure positive value before
Expand Down Expand Up @@ -467,6 +472,8 @@ public void arithSimplification() {
assertThat(yices_term_constructor(mul)).isEqualTo(YICES_ARITH_CONST);
}

// TODO: what is this test supposed to be doing? And remove print.
@Ignore
@Test
public void sumComponents() {
int three = yices_int32(3);
Expand Down Expand Up @@ -499,6 +506,8 @@ public void sumComponents() {
}
}

// TODO: what is this test supposed to be doing? And remove print.
@Ignore
@Test
public void bvSumComponents() {
int bv1 = yices_parse_bvbin("00101");
Expand All @@ -521,6 +530,8 @@ public void bvSumComponents() {
}
}

// TODO: what is this test supposed to be doing? And remove print.
@Ignore
@Test
public void bvExtensionStructureTest() {
int extendBy = 5;
Expand Down Expand Up @@ -569,6 +580,8 @@ public void bvSum() {
assertThat(constructor).isEqualTo(YICES_BV_SUM);
}

// TODO: what is this test supposed to be doing? And remove print.
@Ignore
@Test
public void bvMul() {
int type = yices_bv_type(5);
Expand All @@ -580,4 +593,27 @@ public void bvMul() {
System.out.println(component[1]);
System.out.println(yices_term_constructor(yices_bvpower(component[0], component[1])));
}

/**
* Only to be used for tests in this class. Old implementation used for creating/retrieving named
* variables. Superseded by Yices2FormulaCreator.createNamedVariable() for reasons outlined there.
*/
private static int yices_named_variable(int type, String name) {
int termFromName = yices_get_term_by_name(name);
if (termFromName != -1) {
int termFromNameType = yices_type_of_term(termFromName);
if (type == termFromNameType) {
return termFromName;
} else {
throw new IllegalArgumentException(
String.format(
"Can't create variable with name '%s' and type '%s' "
+ "as it would omit a variable with type '%s'",
name, yices_type_to_string(type), yices_type_to_string(termFromNameType)));
}
}
int var = yices_new_uninterpreted_term(type);
yices_set_term_name(var, name);
return var;
}
Copy link
Member

Choose a reason for hiding this comment

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

This IF-THEN-ELSE logic seems to be used twice. Can we refactor it into a proper utility method?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Only parts of the structure is reused. This version is for tests and for free variables only. The other one is for bound variables and has additional logic. (I reworked the creation of free vars and its not similar to this one anymore)

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@

import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_exists;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_forall;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_subst_term;

import com.google.common.primitives.Ints;
import java.util.ArrayList;
import java.util.List;
import org.sosy_lab.java_smt.api.SolverException;
import org.sosy_lab.java_smt.basicimpl.AbstractQuantifiedFormulaManager;
Expand All @@ -28,27 +30,31 @@ protected Yices2QuantifiedFormulaManager(
@Override
protected Integer eliminateQuantifiers(Integer pExtractInfo)
throws SolverException, InterruptedException {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Yices does not support eliminating Quantifiers.");
throw new UnsupportedOperationException("Yices2 does not support quantifier elimination.");
}

@Override
public Integer mkQuantifier(Quantifier pQ, List<Integer> pVars, Integer pBody) {
/*
* TODO Yices needs variables constructed using yices_new_variable(), but variables passed in
* pVars are constructed with yices_new uninterpreted_term(). Need to construct the correct
* variable type from the variables in pVars and map between them.
*/
// Quantifier support is very limited in Yices2
if (pVars.isEmpty()) {
throw new IllegalArgumentException("Empty variable list for Quantifier.");
} else {
int[] terms = Ints.toArray(pVars);
List<Integer> yicesVars = new ArrayList<>();
for (int var : pVars) {
yicesVars.add(
((Yices2FormulaCreator) formulaCreator).createBoundVariableFromFreeVariable(var));
}
int substBody = pBody;
substBody =
yices_subst_term(
yicesVars.size(), Ints.toArray(pVars), Ints.toArray(yicesVars), substBody);

int[] terms = Ints.toArray(yicesVars);
if (pQ == Quantifier.FORALL) {
return yices_forall(terms.length, terms, pBody);
} else if (pQ == Quantifier.EXISTS) {
return yices_exists(terms.length, terms, pBody);
return yices_forall(terms.length, terms, substBody);
} else {
return yices_exists(terms.length, terms, substBody);
}
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,16 @@ public static Yices2SolverContext create(
new Yices2IntegerFormulaManager(creator, pNonLinearArithmetic);
Yices2RationalFormulaManager rationalTheory =
new Yices2RationalFormulaManager(creator, pNonLinearArithmetic);
Yices2QuantifiedFormulaManager quantTheory = new Yices2QuantifiedFormulaManager(creator);
Yices2FormulaManager manager =
new Yices2FormulaManager(
creator, functionTheory, booleanTheory, integerTheory, rationalTheory, bitvectorTheory);
creator,
functionTheory,
booleanTheory,
integerTheory,
rationalTheory,
bitvectorTheory,
quantTheory);
return new Yices2SolverContext(manager, creator, booleanTheory, pShutdownManager);
}

Expand Down
Loading