From 08a4c48c46fcad47459e2c41ad54bf9a07fd2354 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mika=C3=ABl=20Mayer?= <mikael.mayer@epfl.ch>
Date: Thu, 21 Apr 2016 11:16:48 +0200
Subject: [PATCH] olveMinChange for StringSolver (incremental)

---
 .../leon/solvers/string/StringSolver.scala    | 28 +++++++++++++++++++
 .../solvers/StringSolverSuite.scala           | 17 +++++++++++
 2 files changed, 45 insertions(+)

diff --git a/src/main/scala/leon/solvers/string/StringSolver.scala b/src/main/scala/leon/solvers/string/StringSolver.scala
index bc9ee8419..b717cccf5 100644
--- a/src/main/scala/leon/solvers/string/StringSolver.scala
+++ b/src/main/scala/leon/solvers/string/StringSolver.scala
@@ -628,4 +628,32 @@ object StringSolver {
       solveGeneralProblem(unbounded.map(reduceGeneralEquation(assignment)(_))).map(assignment ++ _)
     })
   }
+  
+  
+  ////////////////////////////////////////////////
+  ////      Incremental problem extension     ////
+  ////////////////////////////////////////////////
+  
+  /** Returns all subsets of i elements of a sequence. */
+  def take[A](i: Int, of: Seq[A]): Stream[Seq[A]] = {
+    if(i > of.size || i < 0) Stream.empty
+    if(i == of.size) Stream(of)
+    else if(i == 0) Stream(Seq.empty)
+    else {
+      take(i - 1, of.tail).map(of.head +: _) #::: take(i, of.tail)
+    }
+  }
+  
+  /** Solves the problem while supposing that a minimal number of variables have been changed.*/
+  def solveMinChange(p: Problem, initialMapping: Assignment): Stream[Assignment] = {
+    // First try to see if the problem is solved. If yes, returns the initial mapping
+    val initKeys = initialMapping.keys.toSeq
+    for{
+      i <- (initialMapping.size to 0 by -1).toStream
+      kept <- take(i, initKeys)
+      ifKept = kept.toSet
+      newProblem = reduceProblem(initialMapping filterKeys ifKept)(p)
+      solution <- solve(newProblem)
+    } yield solution
+  }
 }
\ No newline at end of file
diff --git a/src/test/scala/leon/integration/solvers/StringSolverSuite.scala b/src/test/scala/leon/integration/solvers/StringSolverSuite.scala
index 029bfb233..6faad419e 100644
--- a/src/test/scala/leon/integration/solvers/StringSolverSuite.scala
+++ b/src/test/scala/leon/integration/solvers/StringSolverSuite.scala
@@ -242,4 +242,21 @@ T2: ret Pop() -> 5"""
     assert(p.isReadyWithin(2 seconds), "Could not solve propagate")
     p.futureValue should not be('empty)
   }
+  
+  test("solveMinChange") {
+    implicit val idMap = MMap[String, Identifier]()
+    val problem = List(
+        "u+v+w" === "akbc"
+    )
+    val u = idMap("u")
+    val v = idMap("v")
+    val w = idMap("w")
+    val solutions = solveMinChange(problem, Map(u -> "a", v -> "b", w -> "c"))
+    solutions(0) should equal (Map(v -> "kb"))
+    solutions(1) should equal (Map(u -> "ak"))
+    (2 to 5).toSet.map((i: Int) => solutions(i)) should equal (Set(Map(v -> "", w -> "kbc")
+    , Map(v -> "k", w -> "bc")
+    , Map(v -> "kb", w -> "c")
+    , Map(v -> "kbc", w -> "")))
+  }
 }
\ No newline at end of file
-- 
GitLab