diff --git a/code/jvm/src/main/scala/maf/cli/runnables/IncrementalRun.scala b/code/jvm/src/main/scala/maf/cli/runnables/IncrementalRun.scala index dcf096d11..686cbc74a 100644 --- a/code/jvm/src/main/scala/maf/cli/runnables/IncrementalRun.scala +++ b/code/jvm/src/main/scala/maf/cli/runnables/IncrementalRun.scala @@ -2,9 +2,9 @@ package maf.cli.runnables import maf.bench.scheme.SchemeBenchmarkPrograms import maf.cli.experiments.incremental.* -import maf.deltaDebugging.gtr.GTR -import maf.deltaDebugging.gtr.GTR.* -import maf.deltaDebugging.gtr.transformations.TransformationManager +import maf.deltaDebugging.treeDD.variants.GTR +import maf.deltaDebugging.treeDD.variants.GTR.* +import maf.deltaDebugging.treeDD.transformations.TransformationManager import maf.language.CScheme.* import maf.language.change.CodeVersion.* import maf.language.scheme.SchemeExp @@ -94,7 +94,7 @@ object IncrementalRun extends App: val log = Logger.raw("reduced-program") import SimpleTimer.* - val exp = GTR.reduce(text, oracle, identity, TransformationManager.allTransformations) + val exp = GTR.reduce(text, oracle, TransformationManager.allTransformations) log.log(exp.prettyString()) println(exp.prettyString()) println(oracle(exp).toString) diff --git a/code/shared/src/main/scala/maf/bench/scheme/SchemeBenchmarkPrograms.scala b/code/shared/src/main/scala/maf/bench/scheme/SchemeBenchmarkPrograms.scala index 16b774863..5613bcc79 100644 --- a/code/shared/src/main/scala/maf/bench/scheme/SchemeBenchmarkPrograms.scala +++ b/code/shared/src/main/scala/maf/bench/scheme/SchemeBenchmarkPrograms.scala @@ -92,19 +92,11 @@ object SchemeBenchmarkPrograms: "Streams.scm", // Uses define-macro. "callcc.scm" // call/cc not yet support in concrete interpreter ) - lazy val certainVarious: Set[String] = fromFolder("test/R5RS/various")( - ".DS_Store", - "pico.scm", // Used def-macro, no main body + need to incorporate pico.ini file. - "quasiquoting.scm", // Uses unquote-splicing. - "Streams.scm", // Uses define-macro. - "callcc.scm", // call/cc not yet support in concrete interpreter - "blur.scm", - "eta.scm", - "SICP-compiler.scm", - "kcfa2.scm", - "sym.scm", - "widen.scm", - "mj09.scm" + lazy val ddSet: Set[String] = fromFolder("test/R5RS/DD")( + ".DS_Store" + ) + lazy val succesRateSet: Set[String] = fromFolder("test/R5RS/DD2")( + ".DS_Store" ) lazy val WeiChenRompf2019: Set[String] = SmartUnion.sunionList(List(theLittleSchemer, toplas98, WCR2019)) lazy val sequentialBenchmarks: Set[String] = diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/GTR.scala b/code/shared/src/main/scala/maf/deltaDebugging/gtr/GTR.scala deleted file mode 100644 index de1c43948..000000000 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/GTR.scala +++ /dev/null @@ -1,32 +0,0 @@ -package maf.deltaDebugging.gtr - -import maf.deltaDebugging.gtr.transformations.Transformation -import maf.language.scheme.SchemeExp -import maf.core.Expression - -import scala.annotation.tailrec - -object GTR: - @tailrec - def reduce(tree: SchemeExp, oracle: SchemeExp => Boolean, onOracleHit: SchemeExp => Unit, transformations: List[Transformation]): SchemeExp = - val reducedTree: SchemeExp = BFT(tree, oracle, onOracleHit, transformations) - if tree.size == reducedTree.size then - //println("GTR total transformation count: " + transformations.map(_.getHits).fold(0)(_ + _)) - reducedTree - else reduce(reducedTree, oracle, onOracleHit, transformations) - - private def BFT(tree: SchemeExp, oracle: SchemeExp => Boolean, onOracleHit: SchemeExp => Unit, transformations: List[Transformation]): SchemeExp = - var reducedTree = tree - for (lvl <- 0 to reducedTree.height) - for (transformation <- transformations) - reducedTree = reduceLevelNodes(reducedTree, lvl, oracle, onOracleHit, transformation) - reducedTree - - private def reduceLevelNodes(tree: SchemeExp, lvl: Int, oracle: SchemeExp => Boolean, onOracleHit: SchemeExp => Unit, transformation: Transformation): SchemeExp = - for(node <- tree.levelNodes(lvl)) - for (candidateTree <- transformation.transform(tree, node)) - if candidateTree.size < tree.size then - if oracle(candidateTree) then - onOracleHit(candidateTree) - return reduceLevelNodes(candidateTree, lvl, oracle, onOracleHit, transformation) - tree diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/GTRParallel.scala b/code/shared/src/main/scala/maf/deltaDebugging/gtr/GTRParallel.scala deleted file mode 100644 index 57f892dca..000000000 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/GTRParallel.scala +++ /dev/null @@ -1,41 +0,0 @@ -package maf.deltaDebugging.gtr - -import maf.deltaDebugging.gtr.transformations.Transformation -import maf.language.scheme.SchemeExp -import scala.collection.parallel.CollectionConverters._ - -import scala.annotation.tailrec - -object GTRParallel: - @tailrec - def reduce(tree: SchemeExp, oracle: SchemeExp => Boolean, onOracleHit: SchemeExp => Unit, transformations: List[Transformation]): SchemeExp = - val reducedTree: SchemeExp = BFT(tree, oracle, onOracleHit, transformations) - if tree.size == reducedTree.size then - reducedTree - else reduce(reducedTree, oracle, onOracleHit, transformations) - - private def BFT(tree: SchemeExp, oracle: SchemeExp => Boolean, onOracleHit: SchemeExp => Unit, transformations: List[Transformation]): SchemeExp = - var reducedTree = tree - for (lvl <- 0 to reducedTree.height) - for (transformation <- transformations) - reducedTree = reduceLevelNodes(reducedTree, lvl, oracle, onOracleHit, transformation) - reducedTree - - private def reduceLevelNodes(tree: SchemeExp, lvl: Int, oracle: SchemeExp => Boolean, onOracleHit: SchemeExp => Unit, transformation: Transformation): SchemeExp = - for (node <- tree.levelNodes(lvl)) - reduceNode(tree, node, oracle, onOracleHit, transformation) match - case Some(tpl) => - if tpl._2 then - onOracleHit(tpl._1) - return reduceLevelNodes(tpl._1, lvl, oracle, onOracleHit, transformation) - case _ => - tree - - private def reduceNode(tree: SchemeExp, node: SchemeExp, oracle: SchemeExp => Boolean, onOracleHit: SchemeExp => Unit, transformation: Transformation): Option[(SchemeExp, Boolean)] = - val candidates: List[SchemeExp] = transformation.transform(tree, node).filter(candidate => candidate.size < tree.size).toList - candidates.par.foreach(c => { - if oracle(c) then - return Some(c, true) - else None - }) - None diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/Transformation.scala b/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/Transformation.scala deleted file mode 100644 index f67cef18c..000000000 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/Transformation.scala +++ /dev/null @@ -1,57 +0,0 @@ -package maf.deltaDebugging.gtr.transformations - -import maf.language.scheme.SchemeExp - -abstract class Transformation: - var trees: List[SchemeExp] = List() - var replacements: List[SchemeExp] = List() - - def addTree(t: SchemeExp): Unit = - trees = trees.::(t) - - def addTrees(ts: List[SchemeExp]): Unit = - ts.foreach(addTree) - - def addReplacement(replacement: SchemeExp): Unit = - replacements = replacements.::(replacement) - - def addReplacements(rs: List[SchemeExp]): Unit = - rs.foreach(addReplacement) - - /** transformIdx returns the nth transformation */ - def transformIdx(tree: SchemeExp, node: SchemeExp, idx: Int): Option[SchemeExp] = - require(tree.contains(node)) - trees = List() - replacements = List() - - transformAndAdd(tree, node) //should fill trees and replacements - - val transformations = (trees ++ replacements.map(r => tree.replace(node, r))) - .filterNot(newTree => tree eql newTree) //if a transformation suggest a tree that is eql to the current tree, discard that suggestions - - try Some(transformations(idx)) - catch case _: Throwable => None - - /** transform returns all transformations */ - def transform(tree: SchemeExp, node: SchemeExp): Iterator[SchemeExp] = - require(tree.contains(node)) - trees = List() - replacements = List() - - transformAndAdd(tree, node) //should fill trees and replacements - - val iter = (trees ++ replacements.map(r => tree.replace(node, r))) - .filterNot(newTree => tree eql newTree).iterator //if a transformation suggest a tree that is eql to the current tree, discard that suggestions - - trees = List() - replacements = List() - iter - - /** transformAndAdd is a subclass responsibility */ - protected def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit - - val name: String - private var hits: Int = 0 - def getHits: Int = hits - def hit(tree: SchemeExp, idx: Int): Unit = - hits += 1 \ No newline at end of file diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/TransformationManager.scala b/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/TransformationManager.scala deleted file mode 100644 index b9f32ed49..000000000 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/TransformationManager.scala +++ /dev/null @@ -1,33 +0,0 @@ -package maf.deltaDebugging.gtr.transformations - -import maf.deltaDebugging.gtr.transformations.schemeIf.IfToBegin -import maf.deltaDebugging.gtr.transformations.schemeLambda.* -import maf.deltaDebugging.gtr.transformations.schemeLet.* -import maf.deltaDebugging.gtr.transformations.generics.* -import maf.deltaDebugging.gtr.transformations.schemeIdentifier.ReplaceIdentifier - -object TransformationManager: - - val genericTransformations: List[Transformation] = - List( - DeleteChildSimple, - ReplaceByChild - ) - - val allTransformations: List[Transformation] = - List( - DeleteChildSimple, - IfToBegin, - LetIdentifierDeepDrop, - LetIdentifierShallowDrop, - RemoveCalls, - RemoveCallsAndReplaceByBody, - RemoveLambdaParamByReplacement, - RemoveLambdaParamWithDeepDrop, - RemoveLambdaParamWithShallowDrop, - ReplaceByChild, - ReplaceCalls, - ReplaceBySimpleValue, - ReplaceIdentifier, - ReplaceByValue - ) diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/generics/ReplaceBySimpleValue.scala b/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/generics/ReplaceBySimpleValue.scala deleted file mode 100644 index 27ac382c5..000000000 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/generics/ReplaceBySimpleValue.scala +++ /dev/null @@ -1,13 +0,0 @@ -package maf.deltaDebugging.gtr.transformations.generics - -import maf.deltaDebugging.gtr.transformations.Transformation -import maf.deltaDebugging.gtr.transformations.traits.Replacing -import maf.language.scheme.SchemeExp - -object ReplaceBySimpleValue extends Transformation with Replacing: - override val name: String = "ReplaceBySimpleValue" - - //replace by value under certain circumstances, avoiding time/space overheads - override def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit = - if tree.size < 30 then - addReplacements(values) diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/generics/ReplaceByValue.scala b/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/generics/ReplaceByValue.scala deleted file mode 100644 index 0398fdb9a..000000000 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/generics/ReplaceByValue.scala +++ /dev/null @@ -1,15 +0,0 @@ -package maf.deltaDebugging.gtr.transformations.generics - -import maf.deltaDebugging.gtr.transformations.Transformation -import maf.deltaDebugging.gtr.transformations.traits.Replacing -import maf.core.Identifier -import maf.language.scheme.* -import maf.language.sexp.Value - -object ReplaceByValue extends Transformation with Replacing: - override val name: String = "ReplaceByValue" - - //replace by value under certain circumstances, avoiding time/space overheads - override def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit = - if tree.size >= 30 && tree.size < 50 then - addReplacements(allValues()) diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeIdentifier/ReplaceIdentifier.scala b/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeIdentifier/ReplaceIdentifier.scala deleted file mode 100644 index f81b71395..000000000 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeIdentifier/ReplaceIdentifier.scala +++ /dev/null @@ -1,15 +0,0 @@ -package maf.deltaDebugging.gtr.transformations.schemeIdentifier - -import maf.deltaDebugging.gtr.transformations.Transformation -import maf.deltaDebugging.gtr.transformations.traits.Replacing -import maf.language.scheme.{SchemeExp, SchemeVarExp} - -object ReplaceIdentifier extends Transformation with Replacing: - override val name: String = "ReplaceIdentifier" - - def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit = - node match - case _: SchemeVarExp => - if tree.size < 100 then - addReplacements(allValues()) - case _ => diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/RemoveLambdaParamWithShallowDrop.scala b/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/RemoveLambdaParamWithShallowDrop.scala deleted file mode 100644 index af70f1cea..000000000 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/RemoveLambdaParamWithShallowDrop.scala +++ /dev/null @@ -1,35 +0,0 @@ -package maf.deltaDebugging.gtr.transformations.schemeLambda - -import maf.deltaDebugging.gtr.transformations.Transformation -import maf.deltaDebugging.gtr.transformations.traits.CallReducing -import maf.core.Identifier -import maf.language.scheme.{SchemeDefineVariable, SchemeExp, SchemeLambdaExp, SchemeLettishExp} - -object RemoveLambdaParamWithShallowDrop extends Transformation with CallReducing: - override val name: String = "RemoveLambdaParamWithShallowdrop" - - override def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit = { - def removeLambdaParam(lambda: SchemeLambdaExp, lambdaId: Identifier): Unit = { - for ((arg, argIdx) <- lambda.args.zipWithIndex) - lambda.shallowDropIdentifier(arg) match - case Some(deepDroppedlambda) => - val lambdaReplacedTree = tree.replace(lambda, deepDroppedlambda) - val callsReduced = reduceCallsToId(lambdaReplacedTree, lambdaId, argIdx) - - addTree(callsReduced) - case _ => - } - - node match - case exp: SchemeLettishExp => - val lambdaBindings = exp.bindings.collect({ - case (identifier, lambda: SchemeLambdaExp) => (identifier, lambda) - }) - - for (lambdaBinding <- lambdaBindings) - removeLambdaParam(lambdaBinding._2, lambdaBinding._1) - - case SchemeDefineVariable(name, lambda: SchemeLambdaExp, _) => - removeLambdaParam(lambda, name) - case _ => - } diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLet/LetIdentifierShallowDrop.scala b/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLet/LetIdentifierShallowDrop.scala deleted file mode 100644 index 0f572f3b6..000000000 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLet/LetIdentifierShallowDrop.scala +++ /dev/null @@ -1,16 +0,0 @@ -package maf.deltaDebugging.gtr.transformations.schemeLet - -import maf.deltaDebugging.gtr.transformations.Transformation -import maf.language.scheme.{SchemeExp, SchemeLettishExp} - -object LetIdentifierShallowDrop extends Transformation: - override val name: String = "LetIdentifierShallowDrop" - - def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit = - node match - case lettishExp: SchemeLettishExp => - for (id <- lettishExp.bindings.map(_._1)) - lettishExp.shallowDropIdentifier(id) match - case Some(exp) => addReplacement(exp) - case _ => - case _ => diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/traits/Replacing.scala b/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/traits/Replacing.scala deleted file mode 100644 index a9ea0a90a..000000000 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/traits/Replacing.scala +++ /dev/null @@ -1,93 +0,0 @@ -package maf.deltaDebugging.gtr.transformations.traits - -import maf.core.{Identifier, NoCodeIdentity} -import maf.language.scheme.* -import maf.language.sexp.Value - -trait Replacing: - private var count = -1 - def newID(): String = - count += 1 - "unique_args_" + count.toString - - def newCallerLambda(args: List[SchemeExp]) = - val id = newID() - SchemeLambda( - None, - List(Identifier(id, NoCodeIdentity)), - List(SchemeFuncall( - f = SchemeVar(Identifier(id, NoCodeIdentity)), - args = args, - idn = NoCodeIdentity, - )), - None, - NoCodeIdentity) - - def callerLambdas(): List[SchemeLambda] = - val values: List[SchemeExp] = - List( - SchemeValue(Value.Integer(0), NoCodeIdentity), - SchemeValue(Value.Boolean(true), NoCodeIdentity), - ) - val valuesToTry = values.combinations(1).toList ++ values.combinations(2).toList - valuesToTry.map(args => newCallerLambda(args)) - - def newConstantLambda(BodyExp: SchemeExp): SchemeVarArgLambda = - SchemeVarArgLambda(None, List(), Identifier(newID(), NoCodeIdentity), List(BodyExp), None, NoCodeIdentity) - - def constantLambdas(): List[SchemeVarArgLambda] = List( - newConstantLambda(SchemeValue(Value.Integer(1), NoCodeIdentity)), - newConstantLambda(SchemeValue(Value.String("S"), NoCodeIdentity)), - newConstantLambda(SchemeValue(Value.Symbol("S"), NoCodeIdentity)), - newConstantLambda(SchemeValue(Value.Boolean(true), NoCodeIdentity)), - newConstantLambda(SchemeValue(Value.Boolean(false), NoCodeIdentity)), - newConstantLambda(SchemeValue(Value.Nil, NoCodeIdentity)), - ) - - def lambdaValues(): List[SchemeLambdaExp] = - constantLambdas() ++ callerLambdas() - - val values: List[SchemeExp] = List( - SchemeValue(Value.Integer(1), NoCodeIdentity), - SchemeValue(Value.String("S"), NoCodeIdentity), - SchemeValue(Value.Symbol("S"), NoCodeIdentity), - SchemeValue(Value.Boolean(true), NoCodeIdentity), - SchemeValue(Value.Boolean(false), NoCodeIdentity), - SchemeValue(Value.Nil, NoCodeIdentity) - ) - - def allValues(): List[SchemeExp] = - values ++ lambdaValues() - - def replaceWithAllValues(exp: SchemeExp, toReplace: SchemeExp => Boolean): List[SchemeExp] = - allValues().map(value => { - replaceWithValue(exp, toReplace, value) - }) - - private def replaceWithValue(exp: SchemeExp, toReplace: SchemeExp => Boolean, value: SchemeExp): SchemeExp = - exp.map(subExp => { - if toReplace(subExp) then - value match - case s: SchemeVarArgLambda => - s.copy(vararg = Identifier(newID(), NoCodeIdentity)) - case _ => value - else subExp - }) - - def replaceIdWithAllValues(exp: SchemeExp, id: Identifier): List[SchemeExp] = - replaceWithAllValues(exp, subExp => { - subExp match - case varExp: SchemeVarExp => - varExp.id.name equals id.name - case _ => false - }) - - def replaceCallWithAllValues(exp: SchemeExp, id: Identifier): List[SchemeExp] = - replaceWithAllValues(exp, subExp => { - subExp match - case SchemeFuncall(f: SchemeVarExp, _, _) => - f.id.name equals id.name - case varExp: SchemeVarExp => - varExp.id.name equals id.name - case _ => false - }) diff --git a/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/AST.scala b/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/AST.scala new file mode 100644 index 000000000..db4788dcd --- /dev/null +++ b/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/AST.scala @@ -0,0 +1,16 @@ +package maf.deltaDebugging.nonTreeDD + +import maf.deltaDebugging.nonTreeDD.Interpreter.Register + +object AST: + abstract class Instruction + case class SetConstant(destination: Register, const: Int) extends Instruction + case class Set(destination: Register, binop: BinOp) extends Instruction + + abstract class BinOp(val l: Register, val r: Register) + case class Plus(override val l: Register, override val r: Register) extends BinOp(l, r) + case class Sub(override val l: Register, override val r: Register) extends BinOp(l, r) + case class Mul(override val l: Register, override val r: Register) extends BinOp(l, r) + case class Div(override val l: Register, override val r: Register) extends BinOp(l, r) + + diff --git a/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/Change.scala b/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/Change.scala deleted file mode 100644 index 44506c16d..000000000 --- a/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/Change.scala +++ /dev/null @@ -1,3 +0,0 @@ -package maf.deltaDebugging.nonTreeDD - -abstract class Change diff --git a/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/DeltaDebugger.scala b/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/DeltaDebugger.scala index abc53455a..40fad63db 100644 --- a/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/DeltaDebugger.scala +++ b/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/DeltaDebugger.scala @@ -1,47 +1,40 @@ package maf.deltaDebugging.nonTreeDD -abstract class DeltaDebugger[C <: Change, T <: TestCase[C]] -(factory: List[C] => T, test: T => Boolean) { +import maf.deltaDebugging.nonTreeDD.AST.Instruction - val x: Int = 10 +object DeltaDebugger: + type Program = List[Instruction] - def ddmin(caseToMinimize: T): T = { - ddmin2(caseToMinimize, 2) - } + def ddmin(program: Program, oracle: Program => Boolean): Program = + ddmin2(program, oracle, 2) - private def ddmin2(caseToMinimize: T, n: Int): T = { //n indicates the number of subsets - val subsets: List[T] = makeSubsets(caseToMinimize, n) - val complements: List[T] = findComplements(caseToMinimize, subsets) + private def ddmin2(program: Program, oracle: Program => Boolean, n: Int): Program = //n indicates the number of subsets + val subsets: List[Program] = makeSubsets(program, n) + val complements: List[Program] = findComplements(program, subsets) - subsets.find(testCase => !test(testCase)) match { - case Some(subset) => ddmin2(subset, 2) //reduce to subset + subsets.find(testCase => oracle(testCase)) match + case Some(subset) => ddmin2(subset, oracle, 2) //reduce to subset case None => - complements.find(testCase => !test(testCase)) match { + complements.find(testCase => oracle(testCase)) match case Some(complement) => - ddmin2(complement, Math.max(n - 1, 2)) //reduce to complement + ddmin2(complement, oracle, Math.max(n - 1, 2)) //reduce to complement case None => - if n < caseToMinimize.changes.length then - ddmin2(caseToMinimize, Math.min(caseToMinimize.changes.length, 2 * n)) - else caseToMinimize - } - } - } - - private def makeSubsets(c: T, n: Int): List[T] = { - val subsetSize: Int = c.changes.length / n + if n < program.length then + ddmin2(program, oracle, Math.min(program.length, 2 * n)) + else program + + private def makeSubsets(program: List[Instruction], n: Int): List[List[Instruction]] = + val subsetSize: Int = program.length / n var i: Int = 0 - var res: List[T] = List() + var res: List[List[Instruction]] = List() - while c.changes.slice(i, i + subsetSize).nonEmpty do //while there is still a slice to collect - val x: T = factory(c.changes.slice(i, i + subsetSize)) + while program.slice(i, i + subsetSize).nonEmpty do //while there is still a slice to collect + val x: List[Instruction] = program.slice(i, i + subsetSize) res = res.::(x) //collect it i = i + subsetSize //repeat res - } - private def findComplements(c: T, subsets: List[T]): List[T] = { + private def findComplements(program: List[Instruction], subsets: List[List[Instruction]]): List[List[Instruction]] = subsets.map(subset => { - factory(c.changes.filterNot(c => subset.changes.contains(c))) + program.filterNot(c => subset.contains(c)) }) - } -} diff --git a/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/Interpreter.scala b/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/Interpreter.scala new file mode 100644 index 000000000..76c09b7bf --- /dev/null +++ b/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/Interpreter.scala @@ -0,0 +1,49 @@ +package maf.deltaDebugging.nonTreeDD + +import maf.deltaDebugging.nonTreeDD.AST.Instruction +import maf.deltaDebugging.nonTreeDD.AST.* + +object Interpreter: + type Program = List[Instruction] + abstract class Register(var value: Int) + case object Reg1 extends Register(-1) + case object Reg2 extends Register(-1) + case object Reg3 extends Register(-1) + case object Reg4 extends Register(-1) + case object Reg5 extends Register(-1) + case object Reg6 extends Register(-1) + case object RegReturn extends Register(-1) + + def eval(program: Program): Int = + Reg1.value = -1 + Reg2.value = -1 + Reg3.value = -1 + Reg4.value = -1 + Reg5.value = -1 + Reg6.value = -1 + RegReturn.value = -1 + evalProgram(program) + + private def evalProgram(program: Program): Int = + program match + case instr :: rest => + instr match + case Set(destination, binOp) => + val v1 = binOp.l.value + val v2 = binOp.r.value + binOp match + case _: Plus => + destination.value = v1 + v2 + case _: Mul => + destination.value = v1 * v2 + case _: Div => + destination.value = v1 / v2 + case _: Sub => + destination.value = v1 - v2 + case SetConstant(destination, const) => + destination.value = const + evalProgram(rest) + + case Nil => + RegReturn.value + diff --git a/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/Main.scala b/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/Main.scala index f1c3a2f33..8893406ff 100644 --- a/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/Main.scala +++ b/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/Main.scala @@ -1,42 +1,34 @@ package maf.deltaDebugging.nonTreeDD -object Main { - case class ListChange(s: String, id: Int = ListChange.newID()) extends Change - object ListChange { - private var ID = 0 - def newID(): Int = { - ID = ID + 1 - ID - } - } +import maf.deltaDebugging.nonTreeDD.AST.* +import maf.deltaDebugging.nonTreeDD.Interpreter.* - case class ListTestCase(override val changes: List[ListChange]) extends TestCase[ListChange](changes) +object Main { - val testCasePass: ListTestCase = ListTestCase(List()) //baseline, or trivial test case that passes the test - val testCaseFail: ListTestCase = ListTestCase(List( - ListChange("define"), - ListChange("/"), - ListChange("+"), - ListChange("-"), - ListChange("++"), - ListChange("--"), - ListChange("set!"), //set! is considered buggy - ListChange("let"))) + type Program = List[Instruction] + val program: List[Instruction] = + List( + SetConstant(Reg1, 10), + SetConstant(Reg2, 0), + Set(Reg3, Mul(Reg1, Reg2)), + Set(Reg4, Plus(Reg1, Reg2)), + Set(Reg5, Div(Reg1, Reg2)), + Set(Reg6, Sub(Reg1, Reg2)), - object ListDeltaDebugger extends DeltaDebugger[ListChange, ListTestCase](ListTestCase.apply, noSetBangs) + SetConstant(RegReturn, 200) //ok + ) - val noSetBangs: ListTestCase => Boolean = (c: ListTestCase) => { - c.changes.find(c => c.s == "set!") match { - case Some(_) => false - case None => true + def main(args: Array[String]): Unit = { + val oracle: Program => Boolean = p => { + try + Interpreter.eval(p) + false + catch + case _: Throwable => true } - } - def main(args: Array[String]): Unit = { - println() - println("") - println("simplifying case: " + testCaseFail) - println("simplified case: " + ListDeltaDebugger.ddmin(testCaseFail)) + val reduced = DeltaDebugger.ddmin(program, oracle) + println(reduced) } } \ No newline at end of file diff --git a/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/TestCase.scala b/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/TestCase.scala deleted file mode 100644 index 31a249a5e..000000000 --- a/code/shared/src/main/scala/maf/deltaDebugging/nonTreeDD/TestCase.scala +++ /dev/null @@ -1,3 +0,0 @@ -package maf.deltaDebugging.nonTreeDD - -abstract class TestCase[+C <: Change](val changes: List[C]) diff --git a/code/shared/src/main/scala/maf/deltaDebugging/treeDD/LayeredSchemeReduce.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/LayeredSchemeReduce.scala new file mode 100644 index 000000000..79a115e4d --- /dev/null +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/LayeredSchemeReduce.scala @@ -0,0 +1,20 @@ +package maf.deltaDebugging.treeDD + +import maf.deltaDebugging.treeDD.transformations.Transformation +import maf.language.scheme.SchemeExp + +object LayeredSchemeReduce: + def reduce(tree: SchemeExp, + oracle: SchemeExp => Boolean, + onOracleHit: SchemeExp => Unit, + transformations: List[Transformation], + deadCodeRemover: Option[SchemeExp => Option[SchemeExp]] = None, + layerSize: Int + ): SchemeExp = + var reduced = tree + var subset: List[Transformation] = List() + while subset.size != transformations.size do + subset = transformations.take(subset.size + layerSize) + reduced = SchemeReduce.reduce(reduced, oracle, onOracleHit, subset, deadCodeRemover) + reduced + diff --git a/code/shared/src/main/scala/maf/deltaDebugging/treeDD/ParallelSchemeReduce.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/ParallelSchemeReduce.scala new file mode 100644 index 000000000..33c982ebe --- /dev/null +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/ParallelSchemeReduce.scala @@ -0,0 +1,61 @@ +package maf.deltaDebugging.treeDD + +import maf.deltaDebugging.treeDD.transformations.Transformation +import maf.language.scheme.SchemeExp +import scala.collection.parallel.CollectionConverters._ + +import scala.annotation.tailrec + +import scala.annotation.tailrec + +object ParallelSchemeReduce: + var fixpoint = true + @tailrec + def reduce(tree: SchemeExp, + oracle: SchemeExp => Boolean, + onOracleHit: SchemeExp => Unit, + transformations: List[Transformation]): SchemeExp = + fixpoint = true + val reducedTree: SchemeExp = BFT(tree, oracle, onOracleHit, transformations) + if fixpoint then + reducedTree + else reduce(reducedTree, oracle, onOracleHit, transformations) + + private def BFT(tree: SchemeExp, + oracle: SchemeExp => Boolean, + onOracleHit: SchemeExp => Unit, + transformations: List[Transformation]): SchemeExp = + var reducedTree = tree + for (lvl <- 0 to reducedTree.height) + reducedTree = reduceLevelNodes(reducedTree, lvl, oracle, onOracleHit, transformations) + reducedTree + + private def reduceLevelNodes(tree: SchemeExp, + lvl: Int, + oracle: SchemeExp => Boolean, + onOracleHit: SchemeExp => Unit, + transformations: List[Transformation]): SchemeExp = + val nodes = tree.levelNodes(lvl) + var candidates: List[SchemeExp] = List() + for (t <- transformations) { + for(node <- nodes) { + for(candidate <- t.transform(tree, node)) { + candidates = candidates.::(candidate) + if candidates.size == 16 then + candidates.par.find(oracle(_)) match + case Some(c) => + fixpoint = false + onOracleHit(c) + return reduceLevelNodes(c, lvl, oracle, onOracleHit, transformations) + case _ => + candidates = List() + } + } + } + + candidates.find(oracle(_)) match + case Some(c) => + fixpoint = false + onOracleHit(c) + reduceLevelNodes(c, lvl, oracle, onOracleHit, transformations) + case _ => tree diff --git a/code/shared/src/main/scala/maf/deltaDebugging/treeDD/SchemeReduce.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/SchemeReduce.scala new file mode 100644 index 000000000..b925bb17d --- /dev/null +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/SchemeReduce.scala @@ -0,0 +1,57 @@ +package maf.deltaDebugging.treeDD + +import maf.deltaDebugging.treeDD.transformations.Transformation +import maf.language.scheme.SchemeExp +import maf.core.Expression + +import scala.annotation.tailrec + +object SchemeReduce: + var fixpoint = true + @tailrec + def reduce(tree: SchemeExp, + oracle: SchemeExp => Boolean, + onOracleHit: SchemeExp => Unit, + transformations: List[Transformation], + deadCodeRemover: Option[SchemeExp => Option[SchemeExp]] = None): SchemeExp = + fixpoint = true + val reducedTree: SchemeExp = BFT(tree, oracle, onOracleHit, transformations, deadCodeRemover) + if fixpoint then + //println("GTR total transformation count: " + transformations.map(_.getHits).fold(0)(_ + _)) + reducedTree + else reduce(reducedTree, oracle, onOracleHit, transformations, deadCodeRemover) + + private def BFT(tree: SchemeExp, + oracle: SchemeExp => Boolean, + onOracleHit: SchemeExp => Unit, + transformations: List[Transformation], + deadCodeRemover: Option[SchemeExp => Option[SchemeExp]]): SchemeExp = + var reducedTree = tree + for (lvl <- 0 to reducedTree.height) + for (transformation <- transformations) + reducedTree = reduceLevelNodes(reducedTree, lvl, oracle, onOracleHit, transformation, deadCodeRemover) + reducedTree + + private def reduceLevelNodes(tree: SchemeExp, + lvl: Int, + oracle: SchemeExp => Boolean, + onOracleHit: SchemeExp => Unit, + transformation: Transformation, + deadCodeRemover: Option[SchemeExp => Option[SchemeExp]]): SchemeExp = + for(node <- tree.levelNodes(lvl)) + for (candidateTree <- transformation.transform(tree, node)) + if candidateTree.size <= tree.size then + transformation.invoke() + if oracle(candidateTree) then + fixpoint = false + onOracleHit(candidateTree) + transformation.hit() + deadCodeRemover match + case Some(remover) => + val maybeRemoved = remover(candidateTree) + maybeRemoved match + case Some(removed) => + return reduceLevelNodes(candidateTree, lvl, oracle, onOracleHit, transformation, deadCodeRemover) + case _ => return reduceLevelNodes(candidateTree, lvl, oracle, onOracleHit, transformation, deadCodeRemover) + case _ => return reduceLevelNodes(candidateTree, lvl, oracle, onOracleHit, transformation, deadCodeRemover) + tree diff --git a/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/Transformation.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/Transformation.scala new file mode 100644 index 000000000..e6adef74d --- /dev/null +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/Transformation.scala @@ -0,0 +1,48 @@ +package maf.deltaDebugging.treeDD.transformations + +import maf.language.scheme.{SchemeExp, SchemeParser} + +abstract class Transformation: + var trees: List[SchemeExp] = List() + var replacements: List[SchemeExp] = List() + + def addTree(t: SchemeExp): Unit = + trees = trees.::(t) + + def addTrees(ts: List[SchemeExp]): Unit = + ts.foreach(addTree) + + def addReplacement(replacement: SchemeExp): Unit = + replacements = replacements.::(replacement) + + def addReplacements(rs: List[SchemeExp]): Unit = + rs.foreach(addReplacement) + + /** transform returns all transformations */ + def transform(tree: SchemeExp, node: SchemeExp): Iterator[SchemeExp] = + require(tree.contains(node)) + trees = List() + replacements = List() + + transformAndAdd(tree, node) //should fill trees and replacements + + var suggestions = (trees ++ replacements.map(r => tree.replace(node, r))) + suggestions = suggestions.map(s => SchemeParser.parse(s.prettyString()).head) + + trees = List() + replacements = List() + suggestions.iterator + + /** transformAndAdd is a subclass responsibility */ + protected def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit + + val name: String + private var hits: Int = 0 + def getHits: Int = hits + def hit(): Unit = + hits += 1 + + private var invocations: Int = 0 + def getInvocations: Int = invocations + def invoke(): Unit = + invocations += 1 \ No newline at end of file diff --git a/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/TransformationManager.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/TransformationManager.scala new file mode 100644 index 000000000..eca12e687 --- /dev/null +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/TransformationManager.scala @@ -0,0 +1,33 @@ +package maf.deltaDebugging.treeDD.transformations + +import maf.deltaDebugging.treeDD.transformations.schemeSequencify.IfToBegin +import maf.deltaDebugging.treeDD.transformations.schemeLambda.* +import maf.deltaDebugging.treeDD.transformations.schemeBinding.* +import maf.deltaDebugging.treeDD.transformations.generics.* +import maf.deltaDebugging.treeDD.transformations.schemeIdentifier.ReplaceIdentifier +import maf.deltaDebugging.treeDD.transformations.schemePrim.ReplacePrimCalls + +object TransformationManager: + + val genericTransformations: List[Transformation] = + List( + DeleteChildSimple, + ReplaceByChild + ) + + val allTransformations: List[Transformation] = + List( + LetToBegin, + IfToBegin, + ThunkToBegin, + BindingDrop, + ReplacePrimCalls, + RemoveLambdaParamWithDeepDrop, + ReplaceByChild, + DeleteChildSimple, + ReplaceCalls, + BindingReplace, + RemoveLambdaParamByReplacement, + ReplaceIdentifier, + RemoveCalls, + ) diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/generics/DeleteChildSimple.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/generics/DeleteChildSimple.scala similarity index 89% rename from code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/generics/DeleteChildSimple.scala rename to code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/generics/DeleteChildSimple.scala index 9bf55d7cf..da1002a74 100644 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/generics/DeleteChildSimple.scala +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/generics/DeleteChildSimple.scala @@ -1,6 +1,6 @@ -package maf.deltaDebugging.gtr.transformations.generics +package maf.deltaDebugging.treeDD.transformations.generics -import maf.deltaDebugging.gtr.transformations.Transformation +import maf.deltaDebugging.treeDD.transformations.Transformation import maf.core.{Identifier, Identity} import maf.language.scheme.* diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/generics/ReplaceByChild.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/generics/ReplaceByChild.scala similarity index 72% rename from code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/generics/ReplaceByChild.scala rename to code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/generics/ReplaceByChild.scala index 5b23c79f1..02ac7eb30 100644 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/generics/ReplaceByChild.scala +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/generics/ReplaceByChild.scala @@ -1,6 +1,6 @@ -package maf.deltaDebugging.gtr.transformations.generics +package maf.deltaDebugging.treeDD.transformations.generics -import maf.deltaDebugging.gtr.transformations.Transformation +import maf.deltaDebugging.treeDD.transformations.Transformation import maf.language.scheme.SchemeExp object ReplaceByChild extends Transformation: diff --git a/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/generics/ReplaceByValue.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/generics/ReplaceByValue.scala new file mode 100644 index 000000000..3f1981141 --- /dev/null +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/generics/ReplaceByValue.scala @@ -0,0 +1,15 @@ +package maf.deltaDebugging.treeDD.transformations.generics + +import maf.deltaDebugging.treeDD.transformations.Transformation +import maf.deltaDebugging.treeDD.transformations.traits.Replacing +import maf.core.Identifier +import maf.language.scheme.* +import maf.language.sexp.Value + +object ReplaceByValue extends Transformation: + override val name: String = "ReplaceByValue" + + //replace by value under certain circumstances, avoiding time/space overheads + override def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit = + if tree.size < 40 then + addReplacements(Replacing.allValues(node)) diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLet/LetIdentifierDeepDrop.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeBinding/BindingDrop.scala similarity index 62% rename from code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLet/LetIdentifierDeepDrop.scala rename to code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeBinding/BindingDrop.scala index 5a7eb5514..040986e67 100644 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLet/LetIdentifierDeepDrop.scala +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeBinding/BindingDrop.scala @@ -1,10 +1,10 @@ -package maf.deltaDebugging.gtr.transformations.schemeLet +package maf.deltaDebugging.treeDD.transformations.schemeBinding -import maf.deltaDebugging.gtr.transformations.Transformation +import maf.deltaDebugging.treeDD.transformations.Transformation import maf.language.scheme.{SchemeExp, SchemeLettishExp} -object LetIdentifierDeepDrop extends Transformation: - override val name: String = "LetIdentifierDeepDrop" +object BindingDrop extends Transformation: + override val name: String = "BindingDrop" def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit = node match diff --git a/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeBinding/BindingReplace.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeBinding/BindingReplace.scala new file mode 100644 index 000000000..53498be17 --- /dev/null +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeBinding/BindingReplace.scala @@ -0,0 +1,18 @@ +package maf.deltaDebugging.treeDD.transformations.schemeBinding + +import maf.deltaDebugging.treeDD.transformations.Transformation +import maf.deltaDebugging.treeDD.transformations.traits.Replacing +import maf.language.scheme.{AContractSchemeMessage, ASchemeExp, CSchemeExp, ContractSchemeExp, MatchExpr, RacketModule, RacketModuleExpose, RacketModuleLoad, RacketProvide, RacketRequire, SchemeAssert, SchemeBegin, SchemeCodeChange, SchemeDefineVariable, SchemeExp, SchemeFuncall, SchemeIf, SchemeLambdaExp, SchemeLettishExp, SchemeSanitizer, SchemeSetExp, SchemeSink, SchemeSource, SchemeValue, SchemeVarExp, SymbolicHole, SymbolicVar} + +object BindingReplace extends Transformation: + override val name: String = "BindingReplace" + + override protected def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit = + node match + case lettish: SchemeLettishExp => + for (id <- lettish.bindings.map(_._1)) + val bindingDropped = lettish.dropBinding(id.name) + val lets = Replacing.replaceIdWithAllValues(bindingDropped, id) + addReplacements(lets) + case _ => + diff --git a/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeBinding/DefineDrop.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeBinding/DefineDrop.scala new file mode 100644 index 000000000..cbbed2c78 --- /dev/null +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeBinding/DefineDrop.scala @@ -0,0 +1,29 @@ +package maf.deltaDebugging.treeDD.transformations.schemeBinding + +import maf.deltaDebugging.treeDD.transformations.Transformation +import maf.language.scheme.* + +object DefineDrop extends Transformation: + override val name: String = "DefineDrop" + + override protected def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit = + node match + case SchemeDefineVariable(name, value: SchemeLambdaExp, idn) => + None + case definition@SchemeDefineVariable(name, value, idn) => + val defDropped = tree.deleteChildren(exp => exp eq definition) + defDropped match + case Some(defDroppedTree) => + val refsDropped = defDroppedTree.deleteChildren(subExp => { + subExp match + case varExp: SchemeVarExp => + varExp.id.name equals name.name + case _ => false + }) + + refsDropped match + case Some(tree) => + addTree(tree) + case _ => + case _ => + case _ => diff --git a/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeBinding/DefineReplace.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeBinding/DefineReplace.scala new file mode 100644 index 000000000..4878730a0 --- /dev/null +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeBinding/DefineReplace.scala @@ -0,0 +1,22 @@ +package maf.deltaDebugging.treeDD.transformations.schemeBinding + +import maf.deltaDebugging.treeDD.transformations.Transformation +import maf.deltaDebugging.treeDD.transformations.schemeBinding.DefineDrop.addTree +import maf.deltaDebugging.treeDD.transformations.traits.Replacing +import maf.language.scheme.{SchemeDefineVariable, SchemeExp, SchemeLambdaExp, SchemeVarExp} + +object DefineReplace extends Transformation: + override val name: String = "DefineReplace" + + override protected def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit = + node match + case SchemeDefineVariable(name, value: SchemeLambdaExp, idn) => + None + case definition@SchemeDefineVariable(name, value, idn) => + val defDropped = tree.deleteChildren(exp => exp eq definition) + defDropped match + case Some(defDroppedTree) => + val trees = Replacing.replaceIdWithAllValues(defDroppedTree, name) + addTrees(trees) + case _ => + case _ => \ No newline at end of file diff --git a/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeBinding/LetToBegin.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeBinding/LetToBegin.scala new file mode 100644 index 000000000..49156e775 --- /dev/null +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeBinding/LetToBegin.scala @@ -0,0 +1,15 @@ +package maf.deltaDebugging.treeDD.transformations.schemeBinding + +import maf.core.NoCodeIdentity +import maf.deltaDebugging.treeDD.transformations.Transformation +import maf.language.scheme.{AContractSchemeMessage, ASchemeExp, CSchemeExp, ContractSchemeExp, MatchExpr, RacketModule, RacketModuleExpose, RacketModuleLoad, RacketProvide, RacketRequire, SchemeAssert, SchemeBegin, SchemeCodeChange, SchemeDefineVariable, SchemeExp, SchemeFuncall, SchemeIf, SchemeLambdaExp, SchemeLettishExp, SchemeSanitizer, SchemeSetExp, SchemeSink, SchemeSource, SchemeValue, SchemeVarExp, SymbolicHole, SymbolicVar} + +object LetToBegin extends Transformation: + override val name: String = "LetToBegin" + + override protected def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit = + node match + case exp: SchemeLettishExp => + if exp.bindings.isEmpty then + addReplacement(SchemeBegin(exp.body, NoCodeIdentity)) + case _ => diff --git a/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeIdentifier/ReplaceIdentifier.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeIdentifier/ReplaceIdentifier.scala new file mode 100644 index 000000000..a4b7f1318 --- /dev/null +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeIdentifier/ReplaceIdentifier.scala @@ -0,0 +1,15 @@ +package maf.deltaDebugging.treeDD.transformations.schemeIdentifier + +import maf.deltaDebugging.treeDD.transformations.Transformation +import maf.deltaDebugging.treeDD.transformations.traits.Replacing +import maf.language.scheme.{SchemeExp, SchemeVarExp} + +object ReplaceIdentifier extends Transformation: + override val name: String = "ReplaceIdentifier" + + def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit = + node match + case _: SchemeVarExp => + if tree.size < 100 then + addReplacements(Replacing.allValues(node)) + case _ => diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/RemoveCalls.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeLambda/RemoveCalls.scala similarity index 76% rename from code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/RemoveCalls.scala rename to code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeLambda/RemoveCalls.scala index 27a836257..184a3fbcb 100644 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/RemoveCalls.scala +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeLambda/RemoveCalls.scala @@ -1,11 +1,11 @@ -package maf.deltaDebugging.gtr.transformations.schemeLambda +package maf.deltaDebugging.treeDD.transformations.schemeLambda -import maf.deltaDebugging.gtr.transformations.Transformation -import maf.deltaDebugging.gtr.transformations.traits.Replacing +import maf.deltaDebugging.treeDD.transformations.Transformation +import maf.deltaDebugging.treeDD.transformations.traits.Replacing import maf.core.Identifier import maf.language.scheme.* -object RemoveCalls extends Transformation with Replacing: +object RemoveCalls extends Transformation: override val name: String = "RemoveCalls" override def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit = { def removeIdCalls(id: Identifier, newTree: SchemeExp): Unit = @@ -17,7 +17,7 @@ object RemoveCalls extends Transformation with Replacing: applsRemoved match case Some(callsRemovedTree) => - val trees = replaceCallWithAllValues(callsRemovedTree, id) //this removes any non-call references to the lambda + val trees = Replacing.replaceCallWithAllValues(callsRemovedTree, id) //this removes any non-call references to the lambda addTrees(trees) case _ => diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/RemoveLambdaParamByReplacement.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeLambda/RemoveLambdaParamByReplacement.scala similarity index 78% rename from code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/RemoveLambdaParamByReplacement.scala rename to code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeLambda/RemoveLambdaParamByReplacement.scala index da16c3c81..99f93eb45 100644 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/RemoveLambdaParamByReplacement.scala +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeLambda/RemoveLambdaParamByReplacement.scala @@ -1,11 +1,11 @@ -package maf.deltaDebugging.gtr.transformations.schemeLambda +package maf.deltaDebugging.treeDD.transformations.schemeLambda -import maf.deltaDebugging.gtr.transformations.Transformation -import maf.deltaDebugging.gtr.transformations.traits.{CallReducing, Replacing} +import maf.deltaDebugging.treeDD.transformations.Transformation +import maf.deltaDebugging.treeDD.transformations.traits.{CallReducing, Replacing} import maf.core.Identifier import maf.language.scheme.* -object RemoveLambdaParamByReplacement extends Transformation with CallReducing with Replacing: +object RemoveLambdaParamByReplacement extends Transformation with CallReducing: override val name: String = "RemoveLambdaParamByReplacement" override def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit = { @@ -16,7 +16,7 @@ object RemoveLambdaParamByReplacement extends Transformation with CallReducing w case varargLambda: SchemeVarArgLambda => varargLambda.copy(args = varargLambda.args.filterNot(a => a.name equals arg.name)) case lambda: SchemeLambda => lambda.copy(args = lambda.args.filterNot(a => a.name equals arg.name)) - val argReplacedLambdas = replaceIdWithAllValues(paramDropped, arg) //replace arg (e.g. x) with all kinds of values (e.g. 1, "s", 's, ...) + val argReplacedLambdas = Replacing.replaceIdWithAllValues(paramDropped, arg) //replace arg (e.g. x) with all kinds of values (e.g. 1, "s", 's, ...) for (argReplaced <- argReplacedLambdas) val lambdaReplaced = tree.replace(lambda, argReplaced) diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/RemoveLambdaParamWithDeepDrop.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeLambda/RemoveLambdaParamWithDeepDrop.scala similarity index 86% rename from code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/RemoveLambdaParamWithDeepDrop.scala rename to code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeLambda/RemoveLambdaParamWithDeepDrop.scala index d8e82e5dd..a208d5d68 100644 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/RemoveLambdaParamWithDeepDrop.scala +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeLambda/RemoveLambdaParamWithDeepDrop.scala @@ -1,7 +1,7 @@ -package maf.deltaDebugging.gtr.transformations.schemeLambda +package maf.deltaDebugging.treeDD.transformations.schemeLambda -import maf.deltaDebugging.gtr.transformations.Transformation -import maf.deltaDebugging.gtr.transformations.traits.CallReducing +import maf.deltaDebugging.treeDD.transformations.Transformation +import maf.deltaDebugging.treeDD.transformations.traits.CallReducing import maf.deltaDebugging.primitiveOpNames.PrimitiveOpNames import maf.core.{Identifier, Identity} import maf.language.scheme.* diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/ReplaceCalls.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeLambda/ReplaceCalls.scala similarity index 65% rename from code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/ReplaceCalls.scala rename to code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeLambda/ReplaceCalls.scala index fc7db5937..c03551fe3 100644 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/ReplaceCalls.scala +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeLambda/ReplaceCalls.scala @@ -1,11 +1,11 @@ -package maf.deltaDebugging.gtr.transformations.schemeLambda +package maf.deltaDebugging.treeDD.transformations.schemeLambda -import maf.deltaDebugging.gtr.transformations.Transformation -import maf.deltaDebugging.gtr.transformations.traits.Replacing +import maf.deltaDebugging.treeDD.transformations.Transformation +import maf.deltaDebugging.treeDD.transformations.traits.Replacing import maf.core.Identifier import maf.language.scheme.* -object ReplaceCalls extends Transformation with Replacing: +object ReplaceCalls extends Transformation: override val name: String = "ReplaceCalls" override def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit = { @@ -17,13 +17,13 @@ object ReplaceCalls extends Transformation with Replacing: for(lambdaBinding <- lambdaBindings) val newTree = tree.replace(exp, exp.dropBinding(lambdaBinding._1.name)) - addTrees(replaceCallWithAllValues(newTree, lambdaBinding._1)) + addTrees(Replacing.replaceCallWithAllValues(newTree, lambdaBinding._1)) case defExp@SchemeDefineVariable(name, _: SchemeLambdaExp, _) => val newTree = tree.deleteChildren(child => child eq defExp) //removes the definition newTree match case Some(newTree) => - addTrees(replaceCallWithAllValues(newTree, name)) + addTrees(Replacing.replaceCallWithAllValues(newTree, name)) case _ => case _ => diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/ReplaceNthExpensiveFunction.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeLambda/ReplaceNthExpensiveFunction.scala similarity index 64% rename from code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/ReplaceNthExpensiveFunction.scala rename to code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeLambda/ReplaceNthExpensiveFunction.scala index e20b2a9ae..b21368b47 100644 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/ReplaceNthExpensiveFunction.scala +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeLambda/ReplaceNthExpensiveFunction.scala @@ -1,14 +1,14 @@ -package maf.deltaDebugging.gtr.transformations.schemeLambda +package maf.deltaDebugging.treeDD.transformations.schemeLambda -import maf.deltaDebugging.gtr.transformations.Transformation -import maf.deltaDebugging.gtr.transformations.traits.Replacing +import maf.deltaDebugging.treeDD.transformations.Transformation +import maf.deltaDebugging.treeDD.transformations.traits.Replacing import maf.deltaDebugging.primitiveOpNames.PrimitiveOpNames import maf.core.Identity import maf.language.scheme.* -class ReplaceNthExpensiveFunction(arr: Array[(String, Int)], n: Int) extends Transformation with Replacing: +class ReplaceNthExpensiveFunction(arr: Array[(String, Int)], n: Int) extends Transformation: override val name: String = "ReplaceNthExpensiveFunction" - private val nthExpensive = arr(n) + private val nthExpensiveName: String = arr(n)._1 override protected def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit = node match @@ -18,17 +18,17 @@ class ReplaceNthExpensiveFunction(arr: Array[(String, Int)], n: Int) extends Tra }) for (lambdaBinding <- lambdaBindings) - if lambdaBinding._1.name equals nthExpensive._1 then + if lambdaBinding._1.name equals nthExpensiveName then val newLet = lettishExp.dropBinding(lambdaBinding._1.name) val newTree = tree.replace(lettishExp, newLet) - addTrees(replaceCallWithAllValues(newTree, lambdaBinding._1)) + addTrees(Replacing.replaceCallWithAllValues(newTree, lambdaBinding._1)) case defExp@SchemeDefineVariable(name, _: SchemeLambdaExp, _) => - if name.name equals nthExpensive._1 then + if name.name equals nthExpensiveName then val newTree = tree.deleteChildren(child => child eq defExp) //removes the definition newTree match case Some(newTree) => - addTrees(replaceCallWithAllValues(newTree, name)) + addTrees(Replacing.replaceCallWithAllValues(newTree, name)) case _ => case _ => \ No newline at end of file diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/RemoveCallsAndReplaceByBody.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeLambda/ThunkToBegin.scala similarity index 61% rename from code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/RemoveCallsAndReplaceByBody.scala rename to code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeLambda/ThunkToBegin.scala index f3f74c4e3..b760a4f97 100644 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeLambda/RemoveCallsAndReplaceByBody.scala +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeLambda/ThunkToBegin.scala @@ -1,27 +1,27 @@ -package maf.deltaDebugging.gtr.transformations.schemeLambda +package maf.deltaDebugging.treeDD.transformations.schemeLambda -import maf.deltaDebugging.gtr.transformations.Transformation -import maf.deltaDebugging.gtr.transformations.traits.Replacing +import maf.deltaDebugging.treeDD.transformations.Transformation +import maf.deltaDebugging.treeDD.transformations.traits.Replacing import maf.core.{Identifier, NoCodeIdentity} import maf.language.scheme.* -object RemoveCallsAndReplaceByBody extends Transformation with Replacing: +object ThunkToBegin extends Transformation: override val name: String = "RemoveCallsAndReplaceByBody" override def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit = { def removeCallsAndReplaceByBody(lambda: SchemeLambdaExp, id: Identifier): Unit = val lambdaReplaced = tree.replace(lambda, SchemeBegin(lambda.body, lambda.idn)) - val callsRemoved = lambdaReplaced.deleteChildren({ - case SchemeFuncall(f: SchemeVarExp, _, _) => - f.id.name == id.name - case _ => false + val callsRemoved = lambdaReplaced.map(subExp => { + subExp match + case SchemeFuncall(f: SchemeVarExp, args, idn) => + if f.id.name equals id.name then + f + else subExp + case _ => subExp }) - callsRemoved match - case Some(tree: SchemeExp) => - addTree(tree) - case _ => + addTree(callsRemoved) node match case exp: SchemeLettishExp => diff --git a/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemePrim/ReplacePrimCalls.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemePrim/ReplacePrimCalls.scala new file mode 100644 index 000000000..fe3aaf29a --- /dev/null +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemePrim/ReplacePrimCalls.scala @@ -0,0 +1,44 @@ +package maf.deltaDebugging.treeDD.transformations.schemePrim + +import maf.core.NoCodeIdentity +import maf.deltaDebugging.treeDD.transformations.Transformation +import maf.language.scheme.{AContractSchemeMessage, ASchemeExp, CSchemeExp, ContractSchemeExp, MatchExpr, RacketModule, RacketModuleExpose, RacketModuleLoad, RacketProvide, RacketRequire, SchemeAssert, SchemeBegin, SchemeCodeChange, SchemeDefineVariable, SchemeExp, SchemeFuncall, SchemeIf, SchemeLambdaExp, SchemeLettishExp, SchemeSanitizer, SchemeSetExp, SchemeSink, SchemeSource, SchemeValue, SchemeVarExp, SymbolicHole, SymbolicVar} +import maf.language.sexp.Value + +object ReplacePrimCalls extends Transformation: + override val name: String = "FoldPrimitives" + + override protected def transformAndAdd(tree: SchemeExp, node: SchemeExp): Unit = + node match + case SchemeFuncall(f: SchemeVarExp, args, idn) => + val name = f.id.name + if name.endsWith("?") then + addReplacements( + List( + SchemeValue(Value.Boolean(true), NoCodeIdentity), + SchemeValue(Value.Boolean(false), NoCodeIdentity), + ) + ) + else if name.contains("string->number") then + addReplacements( + List( + SchemeValue(Value.Integer(1), NoCodeIdentity), + SchemeValue(Value.Integer(0), NoCodeIdentity) + ) + ) + else if name.contains("number->string") then + addReplacements( + List( + SchemeValue(Value.String("1"), NoCodeIdentity), + SchemeValue(Value.String("0"), NoCodeIdentity), + ) + ) + else if name.contains("string->symbol") then + addReplacement( + SchemeValue(Value.Symbol("a"), NoCodeIdentity), + ) + else if name.contains("symbol->string") then + addReplacement( + SchemeValue(Value.String("a"), NoCodeIdentity), + ) + case _ => \ No newline at end of file diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeIf/IfToBegin.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeSequencify/IfToBegin.scala similarity index 74% rename from code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeIf/IfToBegin.scala rename to code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeSequencify/IfToBegin.scala index b4e07ef4d..86dd514f4 100644 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/schemeIf/IfToBegin.scala +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/schemeSequencify/IfToBegin.scala @@ -1,6 +1,6 @@ -package maf.deltaDebugging.gtr.transformations.schemeIf +package maf.deltaDebugging.treeDD.transformations.schemeSequencify -import maf.deltaDebugging.gtr.transformations.Transformation +import maf.deltaDebugging.treeDD.transformations.Transformation import maf.language.scheme.* object IfToBegin extends Transformation: diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/traits/CallReducing.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/traits/CallReducing.scala similarity index 89% rename from code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/traits/CallReducing.scala rename to code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/traits/CallReducing.scala index c44047648..d5f4b6d9e 100644 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/transformations/traits/CallReducing.scala +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/traits/CallReducing.scala @@ -1,4 +1,4 @@ -package maf.deltaDebugging.gtr.transformations.traits +package maf.deltaDebugging.treeDD.transformations.traits import maf.core.Identifier import maf.language.scheme.{SchemeExp, SchemeFuncall, SchemeVarExp} diff --git a/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/traits/Replacing.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/traits/Replacing.scala new file mode 100644 index 000000000..5027d413d --- /dev/null +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/transformations/traits/Replacing.scala @@ -0,0 +1,205 @@ +package maf.deltaDebugging.treeDD.transformations.traits + +import maf.core.{Identifier, NoCodeIdentity} +import maf.language.scheme.* +import maf.language.scheme.interpreter.ConcreteValues +import maf.language.sexp.Value +import maf.core.Identity +import maf.language.scheme.lattices.ModularSchemeLattice +import maf.lattice.{HMap, HMapKey} +import maf.modular.{AnalysisResults, ModAnalysis} +import maf.modular.scheme.SchemeDomain + +object Replacing: + private var count = -1 + var valuesMap: Map[SchemeExp, Set[ConcreteValues.Value]] = Map() + var problematicValue: Option[ConcreteValues.Value] = None + + /* + type Analysis = ModAnalysis[SchemeExp] with AnalysisResults[SchemeExp] with SchemeDomain + var analysis: Option[Analysis] = None + */ + + private def newID(): String = + count += 1 + "unique_args_" + count.toString + + private def newCallerLambda(args: List[SchemeExp]) = + val id = newID() + SchemeLambda( + None, + List(Identifier(id, NoCodeIdentity)), + List(SchemeFuncall( + f = SchemeVar(Identifier(id, NoCodeIdentity)), + args = args, + idn = NoCodeIdentity, + )), + None, + NoCodeIdentity) + + private def callerLambdas(): List[SchemeLambda] = + val values: List[SchemeExp] = + List( + SchemeValue(Value.Integer(0), NoCodeIdentity), + SchemeValue(Value.Boolean(true), NoCodeIdentity), + ) + val valuesToTry = values.combinations(1).toList ++ values.combinations(2).toList + valuesToTry.map(args => newCallerLambda(args)) + + private def newConstantLambda(BodyExp: SchemeExp): SchemeVarArgLambda = + SchemeVarArgLambda(None, List(), Identifier(newID(), NoCodeIdentity), List(BodyExp), None, NoCodeIdentity) + + private def constantLambdas(): List[SchemeVarArgLambda] = List( + newConstantLambda(SchemeValue(Value.Integer(1), NoCodeIdentity)), + newConstantLambda(SchemeValue(Value.String("a"), NoCodeIdentity)), + newConstantLambda(SchemeValue(Value.Symbol("a"), NoCodeIdentity)), + newConstantLambda(SchemeValue(Value.Boolean(true), NoCodeIdentity)), + newConstantLambda(SchemeValue(Value.Boolean(false), NoCodeIdentity)), + newConstantLambda(SchemeValue(Value.Nil, NoCodeIdentity)), + ) + + private def lambdaValues(): List[SchemeLambdaExp] = + constantLambdas() ++ callerLambdas() + + private val values: List[SchemeExp] = List( + SchemeValue(Value.Integer(1), NoCodeIdentity), + SchemeValue(Value.String("a"), NoCodeIdentity), + SchemeValue(Value.Symbol("a"), NoCodeIdentity), + SchemeValue(Value.Boolean(true), NoCodeIdentity), + SchemeValue(Value.Boolean(false), NoCodeIdentity), + SchemeValue(Value.Nil, NoCodeIdentity) + ) + + def allSimpleValues(exp: SchemeExp): List[SchemeExp] = + val observedValues = valuesMap.getOrElse(exp, Set()).toList + if observedValues.isEmpty then + values + else + problematicValue match + case Some(concreteProblematicValue) => + val filteredProblematic = observedValues.filter(value => value equals concreteProblematicValue) + val filteredNonProblematic = observedValues.filterNot(value => value equals concreteProblematicValue) + val ordered = filteredProblematic ++ filteredNonProblematic //problematic ones get priority + val expLst = ordered.flatMap(value => valueToExp(value)) + if expLst.isEmpty then + values + else expLst + case None => + val expLst = observedValues.flatMap(value => valueToExp(value)) + if expLst.nonEmpty then + expLst + else values + + def allValues(exp: SchemeExp): List[SchemeExp] = + val observedValues = valuesMap.getOrElse(exp, Set()).toList + if observedValues.isEmpty then + lambdaValues() ++ values + else + problematicValue match + case Some(concreteProblematicValue) => + val filteredProblematic = observedValues.filter(value => value equals concreteProblematicValue) + val filteredNonProblematic = observedValues.filterNot(value => value equals concreteProblematicValue) + val ordered = filteredProblematic ++ filteredNonProblematic //problematic ones get priority + val expLst = ordered.flatMap(value => valueToExp(value)) + if expLst.isEmpty then + lambdaValues() ++ values + else expLst + case None => + val expLst = observedValues.flatMap(value => valueToExp(value)) + if expLst.nonEmpty then + expLst + else lambdaValues() ++ values + + private def replaceWithValue(exp: SchemeExp, toReplace: SchemeExp => Boolean, value: SchemeExp): SchemeExp = + exp.map(subExp => { + if toReplace(subExp) then + value match + case s: SchemeVarArgLambda => + s.copy(vararg = Identifier(newID(), NoCodeIdentity)) + case _ => value + else subExp + }) + + def replaceWithAllValues(exp: SchemeExp, toReplace: SchemeExp => Boolean): List[SchemeExp] = + allValues(exp).map(value => { + replaceWithValue(exp, toReplace, value) + }) + + def replaceIdWithAllValues(exp: SchemeExp, id: Identifier): List[SchemeExp] = + replaceWithAllValues(exp, subExp => { + subExp match + case varExp: SchemeVarExp => + varExp.id.name equals id.name + case _ => false + }) + + def replaceCallWithAllValues(exp: SchemeExp, id: Identifier): List[SchemeExp] = + replaceWithAllValues(exp, subExp => { + subExp match + case SchemeFuncall(f: SchemeVarExp, _, _) => + f.id.name equals id.name + case varExp: SchemeVarExp => + varExp.id.name equals id.name + case _ => false + }) + + def valueToExp(value: ConcreteValues.Value): Option[SchemeExp] = + value match + case ConcreteValues.Value.Str(str) => + Some(SchemeValue(Value.String(str), NoCodeIdentity)) + case ConcreteValues.Value.Pointer(_) => + Some(SchemeValue(Value.String("a"), NoCodeIdentity)) + case ConcreteValues.Value.Integer(n) => + Some(SchemeValue(Value.Integer(n), NoCodeIdentity)) + case ConcreteValues.Value.Real(r) => + Some(SchemeValue(Value.Real(r), NoCodeIdentity)) + case ConcreteValues.Value.Bool(b) => + Some(SchemeValue(Value.Boolean(b), NoCodeIdentity)) + case ConcreteValues.Value.Symbol(s) => + Some(SchemeValue(Value.Symbol(s), NoCodeIdentity)) + case ConcreteValues.Value.Nil => + Some(SchemeValue(Value.Nil, NoCodeIdentity)) + case ConcreteValues.Value.Cons(car, cdr) => + val maybeCar = valueToExp(car) + val maybeCdr = valueToExp(cdr) + (maybeCar, maybeCdr) match + case (Some(carExp), Some(cdrExp)) => + Some(SchemePair(carExp, cdrExp, NoCodeIdentity)) + case _ => + None + case v: ConcreteValues.Value.Clo => + Some(constantLambdas().head) + case _ => None + + private def extractTypes(keySet: Set[HMapKey]): Set[String] = + var res: Set[String] = Set() + for (key <- keySet) + val asString = key.toString + if asString.contains("StrT") then + res += "String" + if asString.contains("IntT") then + res += "Int" + if asString.contains("BoolT") then + res += "Boolean" + if asString.contains("SymbolT") then + res += "Symbol" + if asString.contains("NilT") then + res += "Nil" + res + + private def typeToExps(t: String): List[SchemeExp] = + t match + case "String" => + List(SchemeValue(Value.String("S"), NoCodeIdentity)) + case "Int" => + List(SchemeValue(Value.Integer(1), NoCodeIdentity)) + case "Boolean" => + List( + SchemeValue(Value.Boolean(true), NoCodeIdentity), + SchemeValue(Value.Boolean(false), NoCodeIdentity) + ) + case "Symbol" => + List(SchemeValue(Value.Symbol("S"), NoCodeIdentity)) + case "Nil" => + List(SchemeValue(Value.Nil, NoCodeIdentity)) + case _ => List() diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/variants/CountingGTR.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/variants/CountingGTR.scala similarity index 90% rename from code/shared/src/main/scala/maf/deltaDebugging/gtr/variants/CountingGTR.scala rename to code/shared/src/main/scala/maf/deltaDebugging/treeDD/variants/CountingGTR.scala index a385a5f71..6f7141715 100644 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/variants/CountingGTR.scala +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/variants/CountingGTR.scala @@ -1,6 +1,6 @@ -package maf.deltaDebugging.gtr.variants +package maf.deltaDebugging.treeDD.variants -import maf.deltaDebugging.gtr.transformations.Transformation +import maf.deltaDebugging.treeDD.transformations.Transformation import maf.core.Expression import maf.language.scheme.SchemeExp @@ -33,7 +33,6 @@ object CountingGTR: if candidateTree.size <= tree.size then if oracle(candidateTree) then OracleHits += 1 - transformation.hit(candidateTree, candidateIdx) if OracleHits == max then return candidateTree else return reduceLevelNodes(candidateTree, lvl, oracle, transformation) diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/variants/FirstInternalGTR.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/variants/FirstInternalGTR.scala similarity index 76% rename from code/shared/src/main/scala/maf/deltaDebugging/gtr/variants/FirstInternalGTR.scala rename to code/shared/src/main/scala/maf/deltaDebugging/treeDD/variants/FirstInternalGTR.scala index 8215cc4d3..3883e2ffd 100644 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/variants/FirstInternalGTR.scala +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/variants/FirstInternalGTR.scala @@ -1,7 +1,7 @@ -package maf.deltaDebugging.gtr.variants +package maf.deltaDebugging.treeDD.variants -import maf.deltaDebugging.gtr.GTR -import maf.deltaDebugging.gtr.transformations.Transformation +import maf.deltaDebugging.treeDD.SchemeReduce +import maf.deltaDebugging.treeDD.transformations.Transformation import maf.core.Expression import maf.language.scheme.SchemeExp @@ -12,13 +12,13 @@ object FirstInternalGTR: def reduce(tree: SchemeExp, oracle: SchemeExp => Boolean, transformations: List[Transformation]): SchemeExp = var reducedTree: SchemeExp = tree if reducedTree.height < 3 then - GTR.reduce(reducedTree, oracle, identity, transformations) + SchemeReduce.reduce(reducedTree, oracle, identity, transformations) else for(lvl <- 0 to (reducedTree.height - 3)) for(transformation <- transformations) reducedTree = reduceLevelNodes(reducedTree, lvl, oracle, transformation) if tree.size == reducedTree.size then - GTR.reduce(reducedTree, oracle, identity, transformations) + SchemeReduce.reduce(reducedTree, oracle, identity, transformations) else reduce(reducedTree, oracle, transformations) private def reduceLevelNodes(tree: SchemeExp, lvl: Int, oracle: SchemeExp => Boolean, transformation: Transformation): SchemeExp = @@ -26,7 +26,6 @@ object FirstInternalGTR: for((candidateTree, candidateIdx) <- transformation.transform(tree, node).zipWithIndex) if candidateTree.size <= tree.size then if oracle(candidateTree) then - transformation.hit(candidateTree, candidateIdx) return reduceLevelNodes(candidateTree, lvl, oracle, transformation) tree diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/variants/SimpleGTR.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/variants/GTR.scala similarity index 68% rename from code/shared/src/main/scala/maf/deltaDebugging/gtr/variants/SimpleGTR.scala rename to code/shared/src/main/scala/maf/deltaDebugging/treeDD/variants/GTR.scala index 5a6c83dca..f4c7b5508 100644 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/variants/SimpleGTR.scala +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/variants/GTR.scala @@ -1,12 +1,12 @@ -package maf.deltaDebugging.gtr.variants +package maf.deltaDebugging.treeDD.variants -import maf.deltaDebugging.gtr.transformations.Transformation +import maf.deltaDebugging.treeDD.transformations.Transformation import maf.core.Expression import maf.language.scheme.SchemeExp import scala.annotation.tailrec -object SimpleGTR: +object GTR: @tailrec def reduce(tree: SchemeExp, oracle: SchemeExp => Boolean, transformations: List[Transformation]): SchemeExp = val reducedTree: SchemeExp = BFT(tree, oracle, transformations) @@ -19,15 +19,14 @@ object SimpleGTR: var reducedTree = tree for (lvl <- 0 to reducedTree.height) for (transformation <- transformations) - reducedTree = reduceLevelNodes(reducedTree, lvl, oracle, transformation, 0) + reducedTree = reduceLevelNodes(reducedTree, lvl, oracle, transformation) reducedTree - private def reduceLevelNodes(tree: SchemeExp, lvl: Int, oracle: SchemeExp => Boolean, transformation: Transformation, dropIdx: Int): SchemeExp = - for((node, nodeIdx) <- tree.levelNodes(lvl).drop(dropIdx).zipWithIndex) - for((candidateTree, candidateIdx) <- transformation.transform(tree, node).zipWithIndex) + private def reduceLevelNodes(tree: SchemeExp, lvl: Int, oracle: SchemeExp => Boolean, transformation: Transformation): SchemeExp = + for(node <- tree.levelNodes(lvl)) + for(candidateTree <- transformation.transform(tree, node)) if candidateTree.size <= tree.size then if oracle(candidateTree) then - transformation.hit(candidateTree, candidateIdx) - return reduceLevelNodes(candidateTree, lvl, oracle, transformation, nodeIdx) + return reduceLevelNodes(candidateTree, lvl, oracle, transformation) tree diff --git a/code/shared/src/main/scala/maf/deltaDebugging/gtr/variants/JumpyGTR.scala b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/variants/JumpyGTR.scala similarity index 86% rename from code/shared/src/main/scala/maf/deltaDebugging/gtr/variants/JumpyGTR.scala rename to code/shared/src/main/scala/maf/deltaDebugging/treeDD/variants/JumpyGTR.scala index 37b658686..fd3f46189 100644 --- a/code/shared/src/main/scala/maf/deltaDebugging/gtr/variants/JumpyGTR.scala +++ b/code/shared/src/main/scala/maf/deltaDebugging/treeDD/variants/JumpyGTR.scala @@ -1,6 +1,6 @@ -package maf.deltaDebugging.gtr.variants +package maf.deltaDebugging.treeDD.variants -import maf.deltaDebugging.gtr.transformations.Transformation +import maf.deltaDebugging.treeDD.transformations.Transformation import maf.core.Expression import maf.language.scheme.SchemeExp @@ -22,6 +22,5 @@ object JumpyGTR: for((candidateTree, candidateIdx) <- transformation.transform(tree, node).zipWithIndex) if candidateTree.size <= tree.size then if oracle(candidateTree) then - transformation.hit(candidateTree, candidateIdx) return candidateTree tree diff --git a/code/shared/src/main/scala/maf/language/scheme/interpreter/CountingSchemeInterpreter.scala b/code/shared/src/main/scala/maf/language/scheme/interpreter/CountingSchemeInterpreter.scala new file mode 100644 index 000000000..55fe210ba --- /dev/null +++ b/code/shared/src/main/scala/maf/language/scheme/interpreter/CountingSchemeInterpreter.scala @@ -0,0 +1,150 @@ +package maf.language.scheme.interpreter + +import maf.core.* +import maf.language.change.CodeVersion.* +import maf.language.scheme.* +import maf.util.* +import maf.util.benchmarks.Timeout + +import java.util.concurrent.TimeUnit +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration.{Duration, SECONDS} +import scala.concurrent.* +import scala.util.control.TailCalls.* + +class CountingSchemeInterpreter(cb: (Identity, ConcreteValues.Value) => Unit = (_, _) => (), + io: IO = new EmptyIO()) extends SchemeInterpreter(cb, io): + import ConcreteValues._ + + import scala.util.control.TailCalls._ + + /** Evaluate with a Bound on Evaluation Steps */ + private var evalSteps: Long = 0 + + def getEvalSteps(): Long = evalSteps + + var maxEvalSteps: Long = Long.MaxValue //the maximum number of eval steps before a TimeoutException + var buffer: Int = 1000 //buffer has to be sufficiently large + + def runWithMaxSteps( + program: SchemeExp, + timeout: Timeout.T, + maxSteps: Long, + version: Version = New + ): Value = + setStore(initialSto) + maxEvalSteps = maxSteps + evalSteps = 0 + eval(program, initialEnv, timeout, version).result + + override def eval( + e: SchemeExp, + env: Env, + timeout: Timeout.T, + version: Version, + ): TailRec[Value] = + if timeout.reached then throw new TimeoutException() + e match + case lambda: SchemeLambdaExp => done(Value.Clo(lambda, env)) + case call@SchemeFuncall(f, args, idn) => + evalSteps += 1 + if (evalSteps - buffer) > maxEvalSteps then + throw new TimeoutException() + for + fv <- tailcall(eval(f, env, timeout, version)) + res <- fv match + case Value.Clo(lambda@SchemeLambda(name, argsNames, body, ann, pos2), env2) => + //calledLambdas = calledLambdas + lambda.hashCode() + if argsNames.length != args.length then + signalException( + ArityError(pos2.pos, argsNames.length, args.length) + ) + for + argsv <- evalArgs(args, env, timeout, version) + envExt = argsNames.zip(argsv).foldLeft(env2) { (env3, arg) => + val addr = newAddr(AddrInfo.VarAddr(arg._1)) + extendStore(addr, arg._2) + (env3 + (arg._1.name -> addr)) + } + res <- tailcall(evalSequence(body, envExt, timeout, version)) + yield res + case Value.Clo(lambda@SchemeVarArgLambda(name, argsNames, vararg, body, ann, pos2), env2) => + val arity = argsNames.length + if args.length < arity then + signalException( + VarArityError(pos2.pos, argsNames.length, args.length) + ) + for + argsv <- evalArgs(args, env, timeout, version) + envExt = argsNames.zip(argsv).foldLeft(env2) { (env3, arg) => + val addr = newAddr(AddrInfo.VarAddr(arg._1)) + extendStore(addr, arg._2) + (env3 + (arg._1.name -> addr)) + } + varArgAddr = newAddr(AddrInfo.VarAddr(vararg)) + _ = extendStore(varArgAddr, makeList(args.drop(arity).zip(argsv.drop(arity)))) + envExt2 = envExt + (vararg.name -> varArgAddr) + res <- evalSequence(body, envExt2, timeout, version) + yield res + case Value.Primitive(p) => + for argsv <- tailcall(evalArgs(args, env, timeout, version)) + yield Primitives.allPrimitives(p).call(call, args.zip(argsv)) + case v => + signalException(ValueNotApplicable(v, idn)) + yield res + case SchemeIf(cond, cons, alt, _) => + for + condv <- eval(cond, env, timeout, version) + res <- condv match + case Value.Bool(false) => tailcall(eval(alt, env, timeout, version)) + case _ => tailcall(eval(cons, env, timeout, version)) + yield res + case SchemeLet(bindings, body, pos) => + tailcall(evalLet(bindings, body, pos, env, env, timeout, version)) + case SchemeLetStar(bindings, body, pos) => + tailcall(evalLetStar(bindings, body, pos, env, env, timeout, version)) + case SchemeLetrec(bindings, body, pos) => + /* First extend the environment with all bindings set to unbound */ + val envExt = bindings.foldLeft(env) { (env2, binding) => + val addr = newAddr(AddrInfo.VarAddr(binding._1)) + env2 + (binding._1.name -> addr) + } + /* Then evaluate all bindings in the extended environment */ + tailcall(evalLetrec(bindings, body, pos, envExt, env, timeout, version)) + case SchemeSet(id, v, pos) => + /* TODO: primitives can be reassigned with set! without being redefined */ + val addr = env.get(id.name) match + case Some(addr) => addr + case None => signalException(UndefinedVariableError(id)) + for + v <- eval(v, env, timeout, version) + _ = extendStore(addr, v) + yield Value.Void + case SchemeBegin(exps, _) => + evalSequence(exps, env, timeout, version) + case SchemeAssert(_, _) => + done(Value.Void) + case SchemeDefineVariable(_, _, _) => ??? + case SchemeVar(id) => + env.get(id.name) match + case None => signalException(UndefinedVariableError(id)) + case Some(addr) => + lookupStoreOption(addr) match + case None => signalException(UninitialisedVariableError(id)) + case Some(v) => done(v) + case SchemeValue(v, _) => + done(evalLiteral(v, e)) + case CSchemeFork(body, _) => + // TODO: This is a bit hacky in terms of tailcalls + done(Value.Thread(safeFuture(eval(body, env, timeout, version).result))) + case CSchemeJoin(tExp, _) => + for + threadv <- eval(tExp, env, timeout, version) + res <- threadv match + case Value.Thread(fut) => + done(Await.result(fut, timeout.timeLeft.map(Duration(_, TimeUnit.NANOSECONDS)).getOrElse(Duration.Inf))) + case v => signalException(TypeError("Join expected thread", v)) + yield res + case SchemeCodeChange(old, nw, _) => + if version == Old then tailcall(eval(old, env, timeout, version)) else tailcall(eval(nw, env, timeout, version)) + case _ => throw new Exception(s"Unsupported Scheme expression: $e") diff --git a/code/shared/src/main/scala/maf/language/scheme/interpreter/DeadCodeInterpreter.scala b/code/shared/src/main/scala/maf/language/scheme/interpreter/DeadCodeInterpreter.scala new file mode 100644 index 000000000..3afb8c4e2 --- /dev/null +++ b/code/shared/src/main/scala/maf/language/scheme/interpreter/DeadCodeInterpreter.scala @@ -0,0 +1,141 @@ +package maf.language.scheme.interpreter + +import maf.core.* +import maf.language.change.CodeVersion.* +import maf.language.scheme.* +import maf.language.scheme.interpreter.ConcreteValues.Value +import maf.util.* +import maf.util.benchmarks.Timeout + +import java.util.concurrent.TimeUnit +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration.{Duration, SECONDS} +import scala.concurrent.* +import scala.util.control.TailCalls.* + +class DeadCodeInterpreter(cb: (Identity, ConcreteValues.Value) => Unit = (_, _) => (), + io: IO = new EmptyIO()) extends SchemeInterpreter(cb, io): + + import ConcreteValues._ + import scala.util.control.TailCalls._ + + private var aliveCode: Set[SchemeExp] = Set() + def runAndIdentifyDeadCode( + program: SchemeExp, + timeout: Timeout.T, + version: Version = New + ): (Value, Set[SchemeExp]) = + aliveCode = Set() + setStore(initialSto) + (eval(program, initialEnv, timeout, version).result, aliveCode) + + override def eval(e: SchemeExp, env: Env, timeout: Timeout.T, version: Version): TailRec[Value] = + if timeout.reached then throw new TimeoutException() + e match + case lambda: SchemeLambdaExp => + case another: _ => aliveCode = aliveCode.+(another) + + e match + case lambda: SchemeLambdaExp => done(Value.Clo(lambda, env)) + case call@SchemeFuncall(f, args, idn) => + for + fv <- tailcall(eval(f, env, timeout, version)) + res <- fv match + case Value.Clo(lambda@SchemeLambda(name, argsNames, body, ann, pos2), env2) => + aliveCode = aliveCode.+(lambda) + if argsNames.length != args.length then + signalException( + ArityError(pos2.pos, argsNames.length, args.length) + ) + for + argsv <- evalArgs(args, env, timeout, version) + envExt = argsNames.zip(argsv).foldLeft(env2) { (env3, arg) => + val addr = newAddr(AddrInfo.VarAddr(arg._1)) + extendStore(addr, arg._2) + (env3 + (arg._1.name -> addr)) + } + res <- tailcall(evalSequence(body, envExt, timeout, version)) + yield res + case Value.Clo(lambda@SchemeVarArgLambda(name, argsNames, vararg, body, ann, pos2), env2) => + aliveCode = aliveCode.+(lambda) + val arity = argsNames.length + if args.length < arity then + signalException( + VarArityError(pos2.pos, argsNames.length, args.length) + ) + for + argsv <- evalArgs(args, env, timeout, version) + envExt = argsNames.zip(argsv).foldLeft(env2) { (env3, arg) => + val addr = newAddr(AddrInfo.VarAddr(arg._1)) + extendStore(addr, arg._2) + (env3 + (arg._1.name -> addr)) + } + varArgAddr = newAddr(AddrInfo.VarAddr(vararg)) + _ = extendStore(varArgAddr, makeList(args.drop(arity).zip(argsv.drop(arity)))) + envExt2 = envExt + (vararg.name -> varArgAddr) + res <- evalSequence(body, envExt2, timeout, version) + yield res + case Value.Primitive(p) => + for argsv <- tailcall(evalArgs(args, env, timeout, version)) + yield Primitives.allPrimitives(p).call(call, args.zip(argsv)) + case v => + signalException(ValueNotApplicable(v, idn)) + yield { + res + } + case SchemeIf(cond, cons, alt, _) => + for + condv <- eval(cond, env, timeout, version) + res <- condv match + case Value.Bool(false) => tailcall(eval(alt, env, timeout, version)) + case _ => tailcall(eval(cons, env, timeout, version)) + yield res + case SchemeLet(bindings, body, pos) => + tailcall(evalLet(bindings, body, pos, env, env, timeout, version)) + case SchemeLetStar(bindings, body, pos) => + tailcall(evalLetStar(bindings, body, pos, env, env, timeout, version)) + case SchemeLetrec(bindings, body, pos) => + /* First extend the environment with all bindings set to unbound */ + val envExt = bindings.foldLeft(env) { (env2, binding) => + val addr = newAddr(AddrInfo.VarAddr(binding._1)) + env2 + (binding._1.name -> addr) + } + /* Then evaluate all bindings in the extended environment */ + tailcall(evalLetrec(bindings, body, pos, envExt, env, timeout, version)) + case SchemeSet(id, v, pos) => + /* TODO: primitives can be reassigned with set! without being redefined */ + val addr = env.get(id.name) match + case Some(addr) => addr + case None => signalException(UndefinedVariableError(id)) + for + v <- eval(v, env, timeout, version) + _ = extendStore(addr, v) + yield Value.Void + case SchemeBegin(exps, _) => + evalSequence(exps, env, timeout, version) + case SchemeAssert(_, _) => + done(Value.Void) + case SchemeDefineVariable(_, _, _) => ??? + case SchemeVar(id) => + env.get(id.name) match + case None => signalException(UndefinedVariableError(id)) + case Some(addr) => + lookupStoreOption(addr) match + case None => signalException(UninitialisedVariableError(id)) + case Some(v) => done(v) + case SchemeValue(v, _) => + done(evalLiteral(v, e)) + case CSchemeFork(body, _) => + // TODO: This is a bit hacky in terms of tailcalls + done(Value.Thread(safeFuture(eval(body, env, timeout, version).result))) + case CSchemeJoin(tExp, _) => + for + threadv <- eval(tExp, env, timeout, version) + res <- threadv match + case Value.Thread(fut) => + done(Await.result(fut, timeout.timeLeft.map(Duration(_, TimeUnit.NANOSECONDS)).getOrElse(Duration.Inf))) + case v => signalException(TypeError("Join expected thread", v)) + yield res + case SchemeCodeChange(old, nw, _) => + if version == Old then tailcall(eval(old, env, timeout, version)) else tailcall(eval(nw, env, timeout, version)) + case _ => throw new Exception(s"Unsupported Scheme expression: $e") \ No newline at end of file diff --git a/code/shared/src/main/scala/maf/language/scheme/interpreter/KillLambdaInterpreter.scala b/code/shared/src/main/scala/maf/language/scheme/interpreter/KillLambdaInterpreter.scala new file mode 100644 index 000000000..8bce1a3ed --- /dev/null +++ b/code/shared/src/main/scala/maf/language/scheme/interpreter/KillLambdaInterpreter.scala @@ -0,0 +1,145 @@ +package maf.language.scheme.interpreter + +import maf.core.* +import maf.language.change.CodeVersion.* +import maf.language.scheme.* +import maf.language.scheme.interpreter.ConcreteValues.Value +import maf.util.* +import maf.util.benchmarks.Timeout + +import java.util.concurrent.TimeUnit +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration.{Duration, SECONDS} +import scala.concurrent.* +import scala.util.control.TailCalls.* + +class KillLambdaInterpreter(cb: (Identity, ConcreteValues.Value) => Unit = (_, _) => (), + io: IO = new EmptyIO()) extends SchemeInterpreter(cb, io): + + import ConcreteValues._ + import scala.util.control.TailCalls._ + + private var calls: Map[SchemeLambda, (Set[(SchemeFuncall, ConcreteValues.Value)], Int)] = Map() + def runAndIdentifyCalledLambdas( + program: SchemeExp, + timeout: Timeout.T, + version: Version = New + ): (Value, Map[SchemeLambda, (Set[(SchemeFuncall, ConcreteValues.Value)], Int)]) = + calls = Map() + setStore(initialSto) + (eval(program, initialEnv, timeout, version).result, calls) + + + override def eval(e: SchemeExp, env: Env, timeout: Timeout.T, version: Version): TailRec[Value] = + if timeout.reached then throw new TimeoutException() + var caughtLambda: Option[SchemeLambda] = None + e match + case lambda: SchemeLambdaExp => done(Value.Clo(lambda, env)) + case call@SchemeFuncall(f, args, idn) => + for + fv <- tailcall(eval(f, env, timeout, version)) + res <- fv match + case Value.Clo(lambda@SchemeLambda(name, argsNames, body, ann, pos2), env2) => + caughtLambda = Some(lambda) + if argsNames.length != args.length then + signalException( + ArityError(pos2.pos, argsNames.length, args.length) + ) + for + argsv <- evalArgs(args, env, timeout, version) + envExt = argsNames.zip(argsv).foldLeft(env2) { (env3, arg) => + val addr = newAddr(AddrInfo.VarAddr(arg._1)) + extendStore(addr, arg._2) + (env3 + (arg._1.name -> addr)) + } + res <- tailcall(evalSequence(body, envExt, timeout, version)) + yield res + case Value.Clo(lambda@SchemeVarArgLambda(name, argsNames, vararg, body, ann, pos2), env2) => + val arity = argsNames.length + if args.length < arity then + signalException( + VarArityError(pos2.pos, argsNames.length, args.length) + ) + for + argsv <- evalArgs(args, env, timeout, version) + envExt = argsNames.zip(argsv).foldLeft(env2) { (env3, arg) => + val addr = newAddr(AddrInfo.VarAddr(arg._1)) + extendStore(addr, arg._2) + (env3 + (arg._1.name -> addr)) + } + varArgAddr = newAddr(AddrInfo.VarAddr(vararg)) + _ = extendStore(varArgAddr, makeList(args.drop(arity).zip(argsv.drop(arity)))) + envExt2 = envExt + (vararg.name -> varArgAddr) + res <- evalSequence(body, envExt2, timeout, version) + yield res + case Value.Primitive(p) => + for argsv <- tailcall(evalArgs(args, env, timeout, version)) + yield Primitives.allPrimitives(p).call(call, args.zip(argsv)) + case v => + signalException(ValueNotApplicable(v, idn)) + yield { + caughtLambda match + case Some(lambda) => + calls = calls + (lambda -> { + val prev = calls.getOrElse(lambda, (Set(), 0)) + (prev._1.union(Set((call, res))), prev._2 + 1) + }) + case _ => + res + } + case SchemeIf(cond, cons, alt, _) => + for + condv <- eval(cond, env, timeout, version) + res <- condv match + case Value.Bool(false) => tailcall(eval(alt, env, timeout, version)) + case _ => tailcall(eval(cons, env, timeout, version)) + yield res + case SchemeLet(bindings, body, pos) => + tailcall(evalLet(bindings, body, pos, env, env, timeout, version)) + case SchemeLetStar(bindings, body, pos) => + tailcall(evalLetStar(bindings, body, pos, env, env, timeout, version)) + case SchemeLetrec(bindings, body, pos) => + /* First extend the environment with all bindings set to unbound */ + val envExt = bindings.foldLeft(env) { (env2, binding) => + val addr = newAddr(AddrInfo.VarAddr(binding._1)) + env2 + (binding._1.name -> addr) + } + /* Then evaluate all bindings in the extended environment */ + tailcall(evalLetrec(bindings, body, pos, envExt, env, timeout, version)) + case SchemeSet(id, v, pos) => + /* TODO: primitives can be reassigned with set! without being redefined */ + val addr = env.get(id.name) match + case Some(addr) => addr + case None => signalException(UndefinedVariableError(id)) + for + v <- eval(v, env, timeout, version) + _ = extendStore(addr, v) + yield Value.Void + case SchemeBegin(exps, _) => + evalSequence(exps, env, timeout, version) + case SchemeAssert(_, _) => + done(Value.Void) + case SchemeDefineVariable(_, _, _) => ??? + case SchemeVar(id) => + env.get(id.name) match + case None => signalException(UndefinedVariableError(id)) + case Some(addr) => + lookupStoreOption(addr) match + case None => signalException(UninitialisedVariableError(id)) + case Some(v) => done(v) + case SchemeValue(v, _) => + done(evalLiteral(v, e)) + case CSchemeFork(body, _) => + // TODO: This is a bit hacky in terms of tailcalls + done(Value.Thread(safeFuture(eval(body, env, timeout, version).result))) + case CSchemeJoin(tExp, _) => + for + threadv <- eval(tExp, env, timeout, version) + res <- threadv match + case Value.Thread(fut) => + done(Await.result(fut, timeout.timeLeft.map(Duration(_, TimeUnit.NANOSECONDS)).getOrElse(Duration.Inf))) + case v => signalException(TypeError("Join expected thread", v)) + yield res + case SchemeCodeChange(old, nw, _) => + if version == Old then tailcall(eval(old, env, timeout, version)) else tailcall(eval(nw, env, timeout, version)) + case _ => throw new Exception(s"Unsupported Scheme expression: $e") diff --git a/code/shared/src/main/scala/maf/language/scheme/interpreter/PreHaltInterpreter.scala b/code/shared/src/main/scala/maf/language/scheme/interpreter/PreHaltInterpreter.scala new file mode 100644 index 000000000..eeeea4463 --- /dev/null +++ b/code/shared/src/main/scala/maf/language/scheme/interpreter/PreHaltInterpreter.scala @@ -0,0 +1,42 @@ +package maf.language.scheme.interpreter + +import maf.core.* +import maf.language.change.CodeVersion.* +import maf.language.scheme.* +import maf.language.scheme.interpreter.ConcreteValues.Value +import maf.util.* +import maf.util.benchmarks.Timeout + +import java.util.concurrent.TimeUnit +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration.{Duration, SECONDS} +import scala.concurrent.* +import scala.util.control.TailCalls.* + +class PreHaltInterpreter(cb: (Identity, ConcreteValues.Value) => Unit = (_, _) => (), + io: IO = new EmptyIO(), + problematicValue: ConcreteValues.Value, + soundnessTest: () => Boolean + ) extends SchemeInterpreter(cb, io): + + import ConcreteValues._ + import scala.util.control.TailCalls._ + + override def run(program: SchemeExp, timeout: Timeout.T, version: Version = New): Value = + try + setStore(initialSto) + eval(program, initialEnv, timeout, version).result + catch + case e: InterruptedException => + Value.Integer(1) + + override def extendStore(a: Addr, v: Value): Unit = + if checkAddr(a) && checkValue(v) then Callback.call(a._2.idn, v) + if v equals problematicValue then + if soundnessTest() then + throw InterruptedException() + super.extendStore(a, v) + + + + diff --git a/code/shared/src/main/scala/maf/language/scheme/interpreter/SDCE_Interpreter.scala b/code/shared/src/main/scala/maf/language/scheme/interpreter/SDCE_Interpreter.scala new file mode 100644 index 000000000..8878c4348 --- /dev/null +++ b/code/shared/src/main/scala/maf/language/scheme/interpreter/SDCE_Interpreter.scala @@ -0,0 +1,143 @@ +package maf.language.scheme.interpreter + +import maf.core.* +import maf.language.change.CodeVersion.* +import maf.language.scheme.* +import maf.language.scheme.interpreter.ConcreteValues.Value +import maf.util.* +import maf.util.benchmarks.Timeout + +import java.util.concurrent.TimeUnit +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration.{Duration, SECONDS} +import scala.concurrent.* +import scala.util.control.TailCalls.* + +class SDCE_Interpreter(cb: (Identity, ConcreteValues.Value) => Unit = (_, _) => (), + io: IO = new EmptyIO(), + problematicValue: ConcreteValues.Value, + soundnessTest: () => Boolean + ) extends PreHaltInterpreter(cb, io, problematicValue, soundnessTest): + import ConcreteValues._ + import scala.util.control.TailCalls._ + + private var aliveCode: Set[SchemeExp] = Set() + + def runAndIdentifyDeadCode( + program: SchemeExp, + timeout: Timeout.T, + version: Version = New + ): (Value, Set[SchemeExp]) = + aliveCode = Set() + (super.run(program, timeout, version), aliveCode) + + override def eval(e: SchemeExp, env: Env, timeout: Timeout.T, version: Version): TailRec[Value] = + if timeout.reached then throw new TimeoutException() + e match + case lambda: SchemeLambdaExp => + case another: _ => aliveCode = aliveCode.+(another) + + e match + case lambda: SchemeLambdaExp => done(Value.Clo(lambda, env)) + case call@SchemeFuncall(f, args, idn) => + for + fv <- tailcall(eval(f, env, timeout, version)) + res <- fv match + case Value.Clo(lambda@SchemeLambda(name, argsNames, body, ann, pos2), env2) => + aliveCode = aliveCode.+(lambda) + if argsNames.length != args.length then + signalException( + ArityError(pos2.pos, argsNames.length, args.length) + ) + for + argsv <- evalArgs(args, env, timeout, version) + envExt = argsNames.zip(argsv).foldLeft(env2) { (env3, arg) => + val addr = newAddr(AddrInfo.VarAddr(arg._1)) + extendStore(addr, arg._2) + (env3 + (arg._1.name -> addr)) + } + res <- tailcall(evalSequence(body, envExt, timeout, version)) + yield res + case Value.Clo(lambda@SchemeVarArgLambda(name, argsNames, vararg, body, ann, pos2), env2) => + aliveCode = aliveCode.+(lambda) + val arity = argsNames.length + if args.length < arity then + signalException( + VarArityError(pos2.pos, argsNames.length, args.length) + ) + for + argsv <- evalArgs(args, env, timeout, version) + envExt = argsNames.zip(argsv).foldLeft(env2) { (env3, arg) => + val addr = newAddr(AddrInfo.VarAddr(arg._1)) + extendStore(addr, arg._2) + (env3 + (arg._1.name -> addr)) + } + varArgAddr = newAddr(AddrInfo.VarAddr(vararg)) + _ = extendStore(varArgAddr, makeList(args.drop(arity).zip(argsv.drop(arity)))) + envExt2 = envExt + (vararg.name -> varArgAddr) + res <- evalSequence(body, envExt2, timeout, version) + yield res + case Value.Primitive(p) => + for argsv <- tailcall(evalArgs(args, env, timeout, version)) + yield Primitives.allPrimitives(p).call(call, args.zip(argsv)) + case v => + signalException(ValueNotApplicable(v, idn)) + yield { + res + } + case SchemeIf(cond, cons, alt, _) => + for + condv <- eval(cond, env, timeout, version) + res <- condv match + case Value.Bool(false) => tailcall(eval(alt, env, timeout, version)) + case _ => tailcall(eval(cons, env, timeout, version)) + yield res + case SchemeLet(bindings, body, pos) => + tailcall(evalLet(bindings, body, pos, env, env, timeout, version)) + case SchemeLetStar(bindings, body, pos) => + tailcall(evalLetStar(bindings, body, pos, env, env, timeout, version)) + case SchemeLetrec(bindings, body, pos) => + /* First extend the environment with all bindings set to unbound */ + val envExt = bindings.foldLeft(env) { (env2, binding) => + val addr = newAddr(AddrInfo.VarAddr(binding._1)) + env2 + (binding._1.name -> addr) + } + /* Then evaluate all bindings in the extended environment */ + tailcall(evalLetrec(bindings, body, pos, envExt, env, timeout, version)) + case SchemeSet(id, v, pos) => + /* TODO: primitives can be reassigned with set! without being redefined */ + val addr = env.get(id.name) match + case Some(addr) => addr + case None => signalException(UndefinedVariableError(id)) + for + v <- eval(v, env, timeout, version) + _ = extendStore(addr, v) + yield Value.Void + case SchemeBegin(exps, _) => + evalSequence(exps, env, timeout, version) + case SchemeAssert(_, _) => + done(Value.Void) + case SchemeDefineVariable(_, _, _) => ??? + case SchemeVar(id) => + env.get(id.name) match + case None => signalException(UndefinedVariableError(id)) + case Some(addr) => + lookupStoreOption(addr) match + case None => signalException(UninitialisedVariableError(id)) + case Some(v) => done(v) + case SchemeValue(v, _) => + done(evalLiteral(v, e)) + case CSchemeFork(body, _) => + // TODO: This is a bit hacky in terms of tailcalls + done(Value.Thread(safeFuture(eval(body, env, timeout, version).result))) + case CSchemeJoin(tExp, _) => + for + threadv <- eval(tExp, env, timeout, version) + res <- threadv match + case Value.Thread(fut) => + done(Await.result(fut, timeout.timeLeft.map(Duration(_, TimeUnit.NANOSECONDS)).getOrElse(Duration.Inf))) + case v => signalException(TypeError("Join expected thread", v)) + yield res + case SchemeCodeChange(old, nw, _) => + if version == Old then tailcall(eval(old, env, timeout, version)) else tailcall(eval(nw, env, timeout, version)) + case _ => throw new Exception(s"Unsupported Scheme expression: $e") \ No newline at end of file diff --git a/code/shared/src/main/scala/maf/language/scheme/interpreter/SchemeInterpreter.scala b/code/shared/src/main/scala/maf/language/scheme/interpreter/SchemeInterpreter.scala index dd624d410..8eb62e0e8 100644 --- a/code/shared/src/main/scala/maf/language/scheme/interpreter/SchemeInterpreter.scala +++ b/code/shared/src/main/scala/maf/language/scheme/interpreter/SchemeInterpreter.scala @@ -22,7 +22,8 @@ case class UnexpectedValueTypeException[V](v: V) extends Exception(s"The interpr */ class SchemeInterpreter( cb: (Identity, ConcreteValues.Value) => Unit = (_, _) => (), - val io: IO = new EmptyIO()) + val io: IO = new EmptyIO() + ) extends BaseSchemeInterpreter[TailRec[ConcreteValues.Value]] with ConcreteSchemePrimitives: @@ -125,14 +126,14 @@ class SchemeInterpreter( yield res //determines whether a given value should be checked or not - private def checkValue(v: Value): Boolean = v match + protected def checkValue(v: Value): Boolean = v match case Value.Undefined(_) => //println(s"Undefined behavior arising from identity $idn seen at ${e.idn.pos}") false case _ => true - private def checkAddr(a: Addr): Boolean = a._2 match + protected def checkAddr(a: Addr): Boolean = a._2 match case _: AddrInfo.VarAddr | _: AddrInfo.PtrAddr => true case _ => false @@ -208,6 +209,8 @@ class SchemeInterpreter( case v => signalException(ValueNotApplicable(v, idn)) + /** Evaluate with a Bound on Evaluation Steps */ + /* private var evalSteps: Long = 0 def getEvalSteps(): Long = evalSteps var maxEvalSteps: Long = Long.MaxValue //the maximum number of eval steps before a TimeoutException @@ -220,7 +223,23 @@ class SchemeInterpreter( ): Value = setStore(initialSto) maxEvalSteps = maxSteps + evalSteps = 0 eval(program, initialEnv, Timeout.start(Duration(5, SECONDS)), version).result + */ + + /** Evaluate and identify the lambdas which have been called */ + /* + private var calledLambdas: Set[Int] = Set() + def runAndIdentifyCalledLambdas( + program: SchemeExp, + maxSteps: Long, + version: Version = New + ): (Value, Set[Int]) = + calledLambdas = Set() + + setStore(initialSto) + (eval(program, initialEnv, Timeout.start(Duration(5, SECONDS)), version).result, calledLambdas) + */ def eval( e: SchemeExp, @@ -228,8 +247,11 @@ class SchemeInterpreter( timeout: Timeout.T, version: Version, ): TailRec[Value] = + /* evalSteps += 1 - if (evalSteps - buffer) > maxEvalSteps then throw new TimeoutException() + if (evalSteps - buffer) > maxEvalSteps then + throw new TimeoutException() + */ if timeout.reached then throw new TimeoutException() e match case lambda: SchemeLambdaExp => done(Value.Clo(lambda, env)) @@ -238,8 +260,8 @@ class SchemeInterpreter( fv <- tailcall(eval(f, env, timeout, version)) res <- fv match case Value.Clo(lambda @ SchemeLambda(name, argsNames, body, ann, pos2), env2) => + //calledLambdas = calledLambdas + lambda.hashCode() if argsNames.length != args.length then - signalException( ArityError(pos2.pos, argsNames.length, args.length) ) diff --git a/code/shared/src/main/scala/maf/language/scheme/interpreter/SmartReplaceInterpreter.scala b/code/shared/src/main/scala/maf/language/scheme/interpreter/SmartReplaceInterpreter.scala new file mode 100644 index 000000000..10c539e37 --- /dev/null +++ b/code/shared/src/main/scala/maf/language/scheme/interpreter/SmartReplaceInterpreter.scala @@ -0,0 +1,157 @@ +package maf.language.scheme.interpreter + +import maf.core.* +import maf.language.change.CodeVersion.* +import maf.language.scheme.* +import maf.util.* +import maf.util.benchmarks.Timeout + +import java.util.concurrent.TimeUnit +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration.{Duration, SECONDS} +import scala.concurrent.* +import scala.util.control.TailCalls.* + +class SmartReplaceInterpreter(cb: (Identity, ConcreteValues.Value) => Unit = (_, _) => (), + io: IO = new EmptyIO()) extends SchemeInterpreter(cb, io): + import ConcreteValues._ + import scala.util.control.TailCalls._ + + private var dynAnalysis: Map[SchemeExp, Set[Value]] = Map() + + def runAndProfile(program: SchemeExp, + timeout: Timeout.T, + version: Version = New): (Value, Map[SchemeExp, Set[Value]]) = + setStore(initialSto) + dynAnalysis = Map() + (eval(program, initialEnv, timeout, version).result, dynAnalysis) + + + override def eval( + e: SchemeExp, + env: Env, + timeout: Timeout.T, + version: Version, + ): TailRec[Value] = + /* + evalSteps += 1 + if (evalSteps - buffer) > maxEvalSteps then + throw new TimeoutException() + */ + if timeout.reached then throw new TimeoutException() + e match + case lambda: SchemeLambdaExp => + done(Value.Clo(lambda, env)) + case call@SchemeFuncall(f, args, idn) => + for + fv <- tailcall(eval(f, env, timeout, version)) + res <- fv match + case Value.Clo(lambda@SchemeLambda(name, argsNames, body, ann, pos2), env2) => + //calledLambdas = calledLambdas + lambda.hashCode() + if argsNames.length != args.length then + signalException( + ArityError(pos2.pos, argsNames.length, args.length) + ) + for + argsv <- evalArgs(args, env, timeout, version) + envExt = argsNames.zip(argsv).foldLeft(env2) { (env3, arg) => + val addr = newAddr(AddrInfo.VarAddr(arg._1)) + extendStore(addr, arg._2) + (env3 + (arg._1.name -> addr)) + } + res <- tailcall(evalSequence(body, envExt, timeout, version)) + yield res + case Value.Clo(lambda@SchemeVarArgLambda(name, argsNames, vararg, body, ann, pos2), env2) => + val arity = argsNames.length + if args.length < arity then + signalException( + VarArityError(pos2.pos, argsNames.length, args.length) + ) + for + argsv <- evalArgs(args, env, timeout, version) + envExt = argsNames.zip(argsv).foldLeft(env2) { (env3, arg) => + val addr = newAddr(AddrInfo.VarAddr(arg._1)) + extendStore(addr, arg._2) + (env3 + (arg._1.name -> addr)) + } + varArgAddr = newAddr(AddrInfo.VarAddr(vararg)) + _ = extendStore(varArgAddr, makeList(args.drop(arity).zip(argsv.drop(arity)))) + envExt2 = envExt + (vararg.name -> varArgAddr) + res <- evalSequence(body, envExt2, timeout, version) + yield { + res + } + case Value.Primitive(p) => + for argsv <- tailcall(evalArgs(args, env, timeout, version)) + yield { + Primitives.allPrimitives(p).call(call, args.zip(argsv)) + } + case v => + signalException(ValueNotApplicable(v, idn)) + yield { + dynAnalysis = dynAnalysis + (e -> (dynAnalysis.getOrElse(e, Set()) + res)) + res + } + case SchemeIf(cond, cons, alt, _) => + for + condv <- eval(cond, env, timeout, version) + res <- condv match + case Value.Bool(false) => { + tailcall(eval(alt, env, timeout, version)) + } + case _ => tailcall(eval(cons, env, timeout, version)) + yield { + res + } + case SchemeLet(bindings, body, pos) => + tailcall(evalLet(bindings, body, pos, env, env, timeout, version)) + case SchemeLetStar(bindings, body, pos) => + tailcall(evalLetStar(bindings, body, pos, env, env, timeout, version)) + case SchemeLetrec(bindings, body, pos) => + /* First extend the environment with all bindings set to unbound */ + val envExt = bindings.foldLeft(env) { (env2, binding) => + val addr = newAddr(AddrInfo.VarAddr(binding._1)) + env2 + (binding._1.name -> addr) + } + /* Then evaluate all bindings in the extended environment */ + tailcall(evalLetrec(bindings, body, pos, envExt, env, timeout, version)) + case SchemeSet(id, v, pos) => + /* TODO: primitives can be reassigned with set! without being redefined */ + val addr = env.get(id.name) match + case Some(addr) => addr + case None => signalException(UndefinedVariableError(id)) + for + v <- eval(v, env, timeout, version) + _ = extendStore(addr, v) + yield Value.Void + case SchemeBegin(exps, _) => + evalSequence(exps, env, timeout, version) + case SchemeAssert(_, _) => + done(Value.Void) + case SchemeDefineVariable(_, _, _) => ??? + case varExp@SchemeVar(id) => + env.get(id.name) match + case None => signalException(UndefinedVariableError(id)) + case Some(addr) => + lookupStoreOption(addr) match + case None => signalException(UninitialisedVariableError(id)) + case Some(v) => { + dynAnalysis = dynAnalysis + (varExp -> (dynAnalysis.getOrElse(varExp, Set()) + v)) + done(v) + } + case SchemeValue(v, _) => + done(evalLiteral(v, e)) + case CSchemeFork(body, _) => + // TODO: This is a bit hacky in terms of tailcalls + done(Value.Thread(safeFuture(eval(body, env, timeout, version).result))) + case CSchemeJoin(tExp, _) => + for + threadv <- eval(tExp, env, timeout, version) + res <- threadv match + case Value.Thread(fut) => + done(Await.result(fut, timeout.timeLeft.map(Duration(_, TimeUnit.NANOSECONDS)).getOrElse(Duration.Inf))) + case v => signalException(TypeError("Join expected thread", v)) + yield res + case SchemeCodeChange(old, nw, _) => + if version == Old then tailcall(eval(old, env, timeout, version)) else tailcall(eval(nw, env, timeout, version)) + case _ => throw new Exception(s"Unsupported Scheme expression: $e") \ No newline at end of file diff --git a/code/shared/src/main/scala/maf/modular/worklist/SequentialWorklistAlgorithm.scala b/code/shared/src/main/scala/maf/modular/worklist/SequentialWorklistAlgorithm.scala index 0e8f1d68c..752cc60e6 100644 --- a/code/shared/src/main/scala/maf/modular/worklist/SequentialWorklistAlgorithm.scala +++ b/code/shared/src/main/scala/maf/modular/worklist/SequentialWorklistAlgorithm.scala @@ -14,16 +14,19 @@ trait SequentialWorklistAlgorithm[Expr <: Expression] extends ModAnalysis[Expr]: // adding elements to the worklist var workList: WorkList[Component] = emptyWorkList.add(initialComponent) protected var reAnalysisMap: Map[Component, Int] = Map() - def getReAnalysisMap(): Map[String, Int] = + def getReAnalysisMap(): Map[(Int, Int), Int] = val array: Array[(String, Array[(Component, Int)])] = reAnalysisMap.toArray.groupBy(tpl => tpl._1.toString.split(" ").asInstanceOf[Array[String]].head).toArray var stringsAndNumbers: Map[String, Int] = array.map(tpl => (tpl._1, tpl._2.map(_._2).sum)).toMap stringsAndNumbers = stringsAndNumbers.filterNot(tpl => tpl._1 equals "main") stringsAndNumbers.map(tpl => { + val splitted: Array[String] = tpl._1.split(":").asInstanceOf[Array[String]] + val row = splitted(splitted.length - 2).toInt + val col = splitted.last.toInt val string = tpl._1 val parsed: Array[String] = string.split(Array('@')) val name = parsed.head - (name, tpl._2) + ((row, col), tpl._2) }) def addToWorkList(cmp: Component) = workList = workList.add(cmp) def finished: Boolean = workList.isEmpty diff --git a/code/shared/src/test/scala/maf/test/SchemeBenchmarks.scala b/code/shared/src/test/scala/maf/test/SchemeBenchmarks.scala index 648ea49f0..375fee0d1 100644 --- a/code/shared/src/test/scala/maf/test/SchemeBenchmarks.scala +++ b/code/shared/src/test/scala/maf/test/SchemeBenchmarks.scala @@ -6,8 +6,11 @@ import maf.util.datastructures.SmartUnion trait VariousSequentialBenchmarks extends SchemeBenchmarkTests: override def benchmarks: Set[Benchmark] = SmartUnion.sunion(super.benchmarks, SchemeBenchmarkPrograms.various) -trait CertainVariousSequentialBenchmarks extends SchemeBenchmarkTests: - override def benchmarks: Set[Benchmark] = SmartUnion.sunion(super.benchmarks, SchemeBenchmarkPrograms.certainVarious) +trait DDBenchmarks extends SchemeBenchmarkTests: + override def benchmarks: Set[Benchmark] = SmartUnion.sunion(super.benchmarks, SchemeBenchmarkPrograms.ddSet) + +trait SuccesRateBenchmarks extends SchemeBenchmarkTests: + override def benchmarks: Set[Benchmark] = SmartUnion.sunion(super.benchmarks, SchemeBenchmarkPrograms.succesRateSet) trait RandomSequentialBenchmarks extends SchemeBenchmarkTests: override def benchmarks: Set[Benchmark] = SmartUnion.sunion(super.benchmarks, SchemeBenchmarkPrograms.selectRandomSeq(3)) diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/JumpyGTRTest.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/JumpyGTRTest.scala index 3cafcc81f..b16496d00 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/JumpyGTRTest.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/JumpyGTRTest.scala @@ -1,8 +1,8 @@ package maf.test.deltaDebugging.gtr -import maf.deltaDebugging.gtr.transformations.* -import maf.deltaDebugging.gtr.transformations.generics.{DeleteChildSimple, ReplaceByChild} -import maf.deltaDebugging.gtr.variants.JumpyGTR +import maf.deltaDebugging.treeDD.transformations.* +import maf.deltaDebugging.treeDD.transformations.generics.{DeleteChildSimple, ReplaceByChild} +import maf.deltaDebugging.treeDD.variants.JumpyGTR import maf.language.scheme.{SchemeBegin, SchemeParser} import org.scalatest.flatspec.AnyFlatSpec diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/GTRTest.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/SchemeReduceTest.scala similarity index 82% rename from code/shared/src/test/scala/maf/test/deltaDebugging/gtr/GTRTest.scala rename to code/shared/src/test/scala/maf/test/deltaDebugging/gtr/SchemeReduceTest.scala index 3cc9ad6ec..b745a46e5 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/GTRTest.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/SchemeReduceTest.scala @@ -1,13 +1,13 @@ package maf.test.deltaDebugging.gtr import maf.core.NoCodeIdentity -import maf.deltaDebugging.gtr.GTR -import maf.deltaDebugging.gtr.transformations.* -import maf.deltaDebugging.gtr.transformations.generics.{DeleteChildSimple, ReplaceByChild} +import maf.deltaDebugging.treeDD.SchemeReduce +import maf.deltaDebugging.treeDD.transformations.* +import maf.deltaDebugging.treeDD.transformations.generics.{DeleteChildSimple, ReplaceByChild} import maf.language.scheme.{SchemeBegin, SchemeCodeChange, SchemeExp, SchemeParser} import org.scalatest.flatspec.AnyFlatSpec -class GTRTest extends AnyFlatSpec { +class SchemeReduceTest extends AnyFlatSpec { "GTR" should "be able to reduce a program" in { val programText: String = "(begin " + @@ -16,7 +16,7 @@ class GTRTest extends AnyFlatSpec { val t = SchemeParser.parseProgramText(programText).last - val reduced = GTR.reduce(t, + val reduced = SchemeReduce.reduce(t, t => t.isInstanceOf[SchemeBegin] && t.asInstanceOf[SchemeBegin].exps.length == 1, identity, List(ReplaceByChild, DeleteChildSimple)) @@ -45,7 +45,7 @@ class GTRTest extends AnyFlatSpec { oldExp, newExp, NoCodeIdentity ) - val reducedChange: SchemeExp = GTR.reduce( + val reducedChange: SchemeExp = SchemeReduce.reduce( change, e => { e match diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/LetIdentifierDeepDropTest.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/BindingDropTest.scala similarity index 78% rename from code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/LetIdentifierDeepDropTest.scala rename to code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/BindingDropTest.scala index 9af0f17c4..f5acfdc05 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/LetIdentifierDeepDropTest.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/BindingDropTest.scala @@ -1,9 +1,9 @@ package maf.test.deltaDebugging.gtr.transformations -import maf.deltaDebugging.gtr.transformations.schemeLet.LetIdentifierDeepDrop +import maf.deltaDebugging.treeDD.transformations.schemeBinding.BindingDrop import maf.language.scheme.{SchemeBegin, SchemeParser} -class LetIdentifierDeepDropTest extends AnyFlatSpecTransformations { +class BindingDropTest extends AnyFlatSpecTransformations { "LetIdentifierDeepDrop" should "deep drop a lets identifier" in { val programText = """(begin @@ -17,7 +17,7 @@ class LetIdentifierDeepDropTest extends AnyFlatSpecTransformations { val t: SchemeBegin = SchemeParser.parseProgramText(programText).last.asInstanceOf[SchemeBegin] val letExp = t.exps(1) - val suggestedTrees = LetIdentifierDeepDrop.transform(t, letExp).toList + val suggestedTrees = BindingDrop.transform(t, letExp).toList assertTreeString("(begin (+ 2 2) (let ((a 10)) (+ a) (if #t a 99)))", suggestedTrees) @@ -35,7 +35,7 @@ class LetIdentifierDeepDropTest extends AnyFlatSpecTransformations { val t: SchemeBegin = SchemeParser.parseProgramText(programText).last.asInstanceOf[SchemeBegin] val lambdaExp = t.exps(1) - val suggestedTrees = LetIdentifierDeepDrop.transform(t, lambdaExp).toList + val suggestedTrees = BindingDrop.transform(t, lambdaExp).toList assert(suggestedTrees equals List()) } diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/BindingReplaceTest.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/BindingReplaceTest.scala new file mode 100644 index 000000000..3eeeae0b5 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/BindingReplaceTest.scala @@ -0,0 +1,26 @@ +package maf.test.deltaDebugging.gtr.transformations + +import maf.deltaDebugging.treeDD.transformations.schemeBinding.{BindingDrop, BindingReplace} +import maf.language.scheme.{SchemeBegin, SchemeParser} + +class BindingReplaceTest extends AnyFlatSpecTransformations { + "LetIdentifierReplace" should "replace a lets identifier" in { + val programText = + """(begin + | (+ 2 2) + | (let ((a 10) + | (b 100)) + | b + | (+ b a) + | (if #t a 99)))""".stripMargin + + val t: SchemeBegin = SchemeParser.parseProgramText(programText).last.asInstanceOf[SchemeBegin] + val letExp = t.exps(1) + + val suggestedTrees = BindingReplace.transform(t, letExp).toList + + assertTreeString("(begin (+ 2 2) (let ((a 10)) () (+ () a) (if #t a 99)))", suggestedTrees) + + assertTreeString("(begin (+ 2 2) (let ((a 10)) #f (+ #f a) (if #t a 99)))", suggestedTrees) + } +} diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/DeleteChildSimpleTest.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/DeleteChildSimpleTest.scala index 80143ea84..d8ce2d9ab 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/DeleteChildSimpleTest.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/DeleteChildSimpleTest.scala @@ -1,6 +1,6 @@ package maf.test.deltaDebugging.gtr.transformations -import maf.deltaDebugging.gtr.transformations.generics.DeleteChildSimple +import maf.deltaDebugging.treeDD.transformations.generics.DeleteChildSimple import maf.language.scheme.{SchemeBegin, SchemeExp, SchemeFuncall, SchemeLambdaExp, SchemeLettishExp, SchemeParser} import org.scalatest.flatspec.AnyFlatSpec diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/IfToBeginTest.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/IfToBeginTest.scala index 5e1c35972..58a597f85 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/IfToBeginTest.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/IfToBeginTest.scala @@ -1,6 +1,6 @@ package maf.test.deltaDebugging.gtr.transformations -import maf.deltaDebugging.gtr.transformations.schemeIf.IfToBegin +import maf.deltaDebugging.treeDD.transformations.schemeSequencify.IfToBegin import maf.language.scheme.{SchemeBegin, SchemeParser} import org.scalatest.flatspec.AnyFlatSpec diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/LetIdentifierShallowDropTest.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/LetIdentifierShallowDropTest.scala deleted file mode 100644 index e005a5c4c..000000000 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/LetIdentifierShallowDropTest.scala +++ /dev/null @@ -1,44 +0,0 @@ -package maf.test.deltaDebugging.gtr.transformations - -import maf.deltaDebugging.gtr.transformations.schemeLet.LetIdentifierShallowDrop -import maf.language.scheme.{SchemeBegin, SchemeParser} -import org.scalatest.flatspec.AnyFlatSpec - -class LetIdentifierShallowDropTest extends AnyFlatSpecTransformations { - "LetIdentifierShallowDrop" should "deep drop a lets identifier" in { - val programText = - """(begin - | (+ 2 2) - | (let ((a 10) - | (b 100)) - | b - | (+ b a) - | (if #t a 99)))""".stripMargin - - val t: SchemeBegin = SchemeParser.parseProgramText(programText).last.asInstanceOf[SchemeBegin] - val letExp = t.exps(1) - - val suggestedTrees = LetIdentifierShallowDrop.transform(t, letExp).toList - - assertTreeString("(begin (+ 2 2) (let ((a 10)) (if #t a 99)))", suggestedTrees) - - assertTreeString("(begin (+ 2 2) (let ((b 100)) b))", suggestedTrees) - } - - "LetIdentifierShallowDrop" should "return empty list for non-let exps" in { - val programText = - """(begin - | (+ 2 2) - | (lambda (a) - | (+ 99 a) - | (if #t a 99)))""".stripMargin - - val t: SchemeBegin = SchemeParser.parseProgramText(programText).last.asInstanceOf[SchemeBegin] - val lambdaExp = t.exps(1) - - val suggestedTrees = LetIdentifierShallowDrop.transform(t, lambdaExp).toList - - assert(suggestedTrees equals List()) - } -} - diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/RemoveCallsTest.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/RemoveCallsTest.scala index e21b8a5ca..8b28afd0a 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/RemoveCallsTest.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/RemoveCallsTest.scala @@ -1,6 +1,6 @@ package maf.test.deltaDebugging.gtr.transformations -import maf.deltaDebugging.gtr.transformations.schemeLambda.RemoveCalls +import maf.deltaDebugging.treeDD.transformations.schemeLambda.RemoveCalls import maf.language.scheme.{SchemeBegin, SchemeParser} import org.scalatest.flatspec.AnyFlatSpec diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/RemoveLambdaParamByReplacementTest.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/RemoveLambdaParamByReplacementTest.scala index c8ae9c50d..5027a198d 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/RemoveLambdaParamByReplacementTest.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/RemoveLambdaParamByReplacementTest.scala @@ -1,6 +1,6 @@ package maf.test.deltaDebugging.gtr.transformations -import maf.deltaDebugging.gtr.transformations.schemeLambda.RemoveLambdaParamByReplacement +import maf.deltaDebugging.treeDD.transformations.schemeLambda.RemoveLambdaParamByReplacement import maf.language.scheme.{SchemeBegin, SchemeParser} import org.scalatest.flatspec.AnyFlatSpec diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/RemoveLambdaParamWithDeepDropTest.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/RemoveLambdaParamWithDeepDropTest.scala index 01516ec42..12249bf5d 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/RemoveLambdaParamWithDeepDropTest.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/RemoveLambdaParamWithDeepDropTest.scala @@ -1,6 +1,6 @@ package maf.test.deltaDebugging.gtr.transformations -import maf.deltaDebugging.gtr.transformations.schemeLambda.RemoveLambdaParamWithDeepDrop +import maf.deltaDebugging.treeDD.transformations.schemeLambda.RemoveLambdaParamWithDeepDrop import maf.language.scheme.{SchemeBegin, SchemeParser} import org.scalatest.flatspec.AnyFlatSpec diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/RemoveLambdaParamWithShallowDropTest.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/RemoveLambdaParamWithShallowDropTest.scala deleted file mode 100644 index 70807a2e1..000000000 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/RemoveLambdaParamWithShallowDropTest.scala +++ /dev/null @@ -1,41 +0,0 @@ -package maf.test.deltaDebugging.gtr.transformations - -import maf.deltaDebugging.gtr.transformations.schemeLambda.RemoveLambdaParamWithShallowDrop -import maf.language.scheme.{SchemeBegin, SchemeParser} -import org.scalatest.flatspec.AnyFlatSpec - -class RemoveLambdaParamWithShallowDropTest extends AnyFlatSpecTransformations { - "RemoveLambdaParamWithShallowDrop" should "shallow drop a lambdas param" in { - val programText: String = - """(begin - | (define (f x y) (* x x) (* y y)) - | (f 1 2) - | (f 111 222)) - | """.stripMargin - - val t: SchemeBegin = SchemeParser.parseProgramText(programText).last.asInstanceOf[SchemeBegin] - val defineExp = t.exps.head - - val suggestedTrees = RemoveLambdaParamWithShallowDrop.transform(t, defineExp).toList - - assert(suggestedTrees.length == 2) - assertTreeString("(begin (define f (lambda (x) (* x x))) (f 1) (f 111))", suggestedTrees) - - assertTreeString("(begin (define f (lambda (y) (* y y))) (f 2) (f 222))", suggestedTrees) - } - - "RemoveLambdaParamWithShallowDrop" should "return empty list given a non-lambda-binding exp" in { - val programText: String = - """(begin - | (define (f x y) (* x x) (* y y)) - | (f 1 2) - | (f 111 222)) - | """.stripMargin - - val t: SchemeBegin = SchemeParser.parseProgramText(programText).last.asInstanceOf[SchemeBegin] - val fAppl = t.exps.last - - val suggestedTrees = RemoveLambdaParamWithShallowDrop.transform(t, fAppl).toList - assert(suggestedTrees equals List()) - } -} diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/ReplaceByChildTest.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/ReplaceByChildTest.scala index 1a41e298e..8168e30ee 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/ReplaceByChildTest.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/ReplaceByChildTest.scala @@ -1,6 +1,6 @@ package maf.test.deltaDebugging.gtr.transformations -import maf.deltaDebugging.gtr.transformations.generics.ReplaceByChild +import maf.deltaDebugging.treeDD.transformations.generics.ReplaceByChild import maf.language.scheme.{SchemeBegin, SchemeFuncall, SchemeParser} import org.scalatest.flatspec.AnyFlatSpec diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/ReplaceCallsTest.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/ReplaceCallsTest.scala index 3af3ca348..d9ecfb59c 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/ReplaceCallsTest.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/ReplaceCallsTest.scala @@ -1,6 +1,6 @@ package maf.test.deltaDebugging.gtr.transformations -import maf.deltaDebugging.gtr.transformations.schemeLambda.ReplaceCalls +import maf.deltaDebugging.treeDD.transformations.schemeLambda.ReplaceCalls import maf.language.scheme.{SchemeBegin, SchemeExp, SchemeParser} class ReplaceCallsTest extends AnyFlatSpecTransformations: diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/ReplaceIdentifierTest.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/ReplaceIdentifierTest.scala index 61a4b1d18..1a02ad356 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/ReplaceIdentifierTest.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/ReplaceIdentifierTest.scala @@ -1,7 +1,7 @@ package maf.test.deltaDebugging.gtr.transformations -import maf.deltaDebugging.gtr.transformations.generics.ReplaceByValue -import maf.deltaDebugging.gtr.transformations.schemeIdentifier.ReplaceIdentifier +import maf.deltaDebugging.treeDD.transformations.generics.ReplaceByValue +import maf.deltaDebugging.treeDD.transformations.schemeIdentifier.ReplaceIdentifier import org.scalatest.flatspec.AnyFlatSpec import maf.language.scheme.{SchemeBegin, SchemeFuncall, SchemeLet, SchemeParser} diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/ReplaceNthExpensiveFunctionTest.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/ReplaceNthExpensiveFunctionTest.scala index ea5b5b71a..986916489 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/ReplaceNthExpensiveFunctionTest.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/ReplaceNthExpensiveFunctionTest.scala @@ -1,6 +1,6 @@ package maf.test.deltaDebugging.gtr.transformations -import maf.deltaDebugging.gtr.transformations.schemeLambda.ReplaceNthExpensiveFunction +import maf.deltaDebugging.treeDD.transformations.schemeLambda.ReplaceNthExpensiveFunction import maf.language.scheme.{SchemeBegin, SchemeLet, SchemeParser} class ReplaceNthExpensiveFunctionTest extends AnyFlatSpecTransformations: diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/RemoveCallsAndReplaceByBodyTest.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/ThunkToBeginTest.scala similarity index 52% rename from code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/RemoveCallsAndReplaceByBodyTest.scala rename to code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/ThunkToBeginTest.scala index ba71e773a..b54256ad9 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/RemoveCallsAndReplaceByBodyTest.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/gtr/transformations/ThunkToBeginTest.scala @@ -1,34 +1,34 @@ package maf.test.deltaDebugging.gtr.transformations -import maf.deltaDebugging.gtr.transformations.schemeLambda.RemoveCallsAndReplaceByBody +import maf.deltaDebugging.treeDD.transformations.schemeLambda.ThunkToBegin import maf.language.scheme.{SchemeBegin, SchemeParser} import org.scalatest.flatspec.AnyFlatSpec -class RemoveCallsAndReplaceByBodyTest extends AnyFlatSpecTransformations { - "RemoveCallsAndReplaceByBody" should "remove the calls to define-bound lambda, and replace lambda by body" in { +class ThunkToBeginTest extends AnyFlatSpecTransformations { + "FlattenThunk" should "flatten defined thunks" in { val programText: String = """(begin - | (define (f x) (* x x)) - | (f 1) + | (define (f) (* 10 10)) + | (f) | (+ 2 2) - | (f 111)) + | (f)) | """.stripMargin val t: SchemeBegin = SchemeParser.parseProgramText(programText).last.asInstanceOf[SchemeBegin] val defineExp = t.exps.head - val suggestedTrees = RemoveCallsAndReplaceByBody.transform(t, defineExp).toList //should remove calls to f + val suggestedTrees = ThunkToBegin.transform(t, defineExp).toList //should remove calls to f assert(suggestedTrees.length == 1) - assertTreeString("(begin (define f (begin (* x x))) (+ 2 2))", suggestedTrees) + assertTreeString("(begin (define f (begin (* 10 10))) f (+ 2 2) f)", suggestedTrees) } - "RemoveCallsAndReplaceByBody" should "remove the calls to let-bound lambda, and replace the lambda by body" in { + "FlattenThunk" should "flatten let-bound thunks" in { val programText: String = """(begin - | (let ((f (lambda (x) (* x x)))) - | (f 10) - | (f 100) + | (let ((f (lambda () (* 10 10)))) + | (f) + | (f) | 1000) | (+ 2 2)) | """.stripMargin @@ -36,9 +36,10 @@ class RemoveCallsAndReplaceByBodyTest extends AnyFlatSpecTransformations { val t: SchemeBegin = SchemeParser.parseProgramText(programText).last.asInstanceOf[SchemeBegin] val letExp = t.exps.head - val suggestedTrees = RemoveCallsAndReplaceByBody.transform(t, letExp).toList //should remove calls to f + val suggestedTrees = ThunkToBegin.transform(t, letExp).toList //should remove calls to f + assert(suggestedTrees.length == 1) - assertTreeString("(begin (let ((f (begin (* x x)))) 1000) (+ 2 2))", suggestedTrees) + assertTreeString("(begin (let ((f (begin (* 10 10)))) f f 1000) (+ 2 2))", suggestedTrees) } "RemoveCallsAndReplaceByBody" should "return an empty list given a non-lambda-binding exp" in { @@ -53,7 +54,7 @@ class RemoveCallsAndReplaceByBodyTest extends AnyFlatSpecTransformations { val t: SchemeBegin = SchemeParser.parseProgramText(programText).last.asInstanceOf[SchemeBegin] val letExp = t.exps.head - val suggestedTrees = RemoveCallsAndReplaceByBody.transform(t, letExp).toList + val suggestedTrees = ThunkToBegin.transform(t, letExp).toList assert(suggestedTrees equals List()) } } diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/realBugs/RealBug1.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/realBugs/RealBug1.scala index d13de6ad5..f2a1f4fe0 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/realBugs/RealBug1.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/realBugs/RealBug1.scala @@ -7,4 +7,4 @@ trait RealBug1 extends SchemeSemantics: this: SchemeDomain with SchemeModFLocalSensitivity => override def allocPai(pai: Exp, car: Val, cdr: Val): A[Val] = - storeVal(pai, lattice.cons(car, car)) + storeVal(pai, lattice.cons(cdr, cdr)) diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/SoundnessCountingDDTester.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/SoundnessCountingDDTester.scala index 5c68bb2d2..985e7c996 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/SoundnessCountingDDTester.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/SoundnessCountingDDTester.scala @@ -3,26 +3,22 @@ package maf.test.deltaDebugging.soundnessDD import maf.core.Identity import maf.language.scheme.SchemeExp import maf.language.scheme.interpreter.ConcreteValues.Value -import maf.language.scheme.interpreter.{ConcreteValues, FileIO, SchemeInterpreter} +import maf.language.scheme.interpreter.{ConcreteValues, CountingSchemeInterpreter, FileIO, IO, SchemeInterpreter} import maf.test.modular.scheme.SchemeSoundnessTests import maf.util.benchmarks.Timer trait SoundnessCountingDDTester extends SoundnessDDTester: - protected def runInterpreterWithMaxSteps( - i: SchemeInterpreter, - p: SchemeExp, - maxSteps: Long, - ): Value = - i.runWithMaxSteps(p, maxSteps) // If there are code changes in the file, runs the "new" version by default (ensures compatibility with files containing changes). + override def createInterpreter(addResult: (Identity, Value) => Unit, io: IO, benchmark: Benchmark): CountingSchemeInterpreter = + new CountingSchemeInterpreter(addResult, io) def evalProgramWithMaxSteps(program: SchemeExp, benchmark: Benchmark, maxSteps: Long): (Map[Identity, Set[Value]], Long) = var idnResults = Map[Identity, Set[Value]]().withDefaultValue(Set()) val timeout = concreteTimeout(benchmark) val times = concreteRuns(benchmark) val addResult: (Identity, ConcreteValues.Value) => Unit = (i, v) => idnResults += (i -> (idnResults(i) + v)) - val interpreter = createInterpreter(addResult, io = new FileIO(Map("input.txt" -> "foo\nbar\nbaz", "output.txt" -> "")), benchmark) + val interpreter: CountingSchemeInterpreter = createInterpreter(addResult, io = new FileIO(Map("input.txt" -> "foo\nbar\nbaz", "output.txt" -> "")), benchmark) for _ <- 1 to times do - val (ellapsed, _) = Timer.time(runInterpreterWithMaxSteps(interpreter, program, maxSteps)) + val (ellapsed, _) = Timer.time(interpreter.runWithMaxSteps(program, timeout, maxSteps)) SchemeSoundnessTests.logEllapsed(this, benchmark, ellapsed, concrete = true) (idnResults, interpreter.getEvalSteps()) diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/SoundnessDDTester.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/SoundnessDDTester.scala index 4f691b2de..f8d999859 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/SoundnessDDTester.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/SoundnessDDTester.scala @@ -4,6 +4,8 @@ import maf.core.Identity import maf.language.scheme.SchemeExp import maf.language.scheme.interpreter.ConcreteValues.Value import maf.language.scheme.interpreter.{ConcreteValues, FileIO} +import maf.modular.{AnalysisResults, ModAnalysis} +import maf.modular.scheme.SchemeDomain import maf.test.SlowTest import maf.test.deltaDebugging.soundnessDD.implementation.DD import maf.test.modular.scheme.SchemeSoundnessTests @@ -14,7 +16,7 @@ import scala.concurrent.duration.{Duration, SECONDS} trait SoundnessDDTester extends SchemeSoundnessTests: override def analysisTimeout(b: Benchmark): Timeout.T = Timeout.start(Duration(2, SECONDS)) - override def concreteTimeout(b: Benchmark): Timeout.T = Timeout.start(Duration(5, SECONDS)) //remember: concrete run may not halt + override def concreteTimeout(b: Benchmark): Timeout.T = Timeout.start(Duration(3, SECONDS)) //remember: concrete run may not halt protected def compareResults( analysis: Analysis, @@ -35,7 +37,6 @@ trait SoundnessDDTester extends SchemeSoundnessTests: } "" - def evalProgram(program: SchemeExp, benchmark: Benchmark): Map[Identity, Set[Value]] = var idnResults = Map[Identity, Set[Value]]().withDefaultValue(Set()) val timeout = concreteTimeout(benchmark) @@ -105,8 +106,3 @@ trait SoundnessDDTester extends SchemeSoundnessTests: (None, (evalRunTime, analysisRuntime)) else (Some(compareResults(anl.get, concreteResults.get)), (evalRunTime, analysisRuntime)) } - - /* Subclass Responsibility - override def onBenchmark(benchmark: Benchmark): Unit = - ... - */ diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/Evaluate.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/Evaluate.scala deleted file mode 100644 index 9bf0324f8..000000000 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/Evaluate.scala +++ /dev/null @@ -1,90 +0,0 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation - -import maf.test.deltaDebugging.soundnessDD.SoundnessDDTester -import maf.test.deltaDebugging.soundnessDD.evaluation.baseline.SaveBaseline -import maf.test.deltaDebugging.soundnessDD.evaluation.counting.SaveCounting -import maf.test.deltaDebugging.soundnessDD.evaluation.parallel.SaveParallel -import maf.test.deltaDebugging.soundnessDD.evaluation.transforming.{SaveTransforming, SchemeModFLocalAdaptiveTests1, TransformingDD} -import maf.util.benchmarks.Statistics - -object Evaluate: - def main(args: Array[String]): Unit = { - SaveParallel.save() - SaveBaseline.save() - SaveCounting.save() - SaveTransforming.save() - } - - def save(tests: List[SoundnessDDTester], dataCollectorString: String, dataCollector: DataCollector): Unit = { - tests.foreach(t => org.scalatest.run(t)) - dataCollector.writeTo(dataCollectorString) - } - - def readAndAnalyzeData(dataCollectorString: String): Unit = { - val dataCollector: DataCollector = DataCollector.readObject(dataCollectorString) - - def meanAndStdDev(lst: List[Double]): (Double, Double) = - (Statistics.mean(lst).floor, Statistics.stddev(lst).floor) - - def computeAverages(data: List[ReductionData]): List[(Double)] = - List( - Statistics.mean(data.map(r => r.origSize)).floor, - Statistics.mean(data.map(r => r.reducedSize)).floor, - Statistics.mean(data.map(r => r.reductionTime)).floor, - Statistics.mean(data.map(r => r.interpreterTime)).floor, - Statistics.mean(data.map(r => r.analysisTime)).floor, - Statistics.mean(data.map(r => r.interpreterTimes.size)).floor - ) - - def analyseData(bugName: Option[String], data: List[ReductionData]): Unit = - val averages = computeAverages(data) - val avgOriginalSize = averages(0) - val avgReducedSize = averages(1) - val avgReductionTime = averages(2) - val avgInterpreterTime = averages(3) - val avgAnalysisTime = averages(4) - val avgNumberOfOracleInvocations = averages(5) - - if bugName.isEmpty then - println(">>>>> analysis of all data <<<<<") - else println(">>>>> analysis bug: " + bugName + " <<<<<") - println("number of programs: " + data.length) - println("avg original size: " + avgOriginalSize) - println("avg reduced size: " + avgReducedSize) - println("avg reduction time: " + avgReductionTime) - println("avg interpreter time: " + avgInterpreterTime) - println("avg analysis time: " + avgAnalysisTime) - println("avg # of oracle invocations: " + avgNumberOfOracleInvocations) - println("##################################################") - - val medianOrigSize = Statistics.Q3(data.map(r => r.origSize)) - val dataForLargePrograms = data.filter(r => r.origSize >= medianOrigSize) - val largeAverages = computeAverages(dataForLargePrograms) - val largeAvgOriginalSize = largeAverages(0) - val largeAvgReducedSize = largeAverages(1) - val largeAvgReductionTime = largeAverages(2) - val largeAvgInterpreterTime = largeAverages(3) - val largeAvgAnalysisTime = largeAverages(4) - val largeAvgNumberOfOracleInvocations = largeAverages(5) - - println("FOR LARGE PROGRAMS: ") - println("large: avg original size: " + largeAvgOriginalSize) - println("large: avg reduced size: " + largeAvgReducedSize) - println("large: avg reduction time: " + largeAvgReductionTime) - println("large: avg interpreter time: " + largeAvgInterpreterTime) - println("large: avg analysis time: " + largeAvgAnalysisTime) - println("avg # of oracle invocations: " + largeAvgNumberOfOracleInvocations) - - def analyseIndividualBugs(): Unit = - val grouped = dataCollector.reductionData.groupBy(r => r.bugName) - grouped.keySet.foreach(bugName => { - val data = grouped(bugName) - val medianSize = Statistics.median(data.map(r => r.origSize.toDouble)) - analyseData(Some(bugName), data) - }) - - analyseData(None, dataCollector.reductionData) - - println(dataCollector.reductionData.map(r => r.reducedSize)) - } - diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/baseline/BaselineTester.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/baseline/BaselineTester.scala deleted file mode 100644 index db07d1f12..000000000 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/baseline/BaselineTester.scala +++ /dev/null @@ -1,27 +0,0 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.baseline - -import maf.core.Identity -import maf.language.scheme.SchemeExp -import maf.language.scheme.interpreter.ConcreteValues.Value -import maf.test.SlowTest -import maf.test.deltaDebugging.soundnessDD.SoundnessDDTester -import maf.util.Reader - -trait BaselineTester extends SoundnessDDTester { - - val bugName: String - - override def onBenchmark(benchmark: Benchmark): Unit = - property(s"Analysis of $benchmark using $name is sound.", SlowTest) { - // load the benchmark program - val content = Reader.loadFile(benchmark) - val program = parseProgram(content, benchmark) - - runAndCompare(program, benchmark) match - case Some(failureMsg) => - if failureMsg.nonEmpty then - BaselineDD.bugName = bugName - BaselineDD.reduce(program, this, benchmark) - case _ => - } -} diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/parallel/ParallelDD.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/parallel/ParallelDD.scala deleted file mode 100644 index a4e2ec78c..000000000 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/parallel/ParallelDD.scala +++ /dev/null @@ -1,71 +0,0 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.parallel - -import maf.deltaDebugging.gtr.{GTR, GTRParallel} -import maf.deltaDebugging.gtr.transformations.TransformationManager -import maf.language.scheme.SchemeExp -import maf.test.deltaDebugging.soundnessDD.evaluation.counting.CountingTester -import maf.test.deltaDebugging.soundnessDD.evaluation.{DataCollector, ReductionData} - -object ParallelDD: - var dataCollector = new DataCollector - var bugName = "noneYet" - var maxSteps: Long = Long.MaxValue - - def reduce(program: SchemeExp, - soundnessTester: ParallelTester, - benchmark: String): Unit = - - var oracleInvocations = 0 - var runTimes: List[Long] = List() - var analysisTimes: List[Long] = List() - - val startTime = System.currentTimeMillis() - - val reduced = GTRParallel.reduce( - program, - p => { - oracleInvocations.synchronized { - oracleInvocations += 1 - } - soundnessTester.runCompareAndtimeWithMaxSteps(p, benchmark, maxSteps) match - case (Some((failureMsg, evalSteps)), (runTime, analysisTime)) => - runTimes.synchronized { - runTimes = runTimes.::(runTime) //collect - } - analysisTimes.synchronized { - analysisTimes = analysisTimes.::(analysisTime) //collect - } - maxSteps.synchronized { - maxSteps = Math.min(evalSteps, maxSteps) - } - p.findUndefinedVariables().isEmpty && failureMsg.nonEmpty - - case (None, (runTime, analysisTime)) => - runTimes.synchronized { - runTimes = runTimes.::(runTime) - } - analysisTimes.synchronized { - analysisTimes = analysisTimes.::(analysisTime) - } - false - }, - identity, - TransformationManager.allTransformations - ) - - val endTime = System.currentTimeMillis() - - val reductionData = ReductionData( - benchmark = benchmark, - bugName = bugName, - origSize = program.size, - reducedSize = reduced.size, - reductionTime = endTime - startTime, - interpreterTime = runTimes.sum, - analysisTime = analysisTimes.sum, - interpreterTimes = runTimes, - analysisTimes = analysisTimes - ) - - dataCollector.addReductionData(reductionData) - diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/parallel/ParallelTester.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/parallel/ParallelTester.scala deleted file mode 100644 index b21940f57..000000000 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/parallel/ParallelTester.scala +++ /dev/null @@ -1,23 +0,0 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.parallel - -import maf.test.SlowTest -import maf.test.deltaDebugging.soundnessDD.SoundnessCountingDDTester -import maf.util.Reader - -trait ParallelTester extends SoundnessCountingDDTester { - val bugName: String - - override def onBenchmark(benchmark: Benchmark): Unit = - property(s"Analysis of $benchmark using $name is sound.", SlowTest) { - // load the benchmark program - val content = Reader.loadFile(benchmark) - val program = parseProgram(content, benchmark) - runCompareAndtimeWithMaxSteps(program, benchmark, Long.MaxValue) match - case (Some((failureMsg, evalSteps)), _) => - if failureMsg.nonEmpty then - ParallelDD.maxSteps = evalSteps - ParallelDD.bugName = bugName - ParallelDD.reduce(program, this, benchmark) - case _ => - } -} diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/profiling/ProfilingDataCollector.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/profiling/ProfilingDataCollector.scala deleted file mode 100644 index 74df49bfb..000000000 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/profiling/ProfilingDataCollector.scala +++ /dev/null @@ -1,35 +0,0 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.profiling - -import java.io.{ByteArrayOutputStream, FileInputStream, FileOutputStream, ObjectInputStream, ObjectOutputStream} - -case class ReductionData(candidateFunctionCount: Int, - totalFunctionCount: Int, - oracleCount: Int, - programSize: Int, - reducedSize: Int, - OracleHits: Int, - reductionTime: Long, - oracleTimes: List[(Long, Int)], - analysisSteps: List[(Int, Int)]) extends Serializable - -object ProfilingDataCollector: - def readObject(suffix: String): ProfilingDataCollector = - val ois = new ObjectInputStream(new FileInputStream("/Users/turgut/Desktop/cs5/thesis/AnalysisDevTools/evaluationLogs/objects/" + suffix)) - val o = ois.readObject.asInstanceOf[ProfilingDataCollector] - ois.close() - o - -class ProfilingDataCollector extends Serializable: - var data: List[ReductionData] = List() - def addReductionData(d: ReductionData) = - data = data.::(d) - - def filter(minOriginalSize: Int): ProfilingDataCollector = - val res = new ProfilingDataCollector - res.data = data.filter(r => r.programSize > minOriginalSize) - res - - def writeTo(suffix: String): Unit = - val oos = new ObjectOutputStream(new FileOutputStream("/Users/turgut/Desktop/cs5/thesis/AnalysisDevTools/evaluationLogs/objects/" + suffix)) - oos.writeObject(this) - oos.close() \ No newline at end of file diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/profiling/ProfilingTester.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/profiling/ProfilingTester.scala deleted file mode 100644 index 4684f20c9..000000000 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/profiling/ProfilingTester.scala +++ /dev/null @@ -1,37 +0,0 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.profiling - -import maf.language.scheme.SchemeExp -import maf.modular.worklist.SequentialWorklistAlgorithm -import maf.test.SlowTest -import maf.test.deltaDebugging.soundnessDD.SoundnessDDTester -import maf.util.Reader -import maf.util.benchmarks.{Timeout, Timer} - - -trait ProfilingTester extends SoundnessDDTester: - - def profilingRunAndCompare(program: SchemeExp, benchmark: Benchmark): Option[(String, Array[(String, Int)])] = { - try - val concreteResults = evalProgram(program, benchmark) - // analyze the program using a ModF analysis - val anl = runAnalysis(program, benchmark) - // check if the analysis results soundly (over-)approximate the concrete results - Some(compareResults(anl, concreteResults), - anl.asInstanceOf[SequentialWorklistAlgorithm[SchemeExp]].getReAnalysisMap().toArray.sortWith((tpl1, tpl2) => tpl1._2 > tpl2._2)) - catch case exc: Throwable => - None - } - - override def onBenchmark(benchmark: Benchmark): Unit = - property(s"Analysis of $benchmark using $name has ran.", SlowTest) { - // load the benchmark program - val content = Reader.loadFile(benchmark) - val program = parseProgram(content, benchmark) - - profilingRunAndCompare(program, benchmark) match - case Some((failureMsg, initAnalysisResults)) => - if failureMsg.nonEmpty then - WithProfilingDD.reduce(program, this, benchmark, initAnalysisResults) - WithoutProfilingDD.reduce(program, this, benchmark, initAnalysisResults) - case None => - } diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/profiling/WithProfilingDD.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/profiling/WithProfilingDD.scala deleted file mode 100644 index 3ecf6ba37..000000000 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/profiling/WithProfilingDD.scala +++ /dev/null @@ -1,72 +0,0 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.profiling - -import maf.deltaDebugging.gtr.GTR -import maf.deltaDebugging.gtr.transformations.schemeLambda.ReplaceNthExpensiveFunction -import maf.language.scheme.{SchemeExp, SchemeParser} -import maf.test.deltaDebugging.soundnessDD.evaluation.profiling.* -import maf.test.deltaDebugging.soundnessDD.evaluation.CountLambdaBindings -import org.scalatest.Assertions.fail - -import java.io.{BufferedWriter, File, FileWriter} - -object WithProfilingDD: - val dataCollector = new ProfilingDataCollector - - def reduce(program: SchemeExp, - soundnessTester: ProfilingTester, - benchmark: String, - initAnalysisProfiling: Array[(String, Int)]): Unit = - var reduced = program - - var oracleTimes: List[(Long, Int)] = List() - var analysisSteps: List[(Int, Int)] = List() - var oracleHits = 0 - var oracleCount = 0 - - val reductionStartTime = System.currentTimeMillis() - - def reduceWithProfiling(profiling: Array[(String, Int)]): Unit = - for (i <- profiling.indices) - GTR.reduce( - reduced, - p => { - val startTime = System.currentTimeMillis() - soundnessTester.profilingRunAndCompare(p, benchmark) match - case Some((failureMsg, runAnalysisSteps)) => - oracleCount += 1 - val endTime = System.currentTimeMillis() - oracleTimes = oracleTimes.::((endTime - startTime, oracleHits)) - analysisSteps = analysisSteps.::((runAnalysisSteps.map(_._2).sum, oracleHits)) - p.findUndefinedVariables().isEmpty && - failureMsg.nonEmpty - case None => false - }, - newReduction => { - oracleHits += 1 - soundnessTester.profilingRunAndCompare(newReduction, benchmark) match - case Some((_, newReductionProfiled)) => - reduced = newReduction - return reduceWithProfiling(newReductionProfiled) - case _ => - }, - List(ReplaceNthExpensiveFunction(profiling, i)) - ) - - reduceWithProfiling(initAnalysisProfiling) - - val reductionEndTime = System.currentTimeMillis() - val reductionTime = reductionEndTime - reductionStartTime - - val dataPoint: ReductionData = ReductionData( - candidateFunctionCount = initAnalysisProfiling.length, - totalFunctionCount = CountLambdaBindings.count(program), - oracleCount = oracleCount, - programSize = program.size, - reducedSize = reduced.size, - OracleHits = oracleHits, - reductionTime = reductionTime, - oracleTimes = oracleTimes, - analysisSteps = analysisSteps, - ) - - dataCollector.addReductionData(dataPoint) \ No newline at end of file diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/profiling/WithoutProfilingDD.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/profiling/WithoutProfilingDD.scala deleted file mode 100644 index 6186245bf..000000000 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/profiling/WithoutProfilingDD.scala +++ /dev/null @@ -1,73 +0,0 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.profiling - -import maf.deltaDebugging.gtr.GTR -import maf.deltaDebugging.gtr.transformations.schemeLambda.ReplaceNthExpensiveFunction -import maf.language.scheme.{SchemeExp, SchemeParser} -import maf.test.deltaDebugging.soundnessDD.SoundnessDDTester -import maf.test.deltaDebugging.soundnessDD.evaluation.profiling.* -import maf.test.deltaDebugging.soundnessDD.evaluation.CountLambdaBindings -import org.scalatest.Assertions.fail - -import java.io.{BufferedWriter, File, FileWriter} -import scala.util.Random - -object WithoutProfilingDD: - val dataCollector = new ProfilingDataCollector - - def reduce(program: SchemeExp, - soundnessTester: ProfilingTester, - benchmark: String, - initAnalysisProfiling: Array[(String, Int)]): Unit = - var reduced = program - - var oracleTimes: List[(Long, Int)] = List() - var analysisSteps: List[(Int, Int)] = List() - var oracleHits = 0 - var oracleCount = 0 - - val reductionStartTime = System.currentTimeMillis() - - def reduceWithProfiling(profiling: Array[(String, Int)]): Unit = - for (i <- Random.shuffle(profiling.indices)) - GTR.reduce( - reduced, - p => { - val startTime = System.currentTimeMillis() //collect - soundnessTester.profilingRunAndCompare(p, benchmark) match - case Some((failureMsg, runAnalysisSteps)) => - oracleCount += 1 //collect - val endTime = System.currentTimeMillis() //collect - oracleTimes = oracleTimes.::((endTime - startTime, oracleHits)) //collect - analysisSteps = analysisSteps.::((runAnalysisSteps.map(_._2).sum, oracleHits)) //collect - p.findUndefinedVariables().isEmpty && failureMsg.nonEmpty - case None => false - }, - newReduction => { - oracleHits += 1 - soundnessTester.profilingRunAndCompare(newReduction, benchmark) match - case Some((_, newReductionProfiled)) => - reduced = newReduction - return reduceWithProfiling(newReductionProfiled) - case _ => - }, - List(ReplaceNthExpensiveFunction(profiling, i)) - ) - - reduceWithProfiling(initAnalysisProfiling) - - val reductionEndTime = System.currentTimeMillis() - val reductionTime = reductionEndTime - reductionStartTime - - val dataPoint: ReductionData = ReductionData( - candidateFunctionCount = initAnalysisProfiling.length, - totalFunctionCount = CountLambdaBindings.count(program), - oracleCount = oracleCount, - programSize = program.size, - reducedSize = reduced.size, - OracleHits = oracleHits, - reductionTime = reductionTime, - oracleTimes = oracleTimes, - analysisSteps = analysisSteps - ) - - dataCollector.addReductionData(dataPoint) \ No newline at end of file diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/profiling/evaluate.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/profiling/evaluate.scala deleted file mode 100644 index 14503cab4..000000000 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/profiling/evaluate.scala +++ /dev/null @@ -1,99 +0,0 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.profiling - -import maf.util.benchmarks.Statistics - -object SaveData: - def main(args: Array[String]): Unit = { - org.scalatest.run(new EvalProfilingTestSuiteA) - - val withProfilingDataCollector = WithProfilingDD.dataCollector - val withoutProfilingDataCollector = WithoutProfilingDD.dataCollector - - withProfilingDataCollector.writeTo("withProfilingDataCollector") - withoutProfilingDataCollector.writeTo("withoutProfilingDataCollector") - } - -object ReadAndAnalyzeData: - def main(args: Array[String]): Unit = { - val withProfilingDataCollector = ProfilingDataCollector.readObject("withProfilingDataCollector") - val withoutProfilingDataCollector = ProfilingDataCollector.readObject("withoutProfilingDataCollector") - - def evaluateDataCollector(collector: ProfilingDataCollector): Unit = { - val data = collector.data - val programSizes = data.map(_.programSize) - val reducedSizes = data.map(_.reducedSize) - val reductionTimes = data.map(_.reductionTime) - val oracleCounts = data.map(_.oracleCount) - val oracleHits = data.map(_.OracleHits) - val oracleTimes = data.map(_.oracleTimes) - val analysisSteps = data.map(_.analysisSteps) - val candidateFunctionCounts = data.map(_.candidateFunctionCount) - val totalFunctionCounts = data.map(_.totalFunctionCount) - - val numberOfPrograms = programSizes.size - val averageReductionTime = reductionTimes.sum / reductionTimes.size - val averageOracleCount = oracleCounts.sum / oracleCounts.size - val averageOracleTime = oracleTimes.flatten.map(tpl => tpl._1).sum / oracleTimes.flatten.size - val averageOriginalProgramSize = programSizes.sum / programSizes.size - val averageReducedProgramSize = reducedSizes.sum / reducedSizes.size - val averageNumberOfFunctionsRemoved: Double = oracleHits.sum.toDouble / oracleHits.size - val averageNumberOfFunctions: Double = totalFunctionCounts.sum.toDouble / totalFunctionCounts.size - val averageNumberOfCandidateFunctions: Double = candidateFunctionCounts.sum.toDouble / candidateFunctionCounts.size - - def findTotalAnalysisStepsAfterNReductions(lst: Iterable[(Int, Int)], n: Int): Int = - lst.filter(tpl => tpl._2 == n).map(_._1).sum - - def findAverageAnalysisStepsAfterNReductions(lst: Iterable[(Int, Int)], n: Int): Int = - (lst.filter(tpl => tpl._2 == n).map(_._1).sum) / (lst.filter(tpl => tpl._2 == n).map(_._1).size) - - def findTotals(lst: Iterable[(Int, Int)]): List[Int] = - 0.to(10).map(nmbr => findTotalAnalysisStepsAfterNReductions(lst, nmbr)).toList - - def findAverages(lst: Iterable[(Int, Int)]): List[Int] = - 0.to(10).map(nmbr => findAverageAnalysisStepsAfterNReductions(lst, nmbr)).toList - - val totals = findTotals(analysisSteps.flatten) - - val averages = findAverages(analysisSteps.flatten) - - println("number of programs: " + numberOfPrograms) - println("average reduction time: " + averageReductionTime) - println("average oracle count: " + averageOracleCount) - println("average oracle time: " + averageOracleTime) - println("average original program size: " + averageOriginalProgramSize) - println("average reduced program size: " + averageReducedProgramSize) - println("average number of functions removed: " + averageNumberOfFunctionsRemoved) - println("average number of functions: " + averageNumberOfFunctions) - println("average number of candidate functions: " + averageNumberOfCandidateFunctions) - - println("#####") - - println("total number of analysis steps: " + analysisSteps.flatten.map(tpl => tpl._1).sum) - - averages.zipWithIndex.foreach(tpl => { - val avg = tpl._1 - val idx = tpl._2 - println("avg number of steps for analysis after " + idx + " reductions: " + avg) - }) - } - - val medianProgramSize = Statistics.median(withProfilingDataCollector.data.map(r => r.programSize)) - val largeWithProfiling = withProfilingDataCollector.filter(medianProgramSize.toInt) - val largeWithoutProfiling = withoutProfilingDataCollector.filter(medianProgramSize.toInt) - - println(">>>>> results WITHOUT profiling <<<<< ") - evaluateDataCollector(withoutProfilingDataCollector) - println("") - println("####################################") - println("") - println(">>>>> results WITH profiling <<<<< ") - evaluateDataCollector(withProfilingDataCollector) - - println(">>>>> results LARGE WITHOUT profiling <<<<< ") - evaluateDataCollector(largeWithoutProfiling) - println("") - println("####################################") - println("") - println(">>>>> results LARGE WITH profiling <<<<< ") - evaluateDataCollector(largeWithProfiling) - } diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/profiling/soundnessTests.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/profiling/soundnessTests.scala deleted file mode 100644 index f848d7ec1..000000000 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/profiling/soundnessTests.scala +++ /dev/null @@ -1,52 +0,0 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.profiling - -import maf.core.Position -import maf.language.scheme.primitives.SchemePrelude -import maf.language.scheme.{SchemeExp, SchemeMutableVarBoxer, SchemeParser} -import maf.modular.scheme.SchemeConstantPropagationDomain -import maf.modular.scheme.modflocal.* -import maf.modular.worklist.FIFOWorklistAlgorithm -import maf.test.{AllBenchmarks, AllSequentialBenchmarks, RandomSequentialBenchmarks, VariousSequentialBenchmarks} -import maf.test.deltaDebugging.soundnessBugs.* -import maf.test.deltaDebugging.soundnessDD.SoundnessDDTester - -trait SchemeModFLocalSoundnessTests extends ProfilingTester: - override def benchmarks: Set[Benchmark] = Set("test/R5RS/various/SICP-compiler.scm") - override def parseProgram(txt: String, benchmark: String): SchemeExp = - val parsed = SchemeParser.parse(txt, Position.withSourcePath(benchmark)) - val prelud = SchemePrelude.addPrelude(parsed, incl = Set("__toplevel_cons", "__toplevel_cdr", "__toplevel_set-cdr!")) - val transf = SchemeMutableVarBoxer.transform(prelud) - SchemeParser.rename(SchemeParser.undefine(transf)) - -class EvalProfilingTestSuiteA extends SchemeModFLocalSoundnessTests: - def n = 100 - def name = s"MODF LOCAL w/ ASW -- policy A (n = $n)" - def analysis(prg: SchemeExp) = - new SchemeModFLocal(prg) - with SchemeConstantPropagationDomain - with SchemeModFLocalNoSensitivity - with FIFOWorklistAlgorithm[SchemeExp] - with SchemeModFLocalAnalysisResults - with BeginBug - -class EvalProfilingTestSuiteB extends SchemeModFLocalSoundnessTests: - def n = 100 - def name = s"MODF LOCAL w/ ASW -- policy A (n = $n)" - def analysis(prg: SchemeExp) = - new SchemeModFLocal(prg) - with SchemeConstantPropagationDomain - with SchemeModFLocalNoSensitivity - with FIFOWorklistAlgorithm[SchemeExp] - with SchemeModFLocalAnalysisResults - with CallBug - -class EvalProfilingTestSuiteC extends SchemeModFLocalSoundnessTests: - def n = 100 - def name = s"MODF LOCAL w/ ASW -- policy A (n = $n)" - def analysis(prg: SchemeExp) = - new SchemeModFLocal(prg) - with SchemeConstantPropagationDomain - with SchemeModFLocalNoSensitivity - with FIFOWorklistAlgorithm[SchemeExp] - with SchemeModFLocalAnalysisResults - with LetBug diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/transforming/TransformingTester.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/transforming/TransformingTester.scala deleted file mode 100644 index e164c970f..000000000 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/transforming/TransformingTester.scala +++ /dev/null @@ -1,27 +0,0 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.transforming - -import maf.core.Identity -import maf.language.scheme.SchemeExp -import maf.language.scheme.interpreter.ConcreteValues.Value -import maf.test.SlowTest -import maf.test.deltaDebugging.soundnessDD.SoundnessDDTester -import maf.util.Reader - -trait TransformingTester extends SoundnessDDTester { - val bugName: String - - override def onBenchmark(benchmark: Benchmark): Unit = - property(s"Analysis of $benchmark using $name is sound.", SlowTest) { - // load the benchmark program - val content = Reader.loadFile(benchmark) - val program = parseProgram(content, benchmark) - - runAndCompare(program, benchmark) match - case Some(failureMsg) => - if failureMsg.nonEmpty then - TransformingDD.bugName = bugName - TransformingDD.reduce(program, this, benchmark) - case _ => - } - -} diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/implementation/DD.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/implementation/DD.scala index b9bef06a2..4e4d22777 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/implementation/DD.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/implementation/DD.scala @@ -1,7 +1,7 @@ package maf.test.deltaDebugging.soundnessDD.implementation -import maf.deltaDebugging.gtr.* -import maf.deltaDebugging.gtr.transformations.* +import maf.deltaDebugging.treeDD.* +import maf.deltaDebugging.treeDD.transformations.* import maf.language.scheme.{SchemeExp, SchemeParser} import maf.test.deltaDebugging.soundnessDD.SoundnessDDTester import org.scalatest.Assertions.fail @@ -11,8 +11,7 @@ object DD: def reduce(program: SchemeExp, soundnessTester: DDTester, benchmark: String): Unit = - - val reduced: SchemeExp = GTRParallel.reduce( + val reduced: SchemeExp = SchemeReduce.reduce( program, p => { soundnessTester.runCompareAndtimeWithMaxSteps(p, benchmark, maxSteps) match @@ -26,7 +25,7 @@ object DD: false }, identity, - TransformationManager.genericTransformations + TransformationManager.allTransformations ) val parsedAgain = SchemeParser.parse(reduced.prettyString()).head //parse again, to generate file-related information (e.g. bug is at offset 20-25) diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/implementation/DDTester.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/implementation/DDTester.scala index 5d5168dbc..18804afe3 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/implementation/DDTester.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/implementation/DDTester.scala @@ -3,21 +3,17 @@ package maf.test.deltaDebugging.soundnessDD.implementation import maf.core.Identity import maf.language.scheme.SchemeExp import maf.language.scheme.interpreter.ConcreteValues.Value -import maf.language.scheme.interpreter.{ConcreteValues, FileIO, SchemeInterpreter} +import maf.language.scheme.interpreter.{ConcreteValues, CountingSchemeInterpreter, FileIO, IO, SchemeInterpreter} import maf.test.SlowTest import maf.test.deltaDebugging.soundnessDD.SoundnessDDTester -import maf.test.deltaDebugging.soundnessDD.evaluation.counting.CountingDD +import maf.test.deltaDebugging.soundnessDD.variants.counting.CountingDD import maf.test.modular.scheme.SchemeSoundnessTests import maf.util.Reader import maf.util.benchmarks.Timer trait DDTester extends SoundnessDDTester { - protected def runInterpreterWithMaxSteps( - i: SchemeInterpreter, - p: SchemeExp, - maxSteps: Long, - ): Value = - i.runWithMaxSteps(p, maxSteps) + override def createInterpreter(addResult: (Identity, Value) => Unit, io: IO, benchmark: Benchmark): CountingSchemeInterpreter = + new CountingSchemeInterpreter(addResult, io) def evalProgramWithMaxSteps(program: SchemeExp, benchmark: Benchmark, maxSteps: Long): (Map[Identity, Set[Value]], Long) = var idnResults = Map[Identity, Set[Value]]().withDefaultValue(Set()) @@ -26,7 +22,7 @@ trait DDTester extends SoundnessDDTester { val addResult: (Identity, ConcreteValues.Value) => Unit = (i, v) => idnResults += (i -> (idnResults(i) + v)) val interpreter = createInterpreter(addResult, io = new FileIO(Map("input.txt" -> "foo\nbar\nbaz", "output.txt" -> "")), benchmark) for _ <- 1 to times do - val (ellapsed, _) = Timer.time(runInterpreterWithMaxSteps(interpreter, program, maxSteps)) + val (ellapsed, _) = Timer.time(interpreter.runWithMaxSteps(program, timeout, maxSteps)) SchemeSoundnessTests.logEllapsed(this, benchmark, ellapsed, concrete = true) (idnResults, interpreter.getEvalSteps()) diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/implementation/soundnessTests.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/implementation/soundnessTests.scala index ec42577cc..5817af762 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/implementation/soundnessTests.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/implementation/soundnessTests.scala @@ -8,11 +8,11 @@ import maf.modular.scheme.modflocal.{SchemeModFLocal, SchemeModFLocalAnalysisRes import maf.modular.worklist.FIFOWorklistAlgorithm import maf.test.deltaDebugging.realBugs.* import maf.test.deltaDebugging.soundnessBugs.* -import maf.test.{CertainVariousSequentialBenchmarks, RandomSequentialBenchmarks, VariousSequentialBenchmarks} +import maf.test.{DDBenchmarks, RandomSequentialBenchmarks, VariousSequentialBenchmarks} import maf.test.deltaDebugging.soundnessDD.SoundnessDDTester -trait SchemeModFLocalSoundnessTests extends DDTester with CertainVariousSequentialBenchmarks: - //override def benchmarks: Set[Benchmark] = Set("test/R5RS/various/mceval.scm") +trait SchemeModFLocalSoundnessTests extends DDTester with DDBenchmarks: + override def benchmarks: Set[Benchmark] = Set("test/R5RS/DD/lst-append.scm") override def parseProgram(txt: String, benchmark: String): SchemeExp = val parsed = SchemeParser.parse(txt, Position.withSourcePath(benchmark)) @@ -29,6 +29,7 @@ class SchemeModFLocalAdaptiveTestsA extends SchemeModFLocalSoundnessTests: with SchemeModFLocalNoSensitivity with FIFOWorklistAlgorithm[SchemeExp] with SchemeModFLocalAnalysisResults + with RealBug2 class SchemeModFLocalAdaptiveTestsB extends SchemeModFLocalSoundnessTests: def l = 10 diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/CountLambdaBindings.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/CountLambdaBindings.scala similarity index 94% rename from code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/CountLambdaBindings.scala rename to code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/CountLambdaBindings.scala index 0c52ca999..002986473 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/CountLambdaBindings.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/CountLambdaBindings.scala @@ -1,4 +1,4 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation +package maf.test.deltaDebugging.soundnessDD.variants import maf.language.scheme.{AContractSchemeMessage, ASchemeExp, CSchemeExp, ContractSchemeExp, MatchExpr, SchemeAssert, SchemeBegin, SchemeCodeChange, SchemeDefineVariable, SchemeExp, SchemeFuncall, SchemeIf, SchemeLambdaExp, SchemeLettishExp, SchemeSanitizer, SchemeSetExp, SchemeSink, SchemeSource, SchemeValue, SchemeVarExp, SymbolicHole, SymbolicVar} diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/DataCollector.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/DataCollector.scala similarity index 78% rename from code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/DataCollector.scala rename to code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/DataCollector.scala index d592b4c4d..7b70d14c0 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/DataCollector.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/DataCollector.scala @@ -1,4 +1,4 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation +package maf.test.deltaDebugging.soundnessDD.variants import java.io.{FileInputStream, FileOutputStream, ObjectInputStream, ObjectOutputStream} @@ -6,11 +6,10 @@ case class ReductionData(benchmark: String, bugName:String, origSize: Int, reducedSize: Int, + reductionPercentage: Double, reductionTime: Long, - interpreterTime: Long, - analysisTime: Long, - interpreterTimes: List[Long], - analysisTimes: List[Long]) extends Serializable + oracleTreeSizes: List[Int] + ) extends Serializable object DataCollector: def readObject(suffix: String): DataCollector = diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/DeadCodeElimination/DeadCodeDD.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/DeadCodeElimination/DeadCodeDD.scala new file mode 100644 index 000000000..42f2f3472 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/DeadCodeElimination/DeadCodeDD.scala @@ -0,0 +1,51 @@ +package maf.test.deltaDebugging.soundnessDD.variants.DeadCodeElimination + +import maf.deltaDebugging.treeDD.SchemeReduce +import maf.deltaDebugging.treeDD.transformations.TransformationManager +import maf.language.scheme.{SchemeExp, SchemeLambda} +import maf.test.deltaDebugging.soundnessDD.variants.* + +object DeadCodeDD: + var dataCollector = new DataCollector + var bugName = "noneYet" + + def reduce(startProgram: SchemeExp, + program: SchemeExp, + soundnessTester: DeadCodeTester, + benchmark: String): Unit = + + var oracleInvocations = 0 + var oracleTreeSizes: List[Int] = List() + + val startTime = System.currentTimeMillis() + + val reduced = SchemeReduce.reduce( + program, + p => { + oracleInvocations += 1 + oracleTreeSizes = oracleTreeSizes.::(p.size) + soundnessTester.runCompareAndtime(p, benchmark) match + case (Some(failureMsg), _) => + p.findUndefinedVariables().isEmpty && failureMsg.nonEmpty + + case (None, (runTime, analysisTime)) => + false + }, + identity, + TransformationManager.allTransformations, + ) + + val endTime = System.currentTimeMillis() + val totalReductionTime = endTime - startTime + + val reductionData = ReductionData( + benchmark = benchmark, + bugName = bugName, + origSize = startProgram.size, + reducedSize = reduced.size, + reductionTime = totalReductionTime, + reductionPercentage = 1 - (reduced.size.toDouble / startProgram.size), + oracleTreeSizes = oracleTreeSizes + ) + + dataCollector.addReductionData(reductionData) diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/DeadCodeElimination/DeadCodeRemover.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/DeadCodeElimination/DeadCodeRemover.scala new file mode 100644 index 000000000..120947fa8 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/DeadCodeElimination/DeadCodeRemover.scala @@ -0,0 +1,65 @@ +package maf.test.deltaDebugging.soundnessDD.variants.DeadCodeElimination + +import maf.core.* +import maf.deltaDebugging.treeDD.transformations.traits.Replacing +import maf.language.scheme.interpreter.ConcreteValues +import maf.language.scheme.* +import maf.language.sexp.* + +import scala.util.Random + +object DeadCodeRemover: + type Benchmark = String + + def removeDeadLambdas(program: SchemeExp, + dynAnalysis: Set[SchemeExp], + deadCodeTester: DeadCodeTester, + benchmark: Benchmark + ): SchemeExp = + + val deadCodeRemoved = program.map(exp => { + if dynAnalysis.exists(calledExp => calledExp eq exp) then + exp + else SchemeValue(Value.Nil, NoCodeIdentity) + }) + + val oracleResults = deadCodeTester.runAndCompare(deadCodeRemoved, benchmark) + oracleResults match + case Some(failureMsg) => + if failureMsg.nonEmpty then + return deadCodeRemoved + case _ => + + program + + /* + val deadLambdasRemoved = program.deleteChildren(exp => { + exp match + case l: SchemeLambda => + !dynAnalysis.exists(calledLambda => calledLambda eq l) + case _ => false + }) + + deadLambdasRemoved match + case Some(programVariant) => + val undefinedVars: List[String] = programVariant.findUndefinedVariables().map(id => id.name) + val cleanedUp = programVariant.map(exp => { + exp match + case svar: SchemeVar => + if undefinedVars.contains(svar.id.name) then + SchemeValue(Value.Boolean(true), NoCodeIdentity) + else exp + case _ => exp + }) + + val oracleResults = deadCodeTester.runAndCompare(cleanedUp, benchmark) + oracleResults match + case Some(failureMsg) => + if failureMsg.nonEmpty then + return cleanedUp + case _ => + case _ => + + + program + */ diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/DeadCodeElimination/DeadCodeTester.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/DeadCodeElimination/DeadCodeTester.scala new file mode 100644 index 000000000..8f85f2b8b --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/DeadCodeElimination/DeadCodeTester.scala @@ -0,0 +1,101 @@ +package maf.test.deltaDebugging.soundnessDD.variants.DeadCodeElimination + +import maf.core.{Identity, IdentityWithData, NoCodeIdentity, NoCodeIdentityDebug, SimpleIdentity} +import maf.language.scheme.interpreter.ConcreteValues.Value +import maf.language.scheme.interpreter.* +import maf.language.scheme.* +import maf.language.sexp +import maf.modular.worklist.SequentialWorklistAlgorithm +import maf.test.SlowTest +import maf.test.deltaDebugging.soundnessDD.SoundnessDDTester +import maf.test.deltaDebugging.soundnessDD.variants.baseline.BaselineDD +import maf.test.modular.scheme.SchemeSoundnessTests +import maf.util.Reader +import maf.util.benchmarks.Timer + +trait DeadCodeTester extends SoundnessDDTester { + def bugName: String + + override def createInterpreter(addResult: (Identity, Value) => Unit, io: IO, benchmark: Benchmark): DeadCodeInterpreter = + new DeadCodeInterpreter(addResult, io) + + def evalProgramAndFindLambdas(program: SchemeExp, benchmark: Benchmark): (Map[Identity, Set[Value]], Set[SchemeExp]) = + var idnResults = Map[Identity, Set[Value]]().withDefaultValue(Set()) + val timeout = concreteTimeout(benchmark) + val times = concreteRuns(benchmark) + val addResult: (Identity, ConcreteValues.Value) => Unit = (i, v) => idnResults += (i -> (idnResults(i) + v)) + val interpreter: DeadCodeInterpreter = createInterpreter(addResult, io = new FileIO(Map("input.txt" -> "foo\nbar\nbaz", "output.txt" -> "")), benchmark) + var dynAnalysis: Set[SchemeExp] = Set() + for _ <- 1 to times do + val (ellapsed, _) = Timer.time({ + val tpl = interpreter.runAndIdentifyDeadCode(program, timeout) + dynAnalysis = tpl._2 + }) + SchemeSoundnessTests.logEllapsed(this, benchmark, ellapsed, concrete = true) + (idnResults, dynAnalysis) + + def runAndFindLambdas(program: SchemeExp, benchmark: Benchmark): + (Option[(String, + Set[SchemeExp] + )], (Long, Long)) = + var evalStartTime: Long = 0 + var evalRunTime: Long = 0 + var evalEndTime: Long = 0 + + var analysisStartTime: Long = 0 + var analysisRuntime: Long = 0 + var analysisEndTime: Long = 0 + + var excThrown: Boolean = false + + var concreteResults: Option[Map[Identity, Set[Value]]] = None + var anl: Option[Analysis] = None + var calledExps: Option[Set[SchemeExp]] = None + + try + evalStartTime = System.currentTimeMillis() + val tpl = evalProgramAndFindLambdas(program, benchmark) + calledExps = Some(tpl._2) + concreteResults = Some(tpl._1) + evalEndTime = System.currentTimeMillis() + evalRunTime = evalEndTime - evalStartTime + catch case exc: Throwable => + excThrown = true + evalEndTime = System.currentTimeMillis() + evalRunTime = evalEndTime - evalStartTime + + try + analysisStartTime = System.currentTimeMillis() + anl = Some(runAnalysis(program, benchmark)) + analysisEndTime = System.currentTimeMillis() + analysisRuntime = analysisEndTime - analysisStartTime + catch case exc: Throwable => + excThrown = true + analysisEndTime = System.currentTimeMillis() + analysisRuntime = analysisEndTime - analysisStartTime + + if excThrown then + (None, (evalRunTime, analysisRuntime)) + else (Some((compareResults(anl.get, concreteResults.get), + calledExps.get + )), (evalRunTime, analysisRuntime)) + + override def onBenchmark(benchmark: Benchmark): Unit = + println("DeadCode >>> running benchmark: " + benchmark) + // load the benchmark program + val content = Reader.loadFile(benchmark) + val program = parseProgram(content, benchmark) + + runAndFindLambdas(program, benchmark) match + case (Some((failureMsg, dynAnalysis)), _) => + if failureMsg.nonEmpty then + DeadCodeDD.bugName = bugName + + val postDCE = DeadCodeRemover.removeDeadLambdas(program, dynAnalysis, this, benchmark) + println("pre: " + program.size) + println("post: " + postDCE.size) + //println(program.prettyString()) + //println(postDCE.prettyString()) + DeadCodeDD.reduce(program, postDCE, this, benchmark) + case _ => +} diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/DeadCodeElimination/EvaluateDeadCode.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/DeadCodeElimination/EvaluateDeadCode.scala new file mode 100644 index 000000000..e62484112 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/DeadCodeElimination/EvaluateDeadCode.scala @@ -0,0 +1,18 @@ +package maf.test.deltaDebugging.soundnessDD.variants.DeadCodeElimination + +import maf.test.deltaDebugging.soundnessDD.variants.Evaluate + +object SaveDeadCode: + def save(): Unit = { + Evaluate.save( + List( + new SchemeModFLocalAdaptiveTests1, + new SchemeModFLocalAdaptiveTests2, + new SchemeModFLocalAdaptiveTests3, + new SchemeModFLocalAdaptiveTests4, + new SchemeModFLocalAdaptiveTests5 + ), + "deadCodeDataCollector", + DeadCodeDD.dataCollector + ) + } diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/DeadCodeElimination/soundnessTests.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/DeadCodeElimination/soundnessTests.scala new file mode 100644 index 000000000..698faf124 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/DeadCodeElimination/soundnessTests.scala @@ -0,0 +1,78 @@ +package maf.test.deltaDebugging.soundnessDD.variants.DeadCodeElimination + +import maf.core.Position +import maf.language.scheme.primitives.SchemePrelude +import maf.language.scheme.{SchemeExp, SchemeMutableVarBoxer, SchemeParser} +import maf.modular.scheme.SchemeConstantPropagationDomain +import maf.modular.scheme.modflocal.{SchemeModFLocal, SchemeModFLocalAnalysisResults, SchemeModFLocalNoSensitivity} +import maf.modular.worklist.FIFOWorklistAlgorithm +import maf.test.deltaDebugging.realBugs.* +import maf.test.{AllSequentialBenchmarks, DDBenchmarks, RandomSequentialBenchmarks, VariousSequentialBenchmarks} + +trait SchemeModFLocalSoundnessTests extends DeadCodeTester with DDBenchmarks: + override def benchmarks: Set[Benchmark] = Set("test/R5RS/various/primtest.scm") + override def parseProgram(txt: String, benchmark: String): SchemeExp = + val parsed = SchemeParser.parse(txt, Position.withSourcePath(benchmark)) + val prelud = SchemePrelude.addPrelude(parsed, incl = Set("__toplevel_cons", "__toplevel_cdr", "__toplevel_set-cdr!")) + val transf = SchemeMutableVarBoxer.transform(prelud) + SchemeParser.rename(SchemeParser.undefine(transf)) + +class SchemeModFLocalAdaptiveTests1 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug1" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug1 + +class SchemeModFLocalAdaptiveTests2 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug2" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug2 + +class SchemeModFLocalAdaptiveTests3 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug3" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug3 + +class SchemeModFLocalAdaptiveTests4 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug4" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug4 + +class SchemeModFLocalAdaptiveTests5 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug5" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug5 \ No newline at end of file diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/Evaluate.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/Evaluate.scala new file mode 100644 index 000000000..f94205bb4 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/Evaluate.scala @@ -0,0 +1,223 @@ +package maf.test.deltaDebugging.soundnessDD.variants + +import maf.test.deltaDebugging.soundnessDD.SoundnessDDTester +import maf.test.deltaDebugging.soundnessDD.variants.SDCE.SaveSDCE +import maf.test.deltaDebugging.soundnessDD.variants.baseline.{BaselineDD, SaveBaseline} +import maf.test.deltaDebugging.soundnessDD.variants.counting.{CountingDD, SaveCounting} +import maf.test.deltaDebugging.soundnessDD.variants.killLambda.{KillLambdaDD, SaveKillLambda} +import maf.test.deltaDebugging.soundnessDD.variants.fitness.{FitnessDD, SaveFitness} +import maf.test.deltaDebugging.soundnessDD.variants.parallel.{ParallelDD, SaveParallel} +import maf.test.deltaDebugging.soundnessDD.variants.preHalt.SavePreHalt +import maf.test.deltaDebugging.soundnessDD.variants.smartReplacement.SaveSmartReplacement +import maf.test.deltaDebugging.soundnessDD.variants.transforming.{SaveTransforming, SchemeModFLocalAdaptiveTests1, TransformingDD} +import maf.util.benchmarks.Statistics + +import java.io.PrintWriter + +object Evaluate: + def main(args: Array[String]): Unit = { + def reset(): Unit = { + FitnessDD.dataCollector = new DataCollector + BaselineDD.dataCollector = new DataCollector + TransformingDD.dataCollector = new DataCollector + CountingDD.dataCollector = new DataCollector + ParallelDD.dataCollector = new DataCollector + System.gc() + } + + val warmupIterations = 3 + val dataIterations = 5 + + for(i <- 1 to warmupIterations) { + SaveSDCE.save() + } + + println("JIT warm-up done") + + reset() + + for (i <- 1 to dataIterations) { + SaveSDCE.save() + } + } + + def save(tests: List[SoundnessDDTester], dataCollectorString: String, dataCollector: DataCollector): Unit = { + println("writing to disk") + dataCollector.writeTo(dataCollectorString) + } + + def sizeCreateRow(data: List[ReductionData]): Unit = + val reductionPercentages = data.map(r => r.reductionPercentage) + val avgReductionPercentage = Statistics.median(reductionPercentages) + val stdReductionPercentage = Statistics.stddev(reductionPercentages) + + println("median reduction %: " + avgReductionPercentage + " +- " + stdReductionPercentage) + + + def sizeCreateBoxplot(data: List[ReductionData], path: String): Unit = + println("boxplot...") + val reductionPercentages = data.map(d => d.reductionPercentage) + val asString: String = reductionPercentages.map(t => t.toString + "\n").fold("")((t1, t2) => t1 + t2) + val pw = PrintWriter(path) + pw.write(asString) + pw.close() + + def timeCreateRow(data: List[ReductionData], rowName: String): Unit = + val oracleCount = data.map(p => p.oracleTreeSizes.size.toDouble) + val avgOracleCount = Statistics.median(oracleCount) + val stdOracleCount = Statistics.stddev(oracleCount) + + val reductionTime = data.map(p => p.reductionTime.toDouble) + val avgReductionTime = Statistics.median(reductionTime) + val stdReductionTime = Statistics.stddev(reductionTime) + + println(rowName) + println("median oracle ratio: " + avgOracleCount + " +- " + stdOracleCount) + println("median reduction time ratio: " + avgReductionTime + " +- " + stdReductionTime) + + def timeCreateBoxplot(data: List[(ReductionData, ReductionData)], path: String): Unit = + println("boxplot...") + val reductionTimeRatio = data.map(tpl => tpl._1.reductionTime.toDouble / tpl._2.reductionTime) + val asString: String = reductionTimeRatio.map(t => t.toString + "\n").fold("")((t1, t2) => t1 + t2) + val pw = PrintWriter(path) + pw.write(asString) + pw.close() + + def RQ1(baselineData: List[ReductionData], + randomData: List[ReductionData]): Unit = + println("RQ1: output size, Scheme-Reduce vs GTR*") + sizeCreateRow(baselineData) + sizeCreateRow(randomData) + + sizeCreateBoxplot(baselineData, "/Users/turgut/Desktop/cs5/thesis/evaluations/final/RQ1/GTR.txt") + sizeCreateBoxplot(randomData, "/Users/turgut/Desktop/cs5/thesis/evaluations/final/RQ1/SchemeReduce.txt") + + def RQ2(baselineDD: List[ReductionData], randomData: List[ReductionData]): Unit = + println("RQ2: time, Scheme-Reduce vs GTR*") + + timeCreateRow(baselineDD, "baseline") + timeCreateRow(randomData, "random") + + timeCreateBoxplot(randomData.zip(baselineDD), "/Users/turgut/Desktop/cs5/thesis/evaluations/final/RQ2/runtimes.txt") + + def RQ3(randomData: List[ReductionData], transformingData: List[ReductionData]): Unit = + println("RQ3: time, Ordered Scheme-Reduce vs Scheme-Reduce") + + timeCreateRow(randomData, "Scheme-Reduce") + timeCreateRow(transformingData, "Ordered Scheme-Reduce") + + timeCreateBoxplot(randomData.zip(transformingData), "/Users/turgut/Desktop/cs5/thesis/evaluations/final/RQ3/runtimes.txt") + + def RQ4(transformingData: List[ReductionData], Layered: List[ReductionData]): Unit = + println("RQ4: is layering useful?") + + timeCreateRow(transformingData, "Ordered Scheme-Reduce") + timeCreateRow(Layered, "Layered Scheme-Reduce") + + timeCreateBoxplot(transformingData.zip(Layered), "/Users/turgut/Desktop/cs5/thesis/evaluations/final/RQ4/_1runtimes.txt") + + def RQ5(transformingData: List[ReductionData], parallelData: List[ReductionData]): Unit = + println("RQ5: is parallelism useful?") + + timeCreateRow(transformingData, "Ordered Scheme-Reduce") + timeCreateRow(parallelData, "Parallel Scheme-Reduce") + + timeCreateBoxplot(transformingData.zip(parallelData), "/Users/turgut/Desktop/cs5/thesis/evaluations/final/RQ5/runtimes.txt") + + def RQ6(transformingData: List[ReductionData], countingData: List[ReductionData]): Unit = + println("RQ6") + + sizeCreateRow(transformingData) + sizeCreateRow(countingData) + + sizeCreateBoxplot(transformingData, "/Users/turgut/Desktop/cs5/thesis/evaluations/final/RQ6/SchemeReduce.txt") + sizeCreateBoxplot(countingData, "/Users/turgut/Desktop/cs5/thesis/evaluations/final/RQ6/BE.txt") + + def RQ7(transformingData: List[ReductionData], countingData: List[ReductionData]): Unit = + println("RQ7: transforming vs counting") + + timeCreateRow(transformingData, "Ordered Scheme-Reduce") + timeCreateRow(countingData, "BE Ordered Scheme-Reduce") + + timeCreateBoxplot(transformingData.zip(countingData), "/Users/turgut/Desktop/cs5/thesis/evaluations/final/RQ7/runtimes.txt") + + def RQ8(transformingData: List[ReductionData], preHaltData: List[ReductionData]): Unit = + println("RQ8: transforming vs preHalt") + + timeCreateRow(transformingData, "Ordered Scheme-Reduce") + timeCreateRow(preHaltData, "EH Ordered Scheme-Reduce") + + timeCreateBoxplot(transformingData.zip(preHaltData), "/Users/turgut/Desktop/cs5/thesis/evaluations/final/RQ8/runtimes.txt") + + def RQ9(transformingData: List[ReductionData], killLambdaData: List[ReductionData]): Unit = + println("RQ9") + + timeCreateRow(transformingData, "Ordered Scheme-Reduce") + timeCreateRow(killLambdaData, "kill lambda Scheme-Reduce") + + timeCreateBoxplot(transformingData.zip(killLambdaData), "/Users/turgut/Desktop/cs5/thesis/evaluations/final/RQ9/runtimes.txt") + + def RQ10(transformingData: List[ReductionData], UCE_Data: List[ReductionData]): Unit = + println("RQ10") + + timeCreateRow(transformingData, "Ordered Scheme-Reduce") + timeCreateRow(UCE_Data, "UCE Scheme-Reduce") + + timeCreateBoxplot(transformingData.zip(UCE_Data), "/Users/turgut/Desktop/cs5/thesis/evaluations/final/RQ10/runtimes.txt") + +object ReaderAndAnalyzeData { + def main(args: Array[String]): Unit = { + val baselineDataCollector = DataCollector.readObject("baselineDataCollector") + merge(baselineDataCollector) + val randomDatacollector = DataCollector.readObject("randomDataCollector") + merge(randomDatacollector) + val transformingDataCollector = DataCollector.readObject("transformingDataCollector") + merge(transformingDataCollector) + val parallelDataCollector = DataCollector.readObject("parallelDataCollector") + merge(parallelDataCollector) + val LayeredDataCollector = DataCollector.readObject("LayeredDataCollector") + merge(LayeredDataCollector) + + + val countingDataCollector = DataCollector.readObject("countingDataCollector") + merge(countingDataCollector) + val preHaltDataCollector = DataCollector.readObject("preHaltDataCollector") + merge(preHaltDataCollector) + val killLambdaDataCollector = DataCollector.readObject("killLambdaDataCollector") + merge(killLambdaDataCollector) + val UCEDataCollector = DataCollector.readObject("UCEDataCollector") + merge(UCEDataCollector) + + /*Evaluate.RQ1(baselineDataCollector.reductionData, randomDatacollector.reductionData) + Evaluate.RQ2(baselineDataCollector.reductionData, randomDatacollector.reductionData) + Evaluate.RQ3(randomDatacollector.reductionData, transformingDataCollector.reductionData) + Evaluate.RQ4(transformingDataCollector.reductionData, LayeredDataCollector.reductionData) + Evaluate.RQ5(transformingDataCollector.reductionData, parallelDataCollector.reductionData)*/ + + Evaluate.RQ7(transformingDataCollector.reductionData, countingDataCollector.reductionData) + Evaluate.RQ8(transformingDataCollector.reductionData, preHaltDataCollector.reductionData) + Evaluate.RQ9(transformingDataCollector.reductionData, killLambdaDataCollector.reductionData) + Evaluate.RQ10(transformingDataCollector.reductionData, UCEDataCollector.reductionData) + + //Evaluate.RQ6(transformingDataCollector.reductionData, countingDataCollector.reductionData) + } + + /** Merge aggregates several (non-deterministic) time measurements, to increase confidence in our results */ + def merge(collector: DataCollector): Unit = + val grouped = collector.reductionData.groupBy(d => (d.bugName, d.benchmark)) + val it = grouped.values + var aggregatedList: List[ReductionData] = List() + for (i <- it) { + val first = i.head + val agg = i.tail.fold(first)((r1, r2) => { + ReductionData(r1.benchmark, r1.bugName, r1.origSize, r1.reducedSize, r1.reductionPercentage, r1.reductionTime + r2.reductionTime, r1.oracleTreeSizes) + }) + val divideByLength = ReductionData( + agg.benchmark, agg.bugName, agg.origSize, agg.reducedSize, agg.reductionPercentage, agg.reductionTime / i.length, agg.oracleTreeSizes + ) + aggregatedList = aggregatedList.::(divideByLength) + } + + collector.reductionData = aggregatedList +} + diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/SDCE/DeadCodeRemover.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/SDCE/DeadCodeRemover.scala new file mode 100644 index 000000000..1dcc08e25 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/SDCE/DeadCodeRemover.scala @@ -0,0 +1,33 @@ +package maf.test.deltaDebugging.soundnessDD.variants.SDCE + +import maf.core.* +import maf.deltaDebugging.treeDD.transformations.traits.Replacing +import maf.language.scheme.* +import maf.language.scheme.interpreter.ConcreteValues +import maf.language.sexp.* + +import scala.util.Random + +object DeadCodeRemover: + type Benchmark = String + + def removeDeadCode(program: SchemeExp, + dynAnalysis: Set[SchemeExp], + deadCodeTester: SDCE_Tester, + benchmark: Benchmark + ): SchemeExp = + + val deadCodeRemoved = program.map(exp => { + if dynAnalysis.exists(calledExp => calledExp eq exp) then + exp + else SchemeValue(Value.Nil, NoCodeIdentity) + }) + + val oracleResults = deadCodeTester.runAndCompare(deadCodeRemoved, benchmark) + oracleResults match + case Some(failureMsg) => + if failureMsg.nonEmpty then + return deadCodeRemoved + case _ => + + program \ No newline at end of file diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/SDCE/EvaluateSDCE.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/SDCE/EvaluateSDCE.scala new file mode 100644 index 000000000..2edd05b43 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/SDCE/EvaluateSDCE.scala @@ -0,0 +1,19 @@ +package maf.test.deltaDebugging.soundnessDD.variants.SDCE + +import maf.test.deltaDebugging.soundnessDD.variants.Evaluate +import maf.util.benchmarks.Statistics + +object SaveSDCE: + def save(): Unit = { + Evaluate.save( + List( + new SchemeModFLocalAdaptiveTests1, + new SchemeModFLocalAdaptiveTests2, + new SchemeModFLocalAdaptiveTests3, + new SchemeModFLocalAdaptiveTests4, + new SchemeModFLocalAdaptiveTests5 + ), + "UCEDataCollector", + SDCE_DD.dataCollector + ) + } diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/SDCE/SDCE_DD.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/SDCE/SDCE_DD.scala new file mode 100644 index 000000000..3f44a8319 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/SDCE/SDCE_DD.scala @@ -0,0 +1,60 @@ +package maf.test.deltaDebugging.soundnessDD.variants.SDCE + +import maf.deltaDebugging.treeDD.SchemeReduce +import maf.deltaDebugging.treeDD.transformations.TransformationManager +import maf.language.scheme.SchemeExp +import maf.language.scheme.interpreter.ConcreteValues +import maf.test.deltaDebugging.soundnessDD.variants.* + +object SDCE_DD: + var dataCollector = new DataCollector + var bugName = "noneYet" + var problematicValue: Option[ConcreteValues.Value] = None + var dynAnalysis: Set[SchemeExp] = Set() + + def reduce(program: SchemeExp, + soundnessTester: SDCE_Tester, + benchmark: String): Unit = + + var oracleInvocations = 1 //1, not 0, due to initial call to DeadCodeRemover + var oracleTreeSizes: List[Int] = List() + + val startTime = System.currentTimeMillis() + + val reduced = SchemeReduce.reduce( + program, + p => { + oracleInvocations += 1 + oracleTreeSizes = oracleTreeSizes.::(p.size) + soundnessTester.runAndCompare_(p, benchmark, problematicValue) match + case Some(failureMsg, _, set) => + dynAnalysis = set + p.findUndefinedVariables().isEmpty && failureMsg.nonEmpty + + case None => + false + }, + identity, + TransformationManager.allTransformations, /** Uses all Transformations! */ + Some(newCandidate => { + oracleInvocations += 1 + oracleTreeSizes = oracleTreeSizes.::(newCandidate.size) + Some(DeadCodeRemover.removeDeadCode(newCandidate, dynAnalysis, soundnessTester, benchmark)) + }) + ) + + val endTime = System.currentTimeMillis() + val totalTime = endTime - startTime + + val reductionData = ReductionData( + benchmark = benchmark, + bugName = bugName, + origSize = program.size, + reducedSize = reduced.size, + reductionTime = totalTime, + reductionPercentage = 1 - (reduced.size.toDouble / program.size), + oracleTreeSizes = oracleTreeSizes + ) + + dataCollector.addReductionData(reductionData) + diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/SDCE/SDCE_Tester.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/SDCE/SDCE_Tester.scala new file mode 100644 index 000000000..85fb9b287 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/SDCE/SDCE_Tester.scala @@ -0,0 +1,95 @@ +package maf.test.deltaDebugging.soundnessDD.variants.SDCE + +import maf.core.Identity +import maf.language.scheme.SchemeExp +import maf.language.scheme.interpreter.ConcreteValues.Value +import maf.language.scheme.interpreter.{ConcreteValues, DeadCodeInterpreter, FileIO, PreHaltInterpreter, SDCE_Interpreter, SchemeInterpreter} +import maf.test.SlowTest +import maf.test.deltaDebugging.soundnessDD.SoundnessDDTester +import maf.util.Reader + +trait SDCE_Tester extends SoundnessDDTester { + def bugName: String + + def compareResults_(analysis: Analysis, concreteResults: Map[Identity, Set[Value]]): (String, Option[Value]) = + val analysisResults = analysis.resultsPerIdn + concreteResults.foreach { case (idn, concreteValues) => + val abstractValues = analysisResults.getOrElse(idn, Set.empty) + concreteValues.foreach { concreteValue => + if !abstractValues.exists(checkSubsumption(analysis)(concreteValue, _)) then + return + ( + s""" + | Result at $idn is unsound: + | - concrete value: $concreteValue + | - abstract values: ${analysis.lattice.join(abstractValues)} + """.stripMargin, + Some(concreteValue) + ) + } + } + ("", None) + + def evalProgram(program: SchemeExp, + benchmark: Benchmark, + problematicValue: Option[Value], + anl: Analysis): (Map[Identity, Set[Value]], Set[SchemeExp]) = + var idnResults = Map[Identity, Set[Value]]().withDefaultValue(Set()) + val soundnessTest: () => Boolean = () => compareResults_(anl, idnResults)._1.nonEmpty + val timeout = concreteTimeout(benchmark) + val times = concreteRuns(benchmark) + val addResult: (Identity, ConcreteValues.Value) => Unit = (i, v) => idnResults += (i -> (idnResults(i) + v)) + var dynAnalysis: Set[SchemeExp] = Set() + val interpreter: SchemeInterpreter = + problematicValue match + case Some(value) => + new SDCE_Interpreter( + addResult, + io = new FileIO(Map("input.txt" -> "foo\nbar\nbaz", "output.txt" -> "")), + value, + soundnessTest) + case _ => + new DeadCodeInterpreter(addResult, io = new FileIO(Map("input.txt" -> "foo\nbar\nbaz", "output.txt" -> ""))) + for _ <- 1 to times do + interpreter match + case i: DeadCodeInterpreter => + dynAnalysis = i.runAndIdentifyDeadCode(program, timeout)._2 + case i: SDCE_Interpreter => + dynAnalysis = i.runAndIdentifyDeadCode(program, timeout)._2 + case _ => throw new Exception() + (idnResults, dynAnalysis) + + def runAndCompare_(program: SchemeExp, benchmark: Benchmark, problematicValue: Option[Value]): + Option[(String, Option[Value], Set[SchemeExp])] = { + try + val anl = runAnalysis(program, benchmark) + val concreteResults = + evalProgram(program, + benchmark, + problematicValue, + anl) + // analyze the program using a ModF analysis + + // check if the analysis results soundly (over-)approximate the concrete results + val compared = compareResults_(anl, concreteResults._1) + + Some(compared._1, compared._2, concreteResults._2) + catch case exc: Throwable => + None + } + + override def onBenchmark(benchmark: Benchmark): Unit = + println("Transforming >>> running benchmark: " + benchmark) + // load the benchmark program + val content = Reader.loadFile(benchmark) + val program = parseProgram(content, benchmark) + + runAndCompare_(program, benchmark, None) match + case Some((failureMsg, problematicValue, dynAnalysis)) => + if failureMsg.nonEmpty then + val postDCE = DeadCodeRemover.removeDeadCode(program, dynAnalysis, this, benchmark) + SDCE_DD.problematicValue = problematicValue + SDCE_DD.bugName = bugName + SDCE_DD.reduce(postDCE, this, benchmark) + case _ => +} diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/SDCE/soundnessTests.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/SDCE/soundnessTests.scala new file mode 100644 index 000000000..1d202d469 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/SDCE/soundnessTests.scala @@ -0,0 +1,78 @@ +package maf.test.deltaDebugging.soundnessDD.variants.SDCE + +import maf.core.Position +import maf.language.scheme.primitives.SchemePrelude +import maf.language.scheme.{SchemeExp, SchemeMutableVarBoxer, SchemeParser} +import maf.modular.scheme.SchemeConstantPropagationDomain +import maf.modular.scheme.modflocal.{SchemeModFLocal, SchemeModFLocalAnalysisResults, SchemeModFLocalNoSensitivity} +import maf.modular.worklist.FIFOWorklistAlgorithm +import maf.test.deltaDebugging.realBugs.* +import maf.test.{AllSequentialBenchmarks, DDBenchmarks, RandomSequentialBenchmarks, VariousSequentialBenchmarks} + +trait SchemeModFLocalSoundnessTests extends SDCE_Tester with DDBenchmarks: + //override def benchmarks: Set[Benchmark] = Set("test/R5RS/various/SICP-compiler.scm") + override def parseProgram(txt: String, benchmark: String): SchemeExp = + val parsed = SchemeParser.parse(txt, Position.withSourcePath(benchmark)) + val prelud = SchemePrelude.addPrelude(parsed, incl = Set("__toplevel_cons", "__toplevel_cdr", "__toplevel_set-cdr!")) + val transf = SchemeMutableVarBoxer.transform(prelud) + SchemeParser.rename(SchemeParser.undefine(transf)) + +class SchemeModFLocalAdaptiveTests1 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug1" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug1 + +class SchemeModFLocalAdaptiveTests2 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug2" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug2 + +class SchemeModFLocalAdaptiveTests3 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug3" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug3 + +class SchemeModFLocalAdaptiveTests4 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug4" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug4 + +class SchemeModFLocalAdaptiveTests5 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug5" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug5 diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/baseline/BaselineDD.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/baseline/BaselineDD.scala similarity index 58% rename from code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/baseline/BaselineDD.scala rename to code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/baseline/BaselineDD.scala index dd1f7df17..d5f09f149 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/baseline/BaselineDD.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/baseline/BaselineDD.scala @@ -1,9 +1,9 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.baseline +package maf.test.deltaDebugging.soundnessDD.variants.baseline -import maf.deltaDebugging.gtr.GTR -import maf.deltaDebugging.gtr.transformations.TransformationManager +import maf.deltaDebugging.treeDD.transformations.TransformationManager +import maf.deltaDebugging.treeDD.variants.GTR import maf.language.scheme.SchemeExp -import maf.test.deltaDebugging.soundnessDD.evaluation.* +import maf.test.deltaDebugging.soundnessDD.variants.* object BaselineDD: var dataCollector = new DataCollector @@ -14,8 +14,7 @@ object BaselineDD: benchmark: String): Unit = var oracleInvocations = 0 - var runTimes: List[Long] = List() - var analysisTimes: List[Long] = List() + var oracleTreeSizes: List[Int] = List() val startTime = System.currentTimeMillis() @@ -23,33 +22,28 @@ object BaselineDD: program, p => { oracleInvocations += 1 + oracleTreeSizes = oracleTreeSizes.::(p.size) soundnessTester.runCompareAndtime(p, benchmark) match case (Some(failureMsg), (runTime, analysisTime)) => - runTimes = runTimes.::(runTime) - analysisTimes = analysisTimes.::(analysisTime) p.findUndefinedVariables().isEmpty && failureMsg.nonEmpty case (None, (runTime, analysisTime)) => - runTimes = runTimes.::(runTime) - analysisTimes = analysisTimes.::(analysisTime) false }, - identity, TransformationManager.genericTransformations ) val endTime = System.currentTimeMillis() + val totalReductionTime = endTime - startTime val reductionData = ReductionData( benchmark = benchmark, bugName = bugName, origSize = program.size, reducedSize = reduced.size, - reductionTime = endTime - startTime, - interpreterTime = runTimes.sum, - analysisTime = analysisTimes.sum, - interpreterTimes = runTimes, - analysisTimes = analysisTimes + reductionTime = totalReductionTime, + reductionPercentage = 1 - (reduced.size.toDouble / program.size), + oracleTreeSizes = oracleTreeSizes ) dataCollector.addReductionData(reductionData) diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/baseline/BaselineTester.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/baseline/BaselineTester.scala new file mode 100644 index 000000000..777aa6cf1 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/baseline/BaselineTester.scala @@ -0,0 +1,26 @@ +package maf.test.deltaDebugging.soundnessDD.variants.baseline + +import maf.core.Identity +import maf.language.scheme.SchemeExp +import maf.language.scheme.interpreter.ConcreteValues.Value +import maf.test.SlowTest +import maf.test.deltaDebugging.soundnessDD.SoundnessDDTester +import maf.util.Reader + +trait BaselineTester extends SoundnessDDTester { + + def bugName: String + + override def onBenchmark(benchmark: Benchmark): Unit = + println("Baseline >>> running benchmark: " + benchmark) + // load the benchmark program + val content = Reader.loadFile(benchmark) + val program = parseProgram(content, benchmark) + + runCompareAndtime(program, benchmark) match + case (Some(failureMsg), _) => + if failureMsg.nonEmpty then + BaselineDD.bugName = bugName + BaselineDD.reduce(program, this, benchmark) + case _ => +} diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/baseline/EvaluateBaseline.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/baseline/EvaluateBaseline.scala similarity index 55% rename from code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/baseline/EvaluateBaseline.scala rename to code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/baseline/EvaluateBaseline.scala index 8ce72b1a8..e63f4b7e8 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/baseline/EvaluateBaseline.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/baseline/EvaluateBaseline.scala @@ -1,6 +1,7 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.baseline +package maf.test.deltaDebugging.soundnessDD.variants.baseline -import maf.test.deltaDebugging.soundnessDD.evaluation.Evaluate +import maf.test.DDBenchmarks +import maf.test.deltaDebugging.soundnessDD.variants.Evaluate import maf.util.benchmarks.Statistics object SaveBaseline: @@ -18,8 +19,9 @@ object SaveBaseline: ) } -object ReadAndAnalyzeBaseline: - def main(args: Array[String]): Unit = { - Evaluate.readAndAnalyzeData("baselineDataCollector") - } +object Wrapper extends DDBenchmarks: + override protected def onBenchmark(b: Wrapper.Benchmark): Unit = None + def main(args: Array[Benchmark]): Unit = { + benchmarks.foreach(println) + } diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/baseline/soundnessTests.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/baseline/soundnessTests.scala similarity index 86% rename from code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/baseline/soundnessTests.scala rename to code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/baseline/soundnessTests.scala index 09daabeb5..df73bcbf1 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/baseline/soundnessTests.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/baseline/soundnessTests.scala @@ -1,4 +1,4 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.baseline +package maf.test.deltaDebugging.soundnessDD.variants.baseline import maf.language.scheme.primitives.SchemePrelude import maf.language.scheme.{SchemeExp, SchemeMutableVarBoxer, SchemeParser} @@ -6,10 +6,10 @@ import maf.modular.scheme.SchemeConstantPropagationDomain import maf.modular.scheme.modflocal.* import maf.modular.worklist.FIFOWorklistAlgorithm import maf.test.deltaDebugging.realBugs.* -import maf.test.{CertainVariousSequentialBenchmarks, RandomSequentialBenchmarks, VariousSequentialBenchmarks} +import maf.test.{DDBenchmarks, RandomSequentialBenchmarks, VariousSequentialBenchmarks} import maf.core.Position -trait SchemeModFLocalSoundnessTests extends BaselineTester with CertainVariousSequentialBenchmarks: +trait SchemeModFLocalSoundnessTests extends BaselineTester with DDBenchmarks: //override def benchmarks: Set[Benchmark] = Set("test/R5RS/various/SICP-compiler.scm") override def parseProgram(txt: String, benchmark: String): SchemeExp = val parsed = SchemeParser.parse(txt, Position.withSourcePath(benchmark)) @@ -20,7 +20,7 @@ trait SchemeModFLocalSoundnessTests extends BaselineTester with CertainVariousSe class SchemeModFLocalAdaptiveTests1 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug1" + override def bugName: String = "RealBug1" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain @@ -32,7 +32,7 @@ class SchemeModFLocalAdaptiveTests1 extends SchemeModFLocalSoundnessTests: class SchemeModFLocalAdaptiveTests2 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug2" + override def bugName: String = "RealBug2" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain @@ -44,7 +44,7 @@ class SchemeModFLocalAdaptiveTests2 extends SchemeModFLocalSoundnessTests: class SchemeModFLocalAdaptiveTests3 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug3" + override def bugName: String = "RealBug3" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain @@ -56,7 +56,7 @@ class SchemeModFLocalAdaptiveTests3 extends SchemeModFLocalSoundnessTests: class SchemeModFLocalAdaptiveTests4 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug4" + override def bugName: String = "RealBug4" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain @@ -68,7 +68,7 @@ class SchemeModFLocalAdaptiveTests4 extends SchemeModFLocalSoundnessTests: class SchemeModFLocalAdaptiveTests5 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug5" + override def bugName: String = "RealBug5" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/counting/CountingDD.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/counting/CountingDD.scala similarity index 59% rename from code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/counting/CountingDD.scala rename to code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/counting/CountingDD.scala index 2ae6072fb..279c596e9 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/counting/CountingDD.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/counting/CountingDD.scala @@ -1,9 +1,9 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.counting +package maf.test.deltaDebugging.soundnessDD.variants.counting -import maf.deltaDebugging.gtr.GTR -import maf.deltaDebugging.gtr.transformations.TransformationManager +import maf.deltaDebugging.treeDD.SchemeReduce +import maf.deltaDebugging.treeDD.transformations.TransformationManager import maf.language.scheme.SchemeExp -import maf.test.deltaDebugging.soundnessDD.evaluation.* +import maf.test.deltaDebugging.soundnessDD.variants.* object CountingDD: var dataCollector = new DataCollector @@ -15,25 +15,21 @@ object CountingDD: benchmark: String): Unit = var oracleInvocations = 0 - var runTimes: List[Long] = List() - var analysisTimes: List[Long] = List() + var oracleTreeSizes: List[Int] = List() val startTime = System.currentTimeMillis() - val reduced = GTR.reduce( + val reduced = SchemeReduce.reduce( program, p => { oracleInvocations += 1 + oracleTreeSizes = oracleTreeSizes.::(p.size) soundnessTester.runCompareAndtimeWithMaxSteps(p, benchmark, maxSteps) match case (Some((failureMsg, evalSteps)), (runTime, analysisTime)) => - runTimes = runTimes.::(runTime) //collect - analysisTimes = analysisTimes.::(analysisTime) //collect maxSteps = evalSteps p.findUndefinedVariables().isEmpty && failureMsg.nonEmpty case (None, (runTime, analysisTime)) => - runTimes = runTimes.::(runTime) - analysisTimes = analysisTimes.::(analysisTime) false }, identity, @@ -41,17 +37,16 @@ object CountingDD: ) val endTime = System.currentTimeMillis() - + val totalReductionTime = endTime - startTime + val reductionData = ReductionData( benchmark = benchmark, bugName = bugName, origSize = program.size, reducedSize = reduced.size, - reductionTime = endTime - startTime, - interpreterTime = runTimes.sum, - analysisTime = analysisTimes.sum, - interpreterTimes = runTimes, - analysisTimes = analysisTimes + reductionTime = totalReductionTime, + reductionPercentage = 1 - (reduced.size.toDouble / program.size), + oracleTreeSizes = oracleTreeSizes ) dataCollector.addReductionData(reductionData) diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/counting/CountingTester.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/counting/CountingTester.scala similarity index 80% rename from code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/counting/CountingTester.scala rename to code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/counting/CountingTester.scala index d82e9f52d..f9a327eca 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/counting/CountingTester.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/counting/CountingTester.scala @@ -1,4 +1,4 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.counting +package maf.test.deltaDebugging.soundnessDD.variants.counting import maf.core.Identity import maf.language.scheme.SchemeExp @@ -6,16 +6,16 @@ import maf.language.scheme.interpreter.ConcreteValues.Value import maf.language.scheme.interpreter.{ConcreteValues, FileIO, SchemeInterpreter} import maf.test.SlowTest import maf.test.deltaDebugging.soundnessDD.{SoundnessCountingDDTester, SoundnessDDTester} -import maf.test.deltaDebugging.soundnessDD.evaluation.baseline.BaselineDD +import maf.test.deltaDebugging.soundnessDD.variants.baseline.BaselineDD import maf.test.modular.scheme.SchemeSoundnessTests import maf.util.Reader import maf.util.benchmarks.Timer trait CountingTester extends SoundnessCountingDDTester { - val bugName: String + def bugName: String override def onBenchmark(benchmark: Benchmark): Unit = - property(s"Analysis of $benchmark using $name is sound.", SlowTest) { + println("Counting >>> running benchmark: " + benchmark) // load the benchmark program val content = Reader.loadFile(benchmark) val program = parseProgram(content, benchmark) @@ -26,5 +26,4 @@ trait CountingTester extends SoundnessCountingDDTester { CountingDD.bugName = bugName CountingDD.reduce(program, this, benchmark) case _ => - } } diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/counting/EvaluateCounting.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/counting/EvaluateCounting.scala similarity index 59% rename from code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/counting/EvaluateCounting.scala rename to code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/counting/EvaluateCounting.scala index d2242102e..648d95fe6 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/counting/EvaluateCounting.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/counting/EvaluateCounting.scala @@ -1,6 +1,6 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.counting +package maf.test.deltaDebugging.soundnessDD.variants.counting -import maf.test.deltaDebugging.soundnessDD.evaluation.Evaluate +import maf.test.deltaDebugging.soundnessDD.variants.Evaluate import maf.util.benchmarks.Statistics object SaveCounting: @@ -17,12 +17,5 @@ object SaveCounting: CountingDD.dataCollector ) } - -object ReadAndAnalyzeCounting: - def main(args: Array[String]): Unit = { - Evaluate.readAndAnalyzeData( - "countingDataCollector" - ) - } diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/counting/soundnessTests.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/counting/soundnessTests.scala similarity index 86% rename from code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/counting/soundnessTests.scala rename to code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/counting/soundnessTests.scala index 52aae196f..7bb58c5ec 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/counting/soundnessTests.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/counting/soundnessTests.scala @@ -1,4 +1,4 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.counting +package maf.test.deltaDebugging.soundnessDD.variants.counting import maf.core.Position import maf.language.scheme.{SchemeExp, SchemeMutableVarBoxer, SchemeParser} @@ -6,10 +6,10 @@ import maf.language.scheme.primitives.SchemePrelude import maf.modular.scheme.SchemeConstantPropagationDomain import maf.modular.scheme.modflocal.{SchemeModFLocal, SchemeModFLocalAnalysisResults, SchemeModFLocalNoSensitivity} import maf.modular.worklist.FIFOWorklistAlgorithm -import maf.test.{AllSequentialBenchmarks, CertainVariousSequentialBenchmarks, RandomSequentialBenchmarks, VariousSequentialBenchmarks} +import maf.test.{AllSequentialBenchmarks, DDBenchmarks, RandomSequentialBenchmarks, VariousSequentialBenchmarks} import maf.test.deltaDebugging.realBugs.* -trait SchemeModFLocalSoundnessTests extends CountingTester with CertainVariousSequentialBenchmarks: +trait SchemeModFLocalSoundnessTests extends CountingTester with DDBenchmarks: //override def benchmarks: Set[Benchmark] = Set("test/R5RS/various/SICP-compiler.scm") override def parseProgram(txt: String, benchmark: String): SchemeExp = val parsed = SchemeParser.parse(txt, Position.withSourcePath(benchmark)) @@ -20,7 +20,7 @@ trait SchemeModFLocalSoundnessTests extends CountingTester with CertainVariousSe class SchemeModFLocalAdaptiveTests1 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug1" + override def bugName = "RealBug1" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain @@ -32,7 +32,7 @@ class SchemeModFLocalAdaptiveTests1 extends SchemeModFLocalSoundnessTests: class SchemeModFLocalAdaptiveTests2 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug2" + override def bugName = "RealBug2" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain @@ -44,7 +44,7 @@ class SchemeModFLocalAdaptiveTests2 extends SchemeModFLocalSoundnessTests: class SchemeModFLocalAdaptiveTests3 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug3" + override def bugName = "RealBug3" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain @@ -56,7 +56,7 @@ class SchemeModFLocalAdaptiveTests3 extends SchemeModFLocalSoundnessTests: class SchemeModFLocalAdaptiveTests4 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug4" + override def bugName = "RealBug4" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain @@ -68,7 +68,7 @@ class SchemeModFLocalAdaptiveTests4 extends SchemeModFLocalSoundnessTests: class SchemeModFLocalAdaptiveTests5 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug5" + override def bugName = "RealBug5" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/fitness/EvaluateFitness.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/fitness/EvaluateFitness.scala new file mode 100644 index 000000000..e198b1b14 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/fitness/EvaluateFitness.scala @@ -0,0 +1,29 @@ +package maf.test.deltaDebugging.soundnessDD.variants.fitness + +import maf.deltaDebugging.treeDD.transformations.TransformationManager +import maf.test.DDBenchmarks +import maf.test.deltaDebugging.soundnessDD.variants.Evaluate +import maf.util.benchmarks.Statistics + +object SaveFitness: + def save(): Unit = { + TransformationManager.allTransformations.foreach(t => { + println("pre " + t.name + ": " + (t.getHits, t.getInvocations)) + }) + + Evaluate.save( + List( + new SchemeModFLocalAdaptiveTests1, + new SchemeModFLocalAdaptiveTests2, + new SchemeModFLocalAdaptiveTests3, + new SchemeModFLocalAdaptiveTests4, + new SchemeModFLocalAdaptiveTests5 + ), + "randomDataCollector", + FitnessDD.dataCollector + ) + + TransformationManager.allTransformations.foreach(t => { + println("post " + t.name + ": " + (t.getHits, t.getInvocations)) + }) + } diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/fitness/FitnessDD.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/fitness/FitnessDD.scala new file mode 100644 index 000000000..b17ac7193 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/fitness/FitnessDD.scala @@ -0,0 +1,53 @@ +package maf.test.deltaDebugging.soundnessDD.variants.fitness + +import maf.deltaDebugging.treeDD.SchemeReduce +import maf.deltaDebugging.treeDD.transformations.TransformationManager +import maf.language.scheme.SchemeExp +import maf.test.deltaDebugging.soundnessDD.variants.* + +import scala.util.Random + +object FitnessDD: + var dataCollector = new DataCollector + var bugName = "noneYet" + + def reduce(program: SchemeExp, + soundnessTester: FitnessTester, + benchmark: String): Unit = + + var oracleInvocations = 0 + var oracleTreeSizes: List[Int] = List() + + val startTime = System.currentTimeMillis() + + val reduced = SchemeReduce.reduce( + program, + p => { + oracleInvocations += 1 + oracleTreeSizes = oracleTreeSizes.::(p.size) + soundnessTester.runCompareAndtime(p, benchmark) match + case (Some(failureMsg), _) => + p.findUndefinedVariables().isEmpty && failureMsg.nonEmpty + + case (None, _) => + false + }, + identity, + Random.shuffle(TransformationManager.allTransformations) + ) + + val endTime = System.currentTimeMillis() + val totalTime = endTime - startTime + + val reductionData = ReductionData( + benchmark = benchmark, + bugName = bugName, + origSize = program.size, + reducedSize = reduced.size, + reductionTime = totalTime, + reductionPercentage = 1 - (reduced.size.toDouble / program.size), + oracleTreeSizes = oracleTreeSizes + ) + + dataCollector.addReductionData(reductionData) + diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/fitness/FitnessTester.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/fitness/FitnessTester.scala new file mode 100644 index 000000000..1a8031086 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/fitness/FitnessTester.scala @@ -0,0 +1,26 @@ +package maf.test.deltaDebugging.soundnessDD.variants.fitness + +import maf.core.Identity +import maf.language.scheme.SchemeExp +import maf.language.scheme.interpreter.ConcreteValues.Value +import maf.test.SlowTest +import maf.test.deltaDebugging.soundnessDD.SoundnessDDTester +import maf.util.Reader + +trait FitnessTester extends SoundnessDDTester { + def bugName: String + + override def onBenchmark(benchmark: Benchmark): Unit = + println("Fitness >>> running benchmark: " + benchmark) + // load the benchmark program + val content = Reader.loadFile(benchmark) + val program = parseProgram(content, benchmark) + + runCompareAndtime(program, benchmark) match + case (Some(failureMsg), _) => + if failureMsg.nonEmpty then + FitnessDD.bugName = bugName + FitnessDD.reduce(program, this, benchmark) + case _ => + +} diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/fitness/soundnessTests.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/fitness/soundnessTests.scala new file mode 100644 index 000000000..df00e00d1 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/fitness/soundnessTests.scala @@ -0,0 +1,78 @@ +package maf.test.deltaDebugging.soundnessDD.variants.fitness + +import maf.core.Position +import maf.language.scheme.{SchemeExp, SchemeMutableVarBoxer, SchemeParser} +import maf.language.scheme.primitives.SchemePrelude +import maf.modular.scheme.SchemeConstantPropagationDomain +import maf.modular.scheme.modflocal.{SchemeModFLocal, SchemeModFLocalAnalysisResults, SchemeModFLocalNoSensitivity} +import maf.modular.worklist.FIFOWorklistAlgorithm +import maf.test.deltaDebugging.realBugs.* +import maf.test.{AllSequentialBenchmarks, DDBenchmarks, RandomSequentialBenchmarks, SuccesRateBenchmarks, VariousSequentialBenchmarks} + +trait SchemeModFLocalSoundnessTests extends FitnessTester with DDBenchmarks: + //override def benchmarks: Set[Benchmark] = Set("test/R5RS/various/SICP-compiler.scm") + override def parseProgram(txt: String, benchmark: String): SchemeExp = + val parsed = SchemeParser.parse(txt, Position.withSourcePath(benchmark)) + val prelud = SchemePrelude.addPrelude(parsed, incl = Set("__toplevel_cons", "__toplevel_cdr", "__toplevel_set-cdr!")) + val transf = SchemeMutableVarBoxer.transform(prelud) + SchemeParser.rename(SchemeParser.undefine(transf)) + +class SchemeModFLocalAdaptiveTests1 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug1" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug1 + +class SchemeModFLocalAdaptiveTests2 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug2" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug2 + +class SchemeModFLocalAdaptiveTests3 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug3" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug3 + +class SchemeModFLocalAdaptiveTests4 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug4" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug4 + +class SchemeModFLocalAdaptiveTests5 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug5" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug5 diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/killLambda/EvaluateKillLambda.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/killLambda/EvaluateKillLambda.scala new file mode 100644 index 000000000..9bc26b280 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/killLambda/EvaluateKillLambda.scala @@ -0,0 +1,18 @@ +package maf.test.deltaDebugging.soundnessDD.variants.killLambda + +import maf.test.deltaDebugging.soundnessDD.variants.Evaluate + +object SaveKillLambda: + def save(): Unit = { + Evaluate.save( + List( + new SchemeModFLocalAdaptiveTests1, + new SchemeModFLocalAdaptiveTests2, + new SchemeModFLocalAdaptiveTests3, + new SchemeModFLocalAdaptiveTests4, + new SchemeModFLocalAdaptiveTests5 + ), + "killLambdaDataCollector", + KillLambdaDD.dataCollector + ) + } diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/killLambda/KillLambdaDD.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/killLambda/KillLambdaDD.scala new file mode 100644 index 000000000..3272f072d --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/killLambda/KillLambdaDD.scala @@ -0,0 +1,58 @@ +package maf.test.deltaDebugging.soundnessDD.variants.killLambda + +import maf.deltaDebugging.treeDD.SchemeReduce +import maf.deltaDebugging.treeDD.transformations.TransformationManager +import maf.language.scheme.interpreter.ConcreteValues.Value +import maf.language.scheme.{SchemeExp, SchemeFuncall, SchemeLambda} +import maf.test.deltaDebugging.soundnessDD.variants.* + +object KillLambdaDD: + var dataCollector = new DataCollector + var bugName = "noneYet" + + def reduce(startProgram: SchemeExp, + program: SchemeExp, + soundnessTester: KillLambdaTester, + benchmark: String, + dynAnalysis: Map[SchemeLambda, (Set[(SchemeFuncall, Value)], Int)]): Unit = + + var oracleInvocations = 0 + var oracleTreeSizes: List[Int] = List() + + val startTime = System.currentTimeMillis() + + val killResult = LambdaKiller.killLambdas(program, dynAnalysis, soundnessTester, benchmark) + val postLambdaKills = killResult._1 + oracleTreeSizes = killResult._2 + + val reduced = SchemeReduce.reduce( + postLambdaKills, + p => { + oracleInvocations += 1 + oracleTreeSizes = oracleTreeSizes.::(p.size) + soundnessTester.runAndFindLambdas(p, benchmark) match + case (Some((failureMsg, calledLambdas)), _) => + //topCalledLambdas = calledLambdas + p.findUndefinedVariables().isEmpty && failureMsg.nonEmpty + + case (None, (runTime, analysisTime)) => + false + }, + identity, + TransformationManager.allTransformations, + ) + + val endTime = System.currentTimeMillis() + val totalReductionTime = endTime - startTime + + val reductionData = ReductionData( + benchmark = benchmark, + bugName = bugName, + origSize = startProgram.size, + reducedSize = reduced.size, + reductionTime = totalReductionTime, + reductionPercentage = 1 - (reduced.size.toDouble / startProgram.size), + oracleTreeSizes = oracleTreeSizes + ) + + dataCollector.addReductionData(reductionData) diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/killLambda/KillLambdaTester.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/killLambda/KillLambdaTester.scala new file mode 100644 index 000000000..634e76a34 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/killLambda/KillLambdaTester.scala @@ -0,0 +1,96 @@ +package maf.test.deltaDebugging.soundnessDD.variants.killLambda + +import maf.core.{Identity, IdentityWithData, NoCodeIdentity, NoCodeIdentityDebug, SimpleIdentity} +import maf.language.scheme.{SchemeExp, SchemeFuncall, SchemeLambda, SchemeValue, SchemeVar} +import maf.language.scheme.interpreter.ConcreteValues.Value +import maf.language.scheme.interpreter.{ConcreteValues, FileIO, IO, KillLambdaInterpreter, SchemeInterpreter} +import maf.language.sexp +import maf.modular.worklist.SequentialWorklistAlgorithm +import maf.test.SlowTest +import maf.test.deltaDebugging.soundnessDD.variants.baseline.BaselineDD +import maf.test.deltaDebugging.soundnessDD.SoundnessDDTester +import maf.test.modular.scheme.SchemeSoundnessTests +import maf.util.Reader +import maf.util.benchmarks.Timer + +trait KillLambdaTester extends SoundnessDDTester { + def bugName: String + + override def createInterpreter(addResult: (Identity, Value) => Unit, io: IO, benchmark: Benchmark): KillLambdaInterpreter = + new KillLambdaInterpreter(addResult, io) + + def evalProgramAndFindLambdas(program: SchemeExp, benchmark: Benchmark): + (Map[Identity, Set[Value]], Map[SchemeLambda, (Set[(SchemeFuncall, Value)], Int)]) = + var idnResults = Map[Identity, Set[Value]]().withDefaultValue(Set()) + val timeout = concreteTimeout(benchmark) + val times = concreteRuns(benchmark) + val addResult: (Identity, ConcreteValues.Value) => Unit = (i, v) => idnResults += (i -> (idnResults(i) + v)) + val interpreter: KillLambdaInterpreter = createInterpreter(addResult, io = new FileIO(Map("input.txt" -> "foo\nbar\nbaz", "output.txt" -> "")), benchmark) + var dynAnalysis: Map[SchemeLambda, (Set[(SchemeFuncall, Value)], Int)] = Map() + for _ <- 1 to times do + val (ellapsed, _) = Timer.time({ + val tpl = interpreter.runAndIdentifyCalledLambdas(program, timeout) + dynAnalysis = tpl._2 + }) + SchemeSoundnessTests.logEllapsed(this, benchmark, ellapsed, concrete = true) + (idnResults, dynAnalysis) + + def runAndFindLambdas(program: SchemeExp, benchmark: Benchmark): + (Option[(String, + Map[SchemeLambda, (Set[(SchemeFuncall, Value)], Int)], + )], (Long, Long)) = + var evalStartTime: Long = 0 + var evalRunTime: Long = 0 + var evalEndTime: Long = 0 + + var analysisStartTime: Long = 0 + var analysisRuntime: Long = 0 + var analysisEndTime: Long = 0 + + var excThrown: Boolean = false + + var concreteResults: Option[Map[Identity, Set[Value]]] = None + var anl: Option[Analysis] = None + var calledLambdas: Option[Map[SchemeLambda, (Set[(SchemeFuncall, Value)], Int)]] = None + + try + evalStartTime = System.currentTimeMillis() + val tpl = evalProgramAndFindLambdas(program, benchmark) + calledLambdas = Some(tpl._2) + concreteResults = Some(tpl._1) + evalEndTime = System.currentTimeMillis() + evalRunTime = evalEndTime - evalStartTime + catch case exc: Throwable => + excThrown = true + evalEndTime = System.currentTimeMillis() + evalRunTime = evalEndTime - evalStartTime + + try + analysisStartTime = System.currentTimeMillis() + anl = Some(runAnalysis(program, benchmark)) + analysisEndTime = System.currentTimeMillis() + analysisRuntime = analysisEndTime - analysisStartTime + catch case exc: Throwable => + excThrown = true + analysisEndTime = System.currentTimeMillis() + analysisRuntime = analysisEndTime - analysisStartTime + + if excThrown then + (None, (evalRunTime, analysisRuntime)) + else (Some((compareResults(anl.get, concreteResults.get), + calledLambdas.get, + )), (evalRunTime, analysisRuntime)) + + override def onBenchmark(benchmark: Benchmark): Unit = + println("Kill Lambda >>> running benchmark: " + benchmark) + // load the benchmark program + val content = Reader.loadFile(benchmark) + val program = parseProgram(content, benchmark) + + runAndFindLambdas(program, benchmark) match + case (Some((failureMsg, dynAnalysis)), _) => + if failureMsg.nonEmpty then + KillLambdaDD.bugName = bugName + KillLambdaDD.reduce(program, program, this, benchmark, dynAnalysis) + case _ => +} diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/killLambda/LambdaKiller.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/killLambda/LambdaKiller.scala new file mode 100644 index 000000000..5da8a9144 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/killLambda/LambdaKiller.scala @@ -0,0 +1,91 @@ +package maf.test.deltaDebugging.soundnessDD.variants.killLambda + +import maf.language.scheme.{SchemeExp, SchemeFuncall, SchemeLambda, SchemeValue, SchemeVar, SchemeVarExp} +import maf.language.scheme.interpreter.ConcreteValues +import maf.language.sexp.* +import maf.core.* +import maf.deltaDebugging.treeDD.transformations.traits.Replacing + +import scala.util.Random + +object LambdaKiller: + type Benchmark = String + private var oracleTreeSizes: List[Int] = List() + + def killLambdas(program: SchemeExp, + dynAnalysis: Map[SchemeLambda, (Set[(SchemeFuncall, ConcreteValues.Value)], Int)], + deadCodeTester: KillLambdaTester, + benchmark: Benchmark): (SchemeExp, List[Int]) = + oracleTreeSizes = List() + + var lambdas = dynAnalysis.toList + lambdas = lambdas.sortBy(l => { + l._2._2 + }) + + for (lambdaToKill <- dynAnalysis.keySet) + //val callsAndReturnValues = dynAnalysis(lambdaToKill) + val result = killLambda(program, lambdaToKill, deadCodeTester, benchmark) + if result.nonEmpty then + return killLambdas(result.get._1, result.get._2, deadCodeTester, benchmark) + (program, oracleTreeSizes) + + def killLambda(program: SchemeExp, + lambdaToKill: SchemeLambda, + deadCodeTester: KillLambdaTester, + benchmark: Benchmark): + Option[(SchemeExp, Map[SchemeLambda, (Set[(SchemeFuncall, ConcreteValues.Value)], Int)])] = + + val lambdaKilled = program.deleteChildren(exp => { + exp eq lambdaToKill + }) + + lambdaKilled match + case Some(programVariant) => + val undefinedVars: List[String] = programVariant.findUndefinedVariables().map(id => id.name) + val lambdaName = lambdaToKill.name + lambdaName match + case Some(name) => + val callsReplaced = Replacing.replaceCallWithAllValues(programVariant, Identifier(name, NoCodeIdentity)) + for (candidate <- callsReplaced) { + val oracleResults = deadCodeTester.runAndFindLambdas(candidate, benchmark) + oracleTreeSizes = oracleTreeSizes.::(candidate.size) + oracleResults match + case (Some(tpl), _) => + if tpl._1.nonEmpty then + return Some(candidate, tpl._2) + case _ => + } + None + case _ => None + + /* + val callsReplaced = programVariant.map(exp => { + exp match + case call: SchemeFuncall => + val returnValues: Set[ConcreteValues.Value] = callsAndReturnValues.filter(tpl => tpl._1 eql call).map(tpl => tpl._2) + var converted = returnValues.flatMap(value => Replacing.valueToExp(value)) + converted = Random.shuffle(converted) + if converted.isEmpty then + exp + else + converted.head + case schemeVarExp: SchemeVarExp => + if undefinedVars.contains(schemeVarExp.id.name) then + SchemeValue(Value.Boolean(false), NoCodeIdentity) + else exp + case _ => exp + }) + + val oracleResults = deadCodeTester.runAndFindLambdas(callsReplaced, benchmark) + oracleResults match + case (Some(tpl), _) => + if tpl._1.nonEmpty then + return Some(callsReplaced, tpl._2) + case _ => + None + */ + case _ => None + + + diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/killLambda/soundnessTests.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/killLambda/soundnessTests.scala new file mode 100644 index 000000000..b0ff69b98 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/killLambda/soundnessTests.scala @@ -0,0 +1,78 @@ +package maf.test.deltaDebugging.soundnessDD.variants.killLambda + +import maf.core.Position +import maf.language.scheme.{SchemeExp, SchemeMutableVarBoxer, SchemeParser} +import maf.language.scheme.primitives.SchemePrelude +import maf.modular.scheme.SchemeConstantPropagationDomain +import maf.modular.scheme.modflocal.{SchemeModFLocal, SchemeModFLocalAnalysisResults, SchemeModFLocalNoSensitivity} +import maf.modular.worklist.FIFOWorklistAlgorithm +import maf.test.{AllSequentialBenchmarks, DDBenchmarks, RandomSequentialBenchmarks, VariousSequentialBenchmarks} +import maf.test.deltaDebugging.realBugs.* + +trait SchemeModFLocalSoundnessTests extends KillLambdaTester with DDBenchmarks: + //override def benchmarks: Set[Benchmark] = Set("test/R5RS/various/LambdaKillingTest1.scm") + override def parseProgram(txt: String, benchmark: String): SchemeExp = + val parsed = SchemeParser.parse(txt, Position.withSourcePath(benchmark)) + val prelud = SchemePrelude.addPrelude(parsed, incl = Set("__toplevel_cons", "__toplevel_cdr", "__toplevel_set-cdr!")) + val transf = SchemeMutableVarBoxer.transform(prelud) + SchemeParser.rename(SchemeParser.undefine(transf)) + +class SchemeModFLocalAdaptiveTests1 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug1" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug1 + +class SchemeModFLocalAdaptiveTests2 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug2" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug2 + +class SchemeModFLocalAdaptiveTests3 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug3" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug3 + +class SchemeModFLocalAdaptiveTests4 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug4" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug4 + +class SchemeModFLocalAdaptiveTests5 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug5" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug5 \ No newline at end of file diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/parallel/EvaluateParallel.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/parallel/EvaluateParallel.scala similarity index 57% rename from code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/parallel/EvaluateParallel.scala rename to code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/parallel/EvaluateParallel.scala index b0f670d25..f33796ec8 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/parallel/EvaluateParallel.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/parallel/EvaluateParallel.scala @@ -1,6 +1,6 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.parallel +package maf.test.deltaDebugging.soundnessDD.variants.parallel -import maf.test.deltaDebugging.soundnessDD.evaluation.Evaluate +import maf.test.deltaDebugging.soundnessDD.variants.Evaluate object SaveParallel: def save(): Unit = @@ -15,10 +15,3 @@ object SaveParallel: "parallelDataCollector", ParallelDD.dataCollector ) - -object ReadAndAnalyzeParallel: - def main(args: Array[String]): Unit = { - Evaluate.readAndAnalyzeData( - "parallelDataCollector" - ) - } diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/parallel/ParallelDD.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/parallel/ParallelDD.scala new file mode 100644 index 000000000..e5c6a06a8 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/parallel/ParallelDD.scala @@ -0,0 +1,63 @@ +package maf.test.deltaDebugging.soundnessDD.variants.parallel + +import maf.deltaDebugging.treeDD.{SchemeReduce, ParallelSchemeReduce} +import maf.deltaDebugging.treeDD.transformations.TransformationManager +import maf.language.scheme.SchemeExp +import maf.test.deltaDebugging.soundnessDD.variants.counting.CountingTester +import maf.test.deltaDebugging.soundnessDD.variants.{DataCollector, ReductionData} + +object ParallelDD: + var dataCollector = new DataCollector + var bugName = "noneYet" + + def reduce(program: SchemeExp, + soundnessTester: ParallelTester, + benchmark: String): Unit = + + var oracleInvocations = 0 + var oracleTreeSizes: List[Int] = List() + + val startTime = System.currentTimeMillis() + + val reduced = ParallelSchemeReduce.reduce( + program, + p => { + val candidateSize = p.size + soundnessTester.runCompareAndtime(p, benchmark) match + case (Some(failureMsg), _) => + oracleTreeSizes.synchronized { + oracleTreeSizes = oracleTreeSizes.::(candidateSize) + } + oracleInvocations.synchronized { + oracleInvocations += 1 + } + p.findUndefinedVariables().isEmpty && failureMsg.nonEmpty + + case (None, _) => + oracleTreeSizes.synchronized { + oracleTreeSizes = oracleTreeSizes.::(candidateSize) + } + oracleInvocations.synchronized { + oracleInvocations += 1 + } + false + }, + identity, + TransformationManager.allTransformations + ) + + val endTime = System.currentTimeMillis() + val totalTime = endTime - startTime + + val reductionData = ReductionData( + benchmark = benchmark, + bugName = bugName, + origSize = program.size, + reducedSize = reduced.size, + reductionTime = totalTime, + reductionPercentage = 1 - (reduced.size.toDouble / program.size), + oracleTreeSizes = oracleTreeSizes + ) + + dataCollector.addReductionData(reductionData) + diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/parallel/ParallelTester.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/parallel/ParallelTester.scala new file mode 100644 index 000000000..4e8aee533 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/parallel/ParallelTester.scala @@ -0,0 +1,21 @@ +package maf.test.deltaDebugging.soundnessDD.variants.parallel + +import maf.test.SlowTest +import maf.test.deltaDebugging.soundnessDD.SoundnessDDTester +import maf.util.Reader + +trait ParallelTester extends SoundnessDDTester { + def bugName: String + + override def onBenchmark(benchmark: Benchmark): Unit = + println("Parallel >>> running benchmark: " + benchmark) + // load the benchmark program + val content = Reader.loadFile(benchmark) + val program = parseProgram(content, benchmark) + runCompareAndtime(program, benchmark) match + case (Some(failureMsg), _) => + if failureMsg.nonEmpty then + ParallelDD.bugName = bugName + ParallelDD.reduce(program, this, benchmark) + case _ => +} diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/parallel/soundnessTests.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/parallel/soundnessTests.scala similarity index 88% rename from code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/parallel/soundnessTests.scala rename to code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/parallel/soundnessTests.scala index f25d2f84c..5a77d8da6 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/parallel/soundnessTests.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/parallel/soundnessTests.scala @@ -1,4 +1,4 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.parallel +package maf.test.deltaDebugging.soundnessDD.variants.parallel import maf.core.Position import maf.language.scheme.{SchemeExp, SchemeMutableVarBoxer, SchemeParser} @@ -6,10 +6,10 @@ import maf.language.scheme.primitives.SchemePrelude import maf.modular.scheme.SchemeConstantPropagationDomain import maf.modular.scheme.modflocal.{SchemeModFLocal, SchemeModFLocalAnalysisResults, SchemeModFLocalNoSensitivity} import maf.modular.worklist.FIFOWorklistAlgorithm -import maf.test.CertainVariousSequentialBenchmarks +import maf.test.DDBenchmarks import maf.test.deltaDebugging.realBugs.* -trait SchemeModFLocalSoundnessTests extends ParallelTester with CertainVariousSequentialBenchmarks: +trait SchemeModFLocalSoundnessTests extends ParallelTester with DDBenchmarks: //override def benchmarks: Set[Benchmark] = Set("test/R5RS/various/SICP-compiler.scm") override def parseProgram(txt: String, benchmark: String): SchemeExp = val parsed = SchemeParser.parse(txt, Position.withSourcePath(benchmark)) @@ -20,7 +20,7 @@ trait SchemeModFLocalSoundnessTests extends ParallelTester with CertainVariousSe class SchemeModFLocalAdaptiveTests1 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug1" + override def bugName = "RealBug1" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain @@ -32,7 +32,7 @@ class SchemeModFLocalAdaptiveTests1 extends SchemeModFLocalSoundnessTests: class SchemeModFLocalAdaptiveTests2 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug2" + override def bugName = "RealBug2" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain @@ -44,7 +44,7 @@ class SchemeModFLocalAdaptiveTests2 extends SchemeModFLocalSoundnessTests: class SchemeModFLocalAdaptiveTests3 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug3" + override def bugName = "RealBug3" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain @@ -56,7 +56,7 @@ class SchemeModFLocalAdaptiveTests3 extends SchemeModFLocalSoundnessTests: class SchemeModFLocalAdaptiveTests4 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug4" + override def bugName = "RealBug4" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain @@ -68,7 +68,7 @@ class SchemeModFLocalAdaptiveTests4 extends SchemeModFLocalSoundnessTests: class SchemeModFLocalAdaptiveTests5 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug5" + override def bugName = "RealBug5" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/preHalt/EvaluatePreHalt.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/preHalt/EvaluatePreHalt.scala new file mode 100644 index 000000000..cb68be716 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/preHalt/EvaluatePreHalt.scala @@ -0,0 +1,19 @@ +package maf.test.deltaDebugging.soundnessDD.variants.preHalt + +import maf.test.deltaDebugging.soundnessDD.variants.Evaluate +import maf.util.benchmarks.Statistics + +object SavePreHalt: + def save(): Unit = { + Evaluate.save( + List( + new SchemeModFLocalAdaptiveTests1, + new SchemeModFLocalAdaptiveTests2, + new SchemeModFLocalAdaptiveTests3, + new SchemeModFLocalAdaptiveTests4, + new SchemeModFLocalAdaptiveTests5 + ), + "preHaltDataCollector", + PreHaltDD.dataCollector + ) + } diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/preHalt/PreHaltDD.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/preHalt/PreHaltDD.scala new file mode 100644 index 000000000..2b63dbcfe --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/preHalt/PreHaltDD.scala @@ -0,0 +1,53 @@ +package maf.test.deltaDebugging.soundnessDD.variants.preHalt + +import maf.deltaDebugging.treeDD.SchemeReduce +import maf.deltaDebugging.treeDD.transformations.TransformationManager +import maf.language.scheme.SchemeExp +import maf.language.scheme.interpreter.ConcreteValues +import maf.test.deltaDebugging.soundnessDD.variants.* + +object PreHaltDD: + var dataCollector = new DataCollector + var bugName = "noneYet" + var problematicValue: Option[ConcreteValues.Value] = None + + def reduce(program: SchemeExp, + soundnessTester: PreHaltTester, + benchmark: String): Unit = + + var oracleInvocations = 0 + var oracleTreeSizes: List[Int] = List() + + val startTime = System.currentTimeMillis() + + val reduced = SchemeReduce.reduce( + program, + p => { + oracleInvocations += 1 + oracleTreeSizes = oracleTreeSizes.::(p.size) + soundnessTester.runAndCompare_(p, benchmark, problematicValue) match + case Some(failureMsg, _) => + p.findUndefinedVariables().isEmpty && failureMsg.nonEmpty + + case None => + false + }, + identity, + TransformationManager.allTransformations /** Uses all Transformations! */ + ) + + val endTime = System.currentTimeMillis() + val totalTime = endTime - startTime + + val reductionData = ReductionData( + benchmark = benchmark, + bugName = bugName, + origSize = program.size, + reducedSize = reduced.size, + reductionTime = totalTime, + reductionPercentage = 1 - (reduced.size.toDouble / program.size), + oracleTreeSizes = oracleTreeSizes + ) + + dataCollector.addReductionData(reductionData) + diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/preHalt/PreHaltTester.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/preHalt/PreHaltTester.scala new file mode 100644 index 000000000..6a62238e8 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/preHalt/PreHaltTester.scala @@ -0,0 +1,87 @@ +package maf.test.deltaDebugging.soundnessDD.variants.preHalt + +import maf.core.Identity +import maf.language.scheme.SchemeExp +import maf.language.scheme.interpreter.{ConcreteValues, PreHaltInterpreter, SchemeInterpreter, FileIO} +import maf.language.scheme.interpreter.ConcreteValues.Value +import maf.test.SlowTest +import maf.test.deltaDebugging.soundnessDD.SoundnessDDTester +import maf.util.Reader + +trait PreHaltTester extends SoundnessDDTester { + def bugName: String + + def compareResults_(analysis: Analysis, concreteResults: Map[Identity, Set[Value]]): (String, Option[Value]) = + val analysisResults = analysis.resultsPerIdn + concreteResults.foreach { case (idn, concreteValues) => + val abstractValues = analysisResults.getOrElse(idn, Set.empty) + concreteValues.foreach { concreteValue => + if !abstractValues.exists(checkSubsumption(analysis)(concreteValue, _)) then + return + ( + s""" + | Result at $idn is unsound: + | - concrete value: $concreteValue + | - abstract values: ${analysis.lattice.join(abstractValues)} + """.stripMargin, + Some(concreteValue) + ) + } + } + ("", None) + + def evalProgram(program: SchemeExp, + benchmark: Benchmark, + problematicValue: Option[Value], + anl: Analysis): Map[Identity, Set[Value]] = + var idnResults = Map[Identity, Set[Value]]().withDefaultValue(Set()) + val soundnessTest: () => Boolean = () => compareResults_(anl, idnResults)._1.nonEmpty + val timeout = concreteTimeout(benchmark) + val times = concreteRuns(benchmark) + val addResult: (Identity, ConcreteValues.Value) => Unit = (i, v) => idnResults += (i -> (idnResults(i) + v)) + val interpreter: SchemeInterpreter = + problematicValue match + case Some(value) => + new PreHaltInterpreter(addResult, + io = new FileIO(Map("input.txt" -> "foo\nbar\nbaz", "output.txt" -> "")), + value, + soundnessTest) + case _ => + new SchemeInterpreter(addResult, io = new FileIO(Map("input.txt" -> "foo\nbar\nbaz", "output.txt" -> ""))) + for _ <- 1 to times do + interpreter.run(program, timeout) + idnResults + + def runAndCompare_(program: SchemeExp, benchmark: Benchmark, problematicValue: Option[Value]): + Option[(String, Option[Value])] = { + try + val anl = runAnalysis(program, benchmark) + val concreteResults = + evalProgram(program, + benchmark, + problematicValue, + anl) + // analyze the program using a ModF analysis + + // check if the analysis results soundly (over-)approximate the concrete results + val compared = compareResults_(anl, concreteResults) + + Some(compared._1, compared._2) + catch case exc: Throwable => + None + } + + override def onBenchmark(benchmark: Benchmark): Unit = + println("Transforming >>> running benchmark: " + benchmark) + // load the benchmark program + val content = Reader.loadFile(benchmark) + val program = parseProgram(content, benchmark) + + runAndCompare_(program, benchmark, None) match + case Some((failureMsg, problematicValue)) => + if failureMsg.nonEmpty then + PreHaltDD.problematicValue = problematicValue + PreHaltDD.bugName = bugName + PreHaltDD.reduce(program, this, benchmark) + case _ => +} diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/preHalt/soundnessTests.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/preHalt/soundnessTests.scala new file mode 100644 index 000000000..6df92bc06 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/preHalt/soundnessTests.scala @@ -0,0 +1,78 @@ +package maf.test.deltaDebugging.soundnessDD.variants.preHalt + +import maf.core.Position +import maf.language.scheme.primitives.SchemePrelude +import maf.language.scheme.{SchemeExp, SchemeMutableVarBoxer, SchemeParser} +import maf.modular.scheme.SchemeConstantPropagationDomain +import maf.modular.scheme.modflocal.{SchemeModFLocal, SchemeModFLocalAnalysisResults, SchemeModFLocalNoSensitivity} +import maf.modular.worklist.FIFOWorklistAlgorithm +import maf.test.deltaDebugging.realBugs.* +import maf.test.{AllSequentialBenchmarks, DDBenchmarks, RandomSequentialBenchmarks, VariousSequentialBenchmarks} + +trait SchemeModFLocalSoundnessTests extends PreHaltTester with DDBenchmarks: + //override def benchmarks: Set[Benchmark] = Set("test/R5RS/various/SICP-compiler.scm") + override def parseProgram(txt: String, benchmark: String): SchemeExp = + val parsed = SchemeParser.parse(txt, Position.withSourcePath(benchmark)) + val prelud = SchemePrelude.addPrelude(parsed, incl = Set("__toplevel_cons", "__toplevel_cdr", "__toplevel_set-cdr!")) + val transf = SchemeMutableVarBoxer.transform(prelud) + SchemeParser.rename(SchemeParser.undefine(transf)) + +class SchemeModFLocalAdaptiveTests1 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug1" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug1 + +class SchemeModFLocalAdaptiveTests2 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug2" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug2 + +class SchemeModFLocalAdaptiveTests3 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug3" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug3 + +class SchemeModFLocalAdaptiveTests4 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug4" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug4 + +class SchemeModFLocalAdaptiveTests5 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName = "RealBug5" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug5 diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/smartReplacement/EvaluateSmartReplacement.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/smartReplacement/EvaluateSmartReplacement.scala new file mode 100644 index 000000000..5ac4a95aa --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/smartReplacement/EvaluateSmartReplacement.scala @@ -0,0 +1,28 @@ +package maf.test.deltaDebugging.soundnessDD.variants.smartReplacement + +import maf.test.DDBenchmarks +import maf.test.deltaDebugging.soundnessDD.variants.Evaluate +import maf.util.benchmarks.Statistics + +object SaveSmartReplacement: + def save(): Unit = { + Evaluate.save( + List( + new SchemeModFLocalAdaptiveTests1, + new SchemeModFLocalAdaptiveTests2, + new SchemeModFLocalAdaptiveTests3, + new SchemeModFLocalAdaptiveTests4, + new SchemeModFLocalAdaptiveTests5 + ), + "smartReplacementDataCollector", + SmartReplacementDD.dataCollector + ) + } + +/* +object Wrapper extends DDBenchmarks: + override protected def onBenchmark(b: Wrapper.Benchmark): Unit = None + def main(args: Array[Benchmark]): Unit = { + benchmarks.foreach(println) + } +*/ diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/smartReplacement/SmartReplacementDD.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/smartReplacement/SmartReplacementDD.scala new file mode 100644 index 000000000..ef3879fed --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/smartReplacement/SmartReplacementDD.scala @@ -0,0 +1,65 @@ +package maf.test.deltaDebugging.soundnessDD.variants.smartReplacement + +import maf.core.Identity +import maf.deltaDebugging.treeDD.SchemeReduce +import maf.deltaDebugging.treeDD.transformations.TransformationManager +import maf.deltaDebugging.treeDD.transformations.traits.Replacing +import maf.language.scheme.SchemeExp +import maf.language.scheme.interpreter.ConcreteValues +import maf.test.deltaDebugging.soundnessDD.variants.* + +object SmartReplacementDD: + var dataCollector = new DataCollector + var bugName = "noneYet" + var valuesMap: Map[SchemeExp, Set[ConcreteValues.Value]] = Map() + var problematicValue: Option[ConcreteValues.Value] = None + + def reduce(program: SchemeExp, + soundnessTester: SmartReplacementTester, + benchmark: String): Unit = + + var oracleInvocations = 0 + var oracleTreeSizes: List[Int] = List() + + val startTime = System.currentTimeMillis() + + Replacing.valuesMap = valuesMap + Replacing.problematicValue = problematicValue + + val reduced = SchemeReduce.reduce( + program, + p => { + oracleInvocations += 1 + oracleTreeSizes = oracleTreeSizes.::(p.size) + soundnessTester.runAndCompare_(p, benchmark) match + case Some((failureMsg, dynAnalysis, maybeValue)) => + valuesMap = dynAnalysis + problematicValue = maybeValue + p.findUndefinedVariables().isEmpty && failureMsg.nonEmpty + case None => + false + }, + _ => { + Replacing.valuesMap = valuesMap + Replacing.problematicValue = problematicValue + }, + TransformationManager.allTransformations + ) + + Replacing.problematicValue = None + Replacing.valuesMap = Map() + + val endTime = System.currentTimeMillis() + val totalReductionTime = endTime - startTime + + val reductionData = ReductionData( + benchmark = benchmark, + bugName = bugName, + origSize = program.size, + reducedSize = reduced.size, + reductionTime = totalReductionTime, + reductionPercentage = 1 - (reduced.size.toDouble / program.size), + oracleTreeSizes = oracleTreeSizes + ) + + dataCollector.addReductionData(reductionData) diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/smartReplacement/SmartReplacementTester.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/smartReplacement/SmartReplacementTester.scala new file mode 100644 index 000000000..8292cd80c --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/smartReplacement/SmartReplacementTester.scala @@ -0,0 +1,76 @@ +package maf.test.deltaDebugging.soundnessDD.variants.smartReplacement + +import maf.core.Identity +import maf.deltaDebugging.treeDD.transformations.traits.Replacing +import maf.language.scheme.SchemeExp +import maf.language.scheme.interpreter.ConcreteValues.Value +import maf.language.scheme.interpreter.{ConcreteValues, FileIO, IO, SmartReplaceInterpreter} +import maf.test.SlowTest +import maf.test.deltaDebugging.soundnessDD.SoundnessDDTester +import maf.util.Reader + +trait SmartReplacementTester extends SoundnessDDTester { + def bugName: String + + def compareResults_(analysis: Analysis, concreteResults: Map[Identity, Set[Value]]): (String, Option[Value]) = + val analysisResults = analysis.resultsPerIdn + concreteResults.foreach { case (idn, concreteValues) => + val abstractValues = analysisResults.getOrElse(idn, Set.empty) + concreteValues.foreach { concreteValue => + if !abstractValues.exists(checkSubsumption(analysis)(concreteValue, _)) then + return + ( + s""" + | Result at $idn is unsound: + | - concrete value: $concreteValue + | - abstract values: ${analysis.lattice.join(abstractValues)} + """.stripMargin, + Some(concreteValue) + ) + } + } + ("", None) + + def runAndCompare_(program: SchemeExp, benchmark: Benchmark): + Option[(String, Map[SchemeExp, Set[ConcreteValues.Value]], Option[Value])] = { + try + val concreteResults = replacingEvalProgram(program, benchmark) + // analyze the program using a ModF analysis + val anl = runAnalysis(program, benchmark) + // check if the analysis results soundly (over-)approximate the concrete results + val compared = compareResults_(anl, concreteResults._1) + + Some(compared._1, concreteResults._2, compared._2) + catch case exc: Throwable => + None + } + + override def createInterpreter(addResult: (Identity, Value) => Unit, io: IO, benchmark: Benchmark): SmartReplaceInterpreter = + new SmartReplaceInterpreter(addResult, io) + + def replacingEvalProgram(program: SchemeExp, benchmark: Benchmark): (Map[Identity, Set[Value]], Map[SchemeExp, Set[Value]]) = + var idnResults = Map[Identity, Set[Value]]().withDefaultValue(Set()) + val timeout = concreteTimeout(benchmark) + val times = concreteRuns(benchmark) + val addResult: (Identity, ConcreteValues.Value) => Unit = (i, v) => idnResults += (i -> (idnResults(i) + v)) + val interpreter = createInterpreter(addResult, io = new FileIO(Map("input.txt" -> "foo\nbar\nbaz", "output.txt" -> "")), benchmark) + var dynAnalysisResults: Map[SchemeExp, Set[ConcreteValues.Value]] = Map() + for _ <- 1 to times do + dynAnalysisResults = interpreter.runAndProfile(program, timeout)._2 + (idnResults, dynAnalysisResults) + + override def onBenchmark(benchmark: Benchmark): Unit = + println("SmartReplacement >>> running benchmark: " + benchmark) + // load the benchmark program + val content = Reader.loadFile(benchmark) + val program = parseProgram(content, benchmark) + + runAndCompare_(program, benchmark) match + case Some((failureMsg, dynAnalysis, maybeValue)) => + if failureMsg.nonEmpty then + SmartReplacementDD.problematicValue = maybeValue + SmartReplacementDD.valuesMap = dynAnalysis + SmartReplacementDD.bugName = bugName + SmartReplacementDD.reduce(program, this, benchmark) + case _ => +} diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/smartReplacement/soundnessTests.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/smartReplacement/soundnessTests.scala new file mode 100644 index 000000000..61985a18e --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/smartReplacement/soundnessTests.scala @@ -0,0 +1,79 @@ +package maf.test.deltaDebugging.soundnessDD.variants.smartReplacement + +import maf.language.scheme.primitives.SchemePrelude +import maf.language.scheme.{SchemeExp, SchemeMutableVarBoxer, SchemeParser} +import maf.modular.scheme.* +import maf.modular.scheme.modflocal.* +import maf.modular.worklist.FIFOWorklistAlgorithm +import maf.test.deltaDebugging.realBugs.* +import maf.test.{DDBenchmarks, RandomSequentialBenchmarks, VariousSequentialBenchmarks} +import maf.core.Position + +trait SchemeModFLocalSoundnessTests extends SmartReplacementTester with DDBenchmarks: + //override def benchmarks: Set[Benchmark] = Set("test/R5RS/various/values.scm") + override def parseProgram(txt: String, benchmark: String): SchemeExp = + val parsed = SchemeParser.parse(txt, Position.withSourcePath(benchmark)) + val prelud = SchemePrelude.addPrelude(parsed, incl = Set("__toplevel_cons", "__toplevel_cdr", "__toplevel_set-cdr!")) + val transf = SchemeMutableVarBoxer.transform(prelud) + SchemeParser.rename(SchemeParser.undefine(transf)) + +class SchemeModFLocalAdaptiveTests1 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName: String = "RealBug1" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug1 + +class SchemeModFLocalAdaptiveTests2 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName: String = "RealBug2" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug2 + +class SchemeModFLocalAdaptiveTests3 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName: String = "RealBug3" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug3 + +class SchemeModFLocalAdaptiveTests4 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName: String = "RealBug4" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug4 + +class SchemeModFLocalAdaptiveTests5 extends SchemeModFLocalSoundnessTests: + def l = 10 + def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" + override def bugName: String = "RealBug5" + def analysis(prg: SchemeExp) = + new SchemeModFLocal(prg) + with SchemeConstantPropagationDomain + with SchemeModFLocalNoSensitivity + with FIFOWorklistAlgorithm[SchemeExp] + with SchemeModFLocalAnalysisResults + with RealBug5 + diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/transforming/EvaluateTransforming.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/transforming/EvaluateTransforming.scala similarity index 54% rename from code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/transforming/EvaluateTransforming.scala rename to code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/transforming/EvaluateTransforming.scala index 1bfa42b4f..5e246c01c 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/transforming/EvaluateTransforming.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/transforming/EvaluateTransforming.scala @@ -1,6 +1,6 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.transforming +package maf.test.deltaDebugging.soundnessDD.variants.transforming -import maf.test.deltaDebugging.soundnessDD.evaluation.Evaluate +import maf.test.deltaDebugging.soundnessDD.variants.Evaluate import maf.util.benchmarks.Statistics object SaveTransforming: @@ -13,15 +13,7 @@ object SaveTransforming: new SchemeModFLocalAdaptiveTests4, new SchemeModFLocalAdaptiveTests5 ), - "transformingDataCollector", + "7LayeredDataCollector", TransformingDD.dataCollector ) } - -object ReadAndAnalyzeTransforming: - def main(args: Array[String]): Unit = { - Evaluate.readAndAnalyzeData( - "transformingDataCollector" - ) - } - diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/transforming/TransformingDD.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/transforming/TransformingDD.scala similarity index 51% rename from code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/transforming/TransformingDD.scala rename to code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/transforming/TransformingDD.scala index 06919bbf5..256a2c939 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/transforming/TransformingDD.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/transforming/TransformingDD.scala @@ -1,9 +1,9 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.transforming +package maf.test.deltaDebugging.soundnessDD.variants.transforming -import maf.deltaDebugging.gtr.GTR -import maf.deltaDebugging.gtr.transformations.TransformationManager +import maf.deltaDebugging.treeDD.{LayeredSchemeReduce, SchemeReduce} +import maf.deltaDebugging.treeDD.transformations.TransformationManager import maf.language.scheme.SchemeExp -import maf.test.deltaDebugging.soundnessDD.evaluation.* +import maf.test.deltaDebugging.soundnessDD.variants.* object TransformingDD: var dataCollector = new DataCollector @@ -14,42 +14,39 @@ object TransformingDD: benchmark: String): Unit = var oracleInvocations = 0 - var runTimes: List[Long] = List() - var analysisTimes: List[Long] = List() + var oracleTreeSizes: List[Int] = List() val startTime = System.currentTimeMillis() - val reduced = GTR.reduce( + val reduced = LayeredSchemeReduce.reduce( program, p => { oracleInvocations += 1 + oracleTreeSizes = oracleTreeSizes.::(p.size) soundnessTester.runCompareAndtime(p, benchmark) match - case (Some(failureMsg), (runTime, analysisTime)) => - runTimes = runTimes.::(runTime) - analysisTimes = analysisTimes.::(analysisTime) + case (Some(failureMsg), _) => p.findUndefinedVariables().isEmpty && failureMsg.nonEmpty - case (None, (runTime, analysisTime)) => - runTimes = runTimes.::(runTime) - analysisTimes = analysisTimes.::(analysisTime) + case (None, _) => false }, identity, - TransformationManager.allTransformations /** Uses all Transformations! */ + TransformationManager.allTransformations /** Uses all Transformations! */, + None, + 7 ) val endTime = System.currentTimeMillis() + val totalTime = endTime - startTime val reductionData = ReductionData( benchmark = benchmark, bugName = bugName, origSize = program.size, reducedSize = reduced.size, - reductionTime = endTime - startTime, - interpreterTime = runTimes.sum, - analysisTime = analysisTimes.sum, - interpreterTimes = runTimes, - analysisTimes = analysisTimes + reductionTime = totalTime, + reductionPercentage = 1 - (reduced.size.toDouble / program.size), + oracleTreeSizes = oracleTreeSizes ) dataCollector.addReductionData(reductionData) diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/transforming/TransformingTester.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/transforming/TransformingTester.scala new file mode 100644 index 000000000..c4120b5f2 --- /dev/null +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/transforming/TransformingTester.scala @@ -0,0 +1,26 @@ +package maf.test.deltaDebugging.soundnessDD.variants.transforming + +import maf.core.Identity +import maf.language.scheme.SchemeExp +import maf.language.scheme.interpreter.ConcreteValues.Value +import maf.test.SlowTest +import maf.test.deltaDebugging.soundnessDD.SoundnessDDTester +import maf.util.Reader + +trait TransformingTester extends SoundnessDDTester { + def bugName: String + + override def onBenchmark(benchmark: Benchmark): Unit = + println("Transforming >>> running benchmark: " + benchmark) + // load the benchmark program + val content = Reader.loadFile(benchmark) + val program = parseProgram(content, benchmark) + + runCompareAndtime(program, benchmark) match + case (Some(failureMsg), _) => + if failureMsg.nonEmpty then + TransformingDD.bugName = bugName + TransformingDD.reduce(program, this, benchmark) + case _ => + +} diff --git a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/transforming/soundnessTests.scala b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/transforming/soundnessTests.scala similarity index 85% rename from code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/transforming/soundnessTests.scala rename to code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/transforming/soundnessTests.scala index fa54ead01..111480731 100644 --- a/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/evaluation/transforming/soundnessTests.scala +++ b/code/shared/src/test/scala/maf/test/deltaDebugging/soundnessDD/variants/transforming/soundnessTests.scala @@ -1,4 +1,4 @@ -package maf.test.deltaDebugging.soundnessDD.evaluation.transforming +package maf.test.deltaDebugging.soundnessDD.variants.transforming import maf.core.Position import maf.language.scheme.{SchemeExp, SchemeMutableVarBoxer, SchemeParser} @@ -7,9 +7,9 @@ import maf.modular.scheme.SchemeConstantPropagationDomain import maf.modular.scheme.modflocal.{SchemeModFLocal, SchemeModFLocalAnalysisResults, SchemeModFLocalNoSensitivity} import maf.modular.worklist.FIFOWorklistAlgorithm import maf.test.deltaDebugging.realBugs.* -import maf.test.{AllSequentialBenchmarks, CertainVariousSequentialBenchmarks, RandomSequentialBenchmarks, VariousSequentialBenchmarks} +import maf.test.{AllSequentialBenchmarks, DDBenchmarks, RandomSequentialBenchmarks, VariousSequentialBenchmarks} -trait SchemeModFLocalSoundnessTests extends TransformingTester with CertainVariousSequentialBenchmarks: +trait SchemeModFLocalSoundnessTests extends TransformingTester with DDBenchmarks: //override def benchmarks: Set[Benchmark] = Set("test/R5RS/various/SICP-compiler.scm") override def parseProgram(txt: String, benchmark: String): SchemeExp = val parsed = SchemeParser.parse(txt, Position.withSourcePath(benchmark)) @@ -20,7 +20,7 @@ trait SchemeModFLocalSoundnessTests extends TransformingTester with CertainVario class SchemeModFLocalAdaptiveTests1 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug1" + override def bugName = "RealBug1" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain @@ -32,7 +32,7 @@ class SchemeModFLocalAdaptiveTests1 extends SchemeModFLocalSoundnessTests: class SchemeModFLocalAdaptiveTests2 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug2" + override def bugName = "RealBug2" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain @@ -44,7 +44,7 @@ class SchemeModFLocalAdaptiveTests2 extends SchemeModFLocalSoundnessTests: class SchemeModFLocalAdaptiveTests3 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug3" + override def bugName = "RealBug3" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain @@ -56,7 +56,7 @@ class SchemeModFLocalAdaptiveTests3 extends SchemeModFLocalSoundnessTests: class SchemeModFLocalAdaptiveTests4 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug4" + override def bugName = "RealBug4" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain @@ -68,7 +68,7 @@ class SchemeModFLocalAdaptiveTests4 extends SchemeModFLocalSoundnessTests: class SchemeModFLocalAdaptiveTests5 extends SchemeModFLocalSoundnessTests: def l = 10 def name = s"MODF LOCAL w/ ASW -- policy B (l = $l)" - override val bugName: Benchmark = "RealBug5" + override def bugName = "RealBug5" def analysis(prg: SchemeExp) = new SchemeModFLocal(prg) with SchemeConstantPropagationDomain diff --git a/evaluationLogs/objects/LayeredDataCollector b/evaluationLogs/objects/LayeredDataCollector new file mode 100644 index 000000000..c1ff4970e Binary files /dev/null and b/evaluationLogs/objects/LayeredDataCollector differ diff --git a/evaluationLogs/objects/UCEDataCollector b/evaluationLogs/objects/UCEDataCollector new file mode 100644 index 000000000..bfb5762ee Binary files /dev/null and b/evaluationLogs/objects/UCEDataCollector differ diff --git a/evaluationLogs/objects/baselineDataCollector b/evaluationLogs/objects/baselineDataCollector index cc77e4f79..05f789682 100644 Binary files a/evaluationLogs/objects/baselineDataCollector and b/evaluationLogs/objects/baselineDataCollector differ diff --git a/evaluationLogs/objects/countingDataCollector b/evaluationLogs/objects/countingDataCollector index 73b37dfa3..cec044377 100644 Binary files a/evaluationLogs/objects/countingDataCollector and b/evaluationLogs/objects/countingDataCollector differ diff --git a/evaluationLogs/objects/deadCodeDataCollector b/evaluationLogs/objects/deadCodeDataCollector new file mode 100644 index 000000000..0a5dc9dc4 Binary files /dev/null and b/evaluationLogs/objects/deadCodeDataCollector differ diff --git a/evaluationLogs/objects/killLambdaDataCollector b/evaluationLogs/objects/killLambdaDataCollector new file mode 100644 index 000000000..726bb14c4 Binary files /dev/null and b/evaluationLogs/objects/killLambdaDataCollector differ diff --git a/evaluationLogs/objects/parallelDataCollector b/evaluationLogs/objects/parallelDataCollector index e671dc098..49723db94 100644 Binary files a/evaluationLogs/objects/parallelDataCollector and b/evaluationLogs/objects/parallelDataCollector differ diff --git a/evaluationLogs/objects/preHaltDataCollector b/evaluationLogs/objects/preHaltDataCollector new file mode 100644 index 000000000..4875d2547 Binary files /dev/null and b/evaluationLogs/objects/preHaltDataCollector differ diff --git a/evaluationLogs/objects/profilingDataCollector b/evaluationLogs/objects/profilingDataCollector new file mode 100644 index 000000000..ecaa9a8af Binary files /dev/null and b/evaluationLogs/objects/profilingDataCollector differ diff --git a/evaluationLogs/objects/randomDataCollector b/evaluationLogs/objects/randomDataCollector new file mode 100644 index 000000000..65742de89 Binary files /dev/null and b/evaluationLogs/objects/randomDataCollector differ diff --git a/evaluationLogs/objects/smartReplacementDataCollector b/evaluationLogs/objects/smartReplacementDataCollector new file mode 100644 index 000000000..8c7365e76 Binary files /dev/null and b/evaluationLogs/objects/smartReplacementDataCollector differ diff --git a/evaluationLogs/objects/transformingDataCollector b/evaluationLogs/objects/transformingDataCollector index a3ff80594..778e97a56 100644 Binary files a/evaluationLogs/objects/transformingDataCollector and b/evaluationLogs/objects/transformingDataCollector differ diff --git a/evaluationLogs/objects/withProfilingDataCollector b/evaluationLogs/objects/withProfilingDataCollector new file mode 100644 index 000000000..57ed5beea Binary files /dev/null and b/evaluationLogs/objects/withProfilingDataCollector differ diff --git a/test/R5RS/DD/2.scm b/test/R5RS/DD/2.scm new file mode 100644 index 000000000..3028e7bf8 --- /dev/null +++ b/test/R5RS/DD/2.scm @@ -0,0 +1,33 @@ +; 2.1 +(define (sign number) + (cond ((zero? number) 0) + ((> number 0) 1) + (else -1))) + +(define (divides? deler deeltal) + (= 0 (modulo deeltal deler))) + +(define (leap-year? year) + (if (divides? 4 year) + (if (divides? 100 year) + (divides? 400 year) + #t) + #f)) + +(and (not (or (leap-year? 1989) + (leap-year? 1900))) + (leap-year? 2000) + (= -1 (sign -5)) + (= 1 (sign 17.28)) + (= 0 (sign 0))) + +; 2.4 +(define (derde-machtswortel x) + (define epsilon 0.01) + (define (hulp-derde-machtswortel y) + (if (< (abs (- (* y y y) x)) epsilon) + y + (hulp-derde-machtswortel (/ (+ (/ x (* y y)) y y) 3)))) + (hulp-derde-machtswortel (/ x 3))) + +(= 3.000000068671529 (exact->inexact (derde-machtswortel 27))) \ No newline at end of file diff --git a/test/R5RS/DD/family-budget.scm b/test/R5RS/DD/family-budget.scm new file mode 100644 index 000000000..9362b92c1 --- /dev/null +++ b/test/R5RS/DD/family-budget.scm @@ -0,0 +1,43 @@ +(define familieboom '(jan (piet (frans (tom) + (roel)) + (mie)) + (bram (inge (bert (ina) + (ilse)) + (bart)) + (iris)) + (joost (else (ilse))))) + + + +(define (familiehoofd fam) (car fam)) +(define (kinderen fam) (cdr fam)) +(define (laatste-nakomeling? fam) + (null? (kinderen fam))) + +(define (verdeel-democratisch boom budget) + (define (verdeel boom) + (if (laatste-nakomeling? boom) + 1 + (+ 1 (verdeel-in (kinderen boom))))) + + (define (verdeel-in lst) + (if (null? lst) + 0 + (+ (verdeel (car lst)) + (verdeel-in (cdr lst))))) + (/ budget (verdeel-in (kinderen boom)))) + +(define (budget boom budget-list) + (define (budget-hulp boom budget-list) + (+ (car budget-list) + (budget-hulp-in (kinderen boom) (cdr budget-list)))) + + (define (budget-hulp-in bomen budget-list) + (if (or (null? bomen)(null? budget-list)) + 0 + (+ (budget-hulp (car bomen) budget-list) + (budget-hulp-in (cdr bomen) budget-list)))) + (budget-hulp-in (kinderen boom) budget-list)) + +(and (= (verdeel-democratisch familieboom 1500) 100) + (= (budget familieboom '(100 50 20)) 650)) \ No newline at end of file diff --git a/test/R5RS/DD/fireworks.scm b/test/R5RS/DD/fireworks.scm new file mode 100644 index 000000000..4b3f4f7cc --- /dev/null +++ b/test/R5RS/DD/fireworks.scm @@ -0,0 +1,40 @@ +(define (atom? x) + (not (pair? x))) + +(define mijn-vuurwerk '(groen ((blauw (X (blauw (X X)) X X)) + (rood ((groen (X X)) X)) + X + (geel (X X))))) + +(define (kleur vuurwerk) (car vuurwerk)) +(define (takken vuurwerk) (cadr vuurwerk)) +(define (low-energy? vuurwerk) (eq? vuurwerk 'X)) + +(define (tel-low-energies v) + (cond ((null? v) 0) + ((low-energy? v) 1) + ((atom? v) 0) + (else (+ (tel-low-energies (car v)) + (tel-low-energies (cdr v)))))) + +(define (tel-einde-in takken een-kleur) + (cond ((null? takken) 0) + ((low-energy? (car takken)) 0) + (else (+ (tel-einde (car takken) een-kleur) + (tel-einde-in (cdr takken) een-kleur))))) + +(define (tel-einde vuurwerk een-kleur) + (if (eq? (kleur vuurwerk) een-kleur) + (tel-low-energies (takken vuurwerk)) + (tel-einde-in (takken vuurwerk) een-kleur))) + +(define (ster? vuurwerk) + (not (member 'X (takken vuurwerk)))) + +(and (eq? (kleur mijn-vuurwerk) 'groen) + (equal? (takken mijn-vuurwerk) + '((blauw (X (blauw (X X)) X X)) (rood ((groen (X X)) X)) X (geel (X X)))) + (not (low-energy? mijn-vuurwerk)) + (low-energy? 'X) + (= (tel-einde mijn-vuurwerk 'blauw) 5) + (not (ster? mijn-vuurwerk))) \ No newline at end of file diff --git a/test/R5RS/DD/flatten.scm b/test/R5RS/DD/flatten.scm new file mode 100644 index 000000000..4f67cc3b9 --- /dev/null +++ b/test/R5RS/DD/flatten.scm @@ -0,0 +1,36 @@ +(define (find-last lijst) + (if (null? lijst) + (error "find-last -- lijst heeft geen laatste element") + (let ((next (cdr lijst))) + (if (null? next) + lijst + (find-last next))))) + +(define (atom? x) (not (pair? x))) + +(define (flatten2! lijst) + (let ((hulpcel (cons 'dummy lijst))) + (define (flatten-aux! prev current) + (cond ((null? current) (cdr hulpcel)) + ((null? (car current)) + (set-cdr! prev (cdr current)) + (flatten-aux! prev (cdr current))) + ((pair? (car current)) + (set-cdr! prev (flatten2! (car current))) + (flatten-aux! (find-last prev) (cdr current))) + ((null? (cdr prev)) + (set-cdr! prev current) + (flatten-aux! (cdr prev) (cdr current))) + ((atom? (car current)) + (flatten-aux! (cdr prev) (cdr current))))) + (flatten-aux! hulpcel lijst) + (cdr hulpcel))) + +(define res (and (equal? (flatten2! '((1 2) (3 4 5) (6) (7 8))) '(1 2 3 4 5 6 7 8)) + (equal? (flatten2! '(() (1 2) (3 4 5) () (6) (7 8))) '(1 2 3 4 5 6 7 8)) + (equal? (flatten2! '((1 (2 3) 4) 5 6 (7 8))) '(1 2 3 4 5 6 7 8)) + (equal? (flatten2! '((1 2) (3 4 5) (6) (7 8))) '(1 2 3 4 5 6 7 8)) + (equal? (flatten2! '(() (1 2) (3 4 5) () (6) (7 8))) '(1 2 3 4 5 6 7 8)) + (equal? (flatten2! '(1 2 (3 (4 5) 6 (7 8) 9) 10)) '(1 2 3 4 5 6 7 8 9 10)))) + +res \ No newline at end of file diff --git a/test/R5RS/DD/lst-append.scm b/test/R5RS/DD/lst-append.scm new file mode 100644 index 000000000..c43245595 --- /dev/null +++ b/test/R5RS/DD/lst-append.scm @@ -0,0 +1,37 @@ +;taken from SICP 1, a program that makes heavy use of the built-in append procedure + +(define (rec-sum-lists l1 l2) + (cond ((null? l1) l2) + ((null? l2) l1) + (else (cons (+ (car l1) (car l2)) + (rec-sum-lists (cdr l1) (cdr l2)))))) + +(define (rec-merge-n lst1 lst2 n) + + (define (geef-n+rest lst n) + (cond ((or (= 0 n) (null? lst)) (cons '() lst)) + (else (let* ((res (geef-n+rest (cdr lst) (- n 1))) + (first (car res)) + (rest (cdr res))) + (cons (cons (car lst) first) rest))))) + + (cond ((null? lst1) lst2) + ((null? lst2) lst1) + (else + (let* ((n-lst1 (geef-n+rest lst1 n)) + (n-lst2 (geef-n+rest lst2 n)) + (n-lst1-first (car n-lst1)) + (n-lst1-rest (cdr n-lst1)) + (n-lst2-first (car n-lst2)) + (n-lst2-rest (cdr n-lst2))) + (append (append n-lst1-first n-lst2-first) + (rec-merge-n n-lst1-rest n-lst2-rest n)))))) + +(rec-merge-n '(1 2 3 4 5 6 7 8 9 10) '(11 12 13 14 15) 2) + +(define (fac n) + (if (zero? n) + 1 + (* n (fac (- n 1))))) + +(fac 5) \ No newline at end of file diff --git a/test/R5RS/DD/primtest.scm b/test/R5RS/DD/primtest.scm new file mode 100644 index 000000000..3798311e3 --- /dev/null +++ b/test/R5RS/DD/primtest.scm @@ -0,0 +1,34 @@ +;; Expected result: 1 +(define (square x) (* x x)) +(define (modulo-power base exp n) + (if (= exp 0) + 1 + (if (odd? exp) + (modulo (* base (modulo-power base (- exp 1) n)) n) + (modulo (square (modulo-power base (/ exp 2) n)) n)))) +(define (is-trivial-composite? n) + (or (= (modulo n 2) 0) + (= (modulo n 3) 0) + (= (modulo n 5) 0) + (= (modulo n 7) 0) + (= (modulo n 11) 0) + (= (modulo n 13) 0) + (= (modulo n 17) 0) + (= (modulo n 19) 0) + (= (modulo n 23) 0))) +(define (is-fermat-prime? n iterations) + (or (<= iterations 0) + (let* ((byte-size (ceiling (/ (log n) (log 2)))) + (a (random byte-size))) + (if (= (modulo-power a (- n 1) n) 1) + (is-fermat-prime? n (- iterations 1)) + #f)))) +(define (generate-fermat-prime byte-size iterations) + (let ((n (random byte-size))) + (if + (and (not (is-trivial-composite? n)) (is-fermat-prime? n iterations)) + n + (generate-fermat-prime byte-size iterations)))) +(define iterations 10) +(define byte-size 15) +(generate-fermat-prime byte-size iterations) diff --git a/test/R5RS/DD/sales-period.scm b/test/R5RS/DD/sales-period.scm new file mode 100644 index 000000000..6f6a67475 --- /dev/null +++ b/test/R5RS/DD/sales-period.scm @@ -0,0 +1,57 @@ +;; replaced (apply + l) by (foldr + 0 l) + def of foldr +(define foldr + (lambda (f base lst) + + (define foldr-aux + (lambda (lst) + (if (null? lst) + base + (f (car lst) (foldr-aux (cdr lst)))))) + + (foldr-aux lst))) + +(define (totaal aankopen kortingen) + + (define (zoek-korting kortingen artikel) + (foldr + 0 + (map + (lambda (x) (if (eq? (car x) artikel) + (cadr x) + 0)) kortingen))) + + (if (null? aankopen) + 0 + (let* ((aankoop (car aankopen)) + (korting (zoek-korting kortingen (car aankoop))) + (prijs (cadr aankoop))) + (+ (- prijs (/ (* prijs korting) 100)) + (totaal (cdr aankopen) (cdr kortingen)))))) + +(define (totaal-iter aankopen kortingen) + + (define (zoek-korting kortingen artikel) + (foldr + 0 + (map + (lambda (x) (if (eq? (car x) artikel) + (cadr x) + 0)) kortingen))) + + (define (loop lst res) + (if (null? lst) + res + (let* ((aankoop (car lst)) + (korting (zoek-korting kortingen (car aankoop))) + (prijs (cadr aankoop))) + (loop (cdr lst) + (+ res (- prijs + (/ (* prijs korting) 100))))))) + (loop aankopen 0)) + +(define Z&Mkortingen '((jas 50) (kleed 50) (rok 30) (trui 20))) + +(and (= (totaal '((jas 100) (trui 25) (rok 70) (t-shirt 20)) + '((jas 50) (kleed 50) (rok 30) (trui 20))) + 139) + (= (totaal-iter '((jas 100) (trui 25) (rok 70) (t-shirt 20)) + '((jas 50) (kleed 50) (rok 30) (trui 20))) + 139)) diff --git a/test/R5RS/DD/twitter.scm b/test/R5RS/DD/twitter.scm new file mode 100644 index 000000000..38e038709 --- /dev/null +++ b/test/R5RS/DD/twitter.scm @@ -0,0 +1,90 @@ +(define result '()) +(define output (lambda (i) (set! result (cons i result)))) +(define linebreak (lambda () (set! result (cons 'linebreak result)))) + +(define (output-all . args) + (for-each output args)) +(define (output-all-sep args) + (for-each (lambda (arg) (output arg) (output " ")) + args)) + +(define (make-tweet username text tags) + + (define (output-tweet) + (output-all "Tweet from " username "\n" text "\nTags: ") + (output-all-sep tags) + (linebreak)) + + (define (dispatch msg) + (cond ((eq? msg 'text) text) + ((eq? msg 'tags) tags) + ((eq? msg 'username) username) + ((eq? msg 'output) output-tweet) + (else (output "error - wrong msg ") (output msg)))) + + (if (> (string-length text) 140) + #f + dispatch)) + +(define (make-account name username) + (let ((followers '()) + (tweets '()) + (tweet-wall '())) + + (define (follow account) + ((account 'add-follower) dispatch)) + + (define (add-follower account) + (set! followers (cons account followers))) + + (define (tweet text . tags) + (let ((tweet-obj (make-tweet username text tags))) + (set! tweets (cons tweet-obj tweets)) + (set! tweet-wall (cons tweet-obj tweet-wall)) + (for-each (lambda (follower) + ((follower 'add-tweet-to-wall) tweet-obj)) + followers))) + + (define (add-tweet-to-wall tweet) + (set! tweet-wall (cons tweet tweet-wall))) + + (define (output-wall) + (output "TWEET WALL") (linebreak) + (for-each (lambda (tweet) ((tweet 'output)) (linebreak)) + tweet-wall)) + + (define (dispatch msg) + (cond ((eq? msg 'name) name) + ((eq? msg 'username) username) + ((eq? msg 'follow) follow) + ((eq? msg 'add-follower) add-follower) + ((eq? msg 'tweet) tweet) + ((eq? msg 'add-tweet-to-wall) add-tweet-to-wall) + (else (output "error - wrong msg ") (output msg)))) + dispatch)) + +(define my-tweet (make-tweet "madewael" "Racket is cool!" (list "#Racket" "#Scheme"))) +(define res1 (equal? (my-tweet 'username) "madewael")) +((my-tweet 'output)) + +(define accountE (make-account "Eline Philips" "ephilips")) +(define accountM (make-account "Mattias De Wael" "madewael")) +((accountE 'follow) accountM) +(and res1 + (equal? result '(linebreak + linebreak + " " + "ephilips" + linebreak + "TWEET WALL" + "Twitter name " + linebreak + " " + "#Scheme" + " " + "#Racket" + "\nTags: " + "Racket is cool!" + "\n" + "madewael" + "Tweet from "))) \ No newline at end of file diff --git a/test/R5RS/DD/university.scm b/test/R5RS/DD/university.scm new file mode 100644 index 000000000..20b9577f1 --- /dev/null +++ b/test/R5RS/DD/university.scm @@ -0,0 +1,61 @@ +(define result '()) +(define display2 (lambda (i) (set! result (cons i result)))) +(define newline2 (lambda () (set! result (cons 'newline result)))) + +(define VUBOrganigram + '(VUB (academisch (rectoraat) + (faculteiten + (rechten (bachelor (ba-rechten) + (ba-criminologie)) + (master (ma-rechten) + (ma-criminologie))) + (economie))) + (administratief (personeel) (financien)))) + +(define (display-n n d) + (if (> n 0)(begin (display2 d)(display-n (- n 1) d)))) + +(define (print-lijn aantalblanco tekst) + (display-n aantalblanco " ") + (display2 tekst) + (newline2)) + +(define (label organigram) (car organigram)) +(define (takken organigram) (cdr organigram)) + +(define (organigram-member-in een-label organigrammen) + (if (null? organigrammen) + #f + (or (organigram-member een-label (car organigrammen)) + (organigram-member-in een-label (cdr organigrammen))))) + +(define (organigram-member een-label organigram) + (if (eq? een-label (label organigram)) + organigram + (organigram-member-in een-label (takken organigram)))) + +(define (print organigram) + (define (print diepte organigram) + (print-lijn diepte (label organigram)) + (for-each (lambda (organigram) + (print (+ diepte 1) organigram)) + (takken organigram))) + (print 0 organigram)) + +(define (print-vanaf organigram label) + (let ((res (organigram-member label organigram))) + (if res + (print res) + #f))) + +(print-vanaf VUBOrganigram 'rechten) + +(equal? result + '(newline + financien + " " + " " + newline + personeel + " " + " ")) diff --git a/test/R5RS/DD/work.scm b/test/R5RS/DD/work.scm new file mode 100644 index 000000000..d28b2d68f --- /dev/null +++ b/test/R5RS/DD/work.scm @@ -0,0 +1,44 @@ +;; Taken from http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/scheme/code/fun/ + +; +; Putting Scheme to Work +; By Olivier Danvy +; Bigre special edition "Putting Scheme to Work" +; + +(define fix + (let ((z (lambda (P) + (lambda (u) + (lambda (t) + (lambda (t) + (lambda (i) + (lambda (n) + (lambda (g) + (lambda (S) + (lambda (c) + (lambda (h) + (lambda (e) + (lambda (m) + (lambda (e) + (lambda (t) + (lambda (o) + (lambda (W) + (lambda (o) + (lambda (r) + (lambda (k) + (lambda (!) + (! (lambda (break) + (((((((((((((((((((((W o) r) k) + W) o) r) k) + W) o) r) k) + W) o) r) k) + W) o) r) k) !) + break))))))))))))))))))))))))) + (let ((Z z)) + (((((((((((((((((((z z) z) z) z) z) Z) Z) Z) Z) Z) Z) Z) z) z) z) z) z) z) z)))) + +((fix (lambda (f) + (lambda (n) + (if (zero? n) + 1 + (* n (f (- n 1))))))) 9) \ No newline at end of file diff --git a/test/R5RS/DD2/apple-tree.scm b/test/R5RS/DD2/apple-tree.scm new file mode 100644 index 000000000..286e69d37 --- /dev/null +++ b/test/R5RS/DD2/apple-tree.scm @@ -0,0 +1,76 @@ +(define boom + '((blad (appel . golden)) + (blad (appel . granny)) + (((appel . golden) blad) blad (appel . cox)))) + +(define (blad? boom) + (eq? boom 'blad)) + +(define (appel? boom) + (and (pair? boom) (eq? (car boom) 'appel))) + +(define (type appel) (cdr appel)) + +(define (leafs boom) + (cond ((null? boom) 0) + ((blad? boom) 1) + ((appel? boom) 0) + (else (+ (leafs (car boom)) + (leafs (cdr boom)))))) + +(define (all-apples boom) + (cond ((null? boom) '()) + ((blad? boom) '()) + ((appel? boom) (list (type boom))) + (else (append (all-apples (car boom)) + (all-apples (cdr boom)))))) + +(define (conditional-append l1 l2) + (cond + ((null? l1) l2) + ((member (car l1) l2)(conditional-append (cdr l1) l2)) + (else (cons (car l1)(conditional-append (cdr l1) l2))))) + +(define (apple-types boom) + (cond ((null? boom) '()) + ((blad? boom) '()) + ((appel? boom) (list (type boom))) + (else (conditional-append (apple-types (car boom)) + (apple-types (cdr boom)))))) + +(define (bewerk-boom boom doe-blad doe-appel combiner init) + (cond + ((null? boom) init) + ((blad? boom) (doe-blad boom)) + ((appel? boom) (doe-appel boom)) + (else (combiner + (bewerk-boom (car boom) doe-blad doe-appel combiner init) + (bewerk-boom (cdr boom) doe-blad doe-appel combiner init))))) + +(define (leafs-dmv-bewerk boom) + (bewerk-boom boom + (lambda (blad) 1) + (lambda (appel) 0) + + + 0)) + +(define (all-apples-dmv-bewerk boom) + (bewerk-boom boom + (lambda(blad) '()) + (lambda(appel) (list (type appel))) + append + '())) + +(define (apple-types-dmv-bewerk boom) + (bewerk-boom boom + (lambda(blad) '()) + (lambda(appel) (list(type appel))) + conditional-append + '())) + +(and (= (leafs boom) 4) + (equal? (all-apples boom) '(golden granny golden cox)) + (equal? (apple-types boom) '(granny golden cox)) + (= (leafs-dmv-bewerk boom) 4) + (equal? (all-apples-dmv-bewerk boom) '(golden granny golden cox)) + (equal? (apple-types-dmv-bewerk boom) '(granny golden cox))) \ No newline at end of file diff --git a/test/R5RS/DD2/calc-e-and-cos.scm b/test/R5RS/DD2/calc-e-and-cos.scm new file mode 100644 index 000000000..132c2bdde --- /dev/null +++ b/test/R5RS/DD2/calc-e-and-cos.scm @@ -0,0 +1,30 @@ +(define (calc-e-iter n) + (define (iter ctr res fac-prev) + (if (> ctr n) + res + (let ((new-fac (* ctr fac-prev))) + (iter (+ ctr 1) (+ res (/ 1 new-fac)) new-fac)))) + (iter 1 1 1)) + +(define (calc-cos x n) + (define (iter ctr acc fac xpow sign) + (if (>= ctr n) + acc + (let* ((i (* 2 ctr)) + (newfac (* fac (- i 1) i)) + (newxpow (* xpow x x)) + (newsign (- sign))) + (iter (+ ctr 1) + (+ acc (/ (* newsign newxpow) newfac)) + newfac + newxpow + newsign)))) + (iter 1 1 1 1 1)) + +(define (close-to x y) + (< (abs (- x y)) 0.00000001)) + +(and (close-to (exact->inexact (calc-e-iter 10)) 2.7182818011463845) + (close-to (calc-cos 0 10) 1) + (close-to (calc-cos (/ 3.1415 2) 10) 4.6326794876592664e-05) + (close-to (calc-cos 3.1415 10) -0.9999999992346591)) diff --git a/test/R5RS/DD2/cashdesk-counter.scm b/test/R5RS/DD2/cashdesk-counter.scm new file mode 100644 index 000000000..29d55dd48 --- /dev/null +++ b/test/R5RS/DD2/cashdesk-counter.scm @@ -0,0 +1,69 @@ +(define (maak-teller) + (let ((result 0)) + + (define (toets bedrag) + (set! result (+ result bedrag))) + + (define (reset) + (set! result 0)) + + (define (dispatch msg) + (cond ((eq? msg 'toets) toets) + ((eq? msg 'lees) result) + ((eq? msg 'reset) (reset)) + (else (error "wrong message")))) + dispatch)) + +(define (maak-winkelkassa) + (let ((saldo (maak-teller)) + (te-betalen (maak-teller)) + (ingetoetst 'product) + (ontvangen 0)) + + (define (toets type bedrag) + (set! ingetoetst type) + (cond ((eq? type 'product) + ((te-betalen 'toets) bedrag)) + ((eq? type 'ontvangen) + (set! ontvangen bedrag)) + (else (error "wrong type")))) + + (define (enter) + (if (eq? ingetoetst 'product) + (te-betalen 'lees) + (let ((wisselgeld (- ontvangen (te-betalen 'lees)))) + ((saldo 'toets) (te-betalen 'lees)) + (te-betalen 'reset) + wisselgeld))) + + (define (inhoud) + (saldo 'lees)) + + (define (afsluiten) + (let ((teruggeven saldo)) + (set! saldo 0) + teruggeven)) + + (define (dispatch msg) + (cond ((eq? msg 'toets) toets) + ((eq? msg 'enter) (enter)) + ((eq? msg 'inhoud) (inhoud)) + ((eq? msg 'afsluiten) (afsluiten)) + (else (error "wrong message")))) + dispatch)) + +(define teller (maak-teller)) +(define winkelkassa (maak-winkelkassa)) +((winkelkassa 'toets) 'product 20) +((teller 'toets) 20) +((winkelkassa 'toets) 'product 5) +(and (= (teller 'lees) 20) + (begin (teller 'reset) + (= (teller 'lees) 0)) + (= (winkelkassa 'enter) 25) + (= (begin ((winkelkassa 'toets) 'product 10) + (winkelkassa 'enter)) + 35) + (begin ((winkelkassa 'toets) 'ontvangen 50) + (= (winkelkassa 'enter) 15)) + (= (winkelkassa 'inhoud) 35)) \ No newline at end of file diff --git a/test/R5RS/DD2/grades.scm b/test/R5RS/DD2/grades.scm new file mode 100644 index 000000000..fc9a2d64f --- /dev/null +++ b/test/R5RS/DD2/grades.scm @@ -0,0 +1,34 @@ +(define (show namen punten test?) + (if (null? namen) + '() + (let ((res (show (cdr namen) (cdr punten) test?))) + (if (test? (car punten)) + (cons (car namen) res) + res)))) + +(define (one namen punten) + (define (één-buis? punten) + (if (null? punten) + #f + (let ((punt (car punten)) + (rest (cdr punten))) + (if (< punt 10) + (geen-buis? rest) + (één-buis? rest))))) + + + (define (geen-buis? punten) + (if (null? punten) + #t + (let ((punt (car punten)) + (rest (cdr punten))) + (if (< punt 10) + #f + (geen-buis? rest))))) + + (show namen punten één-buis?)) + +(equal? (one '(wendy dirk kris jan eef) + '((12 13 15 18) (7 10 14 17) (13 8 7 11) + (9 12 11 10) (18 14 17 19))) + '(dirk jan)) \ No newline at end of file diff --git a/test/R5RS/DD2/josephus-problem.scm b/test/R5RS/DD2/josephus-problem.scm new file mode 100644 index 000000000..15fbe6852 --- /dev/null +++ b/test/R5RS/DD2/josephus-problem.scm @@ -0,0 +1,66 @@ +(define result '()) +(define output (lambda (i) (set! result (cons i result)))) + +(define (make-ring n) + (let ((last (cons 0 '()))) + (define (build-list n) + (if (= n 0) + last + (cons n (build-list (- n 1))))) + (let ((ring (build-list n))) + (set-cdr! last ring) + ring))) + +(define (print-ring r) + (define (aux l) + (if (not (null? l)) + (if (eq? (cdr l) r) + (begin (output " ") + (output (car l)) + (output "...")) + (begin (output " ") + (output (car l)) + (aux (cdr l)))))) + (aux r) + #t) + +(define (copy-ring r) + (define last '()) + (define (aux l) + (cond ((eq? (cdr l) r) + (set! last (cons (car l) '())) + last) + (else (cons (car l) (aux (cdr l)))))) + + (let ((first (aux r))) + (set-cdr! last first) + first)) + +(define (right-rotate r) + (define (iter l) + (if (eq? (cdr l) r) + l + (iter (cdr l)))) + (iter r)) + +(define (Josephus r n) + (define (remove-nth! l n) + (if (<= n 2) + (begin (set-cdr! l (cddr l)) + (cdr l)) + (remove-nth! (cdr l) (- n 1)))) + + (define (iter l) + (print-ring l) + (if (eq? l (cdr l)) + (car l) + (iter (remove-nth! l n)))) + + (if (= n 1) + (car (right-rotate r)) + (iter (copy-ring r)))) + +(define ring (make-ring 5)) +(Josephus ring 5) +(print-ring ring) +(equal? result '("..." 0 " " 1 " " 2 " " 3 " " 4 " " 5 " " "..." 5 " " "..." 5 " " 3 " " "..." 3 " " 4 " " 5 " " "..." 3 " " 4 " " 5 " " 0 " " "..." 2 " " 3 " " 4 " " 5 " " 0 " " "..." 0 " " 1 " " 2 " " 3 " " 4 " " 5 " ")) \ No newline at end of file diff --git a/test/R5RS/DD2/lightbulb.scm b/test/R5RS/DD2/lightbulb.scm new file mode 100644 index 000000000..5b20cbb22 --- /dev/null +++ b/test/R5RS/DD2/lightbulb.scm @@ -0,0 +1,50 @@ +(define (MaakLampje aantal) + (define state 'off) + + (define (on!) (set! state 'on)) + + (define (off!) (set! state 'off)) + + (define (broken!) (set! state 'broken)) + + (define (on?) (eq? state 'on)) + + (define (off?) (eq? state 'off)) + + (define (broken?) (eq? state 'broken)) + + (define (switch!) + (set! aantal (- aantal 1)) + (cond ((< aantal 0) (broken!)) + ((off?) (on!)) + ((on?) (off!))) + (not (broken?))) + + (define (change! nieuw) + (off!) + (set! aantal nieuw) + 'changed) + + (define (dispatch msg) + (cond ((eq? msg 'switch!) (switch!)) + ((eq? msg 'on?) (on?)) + ((eq? msg 'off?) (off?)) + ((eq? msg 'test?) (broken?)) + ((eq? msg 'change!) change!) + (else (error "Message not understood.")))) + dispatch) + +(define philips (MaakLampje 5)) +(and (not (philips 'test?)) + (not (philips 'on?)) + (philips 'off?) + (philips 'switch!) + (philips 'switch!) + (philips 'switch!) + (philips 'switch!) + (philips 'switch!) + (not (philips 'switch!)) + (philips 'test?) + (begin ((philips 'change!) 10) + (not (philips 'test?))) + (philips 'off?)) \ No newline at end of file diff --git a/test/R5RS/DD2/organigram.scm b/test/R5RS/DD2/organigram.scm new file mode 100644 index 000000000..16ab4ceda --- /dev/null +++ b/test/R5RS/DD2/organigram.scm @@ -0,0 +1,58 @@ +(define organigram + '(directeur + (hoofd-verkoop (verkoopsleider-vlaanderen) + (verkoopsleider-brussel)) + (hoofd-productie (hoofd-inkoop (bediende1) + (bediende2) + (bediende3)) + (hoofd-fakturen)) + (hoofd-administratie (hoofd-personeel) + (hoofd-boekhouding)))) + +(define (baas organigram) (car organigram)) +(define (sub-organigrammen organigram) (cdr organigram)) + +(define (hierarchisch? p1 p2 organigram) + (define (hierarchisch?-in path organigrammen) + (if (null? organigrammen) + #f + (or (hierarchisch? path (car organigrammen)) + (hierarchisch?-in path (cdr organigrammen))))) + + (define (hierarchisch? path organigram) + (cond + ((and (eq? p1 (baas organigram)) (member p2 path)) #t) + ((and (eq? p2 (baas organigram)) (member p1 path)) #t) + (else (hierarchisch?-in (cons (baas organigram) path) + (sub-organigrammen organigram))))) + (hierarchisch? '() organigram)) + +(define (collegas p organigram) + (define (collegas-in oversten organigrammen) + (if (null? organigrammen) + #f + (or (collegas oversten (car organigrammen)) + (collegas-in oversten (cdr organigrammen))))) + + (define (werknemers-in organigrammen) + (if (null? organigrammen) + '() + (append (werknemers (car organigrammen)) + (werknemers-in (cdr organigrammen))))) + + (define (werknemers organigram) + (cons (baas organigram) + (werknemers-in (sub-organigrammen organigram)))) + + (define (collegas oversten organigram) + (if (eq? p (baas organigram)) + (append oversten + (werknemers-in (sub-organigrammen organigram))) + (collegas-in (cons (baas organigram) oversten) + (sub-organigrammen organigram)))) +(collegas '() organigram)) + +(and (hierarchisch? 'directeur 'verkoopsleider-brussel organigram) + (hierarchisch? 'bediende1 'hoofd-productie organigram) + (not (hierarchisch? 'hoofd-personeel 'bediende3 organigram)) + (equal? (collegas 'hoofd-inkoop organigram) '(hoofd-productie directeur bediende1 bediende2 bediende3))) diff --git a/test/R5RS/DD2/scoreboard.scm b/test/R5RS/DD2/scoreboard.scm new file mode 100644 index 000000000..fcf9f2283 --- /dev/null +++ b/test/R5RS/DD2/scoreboard.scm @@ -0,0 +1,75 @@ +(define result '()) +(define output (lambda (i) (set! result (cons i result)))) +(define linebreak (lambda () (set! result (cons 'linebreak result)))) + +(define (create-counter) + (let ((value 0)) + + (define (reset) + (set! value 0) + 'ok) + + (define (next) + (set! value (+ 1 value)) + 'ok) + + (define (increase x) + (set! value (+ value x))) + + (define (dispatch msg) + (cond ((eq? msg 'reset) reset) + ((eq? msg 'next) next) + ((eq? msg 'read) value) + ((eq? msg 'increase) increase) + (else (error "wrong message: " msg)))) + dispatch)) + + +(define (make-scorebord) + (let ((c-home (create-counter)) + (c-visit (create-counter))) + + (define (reset) + ((c-home 'reset)) + ((c-visit 'reset)) + 'ok) + + (define (read) + (let ((c1 (c-home 'read)) + (c2 (c-visit 'read))) + (output c1) + (output "-") + (output c2) + (linebreak) + 'ok)) + + (define (score team n) + (cond ((not (or (= n 1) (= n 2) (= n 3))) + (linebreak) + (output "De score kan slechts 1, 2 of 3 zijn!") + (linebreak) + 'ok) + ((eq? team 'home) + ((c-home 'increase) n) + 'ok) + ((eq? team 'visit) + ((c-visit 'increase) n) + 'ok) + (else (error "wrong team: " team)))) + + (define (dispatch msg) + (cond ((eq? msg 'reset) reset) + ((eq? msg 'read) read) + ((eq? msg 'score) score) + (else (error "wrong message: " msg)))) + dispatch)) + +(define bord (make-scorebord)) +((bord 'read)) +((bord 'score) 'home 2) +((bord 'read)) +((bord 'score) 'visit 5) +((bord 'read)) +((bord 'reset)) +((bord 'read)) +(equal? result '(linebreak 0 "-" 0 linebreak 0 "-" 2 linebreak "De score kan slechts 1, 2 of 3 zijn!" linebreak linebreak 0 "-" 2 linebreak 0 "-" 0)) diff --git a/test/R5RS/various/LambdaKillingTest1.scm b/test/R5RS/various/LambdaKillingTest1.scm new file mode 100644 index 000000000..33d8b544a --- /dev/null +++ b/test/R5RS/various/LambdaKillingTest1.scm @@ -0,0 +1,20 @@ +(define (fac n) + (if (= n 0) + 1 + (* n (fac (- n 1))))) + +(define (math1) + (+ 0 0) + (fac 3)) + +(define (math2) + (* 0 0) + (fac 5)) + +(define (does-nothing arg1 arg2) + -1) + +(math1) +(math2) + +(does-nothing fac fac) \ No newline at end of file diff --git a/test/R5RS/various/deadCodeTest.scm b/test/R5RS/various/deadCodeTest.scm new file mode 100644 index 000000000..8270a1e66 --- /dev/null +++ b/test/R5RS/various/deadCodeTest.scm @@ -0,0 +1,10 @@ +(define (called n) + (+ 1 1) + n) + +(define (uncalled n) + n) + +(if #t + (called 10) + (uncalled 11)) \ No newline at end of file diff --git a/test/R5RS/various/deadCodeTest2.scm b/test/R5RS/various/deadCodeTest2.scm new file mode 100644 index 000000000..e81f58d7a --- /dev/null +++ b/test/R5RS/various/deadCodeTest2.scm @@ -0,0 +1,14 @@ +(define (called n) + (if (= n 0) + 10 + "hello")) + +(called 0) +(called 1) + +(define (constant-bool n) + n + #f) + +(constant-bool 10) +20 \ No newline at end of file diff --git a/test/R5RS/various/deadCodeTest3.scm b/test/R5RS/various/deadCodeTest3.scm new file mode 100644 index 000000000..92b5a819a --- /dev/null +++ b/test/R5RS/various/deadCodeTest3.scm @@ -0,0 +1,17 @@ +(define (dead-l x y z) + (+ x y) + (+ y z) + (+ z x)) + +(define (alive a b c) + (+ a b)) + + +(alive 3 2 0) +(alive 3 2 dead-l) + +(if #t + (alive 1 2 3) + (begin + (alive 9 9 9) + (alive 8 8 8))) \ No newline at end of file diff --git a/test/R5RS/various/values.scm b/test/R5RS/various/values.scm new file mode 100644 index 000000000..70b7af46b --- /dev/null +++ b/test/R5RS/various/values.scm @@ -0,0 +1,12 @@ +(define (number->string n) + (if (= n 1) + "1" + "-1")) + +(define (string->number s) + (if (eq? "a" s) + 1 + 2)) + +(number->string 1) +(string->number "a") \ No newline at end of file