From 7888fdb8a3191f32f7ee48361916b48e0dcefb5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Blanc?= <regwblanc@gmail.com> Date: Tue, 20 Nov 2012 15:16:22 +0100 Subject: [PATCH] refactor GCD and other --- .../synthesis/{GCD.scala => Algebra.scala} | 38 +++++++++++++++++- .../synthesis/ArithmeticNormalization.scala | 4 -- .../leon/synthesis/LinearEquations.scala | 40 ++++--------------- .../synthesis/rules/IntegerInequalities.scala | 3 +- .../{GCDSuite.scala => AlgebraSuite.scala} | 35 +++++++++++++++- 5 files changed, 79 insertions(+), 41 deletions(-) rename src/main/scala/leon/synthesis/{GCD.scala => Algebra.scala} (63%) rename src/test/scala/leon/test/synthesis/{GCDSuite.scala => AlgebraSuite.scala} (83%) diff --git a/src/main/scala/leon/synthesis/GCD.scala b/src/main/scala/leon/synthesis/Algebra.scala similarity index 63% rename from src/main/scala/leon/synthesis/GCD.scala rename to src/main/scala/leon/synthesis/Algebra.scala index 47057dced..c92b08980 100644 --- a/src/main/scala/leon/synthesis/GCD.scala +++ b/src/main/scala/leon/synthesis/Algebra.scala @@ -1,6 +1,14 @@ package leon.synthesis -object GCD { +/* + * This provides some algebra/number theory functions, including operation such as true division, + * GCD and LCM as well as some matrix computation. + * + * Notice that all those functionalities are independent of the Leon language and + * are working for Integer (by opposition to real numbers). + */ + +object Algebra { def remainder(x: Int, y: Int) = ((x % y) + y.abs) % y.abs @@ -92,4 +100,32 @@ object GCD { else sys.error("shouldn't have forgot a case here") } + + //val that the sol vector with the term in the equation + def eval(sol: Array[Int], equation: Array[Int]): Int = { + require(sol.size == equation.size) + sol.zip(equation).foldLeft(0)((acc, p) => acc + p._1 * p._2) + } + + //multiply the matrix by the vector: [M1 M2 .. Mn] * [v1 .. vn] = v1*M1 + ... + vn*Mn] + def mult(matrix: Array[Array[Int]], vector: Array[Int]): Array[Int] = { + require(vector.size == matrix(0).size && vector.size > 0) + val tmat = matrix.transpose + var tmp: Array[Int] = null + tmp = mult(vector(0), tmat(0)) + var i = 1 + while(i < vector.size) { + tmp = add(tmp, mult(vector(i), tmat(i))) + i += 1 + } + tmp + } + + def mult(c: Int, v: Array[Int]): Array[Int] = v.map(_ * c) + + def add(v1: Array[Int], v2: Array[Int]): Array[Int] = { + require(v1.size == v2.size) + v1.zip(v2).map(p => p._1 + p._2) + } + } diff --git a/src/main/scala/leon/synthesis/ArithmeticNormalization.scala b/src/main/scala/leon/synthesis/ArithmeticNormalization.scala index f81311ffd..6c148e2cc 100644 --- a/src/main/scala/leon/synthesis/ArithmeticNormalization.scala +++ b/src/main/scala/leon/synthesis/ArithmeticNormalization.scala @@ -4,10 +4,6 @@ import leon.purescala.Trees._ import leon.purescala.TreeOps._ import leon.purescala.Common._ -/* - * TODO: move those functions to TreeOps - */ - object ArithmeticNormalization { case class NonLinearExpressionException(msg: String) extends Exception diff --git a/src/main/scala/leon/synthesis/LinearEquations.scala b/src/main/scala/leon/synthesis/LinearEquations.scala index 3d9eb6230..63e234320 100644 --- a/src/main/scala/leon/synthesis/LinearEquations.scala +++ b/src/main/scala/leon/synthesis/LinearEquations.scala @@ -4,6 +4,7 @@ import leon.purescala.Trees._ import leon.purescala.TypeTrees._ import leon.purescala.Common._ import leon.Evaluator +import leon.synthesis.Algebra._ object LinearEquations { @@ -17,7 +18,7 @@ object LinearEquations { val orderedParams: Array[Identifier] = as.toArray val coefsParams0: List[Int] = ArithmeticNormalization(t, orderedParams).map{case IntLiteral(i) => i}.toList val coefsParams: List[Int] = if(coefsParams0.head == 0) coefsParams0.tail else coefsParams0 - val d: Int = GCD.gcd((coefsParams ++ coefsVars).toSeq) + val d: Int = gcd((coefsParams ++ coefsVars).toSeq) if(coefsVars.size == 1) { val coef = coefsVars.head @@ -45,33 +46,6 @@ object LinearEquations { } - //val that the sol vector with the term in the equation - def eval(sol: Array[Int], equation: Array[Int]): Int = { - require(sol.size == equation.size) - sol.zip(equation).foldLeft(0)((acc, p) => acc + p._1 * p._2) - } - - //multiply the matrix by the vector: [M1 M2 .. Mn] * [v1 .. vn] = v1*M1 + ... + vn*Mn] - def mult(matrix: Array[Array[Int]], vector: Array[Int]): Array[Int] = { - require(vector.size == matrix(0).size && vector.size > 0) - val tmat = matrix.transpose - var tmp: Array[Int] = null - tmp = mult(vector(0), tmat(0)) - var i = 1 - while(i < vector.size) { - tmp = add(tmp, mult(vector(i), tmat(i))) - i += 1 - } - tmp - } - - def mult(c: Int, v: Array[Int]): Array[Int] = v.map(_ * c) - - def add(v1: Array[Int], v2: Array[Int]): Array[Int] = { - require(v1.size == v2.size) - v1.zip(v2).map(p => p._1 + p._2) - } - //compute a list of solution of the equation c1*x1 + ... + cn*xn where coef = [c1 ... cn] //return the solution in the form of a list of n-1 vectors that form a basis for the set //of solutions, that is res=(v1, ..., v{n-1}) and any solution x* to the original solution @@ -87,7 +61,7 @@ object LinearEquations { if(i < j) K(i)(j) = 0 else if(i == j) { - K(j)(j) = GCD.gcd(coef.drop(j+1))/GCD.gcd(coef.drop(j)) + K(j)(j) = gcd(coef.drop(j+1))/gcd(coef.drop(j)) } } } @@ -117,8 +91,8 @@ object LinearEquations { //return a particular solution to t + c1x + c2y = 0, with (pre, (x0, y0)) def particularSolution(as: Set[Identifier], t: Expr, c1: Expr, c2: Expr): (Expr, (Expr, Expr)) = { val (IntLiteral(i1), IntLiteral(i2)) = (c1, c2) - val (v1, v2) = GCD.extendedEuclid(i1, i2) - val d = GCD.gcd(i1, i2) + val (v1, v2) = extendedEuclid(i1, i2) + val d = gcd(i1, i2) val pre = Equals(Modulo(t, IntLiteral(d)), IntLiteral(0)) @@ -135,7 +109,7 @@ object LinearEquations { require(normalizedEquation.size >= 2) val t: Expr = normalizedEquation.head val coefs: List[Int] = normalizedEquation.tail.map{case IntLiteral(i) => i} - val d = GCD.gcd(coefs.toSeq) + val d = gcd(coefs.toSeq) val pre = Equals(Modulo(t, IntLiteral(d)), IntLiteral(0)) if(normalizedEquation.size == 2) { @@ -146,7 +120,7 @@ object LinearEquations { } else { val gamma1: Expr = normalizedEquation(1) val coefs: List[Int] = normalizedEquation.drop(2).map{case IntLiteral(i) => i} - val gamma2: Expr = IntLiteral(GCD.gcd(coefs.toSeq)) + val gamma2: Expr = IntLiteral(gcd(coefs.toSeq)) val (_, (w1, w)) = particularSolution(as, t, gamma1, gamma2) val (_, sols) = particularSolution(as, UMinus(Times(w, gamma2)) :: normalizedEquation.drop(2)) (pre, w1 :: sols) diff --git a/src/main/scala/leon/synthesis/rules/IntegerInequalities.scala b/src/main/scala/leon/synthesis/rules/IntegerInequalities.scala index a4ff5fc7a..d3fb488de 100644 --- a/src/main/scala/leon/synthesis/rules/IntegerInequalities.scala +++ b/src/main/scala/leon/synthesis/rules/IntegerInequalities.scala @@ -9,6 +9,7 @@ import purescala.TreeOps._ import purescala.TypeTrees._ import purescala.Definitions._ import LinearEquations.elimVariable +import leon.synthesis.Algebra.lcm class IntegerInequalities(synth: Synthesizer) extends Rule("Integer Inequalities", synth, 300) { def attemptToApplyOn(problem: Problem): RuleResult = { @@ -96,7 +97,7 @@ class IntegerInequalities(synth: Synthesizer) extends Rule("Integer Inequalities yield LessEquals(ceilingDiv(lb, IntLiteral(lc)), floorDiv(ub, IntLiteral(uc)))) RuleFastSuccess(Solution(pre, Set(), witness)) } else { - val L = GCD.lcm((upperBounds ::: lowerBounds).map(_._2)) + val L = lcm((upperBounds ::: lowerBounds).map(_._2)) val newUpperBounds: List[Expr] = upperBounds.map{case (bound, coef) => Times(IntLiteral(L/coef), bound)} val newLowerBounds: List[Expr] = lowerBounds.map{case (bound, coef) => Times(IntLiteral(L/coef), bound)} diff --git a/src/test/scala/leon/test/synthesis/GCDSuite.scala b/src/test/scala/leon/test/synthesis/AlgebraSuite.scala similarity index 83% rename from src/test/scala/leon/test/synthesis/GCDSuite.scala rename to src/test/scala/leon/test/synthesis/AlgebraSuite.scala index eaaa20eb6..240b613dc 100644 --- a/src/test/scala/leon/test/synthesis/GCDSuite.scala +++ b/src/test/scala/leon/test/synthesis/AlgebraSuite.scala @@ -2,9 +2,38 @@ package leon.test.synthesis import org.scalatest.FunSuite -import leon.synthesis.GCD._ +import leon.synthesis.Algebra._ -class GCDSuite extends FunSuite { +class AlgebraSuite extends FunSuite { + + test("remainder") { + assert(remainder(1,1) === 0) + assert(remainder(2,2) === 0) + assert(remainder(2,1) === 0) + assert(remainder(0,1) === 0) + assert(remainder(0,4) === 0) + assert(remainder(1,3) === 1) + assert(remainder(1,8) === 1) + assert(remainder(4,2) === 0) + assert(remainder(17,3) === 2) + assert(remainder(25,5) === 0) + assert(remainder(26,5) === 1) + assert(remainder(29,5) === 4) + + assert(remainder(1,-1) === 0) + assert(remainder(-1,1) === 0) + assert(remainder(2,-2) === 0) + assert(remainder(-2,-2) === 0) + assert(remainder(-2,1) === 0) + assert(remainder(0,-1) === 0) + assert(remainder(1,-2) === 1) + assert(remainder(-1,2) === 1) + assert(remainder(-1,3) === 2) + assert(remainder(-1,-3) === 2) + assert(remainder(1,-3) === 1) + assert(remainder(17,-3) === 2) + assert(remainder(-25,5) === 0) + } test("divide") { assert(divide(1,1) === (1, 0)) @@ -170,3 +199,5 @@ class GCDSuite extends FunSuite { checkExtendedEuclid(10, -15) } } + +// vim: set ts=4 sw=4 et: -- GitLab