-
Manos Koukoutos authoredManos Koukoutos authored
IntInduction.scala 3.64 KiB
/* Copyright 2009-2014 EPFL, Lausanne */
package leon
package synthesis
package rules
import purescala.Common._
import purescala.Expressions._
import purescala.Extractors._
import purescala.Constructors._
import purescala.Types._
import purescala.Definitions._
case object IntInduction extends Rule("Int Induction") {
def instantiateOn(implicit hctx: SearchContext, p: Problem): Traversable[RuleInstantiation] = {
p.as match {
case List(IsTyped(origId, IntegerType)) =>
val tpe = tupleTypeWrap(p.xs.map(_.getType))
val inductOn = FreshIdentifier(origId.name, origId.getType, true)
val postXs = p.xs map (id => FreshIdentifier("r", id.getType, true))
val postXsMap = (p.xs zip postXs).toMap.mapValues(Variable)
val newPhi = subst(origId -> Variable(inductOn), p.phi)
val newPc = subst(origId -> Variable(inductOn), p.pc)
val newWs = subst(origId -> Variable(inductOn), p.ws)
val postCondGT = substAll(postXsMap + (origId -> Minus(Variable(inductOn), InfiniteIntegerLiteral(1))), p.phi)
val postCondLT = substAll(postXsMap + (origId -> Plus(Variable(inductOn), InfiniteIntegerLiteral(1))), p.phi)
val subBase = Problem(List(), subst(origId -> InfiniteIntegerLiteral(0), p.ws), subst(origId -> InfiniteIntegerLiteral(0), p.pc), subst(origId -> InfiniteIntegerLiteral(0), p.phi), p.xs)
val subGT = Problem(inductOn :: postXs, newWs, and(GreaterThan(Variable(inductOn), InfiniteIntegerLiteral(0)), postCondGT, newPc), newPhi, p.xs)
val subLT = Problem(inductOn :: postXs, newWs, and(LessThan(Variable(inductOn), InfiniteIntegerLiteral(0)), postCondLT, newPc), newPhi, p.xs)
val onSuccess: List[Solution] => Option[Solution] = {
case List(base, gt, lt) =>
if (base.pre != BooleanLiteral(true) || (gt.pre != BooleanLiteral(true) && lt.pre != BooleanLiteral(true))) {
// Required to avoid an impossible base-case, which suffices to
// allow invalid programs.
None
} else {
val preIn = or(and(Equals(Variable(inductOn), InfiniteIntegerLiteral(0)), base.pre),
and(GreaterThan(Variable(inductOn), InfiniteIntegerLiteral(0)), gt.pre),
and(LessThan(Variable(inductOn), InfiniteIntegerLiteral(0)), lt.pre))
val preOut = subst(inductOn -> Variable(origId), preIn)
val newFun = new FunDef(FreshIdentifier("rec", alwaysShowUniqueID = true), Nil, tpe, Seq(ValDef(inductOn)),DefType.MethodDef)
val idPost = FreshIdentifier("res", tpe)
newFun.precondition = Some(preIn)
newFun.postcondition = Some(Lambda(Seq(ValDef(idPost)), letTuple(p.xs.toSeq, Variable(idPost), p.phi)))
newFun.body = Some(
IfExpr(Equals(Variable(inductOn), InfiniteIntegerLiteral(0)),
base.toExpr,
IfExpr(GreaterThan(Variable(inductOn), InfiniteIntegerLiteral(0)),
letTuple(postXs, FunctionInvocation(newFun.typed, Seq(Minus(Variable(inductOn), InfiniteIntegerLiteral(1)))), gt.toExpr)
, letTuple(postXs, FunctionInvocation(newFun.typed, Seq(Plus(Variable(inductOn), InfiniteIntegerLiteral(1)))), lt.toExpr)))
)
Some(Solution(preOut, base.defs++gt.defs++lt.defs+newFun, FunctionInvocation(newFun.typed, Seq(Variable(origId))),
Seq(base, gt, lt).forall(_.isTrusted)))
}
case _ =>
None
}
Some(decomp(List(subBase, subGT, subLT), onSuccess, s"Int Induction on '$origId'"))
case _ =>
None
}
}
}