diff --git a/src/main/scala/insynth/InSynth.scala b/src/main/scala/insynth/InSynth.scala index 42d386bc90735608fa63892de65fa5bbfe97f537..ae6d24a7063b9c354b384035fd1286952519ed10 100644 --- a/src/main/scala/insynth/InSynth.scala +++ b/src/main/scala/insynth/InSynth.scala @@ -46,6 +46,7 @@ class InSynth(declarations: List[Declaration], goalType: Type, ordered: Boolean def getExpressions(builder: InitialEnvironmentBuilder) = { info("InSynth synthesizing type + " + goalType + " with declarations " + builder.getAllDeclarations.mkString("\n")) val proofTree = solver.getProofTree(builder) + info("Proof tree is acquired") assert(proofTree != null, "Proof tree is null" ) assert(1 == proofTree.getNodes.size) diff --git a/src/main/scala/insynth/InSynthTemp.scala b/src/main/scala/insynth/InSynthTemp.scala new file mode 100644 index 0000000000000000000000000000000000000000..8c06803df352eedf8f6cea6336c1e3999275831a --- /dev/null +++ b/src/main/scala/insynth/InSynthTemp.scala @@ -0,0 +1,74 @@ +package insynth + +import insynth.reconstruction.stream.{ OrderedStreamFactory, UnorderedStreamFactory } +import insynth.reconstruction.codegen.CodeGenerator +import insynth.reconstruction.{ FastReconstructor => Reconstructor } + +import insynth.interfaces.Declaration +import insynth.engine.InitialEnvironmentBuilder + +import insynth.leon.loader.LeonLoader +import insynth.leon.LeonQueryBuilder + +import _root_.leon.purescala.Definitions.Program +import _root_.leon.purescala.Trees.Hole +import _root_.leon.purescala.TypeTrees.{ TypeTree => Type } + +import insynth.util.logging.HasLogger + +/** + * Main class for the synthesis process invocation + * @param program Leon program object that contains the hole + * @param hole hole in the program on which the synthesis is called + */ +class InSynthTemp(declarations: List[Declaration], goalType: Type, ordered: Boolean = true) extends HasLogger { + +// def this(program: Program, hole: Hole, ordered: Boolean) = +// this(new LeonLoader(program, hole).load, hole.getType, ordered) + + def this(loader: LeonLoader, ordered: Boolean) = + this(loader.load, loader.hole.getType, ordered) + + lazy val solver = new Solver(declarations, new LeonQueryBuilder(goalType)) + + def getExpressions = { + info("InSynth synthesizing type + " + goalType + " with declarations " + solver.allDeclarations.mkString("\n")) + val proofTree = solver.getProofTree + + assert(proofTree != null, "Proof tree is null" ) + assert(1 == proofTree.getNodes.size) + + val codegen = new CodeGenerator + + Reconstructor(proofTree.getNodes.head, codegen, ordered) + } + + def getExpressions(builder: InitialEnvironmentBuilder) = { + info("InSynth synthesizing type + " + goalType + " with declarations " + builder.getAllDeclarations.mkString("\n")) + val proofTree = solver.getProofTree(builder) + info("Proof tree is acquired") + + assert(proofTree != null, "Proof tree is null" ) + assert(1 == proofTree.getNodes.size) + + val codegen = new CodeGenerator + + Reconstructor(proofTree.getNodes.head, codegen, ordered) + } + + def getCurrentBuilder = solver.currentBuilder + +} + +object InSynthTemp { + + def apply(declarations: List[Declaration], goalType: Type, ordered: Boolean) = + new InSynthTemp(declarations, goalType, ordered) + +// def apply(program: Program, hole: Hole, ordered: Boolean) = +// new InSynthTemp(new LeonLoader(program, hole).load, hole.getType, ordered) + + def apply(loader: LeonLoader, ordered: Boolean) = + new InSynthTemp(loader.load, loader.hole.getType, ordered) + +} \ No newline at end of file diff --git a/src/main/scala/insynth/leon/LeonDeclaration.scala b/src/main/scala/insynth/leon/LeonDeclaration.scala index 40255fb76073fd2641eab93c329d69e278446d80..5c263a3dd301e1f2a6513bfe2d7b9a05ae736dd5 100644 --- a/src/main/scala/insynth/leon/LeonDeclaration.scala +++ b/src/main/scala/insynth/leon/LeonDeclaration.scala @@ -29,9 +29,9 @@ extends Declaration(inSynthType, weight) { def getDomainType = leonType - def getSimpleName = expression.toString + def getSimpleName = expression.getSimpleName - override def toString = getSimpleName + ":" + inSynthType + ":" + leonType + "[" + expression + "]" + override def toString = getSimpleName + " : " + inSynthType + " : " + leonType + " [" + expression + "]" } diff --git a/src/main/scala/insynth/leon/ReconstructionExpression.scala b/src/main/scala/insynth/leon/ReconstructionExpression.scala index 26731b2ef069d0babd578b1855b9638a595b32bf..3d9692e45af10dc9b2b1f169a61ef18596bff795 100644 --- a/src/main/scala/insynth/leon/ReconstructionExpression.scala +++ b/src/main/scala/insynth/leon/ReconstructionExpression.scala @@ -26,7 +26,7 @@ case object ErrorExpression extends ReconstructionExpression { object ImmediateExpression { - def apply(id: Identifier, expr: Expr): ImmediateExpression = ImmediateExpression(id.toString, expr) + def apply(id: Identifier, expr: Expr): ImmediateExpression = ImmediateExpression(id.name, expr) } @@ -42,7 +42,7 @@ case class ImmediateExpression( name: String, expr: Expr ) extends Reconstructi object UnaryReconstructionExpression { - def apply(id: Identifier, funToExpr: Expr => Expr): UnaryReconstructionExpression = UnaryReconstructionExpression(id.toString, funToExpr) + def apply(id: Identifier, funToExpr: Expr => Expr): UnaryReconstructionExpression = UnaryReconstructionExpression(id.name, funToExpr) } @@ -58,7 +58,7 @@ case class UnaryReconstructionExpression( name: String, funToExpr: Expr => Expr object NaryReconstructionExpression { - def apply(id: Identifier, funToExpr: List[Expr] => Expr): NaryReconstructionExpression = NaryReconstructionExpression(id.toString, funToExpr) + def apply(id: Identifier, funToExpr: List[Expr] => Expr): NaryReconstructionExpression = NaryReconstructionExpression(id.name, funToExpr) } diff --git a/src/main/scala/insynth/leon/loader/DeclarationFactory.scala b/src/main/scala/insynth/leon/loader/DeclarationFactory.scala index 16c2bd6df1fd19fc412e91c621bf4ada55265400..809de1141df485de7a66c6ce85cdcea78bead39e 100644 --- a/src/main/scala/insynth/leon/loader/DeclarationFactory.scala +++ b/src/main/scala/insynth/leon/loader/DeclarationFactory.scala @@ -1,12 +1,11 @@ package insynth.leon.loader -import insynth.leon.{ LeonDeclaration => Declaration, ReconstructionExpression, - ErrorExpression, UnaryReconstructionExpression, ImmediateExpression } +import insynth.leon.{ LeonDeclaration => Declaration, _ } import insynth.engine.InitialEnvironmentBuilder -import insynth.structures.{ SuccinctType => InSynthType, Variable => InSynthVariable, _} +import insynth.structures.{ SuccinctType => InSynthType, Variable => InSynthVariable, _ } import insynth.leon.TypeTransformer -import leon.purescala.Definitions.{ Program, FunDef, ClassTypeDef, VarDecl } +import leon.purescala.Definitions._ import leon.purescala.TypeTrees.{ TypeTree => LeonType, _ } import leon.purescala.Common.{ Identifier, FreshIdentifier } import leon.purescala.Trees._ @@ -45,13 +44,15 @@ object DeclarationFactory { } def makeInheritance(from: ClassTypeDef, to: ClassTypeDef) = { - val expr = UnaryReconstructionExpression(from + " is " + to, identity[Expr] _) + val expr = UnaryReconstructionExpression("[" + + from.id.name + "=>" + to.id.name + "]", identity[Expr] _) val inSynthType = Arrow(TSet(TypeTransformer(from)), TypeTransformer(to)) Declaration(expr, inSynthType, Untyped) } def makeInheritance(from: ClassType, to: ClassType) = { - val expr = UnaryReconstructionExpression("Inheritane(" + from.classDef + "<<is>>" + to.classDef + ")", identity[Expr] _) + val expr = UnaryReconstructionExpression("[" + + from.classDef.id.name + "=>" + to.classDef.id.name + "]", identity[Expr] _) val inSynthType = Arrow(TSet(TypeTransformer(from)), TypeTransformer(to)) Declaration(expr, inSynthType, FunctionType(List(from), to)) } @@ -68,6 +69,13 @@ object DeclarationFactory { throw new RuntimeException Declaration(getAbsExpression(inSynthType), inSynthType, null) } + +// def makeFieldDeclaration(id: Identifier, caseClassDef: CaseClassType) = { +// makeDeclaration( +// NaryReconstructionExpression( id.name , { CaseClass(caseClassDef, _: List[Expr]) } ), +// FunctionType(caseClassDef.fields map { _.id.getType } toList, classMap(id)) +// ) +// } // define this for abstract declarations def getAbsExpression(inSynthType: InSynthType) = diff --git a/src/main/scala/insynth/leon/loader/HoleExtractor.scala b/src/main/scala/insynth/leon/loader/HoleExtractor.scala index 2a917c3383ab979d4524cd7eff48a1b55783d119..61248d08b0f3aa093c9cb10053e67cf7ba88a2cb 100644 --- a/src/main/scala/insynth/leon/loader/HoleExtractor.scala +++ b/src/main/scala/insynth/leon/loader/HoleExtractor.scala @@ -21,9 +21,9 @@ class HoleExtractor(program: Program, hole: Hole) { for ( funDef <-program.definedFunctions; if funDef.hasBody; - val (foundHole, declarations) = scanMethod(funDef.getBody); + (foundHole, declarations) = scanMethod(funDef.getBody); if foundHole; - val argDeclarations = funDef.args map { makeArgumentDeclaration(_) } + argDeclarations = funDef.args map { makeArgumentDeclaration(_) } ) { foundHoleCount+=1 diff --git a/src/main/scala/insynth/leon/loader/Loader.scala b/src/main/scala/insynth/leon/loader/Loader.scala index 44175bd8ecb748cd738ab1b8b7e9cebe20d600f7..47a6d517fabc7c5b4ac7739ac2b04ccca0d24a13 100644 --- a/src/main/scala/insynth/leon/loader/Loader.scala +++ b/src/main/scala/insynth/leon/loader/Loader.scala @@ -69,7 +69,7 @@ case class LeonLoader(program: Program, hole: Hole, fine("adding fields of variable " + variable) for (field <- fields) list += makeDeclaration( - ImmediateExpression( "Field(" + cas + "." + field.id + ")", + ImmediateExpression( field.id.name , CaseClassSelector(cas, variable.toVariable, field.id) ), field.id.getType ) @@ -152,7 +152,7 @@ case class LeonLoader(program: Program, hole: Hole, case cas: CaseClassDef => for (field <- cas.fields) yield makeDeclaration( - UnaryReconstructionExpression("Field(" + cas + "." + field.id + ")", { CaseClassSelector(cas, _: Expr, field.id) }), + UnaryReconstructionExpression(field.id.name, { CaseClassSelector(cas, _: Expr, field.id) }), FunctionType(List(classMap(cas.id)), field.id.getType)) } @@ -166,11 +166,11 @@ case class LeonLoader(program: Program, hole: Hole, for (caseClassDef@CaseClassDef(id, parent, fields) <- program.definedClasses) yield fields match { case Nil => makeDeclaration( - ImmediateExpression( "Cst(" + id + ")", { CaseClass(caseClassDef, Nil) } ), + ImmediateExpression( id.name, { CaseClass(caseClassDef, Nil) } ), classMap(id) ) case _ => makeDeclaration( - NaryReconstructionExpression( "Cst(" + id + ")", { CaseClass(caseClassDef, _: List[Expr]) } ), + NaryReconstructionExpression( id.name , { CaseClass(caseClassDef, _: List[Expr]) } ), FunctionType(fields map { _.id.getType } toList, classMap(id)) ) } diff --git a/src/main/scala/insynth/leon/loader/PreLoader.scala b/src/main/scala/insynth/leon/loader/PreLoader.scala index ba25d94687356912889c762159cf766567bfb50f..8d420f8ad1980928f7760fd1093db65a77a77192 100644 --- a/src/main/scala/insynth/leon/loader/PreLoader.scala +++ b/src/main/scala/insynth/leon/loader/PreLoader.scala @@ -197,7 +197,7 @@ object PreLoader extends ( (Boolean) => List[Declaration] ) { x: LeonType => makeDeclaration( makeNAE( "If", (args: List[Expr]) => args match { - case List(cond, then, elze) => IfExpr(cond, then, elze) + case List(cond, then_, elze) => IfExpr(cond, then_, elze) case _ => throw new RuntimeException }), FunctionType( List(BooleanType, x, x), x ) diff --git a/src/main/scala/insynth/reconstruction/FastReconstructor.scala b/src/main/scala/insynth/reconstruction/FastReconstructor.scala new file mode 100644 index 0000000000000000000000000000000000000000..72cba71ae22fedfdb6a60922f11ab5bee97e1218 --- /dev/null +++ b/src/main/scala/insynth/reconstruction/FastReconstructor.scala @@ -0,0 +1,47 @@ +package insynth.reconstruction + +import insynth.structures.{ SimpleNode, Weight } +import insynth.reconstruction.shortcut._ +import insynth.reconstruction.stream.{ Node => LambdaNode, _ } +import insynth.reconstruction.codegen.CodeGenerator + +import insynth.Config +import insynth.util.format.{ FormatSuccinctNode, FormatIntermediate, FormatStreamUtils } +import insynth.util.logging.HasLogger +import insynth.util._ + +/** + * Object for reconstruction of proof trees into output(s) + */ +object FastReconstructor extends ( (SimpleNode, CodeGenerator, Boolean) => Stream[Output]) with HasLogger { + + def apply(tree: SimpleNode, codeGenerator: CodeGenerator, streamOrdered: Boolean = false) = { + // logging + entering("apply", FormatSuccinctNode(tree, 8).toString) + fine("reconstructor got proof tree size: " + ProofTreeOperations.size(tree)) + + // create an ordered/unordered extractor + val transformer = + if (streamOrdered) + new Transformer2(new OrderedStreamFactory[LambdaNode]) + else + new Transformer2(new UnorderedStreamFactory[LambdaNode]) + + // transform the trees (first two steps of the code generation phase) + val extractedTrees = transformer(tree) + + // logging + info("extractor phase done") + + // for each tree, generate the code for it + val generatedCode = extractedTrees map { + resPair => Output(codeGenerator(resPair._1), resPair._2) + } + + // logging + info("solutions are generated") + + generatedCode + } + +} diff --git a/src/main/scala/insynth/reconstruction/Output.scala b/src/main/scala/insynth/reconstruction/Output.scala index fbe07c09655968c097099acf6848b2d715c5ba12..0f0a13a999c38eaf0428138401c56675560d001e 100644 --- a/src/main/scala/insynth/reconstruction/Output.scala +++ b/src/main/scala/insynth/reconstruction/Output.scala @@ -9,4 +9,9 @@ import leon.purescala.Trees.Expr case class Output(snippet: Expr, weight: Weight){ def getSnippet = snippet def getWeight = weight + + override def equals(obj:Any) = { + obj.isInstanceOf[Output] && obj.asInstanceOf[Output].snippet == this.snippet + } + } \ No newline at end of file diff --git a/src/main/scala/insynth/reconstruction/Reconstructor.scala b/src/main/scala/insynth/reconstruction/Reconstructor.scala index 159f399af5931a095476c92471f72bc3fc05357d..858719a66f1c36adf43c835a5381b744f3e2c80a 100644 --- a/src/main/scala/insynth/reconstruction/Reconstructor.scala +++ b/src/main/scala/insynth/reconstruction/Reconstructor.scala @@ -8,6 +8,7 @@ import insynth.reconstruction.codegen.CodeGenerator import insynth.Config import insynth.util.format.{ FormatSuccinctNode, FormatIntermediate, FormatStreamUtils } import insynth.util.logging.HasLogger +import insynth.util._ /** * Object for reconstruction of proof trees into output(s) @@ -17,13 +18,15 @@ object Reconstructor extends ( (SimpleNode, CodeGenerator, Boolean) => Stream[Ou def apply(tree: SimpleNode, codeGenerator: CodeGenerator, streamOrdered: Boolean = false) = { // logging entering("apply", FormatSuccinctNode(tree, 8).toString) + fine("reconstructor got proof tree size: " + ProofTreeOperations.size(tree)) // transform the trees (first two steps of the code generation phase) val transformedTree = IntermediateTransformer(tree) // logging info("intermediate transform phase done") - fine("after intermediate " + FormatIntermediate(transformedTree)) + finest("after intermediate " + FormatIntermediate(transformedTree)) + fine("intermediate tree size " + IntermediateTreeOperations.size(transformedTree)) // create an ordered/unordered extractor val extractor = @@ -37,7 +40,7 @@ object Reconstructor extends ( (SimpleNode, CodeGenerator, Boolean) => Stream[Ou // logging info("extractor phase done") - fine("got streamable " + FormatStreamUtils(extractor.transformedStreamable)) + finest("got streamable " + FormatStreamUtils(extractor.transformedStreamable)) // for each tree, generate the code for it val generatedCode = extractedTrees map { diff --git a/src/main/scala/lesynth/SynthesizerExamples.scala b/src/main/scala/lesynth/SynthesizerExamples.scala index 03d696d1219ae98291a11bf0f8cf5bea034e55b2..ddcd81a59b7a777fe499ec28e2391fa3fbb52205 100755 --- a/src/main/scala/lesynth/SynthesizerExamples.scala +++ b/src/main/scala/lesynth/SynthesizerExamples.scala @@ -63,13 +63,13 @@ class SynthesizerForRuleExamples( numberOfCheckInIteration: Int = 5, exampleRunnerSteps: Int = 4000) extends HasLogger { - info("Synthesizer:") - info("numberOfBooleanSnippets: %d".format(numberOfBooleanSnippets)) - info("numberOfCounterExamplesToGenerate: %d".format(numberOfCounterExamplesToGenerate)) -// info("leonTimeout: %d".format(leonTimeout)) + reporter.info("Synthesizer:") + reporter.info("numberOfBooleanSnippets: %d".format(numberOfBooleanSnippets)) + reporter.info("numberOfCounterExamplesToGenerate: %d".format(numberOfCounterExamplesToGenerate)) +// reporter.info("leonTimeout: %d".format(leonTimeout)) - info("holeFunDef: %s".format(holeFunDef)) - info("problem: %s".format(problem.toString)) + reporter.info("holeFunDef: %s".format(holeFunDef)) + reporter.info("problem: %s".format(problem.toString)) // flag denoting if a correct body has been synthesized private var found = false @@ -101,7 +101,7 @@ class SynthesizerForRuleExamples( // store initial precondition since it will be overwritten private var initialPrecondition: Expr = _ // accumulate precondition for the remaining branch to synthesize - private var accumulatingPrecondition: Expr = _ + private var accumulatingCondition: Expr = _ // accumulate the final expression of the hole private var accumulatingExpression: Expr => Expr = _ @@ -157,7 +157,7 @@ class SynthesizerForRuleExamples( reporter.info("######Iteration #" + iteration + " ###############") reporter.info("####################################") reporter.info("# precondition is: " + holeFunDef.precondition.getOrElse(BooleanLiteral(true))) - reporter.info("# accumulatingPrecondition is: " + accumulatingPrecondition) + reporter.info("# accumulatingCondition is: " + accumulatingCondition) reporter.info("# accumulatingExpression(Unit) is: " + accumulatingExpression(UnitLiteral)) reporter.info("####################################") interactivePause @@ -189,9 +189,9 @@ class SynthesizerForRuleExamples( successfulCandidates } -// info("Got candidates of size: " + candidates.size + +// reporter.info("Got candidates of size: " + candidates.size + // " , first 10 of them are: " + candidates.take(10).map(_.getSnippet.toString).mkString(",\t")) - info("Got candidates of size: " + candidates.size) + reporter.info("Got candidates of size: " + candidates.size) fine("Got candidates: " + candidates.map(_.getSnippet.toString).mkString(",\n")) interactivePause @@ -205,24 +205,12 @@ class SynthesizerForRuleExamples( val ranker = evaluationStrategy.getRanker(candidates, accumulatingExpression, gatheredExamples) exampleRunner = evaluationStrategy.getExampleRunner - info("Ranking candidates...") + reporter.info("Ranking candidates...") synthInfo.start(Action.Evaluation) val (maxCandidate, maxCandidateInd) = ranker.getMax val (passed, failedModulo) = ranker.fullyEvaluate(maxCandidateInd) synthInfo.end - // restore original precondition and body - holeFunDef.precondition = oldPreconditionSaved - holeFunDef.body = oldBodySaved - - // check for timeouts - if (!keepGoing) break - - info("candidate with the most successfull evaluations is: " + maxCandidate.getExpr + - " with pass count " + passed + " out of " + gatheredExamples.size) - interactivePause - numberOfTested += batchSize - // get all examples that failed evaluation to filter potential conditions val evaluation = evaluationStrategy.getEvaluation // evaluate all remaining examples @@ -231,15 +219,30 @@ class SynthesizerForRuleExamples( evaluation.evaluate(maxCandidateInd) val (evalArray, size) = evaluation.getEvaluationVector(maxCandidateInd) assert(size == gatheredExamples.size) - val failedExamples = (gatheredExamples zip evalArray).filterNot { + val (passedExamplesPairs, failedExamplesPairs) = (gatheredExamples zip evalArray).partition { case (ex, result) => result - }.map(_._1) - fine("Failed examples for the maximum candidate: " + failedExamples.mkString(", ")) + } + val examplesPartition = + (passedExamplesPairs.map(_._1), failedExamplesPairs.map(_._1)) + + fine("Failed examples for the maximum candidate: " + examplesPartition) + + // restore original precondition and body + holeFunDef.precondition = oldPreconditionSaved + holeFunDef.body = oldBodySaved + + // check for timeouts + if (!keepGoing) break + + reporter.info("candidate with the most successfull evaluations is: " + maxCandidate.getExpr + + " with pass count " + passed + " out of " + gatheredExamples.size) + interactivePause + numberOfTested += batchSize // interactivePause val currentCandidateExpr = maxCandidate.getExpr - if (tryToSynthesizeBranch(currentCandidateExpr, failedExamples)) { + if (tryToSynthesizeBranch(currentCandidateExpr, examplesPartition)) { //noBranchFoundIteration = 0 // after a branch is synthesized it makes sense to consider candidates that previously failed @@ -272,7 +275,7 @@ class SynthesizerForRuleExamples( } if (variableRefinedBranch) { - info("Variable refined, doing branch synthesis again") + reporter.info("Variable refined, doing branch synthesis again") // get new snippets snippets = synthesizeBranchExpressions snippetsIterator = snippets.iterator @@ -284,9 +287,9 @@ class SynthesizerForRuleExamples( // reseting iterator needed because we may have some expressions that previously did not work snippetsIterator = snippets.iterator - info("Filtering based on precondition: " + holeFunDef.precondition.get) + reporter.info("Filtering based on precondition: " + And(initialPrecondition, accumulatingCondition)) fine("counterexamples before filter: " + gatheredExamples.size) - exampleRunner.filter(holeFunDef.precondition.get) + exampleRunner.filter(And(initialPrecondition, accumulatingCondition)) gatheredExamples = exampleRunner.examples fine("counterexamples after filter: " + gatheredExamples.size) fine("counterexamples after filter: " + gatheredExamples.mkString("\n")) @@ -297,7 +300,7 @@ class SynthesizerForRuleExamples( } def generateCounterexamples(program: Program, funDef: FunDef, number: Int): (Seq[Map[Identifier, Expr]], Expr) = { - info("Generate counter examples with precondition " + funDef.precondition.getOrElse(BooleanLiteral(true))) + reporter.info("Generate counter examples with precondition " + funDef.precondition.getOrElse(BooleanLiteral(true))) // save current precondition var precondition = funDef.precondition.getOrElse(BooleanLiteral(true)) @@ -314,7 +317,7 @@ class SynthesizerForRuleExamples( // check if solver could solved this instance if (solved == false && !map.isEmpty) { - info("Found counterexample: " + map) + reporter.info("Found counterexample: " + map) // add current counterexample maps :+= map @@ -340,12 +343,12 @@ class SynthesizerForRuleExamples( def getCurrentBuilder = new InitialEnvironmentBuilder(allDeclarations) def synthesizeBranchExpressions = { - info("Invoking synthesis for branch expressions") + reporter.info("Invoking synthesis for branch expressions") synthInfo.profile(Generation) { inSynth.getExpressions(getCurrentBuilder).distinct } } def synthesizeBooleanExpressions = { - info("Invoking synthesis for condition expressions") + reporter.info("Invoking synthesis for condition expressions") synthInfo.start(Generation) if (variableRefinedCondition) { // store for later fetch (will memoize values) @@ -364,8 +367,8 @@ class SynthesizerForRuleExamples( } def interactivePause = { - System.out.println("Press Any Key To Continue..."); - new java.util.Scanner(System.in).nextLine(); +// System.out.println("Press Any Key To Continue..."); +// new java.util.Scanner(System.in).nextLine(); } def getNewExampleQueue = PriorityQueue[(Expr, Int)]()( @@ -390,11 +393,20 @@ class SynthesizerForRuleExamples( // interactivePause // accumulate precondition for the remaining branch to synthesize - accumulatingPrecondition = holeFunDef.precondition.getOrElse(BooleanLiteral(true)) + accumulatingCondition = BooleanLiteral(true) // save initial precondition - initialPrecondition = accumulatingPrecondition + initialPrecondition = holeFunDef.precondition.getOrElse(BooleanLiteral(true)) + val holeFunDefBody = holeFunDef.getBody // accumulate the final expression of the hole - accumulatingExpression = (finalExp: Expr) => finalExp + accumulatingExpression = (finalExp: Expr) => { + def replaceChoose(expr: Expr) = expr match { + case _: Choose => Some(finalExp) + case _ => None + } + + import TreeOps._ + matchToIfThenElse(searchAndReplace(replaceChoose)(holeFunDefBody)) + } //accumulatingExpressionMatch = accumulatingExpression // each variable of super type can actually have a subtype @@ -412,7 +424,8 @@ class SynthesizerForRuleExamples( fine("Introduced examples: " + gatheredExamples.mkString("\t")) } - def tryToSynthesizeBranch(snippetTree: Expr, failedExamples: Seq[Example]): Boolean = { + def tryToSynthesizeBranch(snippetTree: Expr, examplesPartition: (Seq[Example], Seq[Example])): Boolean = { + val (succeededExamples, failedExamples) = examplesPartition // replace hole in the body with the whole if-then-else structure, with current snippet tree val oldBody = holeFunDef.getBody val newBody = accumulatingExpression(snippetTree) @@ -424,13 +437,13 @@ class SynthesizerForRuleExamples( snippetTree.setType(hole.desiredType) //holeFunDef.getBody.setType(hole.desiredType) - info("Current candidate solution is:\n" + holeFunDef) + reporter.info("Current candidate solution is:\n" + holeFunDef) if (failedExamples.isEmpty) { // check if solver could solved this instance fine("Analyzing program for funDef:" + holeFunDef) val (result, map) = analyzeFunction(holeFunDef) - info("Solver returned: " + result + " with CE " + map) + reporter.info("Solver returned: " + result + " with CE " + map) if (result) { // mark the branch found @@ -456,12 +469,13 @@ class SynthesizerForRuleExamples( holeFunDef.precondition = preconditionToRestore // get counterexamples - info("Going to generating counterexamples: " + holeFunDef) - val (maps, precondition) = generateCounterexamples(program, holeFunDef, numberOfCounterExamplesToGenerate) - - // collect (add) counterexamples from leon - if (collectCounterExamplesFromLeon) - gatheredExamples ++= maps.map(Example(_)) +// info("Going to generating counterexamples: " + holeFunDef) +// val (maps, precondition) = generateCounterexamples(program, holeFunDef, numberOfCounterExamplesToGenerate) +// +// // collect (add) counterexamples from leon +// if (collectCounterExamplesFromLeon) +// gatheredExamples ++= maps.map(Example(_)) + val maps = Seq[Map[Identifier, Expr]]() // will modify funDef body and precondition, restore it later try { @@ -486,11 +500,11 @@ class SynthesizerForRuleExamples( }) ) { fine("boolean snippet is: " + innerSnippetTree) - info("Trying: " + innerSnippetTree + " as a condition.") + reporter.info("Trying: " + innerSnippetTree + " as a condition.") val (innerFound, innerPrec) = tryToSynthesizeBooleanCondition( snippetTree, innerSnippetTree, // counter examples represent those for which candidate fails - (failedExamples.map(_.map) ++ maps) + (failedExamples.map(_.map) ++ maps), succeededExamples.map(_.map) ) // if precondition found @@ -522,22 +536,25 @@ class SynthesizerForRuleExamples( } } - def tryToSynthesizeBooleanCondition(snippetTree: Expr, innerSnippetTree: Expr, counterExamples: Seq[Map[Identifier, Expr]]): (Boolean, Option[Expr]) = { + def tryToSynthesizeBooleanCondition(snippetTree: Expr, innerSnippetTree: Expr, + counterExamples: Seq[Map[Identifier, Expr]], succExamples: Seq[Map[Identifier, Expr]]): (Boolean, Option[Expr]) = { // new condition together with existing precondition - val newCondition = And(Seq(accumulatingPrecondition, innerSnippetTree)) + val newPrecondition = And(Seq(initialPrecondition, accumulatingCondition, innerSnippetTree)) + val newPathCondition = And(Seq(problem.pc, accumulatingCondition, innerSnippetTree)) // new expression should not be false // val notFalseEquivalence = Not(newCondition) val isSatisfiable = - checkSatisfiabilityNoMod(newCondition) - fine("Is " + newCondition + " satisfiable: " + isSatisfiable) + checkSatisfiabilityNoMod(newPathCondition) + fine("Is " + newPathCondition + " satisfiable: " + isSatisfiable) // continue if our expression is not contradictory if (isSatisfiable) { // check if synthesized boolean expression implies precondition (counterexamples) - val implyCounterExamples = (false /: counterExamples) { + var hadRuntimeError = false + val implyCounterExamplesPre = (false /: counterExamples) { case (false, exMapping) => - exampleRunner.evaluateToResult(newCondition, exMapping) match { + exampleRunner.evaluateToResult(newPrecondition, exMapping) match { case EvaluationResults.Successful(BooleanLiteral(false)) => false case r => @@ -545,7 +562,7 @@ class SynthesizerForRuleExamples( val newFunId = FreshIdentifier("tempIntroducedFunction22") val newFun = new FunDef(newFunId, holeFunDef.returnType, holeFunDef.args) // newFun.precondition = Some(newCondition) - newFun.precondition = holeFunDef.precondition + newFun.precondition = Some(initialPrecondition) newFun.postcondition = holeFunDef.postcondition def replaceFunDef(expr: Expr) = expr match { @@ -560,6 +577,8 @@ class SynthesizerForRuleExamples( IfExpr(innerSnippetTree, snippetTree, error) import TreeOps._ +// println("ifInInnermostElse " + ifInInnermostElse) +// println("acc expr before replace: " + accumulatingExpression(ifInInnermostElse)) val newBody = searchAndReplace(replaceFunDef)(accumulatingExpression(ifInInnermostElse)) newFun.body = Some(newBody) @@ -569,8 +588,8 @@ class SynthesizerForRuleExamples( val newCandidate = Let(resFresh2, newBody, - replace(Map(ResultVariable() -> LeonVariable(resFresh2)), - matchToIfThenElse(newFun.getPostcondition))) + matchToIfThenElse(replace(Map(ResultVariable() -> LeonVariable(resFresh2)), + newFun.getPostcondition))) finest("New fun for Error evaluation: " + newFun) // println("new candidate: " + newBody) @@ -588,9 +607,15 @@ class SynthesizerForRuleExamples( // interactivePause res match { - case EvaluationResults.RuntimeError("Condition flow hit unknown path.") => false + case EvaluationResults.RuntimeError("Condition flow hit unknown path.") => + hadRuntimeError = true + false case EvaluationResults.Successful(BooleanLiteral(innerRes)) => !innerRes - case _ => true + case _ => + // TODO think about this + // I put condition into precondition so some examples will be violated? + println("new evalution got: " + res + " for " + newCandidate + " and " + exMapping + " newFun is " + newFun) + true } // fine("Evaluation result for " + newCondition + " on " + exMapping + " is " + r) @@ -598,12 +623,76 @@ class SynthesizerForRuleExamples( } case _ => true } + + fine("implyCounterExamplesPre: " + implyCounterExamplesPre) + + val implyCounterExamples = if (!implyCounterExamplesPre && hadRuntimeError) { + ! succExamples.exists( exMapping => { + // TODO take care of this mess + val newFunId = FreshIdentifier("tempIntroducedFunction22") + val newFun = new FunDef(newFunId, holeFunDef.returnType, holeFunDef.args) +// newFun.precondition = Some(newCondition) + newFun.precondition = Some(initialPrecondition) + newFun.postcondition = holeFunDef.postcondition + + def replaceFunDef(expr: Expr) = expr match { + case FunctionInvocation(`holeFunDef`, args) => + Some(FunctionInvocation(newFun, args)) + case _ => None + } + + val error = Error("Condition flow hit unknown path.") + error.setType(snippetTree.getType) + val ifInInnermostElse = + IfExpr(innerSnippetTree, snippetTree, error) + + import TreeOps._ + val newBody = searchAndReplace(replaceFunDef)(accumulatingExpression(ifInInnermostElse)) + + newFun.body = Some(newBody) + + assert(newBody.getType != Untyped) + val resFresh2 = FreshIdentifier("result22", true).setType(newBody.getType) + + val newCandidate = + Let(resFresh2, newBody, + matchToIfThenElse(replace(Map(ResultVariable() -> LeonVariable(resFresh2)), + newFun.getPostcondition))) + finest("New fun for Error evaluation: " + newFun) +// println("new candidate: " + newBody) + + val newProgram = program.copy(mainObject = + program.mainObject.copy(defs = newFun +: program.mainObject.defs )) +// println("new program: " + newProgram) + + val _evaluator = new CodeGenEvaluator(synthesisContext.context, newProgram, + _root_.leon.codegen.CodeGenEvalParams(maxFunctionInvocations = 500, checkContracts = true)) + + val res = _evaluator.eval(newCandidate, exMapping) + println("for mapping: " + exMapping + "res is: " + res) +// if (newCandidate.toString contains "tree.value < value") +// interactivePause + + interactivePause + res match { + case EvaluationResults.RuntimeError("Condition flow hit unknown path.") => + false + case EvaluationResults.Successful(BooleanLiteral(innerRes)) => innerRes + case _ => + println("new evalution got: " + res + " for " + newCandidate + " and " + exMapping) + false + } + }) + } else + implyCounterExamplesPre + + fine("implyCounterExamples: " + implyCounterExamples) // interactivePause if (!implyCounterExamples) { // if expression implies counterexamples add it to the precondition and try to validate program - holeFunDef.precondition = Some(newCondition) + holeFunDef.precondition = Some(newPathCondition) // do analysis val (valid, map) = analyzeFunction(holeFunDef) @@ -623,19 +712,19 @@ class SynthesizerForRuleExamples( }) accumulatingExpression = newAccumulatingExpression - val currentBranchCondition = And(Seq(accumulatingPrecondition, innerSnippetTree)) + val currentBranchCondition = And(Seq(accumulatingCondition, innerSnippetTree)) // update accumulating precondition fine("updating accumulatingPrecondition") - accumulatingPrecondition = And(Seq(accumulatingPrecondition, Not(innerSnippetTree))) + accumulatingCondition = And(Seq(accumulatingCondition, Not(innerSnippetTree))) fine("updating hole fun precondition and body (to be hole)") // set to set new precondition - val preconditionToRestore = Some(accumulatingPrecondition) + val preconditionToRestore = Some(accumulatingCondition) val variableRefinementResult = variableRefiner.checkRefinements(innerSnippetTree, currentBranchCondition, allDeclarations) if (variableRefinementResult._1) { - info("Variable is refined.") + reporter.info("Variable is refined.") allDeclarations = variableRefinementResult._2 // the reason for two flags is for easier management of re-syntheses only if needed @@ -645,13 +734,13 @@ class SynthesizerForRuleExamples( // found a boolean snippet, break (true, preconditionToRestore) - } else { + } else { // collect (add) counterexamples from leon if (collectCounterExamplesFromLeon && !map.isEmpty) gatheredExamples ++= (map :: Nil).map(Example(_)) // reset funDef and continue with next boolean snippet - val preconditionToRestore = Some(accumulatingPrecondition) + val preconditionToRestore = Some(accumulatingCondition) (false, preconditionToRestore) } } else { diff --git a/src/main/scala/lesynth/evaluation/CodeGenExampleRunner.scala b/src/main/scala/lesynth/evaluation/CodeGenExampleRunner.scala index 269650e6f7c7a1b3825348c119d885adb8a40cfb..e6560d3beaf9900dc64e288e97d887eacae7e384 100644 --- a/src/main/scala/lesynth/evaluation/CodeGenExampleRunner.scala +++ b/src/main/scala/lesynth/evaluation/CodeGenExampleRunner.scala @@ -25,6 +25,7 @@ case class CodeGenExampleRunner(program: Program, funDef: FunDef, ctx: LeonConte val evaluationContext = ctx.copy(reporter = new SilentReporter) + fine("building codegen evaluator with program:\n" + program) lazy val _evaluator = new CodeGenEvaluator(evaluationContext, program, params) override def getEvaluator = _evaluator @@ -38,6 +39,7 @@ case class CodeGenExampleRunner(program: Program, funDef: FunDef, ctx: LeonConte ) def compile(expr: Expr, ids: Seq[Identifier]) = { + finest("Compiling expr: " + expr + " for ids: " + ids) // this get is dubious StopwatchCollections.get("Compilation").newStopwatch profile getEvaluator.compile(expr, ids).get } @@ -47,7 +49,7 @@ case class CodeGenExampleRunner(program: Program, funDef: FunDef, ctx: LeonConte override def evaluate(candidateInd: Int, exampleInd: Int) = { val closure = candidateClosures(candidateInd) - finest("Index evaluate candidate [%d]%s, for [%d]%s.".format( + finer("Index evaluate candidate [%d]%s, for [%d]%s.".format( candidateInd, candidates(candidateInd).prepareExpression, exampleInd, examples(exampleInd) )) @@ -86,15 +88,15 @@ case class CodeGenExampleRunner(program: Program, funDef: FunDef, ctx: LeonConte try { evalClosure(args) match { case Successful(BooleanLiteral(true)) => - finest("EvaluationSuccessful(true) for " + args) + fine("EvaluationSuccessful(true) for " + args) true case m => - finest("Eval failed: " + m) + fine("Eval failed: " + m) false } } catch { case e: StackOverflowError => - finest("Eval failed: " + e) + fine("Eval failed: " + e) false } } diff --git a/src/main/scala/lesynth/examples/InputExamples.scala b/src/main/scala/lesynth/examples/InputExamples.scala index 71a186e420d4c2e4e8feaf3a4de9c6032d27c937..106442bbc164993164b0a1dcf12a71a1b30e1c0d 100755 --- a/src/main/scala/lesynth/examples/InputExamples.scala +++ b/src/main/scala/lesynth/examples/InputExamples.scala @@ -5,40 +5,44 @@ import leon.purescala.TypeTrees._ import leon.purescala.Trees._ import leon.purescala.TreeOps import leon.purescala.Common.Identifier +import leon.purescala.Definitions.Program import leon.evaluators.Evaluator import leon.synthesis.Problem -import leon.purescala.DataGen +import leon.LeonContext import insynth.leon.loader.{ HoleExtractor, LeonLoader } +import leon.datagen._ object InputExamples { - import DataGen._ val rnd = new scala.util.Random(System.currentTimeMillis) val MAX_INT = 1000 - def getDataGenInputExamples(evaluator: Evaluator, p: Problem, + def getDataGenInputExamples(ctx: LeonContext, program: Program, evaluator: Evaluator, p: Problem, numOfModels: Int, numOfTries: Int, _forcedFreeVars: Option[Seq[Identifier]]) = { - val models = findModels(p.pc, evaluator, numOfModels, numOfTries, - forcedFreeVars = _forcedFreeVars) - models.toList + val ins = _forcedFreeVars.getOrElse(TreeOps.variablesOf(p.pc).toSeq) + + val models = new NaiveDataGen(ctx, program, evaluator).generateFor(ins, p.pc, numOfModels, numOfTries) + + models.toList.map(m => (ins zip m).toMap) } - def getDataGenInputExamplesRandomIntegers(evaluator: Evaluator, p: Problem, + def getDataGenInputExamplesRandomIntegers(ctx: LeonContext, program: Program, evaluator: Evaluator, p: Problem, numOfModels: Int, numOfTries: Int, _forcedFreeVars: Option[Seq[Identifier]], bound: Int = MAX_INT) = { import TreeOps._ - val models = findModels(p.pc, evaluator, numOfModels, numOfTries, - forcedFreeVars = _forcedFreeVars) + val ins = _forcedFreeVars.getOrElse(TreeOps.variablesOf(p.pc).toSeq) + + val models = new NaiveDataGen(ctx, program, evaluator).generateFor(ins, p.pc, numOfModels, numOfTries) def foundInteger(x: Expr) = x match { case _:IntLiteral => Some(IntLiteral(rnd.nextInt(bound))) case _ => None } - models.toList.map( innerMap => + models.toList.map(m => (ins zip m).toMap).map( innerMap => innerMap.map( innerEl => innerEl match { case (id, expr) => (id, searchAndReplace(foundInteger)(expr)) }) @@ -176,4 +180,4 @@ object InputExamples { // yield Map(argumentIds(0) -> l1) // // } -} \ No newline at end of file +} diff --git a/src/main/scala/lesynth/ranking/Ranker.scala b/src/main/scala/lesynth/ranking/Ranker.scala index 0137c6a98d5bb07714233c907d11c64a60ef469e..ebf6d42970ece8a984c38299c29274a1c33175a4 100644 --- a/src/main/scala/lesynth/ranking/Ranker.scala +++ b/src/main/scala/lesynth/ranking/Ranker.scala @@ -1,7 +1,7 @@ package lesynth package ranking -import util.control.Breaks._ +import scala.util.control.Breaks._ import scala.collection._ import leon.purescala.Trees.{ Variable => LeonVariable, _ } @@ -83,6 +83,14 @@ class Ranker(candidates: IndexedSeq[Candidate], evaluation: Evaluation, checkTim (candidates(rankings(0)), rankings(0)) } + def fullyEvaluate(ind: Int) = { + val tuple = tuples(ind) + for (_ <- 0 until (tuple._2 - tuple._1)) + evaluate(ind) + + tuples(ind) + } + // def getVerifiedMax = { // val results = (for (candidate <- 0 until candidates.size) // yield (candidate, diff --git a/src/main/scala/lesynth/refinement/Filter.scala b/src/main/scala/lesynth/refinement/Filter.scala index a041a49dc3f9c0924705f2a0b53493059a365f8b..90c6f25dea44c56f3e1127af488fab65e421f3cf 100755 --- a/src/main/scala/lesynth/refinement/Filter.scala +++ b/src/main/scala/lesynth/refinement/Filter.scala @@ -161,6 +161,8 @@ class Filter(program: Program, holeFunDef: FunDef, refiner: VariableRefiner) ext // if we check instance of an constructor we know that it is a constant // case CaseClassInstanceOf(_, _: CaseClass) => // true + case CaseClassInstanceOf(classDef, _: FunctionInvocation) => + true case CaseClassInstanceOf(classDef, innerExpr) if isOfClassType(innerExpr, classDef) => true diff --git a/src/main/scala/lesynth/refinement/VariableRefiner.scala b/src/main/scala/lesynth/refinement/VariableRefiner.scala index 910e1fa728aaefdc8440a26252feece0f5daaa15..a980e6fd98a215a6d5b7a2f960a0cd691d62ddb0 100755 --- a/src/main/scala/lesynth/refinement/VariableRefiner.scala +++ b/src/main/scala/lesynth/refinement/VariableRefiner.scala @@ -22,7 +22,7 @@ class VariableRefiner(directSubclassMap: Map[ClassType, Set[ClassType]], variabl classMap: Map[Identifier, ClassType], reporter: Reporter = new SilentReporter) extends HasLogger { // map from identifier into a set of possible subclasses - private var variableRefinements: MutableMap[Identifier, MutableSet[ClassType]] = MutableMap.empty + protected var variableRefinements: MutableMap[Identifier, MutableSet[ClassType]] = MutableMap.empty for (varDec <- variableDeclarations) { varDec match { case LeonDeclaration(_, _, typeOfVar: ClassType, ImmediateExpression(_, Variable(id))) => @@ -33,7 +33,7 @@ class VariableRefiner(directSubclassMap: Map[ClassType, Set[ClassType]], variabl def getPossibleTypes(id: Identifier) = variableRefinements(id) - def checkRefinements(expr: Expr, allDeclarations: List[Declaration]) = + def checkRefinements(expr: Expr, condition: Expr, allDeclarations: List[Declaration]) = // check for refinements getIdAndClassDef(expr) match { case Some(refinementPair @ (id, classType)) if variableRefinements(id).size > 1 => @@ -51,25 +51,7 @@ class VariableRefiner(directSubclassMap: Map[ClassType, Set[ClassType]], variabl // update declarations val newDeclarations = - for (dec <- allDeclarations) - yield dec match { - case LeonDeclaration(inSynthType, _, decClassType, imex @ ImmediateExpression(_, Variable(`id`))) => - (( - newType.classDef match { - case newTypeCaseClassDef@CaseClassDef(id, parent, fields) => - for (field <- fields) - yield LeonDeclaration( - ImmediateExpression( "Field(" + newTypeCaseClassDef + "." + field.id + ")", - CaseClassSelector(newTypeCaseClassDef, imex.expr, field.id) ), - TypeTransformer(field.id.getType), field.id.getType - ) - case _ => - Seq.empty - } - ): Seq[Declaration]) :+ LeonDeclaration(imex, TypeTransformer(newType), newType) - case _ => - Seq(dec) - } + refinedDeclarations(id, newType, allDeclarations) (true, newDeclarations.flatten) } else { @@ -88,4 +70,26 @@ class VariableRefiner(directSubclassMap: Map[ClassType, Set[ClassType]], variabl None } + def refinedDeclarations(id: Identifier, newType: ClassType, allDeclarations: List[Declaration]) = + for (dec <- allDeclarations) + yield dec match { + case LeonDeclaration(inSynthType, _, decClassType, imex @ ImmediateExpression(_, Variable(`id`))) => + (( + newType.classDef match { + case newTypeCaseClassDef@CaseClassDef(_, parent, fields) => + fine("matched case class def for refinement " + newTypeCaseClassDef) + for (field <- fields) + yield LeonDeclaration( + ImmediateExpression(id.name + "." + field.id.name, + CaseClassSelector(newTypeCaseClassDef, imex.expr, field.id) ), + TypeTransformer(field.id.getType), field.id.getType + ) + case _ => + Seq.empty + } + ): Seq[Declaration]) :+ LeonDeclaration(imex, TypeTransformer(newType), newType) + case _ => + Seq(dec) + } + } \ No newline at end of file diff --git a/src/main/scala/lesynth/refinement/VariableSolverRefiner.scala b/src/main/scala/lesynth/refinement/VariableSolverRefiner.scala new file mode 100755 index 0000000000000000000000000000000000000000..0ffe1aa469cb50e8ac917752801ffccad66ef220 --- /dev/null +++ b/src/main/scala/lesynth/refinement/VariableSolverRefiner.scala @@ -0,0 +1,128 @@ +package lesynth +package refinement + +import scala.collection.mutable.{Map => MutableMap} +import scala.collection.mutable.{Set => MutableSet} + +import leon._ +import leon.purescala.Extractors._ +import leon.purescala.TypeTrees._ +import leon.purescala.Trees._ +import leon.purescala.TreeOps._ +import leon.purescala.Definitions._ +import leon.solvers._ +import leon.purescala.Common.{ Identifier, FreshIdentifier } +import leon.synthesis.Problem + +import insynth.interfaces._ +import insynth.leon.loader._ +import insynth.leon._ + +import insynth.util.logging.HasLogger + +// each variable of super type can actually have a subtype +// get sine declaration maps to be able to refine them +class VariableSolverRefiner(directSubclassMap: Map[ClassType, Set[ClassType]], variableDeclarations: Seq[LeonDeclaration], + classMap: Map[Identifier, ClassType], solver: Solver, reporter: Reporter = new SilentReporter) + extends VariableRefiner(directSubclassMap, variableDeclarations, classMap, reporter) with HasLogger { + + override def checkRefinements(expr: Expr, condition: Expr, allDeclarations: List[Declaration]) = { + val superResult = super.checkRefinements(expr, condition, allDeclarations) + if (superResult._1 == false) { + val variables = allIdentifiers(expr) + if (variables.size == 1) { + val variable = variables.head + variable match { + case oldId@IsTyped(id, AbstractClassType(cd)) if variableRefinements(id).size > 1 => + + assert(variableRefinements(id).map(_.classDef) subsetOf cd.knownDescendents.toSet) + //val optCases = for (dcd <- cd.knownDescendents.sortBy(_.id.name)) yield dcd match { + val optCases = for (dcd <- variableRefinements(id).map(_.classDef)) yield dcd match { + case ccd : CaseClassDef => + fine("testing variable " + id + " with condition " + condition) + val toSat = And(condition, CaseClassInstanceOf(ccd, Variable(id))) + + fine("checking satisfiability of: " + toSat) + solver.solveSAT(toSat) match { + case (Some(false), _) => + fine("variable cannot be of type " + ccd) + None + case _ => + fine("variable can be of type " + ccd) + Some(ccd) + } + case _ => + None + } + + val cases = optCases.flatten + variableRefinements(id) = variableRefinements(id) & cases.map(CaseClassType(_)).toSet + assert(variableRefinements(id).size == cases.size) + + if (cases.size == 1) { + // update declarations + val newDeclarations = + refinedDeclarations(id, CaseClassType(cases.head), allDeclarations) + + (true, newDeclarations.flatten) + } else { + fine("cases.size != 1") + superResult + } + + case id => { + fine("no id found for refinement that has potential refinements > 1") + superResult + } + } + } else { + fine("more than one variable") + superResult + } + } + else superResult + } + + def refineProblem(p: Problem, solver: Solver) = { + + val newAs = p.as.map { + case oldId@IsTyped(id, AbstractClassType(cd)) => + + val optCases = for (dcd <- cd.knownDescendents.sortBy(_.id.name)) yield dcd match { + case ccd : CaseClassDef => + val toSat = And(p.pc, CaseClassInstanceOf(ccd, Variable(id))) + + val isImplied = solver.solveSAT(toSat) match { + case (Some(false), _) => true + case _ => false + } + + println(isImplied) + + if (!isImplied) { + Some(ccd) + } else { + None + } + case _ => + None + } + + val cases = optCases.flatten + + println(id) + println(cases) + + if (cases.size == 1) { +// id.setType(CaseClassType(cases.head)) + FreshIdentifier(oldId.name).setType(CaseClassType(cases.head)) + } else oldId + + case id => id + } + + p.copy(as = newAs) + } + + +} \ No newline at end of file diff --git a/src/main/scala/lesynth/rules/ConditionAbductionSynthesisImmediate.scala b/src/main/scala/lesynth/rules/ConditionAbductionSynthesisImmediate.scala index 6f7567fd6e4bdf9c4862e4327c0c28962eff170e..5feec355e246589a57fc08e5d39f6fb5a8d55816 100755 --- a/src/main/scala/lesynth/rules/ConditionAbductionSynthesisImmediate.scala +++ b/src/main/scala/lesynth/rules/ConditionAbductionSynthesisImmediate.scala @@ -1,80 +1,80 @@ -package lesynth -package rules - -import leon.purescala.Trees._ -import leon.purescala.Common._ -import leon.purescala.TypeTrees._ -import leon.purescala.TreeOps._ -import leon.purescala.Extractors._ -import leon.purescala.Definitions._ -import leon.synthesis._ -import leon.solvers.{ Solver, TimeoutSolver } -import leon.evaluators.CodeGenEvaluator - -import lesynth.examples.InputExamples._ -import lesynth.evaluation._ - -import leon.StopwatchCollections - -case object ConditionAbductionSynthesisImmediate extends Rule("Condition abduction synthesis (immediate).") { - def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { - - p.xs match { - case givenVariable :: Nil => - val solver = new TimeoutSolver(sctx.solver, 500L) - val program = sctx.program - val reporter = sctx.reporter - - val desiredType = givenVariable.getType - val holeFunDef = sctx.functionContext.get - - // temporary hack, should not mutate FunDef - val oldPostcondition = holeFunDef.postcondition - val oldPrecondition = holeFunDef.precondition - - try { - val freshResID = FreshIdentifier("result").setType(holeFunDef.returnType) - val freshResVar = Variable(freshResID) - - val codeGenEval = new CodeGenEvaluator(sctx.context, sctx.program) - def getInputExamples = { - () => - getDataGenInputExamples(codeGenEval, p, - 200, 6000, Some(p.as)) ++ - getDataGenInputExamplesRandomIntegers(codeGenEval, p, - 200, 6000, Some(p.as) // bound the random geenerator - , 5) - } - - val evaluationStrategy = new CodeGenEvaluationStrategy(program, holeFunDef, sctx.context, 1000) - - holeFunDef.postcondition = Some(replace( - Map(givenVariable.toVariable -> ResultVariable().setType(holeFunDef.returnType)), p.phi)) - holeFunDef.precondition = Some(p.pc) - - val synthesizer = new SynthesizerForRuleExamples( - solver, solver.getNewSolver, program, desiredType, holeFunDef, p, sctx, evaluationStrategy, - 20, 1, - reporter = reporter, - introduceExamples = getInputExamples, - numberOfTestsInIteration = 25, - numberOfCheckInIteration = 2) - - synthesizer.synthesize match { - case EmptyReport => None - case FullReport(resFunDef, _) => - List( - RuleInstantiation.immediateSuccess(p, this, - Solution(resFunDef.getPrecondition, Set.empty, resFunDef.body.get))) - } - } finally { - holeFunDef.postcondition = oldPostcondition - holeFunDef.precondition = oldPrecondition - } - case _ => - throw new RuntimeException("Rule is not applicable for more than one output variable.") - Nil - } - - } -} +//package lesynth +//package rules +// +//import leon.purescala.Trees._ +//import leon.purescala.Common._ +//import leon.purescala.TypeTrees._ +//import leon.purescala.TreeOps._ +//import leon.purescala.Extractors._ +//import leon.purescala.Definitions._ +//import leon.synthesis._ +//import leon.solvers.{ Solver, TimeoutSolver } +//import leon.evaluators.CodeGenEvaluator +// +//import lesynth.examples.InputExamples._ +//import lesynth.evaluation._ +// +//import leon.StopwatchCollections +// +//case object ConditionAbductionSynthesisImmediate extends Rule("Condition abduction synthesis (immediate).") { +// def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { +// +// p.xs match { +// case givenVariable :: Nil => +// val solver = new TimeoutSolver(sctx.solver, 500L) +// val program = sctx.program +// val reporter = sctx.reporter +// +// val desiredType = givenVariable.getType +// val holeFunDef = sctx.functionContext.get +// +// // temporary hack, should not mutate FunDef +// val oldPostcondition = holeFunDef.postcondition +// val oldPrecondition = holeFunDef.precondition +// +// try { +// val freshResID = FreshIdentifier("result").setType(holeFunDef.returnType) +// val freshResVar = Variable(freshResID) +// +// val codeGenEval = new CodeGenEvaluator(sctx.context, sctx.program) +// def getInputExamples = { +// () => +// getDataGenInputExamples(codeGenEval, p, +// 200, 6000, Some(p.as)) ++ +// getDataGenInputExamplesRandomIntegers(codeGenEval, p, +// 200, 6000, Some(p.as) // bound the random geenerator +// , 5) +// } +// +// val evaluationStrategy = new CodeGenEvaluationStrategy(program, holeFunDef, sctx.context, 1000) +// +// holeFunDef.postcondition = Some(replace( +// Map(givenVariable.toVariable -> ResultVariable().setType(holeFunDef.returnType)), p.phi)) +// holeFunDef.precondition = Some(p.pc) +// +// val synthesizer = new SynthesizerForRuleExamples( +// solver, solver.getNewSolver, program, desiredType, holeFunDef, p, sctx, evaluationStrategy, +// 20, 1, +// reporter = reporter, +// introduceExamples = getInputExamples, +// numberOfTestsInIteration = 25, +// numberOfCheckInIteration = 2) +// +// synthesizer.synthesize match { +// case EmptyReport => None +// case FullReport(resFunDef, _) => +// List( +// RuleInstantiation.immediateSuccess(p, this, +// Solution(resFunDef.getPrecondition, Set.empty, resFunDef.body.get))) +// } +// } finally { +// holeFunDef.postcondition = oldPostcondition +// holeFunDef.precondition = oldPrecondition +// } +// case _ => +// throw new RuntimeException("Rule is not applicable for more than one output variable.") +// Nil +// } +// +// } +//} diff --git a/src/main/scala/lesynth/rules/ConditionAbductionSynthesisTwoPhase.scala b/src/main/scala/lesynth/rules/ConditionAbductionSynthesisTwoPhase.scala index 53f5576114f36b789e6ea3c920eca7b195e0a9db..05a6a4cd10397e9770b011936718dd7d23076187 100755 --- a/src/main/scala/lesynth/rules/ConditionAbductionSynthesisTwoPhase.scala +++ b/src/main/scala/lesynth/rules/ConditionAbductionSynthesisTwoPhase.scala @@ -16,7 +16,7 @@ import lesynth.evaluation._ import leon.StopwatchCollections -case object ConditionAbductionSynthesisTwoPhase extends Rule("Condition abduction synthesis (two phase).") { +case object ConditionAbductionSynthesisTwoPhase extends Rule("Condition abduction synthesis (two phase).") with TopLevelRule { def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = { p.xs match { @@ -33,7 +33,6 @@ case object ConditionAbductionSynthesisTwoPhase extends Rule("Condition abductio // temporary hack, should not mutate FunDef val oldPostcondition = holeFunDef.postcondition - val oldPrecondition = holeFunDef.precondition try { val freshResID = FreshIdentifier("result").setType(holeFunDef.returnType) @@ -42,20 +41,18 @@ case object ConditionAbductionSynthesisTwoPhase extends Rule("Condition abductio val codeGenEval = new CodeGenEvaluator(sctx.context, sctx.program) def getInputExamples = { () => - getDataGenInputExamples(codeGenEval, p, - 200, 6000, Some(p.as)) ++ - getDataGenInputExamplesRandomIntegers(codeGenEval, p, - 200, 6000, Some(p.as) + //getDataGenInputExamples(sctx.context, sctx.program, codeGenEval, p, + // 100, 6000, Some(p.as)) ++ + getDataGenInputExamplesRandomIntegers(sctx.context, sctx.program, codeGenEval, p, + 100, 6000, Some(p.as) // bound the random geenerator - ,5 - ) + ,10) } - val evaluationStrategy = new CodeGenEvaluationStrategy(program, holeFunDef, sctx.context, 1000) + val evaluationStrategy = new CodeGenEvaluationStrategy(program, holeFunDef, sctx.context, 5000) holeFunDef.postcondition = Some(replace( Map(givenVariable.toVariable -> ResultVariable().setType(holeFunDef.returnType)), p.phi)) - holeFunDef.precondition = Some(p.pc) val synthesizer = new SynthesizerForRuleExamples( solver, solver.getNewSolver, program, desiredType, holeFunDef, p, sctx, evaluationStrategy, @@ -71,7 +68,10 @@ case object ConditionAbductionSynthesisTwoPhase extends Rule("Condition abductio case fr@FullReport(resFunDef, _) => println(fr.summaryString) println("Compilation time: " + StopwatchCollections.get("Compilation").getMillis) - RuleSuccess(Solution(resFunDef.getPrecondition, Set.empty, resFunDef.body.get)) + RuleSuccess( + Solution(BooleanLiteral(true), Set.empty, Tuple(Seq(resFunDef.body.get)), + isTrusted = !synthesizer.verifier.isTimeoutUsed) + ) } } catch { case e: Throwable => @@ -80,13 +80,12 @@ case object ConditionAbductionSynthesisTwoPhase extends Rule("Condition abductio RuleApplicationImpossible } finally { holeFunDef.postcondition = oldPostcondition - holeFunDef.precondition = oldPrecondition } } } }) case _ => - throw new RuntimeException("Rule is not applicable for more than one output variable.") +// throw new RuntimeException("Rule is not applicable for more than one output variable.") Nil } diff --git a/src/main/scala/lesynth/verification/AbstractVerifier.scala b/src/main/scala/lesynth/verification/AbstractVerifier.scala index 5d14e85b1161ea67cfad03f6ea94ae3c650c0b8b..18e4875d57f7b80ecbd4c303d82f61caf26c5878 100644 --- a/src/main/scala/lesynth/verification/AbstractVerifier.scala +++ b/src/main/scala/lesynth/verification/AbstractVerifier.scala @@ -19,6 +19,7 @@ abstract class AbstractVerifier(solver: IncrementalSolver, p: Problem, def analyzeFunction(funDef: FunDef) = { synthInfo.start(Verification) + fine("Analyzing function: " + funDef) // create an expression to verify val theExpr = generateInductiveVerificationCondition(funDef, funDef.getBody) @@ -84,18 +85,28 @@ abstract class AbstractVerifier(solver: IncrementalSolver, p: Problem, val bodyAndPost = Let( resFresh, newBody, - replace(Map(ResultVariable() -> resFresh.toVariable), matchToIfThenElse(p.pc)) + replace(Map(ResultVariable() -> resFresh.toVariable), matchToIfThenElse(funDef.getPostcondition)) ) val precondition = if( isThereARecursiveCall ) { - And( p.phi :: replacements.map( r => replace(r.getMapping, p.pc)) ) + And( funDef.getPrecondition :: replacements.map( r => replace(r.getMapping, funDef.getPostcondition)) ) } else - p.phi + funDef.getPrecondition +// val bodyAndPost = +// Let( +// resFresh, newBody, +// replace(Map(p.xs.head.toVariable -> resFresh.toVariable), matchToIfThenElse(p.phi)) +// ) +// +// val precondition = if( isThereARecursiveCall ) { +// And( p.pc :: replacements.map( r => replace(r.getMapping, p.phi)) ) +// } else +// p.pc val withPrec = Implies(matchToIfThenElse(precondition), bodyAndPost) - fine("Generated verification condition: " + withPrec) + info("Generated verification condition: " + withPrec) withPrec } diff --git a/src/main/scala/lesynth/verification/RelaxedVerifier.scala b/src/main/scala/lesynth/verification/RelaxedVerifier.scala index a1ce8db96e132c80cbab17d7f7cdab76d1be8422..07393f990a123d03fb6345eb99b653b9153cc5d7 100644 --- a/src/main/scala/lesynth/verification/RelaxedVerifier.scala +++ b/src/main/scala/lesynth/verification/RelaxedVerifier.scala @@ -13,8 +13,13 @@ import insynth.util.logging._ class RelaxedVerifier(solver: IncrementalSolver, p: Problem, synthInfo: SynthesisInfo = new SynthesisInfo) extends AbstractVerifier(solver, p, synthInfo) with HasLogger { + + var _isTimeoutUsed = false + + def isTimeoutUsed = _isTimeoutUsed override def checkValidity(expression: Expr) = { + fine("Checking validity - assertCnstr: " + Not(expression)) solver.assertCnstr(Not(expression)) val solverCheckResult = solver.check fine("Solver said " + solverCheckResult + " for " + expression) @@ -24,6 +29,7 @@ class RelaxedVerifier(solver: IncrementalSolver, p: Problem, synthInfo: Synthesi case Some(false) => true case None => + _isTimeoutUsed = true warning("Interpreting None (timeout) as evidence for validity.") true } @@ -31,6 +37,7 @@ class RelaxedVerifier(solver: IncrementalSolver, p: Problem, synthInfo: Synthesi override def checkValidityNoMod(expression: Expr) = { solver.push + fine("Checking validityNoMod - assertCnstr: " + Not(expression)) solver.assertCnstr(Not(expression)) val solverCheckResult = solver.check fine("Solver said " + solverCheckResult + " for " + expression) @@ -42,6 +49,7 @@ class RelaxedVerifier(solver: IncrementalSolver, p: Problem, synthInfo: Synthesi case Some(false) => true case None => + _isTimeoutUsed = true warning("Interpreting None (timeout) as evidence for validity.") true } @@ -49,6 +57,7 @@ class RelaxedVerifier(solver: IncrementalSolver, p: Problem, synthInfo: Synthesi override def checkSatisfiabilityNoMod(expression: Expr) = { solver.push + fine("Checking checkSatisfiabilityNoMod - assertCnstr: " + expression) solver.assertCnstr(expression) val solverCheckResult = solver.check fine("Solver said " + solverCheckResult + " for " + expression) diff --git a/src/test/scala/insynth/InSynthTempTest.scala b/src/test/scala/insynth/InSynthTempTest.scala new file mode 100644 index 0000000000000000000000000000000000000000..61f1d467ec5c9c63d6309b14b696d88f00889b65 --- /dev/null +++ b/src/test/scala/insynth/InSynthTempTest.scala @@ -0,0 +1,673 @@ +package insynth + +import insynth.leon._ +import insynth.leon.loader._ +import insynth.engine._ + +import insynth.reconstruction.{ intermediate => int } +import insynth.reconstruction.{ stream => lambda } +import insynth.reconstruction.shortcut._ +import insynth.reconstruction.stream.{ OrderedStreamFactory } +import insynth.reconstruction.codegen._ +import insynth.reconstruction.Output + +import _root_.leon.purescala.Definitions._ +import _root_.leon.purescala.Common._ +import _root_.leon.purescala.TypeTrees._ +import _root_.leon.purescala.Trees.{ Variable => LeonVariable, _ } + +import lesynth.refinement._ +import lesynth.examples._ +import lesynth.evaluation.CodeGenEvaluationStrategy +import lesynth.ranking.Candidate + +import org.junit.{ Test, Ignore } +import org.junit.Assert._ + +import insynth.util.format._ +import insynth.util._ +import lesynth.util._ + +import insynth.testutil.{ CommonProofTrees, CommonDeclarations, CommonLambda } + +// TODO test abstractions (vals) +class InSynthTempTest { + + import CommonDeclarations._ + import CommonProofTrees._ + import CommonLambda._ + import DeclarationFactory._ + + import Scaffold._ + import TestConfig._ + + import ProofTreeOperations.StringNode + + val transformer = new Transformer2(new OrderedStreamFactory) + val codegen = new CodeGenerator + + val maxElToOutput = 20 + + import lambda.Node._ + + def assertWeight(lambdaNode: lambda.Node, weight: Float) = + assertEquals(size(lambdaNode), weight, 0f) + + def assertWeight(expected: Int, weight: Float) = + assertEquals(expected.toFloat, weight, 0f) + + def assertWeight(pair: (lambda.Node, Float)) = + assertEquals("Node " + pair._1, size(pair._1), pair._2, 0f) + + def assertTake(stream: Stream[(lambda.Node, Float)], num: Int) = { + val result = stream take num + val message = "Part of the resulting stream: " + result.take(maxElToOutput).mkString("\n") + + for (ind <- 0 until result.size) + assertWeight(result(ind)) + for (ind <- 0 until result.size - 1) + assertTrue("Weight are not in non-decreasing order.\n" + "At position " + ind + "\n" + message, stream(ind)._2 <= stream(ind + 1)._2) + result + } + + def interactivePause = { + System.out.println("Press Any Key To Continue..."); + new java.util.Scanner(System.in).nextLine(); + } + + @Ignore + def testAddresses: Unit = { + + for ((sctx, funDef, problem) <- forFile(lesynthTestDir + "Addresses.scala")) { + val program = sctx.program + val arguments = funDef.args.map(_.id) + + assertEquals(1, problem.xs.size) + val resultVariable = problem.xs.head + val hole = Hole(resultVariable.getType) + + val loader = new LeonLoader(program, hole, problem.as, false) + val inSynth = new InSynthTemp(loader, true) + // save all declarations seen + val allDeclarations = inSynth.getCurrentBuilder.getAllDeclarations + + val solver = inSynth.solver + val solution = solver.getProofTree + + assertTrue( + ProofTreeOperations.breadthFirstSearchPrint(solution.getNodes.head), + ProofTreeOperations.checkInhabitants(solution, + StringNode("AddressBook", Set( + StringNode("[Cons=>List]", Set(StringNode("Cons"))) + , + StringNode("pers", Set(StringNode("makeAddressBook"))) + )) + )) + assertTrue( + ProofTreeOperations.breadthFirstSearchPrint(solution.getNodes.head), + ProofTreeOperations.checkInhabitants(solution, + StringNode("addToPers", Set( + StringNode("makeAddressBook", Set( +// StringNode("l.tail", Set()) + )) + , + StringNode("Address", Set( )) + )) + )) + assertTrue( + ProofTreeOperations.breadthFirstSearchPrint(solution.getNodes.head), + ProofTreeOperations.checkInhabitants(solution, + StringNode("addToBusiness", Set( + StringNode("makeAddressBook", Set( +// StringNode("l.tail", Set()) + )) + , + StringNode("Address", Set( )) + )) + )) + + val extractorResults = assertTake(transformer(solution.getNodes.head), 1000) + +// val duplicityMap = (Map[Expr, Set[(lambda.Node, Float)]]() /: extractorResults) { +// (resMap, pair) => +// val snippet = codegen(pair._1) +// resMap + (snippet -> (resMap.getOrElse(snippet, Set.empty) + pair)) +// } + +// val resTemp = transformer(solution.getNodes.head).take(100) +// +// println(resTemp.head) +// val it = resTemp.iterator.buffered +// println(it.head) +// println(it.hasNext) +// println(it.head) +// println(it.hasNext) +// +// for (output <- extractorResults) { +// print("%20s %5f" format (output._1, output._2)) +// +// System.out.println("Press Any Key To Continue..."); +// new java.util.Scanner(System.in).nextLine(); +// } +// println("\nExtracted: " + extractorResults.size) + + val message = + (for (output <- extractorResults) + yield "%20s %5f" format (output._1, output._2)).mkString("\n") + "\nExtracted: " + extractorResults.size + assertTrue("addToPers not found in extracted. results:\n" + message, extractorResults.exists(_._1.toString contains "addToPers")) + assertTrue("addToBusiness not found in extracted. results:\n" + message, extractorResults.exists(_._1.toString contains "addToBusiness")) +// +// println("Duplicity map size " + duplicityMap.size) +// for ( (key, value) <- duplicityMap.filter(_._2.size > 1).take(1)) { +// println("Key: " + key) +// println("Values: " + value.mkString("\n")) +// } + } + } + + @Ignore + def testAddressesWithRefinement: Unit = { + + for ((sctx, funDef, problem) <- forFile(lesynthTestDir + "Addresses.scala")) { + val program = sctx.program + val arguments = funDef.args.map(_.id) + + assertEquals(1, problem.xs.size) + val resultVariable = problem.xs.head + val hole = Hole(resultVariable.getType) + + val loader = new LeonLoader(program, hole, problem.as, false) + val inSynth = new InSynthTemp(loader, true) + // save all declarations seen + val allDeclarations = inSynth.getCurrentBuilder.getAllDeclarations + + val nilAbstractClassDef = program.definedClasses.find(_.id.name == "Nil"). + get.asInstanceOf[CaseClassDef] + val listVal = funDef.args.head.toVariable + + val variableRefiner = + new VariableRefiner(loader.directSubclassesMap, + loader.variableDeclarations, loader.classMap) + + val (refined, newDeclarations) = + variableRefiner.checkRefinements( + CaseClassInstanceOf(nilAbstractClassDef, listVal), BooleanLiteral(true), allDeclarations) + assert(refined) + assert(allDeclarations.size + 2 == newDeclarations.size) + + val declsMessage = "newDeclarations do not contain needed declaration\nnewDeclarations: " + + newDeclarations.map(decl => decl.getSimpleName + ":" + decl.getType).mkString("\n") + assertTrue(declsMessage, newDeclarations.exists(_.getSimpleName contains "l.tail")) + assertTrue(declsMessage, newDeclarations.exists(_.getSimpleName contains "l.a")) + println(declsMessage) + + val builder = new InitialEnvironmentBuilder(newDeclarations) + + val solver = inSynth.solver + val solution = solver.getProofTree(builder) + + val extractorResults = assertTake(transformer(solution.getNodes.head), 1000) + +// val duplicityMap = (Map[Expr, Set[(lambda.Node, Float)]]() /: extractorResults) { +// (resMap, pair) => +// val snippet = codegen(pair._1) +// resMap + (snippet -> (resMap.getOrElse(snippet, Set.empty) + pair)) +// } + + assertTrue( + ProofTreeOperations.breadthFirstSearchPrint(solution.getNodes.head), + ProofTreeOperations.checkInhabitants(solution, + StringNode("AddressBook", Set( + StringNode("[Cons=>List]", Set(StringNode("Cons"))) + , + StringNode("pers", Set(StringNode("makeAddressBook"))) + )) + )) + assertTrue( + ProofTreeOperations.breadthFirstSearchPrint(solution.getNodes.head), + ProofTreeOperations.checkInhabitants(solution, + StringNode("addToPers", Set( + StringNode("makeAddressBook", Set( + StringNode("l.tail", Set()) + )) + , + StringNode("a", Set( )) + )) + )) + assertTrue( + ProofTreeOperations.breadthFirstSearchPrint(solution.getNodes.head), + ProofTreeOperations.checkInhabitants(solution, + StringNode("addToBusiness", Set( + StringNode("makeAddressBook", Set( + StringNode("l.tail", Set()) + )) + , + StringNode("a", Set( )) + )) + )) + assertTrue( + ProofTreeOperations.breadthFirstSearchPrint(solution.getNodes.head), + ProofTreeOperations.checkInhabitants(solution, + StringNode("addToBusiness", Set( + StringNode("makeAddressBook", Set( + StringNode("l.tail", Set()) + )) + , + StringNode("l.a", Set( )) + )) + )) +// val resTemp = transformer(solution.getNodes.head).take(100) +// +// println(resTemp.head) +// val it = resTemp.iterator.buffered +// println(it.head) +// println(it.hasNext) +// println(it.head) +// println(it.hasNext) +// +// for (output <- extractorResults) { +// print("%20s %5f" format (output._1, output._2)) +// +// System.out.println("Press Any Key To Continue..."); +// new java.util.Scanner(System.in).nextLine(); +// } +// println("\nExtracted: " + resTemp.size) +// println("\nExtracted: " + extractorResults.size) + + val message = + (for (output <- extractorResults) + yield "%20s %5f" format (output._1, output._2)).mkString("\n") + "\nExtracted: " + extractorResults.size + assertTrue("addToPers not found in extracted. results:\n" + message, extractorResults.exists(_._1.toString contains "addToPers")) + assertTrue("addToBusiness not found in extracted. results:\n" + message, extractorResults.exists(_._1.toString contains "addToBusiness")) +// +// println("Duplicity map size " + duplicityMap.size) +// for ( (key, value) <- duplicityMap.filter(_._2.size > 1).take(1)) { +// println("Key: " + key) +// println("Values: " + value.mkString("\n")) +// } + } + } + + @Ignore + def testAddressesWithRefinementCodeGen: Unit = { + + for ((sctx, funDef, problem) <- forFile(lesynthTestDir + "Addresses.scala")) { + val program = sctx.program + val arguments = funDef.args.map(_.id) + + assertEquals(1, problem.xs.size) + val resultVariable = problem.xs.head + val hole = Hole(resultVariable.getType) + + val loader = new LeonLoader(program, hole, problem.as, false) + val inSynth = new InSynthTemp(loader, true) + // save all declarations seen + val allDeclarations = inSynth.getCurrentBuilder.getAllDeclarations + + val nilAbstractClassDef = program.definedClasses.find(_.id.name == "Nil"). + get.asInstanceOf[CaseClassDef] + val listVal = funDef.args.head.toVariable + + val variableRefiner = + new VariableRefiner(loader.directSubclassesMap, + loader.variableDeclarations, loader.classMap) + + val (refined, newDeclarations) = + variableRefiner.checkRefinements( + CaseClassInstanceOf(nilAbstractClassDef, listVal), BooleanLiteral(true), allDeclarations) + assert(refined) + assert(allDeclarations.size + 2 == newDeclarations.size) + + val declsMessage = "newDeclarations do not contain needed declaration\nnewDeclarations: " + + newDeclarations.map(decl => decl.getSimpleName + ":" + decl.getType).mkString("\n") + assertTrue(declsMessage, newDeclarations.exists(_.getSimpleName contains "l.tail")) + assertTrue(declsMessage, newDeclarations.exists(_.getSimpleName contains "l.a")) + println(declsMessage) + + val builder = new InitialEnvironmentBuilder(newDeclarations) + + val solver = inSynth.solver + val solution = solver.getProofTree(builder) + + val extractorResults = assertTake(transformer(solution.getNodes.head), 20000) + + var ind = 1 + for ((output, snippet) <- extractorResults zip (extractorResults map { p => codegen(p._1) })) { + print("%20s %20s\n".format(snippet, output._1.toString)) + ind +=1 + + if ((ind % 1000) == 0) { + interactivePause + } + } + + val message = + (for (output <- extractorResults) + yield "%20s %5f" format (output._1, output._2)).mkString("\n") + "\nExtracted: " + extractorResults.size + assertTrue("addToPers not found in extracted. results:\n" + message, extractorResults.exists(_._1.toString contains "addToPers")) + assertTrue("addToBusiness not found in extracted. results:\n" + message, extractorResults.exists(_._1.toString contains "addToBusiness")) +// +// println("Duplicity map size " + duplicityMap.size) +// for ( (key, value) <- duplicityMap.filter(_._2.size > 1).take(1)) { +// println("Key: " + key) +// println("Values: " + value.mkString("\n")) +// } + } + } + + @Ignore + def testAddressesWithRefinementTime: Unit = { + + for ((sctx, funDef, problem) <- forFile(lesynthTestDir + "Addresses.scala")) { + val program = sctx.program + val arguments = funDef.args.map(_.id) + + assertEquals(1, problem.xs.size) + val resultVariable = problem.xs.head + val hole = Hole(resultVariable.getType) + + val loader = new LeonLoader(program, hole, problem.as, false) + val inSynth = new InSynthTemp(loader, true) + // save all declarations seen + val allDeclarations = inSynth.getCurrentBuilder.getAllDeclarations + + val nilAbstractClassDef = program.definedClasses.find(_.id.name == "Nil"). + get.asInstanceOf[CaseClassDef] + val listVal = funDef.args.head.toVariable + + val variableRefiner = + new VariableRefiner(loader.directSubclassesMap, + loader.variableDeclarations, loader.classMap) + + val (refined, newDeclarations) = + variableRefiner.checkRefinements( + CaseClassInstanceOf(nilAbstractClassDef, listVal), BooleanLiteral(true), allDeclarations) + assert(refined) + assert(allDeclarations.size + 2 == newDeclarations.size) + + val declsMessage = "newDeclarations do not contain needed declaration\nnewDeclarations: " + + newDeclarations.map(decl => decl.getSimpleName + ":" + decl.getType).mkString("\n") + assertTrue(declsMessage, newDeclarations.exists(_.getSimpleName contains "l.tail")) + assertTrue(declsMessage, newDeclarations.exists(_.getSimpleName contains "l.a")) + + val builder = new InitialEnvironmentBuilder(newDeclarations) + + val solver = inSynth.solver + val solution = solver.getProofTree(builder) + + val startTime = System.currentTimeMillis + val extractorResults = assertTake(transformer(solution.getNodes.head), 5000) + println("Time for extracting 5000 solutions: " + (System.currentTimeMillis - startTime)) + +// val duplicityMap = (Map[Expr, Set[(lambda.Node, Float)]]() /: extractorResults) { +// (resMap, pair) => +// val snippet = codegen(pair._1) +// resMap + (snippet -> (resMap.getOrElse(snippet, Set.empty) + pair)) +// } + + assertTrue( + ProofTreeOperations.breadthFirstSearchPrint(solution.getNodes.head), + ProofTreeOperations.checkInhabitants(solution, + StringNode("AddressBook", Set( + StringNode("[Cons=>List]", Set(StringNode("Cons"))) + , + StringNode("pers", Set(StringNode("makeAddressBook"))) + )) + )) + assertTrue( + ProofTreeOperations.breadthFirstSearchPrint(solution.getNodes.head), + ProofTreeOperations.checkInhabitants(solution, + StringNode("addToPers", Set( + StringNode("makeAddressBook", Set( + StringNode("l.tail", Set()) + )) + , + StringNode("a", Set( )) + )) + )) + assertTrue( + ProofTreeOperations.breadthFirstSearchPrint(solution.getNodes.head), + ProofTreeOperations.checkInhabitants(solution, + StringNode("addToBusiness", Set( + StringNode("makeAddressBook", Set( + StringNode("l.tail", Set()) + )) + , + StringNode("a", Set( )) + )) + )) + assertTrue( + ProofTreeOperations.breadthFirstSearchPrint(solution.getNodes.head), + ProofTreeOperations.checkInhabitants(solution, + StringNode("addToBusiness", Set( + StringNode("makeAddressBook", Set( + StringNode("l.tail", Set()) + )) + , + StringNode("l.a", Set( )) + )) + )) +// val resTemp = transformer(solution.getNodes.head).take(100) +// +// println(resTemp.head) +// val it = resTemp.iterator.buffered +// println(it.head) +// println(it.hasNext) +// println(it.head) +// println(it.hasNext) +// +// for (output <- extractorResults) { +// print("%20s %5f" format (output._1, output._2)) +// +// System.out.println("Press Any Key To Continue..."); +// new java.util.Scanner(System.in).nextLine(); +// } +// println("\nExtracted: " + resTemp.size) +// println("\nExtracted: " + extractorResults.size) + + val message = + (for (output <- extractorResults) + yield "%20s %5f" format (output._1, output._2)).mkString("\n") + "\nExtracted: " + extractorResults.size + assertTrue("addToPers not found in extracted. results:\n" + message, extractorResults.exists(_._1.toString contains "addToPers")) + assertTrue("addToBusiness not found in extracted. results:\n" + message, extractorResults.exists(_._1.toString contains "addToBusiness")) +// +// println("Duplicity map size " + duplicityMap.size) +// for ( (key, value) <- duplicityMap.filter(_._2.size > 1).take(1)) { +// println("Key: " + key) +// println("Values: " + value.mkString("\n")) +// } + } + } + + @Ignore + def testListConcatWithRefinementCodeGen: Unit = { + + for ((sctx, funDef, problem) <- forFile(lesynthSynthesisDir + "List/ListConcat.scala")) { + val program = sctx.program + val arguments = funDef.args.map(_.id) + + assertEquals(1, problem.xs.size) + val resultVariable = problem.xs.head + val hole = Hole(resultVariable.getType) + + val loader = new LeonLoader(program, hole, problem.as, false) + val inSynth = new InSynthTemp(loader, true) + // save all declarations seen + val allDeclarations = inSynth.getCurrentBuilder.getAllDeclarations + + val nilAbstractClassDef = program.definedClasses.find(_.id.name == "Nil"). + get.asInstanceOf[CaseClassDef] + val listVal = funDef.args.head.toVariable + + val variableRefiner = + new VariableRefiner(loader.directSubclassesMap, + loader.variableDeclarations, loader.classMap) + + val (refined, newDeclarations) = + variableRefiner.checkRefinements( + CaseClassInstanceOf(nilAbstractClassDef, listVal), BooleanLiteral(true), allDeclarations) + assert(refined) + assert(allDeclarations.size + 2 == newDeclarations.size) + + val declsMessage = "newDeclarations do not contain needed declaration\nnewDeclarations: " + + newDeclarations.map(decl => decl.getSimpleName + ":" + decl.getType).mkString("\n") + assertTrue(declsMessage, newDeclarations.exists(_.getSimpleName contains "l1.tail")) + assertTrue(declsMessage, newDeclarations.exists(_.getSimpleName contains "l1.head")) + println(declsMessage) + + val builder = new InitialEnvironmentBuilder(newDeclarations) + + val solver = inSynth.solver + val solution = solver.getProofTree(builder) + + val extractorResults = assertTake(transformer(solution.getNodes.head), 1000) + + var ind = 1 + for ((output, snippet) <- extractorResults zip (extractorResults map { p => codegen(p._1) })) { + print("%20s %20s\n".format(snippet, output._1.toString)) + ind +=1 + + if ((ind % 1000) == 0) { + interactivePause + } + } + +// val message = +// (for (output <- extractorResults) +// yield "%20s %5f" format (output._1, output._2)).mkString("\n") + "\nExtracted: " + extractorResults.size +// assertTrue("addToPers not found in extracted. results:\n" + message, extractorResults.exists(_._1.toString contains "addToPers")) +// assertTrue("addToBusiness not found in extracted. results:\n" + message, extractorResults.exists(_._1.toString contains "addToBusiness")) +// +// println("Duplicity map size " + duplicityMap.size) +// for ( (key, value) <- duplicityMap.filter(_._2.size > 1).take(1)) { +// println("Key: " + key) +// println("Values: " + value.mkString("\n")) +// } + } + } + + @Test + def testAddressesWithRefinementBoolean: Unit = { + + for ((sctx, funDef, problem) <- forFile(lesynthTestDir + "Addresses.scala")) { + val program = sctx.program + val arguments = funDef.args.map(_.id) + + assertEquals(1, problem.xs.size) + val resultVariable = problem.xs.head + val hole = Hole(BooleanType) + + val loader = new LeonLoader(program, hole, problem.as, false) + val inSynth = new InSynthTemp(loader, true) + // save all declarations seen + val allDeclarations = inSynth.getCurrentBuilder.getAllDeclarations + + val nilAbstractClassDef = program.definedClasses.find(_.id.name == "Nil"). + get.asInstanceOf[CaseClassDef] + val listVal = funDef.args.head.toVariable + + val variableRefiner = + new VariableRefiner(loader.directSubclassesMap, + loader.variableDeclarations, loader.classMap) + + val (refined, newDeclarations) = + variableRefiner.checkRefinements( + CaseClassInstanceOf(nilAbstractClassDef, listVal), BooleanLiteral(true), allDeclarations) + assert(refined) + assert(allDeclarations.size + 2 == newDeclarations.size) + + val declsMessage = "newDeclarations do not contain needed declaration\nnewDeclarations: " + + newDeclarations.map(decl => decl.getSimpleName + ":" + decl.getType).mkString("\n") + assertTrue(declsMessage, newDeclarations.exists(_.getSimpleName contains "l.tail")) + assertTrue(declsMessage, newDeclarations.exists(_.getSimpleName contains "l.a")) + println(declsMessage) + + val builder = new InitialEnvironmentBuilder(newDeclarations) + + val solver = inSynth.solver + val solution = solver.getProofTree(builder) + + val extractorResults = assertTake(transformer(solution.getNodes.head), 100) + +// val duplicityMap = (Map[Expr, Set[(lambda.Node, Float)]]() /: extractorResults) { +// (resMap, pair) => +// val snippet = codegen(pair._1) +// resMap + (snippet -> (resMap.getOrElse(snippet, Set.empty) + pair)) +// } + +// assertTrue( +// ProofTreeOperations.breadthFirstSearchPrint(solution.getNodes.head), +// ProofTreeOperations.checkInhabitants(solution, +// StringNode("AddressBook", Set( +// StringNode("[Cons=>List]", Set(StringNode("Cons"))) +// , +// StringNode("pers", Set(StringNode("makeAddressBook"))) +// )) +// )) +// assertTrue( +// ProofTreeOperations.breadthFirstSearchPrint(solution.getNodes.head), +// ProofTreeOperations.checkInhabitants(solution, +// StringNode("addToPers", Set( +// StringNode("makeAddressBook", Set( +// StringNode("l.tail", Set()) +// )) +// , +// StringNode("a", Set( )) +// )) +// )) +// assertTrue( +// ProofTreeOperations.breadthFirstSearchPrint(solution.getNodes.head), +// ProofTreeOperations.checkInhabitants(solution, +// StringNode("addToBusiness", Set( +// StringNode("makeAddressBook", Set( +// StringNode("l.tail", Set()) +// )) +// , +// StringNode("a", Set( )) +// )) +// )) +// assertTrue( +// ProofTreeOperations.breadthFirstSearchPrint(solution.getNodes.head), +// ProofTreeOperations.checkInhabitants(solution, +// StringNode("addToBusiness", Set( +// StringNode("makeAddressBook", Set( +// StringNode("l.tail", Set()) +// )) +// , +// StringNode("l.a", Set( )) +// )) +// )) +// val resTemp = transformer(solution.getNodes.head).take(100) +// +// println(resTemp.head) +// val it = resTemp.iterator.buffered +// println(it.head) +// println(it.hasNext) +// println(it.head) +// println(it.hasNext) +// + for (output <- extractorResults) { + print("%20s %5f" format (output._1, output._2)) + + System.out.println("Press Any Key To Continue..."); + new java.util.Scanner(System.in).nextLine(); + } +// println("\nExtracted: " + resTemp.size) +// println("\nExtracted: " + extractorResults.size) + +// val message = +// (for (output <- extractorResults) +// yield "%20s %5f" format (output._1, output._2)).mkString("\n") + "\nExtracted: " + extractorResults.size +// assertTrue("addToPers not found in extracted. results:\n" + message, extractorResults.exists(_._1.toString contains "addToPers")) +// assertTrue("addToBusiness not found in extracted. results:\n" + message, extractorResults.exists(_._1.toString contains "addToBusiness")) +// +// println("Duplicity map size " + duplicityMap.size) +// for ( (key, value) <- duplicityMap.filter(_._2.size > 1).take(1)) { +// println("Key: " + key) +// println("Values: " + value.mkString("\n")) +// } + } + } + + +} \ No newline at end of file diff --git a/src/test/scala/lesynth/EnumerationFastTest.scala b/src/test/scala/lesynth/EnumerationFastTest.scala new file mode 100644 index 0000000000000000000000000000000000000000..7eccbb25a1cb2cb3a6107c2c268ee6e5538aadd3 --- /dev/null +++ b/src/test/scala/lesynth/EnumerationFastTest.scala @@ -0,0 +1,182 @@ +package lesynth + +import org.scalatest.FunSuite +import org.scalatest.matchers.ShouldMatchers._ + +import leon._ +import leon.purescala.Definitions._ +import leon.purescala.Trees._ +import java.io.{ BufferedWriter, FileWriter, File } +import leon.evaluators.CodeGenEvaluator +import leon.purescala.TreeOps +import leon.purescala.Common._ +import leon.codegen.CodeGenEvalParams +import leon.purescala.TypeTrees._ +import leon.evaluators.EvaluationResults._ + +import insynth._ +import insynth.leon._ +import insynth.leon.loader._ +import insynth.engine._ + +import lesynth.refinement._ +import lesynth.examples._ +import lesynth.evaluation.CodeGenEvaluationStrategy +import lesynth.ranking.Candidate +import insynth.reconstruction.Output + +import insynth.util._ +import lesynth.util._ + +class EnumerationFastTest extends FunSuite { + + import Scaffold._ + import TestConfig._ + + val CANDIDATES_TO_ENUMERATE = 50 :: 100 :: 1000 :: 10000 :: Nil + + val files = List("InsertionSortInsert.scala", "ListConcat.scala", "MergeSortSort.scala", + "RedBlackTreeInsert.scala") map { lesynthTestDir + _ } + + ignore("Candidate enumeration duplicates") { + + for (candidatesToEnumerate <- CANDIDATES_TO_ENUMERATE; + file <- files; + (sctx, funDef, problem) <- forFile(file)) { + val program = sctx.program + val arguments = funDef.args.map(_.id) + + expect(1) { problem.xs.size } + val resultVariable = problem.xs.head + val hole = Hole(resultVariable.getType) + + val loader = new LeonLoader(program, hole, problem.as, false) + val inSynth = new InSynthTemp(loader, true) + // save all declarations seen + val allDeclarations = inSynth.getCurrentBuilder.getAllDeclarations + + val builder = new InitialEnvironmentBuilder(allDeclarations) + + val outputs = inSynth.getExpressions(builder) + + val taken = outputs.take(candidatesToEnumerate).map(_.getSnippet).toList + val takenDistinct = taken.distinct + val takenRepeated = taken.filter(snip => taken.count(_ == snip) > 1) + + assert(taken.size == takenDistinct.size, "First " + candidatesToEnumerate + + " are not distinct." + + "Repeated #" + takenRepeated.size + + ": " + takenRepeated.map(snip => snip.toString + + " repeats " + taken.count(_ == snip)).mkString("\n") + ) + assert(takenRepeated.isEmpty) + } + } + + test("Enumeration in Address example") { + + for ((sctx, funDef, problem) <- forFile(lesynthTestDir + "Addresses.scala")) { + val program = sctx.program + val arguments = funDef.args.map(_.id) + + expect(1) { problem.xs.size } + val resultVariable = problem.xs.head + val hole = Hole(resultVariable.getType) + + val loader = new LeonLoader(program, hole, problem.as, false) + val inSynth = new InSynthTemp(loader, true) + // save all declarations seen + val allDeclarations = inSynth.getCurrentBuilder.getAllDeclarations + + val nilAbstractClassDef = program.definedClasses.find(_.id.name == "Nil"). + get.asInstanceOf[CaseClassDef] + val listVal = funDef.args.head.toVariable + + val variableRefiner = + new VariableRefiner(loader.directSubclassesMap, + loader.variableDeclarations, loader.classMap) + + val (refined, newDeclarations) = + variableRefiner.checkRefinements( + CaseClassInstanceOf(nilAbstractClassDef, listVal), BooleanLiteral(true), allDeclarations) + assert(refined) + assert(allDeclarations.size + 2 == newDeclarations.size) + + for (decl <- newDeclarations) + println(decl.getSimpleName) + + val builder = new InitialEnvironmentBuilder(newDeclarations) + +// val solver = inSynth.solver +// solver.getProofTree(builder) +// val solution = solver.getProofTree +// +// import ProofTreeOperations._ +// assert(ProofTreeOperations.checkInhabitants(solution, +// StringNode("AddressBook", Set( +// //StringNode("[Cons=>List]", Set(StringNode("Cons"))), +// StringNode("makeAddressBook", Set(StringNode("tail"))) +// )) +// )) + + val outputs = inSynth.getExpressions(builder) + + for (output <- outputs.take(20000)) + printf("%20s %5f\n", output.getSnippet.toString, output.getWeight) + +// val proofTree = inSynth.solver.getProofTree(builder) +// val os = new java.io.PrintWriter(new java.io.FileOutputStream("proofTree.xml")) +// insynth.util.format.TreePrinter.printAnswerAsXML(os, proofTree, 6) + } + + } + + ignore("Enumeration in Address (mergeAddressBooks) example") { + + for ((sctx, funDef, problem) <- forFile(lesynthTestDir + "AddressesMergeAddressBooks.scala")) { + val program = sctx.program + val arguments = funDef.args.map(_.id) + + expect(1) { problem.xs.size } + val resultVariable = problem.xs.head + val hole = Hole(resultVariable.getType) + + val loader = new LeonLoader(program, hole, problem.as, false) + val inSynth = new InSynthTemp(loader, true) + // save all declarations seen + val allDeclarations = inSynth.getCurrentBuilder.getAllDeclarations + +// val nilAbstractClassDef = program.definedClasses.find(_.id.name == "Nil"). +// get.asInstanceOf[CaseClassDef] +// val listVal = funDef.args.head.toVariable +// +// val variableRefiner = +// new VariableRefiner(loader.directSubclassesMap, +// loader.variableDeclarations, loader.classMap) +// +// val (refined, newDeclarations) = +// variableRefiner.checkRefinements( +// CaseClassInstanceOf(nilAbstractClassDef, listVal), BooleanLiteral(true), allDeclarations) +// assert(refined) +// assert(allDeclarations.size + 2 == newDeclarations.size) +// +// for (decl <- newDeclarations) +// println(decl.getSimpleName) +// +// val builder = new InitialEnvironmentBuilder(newDeclarations) + //assert(inSynth.getCurrentBuilder.getAllDeclarations.size > 13, { throw new RuntimeException; "aaa" }) +// assert(false) + + val outputs = inSynth.getExpressions//(builder) + +// val proofTree = inSynth.solver.getProofTree(builder) +// val os = new java.io.PrintWriter(new java.io.FileOutputStream("proofTree.xml")) +// insynth.util.format.TreePrinter.printAnswerAsXML(os, proofTree, 6) + + for (output <- outputs.take(20000)) + printf("%20s %5f\n", output.getSnippet.toString, output.getWeight) + } + + } + +} \ No newline at end of file diff --git a/src/test/scala/lesynth/EnumerationTest.scala b/src/test/scala/lesynth/EnumerationTest.scala index 3cfd735c5ebc1f81a31d932c5ebc5bfacda8e3ad..b1a1efd5c238f96220c91c71988a5e0edb652980 100644 --- a/src/test/scala/lesynth/EnumerationTest.scala +++ b/src/test/scala/lesynth/EnumerationTest.scala @@ -19,12 +19,13 @@ import insynth.leon._ import insynth.leon.loader._ import insynth.engine._ -import lesynth.examples.InputExamples +import lesynth.refinement._ +import lesynth.examples._ import lesynth.evaluation.CodeGenEvaluationStrategy import lesynth.ranking.Candidate import insynth.reconstruction.Output -import lesynth.examples.Example +import insynth.util._ import lesynth.util._ class EnumerationTest extends FunSuite { @@ -71,5 +72,159 @@ class EnumerationTest extends FunSuite { assert(takenRepeated.isEmpty) } } + + ignore("Enumeration in Address example") { + + for ((sctx, funDef, problem) <- forFile(lesynthTestDir + "Addresses.scala")) { + val program = sctx.program + val arguments = funDef.args.map(_.id) + + expect(1) { problem.xs.size } + val resultVariable = problem.xs.head + val hole = Hole(resultVariable.getType) + + val loader = new LeonLoader(program, hole, problem.as, false) + val inSynth = new InSynth(loader, true) + // save all declarations seen + val allDeclarations = inSynth.getCurrentBuilder.getAllDeclarations + + val nilAbstractClassDef = program.definedClasses.find(_.id.name == "Nil"). + get.asInstanceOf[CaseClassDef] + val listVal = funDef.args.head.toVariable + + val variableRefiner = + new VariableRefiner(loader.directSubclassesMap, + loader.variableDeclarations, loader.classMap) + + val (refined, newDeclarations) = + variableRefiner.checkRefinements( + CaseClassInstanceOf(nilAbstractClassDef, listVal), BooleanLiteral(true), allDeclarations) + assert(refined) + assert(allDeclarations.size + 2 == newDeclarations.size) + + for (decl <- newDeclarations) + println(decl.getSimpleName) + + val builder = new InitialEnvironmentBuilder(newDeclarations) + + val solver = inSynth.solver + solver.getProofTree(builder) + val solution = solver.getProofTree + + import ProofTreeOperations._ + assert(ProofTreeOperations.checkInhabitants(solution, + StringNode("AddressBook", Set( + //StringNode("[Cons=>List]", Set(StringNode("Cons"))), + StringNode("makeAddressBook", Set(StringNode("tail"))) + )) + )) + + val outputs = inSynth.getExpressions(builder) + +// val proofTree = inSynth.solver.getProofTree(builder) +// val os = new java.io.PrintWriter(new java.io.FileOutputStream("proofTree.xml")) +// insynth.util.format.TreePrinter.printAnswerAsXML(os, proofTree, 6) + +// for (output <- outputs.take(20000)) +// printf("%20s %5f\n", output.getSnippet.toString, output.getWeight) + } + + } + + ignore("Enumeration in Address (mergeAddressBooks) example") { + + for ((sctx, funDef, problem) <- forFile(lesynthTestDir + "AddressesMergeAddressBooks.scala")) { + val program = sctx.program + val arguments = funDef.args.map(_.id) + + expect(1) { problem.xs.size } + val resultVariable = problem.xs.head + val hole = Hole(resultVariable.getType) + + val loader = new LeonLoader(program, hole, problem.as, false) + val inSynth = new InSynth(loader, true) + // save all declarations seen + val allDeclarations = inSynth.getCurrentBuilder.getAllDeclarations + +// val nilAbstractClassDef = program.definedClasses.find(_.id.name == "Nil"). +// get.asInstanceOf[CaseClassDef] +// val listVal = funDef.args.head.toVariable +// +// val variableRefiner = +// new VariableRefiner(loader.directSubclassesMap, +// loader.variableDeclarations, loader.classMap) +// +// val (refined, newDeclarations) = +// variableRefiner.checkRefinements( +// CaseClassInstanceOf(nilAbstractClassDef, listVal), BooleanLiteral(true), allDeclarations) +// assert(refined) +// assert(allDeclarations.size + 2 == newDeclarations.size) +// +// for (decl <- newDeclarations) +// println(decl.getSimpleName) +// +// val builder = new InitialEnvironmentBuilder(newDeclarations) + //assert(inSynth.getCurrentBuilder.getAllDeclarations.size > 13, { throw new RuntimeException; "aaa" }) +// assert(false) + + val outputs = inSynth.getExpressions//(builder) + +// val proofTree = inSynth.solver.getProofTree(builder) +// val os = new java.io.PrintWriter(new java.io.FileOutputStream("proofTree.xml")) +// insynth.util.format.TreePrinter.printAnswerAsXML(os, proofTree, 6) + + for (output <- outputs.take(20000)) + printf("%20s %5f\n", output.getSnippet.toString, output.getWeight) + } + + } + + test("Enumeration in Address (mergeAddressBooks) example with fast reconstructor") { + + for ((sctx, funDef, problem) <- forFile(lesynthTestDir + "AddressesMergeAddressBooks.scala")) { + val program = sctx.program + val arguments = funDef.args.map(_.id) + + expect(1) { problem.xs.size } + val resultVariable = problem.xs.head + val hole = Hole(resultVariable.getType) + + val loader = new LeonLoader(program, hole, problem.as, false) + val inSynth = new InSynthTemp(loader, true) + // save all declarations seen + val allDeclarations = inSynth.getCurrentBuilder.getAllDeclarations + +// val nilAbstractClassDef = program.definedClasses.find(_.id.name == "Nil"). +// get.asInstanceOf[CaseClassDef] +// val listVal = funDef.args.head.toVariable +// +// val variableRefiner = +// new VariableRefiner(loader.directSubclassesMap, +// loader.variableDeclarations, loader.classMap) +// +// val (refined, newDeclarations) = +// variableRefiner.checkRefinements( +// CaseClassInstanceOf(nilAbstractClassDef, listVal), BooleanLiteral(true), allDeclarations) +// assert(refined) +// assert(allDeclarations.size + 2 == newDeclarations.size) +// +// for (decl <- newDeclarations) +// println(decl.getSimpleName) +// +// val builder = new InitialEnvironmentBuilder(newDeclarations) + //assert(inSynth.getCurrentBuilder.getAllDeclarations.size > 13, { throw new RuntimeException; "aaa" }) +// assert(false) + + val outputs = inSynth.getExpressions//(builder) + +// val proofTree = inSynth.solver.getProofTree(builder) +// val os = new java.io.PrintWriter(new java.io.FileOutputStream("proofTree.xml")) +// insynth.util.format.TreePrinter.printAnswerAsXML(os, proofTree, 6) + + for (output <- outputs.take(20000)) + printf("%20s %5f\n", output.getSnippet.toString, output.getWeight) + } + + } } \ No newline at end of file diff --git a/src/test/scala/lesynth/VariableRefinerTest.scala b/src/test/scala/lesynth/VariableRefinerTest.scala index b452822297013b820408a489d7abda0aaf8fc160..49f30a53e93f0f0b9b207ea4abb9155a6171c1de 100644 --- a/src/test/scala/lesynth/VariableRefinerTest.scala +++ b/src/test/scala/lesynth/VariableRefinerTest.scala @@ -77,12 +77,14 @@ class VariableRefinerTest extends FunSpec with GivenWhenThen { ) :: Nil )) { variableRefiner.checkRefinements(CaseClassInstanceOf(nilAbstractClassDef, listVal), + BooleanLiteral(true), allDeclarations) } and("after 2nd consequtive call, nothing should happen") expect((false, allDeclarations)) { variableRefiner.checkRefinements(CaseClassInstanceOf(nilAbstractClassDef, listVal), + BooleanLiteral(true), allDeclarations) } } diff --git a/src/test/scala/lesynth/VariableSolverRefinerTest.scala b/src/test/scala/lesynth/VariableSolverRefinerTest.scala new file mode 100644 index 0000000000000000000000000000000000000000..ba09ed5002ee1667982b98711e1fee275e83a4bf --- /dev/null +++ b/src/test/scala/lesynth/VariableSolverRefinerTest.scala @@ -0,0 +1,233 @@ +package lesynth + +import scala.util.Random + +import org.scalatest.FunSpec +import org.scalatest.GivenWhenThen + +import leon.purescala.Definitions._ +import leon.purescala.Common._ +import leon.purescala.TypeTrees._ +import leon.purescala.Trees._ + +import insynth._ +import insynth.leon._ +import insynth.leon.loader._ + +import lesynth.refinement._ + +import lesynth.util._ + +class VariableSolverRefinerTest extends FunSpec with GivenWhenThen { + + import Scaffold._ + import TestConfig._ + + describe("A variable solver refiner with list ADT") { + + it("should refine if condition is isEmpty()") { + + for ( (sctx, funDef, problem) <- forFile(lesynthTestDir + "refinement/ListConcatWithEmpty.scala")) { + val program = sctx.program + val solver = sctx.solver + + val hole = Hole(funDef.getBody.getType) + val loader = new LeonLoader(program, hole, problem.as, false) + val allDeclarations = loader.load +// val inSynth = new InSynth(loader, true) +// val allDeclarations = inSynth.getCurrentBuilder.getAllDeclarations + val (directSubclassMap, listAbstractClass, classMap) = buildClassMap(program) + + val isEmpty = + program.definedFunctions.find { + _.id.name == "isEmpty" + } match { + case Some(found) => (x: Expr) => FunctionInvocation(found, Seq(x)) + case _ => fail("could not extract isEmpty"); null + } + + val isEmptyBad = + program.definedFunctions.find { + _.id.name == "isEmptyBad" + } match { + case Some(found) => (x: Expr) => FunctionInvocation(found, Seq(x)) + case _ => fail("could not extract isEmpty"); null + } + + val listVal = funDef.args.head.toVariable + val listLeonDeclaration = LeonDeclaration( + ImmediateExpression( "tempVar", listVal ), + TypeTransformer(listAbstractClass), listAbstractClass + ) + + given("a VariableSolverRefiner") + val declarations = List(listLeonDeclaration) + val variableRefiner = new VariableSolverRefiner( + directSubclassMap, declarations, classMap, solver + ) + + val res = variableRefiner.checkRefinements( + isEmpty(listVal), + isEmpty(listVal), + declarations + ) + + then("declarations should be updated accordingly") + expect((true, declarations.size)) { + (res._1, res._2.size) + } + + and("after 2nd consequtive call, nothing should happen") + expect((false, res._2)) { + val res2 = variableRefiner.checkRefinements( + isEmpty(listVal), + isEmpty(listVal), + res._2 + ) + (res2._1, res2._2) + } + } + } + + it("should refine list to Cons if condition is hasContent()") { + + for ( (sctx, funDef, problem) <- forFile(lesynthTestDir + "refinement/ListConcatWithEmpty.scala")) { + val program = sctx.program + val solver = sctx.solver + + val hole = Hole(funDef.getBody.getType) + val loader = new LeonLoader(program, hole, problem.as, false) + val allDeclarations = loader.load +// val inSynth = new InSynth(loader, true) +// val allDeclarations = inSynth.getCurrentBuilder.getAllDeclarations + val (directSubclassMap, listAbstractClass, classMap) = buildClassMap(program) + + val hasContent = + program.definedFunctions.find { + _.id.name == "hasContent" + } match { + case Some(found) => (x: Expr) => FunctionInvocation(found, Seq(x)) + case _ => fail("could not extract hasContent"); null + } + + val listVal = funDef.args.head.toVariable + val listLeonDeclaration = LeonDeclaration( + ImmediateExpression( "tempVar", listVal ), + TypeTransformer(listAbstractClass), listAbstractClass + ) + + given("a VariableSolverRefiner") + val declarations = List(listLeonDeclaration) + val variableRefiner = new VariableSolverRefiner( + directSubclassMap, declarations, classMap, solver + ) + + val res = variableRefiner.checkRefinements( + hasContent(listVal), + hasContent(listVal), + declarations + ) + + then("declarations should be updated accordingly") + expect((true, declarations.size + 2)) { + (res._1, res._2.size) + } + + and("after 2nd consequtive call, nothing should happen") + expect((false, res._2)) { + val res2 = variableRefiner.checkRefinements( + hasContent(listVal), + hasContent(listVal), + res._2 + ) + (res2._1, res2._2) + } + } + } + + it("should not refine if condition is isEmptyBad()") { + + for ( (sctx, funDef, problem) <- forFile(lesynthTestDir + "refinement/ListConcatWithEmpty.scala")) { + val program = sctx.program + val solver = sctx.solver + + val hole = Hole(funDef.getBody.getType) + val loader = new LeonLoader(program, hole, problem.as, false) + val allDeclarations = loader.load +// val inSynth = new InSynth(loader, true) +// val allDeclarations = inSynth.getCurrentBuilder.getAllDeclarations + val (directSubclassMap, listAbstractClass, classMap) = buildClassMap(program) + + val isEmpty = + program.definedFunctions.find { + _.id.name == "isEmpty" + } match { + case Some(found) => (x: Expr) => FunctionInvocation(found, Seq(x)) + case _ => fail("could not extract isEmpty"); null + } + + val isEmptyBad = + program.definedFunctions.find { + _.id.name == "isEmptyBad" + } match { + case Some(found) => (x: Expr) => FunctionInvocation(found, Seq(x)) + case _ => fail("could not extract isEmpty"); null + } + + val listVal = funDef.args.head.toVariable + val listLeonDeclaration = LeonDeclaration( + ImmediateExpression( "tempVar", listVal ), + TypeTransformer(listAbstractClass), listAbstractClass + ) + + given("a VariableSolverRefiner") + val declarations = List(listLeonDeclaration) + val variableRefiner = new VariableSolverRefiner( + directSubclassMap, declarations, classMap, solver + ) + + val res = variableRefiner.checkRefinements( + isEmptyBad(listVal), + isEmptyBad(listVal), + declarations + ) + + then("declarations should not be updated") + expect((false, res._2)) { + val res2 = variableRefiner.checkRefinements( + isEmptyBad(listVal), + isEmptyBad(listVal), + res._2 + ) + (res2._1, res2._2) + } + } + } + + } + + private def buildClassMap(program: Program) = { + val listAbstractClassDef = program.definedClasses.find(_.id.name == "List"). + get.asInstanceOf[AbstractClassDef] + + val nilAbstractClassDef = program.definedClasses.find(_.id.name == "Nil"). + get.asInstanceOf[CaseClassDef] + + val consAbstractClassDef = program.definedClasses.find(_.id.name == "Cons"). + get.asInstanceOf[CaseClassDef] + + val directSubclassMap: Map[ClassType, Set[ClassType]] = Map( + AbstractClassType(listAbstractClassDef) -> + Set(CaseClassType(nilAbstractClassDef), CaseClassType(consAbstractClassDef)) + ) + + val classMap: Map[Identifier, ClassType] = Map( + listAbstractClassDef.id -> AbstractClassType(listAbstractClassDef), + nilAbstractClassDef.id -> CaseClassType(nilAbstractClassDef), + consAbstractClassDef.id -> CaseClassType(consAbstractClassDef) + ) + + (directSubclassMap, AbstractClassType(listAbstractClassDef), classMap) + } + +} \ No newline at end of file diff --git a/src/test/scala/lesynth/util/TestConfig.scala b/src/test/scala/lesynth/util/TestConfig.scala index cdcb14fdc777b03236027ad2fd00838b5450db57..49eeeb5f3270b1461671183bcbf8d2bbe7b4b2af 100644 --- a/src/test/scala/lesynth/util/TestConfig.scala +++ b/src/test/scala/lesynth/util/TestConfig.scala @@ -24,6 +24,8 @@ object TestConfig { val synthesisTestDir = "testcases/insynth-synthesis-tests/" val lesynthTestDir = "testcases/lesynth/test/" + + val lesynthSynthesisDir = "testcases/lesynth/synthesis/" val HOME_FOLDER = "/home/kuraj/" diff --git a/testcases/lesynth/synthesis/BatchedQueue/BatchedQueueCheckf.scala b/testcases/lesynth/synthesis/BatchedQueue/BatchedQueueCheckf.scala index 56ceaaa9b2a703929b6a05665d9476d3eddea77e..4faa50286c879d90d3e9fe12db58856459ee8993 100644 --- a/testcases/lesynth/synthesis/BatchedQueue/BatchedQueueCheckf.scala +++ b/testcases/lesynth/synthesis/BatchedQueue/BatchedQueueCheckf.scala @@ -15,36 +15,26 @@ object BatchedQueue { def content(p: Queue): Set[Int] = content(p.f) ++ content(p.r) - def size(l: List) : Int = l match { - case Nil => 0 - case Cons(head, tail) => 1 + size(tail) - } - - def size(q: Queue) : Int = - size(q.f) + size(q.r) - - def isEmpty(p: Queue): Boolean = p.f == Nil - case class Queue(f: List, r: List) def rev_append(aList: List, bList: List): List = (aList match { case Nil => bList case Cons(x, xs) => rev_append(xs, Cons(x, bList)) - }) ensuring ( - res => - content(res) == content(aList) ++ content(bList) && - size(res) == size(aList) + size(bList) - ) - - def reverse(list: List) = rev_append(list, Nil) ensuring ( - res => - content(res) == content(list) && size(res) == size(list) - ) - + }) ensuring (content(_) == content(aList) ++ content(bList)) + + def reverse(list: List) = rev_append(list, Nil) ensuring (content(_) == content(list)) + def invariantList(q:Queue, f: List, r: List): Boolean = { rev_append(q.f, q.r) == rev_append(f, r) && { if (q.f == Nil) q.r == Nil else true } } + + def tail(p: Queue): Queue = { + p.f match { + case Nil => p + case Cons(_, xs) => checkf(xs, p.r) + } + } //(f match { // case Nil => Queue(reverse(r), Nil) diff --git a/testcases/lesynth/synthesis/BatchedQueue/BatchedQueueSnoc.scala b/testcases/lesynth/synthesis/BatchedQueue/BatchedQueueSnoc.scala index cf30f2f1b39f732bcff1fbd7cd83a231275a9d42..6541b33b5dbce7b126d0eeac8b46858d286fa59d 100644 --- a/testcases/lesynth/synthesis/BatchedQueue/BatchedQueueSnoc.scala +++ b/testcases/lesynth/synthesis/BatchedQueue/BatchedQueueSnoc.scala @@ -15,8 +15,6 @@ object BatchedQueue { def content(p: Queue): Set[Int] = content(p.f) ++ content(p.r) - def isEmpty(p: Queue): Boolean = p.f == Nil - case class Queue(f: List, r: List) def rev_append(aList: List, bList: List): List = (aList match { @@ -26,28 +24,24 @@ object BatchedQueue { def reverse(list: List) = rev_append(list, Nil) ensuring (content(_) == content(list)) - def checkf(f: List, r: List): Queue = (f match { - case Nil => Queue(reverse(r), Nil) - case _ => Queue(f, r) - }) ensuring { - res => content(res) == content(f) ++ content(r) + def invariantList(q:Queue, f: List, r: List): Boolean = { + rev_append(q.f, q.r) == rev_append(f, r) && + { if (q.f == Nil) q.r == Nil else true } } - - def head(p: Queue): Set[Int] = ( - p.f match { - case Nil => Set[Int]() - case Cons(x, xs) => Set(x) - }) ensuring ( - res => - if (isEmpty(p)) true - else content(p) == res ++ content(tail(p))) - + def tail(p: Queue): Queue = { p.f match { case Nil => p case Cons(_, xs) => checkf(xs, p.r) } } + + def checkf(f: List, r: List): Queue = (f match { + case Nil => Queue(reverse(r), Nil) + case _ => Queue(f, r) + }) ensuring { + res => content(res) == content(f) ++ content(r) + } // // def last(p: Queue): Int = { // require(!isEmpty(p)) @@ -60,16 +54,7 @@ object BatchedQueue { def snoc(p: Queue, x: Int): Queue = choose { (res: Queue) => content(res) == content(p) ++ Set(x) && - (if (isEmpty(p)) true - else content(tail(res)) ++ Set(x) == content(tail(res))) + (p.f == Nil || content(tail(res)) ++ + Set(x) == content(tail(res))) } - - def main(args: Array[String]): Unit = { - val pair = Queue(Cons(4, Nil), Cons(3, Nil)) - - println(head(pair)) - println(content(pair) == head(pair) ++ content(tail(pair))) - - println(head(Queue(Nil, Nil))) - } } diff --git a/testcases/lesynth/synthesis/BatchedQueue/BatchedQueueTail.scala b/testcases/lesynth/synthesis/BatchedQueue/BatchedQueueTail.scala index 83253e101f3f2d88fae44bb1f19c1b5aeed02c59..d35737dab64b76701d1904aae49dd4bfdb188a27 100644 --- a/testcases/lesynth/synthesis/BatchedQueue/BatchedQueueTail.scala +++ b/testcases/lesynth/synthesis/BatchedQueue/BatchedQueueTail.scala @@ -15,67 +15,42 @@ object BatchedQueue { def content(p: Queue): Set[Int] = content(p.f) ++ content(p.r) - def size(l: List): Int = l match { - case Nil => 0 - case Cons(head, tail) => 1 + size(tail) - } - - def size(q: Queue): Int = - size(q.f) + size(q.r) - -// def isEmpty(p: Queue): Boolean = p.f == Nil && p.r == Nil + def isEmpty(p: Queue): Boolean = p.f == Nil case class Queue(f: List, r: List) def rev_append(aList: List, bList: List): List = (aList match { case Nil => bList case Cons(x, xs) => rev_append(xs, Cons(x, bList)) - }) ensuring ( - res => - content(res) == content(aList) ++ content(bList) && - size(res) == size(aList) + size(bList)) + }) ensuring (content(_) == content(aList) ++ content(bList)) - def reverse(list: List) = rev_append(list, Nil) ensuring ( - res => - content(res) == content(list) && size(res) == size(list)) + def reverse(list: List) = rev_append(list, Nil) ensuring (content(_) == content(list)) + def invariantList(q:Queue, f: List, r: List): Boolean = { + rev_append(q.f, q.r) == rev_append(f, r) && + { if (q.f == Nil) q.r == Nil else true } + } + def checkf(f: List, r: List): Queue = (f match { case Nil => Queue(reverse(r), Nil) case _ => Queue(f, r) }) ensuring { - res => - content(res) == content(f) ++ content(r) && - size(res) == size(f) + size(r) + res => content(res) == content(f) ++ content(r) } - - def head(p: Queue): List = { - p.f match { - case Nil => Nil - case Cons(x, xs) => Cons(x, Nil) - } - } - - def correctQueue(q:Queue) = if (q.f == Nil) q.r == Nil else true - def invariantList(q:Queue, f: List, r: List): Boolean = { - rev_append(q.f, q.r) == rev_append(f, r) - } - - def merge(l1: List, l2: List): List = l1 match { - case Nil => l2 - case Cons(a, tail) => Cons(a, merge(tail, l2)) - } - + def tail(p: Queue): Queue = { + require( if (p.f == Nil) p.r == Nil else true ) // p.f match { // case Nil => p // case Cons(_, xs) => checkf(xs, p.r) // } - def tail(p: Queue): List = { - require(correctQueue(p)) choose { - (res: List) => - invariantList(p, merge(head(p), res), Nil) + (res: Queue) => + p.f match { + case Nil => isEmpty(res) + case Cons(x, xs) => content(res) ++ Set(x) == content(p) && content(res) != content(p) + } } } - + } diff --git a/testcases/lesynth/synthesis/MergeSort/MergeSortSort.scala b/testcases/lesynth/synthesis/MergeSort/MergeSortSort.scala index 82be984ba85dd726d3e31a6effa17531f5e8e58b..987c538c4ab36dc9b378f03fc24592210bcbd62b 100644 --- a/testcases/lesynth/synthesis/MergeSort/MergeSortSort.scala +++ b/testcases/lesynth/synthesis/MergeSort/MergeSortSort.scala @@ -42,7 +42,7 @@ object MergeSort { // } ensuring(res => contents(list) == contents(res.fst) ++ contents(res.snd)) def split(list: List): Pair = { - splithelper(Nil(),list,2) + splithelper(Nil(),list,size(list)/2) } ensuring(res => contents(list) == contents(res.fst) ++ contents(res.snd)) def merge(aList : List, bList : List) : List = { diff --git a/testcases/lesynth/synthesis/Other/Addresses.scala b/testcases/lesynth/synthesis/Other/Addresses.scala deleted file mode 100644 index 1563ee5ebf4bf3d505f5f0c3d68960f5b1c11e8a..0000000000000000000000000000000000000000 --- a/testcases/lesynth/synthesis/Other/Addresses.scala +++ /dev/null @@ -1,85 +0,0 @@ -import scala.collection.immutable.Set -import leon.Annotations._ -import leon.Utils._ - -object Addresses { - - case class Address(a: Int, b: Int, priv: Boolean) - - sealed abstract class List - case class Cons(a: Address, tail:List) extends List - case object Nil extends List - - def setA(l: List) : Set[Address] = l match { - case Nil => Set.empty[Address] - case Cons(a, l1) => Set(a) ++ setA(l1) - } - - def size(l: List) : Int = l match { - case Nil => 0 - case Cons(head, tail) => 1 + size(tail) - } - - def hasPrivate(l: List): Boolean = l match { - case Nil => false - case Cons(a, l1) => - if (a.priv) true - else hasPrivate(l1) - } - - case class AddressBook(business : List, pers : List) - - def size(ab: AddressBook): Int = size(ab.business) + size(ab.pers) - -// def makeAddressBook(l: List): AddressBook = (l match { -// case Nil => AddressBook(Nil, Nil) -// case Cons(a, l1) => { -// val res = makeAddressBook(l1) -// if (a.priv) AddressBook(res.business, Cons(a, res.pers)) -// else AddressBook(Cons(a, res.business), res.pers) -// } -// }) ensuring { -// res => -// size(res) == size(l) && -// !hasPrivate(res.business) && -// hasPrivate(res.pers) -// } - -// def makeAddressBook(l: List): AddressBook = (l match { -// case Nil => AddressBook(Nil, Nil) -// case Cons(a, l1) => { -// val res = makeAddressBook(l1) -// if (a.priv) AddressBook(res.business, Cons(a, res.pers)) -// else AddressBook(Cons(a, res.business), res.pers) -// } -// }) ensuring { -// res => -// size(res) == size(l) && -// (if (size(res.business) > 0) { -// !hasPrivate(res.business) -// } else true ) && -// (if (size(res.pers) > 0) { -// hasPrivate(res.pers) -// } else true ) -// } -// -// def makeAddressBook(l: List): AddressBook = -// choose { -// (res: AddressBook) => -// size(res) == size(l) && -// (if (size(res.business) > 0) { -// !hasPrivate(res.business) -// } else true ) && -// (if (size(res.pers) > 0) { -// hasPrivate(res.pers) -// } else true ) -// } - - def makeAddressBook(l: List): AddressBook = - choose { - (res: AddressBook) => - size(res) == size(l) && - hasPrivate(res.pers) && !hasPrivate(res.business) - } - -} diff --git a/testcases/lesynth/synthesis/Other/AddressesMakeAddressBook.scala b/testcases/lesynth/synthesis/Other/AddressesMakeAddressBook.scala index 2c14f9619b04732576039ac780b1136a2a03060f..6b9a73a9c1290c626d03f8a8cad3ea8f49bc8598 100644 --- a/testcases/lesynth/synthesis/Other/AddressesMakeAddressBook.scala +++ b/testcases/lesynth/synthesis/Other/AddressesMakeAddressBook.scala @@ -3,16 +3,21 @@ import leon.Annotations._ import leon.Utils._ object Addresses { + case class Info( + address: Int, + zipcode: Int, + local: Boolean + ) - case class Address(a: Int, b: Int, priv: Boolean) + case class Address(info: Info, priv: Boolean) sealed abstract class List case class Cons(a: Address, tail:List) extends List case object Nil extends List - def setA(l: List) : Set[Address] = l match { + def content(l: List) : Set[Address] = l match { case Nil => Set.empty[Address] - case Cons(a, l1) => Set(a) ++ setA(l1) + case Cons(addr, l1) => Set(addr) ++ content(l1) } def size(l: List) : Int = l match { @@ -37,6 +42,13 @@ object Addresses { case class AddressBook(business : List, pers : List) def size(ab: AddressBook): Int = size(ab.business) + size(ab.pers) + + def isEmpty(ab: AddressBook) = size(ab) == 0 + + def content(ab: AddressBook) : Set[Address] = content(ab.pers) ++ content(ab.business) + + def addressBookInvariant(ab: AddressBook) = allPrivate(ab.pers) && allBusiness(ab.business) + // def makeAddressBook(l: List): AddressBook = (l match { // case Nil => AddressBook(Nil, Nil) @@ -85,8 +97,7 @@ object Addresses { def makeAddressBook(l: List): AddressBook = choose { (res: AddressBook) => - size(res) == size(l) && - allPrivate(res.pers) && allBusiness(res.business) + size(res) == size(l) && addressBookInvariant(res) } } diff --git a/testcases/lesynth/synthesis/Other/AddressesMakeAddressBookWithHelpers.scala b/testcases/lesynth/synthesis/Other/AddressesMakeAddressBookWithHelpers.scala index c13af538aab11dc0ff026a7be44b2517ddce0e72..c22541f8c9649c1e5485a41d5ebe4ce093d68bf2 100644 --- a/testcases/lesynth/synthesis/Other/AddressesMakeAddressBookWithHelpers.scala +++ b/testcases/lesynth/synthesis/Other/AddressesMakeAddressBookWithHelpers.scala @@ -10,9 +10,9 @@ object Addresses { case class Cons(a: Address, tail:List) extends List case object Nil extends List - def setA(l: List) : Set[Address] = l match { + def content(l: List) : Set[Address] = l match { case Nil => Set.empty[Address] - case Cons(a, l1) => Set(a) ++ setA(l1) + case Cons(addr, l1) => Set(addr) ++ content(l1) } def size(l: List) : Int = l match { @@ -41,7 +41,16 @@ object Addresses { def addToBusiness(ab: AddressBook, adr: Address) = AddressBook(Cons(adr, ab.business), ab.pers) def size(ab: AddressBook): Int = size(ab.business) + size(ab.pers) + + def content(ab: AddressBook) : Set[Address] = content(ab.pers) ++ content(ab.business) + + def addressBookInvariant(ab: AddressBook) = allPrivate(ab.pers) && allBusiness(ab.business) + def merge(l1: List, l2: List): List = l1 match { + case Nil => l2 + case Cons(a, tail) => Cons(a, merge(tail, l2)) + } + // def makeAddressBook(l: List): AddressBook = (l match { // case Nil => AddressBook(Nil, Nil) // case Cons(a, l1) => { @@ -90,7 +99,8 @@ object Addresses { choose { (res: AddressBook) => size(res) == size(l) && - allPrivate(res.pers) && allBusiness(res.business) + allPrivate(res.pers) && allBusiness(res.business) && + content(res) == content(l) } } diff --git a/testcases/lesynth/synthesis/Other/AddressesMergeAddressBooks.scala b/testcases/lesynth/synthesis/Other/AddressesMergeAddressBooks.scala index c40625ad431fe9646e9bfc132ad32eda729f41fb..0d6d8c0677806c687186184aa929e80032b869a8 100644 --- a/testcases/lesynth/synthesis/Other/AddressesMergeAddressBooks.scala +++ b/testcases/lesynth/synthesis/Other/AddressesMergeAddressBooks.scala @@ -3,16 +3,21 @@ import leon.Annotations._ import leon.Utils._ object Addresses { + case class Info( + address: Int, + zipcode: Int, + phoneNumber: Int + ) - case class Address(a: Int, b: Int, priv: Boolean) + case class Address(info: Info, priv: Boolean) sealed abstract class List case class Cons(a: Address, tail:List) extends List case object Nil extends List - def setA(l: List) : Set[Address] = l match { + def content(l: List) : Set[Address] = l match { case Nil => Set.empty[Address] - case Cons(a, l1) => Set(a) ++ setA(l1) + case Cons(addr, l1) => Set(addr) ++ content(l1) } def size(l: List) : Int = l match { @@ -36,14 +41,16 @@ object Addresses { case class AddressBook(business : List, pers : List) - def addToPers(ab: AddressBook, adr: Address) = AddressBook(ab.business, Cons(adr, ab.pers)) - - def addToBusiness(ab: AddressBook, adr: Address) = AddressBook(Cons(adr, ab.business), ab.pers) - def size(ab: AddressBook): Int = size(ab.business) + size(ab.pers) - + + def addToPers(ab: AddressBook, adr: Address) = AddressBook(ab.business, Cons(adr, ab.pers)) + + def addToBusiness(ab: AddressBook, adr: Address) = AddressBook(Cons(adr, ab.business), ab.pers) + def isEmpty(ab: AddressBook) = size(ab) == 0 + def content(ab: AddressBook) : Set[Address] = content(ab.pers) ++ content(ab.business) + def addressBookInvariant(ab: AddressBook) = allPrivate(ab.pers) && allBusiness(ab.business) def makeAddressBook(l: List): AddressBook = (l match {