Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
@@ -0,0 +1,77 @@
/*
* This file is part of JavaSMT,
* an API wrapper for a collection of SMT solvers:
* https://github.com/sosy-lab/java-smt
*
* SPDX-FileCopyrightText: 2025 Dirk Beyer <https://www.sosy-lab.org>
*
* SPDX-License-Identifier: Apache-2.0
*/

package org.sosy_lab.java_smt.solvers.yices2;

import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_application;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_eq;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_function_type;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_lambda;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_new_variable;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_update;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import org.sosy_lab.java_smt.api.Formula;
import org.sosy_lab.java_smt.api.FormulaType;
import org.sosy_lab.java_smt.basicimpl.AbstractArrayFormulaManager;

@SuppressWarnings({"ClassTypeParameterName", "MethodTypeParameterName"})
public class Yices2ArrayFormulaManager
extends AbstractArrayFormulaManager<Integer, Integer, Long, Integer> {

/**
* Cache with constant array values.
*
* <p>Used in {@link #internalMakeArray(FormulaType, FormulaType, Integer)} to guarantee that
* existing constant array values are never re-created
*/
private final Table<Integer, Integer, Integer> constCache = HashBasedTable.create();

public Yices2ArrayFormulaManager(Yices2FormulaCreator pCreator) {
super(pCreator);
}

@Override
protected Integer select(Integer pArray, Integer pIndex) {
return yices_application(pArray, 1, new int[] {pIndex});
}

@Override
protected Integer store(Integer pArray, Integer pIndex, Integer pValue) {
return yices_update(pArray, 1, new int[] {pIndex}, pValue);
}

@Override
protected <TI extends Formula, TE extends Formula> Integer internalMakeArray(
String pName, FormulaType<TI> pIndexType, FormulaType<TE> pElementType) {
var yicesFuncType =
yices_function_type(1, new int[] {toSolverType(pIndexType)}, toSolverType(pElementType));
return ((Yices2FormulaCreator) getFormulaCreator()).createNamedVariable(yicesFuncType, pName);
}

@Override
protected <TI extends Formula, TE extends Formula> Integer internalMakeArray(
FormulaType<TI> pIndexType, FormulaType<TE> pElementType, Integer defaultElement) {
var arraySort = toSolverType(FormulaType.getArrayType(pIndexType, pElementType));
var constantArray = constCache.get(arraySort, defaultElement);
if (constantArray == null) {
constantArray =
yices_lambda(1, new int[] {yices_new_variable(toSolverType(pIndexType))}, defaultElement);
constCache.put(arraySort, defaultElement, constantArray);
}
return constantArray;
}

@Override
protected Integer equivalence(Integer pArray1, Integer pArray2) {
return yices_eq(pArray1, pArray2);
}
}
26 changes: 26 additions & 0 deletions src/org/sosy_lab/java_smt/solvers/yices2/Yices2Formula.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@

package org.sosy_lab.java_smt.solvers.yices2;

import static com.google.common.base.Preconditions.checkNotNull;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_term_to_string;

import com.google.errorprone.annotations.Immutable;
import org.sosy_lab.java_smt.api.ArrayFormula;
import org.sosy_lab.java_smt.api.BitvectorFormula;
import org.sosy_lab.java_smt.api.BooleanFormula;
import org.sosy_lab.java_smt.api.Formula;
import org.sosy_lab.java_smt.api.FormulaType;
import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula;
import org.sosy_lab.java_smt.api.NumeralFormula.RationalFormula;

Expand Down Expand Up @@ -78,4 +81,27 @@ static final class Yices2BooleanFormula extends Yices2Formula implements Boolean
super(pTerm);
}
}

