diff --git a/src/main/scala/leon/termination/StructuralSize.scala b/src/main/scala/leon/termination/StructuralSize.scala index e4b7d42139f5a921c23012c202c7d877422b1803..8d53f0c6f34ff0579318360ecdf93394e24fcd6b 100644 --- a/src/main/scala/leon/termination/StructuralSize.scala +++ b/src/main/scala/leon/termination/StructuralSize.scala @@ -16,23 +16,51 @@ trait StructuralSize { private val sizeCache : MutableMap[TypeTree, FunDef] = MutableMap.empty - // function absBigInt(x: BigInt): BigInt = if (x >= 0) x else -x - val typedAbsBigIntFun = makeAbsFun(IntegerType, "absBigInt", e => UMinus(e), InfiniteIntegerLiteral(0)) - - // function absInt(x: Int): Int = if (x >= 0) x else -x - val typedAbsIntFun = makeAbsFun(Int32Type, "absInt", e => BVUMinus(e), IntLiteral(0)) - - def makeAbsFun(tp: TypeTree, name: String, uminus: Expr => Expr, zero: Expr): TypedFunDef = { - val x = FreshIdentifier("x", tp, alwaysShowUniqueID = true) - val absFun = new FunDef(FreshIdentifier(name, alwaysShowUniqueID = true), Seq(), Seq(ValDef(x)), tp) + /* Absolute value for BigInt type + * + * def absBigInt(x: BigInt): BigInt = if (x >= 0) x else -x + */ + val typedAbsBigIntFun: TypedFunDef = { + val x = FreshIdentifier("x", IntegerType, alwaysShowUniqueID = true) + val absFun = new FunDef(FreshIdentifier("absBigInt", alwaysShowUniqueID = true), Seq(), Seq(ValDef(x)), IntegerType) absFun.body = Some(IfExpr( - GreaterEquals(Variable(x), zero), + GreaterEquals(Variable(x), InfiniteIntegerLiteral(0)), Variable(x), - uminus(Variable(x)) + UMinus(Variable(x)) )) absFun.typed } + /* Absolute value for Int (32 bit) type + * + * We use a recursive function here as the bv2int functionality provided + * through SMT solvers is waaaaay too slow. Recursivity requires the + * postcondition for verification efforts to succeed. + * + * def absInt(x: Int): BigInt = (if (x == 0) { + * BigInt(0) + * } else if (x > 0) { + * 1 + absInt(x - 1) + * } else { + * 1 + absInt(-(x + 1)) // avoids -Integer.MIN_VALUE overflow + * }) ensuring (_ >= 0) + */ + def typedAbsIntFun: TypedFunDef = { + val x = FreshIdentifier("x", Int32Type, alwaysShowUniqueID = true) + val absFun = new FunDef(FreshIdentifier("absInt", alwaysShowUniqueID = true), Seq(), Seq(ValDef(x)), IntegerType) + absFun.body = Some(IfExpr( + Equals(Variable(x), IntLiteral(0)), + InfiniteIntegerLiteral(0), + IfExpr( + GreaterThan(Variable(x), IntLiteral(0)), + Plus(InfiniteIntegerLiteral(1), FunctionInvocation(absFun.typed, Seq(BVMinus(Variable(x), IntLiteral(1))))), + Plus(InfiniteIntegerLiteral(1), FunctionInvocation(absFun.typed, Seq(BVUMinus(BVPlus(Variable(x), IntLiteral(1)))))) + ))) + val res = FreshIdentifier("res", IntegerType, alwaysShowUniqueID = true) + absFun.postcondition = Some(Lambda(Seq(ValDef(res)), GreaterEquals(Variable(res), InfiniteIntegerLiteral(0)))) + absFun.typed + } + def size(expr: Expr) : Expr = { def funDef(ct: ClassType, cases: ClassType => Seq[MatchCase]): FunDef = { // we want to reuse generic size functions for sub-types @@ -78,10 +106,8 @@ trait StructuralSize { }).foldLeft[Expr](InfiniteIntegerLiteral(0))(Plus) case IntegerType => FunctionInvocation(typedAbsBigIntFun, Seq(expr)) -/* case Int32Type => FunctionInvocation(typedAbsIntFun, Seq(expr)) -*/ case _ => InfiniteIntegerLiteral(0) } }