Skip to content

Commit

Permalink
Merge pull request #128 from ftsrg/simplifyGenericArrayRead-fix
Browse files Browse the repository at this point in the history
Fixed simplifyGenericArrayRead
  • Loading branch information
leventeBajczi committed Aug 7, 2021
2 parents 0594693 + 44381d8 commit e256056
Show file tree
Hide file tree
Showing 19 changed files with 413 additions and 76 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ buildscript {

allprojects {
group = "hu.bme.mit.inf.theta"
version = "2.20.0"
version = "2.21.0"

apply(from = rootDir.resolve("gradle/shared-with-buildSrc/mirrors.gradle.kts"))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ public static Collection<Object[]> data() {

{ "src/test/resources/arrays.cfa", PRED_BOOL, BW_BIN_ITP, false, 8 },

{ "src/test/resources/arrayinit.cfa", PRED_CART, BW_BIN_ITP, false, 3 },

{ "src/test/resources/arrays.cfa", EXPL, SEQ_ITP, false, 8 },

{ "src/test/resources/counter5_true.cfa", PRED_BOOL, SEQ_ITP, true, 0 },
Expand Down
18 changes: 18 additions & 0 deletions subprojects/cfa/cfa-analysis/src/test/resources/arrayinit.cfa
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
main process cfa {
var arr: [int]->int
var x: int

init loc L0
loc L1
loc L2
final loc END
error loc ERR

L0 -> L1 { arr := [ 0 <- 1, 1 <- x + 2, default <- 0 ] }

L1 -> L2 { assume arr[0] = 1 and arr[34] = 0 }
L1 -> ERR { assume not (arr[0] = 1 and arr[34] = 0) }

L2 -> END { assume arr[1] = 2 }
L2 -> ERR { assume not (arr[1] = 2) }
}
2 changes: 1 addition & 1 deletion subprojects/cfa/cfa/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Variables of the CFA can have the following types.
Expressions of the CFA include the following.
* Identifiers (variables).
* Literals, e.g., `true`, `false` (Bool), `0`, `123` (integer), `4 % 5` (rational).
* Array literals can be given by listing the key-value pairs and the (mandatory) default element, e.g., `[0 <- 182, 1 <- 41, default <- 75]`. If there are no elements, the key type has to be given before the default element, e.g., `[<int>default <- 75]`.
* Array literals can be given by listing the key-value pairs and the (mandatory) default element, e.g., `[0 <- 182, 1 <- 41, default <- 75]`. If there are no elements, the key type has to be given before the default element, e.g., `[<int>default <- 75]`. Note that any expression can be used as a value, but this will only result in an ArrayLitExpr when all operands are literals, or can be simplified to literals. Otherwise, this construct will yield an `ArrayInitExpr`, which is semantically equivalent to successive writes to an otherwise empty array, containing only the _else_ value for every index.
* Bitvector literals can be given by stating the length and the exact value of the bitvector in binary, decimal or hexadecimal form. (E.g. `4'd5` is a 4-bit-long bitvector with the decimal value 5.) _This is an experimental feature. See the [details](doc/bitvectors.md) for more information._
* Floating point literals can be given in the following form: `[+-]?bitvector.bitvector`, defining the optional sign (+/-), exponent and significand in this order. (E.g. `+5'b10000.10'd0` is `+2.0f` of type `fp[5:11]` (half-precision IEEE-754 float)). The value is calculated the following way (using `e` for exponent size, and `E`, `S` for values, `h` for sign): `value = (-1)^h * 1.S * 2^(E-2^(e-1)+1)`
* Comparison, e.g., `=`, `/=`, `<`, `>`, `<=`, `>=`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Rem;
import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Sub;
import static hu.bme.mit.theta.core.type.anytype.Exprs.Prime;
import static hu.bme.mit.theta.core.type.arraytype.ArrayExprs.Array;
import static hu.bme.mit.theta.core.type.arraytype.ArrayExprs.ArrayInit;
import static hu.bme.mit.theta.core.type.arraytype.ArrayExprs.Read;
import static hu.bme.mit.theta.core.type.arraytype.ArrayExprs.Write;
import static hu.bme.mit.theta.core.type.booltype.BoolExprs.And;
Expand Down Expand Up @@ -125,6 +125,7 @@
import static hu.bme.mit.theta.core.type.fptype.FpExprs.ToFp;
import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int;
import static hu.bme.mit.theta.core.type.rattype.RatExprs.Rat;
import static hu.bme.mit.theta.core.utils.ExprUtils.simplify;
import static hu.bme.mit.theta.core.utils.TypeUtils.cast;
import static hu.bme.mit.theta.core.utils.TypeUtils.castBv;
import static java.util.stream.Collectors.toList;
Expand Down Expand Up @@ -1039,7 +1040,7 @@ private <T1 extends Type, T2 extends Type> Expr<?> createArrayLitExpr(final ArrL
.collect(Collectors.toUnmodifiableList());

final Expr<T2> elseExpr = cast(ctx.elseExpr.accept(this), valueType);
return Array(elems, elseExpr, ArrayType.of(indexType, valueType));
return simplify(ArrayInit(elems, elseExpr, ArrayType.of(indexType, valueType)));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import hu.bme.mit.theta.core.type.anytype.PrimeExpr;
import hu.bme.mit.theta.core.type.anytype.RefExpr;
import hu.bme.mit.theta.core.type.arraytype.ArrayEqExpr;
import hu.bme.mit.theta.core.type.arraytype.ArrayInitExpr;
import hu.bme.mit.theta.core.type.arraytype.ArrayLitExpr;
import hu.bme.mit.theta.core.type.arraytype.ArrayNeqExpr;
import hu.bme.mit.theta.core.type.arraytype.ArrayReadExpr;
Expand Down Expand Up @@ -307,6 +308,8 @@ private ExprWriter() {

.addCase(ArrayLitExpr.class, this::arrayLit)

.addCase(ArrayInitExpr.class, this::arrayInit)

// FloatingPoint

.addCase(FpAbsExpr.class, e -> prefixUnary(e, " fpabs "))
Expand Down Expand Up @@ -470,5 +473,12 @@ private String arrayLit(final ArrayLitExpr<?, ?> expr) {
"]";
}

private String arrayInit(final ArrayInitExpr<?, ?> expr) {
return "[" +
expr.getElements().stream().map(e -> write(e.get1()) + " <- " + write(e.get2())).collect(Collectors.joining(", ")) +
"<" + expr.getType().getIndexType().toString() + ">default" + " <- " + write(expr.getElseElem()) +
"]";
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
*/
package hu.bme.mit.theta.core.type.arraytype;

import java.util.List;

import hu.bme.mit.theta.common.Tuple2;
import hu.bme.mit.theta.core.type.Expr;
import hu.bme.mit.theta.core.type.Type;

import java.util.List;

public final class ArrayExprs {

private ArrayExprs() {
Expand All @@ -32,11 +32,17 @@ public static <IndexType extends Type, ElemType extends Type> ArrayType<IndexTyp
}

public static <IndexType extends Type, ElemType extends Type> ArrayLitExpr<IndexType, ElemType> Array(
final List<Tuple2<Expr<IndexType>, Expr<ElemType>>> elems, final Expr<ElemType> elseElem,
final List<Tuple2<? extends Expr<IndexType>, ? extends Expr<ElemType>>> elems, final Expr<ElemType> elseElem,
final ArrayType<IndexType, ElemType> type) {
return ArrayLitExpr.of(elems, elseElem, type);
}

public static <IndexType extends Type, ElemType extends Type> ArrayInitExpr<IndexType, ElemType> ArrayInit(
final List<Tuple2<Expr<IndexType>, Expr<ElemType>>> elems, final Expr<ElemType> elseElem,
final ArrayType<IndexType, ElemType> type) {
return ArrayInitExpr.of(elems, elseElem, type);
}

public static <IndexType extends Type, ElemType extends Type> ArrayReadExpr<IndexType, ElemType> Read(
final Expr<ArrayType<IndexType, ElemType>> array, final Expr<IndexType> index) {
return ArrayReadExpr.of(array, index);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package hu.bme.mit.theta.core.type.arraytype;

import com.google.common.collect.ImmutableList;
import hu.bme.mit.theta.common.Tuple2;
import hu.bme.mit.theta.core.model.Valuation;
import hu.bme.mit.theta.core.type.Expr;
import hu.bme.mit.theta.core.type.LitExpr;
import hu.bme.mit.theta.core.type.MultiaryExpr;
import hu.bme.mit.theta.core.type.Type;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

/**
* ArrayInitExpr is a way to specify arbitrary array 'literals' that may contain non-literal elements as well.
* Note that while this class is a descendant of MultiaryExpr, it is used in a non-standard way:
* - ops is only used as a generic Type type,
* - ops are solely used for inter-object interactions, intra-class the `elems` and `elseElem` are used.
* - `elems` and `elseElem` are mapped to `ops` by first placing the `elseElem`, then all indices, then all elements.
*/

public final class ArrayInitExpr<IndexType extends Type, ElemType extends Type> extends MultiaryExpr<Type, ArrayType<IndexType, ElemType>> {

private static final int HASH_SEED = 241;
private static final String OPERATOR_LABEL = "arrayinit";

private final ArrayType<IndexType, ElemType> type;

private final List<Tuple2<Expr<IndexType>, Expr<ElemType>>> elems;

private final Expr<ElemType> elseElem;

private ArrayInitExpr(final List<Tuple2<Expr<IndexType>, Expr<ElemType>>> elems,
final Expr<ElemType> elseElem, final ArrayType<IndexType, ElemType> type) {
//noinspection unchecked
super(Stream.concat(List.of((Expr<Type>)elseElem).stream(), Stream.concat(elems.stream().map(objects -> (Expr<Type>)objects.get1()), elems.stream().map(objects -> (Expr<Type>)objects.get2()))).collect(Collectors.toList()));
this.type = checkNotNull(type);
this.elseElem = checkNotNull(elseElem);
this.elems = checkNotNull(elems);
}

public static <IndexType extends Type, ElemType extends Type> ArrayInitExpr<IndexType, ElemType> of(
final List<Tuple2<Expr<IndexType>, Expr<ElemType>>> elems,
final Expr<ElemType> elseElem,
final ArrayType<IndexType, ElemType> type) {
return new ArrayInitExpr<>(elems, elseElem, type);
}

public List<Tuple2<Expr<IndexType>, Expr<ElemType>>> getElements() { return ImmutableList.copyOf(elems); }

public Expr<ElemType> getElseElem() { return elseElem; }

@Override
public ArrayType<IndexType, ElemType> getType() {
return type;
}

@Override
public LitExpr<ArrayType<IndexType, ElemType>> eval(final Valuation val) {
return ArrayLitExpr.of(elems.stream().map(objects -> Tuple2.of(objects.get1().eval(val), objects.get2().eval(val))).collect(Collectors.toList()), elseElem, type);
}


@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
} else if (obj instanceof ArrayInitExpr) {
final ArrayInitExpr<?, ?> that = (ArrayInitExpr<?, ?>) obj;
return this.type.equals(that.type) && this.elems.equals(that.elems) && elseElem.equals(that.elseElem);
} else {
return false;
}
}


@SuppressWarnings("unchecked")
@Override
public MultiaryExpr<Type, ArrayType<IndexType, ElemType>> with(Iterable<? extends Expr<Type>> ops) {
long size = StreamSupport.stream(ops.spliterator(), false).count();
checkState(size % 2 == 1, "Ops must be odd long!");
long counter = 0;
Expr<ElemType> elseElem = null;
List<Expr<IndexType>> indices = new ArrayList<>();
List<Expr<ElemType>> elems = new ArrayList<>();
for (Expr<Type> op : ops) {
if(counter == 0) elseElem = (Expr<ElemType>) op;
else if (counter <= (size-1)/2) indices.add((Expr<IndexType>) op);
else elems.add((Expr<ElemType>) op);
++counter;
}
List<Tuple2<Expr<IndexType>, Expr<ElemType>>> newOps = new ArrayList<>();
for (int i = 0; i < indices.size(); i++) {
newOps.add(Tuple2.of(indices.get(i), elems.get(i)));
}
return ArrayInitExpr.of(newOps, elseElem, type);
}

@Override
protected int getHashSeed() {
return HASH_SEED;
}

@Override
public String getOperatorLabel() {
return OPERATOR_LABEL;
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
package hu.bme.mit.theta.core.type.arraytype;

import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;

import com.google.common.collect.ImmutableList;

import hu.bme.mit.theta.common.Tuple2;
import hu.bme.mit.theta.common.Utils;
import hu.bme.mit.theta.core.model.ImmutableValuation;
import hu.bme.mit.theta.core.model.Valuation;
import hu.bme.mit.theta.core.type.Expr;
import hu.bme.mit.theta.core.type.LitExpr;
import hu.bme.mit.theta.core.type.NullaryExpr;
import hu.bme.mit.theta.core.type.Type;
import hu.bme.mit.theta.core.utils.ExprSimplifier;

import java.util.List;
import java.util.stream.Collectors;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

public final class ArrayLitExpr<IndexType extends Type, ElemType extends Type> extends NullaryExpr<ArrayType<IndexType, ElemType>>
implements LitExpr<ArrayType<IndexType, ElemType>> {
Expand All @@ -21,27 +25,34 @@ public final class ArrayLitExpr<IndexType extends Type, ElemType extends Type> e

private final ArrayType<IndexType, ElemType> type;

private final List<Tuple2<Expr<IndexType>, Expr<ElemType>>> elems;
private final List<Tuple2<LitExpr<IndexType>, LitExpr<ElemType>>> elems;

private final Expr<ElemType> elseElem;
private final LitExpr<ElemType> elseElem;

private volatile int hashCode;

private ArrayLitExpr(final List<Tuple2<Expr<IndexType>, Expr<ElemType>>> elems,
private ArrayLitExpr(final List<Tuple2<? extends Expr<IndexType>, ? extends Expr<ElemType>>> elems,
final Expr<ElemType> elseElem, final ArrayType<IndexType, ElemType> type) {
this.type = checkNotNull(type);
this.elseElem = checkNotNull(elseElem);
this.elems = checkNotNull(elems);
Expr<ElemType> simplifiedElem = ExprSimplifier.simplify(checkNotNull(elseElem), ImmutableValuation.empty());
checkState(simplifiedElem instanceof LitExpr, "ArrayLitExprs shall only contain literal values!");
this.elseElem = (LitExpr<ElemType>) simplifiedElem;
this.elems = checkNotNull(elems).stream().map(elem -> {
Expr<IndexType> index = ExprSimplifier.simplify(elem.get1(), ImmutableValuation.empty());
Expr<ElemType> element = ExprSimplifier.simplify(elem.get2(), ImmutableValuation.empty());
checkState(index instanceof LitExpr && element instanceof LitExpr, "ArrayLitExprs shall only contain literal values");
return Tuple2.of((LitExpr<IndexType>)index, (LitExpr<ElemType>)element);
}).collect(Collectors.toList());
}

public static <IndexType extends Type, ElemType extends Type> ArrayLitExpr<IndexType, ElemType> of(
final List<Tuple2<Expr<IndexType>, Expr<ElemType>>> elems,
final List<Tuple2<? extends Expr<IndexType>, ? extends Expr<ElemType>>> elems,
final Expr<ElemType> elseElem,
final ArrayType<IndexType, ElemType> type) {
return new ArrayLitExpr<>(elems, elseElem, type);
}

public List<Tuple2<Expr<IndexType>, Expr<ElemType>>> getElements() { return ImmutableList.copyOf(elems); }
public List<Tuple2<LitExpr<IndexType>, LitExpr<ElemType>>> getElements() { return ImmutableList.copyOf(elems); }

public Expr<ElemType> getElseElem() { return elseElem; }

Expand All @@ -61,7 +72,7 @@ public int hashCode() {
if (tmp == 0) {
tmp = HASH_SEED;
tmp = 31 * tmp + type.hashCode();
for(Tuple2<Expr<IndexType>, Expr<ElemType>> elem : elems) {
for(Tuple2<LitExpr<IndexType>, LitExpr<ElemType>> elem : elems) {
tmp = 31 * tmp + elem.hashCode();
}
hashCode = tmp;
Expand All @@ -75,7 +86,7 @@ public boolean equals(final Object obj) {
return true;
} else if (obj instanceof ArrayLitExpr) {
final ArrayLitExpr<?, ?> that = (ArrayLitExpr<?, ?>) obj;
return this.type.equals(that.type) && this.elems.equals(that.elems);
return this.type.equals(that.type) && this.elems.equals(that.elems) && elseElem.equals(that.elseElem);
} else {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,20 @@
*/
package hu.bme.mit.theta.core.type.arraytype;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static hu.bme.mit.theta.core.utils.TypeUtils.cast;

import java.util.List;

import com.google.common.collect.ImmutableList;

import hu.bme.mit.theta.common.Tuple2;
import hu.bme.mit.theta.common.Utils;
import hu.bme.mit.theta.core.model.Valuation;
import hu.bme.mit.theta.core.type.Expr;
import hu.bme.mit.theta.core.type.LitExpr;
import hu.bme.mit.theta.core.type.Type;

import java.util.List;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static hu.bme.mit.theta.core.utils.TypeUtils.cast;

public final class ArrayReadExpr<IndexType extends Type, ElemType extends Type> implements Expr<ElemType> {

private static final int HASH_SEED = 1321;
Expand Down Expand Up @@ -76,9 +75,9 @@ public ElemType getType() {
public LitExpr<ElemType> eval(final Valuation val) {
ArrayLitExpr<IndexType, ElemType> arrayVal = (ArrayLitExpr<IndexType, ElemType>)array.eval(val);
LitExpr<IndexType> indexVal = index.eval(val);
for (Tuple2<Expr<IndexType>, Expr<ElemType>> elem : arrayVal.getElements()) {
for (Tuple2<LitExpr<IndexType>, LitExpr<ElemType>> elem : arrayVal.getElements()) {
if (elem.get1().equals(indexVal)){
return (LitExpr<ElemType>)elem.get2();
return elem.get2();
}
}
return (LitExpr<ElemType>)arrayVal.getElseElem();
Expand Down
Loading

0 comments on commit e256056

Please sign in to comment.