diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala index d55f225bc96fc83319f1cf0ae41f503a7c5a873d..7901e428fe605751a7162132face803f8ec9c805 100644 --- a/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala +++ b/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala @@ -78,6 +78,9 @@ trait SMTLIBTarget { case RawArrayType(from, to) => r + case ft @ FunctionType(from, to) => + FiniteLambda(r.default, r.elems.toSeq, ft) + case _ => unsupported("Unable to extract from raw array for "+tpe) } diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala index f781cdc480b545e3e8c3e285a95735a68b315cad..91e205c6af357074fc39beb1dc34f104e0b6e8c7 100644 --- a/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala +++ b/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala @@ -188,9 +188,12 @@ trait SMTLIBZ3Target extends SMTLIBTarget { for (me <- smodel) me match { case DefineFun(s, args, kind, e) => if(args.isEmpty) { - val id = variables.toA(s) - // EK: this is a little hack, we pass models for array functions as let-defs - model += id -> fromSMT(e, id.getType)(Map(), modelFunDefs) + variables.getA(s) match { + case Some(id) => + // EK: this is a little hack, we pass models for array functions as let-defs + model += id -> fromSMT(e, id.getType)(Map(), modelFunDefs) + case _ => // function, should be handled elsewhere + } } case _ => } diff --git a/src/main/scala/leon/solvers/templates/LambdaManager.scala b/src/main/scala/leon/solvers/templates/LambdaManager.scala index 7249313f16c1f171d1ef15888616ebff1108c468..d8aa9026f49cbd7b9e58db2ee42d6c80e82698fe 100644 --- a/src/main/scala/leon/solvers/templates/LambdaManager.scala +++ b/src/main/scala/leon/solvers/templates/LambdaManager.scala @@ -112,7 +112,7 @@ class LambdaManager[T](encoder: TemplateEncoder[T]) { template.contextEquality(that) match { case None => encoder.mkNot(equals) case Some(Seq()) => equals - case Some(seq) => encoder.mkImplies(encoder.mkAnd(seq : _*), equals) + case Some(seq) => encoder.mkEquals(encoder.mkAnd(seq : _*), equals) } }.toSeq } diff --git a/src/main/scala/leon/solvers/templates/Templates.scala b/src/main/scala/leon/solvers/templates/Templates.scala index c7e79263f807141565644ac864cafa59ad70a8b7..6c26fa8d88f856c24b710a38b936492e828fe7ad 100644 --- a/src/main/scala/leon/solvers/templates/Templates.scala +++ b/src/main/scala/leon/solvers/templates/Templates.scala @@ -230,7 +230,6 @@ object LambdaTemplate { private def structuralKey[T](lambda: Lambda, dependencies: Map[Identifier, T]): (Lambda, Map[Identifier,T]) = { def closureIds(expr: Expr): Seq[Identifier] = { - val vars = variablesOf(expr) val allVars : Seq[Identifier] = foldRight[Seq[Identifier]] { (expr, idSeqs) => idSeqs.foldLeft(expr match { case Variable(id) => Seq(id) @@ -238,10 +237,11 @@ object LambdaTemplate { })((acc, seq) => acc ++ seq) } (expr) + val vars = variablesOf(expr) allVars.filter(vars(_)).distinct } - val grouped : Map[TypeTree, Seq[Identifier]] = closureIds(lambda).groupBy(_.getType) + val grouped : Map[TypeTree, Seq[Identifier]] = (lambda.args.map(_.id) ++ closureIds(lambda)).groupBy(_.getType) val subst : Map[Identifier, Identifier] = grouped.foldLeft(Map.empty[Identifier,Identifier]) { case (subst, (tpe, ids)) => val currentVars = typedIds(tpe) @@ -257,7 +257,10 @@ object LambdaTemplate { subst ++ (ids zip typedVars) } - val structuralLambda = replaceFromIDs(subst.mapValues(_.toVariable), lambda).asInstanceOf[Lambda] + val newArgs = lambda.args.map(vd => ValDef(subst(vd.id), vd.tpe)) + val newBody = replaceFromIDs(subst.mapValues(_.toVariable), lambda.body) + val structuralLambda = Lambda(newArgs, newBody) + val newDeps = dependencies.map { case (id, idT) => subst(id) -> idT } structuralLambda -> newDeps diff --git a/src/test/resources/regression/verification/purescala/valid/FlatMap.scala b/src/test/resources/regression/verification/purescala/valid/FlatMap.scala new file mode 100644 index 0000000000000000000000000000000000000000..56f8c47e86d835055e6c3a9ea44cb7b886e464fb --- /dev/null +++ b/src/test/resources/regression/verification/purescala/valid/FlatMap.scala @@ -0,0 +1,48 @@ +import leon.lang._ +import leon.collection._ + +object FlatMap { + + def append[T](l1: List[T], l2: List[T]): List[T] = l1 match { + case Cons(head, tail) => Cons(head, append(tail, l2)) + case Nil() => l2 + } + + def associative_append_lemma[T](l1: List[T], l2: List[T], l3: List[T]): Boolean = { + append(append(l1, l2), l3) == append(l1, append(l2, l3)) + } + + def associative_append_lemma_induct[T](l1: List[T], l2: List[T], l3: List[T]): Boolean = { + l1 match { + case Nil() => associative_append_lemma(l1, l2, l3) + case Cons(head, tail) => associative_append_lemma(l1, l2, l3) && associative_append_lemma_induct(tail, l2, l3) + } + }.holds + + def flatMap[T,U](list: List[T], f: T => List[U]): List[U] = list match { + case Cons(head, tail) => append(f(head), flatMap(tail, f)) + case Nil() => Nil() + } + + def associative_lemma[T,U,V](list: List[T], f: T => List[U], g: U => List[V]): Boolean = { + flatMap(flatMap(list, f), g) == flatMap(list, (x: T) => flatMap(f(x), g)) + } + + def associative_lemma_induct[T,U,V](list: List[T], flist: List[U], glist: List[V], f: T => List[U], g: U => List[V]): Boolean = { + associative_lemma(list, f, g) && + append(glist, flatMap(append(flist, flatMap(list, f)), g)) == append(append(glist, flatMap(flist, g)), flatMap(list, (x: T) => flatMap(f(x), g))) && + (glist match { + case Cons(ghead, gtail) => + associative_lemma_induct(list, flist, gtail, f, g) + case Nil() => flist match { + case Cons(fhead, ftail) => + associative_lemma_induct(list, ftail, g(fhead), f, g) + case Nil() => list match { + case Cons(head, tail) => associative_lemma_induct(tail, f(head), Nil(), f, g) + case Nil() => true + } + } + }) + }.holds + +} diff --git a/src/test/resources/regression/verification/purescala/valid/FlatMap.scala.BAK b/src/test/resources/regression/verification/purescala/valid/FlatMap.scala.BAK deleted file mode 100644 index fc177bd1f9e750fe2f79cf9fe910d3279ceaf299..0000000000000000000000000000000000000000 --- a/src/test/resources/regression/verification/purescala/valid/FlatMap.scala.BAK +++ /dev/null @@ -1,69 +0,0 @@ -import leon.lang._ -import leon.collection._ - -object Lists5 { - - def append[T](l1: List[T], l2: List[T]): List[T] = l1 match { - case Cons(head, tail) => Cons(head, append(tail, l2)) - case Nil() => l2 - } - - def associative_append_lemma[T](l1: List[T], l2: List[T], l3: List[T]): Boolean = { - append(append(l1, l2), l3) == append(l1, append(l2, l3)) - } - - def associative_append_lemma_induct[T](l1: List[T], l2: List[T], l3: List[T]): Boolean = { - l1 match { - case Nil() => associative_append_lemma(l1, l2, l3) - case Cons(head, tail) => associative_append_lemma(l1, l2, l3) && associative_append_lemma_induct(tail, l2, l3) - } - }.holds - - def flatMap[T,U](list: List[T], f: T => List[U]): List[U] = list match { - case Cons(head, tail) => append(f(head), flatMap(tail, f)) - case Nil() => Nil() - } - - def associative_lemma[T,U,V](list: List[T], f: T => List[U], g: U => List[V]): Boolean = { - flatMap(flatMap(list, f), g) == flatMap(list, (x: T) => flatMap(f(x), g)) - } - - def associative_lemma_helper[T,U,V](fprev: List[U], fcur: List[U], fgprev: List[V], fgcur: List[V], tail: List[T], f: T => List[U], g: U => List[V]): Boolean = { - val left = fcur match { - case Cons(fhead, ftail) => - flatMap(append(fprev, Cons(fhead, append(ftail, flatMap(tail, f)))), g) - case Nil() => - flatMap(append(fprev, flatMap(tail, f)), g) - } - - val right = fgcur match { - case Cons(fghead, fgtail) => - append(fgprev, Cons(fghead, append(fgtail, flatMap(tail, (x: T) => flatMap(f(x), g))))) - case Nil() => - append(fgprev, flatMap(tail, (x: T) => flatMap(f(x), g))) - } - - left == right && (fgcur match { - case Cons(fghead, fgtail) => associative_lemma_helper(fprev, fcur, append(fgprev, Cons(fghead, Nil())), fgtail, tail, f, g) - case Nil() => fcur match { - case Cons(fhead, ftail) => associative_lemma_helper(append(fprev, Cons(fhead, Nil())), ftail, fgprev, fgcur, tail, f, g) - case Nil() => tail match { - case Nil() => true - case Cons(head, tail) => f(head) match { - case fl @ Cons(fh, ft) => associative_lemma_helper(Nil(), fl, Nil(), flatMap(fl, g), tail, f, g) - case Nil() => associative_lemma_helper(Nil(), Nil(), Nil(), Nil(), tail, f, g) - } - } - } - }) - } - - def associative_lemma_induct[T,U,V](list: List[T], f: T => List[U], g: U => List[V]): Boolean = { - list match { - case Nil() => associative_lemma(list, f, g) - case Cons(head, tail) => - associative_lemma(list, f, g) && associative_lemma_induct(tail, f, g) && associative_lemma_helper(Nil(), Nil(), Nil(), Nil(), list, f, g) - } - }.holds - -}