Skip to content

Commit c9b34d4

Browse files
authored
Merge pull request #447 from sosy-lab/fix_yices2_quantifier
Add Proper Yices2 Quantifier Support
2 parents e5d1c16 + fb5d3e5 commit c9b34d4

16 files changed

+787
-263
lines changed

src/org/sosy_lab/java_smt/api/visitors/FormulaVisitor.java

+7-4
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,13 @@ public interface FormulaVisitor<R> {
7272
*
7373
* @param f Quantifier formula.
7474
* @param quantifier Quantifier type: either {@code FORALL} or {@code EXISTS}.
75-
* @param boundVariables Variables bound by the quantifier. <b>NOTE:</b> not all solvers hold
76-
* metadata about bound variables. In case this is not available, this method will be called
77-
* with an empty list, yet {@code #mkQuantifier} will work fine with an empty list as well.
78-
* @param body Body of the quantifier.
75+
* @param boundVariables Variables bound by the quantifier. The variables are provided as free
76+
* variables, such that they can be used as normal symbols in JavaSMT. <b>NOTE:</b> not all
77+
* solvers hold metadata about bound variables. In case this is not available, this method
78+
* will be called with an empty list, yet {@code #mkQuantifier} will work fine with an empty
79+
* list as well.
80+
* @param body Body of the quantifier. The body is provided without bound variables, i.e., all
81+
* bound variables from this quantifier application are provided as free variables.
7982
*/
8083
R visitQuantifier(
8184
BooleanFormula f, Quantifier quantifier, List<Formula> boundVariables, BooleanFormula body);

src/org/sosy_lab/java_smt/solvers/yices2/Yices2FormulaCreator.java

+160-51
Large diffs are not rendered by default.

src/org/sosy_lab/java_smt/solvers/yices2/Yices2FormulaManager.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ protected Yices2FormulaManager(
4545
Yices2BooleanFormulaManager pBooleanManager,
4646
Yices2IntegerFormulaManager pIntegerManager,
4747
Yices2RationalFormulaManager pRationalManager,
48-
Yices2BitvectorFormulaManager pBitvectorManager) {
48+
Yices2BitvectorFormulaManager pBitvectorManager,
49+
Yices2QuantifiedFormulaManager pQuantifiedFormulaManager) {
4950
super(
5051
pFormulaCreator,
5152
pFunctionManager,
@@ -54,7 +55,7 @@ protected Yices2FormulaManager(
5455
pRationalManager,
5556
pBitvectorManager,
5657
null,
57-
null,
58+
pQuantifiedFormulaManager,
5859
null,
5960
null,
6061
null,

src/org/sosy_lab/java_smt/solvers/yices2/Yices2NativeApi.java

+9-20
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,15 @@ private Yices2NativeApi() {}
610610
public static native int[] yices_bvsum_component(int t, int i, int bitsize);
611611

612612
// TODO can return up to UINT32_MAX ?
613-
/** Returns an array in the form [term,power]. */
613+
// Daniel: we cast the uint return of exp to signed int (jint), this is obviously wrong!
614+
/**
615+
* Returns an array of size 2 in the form [term,exp] for the term and exponent at index i and
616+
* checks automatically for errors (original function return) and throws IllegalArgumentException
617+
* for return value -1. Original API: int32_t yices_product_component(term_t t, int32_t i, term_t
618+
* *term, uint32_t *exp) Component of a power product. A product t is of the form t0^d0 × … ×
619+
* tn^dn. This function stores the term ti into *term and the exponent di into *exp. The function
620+
* returns -1 if t is not a product or if the index i is too large. It returns 0 otherwise.
621+
*/
614622
public static native int[] yices_product_component(int t, int i);
615623

616624
/*
@@ -783,25 +791,6 @@ public static String yices_model_to_string(long m) {
783791

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

786-
public static int yices_named_variable(int type, String name) {
787-
int termFromName = yices_get_term_by_name(name);
788-
if (termFromName != -1) {
789-
int termFromNameType = yices_type_of_term(termFromName);
790-
if (type == termFromNameType) {
791-
return termFromName;
792-
} else {
793-
throw new IllegalArgumentException(
794-
String.format(
795-
"Can't create variable with name '%s' and type '%s' "
796-
+ "as it would omit a variable with type '%s'",
797-
name, yices_type_to_string(type), yices_type_to_string(termFromNameType)));
798-
}
799-
}
800-
int var = yices_new_uninterpreted_term(type);
801-
yices_set_term_name(var, name);
802-
return var;
803-
}
804-
805794
/**
806795
* @return int 1 if the Yices2-lib is compiled thread-safe and 0 otherwise
807796
*/

src/org/sosy_lab/java_smt/solvers/yices2/Yices2NativeApiTest.java

+131-61
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
package org.sosy_lab.java_smt.solvers.yices2;
1010

11+
import static com.google.common.base.Preconditions.checkArgument;
1112
import static com.google.common.truth.Truth.assertThat;
1213
import static org.junit.Assert.assertThrows;
1314
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_APP_TERM;
@@ -16,8 +17,10 @@
1617
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_BV_CONST;
1718
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_BV_SUM;
1819
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_EQ_TERM;
20+
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_FORALL_TERM;
1921
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_NOT_TERM;
2022
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_OR_TERM;
23+
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_POWER_PRODUCT;
2124
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_add;
2225
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_and;
2326
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_and2;
@@ -42,23 +45,27 @@
4245
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_check_context;
4346
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_context_disable_option;
4447
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_eq;
48+
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_exists;
4549
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_exit;
4650
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_false;
51+
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_forall;
4752
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_free_config;
4853
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_free_context;
4954
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_function_type;
55+
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_get_term_by_name;
5056
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_get_term_name;
5157
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_idiv;
5258
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_iff;
5359
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_init;
5460
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_int32;
5561
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_int64;
5662
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_int_type;
63+
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_is_thread_safe;
5764
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_mul;
58-
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_named_variable;
5965
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_new_config;
6066
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_new_context;
6167
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_new_uninterpreted_term;
68+
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_new_variable;
6269
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_not;
6370
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_or;
6471
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_or2;
@@ -82,16 +89,15 @@
8289
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_term_num_children;
8390
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_term_to_string;
8491
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_true;
92+
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_type_of_term;
93+
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_type_to_string;
8594
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_zero_extend;
8695

8796
import com.google.common.base.Joiner;
88-
import com.google.common.base.Preconditions;
8997
import com.google.common.collect.Lists;
9098
import com.google.common.primitives.Ints;
9199
import java.math.BigInteger;
92-
import java.util.ArrayList;
93100
import java.util.Arrays;
94-
import java.util.List;
95101
import org.junit.After;
96102
import org.junit.AssumptionViolatedException;
97103
import org.junit.Before;
@@ -196,6 +202,7 @@ public void arithAddUNSAT() {
196202
assertThat(yices_check_context(env, 0)).isEqualTo(UNSAT);
197203
}
198204

205+
@SuppressWarnings("CheckReturnValue")
199206
@Test
200207
public void rationalError() {
201208
assertThrows(IllegalArgumentException.class, () -> yices_rational32(1, 0));
@@ -204,10 +211,10 @@ public void rationalError() {
204211
@Test
205212
public void negativeRationalError() {
206213
// TODO negative unsigned integer causes no error. Need to ensure positive value before
207-
int rat = yices_rational32(1, -5);
208-
System.out.println(rat); // "use" variable
214+
assertThat(yices_rational32(1, -5)).isGreaterThan(0);
209215
}
210216

217+
@SuppressWarnings("CheckReturnValue")
211218
@Test
212219
public void wrongType() {
213220
int one = yices_int32(1);
@@ -300,7 +307,7 @@ public void bvValueTest() {
300307
int bv = yices_bvconst_int64(4, value);
301308
if (yices_term_constructor(bv) == YICES_BV_CONST) {
302309
int[] littleEndianBV = yices_bv_const_value(bv, yices_term_bitsize(bv));
303-
Preconditions.checkArgument(littleEndianBV.length != 0, "BV was empty");
310+
checkArgument(littleEndianBV.length != 0, "BV was empty");
304311
String bigEndianBV = Joiner.on("").join(Lists.reverse(Ints.asList(littleEndianBV)));
305312
BigInteger big = new BigInteger(bigEndianBV, 2);
306313
assertThat(big).isEqualTo(BigInteger.valueOf(value));
@@ -473,80 +480,100 @@ public void sumComponents() {
473480
int[] oneX = {three, x};
474481
int sumOneX = yices_sum(2, oneX);
475482
for (int i = 0; i < yices_term_num_children(sumOneX); i++) {
476-
System.out.println(yices_term_to_string(sumOneX));
477-
System.out.println(Arrays.toString(yices_sum_component(sumOneX, i)));
483+
assertThat(yices_term_to_string(sumOneX)).isNotNull();
484+
assertThat(Arrays.toString(yices_sum_component(sumOneX, i))).isNotNull();
478485
}
479486
int[] twoX = {three, x, x};
480487
int sumTwoX = yices_sum(3, twoX);
481488
for (int i = 0; i < yices_term_num_children(sumTwoX); i++) {
482-
System.out.println(yices_term_to_string(sumTwoX));
483-
System.out.println(Arrays.toString(yices_sum_component(sumTwoX, i)));
489+
assertThat(yices_term_to_string(sumTwoX)).isNotNull();
490+
assertThat(Arrays.toString(yices_sum_component(sumTwoX, i))).isNotNull();
484491
}
485492
int[] twoThrees = {three, x, three};
486493
int sumTwoThrees = yices_sum(3, twoThrees);
487494
for (int i = 0; i < yices_term_num_children(sumTwoThrees); i++) {
488-
System.out.println(yices_term_to_string(sumTwoThrees));
489-
System.out.println(Arrays.toString(yices_sum_component(sumTwoThrees, i)));
495+
assertThat(yices_term_to_string(sumTwoThrees)).isNotNull();
496+
assertThat(Arrays.toString(yices_sum_component(sumTwoThrees, i))).isNotNull();
490497
}
491498
int xTimesRational = yices_mul(rat, x);
492499
int[] ratSum = {three, xTimesRational};
493500
int sumRatX = yices_sum(2, ratSum);
494501
for (int i = 0; i < yices_term_num_children(sumRatX); i++) {
495-
System.out.println(yices_term_to_string(sumRatX));
496-
System.out.println(Arrays.toString(yices_sum_component(sumRatX, i)));
502+
assertThat(yices_term_to_string(sumRatX)).isNotNull();
503+
assertThat(Arrays.toString(yices_sum_component(sumRatX, i))).isNotNull();
497504
}
498505
}
499506

500507
@Test
501508
public void bvSumComponents() {
502-
int bv1 = yices_parse_bvbin("00101");
509+
String bv1StringValue = "00101";
510+
int bv1 = yices_parse_bvbin(bv1StringValue);
503511
int bv5type = yices_bv_type(5);
504512
int x = yices_named_variable(bv5type, "x");
505513
int negativeX = yices_bvmul(yices_bvconst_minus_one(5), x);
506514
int add = yices_bvadd(bv1, negativeX);
507-
for (int i = 0; i < yices_term_num_children(add); i++) {
508-
System.out.println(yices_term_to_string(add));
509-
int[] component = yices_bvsum_component(add, i, yices_term_bitsize(add));
510-
String value =
511-
Joiner.on("")
512-
.join(
513-
Lists.reverse(
514-
Ints.asList(Arrays.copyOfRange(component, 0, component.length - 1))));
515-
int term = component[component.length - 1];
516-
System.out.println("Value of coefficient: " + value);
517-
System.out.println("Coefficient as BigInt: " + new BigInteger(value, 2));
518-
System.out.println("Term id: " + term);
519-
}
520-
}
521-
522-
@Test
515+
assertThat(yices_term_num_children(add)).isEqualTo(2);
516+
assertThat(yices_term_to_string(add)).isNotNull();
517+
518+
int[] component1 = yices_bvsum_component(add, 0, yices_term_bitsize(add));
519+
String value1 =
520+
Joiner.on("")
521+
.join(
522+
Lists.reverse(
523+
Ints.asList(Arrays.copyOfRange(component1, 0, component1.length - 1))));
524+
int term1 = component1[component1.length - 1];
525+
// Value of coefficient
526+
assertThat(value1).isEqualTo(bv1StringValue);
527+
// Coefficient as BigInt
528+
assertThat(new BigInteger(value1, 2)).isEqualTo(BigInteger.valueOf(5));
529+
// Term id is NULL (-1) for i = 0
530+
assertThat(term1).isEqualTo(-1);
531+
532+
int[] component2 = yices_bvsum_component(add, 1, yices_term_bitsize(add));
533+
String value2 =
534+
Joiner.on("")
535+
.join(
536+
Lists.reverse(
537+
Ints.asList(Arrays.copyOfRange(component2, 0, component2.length - 1))));
538+
int term2 = component2[component2.length - 1];
539+
// Value of coefficient (-1 == 11111)
540+
assertThat(value2).isEqualTo("11111");
541+
// Coefficient as BigInt (31 because it has no sign bit, and -1 is max for bv)
542+
assertThat(new BigInteger(value2, 2)).isEqualTo(BigInteger.valueOf(31));
543+
// Term id is NULL (-1) for i = 0
544+
assertThat(term2).isEqualTo(x);
545+
}
546+
547+
@SuppressWarnings("CheckReturnValue")
548+
@Test(expected = IllegalArgumentException.class)
523549
public void bvExtensionStructureTest() {
550+
int initialSize = 5;
524551
int extendBy = 5;
525-
int x = yices_named_variable(yices_bv_type(5), "x");
526-
List<Integer> terms = new ArrayList<>();
527-
terms.add(yices_sign_extend(x, extendBy));
528-
terms.add(yices_sign_extend(x, extendBy));
529-
terms.add(yices_zero_extend(x, extendBy));
530-
terms.add(yices_zero_extend(x, extendBy));
531-
for (int t : terms) {
532-
System.out.println("--------BEGIN-------");
533-
System.out.println(yices_term_to_string(t));
534-
for (int i = 0; i < yices_term_num_children(t); i++) {
535-
System.out.println(yices_term_to_string(yices_term_child(t, i)));
536-
}
537-
int bv = yices_proj_arg(yices_term_child(t, 0));
538-
int bvSize = yices_term_bitsize(bv);
539-
int extendedBy = yices_term_num_children(t) - bvSize;
540-
System.out.println("Extended by: " + extendedBy);
541-
if (extendedBy != 0) {
542-
if (yices_term_child(t, bvSize) == yices_false()) {
543-
System.out.println("Zero-Extend");
544-
} else {
545-
System.out.println("Sign-extend");
546-
}
547-
}
548-
System.out.println("--------END-------");
549-
}
552+
int x = yices_named_variable(yices_bv_type(initialSize), "x");
553+
int signExtendedX = yices_sign_extend(x, extendBy);
554+
int zeroExtendedX = yices_zero_extend(x, extendBy);
555+
556+
assertThat(yices_term_to_string(x)).isNotNull();
557+
assertThat(yices_term_num_children(x)).isEqualTo(0);
558+
assertThat(yices_term_num_children(signExtendedX)).isEqualTo(initialSize + extendBy);
559+
assertThat(yices_term_to_string(signExtendedX)).isNotNull();
560+
assertThat(yices_term_num_children(zeroExtendedX)).isEqualTo(initialSize + extendBy);
561+
assertThat(yices_term_to_string(zeroExtendedX)).isNotNull();
562+
563+
int bvSignExt = yices_proj_arg(yices_term_child(signExtendedX, 0));
564+
int bvSizeSignExt = yices_term_bitsize(bvSignExt);
565+
int extendedBySignExt = yices_term_num_children(signExtendedX) - bvSizeSignExt;
566+
assertThat(extendedBySignExt).isEqualTo(extendBy);
567+
568+
int bvZeroExt = yices_proj_arg(yices_term_child(zeroExtendedX, 0));
569+
int bvSizeZeroExt = yices_term_bitsize(bvZeroExt);
570+
int extendedByZeroExt = yices_term_num_children(zeroExtendedX) - bvSizeZeroExt;
571+
assertThat(extendedByZeroExt).isEqualTo(extendBy);
572+
573+
assertThat(yices_term_child(zeroExtendedX, bvSizeZeroExt)).isEqualTo(yices_false());
574+
assertThat(yices_term_child(signExtendedX, bvSizeSignExt)).isNotEqualTo(yices_false());
575+
576+
yices_proj_arg(yices_term_child(x, 0)); // throws
550577
}
551578

552579
@Test
@@ -572,10 +599,53 @@ public void bvMul() {
572599
int type = yices_bv_type(5);
573600
int bv2 = yices_named_variable(type, "x");
574601
int mul = yices_bvmul(bv2, bv2);
575-
System.out.println(yices_term_constructor(mul));
602+
assertThat(yices_term_constructor(mul)).isEqualTo(YICES_POWER_PRODUCT);
603+
// bv2 + bv2 == bv2²
576604
int[] component = yices_product_component(mul, 0);
577-
System.out.println(component[0]);
578-
System.out.println(component[1]);
579-
System.out.println(yices_term_constructor(yices_bvpower(component[0], component[1])));
605+
assertThat(component[0]).isEqualTo(bv2);
606+
assertThat(component[1]).isEqualTo(2);
607+
assertThat(yices_term_constructor(yices_bvpower(component[0], component[1]))).isGreaterThan(0);
608+
}
609+
610+
@Test
611+
public void isThreadSafe() {
612+
// TODO: this explains why our concurrency tests fail ;D FIX!
613+
assertThat(yices_is_thread_safe()).isEqualTo(0);
614+
}
615+
616+
@Test
617+
public void quantifierTest() {
618+
int boundVar = yices_new_variable(yices_int_type());
619+
int eleven = yices_int32(11);
620+
int body = yices_eq(eleven, boundVar);
621+
622+
int forall = yices_forall(1, new int[] {boundVar}, body);
623+
int exists = yices_exists(1, new int[] {boundVar}, body);
624+
625+
assertThat(yices_term_constructor(forall)).isEqualTo(YICES_FORALL_TERM);
626+
assertThat(yices_term_constructor(exists)).isEqualTo(YICES_NOT_TERM);
627+
assertThat(yices_term_constructor(yices_term_child(exists, 0))).isEqualTo(YICES_FORALL_TERM);
628+
}
629+
630+
/**
631+
* Only to be used for tests in this class. Old implementation used for creating/retrieving named
632+
* variables. Superseded by {@link Yices2FormulaCreator#createNamedVariable} for reasons outlined
633+
* there.
634+
*/
635+
private static int yices_named_variable(int type, String name) {
636+
int termFromName = yices_get_term_by_name(name);
637+
if (termFromName != -1) {
638+
int termFromNameType = yices_type_of_term(termFromName);
639+
checkArgument(
640+
type == termFromNameType,
641+
"Cannot override symbol '%s' with new symbol '%s' of type '%s'",
642+
yices_type_to_string(termFromNameType),
643+
name,
644+
yices_type_to_string(type));
645+
return termFromName;
646+
}
647+
int var = yices_new_uninterpreted_term(type);
648+
yices_set_term_name(var, name);
649+
return var;
580650
}
581651
}

0 commit comments

Comments
 (0)