@SuppressWarnings({"ClassTypeParameterName", "MethodTypeParameterName"})
@Immutable
static final class Yices2ArrayFormula<TI extends Formula, TE extends Formula>
extends Yices2Formula implements ArrayFormula<TI, TE> {

private final FormulaType<TI> indexType;
private final FormulaType<TE> elementType;

Yices2ArrayFormula(Integer info, FormulaType<TI> pIndexType, FormulaType<TE> pElementType) {
super(info);
this.indexType = checkNotNull(pIndexType);
this.elementType = checkNotNull(pElementType);
}

public FormulaType<TI> getIndexType() {
return indexType;
}

public FormulaType<TE> getElementType() {
return elementType;
}
}
}
122 changes: 105 additions & 17 deletions src/org/sosy_lab/java_smt/solvers/yices2/Yices2FormulaCreator.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_ARITH_CONST;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_ARITH_GE_ATOM;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_ARITH_SUM;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_ARRAY_SELECT;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_BIT_TERM;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_BOOL_CONST;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_BV_ARRAY;
Expand All @@ -41,12 +42,14 @@
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;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_ITE_TERM;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_LAMBDA_TERM;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_NOT_TERM;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_OR_TERM;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_POWER_PRODUCT;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_RDIV;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_SELECT_TERM;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_UNINTERPRETED_TERM;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_UPDATE_TERM;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_VARIABLE;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.YICES_XOR_TERM;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_abs;
Expand Down Expand Up @@ -111,16 +114,19 @@
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_term_bitsize;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_term_child;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_term_constructor;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_term_is_bitvector;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_term_is_bool;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_term_is_int;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_term_is_real;
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_child;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_type_is_bitvector;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_type_is_bool;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_type_is_function;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_type_is_int;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_type_is_real;
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_update;
import static org.sosy_lab.java_smt.solvers.yices2.Yices2NativeApi.yices_xor;

import com.google.common.base.Joiner;
Expand All @@ -136,24 +142,30 @@
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.sosy_lab.common.rationals.Rational;
import org.sosy_lab.java_smt.api.ArrayFormula;
import org.sosy_lab.java_smt.api.BitvectorFormula;
import org.sosy_lab.java_smt.api.BooleanFormula;
import org.sosy_lab.java_smt.api.Formula;
import org.sosy_lab.java_smt.api.FormulaType;
import org.sosy_lab.java_smt.api.FormulaType.ArrayFormulaType;
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;
import org.sosy_lab.java_smt.solvers.yices2.Yices2Formula.Yices2ArrayFormula;
import org.sosy_lab.java_smt.solvers.yices2.Yices2Formula.Yices2BitvectorFormula;
import org.sosy_lab.java_smt.solvers.yices2.Yices2Formula.Yices2BooleanFormula;
import org.sosy_lab.java_smt.solvers.yices2.Yices2Formula.Yices2IntegerFormula;
import org.sosy_lab.java_smt.solvers.yices2.Yices2Formula.Yices2RationalFormula;

