From 3e99e54d4057b3ce116c914de0e6baec19426dc5 Mon Sep 17 00:00:00 2001 From: Regis Blanc <regwblanc@gmail.com> Date: Mon, 6 Jun 2016 18:44:01 +0200 Subject: [PATCH] array encoded with raw array operations --- src/main/scala/leon/solvers/RawArray.scala | 36 +++++++++++++ .../leon/solvers/smtlib/SMTLIBTarget.scala | 6 +++ .../leon/solvers/theories/ArrayEncoder.scala | 50 +++++++++---------- .../leon/solvers/z3/AbstractZ3Solver.scala | 5 ++ .../purescala/valid/ADTWithArray1.scala | 14 ++++++ .../purescala/valid/ADTWithArray2.scala | 14 ++++++ 6 files changed, 98 insertions(+), 27 deletions(-) create mode 100644 src/test/resources/regression/verification/purescala/valid/ADTWithArray1.scala create mode 100644 src/test/resources/regression/verification/purescala/valid/ADTWithArray2.scala diff --git a/src/main/scala/leon/solvers/RawArray.scala b/src/main/scala/leon/solvers/RawArray.scala index 59b11894d..cfad13b80 100644 --- a/src/main/scala/leon/solvers/RawArray.scala +++ b/src/main/scala/leon/solvers/RawArray.scala @@ -6,6 +6,8 @@ package solvers import purescala.Types._ import purescala.Expressions._ import purescala.Extractors._ +import purescala.{PrettyPrintable, PrinterContext} +import purescala.PrinterHelpers._ // Corresponds to a complete map (SMT Array), not a Leon/Scala array // Only used within solvers or SMT for encoding purposes @@ -29,3 +31,37 @@ case class RawArrayValue(keyTpe: TypeTree, elems: Map[Expr, Expr], default: Expr s"RawArray[${keyTpe.asString}]($elemsString, default = ${default.asString})" } } + +case class RawArraySelect(array: Expr, index: Expr) extends Expr with Extractable with PrettyPrintable { + + override def extract: Option[(Seq[Expr], (Seq[Expr]) => Expr)] = + Some((Seq(array, index), es => RawArraySelect(es(0), es(1)))) + + val getType = array.getType.asInstanceOf[RawArrayType].to + + override def asString(implicit ctx: LeonContext) = { + s"$array($index)" + } + + override def printWith(implicit pctx: PrinterContext) = { + p"$array($index)" + } + +} + +case class RawArrayUpdated(array: Expr, index: Expr, newValue: Expr) extends Expr with Extractable with PrettyPrintable { + + val getType = array.getType + + override def extract: Option[(Seq[Expr], (Seq[Expr]) => Expr)] = + Some((Seq(array, index, newValue), es => RawArrayUpdated(es(0), es(1), es(2)))) + + override def asString(implicit ctx: LeonContext) = { + s"$array($index) = $newValue" + } + + override def printWith(implicit pctx: PrinterContext) = { + p"$array($index) = $newValue" + } + +} diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala index 77ed0a9c8..bb576468c 100644 --- a/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala +++ b/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala @@ -438,6 +438,11 @@ trait SMTLIBTarget extends Interruptible { FunctionApplication(selector, Seq(toSMT(a))) + case al @ RawArraySelect(a, i) => + ArraysEx.Select(toSMT(a), toSMT(i)) + case al @ RawArrayUpdated(a, i, e) => + ArraysEx.Store(toSMT(a), toSMT(i), toSMT(e)) + case al @ ArraySelect(a, i) => val tpe = normalizeType(a.getType) @@ -445,6 +450,7 @@ trait SMTLIBTarget extends Interruptible { ArraysEx.Select(scontent, toSMT(i)) + case al @ ArrayUpdated(a, i, e) => val tpe = normalizeType(a.getType) diff --git a/src/main/scala/leon/solvers/theories/ArrayEncoder.scala b/src/main/scala/leon/solvers/theories/ArrayEncoder.scala index fd12709f6..a1bf0e4c3 100644 --- a/src/main/scala/leon/solvers/theories/ArrayEncoder.scala +++ b/src/main/scala/leon/solvers/theories/ArrayEncoder.scala @@ -6,8 +6,11 @@ package theories import purescala.Common._ import purescala.Expressions._ +import purescala.ExprOps._ +import purescala.Extractors._ import purescala.Constructors._ import purescala.Types._ +import purescala.Types._ import purescala.Definitions._ import leon.utils.Bijection import leon.purescala.TypeOps @@ -15,7 +18,7 @@ import leon.purescala.TypeOps class ArrayEncoder(ctx: LeonContext, p: Program) extends TheoryEncoder { private val arrayTypeParam = TypeParameter.fresh("A") - val ArrayCaseClass = new CaseClassDef(FreshIdentifier("Array"), Seq(TypeParameterDef(arrayTypeParam)), None, false) + val ArrayCaseClass = new CaseClassDef(FreshIdentifier("InternalArray"), Seq(TypeParameterDef(arrayTypeParam)), None, false) val rawArrayField = FreshIdentifier("raw", RawArrayType(Int32Type, arrayTypeParam)) val lengthField = FreshIdentifier("length", Int32Type) ArrayCaseClass.setFields(Seq(ValDef(rawArrayField), ValDef(lengthField))) @@ -60,36 +63,32 @@ class ArrayEncoder(ctx: LeonContext, p: Program) extends TheoryEncoder { val ra = transform(a) Some(CaseClassSelector(ra.getType.asInstanceOf[CaseClassType], ra, lengthField)) - //case al @ ArraySelect(a, i) => - // val tpe = normalizeType(a.getType) - - // val scontent = FunctionApplication(selectors.toB((tpe, 1)), Seq(toSMT(a))) - - // ArraysEx.Select(scontent, toSMT(i)) - - //case al @ ArrayUpdated(a, i, e) => - // val tpe = normalizeType(a.getType) + case al @ ArraySelect(a, i) => + val ra = transform(a) + val ri = transform(i) + val raw = CaseClassSelector(ra.getType.asInstanceOf[CaseClassType], ra, rawArrayField) + Some(RawArraySelect(raw, ri)) - // val sa = toSMT(a) - // val ssize = FunctionApplication(selectors.toB((tpe, 0)), Seq(sa)) - // val scontent = FunctionApplication(selectors.toB((tpe, 1)), Seq(sa)) + case al @ ArrayUpdated(a, i, e) => + val ra = transform(a) + val ri = transform(i) + val re = transform(e) - // val newcontent = ArraysEx.Store(scontent, toSMT(i), toSMT(e)) + val length = CaseClassSelector(ra.getType.asInstanceOf[CaseClassType], ra, lengthField) + val raw = CaseClassSelector(ra.getType.asInstanceOf[CaseClassType], ra, rawArrayField) - // val constructor = constructors.toB(tpe) - // FunctionApplication(constructor, Seq(ssize, newcontent)) + Some(CaseClass(ra.getType.asInstanceOf[CaseClassType], Seq(RawArrayUpdated(raw, ri, re), length))) - //case a @ FiniteArray(elems, oDef, size) => - // val tpe @ ArrayType(to) = normalizeType(a.getType) - // declareSort(tpe) + case a @ FiniteArray(elems, oDef, size) => - // val default: Expr = oDef.getOrElse(simplestValue(to)) + val tpe @ ArrayType(to) = a.getType + val default: Expr = transform(oDef.getOrElse(simplestValue(to))) - // val arr = toSMT(RawArrayValue(Int32Type, elems.map { - // case (k, v) => IntLiteral(k) -> v - // }, default)) + val raw = RawArrayValue(Int32Type, elems.map { + case (k, v) => IntLiteral(k) -> transform(v) + }, default) + Some(CaseClass(ArrayCaseClass.typed(Seq(to)), Seq(raw, transform(size)))) - // FunctionApplication(constructors.toB(tpe), List(toSMT(size), arr)) case _ => None } @@ -123,11 +122,8 @@ class ArrayEncoder(ctx: LeonContext, p: Program) extends TheoryEncoder { override def transformExpr(e: Expr)(implicit binders: Map[Identifier, Identifier]): Option[Expr] = e match { case cc @ CaseClass(cct, args) if cct.classDef == ArrayCaseClass => - println("Hey there!") val Seq(rawArray, length) = args - println(args) val leonArray = fromRaw(rawArray, length) - println(leonArray) Some(leonArray) // Some(StringLiteral(convertToString(cc)).copiedFrom(cc)) //case FunctionInvocation(SizeI, Seq(a)) => diff --git a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala index 99567a865..15b654e7f 100644 --- a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala +++ b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala @@ -417,6 +417,11 @@ trait AbstractZ3Solver extends Z3Solver { val tester = testers.toB(cct) tester(rec(e)) + case al @ RawArraySelect(a, i) => + z3.mkSelect(rec(a), rec(i)) + case al @ RawArrayUpdated(a, i, e) => + z3.mkStore(rec(a), rec(i), rec(e)) + case al @ ArraySelect(a, i) => val tpe = normalizeType(a.getType) diff --git a/src/test/resources/regression/verification/purescala/valid/ADTWithArray1.scala b/src/test/resources/regression/verification/purescala/valid/ADTWithArray1.scala new file mode 100644 index 000000000..62eeb2b10 --- /dev/null +++ b/src/test/resources/regression/verification/purescala/valid/ADTWithArray1.scala @@ -0,0 +1,14 @@ +import leon.collection._ + +object ADTWithArray1 { + + case class A1(x: Int) + + case class B(t: Array[A1]) + + def test(b: B): A1 = { + require(b.t.length > 0 && b.t(0).x > 0) + b.t(0) + } ensuring(a => a.x >= 0) + +} diff --git a/src/test/resources/regression/verification/purescala/valid/ADTWithArray2.scala b/src/test/resources/regression/verification/purescala/valid/ADTWithArray2.scala new file mode 100644 index 000000000..89a89a3f9 --- /dev/null +++ b/src/test/resources/regression/verification/purescala/valid/ADTWithArray2.scala @@ -0,0 +1,14 @@ +import leon.collection._ + +object ADTWithArray2 { + + case class A1(x: Int) + + case class B(t: Array[A1]) + + def test(b: B): Int = { + require(b.t.length > 2) + b.t.length + } ensuring(a => a > 0) + +} -- GitLab