@SuppressWarnings({"ClassTypeParameterName", "MethodTypeParameterName"})
public class Yices2FormulaCreator extends FormulaCreator<Integer, Integer, Long, Integer> {

private static final ImmutableSet<Integer> CONSTANT_AND_VARIABLE_CONSTRUCTORS =
Expand All @@ -170,6 +182,14 @@ public class Yices2FormulaCreator extends FormulaCreator<Integer, Integer, Long,
*/
private final Table<String, Integer, Integer> formulaCache = HashBasedTable.create();

/**
* List of all UF function declarations.
*
* <p>We need this in the visitor to tell the difference between functions and arrays. Both are
* modeled internally by function terms.
*/
private final Set<Integer> ufSymbols = new HashSet<>();

protected Yices2FormulaCreator() {
super(null, yices_bool_type(), yices_int_type(), yices_real_type(), null, null);
}
Expand All @@ -186,7 +206,7 @@ public Integer getFloatingPointType(FloatingPointType pType) {

@Override
public Integer getArrayType(Integer pIndexType, Integer pElementType) {
throw new UnsupportedOperationException();
return yices_function_type(1, new int[] {pIndexType}, pElementType);
}

@Override
Expand All @@ -199,6 +219,20 @@ public Integer extractInfo(Formula pT) {
return Yices2FormulaManager.getYicesTerm(pT);
}

@Override
@SuppressWarnings("unchecked")
protected <TI extends Formula, TE extends Formula> FormulaType<TE> getArrayFormulaElementType(
ArrayFormula<TI, TE> pArray) {
return ((Yices2ArrayFormula<TI, TE>) pArray).getElementType();
}

@Override
@SuppressWarnings("unchecked")
protected <TI extends Formula, TE extends Formula> FormulaType<TI> getArrayFormulaIndexType(
ArrayFormula<TI, TE> pArray) {
return ((Yices2ArrayFormula<TI, TE>) pArray).getIndexType();
}

@SuppressWarnings("unchecked")
@Override
public <T extends Formula> T encapsulate(FormulaType<T> pType, Integer pTerm) {
Expand All @@ -219,6 +253,10 @@ public <T extends Formula> T encapsulate(FormulaType<T> pType, Integer pTerm) {
return (T) new Yices2RationalFormula(pTerm);
} else if (pType.isBitvectorType()) {
return (T) new Yices2BitvectorFormula(pTerm);
} else if (pType.isArrayType()) {
var range = ((ArrayFormulaType<?, ?>) pType).getElementType();
var dom = ((ArrayFormulaType<?, ?>) pType).getIndexType();
return (T) encapsulateArray(pTerm, dom, range);
}
throw new IllegalArgumentException("Cannot create formulas of type " + pType + " in Yices");
}
Expand All @@ -235,32 +273,51 @@ public BitvectorFormula encapsulateBitvector(Integer pTerm) {
return new Yices2BitvectorFormula(pTerm);
}

@Override
protected <TI extends Formula, TE extends Formula> ArrayFormula<TI, TE> encapsulateArray(
Integer pTerm, FormulaType<TI> pIndexType, FormulaType<TE> pElementType) {
checkArgument(
getFormulaType(pTerm).equals(FormulaType.getArrayType(pIndexType, pElementType)),
"Array formula has unexpected type: %s",
getFormulaType(pTerm));
return new Yices2Formula.Yices2ArrayFormula<>(pTerm, pIndexType, pElementType);
}

@SuppressWarnings("unchecked")
@Override
public <T extends Formula> FormulaType<T> getFormulaType(T pFormula) {
if (pFormula instanceof BitvectorFormula) {
int type = yices_type_of_term(extractInfo(pFormula));
return (FormulaType<T>) FormulaType.getBitvectorTypeWithSize(yices_bvtype_size(type));
} else if (pFormula instanceof ArrayFormula) {
return (FormulaType<T>) convertType(yices_type_of_term(extractInfo(pFormula)));
} else {
return super.getFormulaType(pFormula);
}
}

@Override
public FormulaType<?> getFormulaType(Integer pFormula) {
if (yices_term_is_bool(pFormula)) {
return convertType(yices_type_of_term(pFormula));
}

/** Convert from Yices2 types to JavaSMT FormulaTypes. */
private FormulaType<?> convertType(Integer pType) {
if (yices_type_is_bool(pType)) {
return FormulaType.BooleanType;
} else if (yices_term_is_int(pFormula)) {
} else if (yices_type_is_int(pType)) {
return FormulaType.IntegerType;
} else if (yices_term_is_real(pFormula)) {
} else if (yices_type_is_real(pType)) {
return FormulaType.RationalType;
} else if (yices_term_is_bitvector(pFormula)) {
return FormulaType.getBitvectorTypeWithSize(yices_term_bitsize(pFormula));
} else if (yices_type_is_bitvector(pType)) {
return FormulaType.getBitvectorTypeWithSize(yices_bvtype_size(pType));
} else if (yices_type_is_function(pType)) {
var domain = yices_type_child(pType, 0);
var range = yices_type_child(pType, 1);
return FormulaType.getArrayType(convertType(domain), convertType(range));
}
throw new IllegalArgumentException(
String.format(
"Unknown formula type '%s' for formula '%s'",
yices_type_to_string(yices_type_of_term(pFormula)), yices_term_to_string(pFormula)));
String.format("Unknown formula type '%s'", yices_type_to_string(pType)));
}

/** Creates a named, free variable. Might retrieve it from the cache if created prior. */
Expand Down Expand Up @@ -335,6 +392,17 @@ public <R> R visit(FormulaVisitor<R> pVisitor, Formula pFormula, Integer pF) {
return pVisitor.visitConstant(pFormula, convertValue(pF, pF));
case YICES_BV_CONST:
return pVisitor.visitConstant(pFormula, convertValue(pF, pF));
case YICES_LAMBDA_TERM:
// We use lambda terms as array constants
return pVisitor.visitFunction(
pFormula,
ImmutableList.of(encapsulateWithTypeOf(yices_term_child(pF, 1))),
FunctionDeclarationImpl.of(
"const",
FunctionDeclarationKind.CONST,
ImmutableList.of(getFormulaType(yices_term_child(pF, 1))),
getFormulaType(pF),
0));
case YICES_UNINTERPRETED_TERM:
return pVisitor.visitFreeVariable(pFormula, yices_get_term_name(pF));
case YICES_VARIABLE:
Expand Down Expand Up @@ -398,11 +466,26 @@ private <R> R visitFunctionApplication(
functionKind = FunctionDeclarationKind.ITE;
break;
case YICES_APP_TERM:
functionKind = FunctionDeclarationKind.UF;
functionArgs = getArgs(pF);
functionName = yices_term_to_string(functionArgs.get(0));
functionDeclaration = functionArgs.get(0);
functionArgs.remove(0);
var fun = yices_term_child(pF, 0);
if (ufSymbols.contains(fun)) {
functionKind = FunctionDeclarationKind.UF;
functionArgs = getArgs(pF);
functionName = yices_get_term_name(functionArgs.get(0));
functionDeclaration = functionArgs.get(0);
functionArgs.remove(0);
} else {
functionKind = FunctionDeclarationKind.SELECT;
functionArgs = getArgs(pF);
functionName = "select";
functionDeclaration = -YICES_ARRAY_SELECT;
}
break;
case YICES_UPDATE_TERM:
functionKind = FunctionDeclarationKind.STORE;
functionArgs =
ImmutableList.of(
yices_term_child(pF, 0), yices_term_child(pF, 1), yices_term_child(pF, 2));
functionDeclaration = -YICES_UPDATE_TERM;
break;
case YICES_EQ_TERM:
functionKind = FunctionDeclarationKind.EQ; // Covers all equivalences
Expand Down Expand Up @@ -760,6 +843,10 @@ public Integer callFunctionImpl(Integer pDeclaration, List<Integer> pArgs) {
return yices_bvproduct(pArgs.size(), Ints.toArray(pArgs));
case YICES_AND:
return yices_and(pArgs.size(), Ints.toArray(pArgs));
case YICES_ARRAY_SELECT:
return yices_application(pArgs.get(0), 1, new int[] {pArgs.get(1)});
case YICES_UPDATE_TERM:
return yices_update(pArgs.get(0), 1, new int[] {pArgs.get(1)}, pArgs.get(2));
default:
// TODO add more cases
// if something bad happens here,
Expand Down Expand Up @@ -808,6 +895,7 @@ public Integer declareUFImpl(String pName, Integer pReturnType, List<Integer> pA
yicesFuncType = yices_function_type(size, argTypeArray, pReturnType);
}
int uf = createNamedVariable(yicesFuncType, pName);
ufSymbols.add(uf);
return uf;
}

Expand Down
Loading