diff --git a/.gitignore b/.gitignore
index 691ecc38..d700149c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,12 +1,17 @@
*~
+
+# sbt-specific
target/
-.project
-.cache
+
+# eclipse
.classpath
-.worksheet
-.history
-*.sc
+.worksheet/
.settings/
+.project
+target.eclipse/
+.cache-main
+.cache-tests
+*.sc
+*.log
+# intellij idea
.idea/
-.cache-*
-
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..b5358b53
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,6 @@
+language: scala
+scala:
+ - 2.12.4
+
+script:
+ - sbt test
diff --git a/build.sbt b/build.sbt
index 8fb7ea0e..973d03f1 100644
--- a/build.sbt
+++ b/build.sbt
@@ -1,54 +1,67 @@
+import CustomKeys._
+
//*** Declare projects
-val Jandom = project in file("core") enablePlugins(BuildInfoPlugin)
+lazy val JandomCore = project in file("core") enablePlugins(BuildInfoPlugin)
+
+lazy val JandomExtended = project in file("extended") dependsOn JandomCore % "compile->compile;test->test"
+
+lazy val Jandom = project in file(".") aggregate (JandomCore, JandomExtended)
+
+//*** This delegates the Jandom run task to execute the run task in the Jandom sub-projects
-val JandomExtended = project in file("extended") dependsOn Jandom % "compile->compile;test->test"
+aggregate in assembly := false
-val root = project in file(".") aggregate (Jandom, JandomExtended)
+assembly := (assembly in JandomExtended).value
-// This delegates the root run task to the run task in the Jandom project
+run := (run in JandomCore in Compile).evaluated
-run <<= run in ("Jandom", Compile)
+run in Test := (run in JandomCore in Test).evaluated
-run in Test <<= run in ("Jandom", Test)
+run in Jmh := (run in JandomExtended in Jmh).evaluated
-// Add a new benchmark configuration...
-// val Bench = config("bench") extend(Test)
-// val root = project in file(".") configs(Bench) settings( inConfig(Bench) (Defaults.testSettings):_*) aggregate (Jandom, JandomExtended)
+//*** Do not update snapshots every time
+
+updateOptions in ThisBuild := updateOptions.value.withLatestSnapshots(false)
//*** Scala configuration
-scalaVersion in ThisBuild := "2.11.8"
+scalaVersion in ThisBuild := "2.12.3"
-scalacOptions in ThisBuild ++= Seq("-deprecation", "-feature", "-Xlint", "-Xlint:-delayedinit-select", "-Xlint:-missing-interpolator")
+scalacOptions in ThisBuild ++= Seq("-deprecation", "-feature", "-unchecked", "-Xlint:_,-missing-interpolator", "-Ywarn-unused:-implicits")
fork in ThisBuild := true
//*** Resolvers
-resolvers in ThisBuild ++= Seq(
+resolvers in ThisBuild ++= Seq (
Resolver.sonatypeRepo("releases"),
- Resolver.sonatypeRepo("snapshots")
+ Resolver.sonatypeRepo("snapshots"),
+ "Soot snapshot" at "https://soot-build.cs.uni-paderborn.de/nexus/repository/soot-snapshot/",
+ "Soot release" at
+ "https://soot-build.cs.uni-paderborn.de/nexus/repository/soot-release/"
)
-//*** Detect PPL
+//*** Custom keys
-val optionalPPLPathName = try {
- val PPLPathName = Process("ppl-config -l").lines.head+"/ppl/ppl_java.jar"
+pplJar in ThisBuild := {
+ try {
+ val PPLPathName = scala.sys.process.Process("ppl-config -l").lineStream.head+"/ppl/ppl_java.jar"
if (file(PPLPathName).exists) Some(PPLPathName) else None
} catch {
case _ : Exception => None
}
+}
+
+gitHeadCommitSHA in ThisBuild := scala.sys.process.Process("git rev-parse HEAD").lineStream.head
+
+//*** Eclipse plugin
-pplJar in ThisBuild := optionalPPLPathName
+// unfortunately, it is not possible to choose the compiler version with the eclipse plugin.
-// for removing warnings when Breeze does not find native libraries
-//
-// javaOptions in ThisBuild ++= Seq("-Dcom.github.fommil.netlib.BLAS=com.github.fommil.netlib.F2jBLAS",
-// "-Dcom.github.fommil.netlib.LAPACK=com.github.fommil.netlib.F2jLAPACK",
-// "-Dcom.github.fommil.netlib.ARPACK=com.github.fommil.netlib.F2jARPACK")
+EclipseKeys.eclipseOutput := Some("target.eclipse")
-// Metadata
+//*** Metadata for the build
name in ThisBuild := "Jandom"
@@ -64,20 +77,20 @@ homepage in ThisBuild := Some(url("https://github.com/jandom-devel/Jandom"))
startYear in ThisBuild := Some(2011)
-developers := List(
- new Developer(
+developers in ThisBuild := List(
+ Developer(
"amato",
"Gianluca Amato", "gianluca.amato@unich.it",
url("http://www.sci.unich.it/~amato/")
),
- new Developer(
+ Developer(
"scozzari",
"Francesca Scozzari", "francesca.scozzari@unich.it",
url("http://www.sci.unich.it/~scozzari/")
)
)
-scmInfo := Some(new ScmInfo(
+scmInfo in ThisBuild := Some(ScmInfo(
url("https://github.com/jandom-devel/Jandom"),
"scm:git:https://github.com/jandom-devel/Jandom.git",
Some("scm:git:https://github.com/jandom-devel/Jandom.git")
diff --git a/core/.gitignore b/core/.gitignore
deleted file mode 100644
index 4c4e7f96..00000000
--- a/core/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/target.eclipse/
-/bin/
diff --git a/core/build.sbt b/core/build.sbt
index d82a1e06..d378606b 100644
--- a/core/build.sbt
+++ b/core/build.sbt
@@ -1,53 +1,39 @@
+import CustomKeys._
+
//*** Libraries
libraryDependencies ++= Seq(
- "org.apache.commons" % "commons-lang3" % "3.5",
- "org.scalatest" %% "scalatest" % "3.0.0" % "test",
- "org.scalacheck" %% "scalacheck" % "1.13.3" % "test",
- "org.mockito" % "mockito-core" % "2.2.9" % "test",
- "org.spire-math" %% "spire" % "0.12.0",
- "org.scalanlp" %% "breeze" % "0.12",
- "it.unich.scalafix" %% "scalafix" % "0.5.0",
- // for using native linear algebra libraries
- // "org.scalanlp" %% "breeze-natives" % "0.12",
- "org.rogach" %% "scallop" % "2.0.3",
- "org.scala-lang.modules" %% "scala-swing" % "1.0.2",
- "org.scala-lang.modules" %% "scala-parser-combinators" % "1.0.4",
+ "org.apache.commons" % "commons-lang3" % "3.6",
+ "org.scalatest" %% "scalatest" % "3.0.4" % Test,
+ "org.scalacheck" %% "scalacheck" % "1.13.5" % Test,
+ "org.mockito" % "mockito-core" % "2.10.0" % Test,
+ "org.typelevel" %% "spire" % "0.14.1",
+ "it.unich.scalafix" %% "scalafix" % "0.7.0-SNAPSHOT",
+ "org.rogach" %% "scallop" % "3.1.0",
+ "org.scala-lang.modules" %% "scala-swing" % "2.0.0",
+ "org.scala-lang.modules" %% "scala-parser-combinators" % "1.0.6",
"org.scala-lang" % "scala-reflect" % scalaVersion.value,
// ASM is included in the Soot Jar
- "soot" % "soot" % "2.5.0+git2" from "http://soot-build.cs.uni-paderborn.de/nightly/soot/soot-trunk.jar"
+ "ca.mcgill.sable" % "soot" %"3.0.0-SNAPSHOT"
)
//*** Additional source directories for PPL
-unmanagedJars in Compile ++= (pplJar.value map file).toSeq
-
unmanagedSourceDirectories in Compile ++= (pplJar.value map { _ => (sourceDirectory in Compile).value / "ppl" }).toSeq
unmanagedSourceDirectories in Test ++= (pplJar.value map { _ => (sourceDirectory in Test).value / "ppl" }).toSeq
-//*** Eclipse plugin
-
-EclipseKeys.createSrc := EclipseCreateSrc.Default + EclipseCreateSrc.Managed
-
-EclipseKeys.executionEnvironment := Some(EclipseExecutionEnvironment.JavaSE17)
-
-EclipseKeys.eclipseOutput := Some("target.eclipse")
-
-// It would be nice to be able to exclude resource directories from compilation.
-
-managedSourceDirectories in Test := Seq()
+unmanagedJars in Compile ++= (pplJar.value map file).toSeq
-managedResourceDirectories in Test := Seq()
+//*** BuildInfo plugin
-managedResourceDirectories in Compile := Seq()
+buildInfoKeys ++= Seq[BuildInfoKey](name, version, scalaVersion, sbtVersion, gitHeadCommitSHA)
-unmanagedResourceDirectories in Compile := Seq()
+buildInfoPackage := "it.unich.jandom"
-//*** BuildInfo plugin
+//*** IDEA plugin
-gitHeadCommitSHA := Process("git rev-parse HEAD").lines.head
+ideOutputDirectory in Compile := Some(file("core/target/idea/classes"))
-buildInfoKeys := Seq[BuildInfoKey](name, version, scalaVersion, sbtVersion, gitHeadCommitSHA)
+ideOutputDirectory in Test := Some(file("core/target/idea/test-classes"))
-buildInfoPackage := "it.unich.jandom"
diff --git a/core/examples/Java/Congruence.class b/core/examples/Java/Congruence.class
index ed6f022c..a6fdb69d 100644
Binary files a/core/examples/Java/Congruence.class and b/core/examples/Java/Congruence.class differ
diff --git a/core/examples/Java/Congruence.java b/core/examples/Java/Congruence.java
index f6622569..1c1c21a8 100644
--- a/core/examples/Java/Congruence.java
+++ b/core/examples/Java/Congruence.java
@@ -1,8 +1,23 @@
/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
*/
class Congruence {
- static void test() {
+ static void basic_congruence_add() {
int x = 3;
int y = 12;
if(x < 12)
@@ -11,7 +26,7 @@ static void test() {
x += 2;
}
- static void testCongruence() {
+ static void basic_congruence_mul() {
int x = 2;
int y = 3;
int z = x*y;
@@ -20,6 +35,12 @@ static void testCongruence() {
}
}
+ /**
+ * Example taken from
+ *
+ * this slides of Minè (91/103)
+ *
+ */
static void mineCongruence() {
int x = 0;
int y = 2;
@@ -32,6 +53,12 @@ static void mineCongruence() {
}
}
+ /**
+ * Example taken from
+ *
+ * this slides of Minè (96/103)
+ *
+ */
static void mineProductIntervalCongruence() {
int x = 1;
while(x-10 <= 0) {
diff --git a/core/examples/Java/NumericalTestExtra.class b/core/examples/Java/NumericalTestExtra.class
new file mode 100644
index 00000000..77f21c9b
Binary files /dev/null and b/core/examples/Java/NumericalTestExtra.class differ
diff --git a/core/examples/Java/NumericalTestExtra.java b/core/examples/Java/NumericalTestExtra.java
new file mode 100644
index 00000000..0294ffed
--- /dev/null
+++ b/core/examples/Java/NumericalTestExtra.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
+
+public class NumericalTestExtra {
+
+ static void simple_multiplication_test() {
+ int a = 10;
+ int b = -2;
+ int c = 10 + a*b;
+ }
+ static void simple_algebra_example() {
+ int a = 10;
+ a = -a;
+ int c = -100 * + a;
+ }
+
+ static void simple_loop_with_exit() {
+ int a = 0;
+ while(a <= 0)
+ a = 1;
+ }
+
+ static void remainder_of_one() {
+ int x = 1;
+ x = x % 2;
+ }
+
+ @SuppressWarnings("ALL")
+ static void filter() {
+ int a = 2;
+ a += -12;
+ if(a < 0)
+ a++;
+ else
+ a--;
+ }
+
+ static void divison_by_zero() {
+ int x = 0;
+ int y = 2;
+ int z = y / x;
+ }
+}
diff --git a/core/examples/Java/SvBenchmark.class b/core/examples/Java/SvBenchmark.class
new file mode 100644
index 00000000..bdf5a2c5
Binary files /dev/null and b/core/examples/Java/SvBenchmark.class differ
diff --git a/core/examples/Java/SvBenchmark.java b/core/examples/Java/SvBenchmark.java
new file mode 100644
index 00000000..6c885dfd
--- /dev/null
+++ b/core/examples/Java/SvBenchmark.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
+
+/**
+ * These examples are a Java-Translation of some C examples taken from the the
+ * sv-benchmark
+ */
+public class SvBenchmark {
+ // taken from sv-benchmarks repository
+ static void sum04_false_unreach_call_true_termination(){
+ int i = 1;
+ int sn = 0;
+ while(i <= 8) {
+ if (i < 4)
+ sn = sn + (2);
+ i = i + 1;
+ }
+ // POST CONDITION: sn == 6
+ }
+
+ static void for_infinite_loop_2_true_unreach_call_false_termination() {
+ int i_U = 0;
+ int x = 0;
+ int y = 0;
+ int n = x*y*i_U + 12*3*x*y;
+ if(!(n > 0)) {
+ return;
+ }
+ boolean z = true;
+ for(i_U = 0; z; i_U++) {
+ x++;
+ //verifierAssert(!x ? 1 : 0);
+ }
+ //UNREACHABLE CODE
+ x += 12;
+ }
+}
diff --git a/core/examples/Java/TestBox.class b/core/examples/Java/TestBox.class
new file mode 100644
index 00000000..a8778355
Binary files /dev/null and b/core/examples/Java/TestBox.class differ
diff --git a/core/examples/Java/TestBox.java b/core/examples/Java/TestBox.java
new file mode 100644
index 00000000..e1edc08d
--- /dev/null
+++ b/core/examples/Java/TestBox.java
@@ -0,0 +1,118 @@
+public class TestBox {
+ public static int BoxWhile() {
+ int x = 10;
+ int y = 5;
+ while (x > 0) {
+ y++;
+ x--;
+
+ }
+ return x;
+ }
+
+ public static void BoxIfWhile() {
+ int x = 0;
+ int y = 10;
+ while (x + y <= 15) {
+ x--;
+ y = y *2;
+ }
+ int w = 0;
+ if (x - y < 30)
+ w = x * y;
+ }
+
+ public static void BoxIf() {
+ int x = 0;
+ int y = 10;
+ int w = 0;
+ if (x - y < 30)
+ w = x * y;
+ }
+
+ public static void BoxNull() {
+ int x = 0;
+ }
+
+ public static void remainder() {
+ int x = 10;
+ int y = 0;
+ while (x < 15) {
+ x++;
+ y++;
+ }
+ int w = x % y;
+ }
+
+ public static void test1(){
+ int i = 0;
+ while(i < 10) {
+ i++;
+ }
+ }
+
+ public static void test2() {
+ int x = 7;
+ while (x >= -10) {
+ x = x - 2;
+ }
+ }
+
+ public static void test3(){
+ int i = 1;
+ while(i < 10) {
+ i = i * 11;
+ }
+ }
+
+ public static void test4() {
+ int x = 0;
+ int y = -20;
+ int w = x + y;
+ if (w - x != -5) {
+ y = y * w;
+ } else {
+ w = x % y;
+ }
+ }
+
+ public static void test6() {
+ int x = 0;
+ int y = 15;
+ while (x != 5) {
+ x = x * y;
+ }
+ }
+
+ public static void test7(){
+ int k = Integer.MAX_VALUE;
+ int i = 0;
+ while(i < k){
+ i++;
+ }
+ }
+
+ public static void test8() {
+ int x = -5;
+ int y = 15;
+ while (x <= 5) {
+ y = x * y;
+ x++;
+ }
+ if (x >= 7) {
+ x = x - 10;
+ } else {
+ x = x + 10;
+ }
+ }
+
+ public static void test9() {
+ int x = 0;
+ int y = 7;
+ while (x <= 5) {
+ x++;
+ }
+ int w = y % x;
+ int z = x % y;
+ }
+}
diff --git a/core/examples/Java/TestBug.class b/core/examples/Java/TestBug.class
new file mode 100644
index 00000000..b9ee88fa
Binary files /dev/null and b/core/examples/Java/TestBug.class differ
diff --git a/core/examples/Java/TestBug.java b/core/examples/Java/TestBug.java
new file mode 100644
index 00000000..7580faf1
--- /dev/null
+++ b/core/examples/Java/TestBug.java
@@ -0,0 +1,11 @@
+public class TestBug {
+ public static void BoxDoubleDisequality() {
+ int x = -5;
+ if (x != 5) x++;
+ }
+
+ public static void BoxDoubleDisequality1() {
+ int x = 5;
+ if (x != 5) x++;
+ }
+}
diff --git a/core/examples/Java/UniPDTests.class b/core/examples/Java/UniPDTests.class
deleted file mode 100644
index aea04110..00000000
Binary files a/core/examples/Java/UniPDTests.class and /dev/null differ
diff --git a/core/examples/Java/UniPDTests.java b/core/examples/Java/UniPDTests.java
deleted file mode 100644
index b2954a62..00000000
--- a/core/examples/Java/UniPDTests.java
+++ /dev/null
@@ -1,68 +0,0 @@
-public class UniPDTests {
-
- static void simple_multiplication_test() {
- int a = 10;
- int b = -2;
- int c = 10 + a*b;
- }
- static void a_little_bit_of_algebra() {
- int a = 10;
- a = -a;
- int c = -100 * + a;
- }
-
- static void simple_loop_with_exit() {
- int a = 0;
- while(a <= 0)
- a = 1;
- }
-
- static void reduceOddAndGeq() {
- int x = 1;
- x = x % 2;
- }
-
- @SuppressWarnings("ALL")
- static void filter() {
- int a = 2;
- a += -12;
- if(a < 0)
- a++;
- else
- a--;
- }
- static void divisonByZero() {
- int x = 0;
- int y = 2;
- int z = y / x;
- }
-
- // taken from sv-benchmarks repository
- static void sum04_false_unreach_call_true_termination(){
- int i = 1;
- int sn = 0;
- while(i <= 8) {
- if (i < 4)
- sn = sn + (2);
- i = i + 1;
- }
- // POST CONDITION: sn == 6
- }
-
- static void for_infinite_loop_2_true_unreach_call_false_termination() {
- int i_U = 0;
- int x = 0;
- int y = 0;
- int n = x*y*i_U + 12*3*x*y;
- if(!(n > 0)) {
- return;
- }
- boolean z = true;
- for(i_U = 0; z; i_U++) {
- x++;
- //verifierAssert(!x ? 1 : 0);
- }
- //UNREACHABLE CODE
- x += 12;
- }
-}
diff --git a/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLBoxDouble.scala b/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLBoxDouble.scala
index 6c4b0dd9..9066754c 100644
--- a/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLBoxDouble.scala
+++ b/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLBoxDouble.scala
@@ -1,5 +1,5 @@
/**
- * Copyright 2013, 2016 Gianluca Amato
+ * Copyright 2013, 2016 Gianluca Amato
*
* This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
* JANDOM is free software: you can redistribute it and/or modify
@@ -18,6 +18,8 @@
package it.unich.jandom.domains.numerical.ppl
+import scala.collection.JavaConverters._
+
import it.unich.jandom.domains.numerical.LinearForm
import it.unich.jandom.domains.numerical.NumericalProperty
import it.unich.jandom.utils.numberext.RationalExt
@@ -57,13 +59,13 @@ final class PPLBoxDouble(val pplbox: Double_Box) extends NumericalProperty[PPLBo
def narrowing(that: PPLBoxDouble): PPLBoxDouble = {
val newpplbox = new Double_Box(that.pplbox)
+ newpplbox.intersection_assign(this.pplbox)
newpplbox.CC76_narrowing_assign(pplbox)
new PPLBoxDouble(newpplbox)
}
def union(that: PPLBoxDouble): PPLBoxDouble = {
val newpplbox = new Double_Box(pplbox)
- val x = new Double_Box(pplbox.space_dimension(), Degenerate_Element.EMPTY)
newpplbox.upper_bound_assign(that.pplbox)
new PPLBoxDouble(newpplbox)
}
@@ -129,7 +131,7 @@ final class PPLBoxDouble(val pplbox: Double_Box) extends NumericalProperty[PPLBo
def maximize(lf: LinearForm) = {
if (isEmpty) {
- if (lf.homcoeffs.forall(_ == 0.0))
+ if (lf.homcoeffs.forall(_ == Rational.zero))
RationalExt(lf.known)
else
RationalExt.NegativeInfinity
@@ -148,7 +150,7 @@ final class PPLBoxDouble(val pplbox: Double_Box) extends NumericalProperty[PPLBo
def frequency(lf: LinearForm) = {
if (isEmpty) {
- if (lf.homcoeffs.forall(_ == 0.0))
+ if (lf.homcoeffs.forall(_ == Rational.zero))
Option(lf.known)
else
Option.empty
@@ -167,16 +169,13 @@ final class PPLBoxDouble(val pplbox: Double_Box) extends NumericalProperty[PPLBo
}
def constraints = {
- import scala.collection.JavaConversions._
-
val cs = pplbox.constraints()
- cs flatMap PPLUtils.fromPPLConstraint
+ cs.asScala flatMap PPLUtils.fromPPLConstraint
}
def isPolyhedral = {
- import scala.collection.JavaConversions._
val cs = pplbox.constraints()
- cs forall PPLUtils.isRepresentableAsLinearForms
+ cs.asScala forall PPLUtils.isRepresentableAsLinearForms
}
def addVariable: PPLBoxDouble = {
diff --git a/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLBoxDoubleDomain.scala b/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLBoxDoubleDomain.scala
index 251d75cd..fe8c5b5a 100644
--- a/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLBoxDoubleDomain.scala
+++ b/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLBoxDoubleDomain.scala
@@ -32,7 +32,6 @@ import parma_polyhedra_library.Double_Box
*
* This class could me removed in favor of `PPLDomain[C_Polyehdron]` and the analogous macro-based
* domain, but we keep it here since it the simplest PPL class in which to tinker around.
- * @param pplbox an object of class `Double_Box` which is the $PPL wrapped object.
* @author Gianluca Amato
*/
class PPLBoxDoubleDomain extends NumericalDomain {
diff --git a/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLDomain.scala b/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLDomain.scala
index 824c2969..bb541a62 100644
--- a/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLDomain.scala
+++ b/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLDomain.scala
@@ -1,5 +1,5 @@
/**
- * Copyright 2013, 2016 Gianluca Amato
+ * Copyright 2013, 2016, 2017 Gianluca Amato
*
* This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
* JANDOM is free software: you can redistribute it and/or modify
@@ -18,21 +18,10 @@
package it.unich.jandom.domains.numerical.ppl
-import it.unich.jandom.domains.DomainTransformation
-import it.unich.jandom.domains.WideningDescription
import it.unich.jandom.domains.numerical.NumericalDomain
-import parma_polyhedra_library.By_Reference
-import parma_polyhedra_library.Coefficient
-import parma_polyhedra_library.Complexity_Class
-import parma_polyhedra_library.Congruence_System
-import parma_polyhedra_library.Constraint
-import parma_polyhedra_library.Constraint_System
-import parma_polyhedra_library.Degenerate_Element
-import parma_polyhedra_library.Linear_Expression
-import parma_polyhedra_library.Partial_Function
-import parma_polyhedra_library.Polyhedron
-import parma_polyhedra_library.Variable
-import parma_polyhedra_library.Variables_Set
+import it.unich.jandom.domains.{DomainTransformation, WideningDescription}
+import it.unich.scalafix.Box
+import parma_polyhedra_library._
/**
* This is the domain of PPL properties. It is able to represent (almost) any property
@@ -50,8 +39,6 @@ class PPLDomain[PPLNativeProperty <: AnyRef: Manifest] extends NumericalDomain {
PPLInitializer
- val widenings = Seq(WideningDescription.default[Property])
-
/*
* The class object corresponding to PPLNativeProperty
*/
@@ -123,11 +110,28 @@ class PPLDomain[PPLNativeProperty <: AnyRef: Manifest] extends NumericalDomain {
private[domains] def frequency(me: PPLNativeProperty, le: Linear_Expression, freq_n: Coefficient, freq_d: Coefficient, val_n: Coefficient, val_d: Coefficient) =
frequencyHandle.invoke(me, le, freq_n, freq_d, val_n, val_d).asInstanceOf[java.lang.Boolean].booleanValue()
- /**
+ /**
* It is true if `PPLNativeProperty` has the `CC76_narrowing_assign` method.
*/
val supportsNarrowing = narrowingAssignHandle != null
+ private val wideningsList = for {
+ m <- myClass.getMethods()
+ name = m.getName
+ if name.toString.endsWith("_widening_assign")
+ wideningName = name.toString.stripSuffix("_widening_assign")
+ } yield
+ WideningDescription(wideningName, s"The PPL widening using the ${name.toString} method",
+ Box.apply[Property] { (a: Property, b: Property) => {
+ val newpplobject = copyConstructor(a.pplobject)
+ upper_bound_assign(newpplobject,b.pplobject)
+ m.invoke(newpplobject, a.pplobject, null)
+ new PPLProperty(this, newpplobject)
+ }
+ })
+
+ val widenings = WideningDescription.default[Property] +: wideningsList.toSeq
+
def top(n: Int): Property = {
val pplobject = constructor(n, Degenerate_Element.UNIVERSE)
new PPLProperty(this, pplobject)
@@ -141,7 +145,6 @@ class PPLDomain[PPLNativeProperty <: AnyRef: Manifest] extends NumericalDomain {
/**
* Build a PPL property from a PPL property of other type. Conversion is slow because the right constructor
* is looked up at runtime.
- * @tparam PPLSourceProperty the class of the native PPL property
* @param x the source `PPLProperty`
* @return x transformed into a `PPLPropert[PPLNativeProperty]`
*/
diff --git a/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLDomainMacro.scala b/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLDomainMacro.scala
index 438a2f4c..3d1a3d44 100644
--- a/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLDomainMacro.scala
+++ b/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLDomainMacro.scala
@@ -79,7 +79,6 @@ object PPLDomainMacro {
val outputTree = q"""
import it.unich.jandom.domains.DomainTransformation
- import parma_polyhedra_library._
object PPLtoPPL extends DomainTransformation[PPLDomainMacro[$PPLSourceTypeTag], PPLDomainMacro[$PPLDestTypeTag]] {
def apply(src: PPLDomainMacro[$PPLSourceTypeTag], dst: PPLDomainMacro[$PPLDestTypeTag]): src.Property => dst.Property = { (x) =>
@@ -121,7 +120,8 @@ object PPLDomainMacro {
val narrowing = if (supportsCC76Narrowing)
q"""
def narrowing(that: ThisProperty): ThisProperty = {
- val newpplobject = new $PPLTypeTag(pplobject)
+ val newpplobject = new $PPLTypeTag(that.pplobject)
+ newpplobject.intersection_assign(pplobject)
newpplobject.CC76_narrowing_assign(pplobject)
new ThisProperty(newpplobject)
}
@@ -134,6 +134,7 @@ object PPLDomainMacro {
"""
val outputTree = q"""
+ import collection.JavaConverters._
import it.unich.jandom.domains.WideningDescription
import it.unich.jandom.domains.numerical.LinearForm
import it.unich.jandom.domains.numerical.ppl._
@@ -159,7 +160,6 @@ object PPLDomainMacro {
def union(that: ThisProperty): ThisProperty = {
val newpplobject = new $PPLTypeTag(pplobject)
- val x = new $PPLTypeTag(pplobject.space_dimension(), Degenerate_Element.EMPTY)
newpplobject.upper_bound_assign(that.pplobject)
new ThisProperty(newpplobject)
}
@@ -184,14 +184,14 @@ object PPLDomainMacro {
}
def linearInequality(lf: LinearForm): ThisProperty = {
- val (le, den) = PPLUtils.toPPLLinearExpression(lf)
+ val (le, _) = PPLUtils.toPPLLinearExpression(lf)
val newpplobject = new $PPLTypeTag(pplobject)
newpplobject.refine_with_constraint(new Constraint(le, Relation_Symbol.LESS_OR_EQUAL, new Linear_Expression_Coefficient(new Coefficient(0))))
new ThisProperty(newpplobject)
}
def linearDisequality(lf: LinearForm): ThisProperty = {
- val (le, den) = PPLUtils.toPPLLinearExpression(lf)
+ val (le, _) = PPLUtils.toPPLLinearExpression(lf)
val newpplobject1 = new $PPLTypeTag(pplobject)
val newpplobject2 = new $PPLTypeTag(pplobject)
newpplobject1.refine_with_constraint(new Constraint(le, Relation_Symbol.LESS_THAN, new Linear_Expression_Coefficient(new Coefficient(0))))
@@ -201,27 +201,35 @@ object PPLDomainMacro {
}
def minimize(lf: LinearForm) = {
- val (le, den) = PPLUtils.toPPLLinearExpression(lf)
- val exact = new By_Reference[java.lang.Boolean](false)
- val val_n = new Coefficient(0)
- val val_d = new Coefficient(0)
- val result = pplobject.minimize(le, val_n, val_d, exact)
- if (!result)
- RationalExt.NegativeInfinity
- else
- RationalExt(val_n.getBigInteger(), val_d.getBigInteger().multiply(den.getBigInteger()))
+ if (pplobject.is_empty())
+ RationalExt.PositiveInfinity
+ else {
+ val (le, den) = PPLUtils.toPPLLinearExpression(lf)
+ val exact = new By_Reference[java.lang.Boolean](false)
+ val val_n = new Coefficient(0)
+ val val_d = new Coefficient(0)
+ val result = pplobject.minimize(le, val_n, val_d, exact)
+ if (!result)
+ RationalExt.NegativeInfinity
+ else
+ RationalExt(val_n.getBigInteger(), val_d.getBigInteger().multiply(den.getBigInteger()))
+ }
}
def maximize(lf: LinearForm) = {
- val (le, den) = PPLUtils.toPPLLinearExpression(lf)
- val exact = new By_Reference[java.lang.Boolean](false)
- val val_n = new Coefficient(0)
- val val_d = new Coefficient(0)
- val result = pplobject.maximize(le, val_n, val_d, exact)
- if (!result)
- RationalExt.PositiveInfinity
- else
- RationalExt(val_n.getBigInteger(), val_d.getBigInteger().multiply(den.getBigInteger()))
+ if (pplobject.is_empty())
+ RationalExt.NegativeInfinity
+ else {
+ val (le, den) = PPLUtils.toPPLLinearExpression(lf)
+ val exact = new By_Reference[java.lang.Boolean](false)
+ val val_n = new Coefficient(0)
+ val val_d = new Coefficient(0)
+ val result = pplobject.maximize(le, val_n, val_d, exact)
+ if (!result)
+ RationalExt.PositiveInfinity
+ else
+ RationalExt(val_n.getBigInteger(), val_d.getBigInteger().multiply(den.getBigInteger()))
+ }
}
def frequency(lf: LinearForm) = {
@@ -238,15 +246,12 @@ object PPLDomainMacro {
}
def constraints = {
- import collection.JavaConversions._
-
- val cs = pplobject.minimized_constraints()
+ val cs = pplobject.minimized_constraints().asScala
cs flatMap PPLUtils.fromPPLConstraint
}
def isPolyhedral = {
- import collection.JavaConversions._
- val cs = pplobject.minimized_constraints()
+ val cs = pplobject.minimized_constraints().asScala
(cs forall PPLUtils.isRepresentableAsLinearForms) && pplobject.minimized_congruences().isEmpty()
}
@@ -320,7 +325,7 @@ object PPLDomainMacro {
def apply(x: $PPLTypeTag): ThisProperty = new ThisProperty(x)
- val widenings = Seq(..$widenings)
+ val widenings = WideningDescription.default[Property] +: Seq(..$widenings)
}
ThisDomain
diff --git a/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLProperty.scala b/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLProperty.scala
index 67f92670..b5f9e6b8 100644
--- a/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLProperty.scala
+++ b/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLProperty.scala
@@ -18,6 +18,8 @@
package it.unich.jandom.domains.numerical.ppl
+import scala.collection.JavaConverters._
+
import it.unich.jandom.domains.numerical.LinearForm
import it.unich.jandom.domains.numerical.NumericalProperty
import it.unich.jandom.utils.numberext.RationalExt
@@ -57,6 +59,7 @@ class PPLProperty[PPLNativeProperty <: AnyRef](val domain: PPLDomain[PPLNativePr
def narrowing(that: PPLProperty[PPLNativeProperty]): PPLProperty[PPLNativeProperty] = {
if (domain.supportsNarrowing) {
val newpplobject = domain.copyConstructor(that.pplobject)
+ domain.intersection_assign(newpplobject, pplobject)
domain.narrowing_assign(newpplobject, pplobject)
new PPLProperty(domain, newpplobject)
} else
@@ -112,7 +115,7 @@ class PPLProperty[PPLNativeProperty <: AnyRef](val domain: PPLDomain[PPLNativePr
def minimize(lf: LinearForm) = {
if (isEmpty) {
- if (lf.homcoeffs.forall(_ == 0.0))
+ if (lf.homcoeffs.forall(_ == Rational.zero))
lf.known
else
RationalExt.PositiveInfinity
@@ -131,7 +134,7 @@ class PPLProperty[PPLNativeProperty <: AnyRef](val domain: PPLDomain[PPLNativePr
def maximize(lf: LinearForm) = {
if (isEmpty) {
- if (lf.homcoeffs.forall(_ == 0.0))
+ if (lf.homcoeffs.forall(_ == Rational.zero))
lf.known
else
RationalExt.NegativeInfinity
@@ -150,7 +153,7 @@ class PPLProperty[PPLNativeProperty <: AnyRef](val domain: PPLDomain[PPLNativePr
def frequency(lf: LinearForm) = {
if (isEmpty) {
- if (lf.homcoeffs.forall(_ == 0.0))
+ if (lf.homcoeffs.forall(_ == Rational.zero))
Option(lf.known)
else
Option.empty
@@ -169,18 +172,15 @@ class PPLProperty[PPLNativeProperty <: AnyRef](val domain: PPLDomain[PPLNativePr
}
def constraints = {
- import scala.collection.JavaConversions._
-
val cs = domain.minimized_constraints(pplobject)
- cs flatMap PPLUtils.fromPPLConstraint
+ cs.asScala flatMap PPLUtils.fromPPLConstraint
}
def isPolyhedral = {
- import scala.collection.JavaConversions._
val cs = domain.minimized_constraints(pplobject)
// we explicitly check if the object is empty since, in this case, it has a unsatisfiable
// congruence.
- isEmpty || ((cs forall PPLUtils.isRepresentableAsLinearForms) && domain.minimized_congruences(pplobject).isEmpty())
+ isEmpty || ((cs.asScala forall PPLUtils.isRepresentableAsLinearForms) && domain.minimized_congruences(pplobject).isEmpty())
}
def addVariable = {
diff --git a/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLUtils.scala b/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLUtils.scala
index b26fc0bb..9e7756a1 100644
--- a/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLUtils.scala
+++ b/core/src/main/ppl/it/unich/jandom/domains/numerical/ppl/PPLUtils.scala
@@ -18,6 +18,8 @@
package it.unich.jandom.domains.numerical.ppl
+import scala.collection.JavaConverters._
+
import it.unich.jandom.domains.numerical.LinearForm
import parma_polyhedra_library._
import spire.math.Rational
@@ -93,13 +95,11 @@ private[jandom] object PPLUtils {
* @param vars the variables to use for the string form
*/
def constraintsToString(cs: Constraint_System, vars: Seq[String]): String = {
- import scala.collection.JavaConversions._
-
val vs = new Variable_Stringifier {
def stringify(x: Long) = vars(x.toInt)
}
Variable.setStringifier(vs)
- val result = for (c <- cs) yield c.toString
+ val result = for (c <- cs.asScala) yield c.toString
Variable.setStringifier(null)
result.mkString("[ ", " , ", " ]")
}
diff --git a/core/src/main/scala/it/unich/jandom/benchmark/FASTLoader.scala b/core/src/main/scala/it/unich/jandom/benchmark/FASTLoader.scala
new file mode 100644
index 00000000..08f75694
--- /dev/null
+++ b/core/src/main/scala/it/unich/jandom/benchmark/FASTLoader.scala
@@ -0,0 +1,64 @@
+/**
+ * Copyright 2015, 2016, 2017 Gianluca Amato
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
+
+
+package it.unich.jandom.benchmark
+
+import scala.collection.JavaConverters._
+
+import java.io.File
+import java.util.jar.JarFile
+
+import it.unich.jandom.parsers.FastParser
+import it.unich.jandom.targets.lts.LTS
+
+/**
+ * This trait loads and parser all models in /fast/ resource directory.
+ *
+ * @author Gianluca Amato
+ */
+
+trait FASTLoader {
+ private val path = "fast/"
+ private val jarFile = new File(getClass.getProtectionDomain.getCodeSource.getLocation.getPath)
+
+ // determine resource names when the program is packaged as a jar and when not
+ private val uris = if (jarFile.isFile) { // Run with JAR file
+ val jar = new JarFile(jarFile)
+ val entries = jar.entries //gives ALL entries in jar
+ val result = (for (element <- entries.asScala; name = element.getName
+ if (name startsWith path) && (name.length > path.length)) yield "/"+name).toList
+ jar.close()
+ result
+ }
+ else { // Run with IDE
+ val resources = getClass.getResource(path).toURI
+ val dir = new File(resources)
+ dir.list().toList
+ }
+
+ /**
+ * A sequence of Alice models.
+ */
+ val ltss: Seq[LTS] = for (uri <- uris) yield {
+ val stream = getClass.getResourceAsStream(uri)
+ val content = scala.io.Source.fromInputStream(stream).getLines.mkString("\n")
+ val result = FastParser().parse(content).get
+ result.copy(name = s"${result.name} -- $uri")
+ }
+}
diff --git a/core/src/main/scala/it/unich/jandom/domains/AbstractDomain.scala b/core/src/main/scala/it/unich/jandom/domains/AbstractDomain.scala
index 83047678..45c40cc1 100644
--- a/core/src/main/scala/it/unich/jandom/domains/AbstractDomain.scala
+++ b/core/src/main/scala/it/unich/jandom/domains/AbstractDomain.scala
@@ -37,17 +37,34 @@ trait AbstractDomain {
*/
def defaultWidening = widenings.head.box
+ /**
+ * Returns the default narrowing of the domain. It should correspond to the narrowing method of
+ * the ``it.unich.jandom.domains.AbstractProperty`` class.
+ */
+ def defaultNarrowing = narrowings.head.box
+
/**
* Returns the widening with the given name.
*/
def widening(name: String) = widenings.find ( _.name == name ).get.box
+ /**
+ * Returns the narrowing with the given name.
+ */
+ def narrowing(name: String) = narrowings.find ( _.name == name ).get.box
+
/**
* A non-empty set of widenings supported by the abstract domain. The first element is supposed to be
* the default widening.
*/
def widenings: Seq[WideningDescription[Property]]
+ /**
+ * A non-empty set of narrowings supported by the abstract domain. The first element is supposed to be
+ * the default narrowing.
+ */
+ def narrowings: Seq[NarrowingDescription[Property]] = Seq(NarrowingDescription.default[Property])
+
/**
* ScalaFixDomain is an instance of the ScalaFix type-class Domain for this abstract domain.
*/
diff --git a/core/src/main/scala/it/unich/jandom/domains/AbstractProperty.scala b/core/src/main/scala/it/unich/jandom/domains/AbstractProperty.scala
index ac578420..abcfab92 100644
--- a/core/src/main/scala/it/unich/jandom/domains/AbstractProperty.scala
+++ b/core/src/main/scala/it/unich/jandom/domains/AbstractProperty.scala
@@ -1,5 +1,5 @@
/**
- * Copyright 2013 Gianluca Amato
+ * Copyright 2013, 2016 Gianluca Amato
*
* This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
* JANDOM is free software: you can redistribute it and/or modify
@@ -8,7 +8,7 @@
* (at your option) any later version.
*
* JANDOM is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty ofa
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
@@ -55,7 +55,7 @@ trait AbstractProperty[Property <: AbstractProperty[Property]] extends Partially
def domain: Domain
/**
- * Compute an upper bound of two abstract properties. If it is possible and convenient, this should compute
+ * Computes an upper bound of two abstract properties. If it is possible and convenient, this should compute
* the least upper bound, but it is not a requirement.
* @param that the abstract object to join with `this`.
* @note $NOTEFIBER
@@ -64,7 +64,7 @@ trait AbstractProperty[Property <: AbstractProperty[Property]] extends Partially
def union(that: Property): Property
/**
- * Compute an upper approximation of the greatest lower bound of two abstract properties.
+ * Computes an upper approximation of the greatest lower bound of two abstract properties.
* @param that the abstract object to meet with `this`.
* @note $NOTEFIBER
* @return a lower bound of the two abstract properties.
@@ -72,15 +72,29 @@ trait AbstractProperty[Property <: AbstractProperty[Property]] extends Partially
def intersection(that: Property): Property
/**
- * The standard widening for two abstract properties.
- * @param that the abstract object to be widened with `this`. `that` is NOT assumed to be bigger than `this`.
+ * The standard widening for two abstract properties. The object `this` should be widened with `that`. The
+ * result should be an upper bound of the two properties, and convergemce of the sequence s(i+1) = s(i) widening v(i)
+ * should be ensured for any sequence of v(i)'s.
+ *
+ * Important: `that` is not required to be bigger than `this`. This generality is needed in order to deal with
+ * non-monotonic domains or initial assignments which are not pre-fixpoints of the equation system. An alternative
+ * could be requiring `that` to be always bigger than `this` but unconditionally applying union before widening. However,
+ * this would preclude the possibily to apply heuristics for widening in non-monotonic domains.
+ * @param that the abstract object to be widened with `this`.
* @return the widening of the two abstract properties.
*/
def widening(that: Property): Property
/**
- * The standard narrowing for two abstract properties.
- * @param that the abstract object to be narrowed with `this`. `that` IS assumed to be smaller than `this`.
+ * The standard narrowing for two abstract properties. The object `this` should be narrowed with `that`. The
+ * result should be smaller than `this` but bigger than `this intersection that` (or, more generally, a correct
+ * approximation of the concrete intersection). Moreover, convergence of the sequence s(i+1) = s(i) narrowing v(i)
+ * should be ensured for any sequence of v(i)'s.
+ *
+ * Important: `that` is not required to be bigger than `this`. This generality is needed in order to deal with
+ * non-monotonic domains. When the domain is monotonic, `that` is smaller than `this`, we fall in the standard
+ * notion of narrowing we found in the literature.
+ * @param that the abstract object to be narrowed with `this`.
* @return the narrowing of the two abstract properties.
*/
def narrowing(that: Property): Property
diff --git a/core/src/main/scala/it/unich/jandom/domains/DomainTransformation.scala b/core/src/main/scala/it/unich/jandom/domains/DomainTransformation.scala
index 48ca9415..985ca294 100644
--- a/core/src/main/scala/it/unich/jandom/domains/DomainTransformation.scala
+++ b/core/src/main/scala/it/unich/jandom/domains/DomainTransformation.scala
@@ -19,17 +19,14 @@
package it.unich.jandom.domains
import it.unich.jandom.domains.numerical._
-import it.unich.jandom.utils.breeze.RationalForBreeze._
-import it.unich.jandom.utils.numberext.RationalExt
-import it.unipd.jandom.domains.numerical.mod._
-import it.unipd.jandom.domains.numerical.sign.Sign.Zero
-import it.unipd.jandom.domains.numerical.sign.SignDomain
-import it.unipd.jandom.domains.numerical.sign.Sign._
-import it.unipd.jandom.domains.numerical.sign._
-import it.unipd.jandom.domains.numerical.parity._
import it.unipd.jandom.domains.numerical.congruence._
import it.unipd.jandom.domains.numerical.congruence.Congruence._
-import it.unipd.jandom.domains.numerical.congruence.CongruenceDomainCore._
+import it.unipd.jandom.domains.numerical.sign._
+import it.unipd.jandom.domains.numerical.sign.Sign.Zero
+import it.unipd.jandom.domains.numerical.mod._
+
+import it.unipd.jandom.domains.numerical.parity._
+import it.unich.jandom.utils.numberext.{DenseMatrix, Bounds, RationalExt}
/**
@@ -58,64 +55,38 @@ trait DomainTransformation[-DomA <: AbstractDomain, -DomB <: AbstractDomain] ext
* @author Francesca Scozzari
*/
object DomainTransformation {
- implicit object ParallelotopeToBoxDouble extends DomainTransformation[ParallelotopeDomain, BoxDoubleDomain] {
- import breeze.linalg.DenseMatrix
- def apply(src: ParallelotopeDomain, dst: BoxDoubleDomain): src.Property => dst.Property = { (x) =>
- val newPar = x.rotate(DenseMatrix.eye(x.dimension))
- if (newPar.isEmpty)
- dst.bottom(newPar.dimension)
- else
- dst(newPar.low.toArray, newPar.high.toArray)
- }
- }
-
implicit object ParallelotopeRationalToBoxDouble extends DomainTransformation[ParallelotopeRationalDomain, BoxDoubleDomain] {
- import breeze.linalg.DenseMatrix
def apply(src: ParallelotopeRationalDomain, dst: BoxDoubleDomain): src.Property => dst.Property = { (x) =>
val newPar = x.rotate(DenseMatrix.eye(x.dimension))
if (newPar.isEmpty)
dst.bottom(newPar.dimension)
else
- dst(newPar.low.toArray map (_.toDouble), newPar.high.toArray map (_.toDouble))
+ dst(newPar.low.data map (_.toDouble), newPar.high.data map (_.toDouble))
}
}
implicit object ParallelotopeRationalToBoxRational extends DomainTransformation[ParallelotopeRationalDomain, BoxRationalDomain] {
- import breeze.linalg.DenseMatrix
def apply(src: ParallelotopeRationalDomain, dst: BoxRationalDomain): src.Property => dst.Property = { (x) =>
val newPar = x.rotate(DenseMatrix.eye(x.dimension))
if (newPar.isEmpty)
dst.bottom(newPar.dimension)
else
- dst(newPar.low.toArray, newPar.high.toArray)
- }
- }
-
- implicit object BoxDoubleToParallelotope extends DomainTransformation[BoxDoubleDomain, ParallelotopeDomain] {
- import breeze.linalg.{ DenseMatrix, DenseVector }
- def apply(src: BoxDoubleDomain, dst: ParallelotopeDomain): src.Property => dst.Property = { (x) =>
- dst(DenseVector(x.low), DenseMatrix.eye(x.dimension), DenseVector(x.high))
+ dst(newPar.low.data, newPar.high.data)
}
}
implicit object BoxDoubleToParallelotopeRational extends DomainTransformation[BoxDoubleDomain, ParallelotopeRationalDomain] {
- import breeze.linalg.{ DenseMatrix, DenseVector }
def apply(src: BoxDoubleDomain, dst: ParallelotopeRationalDomain): src.Property => dst.Property = { (x) =>
- dst(DenseVector(x.low map { RationalExt(_) }), DenseMatrix.eye(x.dimension), DenseVector(x.high map { RationalExt(_) }))
+ dst(Bounds(x.low map { RationalExt(_) }), DenseMatrix.eye(x.dimension), Bounds(x.high map { RationalExt(_) }))
}
}
implicit object BoxRationalToParallelotopeRational extends DomainTransformation[BoxRationalDomain, ParallelotopeRationalDomain] {
- import breeze.linalg.{ DenseMatrix, DenseVector }
- def apply(src: BoxRationalDomain, dst: ParallelotopeRationalDomain): src.Property => dst.Property = { (x) =>
- dst(DenseVector(x.low), DenseMatrix.eye(x.dimension), DenseVector(x.high))
+ def apply(src: BoxRationalDomain, dst: ParallelotopeRationalDomain ): src.Property => dst.Property = { (x) =>
+ dst(Bounds(x.low), DenseMatrix.eye(x.dimension), Bounds(x.high))
}
}
- implicit object ParallelotopeToParallelotope extends DomainTransformation[ParallelotopeDomain, ParallelotopeDomain] {
- def apply(src: ParallelotopeDomain, dst: ParallelotopeDomain): src.Property => dst.Property = { (x) => new dst.Property(x.isEmpty, x.low, x.A, x.high) }
- }
-
implicit object ParallelotopeRationalParallelotopeRational extends DomainTransformation[ParallelotopeRationalDomain, ParallelotopeRationalDomain] {
def apply(src: ParallelotopeRationalDomain, dst: ParallelotopeRationalDomain): src.Property => dst.Property = { (x) => new dst.Property(x.isEmpty, x.low, x.A, x.high) }
}
@@ -166,16 +137,16 @@ object DomainTransformation {
p =>
if (p.isEmpty || p.elements.contains(CongruenceBottom)) //If the property is unreachable return bottom
dst.bottom(p.dimension)
- else
- dst(
- p.elements.map {
- case Mod(None, constant) => constant.toDouble
- case Mod(a, b) => Double.NegativeInfinity
- },
- p.elements.map {
- case Mod(None, constant) => constant.toDouble
- case Mod(a, b) => Double.PositiveInfinity
- })
+ else {
+ val (low, high) = (p.elements.map {
+ case Mod(None, constant) => (constant.toDouble, constant.toDouble)
+ case Mod(a, b) => (Double.NegativeInfinity, Double.PositiveInfinity)
+ case CongruenceBottom => (Double.PositiveInfinity, Double.NegativeInfinity)
+ //This case is already covered in the previous if, but otherwise sbt gave a warning
+ //due to non exhaustive pattern matching
+ }).unzip
+ dst(low, high)
+ }
}
implicit object BoxDoubleToCongruence extends DomainTransformation[BoxDoubleDomain, CongruenceDomain] {
diff --git a/core/src/main/scala/it/unich/jandom/domains/NarrowingDescription.scala b/core/src/main/scala/it/unich/jandom/domains/NarrowingDescription.scala
new file mode 100644
index 00000000..344c28ef
--- /dev/null
+++ b/core/src/main/scala/it/unich/jandom/domains/NarrowingDescription.scala
@@ -0,0 +1,55 @@
+/**
+ * Copyright 2017 Gianluca Amato
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
+package it.unich.jandom.domains
+
+import it.unich.scalafix.Box
+
+/**
+ * The description of a narrowing.
+ * @tparam Property type of objects on which the narrowing operates.
+ * @param name short name of the narrowing.
+ * @param description long description of the narrowing.
+ * @param box the box which implements the narrowing.
+ */
+class NarrowingDescription[Property](val name: String, val description: String, val box: Box[Property]) {
+ /**
+ * Application of narrowing description is equivalent to the application of the underlying box.
+ */
+ def apply(a: Property, b: Property) = box(a, b)
+}
+
+/**
+ * Companion object for narrowing description. It contains factory methods.
+ */
+object NarrowingDescription {
+ /**
+ * Builds a narrowing description.
+ * @tparam Property type of objects on which the narrowing operates.
+ * @param name short name of the narrowing.
+ * @param description long description of the narrowing.
+ * @param box the box which implements the narrowing.
+ */
+ def apply[Property](name: String, description: String, box: Box[Property]) =
+ new NarrowingDescription(name, description, box)
+
+ /**
+ * Returns the description of the standard narrowing for abstract property `Property`.
+ */
+ def default[Property <: AbstractProperty[Property]] =
+ NarrowingDescription("default", "The default narrowing.", Box { (a: Property, b: Property) => a narrowing b })
+}
diff --git a/core/src/main/scala/it/unich/jandom/domains/WideningDescription.scala b/core/src/main/scala/it/unich/jandom/domains/WideningDescription.scala
index 8fe14701..8afe71e4 100644
--- a/core/src/main/scala/it/unich/jandom/domains/WideningDescription.scala
+++ b/core/src/main/scala/it/unich/jandom/domains/WideningDescription.scala
@@ -21,14 +21,14 @@ import it.unich.scalafix.Box
/**
* The description of a widening.
- * @tparam the type of objects on which the widening operates.
- * @param box the box which implements the widening.
+ * @tparam Property type of objects on which the widening operates.
* @param name short name of the widening.
- * @param description long description of the widening.
+ * @param description long description of the widening
+ * @param box the box which implements the widening.
*/
class WideningDescription[Property](val name: String, val description: String, val box: Box[Property]) {
/**
- * Application of widening is equivalent to the application of the underlying box.
+ * Application of widening description is equivalent to the application of the underlying box.
*/
def apply(a: Property, b: Property) = box(a, b)
}
@@ -39,10 +39,10 @@ class WideningDescription[Property](val name: String, val description: String, v
object WideningDescription {
/**
* Builds a widening description.
- * @tparam the type of objects on which the widening operates.
- * @param box the box which implements the widening.
+ * @tparam Property type of objects on which the widening operates.
* @param name short name of the widening.
* @param description long description of the widening.
+ * @param box the box which implements the widening.
*/
def apply[Property](name: String, description: String, box: Box[Property]) =
new WideningDescription(name, description, box)
diff --git a/core/src/main/scala/it/unich/jandom/domains/numerical/BoxDoubleDomain.scala b/core/src/main/scala/it/unich/jandom/domains/numerical/BoxDoubleDomain.scala
index 1c5f0853..2df54b16 100644
--- a/core/src/main/scala/it/unich/jandom/domains/numerical/BoxDoubleDomain.scala
+++ b/core/src/main/scala/it/unich/jandom/domains/numerical/BoxDoubleDomain.scala
@@ -52,6 +52,7 @@ class BoxDoubleDomain(val overReals: Boolean) extends NumericalDomain {
final class Property(val low: Array[Double], val high: Array[Double], val isEmpty: Boolean) extends NumericalProperty[Property] {
require(normalized, s"The parameters low: ${low.mkString(",")}, high: ${high.mkString(",")} and isEmpty: ${isEmpty} are not normalized")
+
type Domain = BoxDoubleDomain
def domain = BoxDoubleDomain.this
@@ -132,7 +133,7 @@ class BoxDoubleDomain(val overReals: Boolean) extends NumericalDomain {
* If `remove` is a valid index in `x` and `y`, the factor `x(remove) * y(remove)` is
* removed from the dot product.
*/
- private def dotprod_lo(x: Seq[Double], y: Seq[Double], remove: Int = -1): Double = {
+ private def dotprod_lo(x: Seq[Double], y: Seq[Double], remove: Int): Double = {
var sum: Double = 0
for (i <- x.indices; if i != remove && x(i) != 0) sum = add_lo(sum, mul_lo(x(i), y(i)))
sum
@@ -144,7 +145,7 @@ class BoxDoubleDomain(val overReals: Boolean) extends NumericalDomain {
* If `remove` is a valid index in `x` and `y`, the factor `x(remove) * y(remove)` is
* removed from the dot product.
*/
- private def dotprod_hi(x: Seq[Double], y: Seq[Double], remove: Int = -1): Double = {
+ private def dotprod_hi(x: Seq[Double], y: Seq[Double], remove: Int): Double = {
var sum: Double = 0
for (i <- x.indices; if i != remove && x(i) != 0) sum = add_hi(sum, mul_hi(x(i), y(i)))
sum
@@ -196,8 +197,8 @@ class BoxDoubleDomain(val overReals: Boolean) extends NumericalDomain {
if (that.isEmpty) {
that
} else {
- val newlow = (low, that.low).zipped.map((l1, l2) => if (l1 == Double.NegativeInfinity) l2 else l1 min l2)
- val newhigh = (high, that.high).zipped.map((l1, l2) => if (l1 == Double.PositiveInfinity) l2 else l1 max l2)
+ val newlow = (low, that.low).zipped.map((l1, l2) => if (l1 == Double.NegativeInfinity) l2 else l1)
+ val newhigh = (high, that.high).zipped.map((l1, l2) => if (l1 == Double.PositiveInfinity) l2 else l1)
BoxDoubleDomain.this(newlow, newhigh)
}
}
@@ -261,17 +262,6 @@ class BoxDoubleDomain(val overReals: Boolean) extends NumericalDomain {
(lf.homcoeffs.zipWithIndex) map { case (c, i) => if (c > Rational.zero) low(i) else high(i) }
}
- /**
- * Compute the corner of the box which maximizes a linear form.
- * @todo should be generalized to linear forms over arbitrary types.
- * @param coeff the homogeneous coefficients
- * @return the coordinates of the point which maximizes the linear form
- */
- private def linearArgmax(lf: LinearForm): Seq[Double] = {
- require(lf.dimension <= dimension)
- (lf.homcoeffs.zipWithIndex) map { case (c, i) => if (c < Rational.zero) low(i) else high(i) }
- }
-
/**
* @inheritdoc
* @note @inheritdoc
@@ -333,9 +323,9 @@ class BoxDoubleDomain(val overReals: Boolean) extends NumericalDomain {
}
case 1 => {
val posinf = infinities.head
- if (homcoeffs(posinf) < 0)
+ if (homcoeffs(posinf) < 0) {
newlow(posinf) = low(posinf) max ((-dotprod_lo(homcoeffs, lfArgmin, posinf) - known) / homcoeffs(posinf))
- else
+ } else
newhigh(posinf) = high(posinf) min ((-dotprod_hi(homcoeffs, lfArgmin, posinf) - known) / homcoeffs(posinf))
}
case _ =>
@@ -456,7 +446,8 @@ class BoxDoubleDomain(val overReals: Boolean) extends NumericalDomain {
def top = BoxDoubleDomain.this.top(low.length)
def tryCompareTo[B >: Property](other: B)(implicit arg0: (B) => PartiallyOrdered[B]): Option[Int] = other match {
- case other: Property =>
+ // we use BoxDoubleDomain#Property instead of just Property to avoid a warning
+ case other: BoxDoubleDomain#Property =>
require(dimension == other.dimension)
(isEmpty, other.isEmpty) match {
case (true, true) => Option(0)
diff --git a/core/src/main/scala/it/unich/jandom/domains/numerical/BoxRationalDomain.scala b/core/src/main/scala/it/unich/jandom/domains/numerical/BoxRationalDomain.scala
index ca212db3..c97f94a0 100644
--- a/core/src/main/scala/it/unich/jandom/domains/numerical/BoxRationalDomain.scala
+++ b/core/src/main/scala/it/unich/jandom/domains/numerical/BoxRationalDomain.scala
@@ -79,7 +79,7 @@ class BoxRationalDomain private extends NumericalDomain {
* If `remove` is a valid index in `x` and `y`, the factor `x(remove) * y(remove)` is
* removed from the dot product.
*/
- private def dotprod(x: Seq[Rational], y: Seq[RationalExt], remove: Int = -1): RationalExt = {
+ private def dotprod(x: Seq[Rational], y: Seq[RationalExt], remove: Int): RationalExt = {
var sum = RationalExt.zero
for (i <- x.indices; if i != remove && !x(i).isZero) sum += x(i) * y(i)
sum
@@ -131,8 +131,8 @@ class BoxRationalDomain private extends NumericalDomain {
if (that.isEmpty) {
that
} else {
- val newlow = (low, that.low).zipped.map((l1, l2) => if (l1 == RationalExt.NegativeInfinity) l2 else l1 min l2)
- val newhigh = (high, that.high).zipped.map((l1, l2) => if (l1 == RationalExt.PositiveInfinity) l2 else l1 max l2)
+ val newlow = (low, that.low).zipped.map((l1, l2) => if (l1 == RationalExt.NegativeInfinity) l2 else l1)
+ val newhigh = (high, that.high).zipped.map((l1, l2) => if (l1 == RationalExt.PositiveInfinity) l2 else l1)
BoxRationalDomain.this(newlow, newhigh)
}
}
@@ -185,17 +185,6 @@ class BoxRationalDomain private extends NumericalDomain {
(lf.homcoeffs,low,high).zipped.map{(c, l, h) => if (c > Rational.zero) l else h }
}
- /**
- * Compute the corner of the box which maximizes a linear form.
- * @todo should be generalized to linear forms over arbitrary types.
- * @param coeff the homogeneous coefficients
- * @return the coordinates of the point which maximizes the linear form
- */
- private def linearArgmax(lf: LinearForm): Seq[RationalExt] = {
- require(lf.dimension <= dimension)
- (lf.homcoeffs,low,high).zipped.map{(c, l, h) => if (c < Rational.zero) l else h }
- }
-
/**
* @inheritdoc
* @note @inheritdoc
@@ -375,7 +364,8 @@ class BoxRationalDomain private extends NumericalDomain {
def top = BoxRationalDomain.this.top(low.length)
def tryCompareTo[B >: Property](other: B)(implicit arg0: (B) => PartiallyOrdered[B]): Option[Int] = other match {
- case other: Property =>
+ // we use BoxRationalDomain#Property instead of just Property to avoid a warning
+ case other: BoxRationalDomain#Property =>
require(dimension == other.dimension)
(isEmpty, other.isEmpty) match {
case (true, true) => Option(0)
@@ -414,7 +404,7 @@ class BoxRationalDomain private extends NumericalDomain {
else
new Property(low, high, false)
}
-
+
val widenings = Seq(WideningDescription.default[Property])
/**
diff --git a/core/src/main/scala/it/unich/jandom/domains/numerical/NumericalDomain.scala b/core/src/main/scala/it/unich/jandom/domains/numerical/NumericalDomain.scala
index 94e5024e..e0cac367 100644
--- a/core/src/main/scala/it/unich/jandom/domains/numerical/NumericalDomain.scala
+++ b/core/src/main/scala/it/unich/jandom/domains/numerical/NumericalDomain.scala
@@ -31,5 +31,7 @@ abstract class NumericalDomain extends DimensionFiberedDomain {
* @inheritdoc
* For numerical domains, properties needs to be instances of [[it.unich.jandom.domains.NumericalProperty]].
*/
+ //type T <: Any // @TODO: Make this method more type-generic
+ def updateData(x: Double, y: Double): Unit = x * 1
type Property <: NumericalProperty[Property]
}
diff --git a/core/src/main/scala/it/unich/jandom/domains/numerical/ParallelotopeDomain.scala b/core/src/main/scala/it/unich/jandom/domains/numerical/ParallelotopeDomain.scala
deleted file mode 100644
index 424e03bd..00000000
--- a/core/src/main/scala/it/unich/jandom/domains/numerical/ParallelotopeDomain.scala
+++ /dev/null
@@ -1,822 +0,0 @@
-/**
- * Copyright 2013, 2016 Gianluca Amato
- *
- * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
- * JANDOM is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * JANDOM is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of a
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with JANDOM. If not, see .
- */
-
-package it.unich.jandom.domains.numerical
-
-import scala.collection.mutable.ListBuffer
-import scala.util.Try
-import breeze.linalg._
-import it.unich.jandom.domains.CachedTopBottom
-import it.unich.jandom.domains.WideningDescription
-import it.unich.jandom.utils.breeze.countNonZero
-import it.unich.jandom.utils.numberext.RationalExt
-
-/**
- * This is the abstract domain of parallelotopes as appears in the NSAD 2012 paper. It is written
- * using the Breeze Math library. It is not safe, due to rounding problem of arithmetic.
- *
- * @author Gianluca Amato
- * @author Francesca Scozzari
- */
-class ParallelotopeDomain private (favorAxes: Boolean) extends NumericalDomain {
- val widenings = Seq(WideningDescription.default[Property])
-
- /**
- * Build a non-empty parallelotope. If the parallelotope is not empty, the result is undetermined.
- * @param A is the constraint matrix. It should be invertible.
- * @param low lower bounds.
- * @param high higher bounds.
- * @note `low` and `high` should have the same length. The matrix `A` should be invertible
- * of the same size of the two vectors.
- * @throws IllegalArgumentException if `low` and `high` are not of the same length, if `A` is not
- * square or if `A` has not the same size of `low`.
- */
- def apply(low: DenseVector[Double], A: DenseMatrix[Double], high: DenseVector[Double]): Property = {
- val isEmpty = (0 until low.size) exists { i => low(i) > high(i) }
- val isEmpty2 = (0 until low.size) exists { i => low(i).isInfinite() && low(i) == high(i) }
- new Property(isEmpty || isEmpty2, low, A, high)
- }
-
- /**
- * @inheritdoc
- * @note @inheritdoc
- * @throws $ILLEGAL
- */
- def top(n: Int): Property = {
- val low = DenseVector.fill(n)(Double.NegativeInfinity)
- val high = DenseVector.fill(n)(Double.PositiveInfinity)
- val A = DenseMatrix.eye[Double](n)
- // the full parallelotope of dimension 0 is not empty!
- new Property(false, low, A, high)
- }
-
- /**
- * @inheritdoc
- * @note @inheritdoc
- * @throws $ILLEGAL
- */
- def bottom(n: Int): Property = {
- val low = DenseVector.fill(n)(1.0)
- val high = DenseVector.fill(n)(0.0)
- val A = DenseMatrix.eye[Double](n)
- new Property(true, low, A, high)
- }
-
- /**
- * Given the box specified by `low` and `high` and the linear form `lf`, determines the pair
- * of the least and greatest value of the linear form in the box.
- * @param lf a linear form.
- * @param low lower bound of the box.
- * @param high higher bound of the box.
- * @note `low`, `high` and `lf` should be of the same length.
- * @return the least and greatest value of `lf` in the box determine by `low` and `high`.
- */
- private def extremalsInBox(lf: DenseVector[Double], low: DenseVector[Double], high: DenseVector[Double]): (Double, Double) = {
- var minc = 0.0
- var maxc = 0.0
- for (i <- 0 until lf.length)
- if (lf(i) > 0) {
- minc += lf(i) * low(i)
- maxc += lf(i) * high(i)
- } else if (lf(i) < 0) {
- minc += lf(i) * high(i)
- maxc += lf(i) * low(i)
- }
- (minc, maxc)
- }
-
- /**
- * Given a sequence of vectors of the same length `n`, returns a sequence of `n` indexes
- * of vectors which are linearly independent. It is based on Gaussian elimination.
- * @param m a sequence of vectors, all of the same length.
- * @return a sequence of positions in m.
- */
- private def pivoting(m: IndexedSeq[DenseVector[Double]]): Seq[Int] = {
- val dimension = m(0).length
- val indexes = ListBuffer[Int]()
- val pivots = ListBuffer[(DenseVector[Double], Int)]()
- var i = 0
- while (indexes.length < dimension) {
- val row = m(i).copy
- for (p <- pivots) row -= p._1 * row(p._2)
- val col = (0 until row.length) find (row(_) != 0)
- col match {
- case Some(col) =>
- row /= row(col)
- pivots.append(Tuple2(row, col))
- indexes.append(i)
- case None =>
- }
- i += 1
- }
- indexes.toList
- }
-
- /**
- * This is an element of the parallelotope domain.
- *
- * @constructor Builds a parallelotope
- * @param isEmpty is true if the parallelotope is empty. In this case, the other parameters are not relevant.
- * @param A is the constraint matrix. It should be invertible.
- * @param low lower bounds.
- * @param high higher bounds.
- * @note `low` and `high` should have the same length. The matrix `A` should be invertible
- * of the same size of the two vectors.
- * @throws IllegalArgumentException if `low` and `high` are not of the same length, if `A` is not
- * square or if `A` has not the same size of `low`.
- */
- final class Property(
- val isEmpty: Boolean,
- val low: DenseVector[Double],
- val A: DenseMatrix[Double],
- val high: DenseVector[Double])
- extends NumericalProperty[Property] {
-
- require(low.length == A.rows)
- require(low.length == A.cols)
- require(Try(A \ DenseMatrix.eye[Double](dimension)).isSuccess, s"The shape matrix ${A} is not invertible")
- require(normalized)
-
- type Domain = ParallelotopeDomain
-
- def domain = ParallelotopeDomain.this
-
- private def normalized: Boolean = {
- low.length == high.length && (
- (0 until low.length - 1) forall { i =>
- !low(i).isPosInfinity &&
- !high(i).isNegInfinity &&
- (low(i) <= high(i) || isEmpty)
- })
- }
-
- /**
- * @inheritdoc
- * @note @inheritdoc
- * @throws $ILLEGAL
- */
- def widening(that: Property): Property = {
- require(dimension == that.dimension)
- if (isEmpty)
- that
- else {
- val thatRotated = that.rotate(A)
- val newlow = low.copy
- val newhigh = high.copy
- for (i <- 0 until dimension) {
- if (thatRotated.low(i) < low(i)) newlow(i) = Double.NegativeInfinity
- if (thatRotated.high(i) > high(i)) newhigh(i) = Double.PositiveInfinity
- }
- new Property(false, newlow, A, newhigh)
- }
- }
-
- /**
- * @inheritdoc
- * @note @inheritdoc
- * @throws $ILLEGAL
- */
- def narrowing(that: Property): Property = {
- require(dimension == that.dimension)
- if (that.isEmpty) {
- that
- } else {
- val thatRotated = that.rotate(A)
- val newlow = low.copy
- val newhigh = high.copy
- for (i <- 0 until dimension) {
- if (low(i).isInfinity) newlow(i) = thatRotated.low(i) else newlow(i) = newlow(i) min thatRotated.low(i)
- if (high(i).isInfinity) newhigh(i) = thatRotated.high(i) else newhigh(i) = newhigh(i) max thatRotated.high(i)
- }
- new Property(false, newlow, A, newhigh)
- }
- }
-
- /**
- * @inheritdoc
- * It is equivalent to `intersectionWeak`.
- * @note @inheritdoc
- * @throws $ILLEGAL
- */
- def intersection(that: Property): Property = intersectionWeak(that)
-
- /**
- * @inheritdoc
- * The union of two parallelotopes is not a parallelotope. Moreover, there is no least
- * parallelotopes containing the union of two parallelotopes. Hence, this methods uses
- * heuristics to find a good result.
- * @note @inheritdoc
- * @throws $ILLEGAL
- */
- def union(that: Property): Property = {
-
- /*
- * A PrioritizedConstraint is a tuple `(a, m, M, p)` where `a` is a vector, `m` and `M` are
- * reals and `p` is an integer, whose intended meaning is the constraint `m <= ax <= M`
- * with a given priority `p`.
- */
- type PrioritizedConstraint = (DenseVector[Double], Double, Double, Int)
-
- /*
- * Given a linear form `v`, compute a prioritized constraint `(v,m,M,p)`. The parameter `ownedBy`
- * tells whether the line form under consideration is one of the "native" forms of this (1) or
- * that (2). This is used to refine priorities.
- */
- def priority(v: DenseVector[Double], ownedBy: Int = 0): PrioritizedConstraint = {
- val y1 = A.t \ v
- val (l1, u1) = domain.extremalsInBox(y1, low, high)
- val y2 = that.A.t \ v
- val (l2, u2) = domain.extremalsInBox(y2, that.low, that.high)
- val p =
- if (l1 == l2 && l2 == u1 && u1 == u2)
- 0
- else if (favorAxes && countNonZero(v) == 1)
- 25 // previous value for test: 10
- else if (!l1.isInfinity && !l2.isInfinity && !u1.isInfinity && !u2.isInfinity) {
- if (l1 == l2 && u1 == u2)
- 10
- else if (l1 >= l2 && u1 <= u2)
- if (ownedBy == 2) 20 else 30
- else if (l2 >= l1 && u2 <= u1)
- if (ownedBy == 1) 20 else 30
- else if (l2 <= u1 && l2 >= l1 && u2 >= u1)
- 30
- else if (l2 <= l1 && u2 >= l1 && u2 <= u1)
- 30
- else 40
- } else if (l1 == l2 && !l1.isInfinity && !l2.isInfinity)
- 50
- else if (u1 == u2 && !u1.isInfinity && !u2.isInfinity)
- 50
- else if (!l1.isInfinity && !l2.isInfinity)
- 60
- else if (!u1.isInfinity && !u2.isInfinity)
- 60
- else 100
- (v, l1 min l2, u1 max u2, p)
- }
-
- /*
- * Determines whether `v1` and `v2` are linearly dependent.
- * @return `None` if `v1` and `v2` are not linearly dependent, otherwise it is
- * `Some(k)` such that `v1 = k * v2`.
- */
- def linearDep(v1: DenseVector[Double], v2: DenseVector[Double]): Option[Double] = {
- var i: Int = 0
- while (i < dimension && (v1(i) == 0 || v2(i) == 0)) i += 1
- if (i == dimension)
- Option(1)
- else if (v1 / v1(i) == v2 / v2(i))
- Option(v1(i) / v2(i))
- else
- Option.empty
- }
-
- /*
- * The inversion join procedure.
- * @param vi first vector
- * @param vj second vector
- * @param min1i least value of v1 in this
- * @param min2i least value of v1 in that
- * @param min1j least value of v2 in that
- * @param min2j least value of v2 in that
- * @return None if `v1` and `v2` do not form an inversion, otherwise it is `Some(v)` where `v` is the
- * new linear form computed by the inversion procedure.
- */
- def newConstraint(vi: DenseVector[Double], vj: DenseVector[Double], min1i: Double, min2i: Double, min1j: Double, min2j: Double): Option[DenseVector[Double]] = {
- if (min1i.isInfinity || min2i.isInfinity || min1j.isInfinity || min2j.isInfinity)
- Option.empty
- else if (linearDep(vi, vj).isEmpty)
- Option.empty
- else {
- val (deltai, deltaj) = if (min2j - min1j >= 0) (min1i - min2i, min2j - min1j) else (min2i - min1i, min1j - min2j)
- if (deltai * deltaj > 0)
- Option(-vi * deltaj - vj * deltai)
- else
- Option.empty
- }
- }
-
- require(dimension == that.dimension)
-
- // special cases
- if (isEmpty)
- that
- else if (that.isEmpty)
- this
- else if (dimension == 0)
- this
- else {
- val thisRotated = this.rotate(that.A)
- val thatRotated = that.rotate(this.A)
- val Q = scala.collection.mutable.ArrayBuffer[PrioritizedConstraint]()
-
- val bulk = DenseMatrix.vertcat(this.A, that.A)
- val min1 = DenseVector.vertcat(this.low, thisRotated.low)
- val min2 = DenseVector.vertcat(thatRotated.low, that.low)
- val max1 = DenseVector.vertcat(this.high, thisRotated.high)
- val max2 = DenseVector.vertcat(thatRotated.high, that.high)
-
- for (i <- 0 until dimension) Q += priority(this.A.t(::, i), 1)
- for (i <- 0 until dimension) Q += priority(that.A.t(::, i), 2)
- for (i <- 0 until dimension; j <- i + 1 until dimension) {
- val v1 = bulk.t(::, i)
- val v2 = bulk.t(::, j)
- val nc1 = newConstraint(v1, v2, min1(i), min2(i), min1(j), min2(j))
- if (nc1.isDefined) Q += priority(nc1.get)
- val nc2 = newConstraint(v1, -v2, min1(i), min2(i), -max1(j), -max2(j))
- if (nc2.isDefined) Q += priority(nc2.get)
- val nc3 = newConstraint(-v1, -v2, -max1(i), -max2(i), -max1(j), -max2(j))
- if (nc3.isDefined) Q += priority(nc3.get)
- val nc4 = newConstraint(-v1, v2, -max1(i), -max2(i), min1(j), min2(j))
- if (nc4.isDefined) Q += priority(nc4.get)
- }
- val Qsorted = Q.sortBy(_._4)
- val pvt = domain.pivoting(Qsorted map (_._1))
-
- val newA = DenseMatrix(pvt map (Qsorted(_)._1): _*)
- val newlow = DenseVector(pvt map (Qsorted(_)._2): _*)
- val newhigh = DenseVector(pvt map (Qsorted(_)._3): _*)
-
- new Property(false, newlow, newA, newhigh)
- }
- }
-
- /**
- * This is a variant of `union` using weak join. The shape of the resulting
- * parallelotope is the same shap of `this`.
- * @param that the abstract object to be joined with `this`.
- * @note $NOTEDIMENSION
- * @return the weak union of the two abstract objects.
- */
- def unionWeak(that: Property): Property = {
- require(dimension == that.dimension)
- if (isEmpty)
- that
- else if (that.isEmpty)
- this
- else {
- val result = that.rotate(A)
- for (i <- 0 until dimension) {
- result.low(i) = result.low(i) min low(i)
- result.high(i) = result.high(i) max high(i)
- }
- new Property(false, result.low, result.A, result.high) //this is to normalize
- }
- }
-
- /**
- * This is the weak intersection of two abstract objects. The shape of the resulting
- * parallelotope is the same shap of `this`.
- * @param that the abstract object to be intersected with `this`.
- * @note $NOTEDIMENSION
- * @return the intersection of the two abstract objects.
- */
- def intersectionWeak(that: Property): Property = {
- require(dimension == that.dimension)
- if (isEmpty)
- this
- else if (that.isEmpty)
- that
- else {
- val result = that.rotate(A)
- for (i <- 0 until dimension) {
- result.low(i) = result.low(i) max low(i)
- result.high(i) = result.high(i) min high(i)
- }
- if ((0 until result.low.length) exists { i => (result.low(i) > result.high(i)) })
- bottom
- else
- new Property(false, result.low, result.A, result.high) //this is to normalize
- }
- }
-
- /**
- * @inheritdoc
- * @note @inheritdoc
- * @todo @inheritdoc
- * @throws $ILLEGAL
- */
- def linearAssignment(n: Int, lf: LinearForm): Property = {
- require(n <= dimension && lf.dimension <= dimension)
- val tcoeff = lf.homcoeffs map (_.toDouble)
- val known = lf.known.toDouble
- if (isEmpty)
- this
- else {
- val coeff = DenseVector(tcoeff.padTo(dimension, 0.0): _*)
- if (coeff(n) != 0) {
- // invertible assignment
- val increment = A(::, n) * known / coeff(n)
- val newlow = low + increment
- val newhigh = high + increment
- // in the past we could use SparseVector instead of DenseVector, but this does not work anymore
- val ei = DenseVector.zeros[Double](dimension)
- ei(n) = 1
- val newA = A - (A(::, n) * (coeff - ei).t) / coeff(n)
- new Property(false, newlow, newA, newhigh)
- } else {
- // non-invertible assignment
- val newP = nonDeterministicAssignment(n)
- val Aprime = newP.A.copy
- val j = ((0 until Aprime.rows) find { Aprime(_, n) != 0 }).get
- for (s <- 0 until dimension if Aprime(s, n) != 0 && s != j)
- Aprime(s, ::) :-= Aprime(j, ::) * Aprime(s, n) / Aprime(j, n)
- val ei = DenseVector.zeros[Double](dimension)
- ei(n) = 1
- Aprime(j, ::) := (ei - coeff).t
- val newlow = newP.low.copy
- val newhigh = newP.high.copy
- newlow(j) = known
- newhigh(j) = known
- new Property(false, newlow, Aprime, newhigh)
- }
- }
- }
-
- private def dotprod(x: DenseVector[Double], y: DenseVector[Double], remove: Int = -1): Double = {
- var sum: Double = 0
- for (i <- 0 until x.length if i != remove if x(i) != 0) sum = sum + x(i) * y(i)
- sum
- }
-
- /**
- * @inheritdoc
- * @note @inheritdoc
- * @todo @inheritdoc
- * @throws ILLEGAL
- */
- def linearInequality(lf: LinearForm): Property = {
- require(lf.dimension <= dimension)
- if (isEmpty)
- this
- else if (dimension == 0)
- if (lf.known > 0)
- bottom
- else
- this
- else {
- val known = lf.known.toDouble
- val coeffs = DenseVector(lf.homcoeffs map (_.toDouble) padTo (dimension, 0.0): _*)
- val coeffsTransformed = A.t \ coeffs
-
- val removeCandidates = (0 until dimension) find { i => coeffsTransformed(i) != 0 && low(i).isInfinity && high(i).isInfinity }
- removeCandidates match {
- case None => {
- val newlow = low.copy
- val newhigh = high.copy
- val (minc, maxc) = domain.extremalsInBox(coeffsTransformed, newlow, newhigh)
- if (minc > -known)
- bottom
- else {
- val lfArgmin = coeffsTransformed mapPairs { case (i, c) => if (c > 0) low(i) else high(i) }
- val infinities = (0 until dimension) filter { i => lfArgmin(i).isInfinity && coeffsTransformed(i) != 0 }
- infinities.size match {
- case 0 =>
- for (i <- 0 until dimension) {
- if (coeffsTransformed(i) > 0) newhigh(i) = high(i) min (lfArgmin(i) + (-known - minc) / coeffsTransformed(i))
- else if (coeffsTransformed(i) < 0) newlow(i) = low(i) max (lfArgmin(i) + (-known - minc) / coeffsTransformed(i))
- }
- case 1 => {
- val posinf = infinities.head
- if (coeffsTransformed(posinf) < 0)
- newlow(posinf) = low(posinf) max ((-dotprod(coeffsTransformed, lfArgmin, posinf) - known) / coeffsTransformed(posinf))
- else
- newhigh(posinf) = high(posinf) min ((-dotprod(coeffsTransformed, lfArgmin, posinf) - known) / coeffsTransformed(posinf))
- }
- case _ =>
- }
- new Property(false, newlow, A, newhigh)
- }
- }
- case Some(chosen) => {
- // TODO: check.. I think this may generate non-invertible matrices
- val newA = A.copy
- val newhigh = high.copy
- newA(chosen, ::) := coeffs.t
- newhigh(chosen) = -known
- new Property(false, low, newA, newhigh)
- }
- }
- }
- }
-
- /**
- * @inheritdoc
- * @note @inheritdoc
- * @throws $ILLEGAL
- */
- def linearDisequality(lf: LinearForm): Property = {
- val tcoeff = lf.homcoeffs
- val known = lf.known.toDouble
- if (tcoeff.forall(_.isZero))
- if (known == 0) bottom else this
- else {
- val row = (0 until dimension).find(A(_, ::).t == DenseVector(tcoeff map { _.toDouble }: _*))
- row match {
- case None => this
- case Some(row) =>
- if (low(row) == known && high(row) == known) bottom else this
- }
- }
- }
-
- /**
- * @inheritdoc
- * @note @inheritdoc
- * @throws $ILLEGAL
- */
- def nonDeterministicAssignment(n: Int): Property = {
- require(n <= dimension)
- if (isEmpty)
- this
- else {
- val unsortedCandidates = (0 until dimension) filter { i => A(i, n) != 0 && (!low(i).isNegInfinity || !high(i).isPosInfinity) }
- if (unsortedCandidates.isEmpty)
- this
- else {
- // We prever to use as a pivot a simple constraint. Therefore, we order constraints by the number of
- // non-zero coefficients.
- val countNonZeroInRows = countNonZero(A(*, ::))
- val removeCandidates = unsortedCandidates.sortBy({ i => countNonZeroInRows(i) })
- val removeCandidatesEq = removeCandidates filter { i => low(i) == high(i) }
- val removeCandidatesBounded = removeCandidates filter { i => !low(i).isInfinity && !high(i).isInfinity }
-
- val pivot =
- if (!removeCandidatesEq.isEmpty) removeCandidatesEq.head
- else if (!removeCandidatesBounded.isEmpty) removeCandidatesBounded.head
- else removeCandidates.head
- val rowPivot = A(pivot, ::)
-
- val newA = A.copy
- val newlow = low.copy
- val newhigh = high.copy
-
- for (i <- removeCandidates if i != pivot) {
- val value1 = rowPivot(n)
- val value2 = A(i, n)
- val rowi = A(i, ::)
- newA(i, ::) := rowPivot * value2 - rowi * value1
- val (minPivot, maxPivot) = if (A(i, n) < 0) (high(pivot), low(pivot)) else (low(pivot), high(pivot))
- val (mini, maxi) = if (-A(pivot, n) < 0) (high(i), low(i)) else (low(i), high(i))
- newlow(i) = minPivot * value2 - mini * value1
- newhigh(i) = maxPivot * value2 - maxi * value1
- }
- newlow(pivot) = Double.NegativeInfinity
- newhigh(pivot) = Double.PositiveInfinity
- new Property(false, newlow, newA, newhigh)
- }
- }
- }
-
- def addVariable(): Property = {
- if (isEmpty)
- ParallelotopeDomain.this.bottom(A.rows + 1)
- else {
- val e = DenseMatrix.zeros[Double](dimension + 1, 1)
- e(dimension, 0) = 1.0
- val newA = DenseMatrix.horzcat(DenseMatrix.vertcat(A, DenseMatrix.zeros[Double](1, dimension)), e)
- val newlow = DenseVector.vertcat(low, DenseVector(Double.NegativeInfinity))
- val newhigh = DenseVector.vertcat(high, DenseVector(Double.PositiveInfinity))
- new Property(false, newlow, newA, newhigh)
- }
- }
-
- def constraints = {
- if (isEmpty)
- Seq(LinearForm(1))
- else {
- val set1 = for {
- i <- 0 until dimension
- if !low(i).isInfinity
- } yield -LinearForm(-low(i) +: A(i, ::).t.toScalaVector: _*)
- val set2 = for {
- i <- 0 until dimension
- if !high(i).isInfinity
- } yield LinearForm(-high(i) +: A(i, ::).t.toScalaVector: _*)
- set1 ++ set2
- }
- }
-
- def isPolyhedral = true
-
- /**
- * @inheritdoc
- * @note @inheritdoc
- * @throws $ILLEGAL
- */
- def delVariable(n: Int): Property = {
- def rowToSeq(M: DenseMatrix[Double], i: Int, n: Int): Seq[Double] =
- for (j <- 0 until A.rows; if j != n) yield M(i, j)
-
- if (isEmpty)
- ParallelotopeDomain.this.bottom(A.rows - 1)
- else {
- val forgot = this.nonDeterministicAssignment(n)
- val set1 = for {
- i <- 0 until dimension
- if !forgot.low(i).isInfinity && forgot.A(i, n) == 0
- } yield -LinearForm(-forgot.low(i) +: rowToSeq(forgot.A, i, n): _*)
- val set2 = for {
- i <- 0 until dimension
- if !forgot.high(i).isInfinity && forgot.A(i, n) == 0
- } yield LinearForm(-forgot.high(i) +: rowToSeq(forgot.A, i, n): _*)
-
- (set1 ++ set2).foldLeft(ParallelotopeDomain.this.top(A.rows - 1)) { (p, lf) => p.linearInequality(lf) }
- }
- }
-
- /**
- * @inheritdoc
- */
- def mapVariables(rho: Seq[Int]): Property = {
- if (isEmpty)
- this
- else {
- val slice = for (i <- 0 until dimension; j = rho.indexOf(i); if j != -1) yield j
- val newA = A(slice, slice).toDenseMatrix
- val newlow = low(slice).toDenseVector
- val newhigh = high(slice).toDenseVector
- new Property(false, newlow, newA, newhigh)
- }
- }
-
- /**
- * Compute the minimum and maximum value of a linear form in a parallelotope.
- * @todo should be generalized to linear forms over arbitrary types.
- * @return a tuple with two components: the first component is the least value, the second component is the greatest value
- * of the linear form over the box.
- */
- def linearEvaluation(lf: LinearForm): (RationalExt, RationalExt) = {
- val tcoeff = lf.homcoeffs
- if (isEmpty && tcoeff.exists { !_.isZero })
- (RationalExt.PositiveInfinity, RationalExt.NegativeInfinity)
- else if (dimension == 0)
- (lf.known, lf.known)
- else {
- val vec = DenseVector(tcoeff map { _.toDouble } padTo (dimension, 0.0): _*)
- val newvec = A.t \ vec
- val (min, max) = domain.extremalsInBox(newvec, low, high)
- (RationalExt(min) + lf.known, RationalExt(max) + lf.known)
- }
- }
-
- def minimize(lf: LinearForm) = linearEvaluation(lf)._1
-
- def maximize(lf: LinearForm) = linearEvaluation(lf)._2
-
- def frequency(lf: LinearForm) = {
- val (min, max) = linearEvaluation(lf)
- if (min == max) Option(min.value) else Option.empty
- }
-
- def dimension = A.rows
-
- def isTop = low.forall(_.isNegInfinity) && high.forall(_.isPosInfinity)
-
- def isBottom = isEmpty
-
- def bottom = ParallelotopeDomain.this.bottom(dimension)
-
- def top = ParallelotopeDomain.this.top(dimension)
-
- def tryCompareTo[B >: Property](that: B)(implicit arg0: (B) => PartiallyOrdered[B]): Option[Int] = that match {
- case that: Property =>
- val lte = this <= that
- val gte = that <= this
- if (lte && gte)
- Option(0)
- else if (lte)
- Option(-1)
- else if (gte)
- Option(1)
- else
- Option.empty
- case _ => Option.empty
- }
-
- /**
- * It computes the smallest parallelotope which contains `this` and is definable
- * over a new shape matrix `Aprime`.
- * @param Aprime the new shape matrix.
- * @note `Aprime` should be an invertible matrix of the same dimension as `this`.
- * @throws IllegalArgumentException if `Aprime` is not square or has not the correct dimension.
- */
- def rotate(Aprime: DenseMatrix[Double]): Property = {
- require(dimension == Aprime.rows && dimension == Aprime.cols)
- if (isEmpty)
- this
- else {
- val B = Aprime * (A \ DenseMatrix.eye[Double](dimension))
- val newlow = DenseVector.zeros[Double](dimension)
- val newhigh = DenseVector.zeros[Double](dimension)
- B.foreachPair {
- case ((i, j), v) =>
- if (v > 0) {
- newlow(i) += v * low(j)
- newhigh(i) += v * high(j)
- } else if (v < 0) {
- newhigh(i) += v * low(j)
- newlow(i) += v * high(j)
- }
- }
- new Property(false, newlow, Aprime, newhigh)
- }
- }
-
- def <=[B >: Property](that: Property)(implicit arg0: (B) => PartiallyOrdered[B]): Boolean = {
- if (isEmpty)
- true
- else if (that.isEmpty)
- false
- else if (that.isTop)
- true
- else {
- val ptemp = this.rotate(that.A)
- (0 until ptemp.low.length) forall { i => ptemp.low(i) >= that.low(i) && ptemp.high(i) <= that.high(i) }
- }
- }
-
- def >=[B >: Property](that: Property)(implicit arg0: (B) => PartiallyOrdered[B]): Boolean =
- that <= this
-
- def <[B >: Property](that: Property)(implicit arg0: (B) => PartiallyOrdered[B]): Boolean =
- (this <= that) && !(this >= that)
-
- def >[B >: Property](that: Property)(implicit arg0: (B) => PartiallyOrdered[B]): Boolean =
- (this >= that) && !(this <= that)
-
- def mkString(vars: Seq[String]): String = {
-
- /*
- * Returns a string representation of the linear form `lf`.
- */
- def lfToString(lf: DenseVector[Double]): String = {
- var first = true
- val s = new StringBuilder
-
- for (index <- 0 until dimension) {
- val coeff = lf(index)
- val term = coeff match {
- case 0 => ""
- case 1 => vars(index)
- case -1 => "-" + vars(index)
- case c => c.toString + "*" + vars(index)
- }
- if (coeff != 0) {
- if (first || coeff < 0) {
- s ++= term
- first = false
- } else if (coeff != 0)
- s ++= "+" + term
- }
- }
- if (s.isEmpty) "0" else s.toString
- }
-
- if (isEmpty)
- "empty"
- else {
- val eqns = for (i <- 0 until dimension) yield {
- if (low(i) < high(i))
- s"${if (low(i).isNegInfinity) "-∞" else low(i)} ≤ ${lfToString(A.t(::, i))} ≤ ${if (high(i).isPosInfinity) "+∞" else high(i)}"
- else
- s"${lfToString(A.t(::, i))} = ${high(i)}"
- }
- eqns.mkString("[ ", " , ", " ]")
- }
- }
- }
-
-}
-
-/**
- * Companion class for the parallelotope domain
- */
-object ParallelotopeDomain {
- private lazy val standard = new ParallelotopeDomain(false) with CachedTopBottom
- private lazy val favoring = new ParallelotopeDomain(true) with CachedTopBottom
-
- /**
- * Returns an abstract domain for parallelotopes.
- * @param favorAxes determines whether the heuristics built into the domain should try to keep the variability
- * along axes at the minimum. This is generally useful when the domain is one of the component of the sum
- * combinator.
- */
- def apply(favorAxes: Boolean = false) = if (favorAxes) favoring else standard
-}
diff --git a/core/src/main/scala/it/unich/jandom/domains/numerical/ParallelotopeRationalDomain.scala b/core/src/main/scala/it/unich/jandom/domains/numerical/ParallelotopeRationalDomain.scala
index 67c10f4b..a39b5f78 100644
--- a/core/src/main/scala/it/unich/jandom/domains/numerical/ParallelotopeRationalDomain.scala
+++ b/core/src/main/scala/it/unich/jandom/domains/numerical/ParallelotopeRationalDomain.scala
@@ -1,122 +1,121 @@
/**
- * Copyright 2013, 2016 Jandom Team
- *
- * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
- * JANDOM is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * JANDOM is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of a
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with JANDOM. If not, see .
- */
+ * Copyright 2013, 2017 Jandom Team
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unich.jandom.domains.numerical
+import it.unich.jandom.domains.{CachedTopBottom, WideningDescription}
+import it.unich.jandom.utils.numberext.{Bounds, DenseMatrix, DenseVector, RationalExt}
+import spire.math.Rational
+
import scala.collection.mutable.ListBuffer
import scala.util.Try
-import breeze.linalg._
-import it.unich.jandom.domains.CachedTopBottom
-import it.unich.jandom.domains.WideningDescription
-import it.unich.jandom.utils.breeze.RationalForBreeze._
-import it.unich.jandom.utils.breeze.countNonZero
-import it.unich.jandom.utils.numberext.RationalExt
-import spire.math.Rational
/**
- * This is the abstract domain of parallelotopes as appears in the NSAD 2012 paper. It is written
- * using the Breeze Math library and uses rational numbers.
- *
- * @param favorAxis determines whether the heuristics built into the domain should try to keep constraints
- * corresponding to Cartesian axis. If `favorAxis` is `1`, axis are favorite. The opposite happens when favorAxis
- * is `-1`. If `favorAxis` is `0`, axis are considered like all the other constraints
- *
- * @author Gianluca Amato
- * @author Francesca Scozzari
- * @author Marco Rubino
- */
-class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDomain {
+ * This is the abstract domain of parallelotopes as appears in the NSAD 2012 paper. It is written
+ * using the Breeze Math library and uses rational numbers.
+ *
+ * @param favorAxis determines whether the heuristics built into the domain should try to keep constraints
+ * corresponding to Cartesian axis. If `favorAxis` is `1`, axis are favorite. The opposite happens when favorAxis
+ * is `-1`. If `favorAxis` is `0`, axis are considered like all the other constraints
+ * @author Gianluca Amato
+ * @author Francesca Scozzari
+ * @author Marco Rubino
+ */
+class ParallelotopeRationalDomain private(favorAxis: Int) extends NumericalDomain {
val widenings = Seq(WideningDescription.default[Property])
-
/**
- * Build a non-empty parallelotope. If the parallelotope is not empty, the result is undetermined.
- * @param A is the constraint matrix. It should be invertible.
- * @param low lower bounds.
- * @param high higher bounds.
- * @note `low` and `high` should have the same length. The matrix `A` should be invertiible
- * of the same size of the two vectors.
- * @throws IllegalArgumentException if `low` and `high` are not of the same length, if `A` is not
- * square or if `A` has not the same size of `low`.
- */
- def apply(low: DenseVector[RationalExt], A: DenseMatrix[Rational], high: DenseVector[RationalExt]): Property = {
- val isEmpty = (0 until low.size) exists { i => low(i) > high(i) }
- val isEmpty2 = (0 until low.size) exists { i => low(i).isInfinity && low(i) == high(i) }
+ * Build a non-empty parallelotope. If the parallelotope is not empty, the result is undetermined.
+ *
+ * @param A is the constraint matrix. It should be invertible.
+ * @param low lower bounds.
+ * @param high higher bounds.
+ * @note `low` and `high` should have the same length. The matrix `A` should be invertiible
+ * of the same size of the two vectors.
+ * @throws IllegalArgumentException if `low` and `high` are not of the same length, if `A` is not
+ * square or if `A` has not the same size of `low`.
+ */
+ def apply(low: Bounds, A: DenseMatrix, high: Bounds): Property = {
+ val isEmpty = (0 until low.length) exists { i => low(i) > high(i) }
+ val isEmpty2 = (0 until low.length) exists { i => low(i).isInfinity && low(i) == high(i) }
new Property(isEmpty || isEmpty2, low, A, high)
}
/**
- * @inheritdoc
- * @note @inheritdoc
- * @throws $ILLEGAL
- */
+ * @inheritdoc
+ * @note @inheritdoc
+ * @throws $ILLEGAL
+ */
def top(n: Int): Property = {
/* The full parallelotope of dimension 0 is not empty! */
- val low = DenseVector.fill(n)(RationalExt.NegativeInfinity)
- val high = DenseVector.fill(n)(RationalExt.PositiveInfinity)
- val A = DenseMatrix.eye[Rational](n)
+ val low = Bounds.fill(n)(RationalExt.NegativeInfinity)
+ val high = Bounds.fill(n)(RationalExt.PositiveInfinity)
+ val A = DenseMatrix.eye(n)
new Property(false, low, A, high)
}
/**
- * Returns an full parallelotope whose shape is given by the matrix A.
- * @param A the shape matrix
- */
- def top(A: DenseMatrix[Rational]): Property = {
+ * Returns an full parallelotope whose shape is given by the matrix A.
+ *
+ * @param A the shape matrix
+ */
+ def top(A: DenseMatrix): Property = {
val n = A.rows
- val low = DenseVector.fill(n)(RationalExt.NegativeInfinity)
- val high = DenseVector.fill(n)(RationalExt.PositiveInfinity)
+ val low = Bounds.fill(n)(RationalExt.NegativeInfinity)
+ val high = Bounds.fill(n)(RationalExt.PositiveInfinity)
new Property(false, low, A, high)
}
/**
- * @inheritdoc
- * @note @inheritdoc
- * @throws $ILLEGAL
- */
+ * @inheritdoc
+ * @note @inheritdoc
+ * @throws $ILLEGAL
+ */
def bottom(n: Int): Property = {
- val low = DenseVector.fill(n)(RationalExt.one)
- val high = DenseVector.fill(n)(RationalExt.zero)
- val A = DenseMatrix.eye[Rational](n)
+ val low = Bounds.fill(n)(RationalExt.one)
+ val high = Bounds.fill(n)(RationalExt.zero)
+ val A = DenseMatrix.eye(n)
new Property(true, low, A, high)
}
/**
- * Returns an empty parallelotope whose shape is given by the matrix A.
- * @param A the shape matrix
- */
- def bottom(A: DenseMatrix[Rational]): Property = {
+ * Returns an empty parallelotope whose shape is given by the matrix A.
+ *
+ * @param A the shape matrix
+ */
+ def bottom(A: DenseMatrix): Property = {
val n = A.rows
- val low = DenseVector.fill(n)(RationalExt.one)
- val high = DenseVector.fill(n)(RationalExt.zero)
+ val low = Bounds.fill(n)(RationalExt.one)
+ val high = Bounds.fill(n)(RationalExt.zero)
new Property(true, low, A, high)
}
/**
- * Given the box specified by `low` and `high` and the linear form `lf`, determines the pair
- * of the least and greatest value of the linear form in the box.
- * @param lf a linear form.
- * @param low lower bound of the box.
- * @param high higher bound of the box.
- * @note `low`, `high` and `lf` should be of the same length.
- * @return the least and greatest value of `lf` in the box determine by `low` and `high`.
- */
- private def extremalsInBox(lf: DenseVector[Rational], low: DenseVector[RationalExt], high: DenseVector[RationalExt]): (RationalExt, RationalExt) = {
+ * Given the box specified by `low` and `high` and the linear form `lf`, determines the pair
+ * of the least and greatest value of the linear form in the box.
+ *
+ * @param lf a linear form.
+ * @param low lower bound of the box.
+ * @param high higher bound of the box.
+ * @note `low`, `high` and `lf` should be of the same length.
+ * @return the least and greatest value of `lf` in the box determine by `low` and `high`.
+ */
+ private def extremalsInBox(lf: DenseVector, low: Bounds, high: Bounds): (RationalExt, RationalExt) = {
var minc = RationalExt.zero
var maxc = RationalExt.zero
for (i <- 0 until lf.length)
@@ -131,15 +130,16 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
}
/**
- * Given a sequence of vectors of the same length `n`, returns a sequence of `n` indexes
- * of vectors which are linearly independent. It is based on Gaussian elimination.
- * @param m a sequence of vectors, all of the same length.
- * @return a sequence of positions in m.
- */
- private def pivoting(m: IndexedSeq[DenseVector[Rational]]): List[Int] = {
+ * Given a sequence of vectors of the same length `n`, returns a sequence of `n` indexes
+ * of vectors which are linearly independent. It is based on Gaussian elimination.
+ *
+ * @param m a sequence of vectors, all of the same length.
+ * @return a sequence of positions in m.
+ */
+ private def pivoting(m: IndexedSeq[DenseVector]): List[Int] = {
val dimension = m(0).length
val indexes = ListBuffer[Int]()
- val pivots = ListBuffer[(DenseVector[Rational], Int)]()
+ val pivots = ListBuffer[(DenseVector, Int)]()
var i = 0
while (indexes.length < dimension) {
val row = m(i).copy
@@ -158,28 +158,28 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
}
/**
- * This is an element of the parallelotope domain.
- *
- * @constructor Builds a parallelotope
- * @param isEmpty is true if the parallelotope is empty. In this case, the other parameters are not relevant.
- * @param A is the constraint matrix. It should be invertible.
- * @param low lower bounds.
- * @param high higher bounds.
- * @note `low` and `high` should have the same length. The matrix `A` should be invertible
- * of the same size of the two vectors.
- * @throws IllegalArgumentException if `low` and `high` are not of the same length, if `A` is not
- * square or if `A` has not the same size of `low`.
- */
+ * This is an element of the parallelotope domain.
+ *
+ * @constructor Builds a parallelotope
+ * @param isEmpty is true if the parallelotope is empty. In this case, the other parameters are not relevant.
+ * @param A is the constraint matrix. It should be invertible.
+ * @param low lower bounds.
+ * @param high higher bounds.
+ * @note `low` and `high` should have the same length. The matrix `A` should be invertible
+ * of the same size of the two vectors.
+ * @throws IllegalArgumentException if `low` and `high` are not of the same length, if `A` is not
+ * square or if `A` has not the same size of `low`.
+ */
final class Property(
- val isEmpty: Boolean,
- val low: DenseVector[RationalExt],
- val A: DenseMatrix[Rational],
- val high: DenseVector[RationalExt])
- extends NumericalProperty[Property] {
+ val isEmpty: Boolean,
+ val low: Bounds,
+ val A: DenseMatrix,
+ val high: Bounds)
+ extends NumericalProperty[Property] {
require(low.length == A.rows)
require(low.length == A.cols)
- require(Try(A \ DenseMatrix.eye[Rational](dimension)).isSuccess, s"The shape matrix ${A} is not invertible")
+ require(Try(A \ DenseMatrix.eye(dimension)).isSuccess, s"The shape matrix ${A} is not invertible")
require(normalized)
type Domain = ParallelotopeRationalDomain
@@ -196,16 +196,15 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
}
/**
- * @inheritdoc
- * @note @inheritdoc
- * @throws $ILLEGAL
- */
+ * @inheritdoc
+ * @note @inheritdoc
+ * @throws $ILLEGAL
+ */
def widening(that: Property): Property = {
require(dimension == that.dimension)
if (isEmpty)
that
else {
- val thatRotated = that.rotate(A)
val thisRotated = this.rotate(that.A)
if (thisRotated < that) {
val newlow = thisRotated.low.copy
@@ -216,6 +215,7 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
}
new Property(false, newlow, that.A, newhigh)
} else {
+ val thatRotated = that.rotate(A)
val newlow = low.copy
val newhigh = high.copy
for (i <- 0 to dimension - 1) {
@@ -229,32 +229,34 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
}
/**
- * @inheritdoc
- * @note @inheritdoc
- * @throws $ILLEGAL
- */
+ * @inheritdoc
+ * @note @inheritdoc
+ * @throws $ILLEGAL
+ */
def narrowing(that: Property): Property = {
require(dimension == that.dimension)
if (that.isEmpty) {
that
+ } else if (this.isEmpty) {
+ this
} else {
val thatRotated = that.rotate(A)
val newlow = low.copy
val newhigh = high.copy
for (i <- 0 to dimension - 1) {
- if (low(i).isInfinity) newlow(i) = thatRotated.low(i) else newlow(i) = newlow(i) min thatRotated.low(i)
- if (high(i).isInfinity) newhigh(i) = thatRotated.high(i) else newhigh(i) = newhigh(i) max thatRotated.high(i)
+ if (low(i).isInfinity) newlow(i) = thatRotated.low(i)
+ if (high(i).isInfinity) newhigh(i) = thatRotated.high(i)
}
new Property(false, newlow, A, newhigh)
}
}
/**
- * @inheritdoc
- * It is equivalent to `intersectionWeak`.
- * @note @inheritdoc
- * @throws $ILLEGAL
- */
+ * @inheritdoc
+ * It is equivalent to `intersectionWeak`.
+ * @note @inheritdoc
+ * @throws $ILLEGAL
+ */
def intersection(that: Property): Property = {
if (that.isEmpty)
that
@@ -265,13 +267,13 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
}
/**
- * @inheritdoc
- * The union of two parallelotopes is not a parallelotope. Moreover, there is no least
- * parallelotopes containing the union of two parallelotopes. Hence, this methods uses
- * heuristics to find a good result.
- * @note @inheritdoc
- * @throws $ILLEGAL
- */
+ * @inheritdoc
+ * The union of two parallelotopes is not a parallelotope. Moreover, there is no least
+ * parallelotopes containing the union of two parallelotopes. Hence, this methods uses
+ * heuristics to find a good result.
+ * @note @inheritdoc
+ * @throws $ILLEGAL
+ */
def union(that: Property): Property = {
/*
@@ -279,23 +281,23 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
* rational and `p` is an integer, whose intended meaning is the constraint `m <= ax <= M`
* with a given priority `p`.
*/
- type PrioritizedConstraint = (DenseVector[Rational], RationalExt, RationalExt, Int)
+ type PrioritizedConstraint = (DenseVector, RationalExt, RationalExt, Int)
/*
* Given a linear form `v`, compute a prioritized constraint `(v,m,M,p)`. The parameter `ownedBy`
* tells whether the line form under consideration is one of the "native" forms of this (1) or
* that (2). This is used to refine priorities.
*/
- def priority(v: DenseVector[Rational], ownedBy: Int = 0): PrioritizedConstraint = {
+ def priority(v: DenseVector, ownedBy: Int = 0): PrioritizedConstraint = {
val y1 = A.t \ v
val (l1, u1) = domain.extremalsInBox(y1, low, high)
val y2 = that.A.t \ v
val (l2, u2) = domain.extremalsInBox(y2, that.low, that.high)
val p =
- if (favorAxis == 1 && countNonZero(v) == 1) // favorAxes
+ if (favorAxis == 1 && v.countNonZero == 1) // favorAxes
0
- else if (favorAxis == -1 && countNonZero(v) == 1) // not favorAxes
+ else if (favorAxis == -1 && v.countNonZero == 1) // not favorAxes
101
else if (l1 == l2 && l2 == u1 && u1 == u2) /// if nothing choose axes
1
@@ -330,7 +332,7 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
* @return `None` if `v1` and `v2` are not linearly dependent, otherwise it is
* `Some(k)` such that `v1 = k * v2`.
*/
- def linearDep(v1: DenseVector[Rational], v2: DenseVector[Rational]): Option[Rational] = {
+ def linearDep(v1: DenseVector, v2: DenseVector): Option[Rational] = {
var i: Int = 0
while (i < dimension && (v1(i).isZero || v2(i).isZero)) i += 1
if (i == dimension)
@@ -352,7 +354,7 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
* @return None if `v1` and `v2` do not form an inversion, otherwise it is `Some(v)` where `v` is the
* new linear form computed by the inversion procedure.
*/
- def newConstraint(vi: DenseVector[Rational], vj: DenseVector[Rational], min1i: RationalExt, min2i: RationalExt, min1j: RationalExt, min2j: RationalExt): Option[DenseVector[Rational]] = {
+ def newConstraint(vi: DenseVector, vj: DenseVector, min1i: RationalExt, min2i: RationalExt, min1j: RationalExt, min2j: RationalExt): Option[DenseVector] = {
if (min1i.isInfinity || min2i.isInfinity || min1j.isInfinity || min2j.isInfinity)
Option.empty
else if (linearDep(vi, vj).isEmpty)
@@ -383,16 +385,16 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
val thatRotated = that.rotate(this.A)
val Q = scala.collection.mutable.ArrayBuffer[PrioritizedConstraint]()
- val bulk = DenseMatrix.vertcat(this.A, that.A)
- val min1 = DenseVector.vertcat(this.low, thisRotated.low)
- val min2 = DenseVector.vertcat(thatRotated.low, that.low)
- val max1 = DenseVector.vertcat(this.high, thisRotated.high)
- val max2 = DenseVector.vertcat(thatRotated.high, that.high)
- for (i <- 0 until dimension) Q += priority(this.A.t(::, i), 1)
- for (i <- 0 until dimension) Q += priority(that.A.t(::, i), 2)
+ val bulk = this.A vertcat that.A
+ val min1 = this.low vertcat thisRotated.low
+ val min2 = thatRotated.low vertcat that.low
+ val max1 = this.high vertcat thisRotated.high
+ val max2 = thatRotated.high vertcat that.high
+ for (i <- 0 until dimension) Q += priority(this.A.row(i), 1)
+ for (i <- 0 until dimension) Q += priority(that.A.row(i), 2)
for (i <- 0 until dimension; j <- i + 1 until dimension) {
- val v1 = bulk.t(::, i)
- val v2 = bulk.t(::, j)
+ val v1 = bulk.row(i)
+ val v2 = bulk.row(j)
val nc1 = newConstraint(v1, v2, min1(i), min2(i), min1(j), min2(j))
if (nc1.isDefined) Q += priority(nc1.get)
@@ -402,26 +404,26 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
if (nc3.isDefined) Q += priority(nc3.get)
val nc4 = newConstraint(-v1, v2, -max1(i), -max2(i), min1(j), min2(j))
if (nc4.isDefined) Q += priority(nc4.get)
-
}
val Qsorted = Q.sortBy(_._4)
val pvt = domain.pivoting(Qsorted map (_._1))
val newA = DenseMatrix(pvt map (Qsorted(_)._1): _*)
- val newlow = DenseVector(pvt map (Qsorted(_)._2): _*)
- val newhigh = DenseVector(pvt map (Qsorted(_)._3): _*)
+ val newlow = Bounds(pvt map (Qsorted(_)._2): _*)
+ val newhigh = Bounds(pvt map (Qsorted(_)._3): _*)
new Property(false, newlow, newA, newhigh)
}
}
/**
- * This is a variant of `union` using weak join. The shape of the resulting
- * parallelotope is the same shap of `this`.
- * @param that the abstract object to be joined with `this`.
- * @note $NOTEDIMENSION
- * @return the weak union of the two abstract objects.
- */
+ * This is a variant of `union` using weak join. The shape of the resulting
+ * parallelotope is the same shap of `this`.
+ *
+ * @param that the abstract object to be joined with `this`.
+ * @note $NOTEDIMENSION
+ * @return the weak union of the two abstract objects.
+ */
def unionWeak(that: Property): Property = {
require(dimension == that.dimension)
if (isEmpty)
@@ -439,12 +441,13 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
}
/**
- * This is the weak intersection of two abstract objects. The shape of the resulting
- * parallelotope is the same shape of `this`.
- * @param that the abstract object to be intersected with `this`.
- * @note $NOTEDIMENSION
- * @return the intersection of the two abstract objects.
- */
+ * This is the weak intersection of two abstract objects. The shape of the resulting
+ * parallelotope is the same shape of `this`.
+ *
+ * @param that the abstract object to be intersected with `this`.
+ * @note $NOTEDIMENSION
+ * @return the intersection of the two abstract objects.
+ */
def intersectionWeak(that: Property): Property = {
require(dimension == that.dimension)
if (isEmpty)
@@ -465,11 +468,11 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
}
/**
- * @inheritdoc
- * @note @inheritdoc
- * @todo @inheritdoc
- * @throws $ILLEGAL
- */
+ * @inheritdoc
+ * @note @inheritdoc
+ * @todo @inheritdoc
+ * @throws $ILLEGAL
+ */
def linearAssignment(n: Int, lf: LinearForm): Property = {
require(n <= dimension && lf.dimension <= dimension)
val tcoeff = lf.homcoeffs
@@ -477,10 +480,10 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
if (isEmpty)
this
else {
- val coeff = DenseVector(tcoeff.padTo(dimension, Rational.zero) :_*)
- if (coeff(n) != Rational.zero) {
+ val coeff = DenseVector(tcoeff.padTo(dimension, Rational.zero): _*)
+ if (!coeff(n).isZero) {
// invertible assignment
- val increment = A(::, n) * known / coeff(n)
+ val increment = A.col(n) * known / coeff(n)
val newlow = low.copy
val newhigh = high.copy
// cannot use Breeze here since they are RationalExt
@@ -488,21 +491,23 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
newlow(i) += increment(i)
newhigh(i) += increment(i)
}
- val ei = DenseVector.zeros[Rational](dimension)
+ val ei = DenseVector.zeros(dimension)
ei(n) = Rational.one
- val newA = A - (A(::, n) * (coeff - ei).t) / coeff(n)
+ val newA = A - (A.col(n) * (coeff - ei).t) / coeff(n)
new Property(false, newlow, newA, newhigh)
} else {
// non-invertible assignment
val newP = nonDeterministicAssignment(n)
val Aprime = newP.A.copy
- val j = ((0 until Aprime.rows) find { !Aprime(_, n).isZero }).get
+ val j = ((0 until Aprime.rows) find {
+ !Aprime(_, n).isZero
+ }).get
for (s <- 0 until dimension if !Aprime(s, n).isZero && s != j)
- Aprime(s, ::) :-= Aprime(j, ::) * Aprime(s, n) / Aprime(j, n)
- val ei = DenseVector.zeros[Rational](dimension)
+ Aprime.rowUpdate(s, Aprime.row(s) - Aprime.row(j) * (Aprime(s, n) / Aprime(j, n)))
+ val ei = DenseVector.zeros(dimension)
ei(n) = Rational.one
- Aprime(j, ::) := (ei - coeff).t
+ Aprime.rowUpdate(j, ei - coeff)
val newlow = newP.low.copy
val newhigh = newP.high.copy
newlow(j) = known
@@ -514,21 +519,21 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
}
/**
- * Computes the dot product of `x` and `y` with the proviso that if `x` is zero, then `x*y`
- * is zero even when `y` is an infinite value (which is not the standard behaviour).
- */
- private def dotprod(x: DenseVector[Rational], y: DenseVector[RationalExt], remove: Int = -1): RationalExt = {
+ * Computes the dot product of `x` and `y` with the proviso that if `x` is zero, then `x*y`
+ * is zero even when `y` is an infinite value (which is not the standard behaviour).
+ */
+ private def dotprod(x: DenseVector, y: Bounds, remove: Int): RationalExt = {
var sum = RationalExt.zero
for (i <- 0 until x.length if i != remove if x(i) != Rational.zero) sum = sum + y(i) * x(i)
sum
}
/**
- * @inheritdoc
- * @note @inheritdoc
- * @todo @inheritdoc
- * @throws ILLEGAL
- */
+ * @inheritdoc
+ * @note @inheritdoc
+ * @todo @inheritdoc
+ * @throws ILLEGAL
+ */
def linearInequality(lf: LinearForm): Property = {
require(lf.dimension <= dimension)
if (isEmpty)
@@ -579,7 +584,7 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
// TODO: check.. I think this may generate non-invertible matrices
val newA = A.copy
val newhigh = high.copy
- newA(chosen, ::) := coeffs.t
+ newA.rowUpdate(chosen, coeffs)
newhigh(chosen) = -known
new Property(false, low, newA, newhigh)
}
@@ -588,20 +593,23 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
}
/**
- * @inheritdoc
- * @note @inheritdoc
- * @throws $ILLEGAL
- */
+ * @inheritdoc
+ * @note @inheritdoc
+ * @throws $ILLEGAL
+ */
def linearDisequality(lf: LinearForm): Property = {
val tcoeff = lf.homcoeffs
val known = lf.known
- if (tcoeff.forall(_ == Rational.zero))
- if (known == Rational.zero) bottom else this
- else {
+ if (tcoeff.forall(_.isZero)) {
+ if (known.isZero)
+ bottom
+ else
+ this
+ } else {
val row = (0 until dimension).find { (r) =>
- val v1 = A(r, ::).t
- val v2 = DenseVector[Rational](tcoeff: _*)
- v1 == v2
+ val v1 = A.row(r)
+ val v2 = DenseVector(tcoeff: _*)
+ v1.data sameElements v2.data
}
row match {
case None => this
@@ -612,10 +620,10 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
}
/**
- * @inheritdoc
- * @note @inheritdoc
- * @throws $ILLEGAL
- */
+ * @inheritdoc
+ * @note @inheritdoc
+ * @throws $ILLEGAL
+ */
def nonDeterministicAssignment(n: Int): Property = {
require(n <= dimension)
if (isEmpty)
@@ -627,7 +635,7 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
else {
// We prever to use as a pivot a simple constraint. Therefore, we order constraints by the number of
// non-zero coefficients.
- val countNonZeroInRows = countNonZero(A(*, ::))
+ val countNonZeroInRows = A.countNonZeroInRows
val removeCandidates = unsortedCandidates.sortBy({ i => countNonZeroInRows(i) })
val removeCandidatesEq = removeCandidates filter { i => low(i) == high(i) }
val removeCandidatesBounded = removeCandidates filter { i => !low(i).isInfinity && !high(i).isInfinity }
@@ -636,7 +644,7 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
if (!removeCandidatesEq.isEmpty) removeCandidatesEq.head
else if (!removeCandidatesBounded.isEmpty) removeCandidatesBounded.head
else removeCandidates.head
- val rowPivot = A(pivot, ::)
+ val rowPivot = A.row(pivot)
val newA = A.copy
val newlow = low.copy
@@ -645,8 +653,8 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
for (i <- removeCandidates if i != pivot) {
val value1 = rowPivot(n)
val value2 = A(i, n)
- val rowi = A(i, ::)
- newA(i, ::) := rowPivot * value2 - rowi * value1
+ val rowi = A.row(i)
+ newA.rowUpdate(i, rowPivot * value2 - rowi * value1)
val (minPivot, maxPivot) = if (A(i, n) < Rational.zero) (high(pivot), low(pivot)) else (low(pivot), high(pivot))
val (mini, maxi) = if (-A(pivot, n) < Rational.zero) (high(i), low(i)) else (low(i), high(i))
newlow(i) = minPivot * value2 - mini * value1
@@ -661,13 +669,13 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
def addVariable(): Property = {
if (isEmpty)
- ParallelotopeRationalDomain.this.bottom(A.rows + 1)
+ ParallelotopeRationalDomain.this.bottom(dimension + 1)
else {
- val e = DenseMatrix.zeros[Rational](dimension + 1, 1)
+ val e = DenseMatrix.zeros(dimension + 1, 1)
e(dimension, 0) = Rational.one
- val newA = DenseMatrix.horzcat(DenseMatrix.vertcat(A, DenseMatrix.zeros[Rational](1, dimension)), e)
- val newlow = DenseVector.vertcat(low, DenseVector(RationalExt.NegativeInfinity))
- val newhigh = DenseVector.vertcat(high, DenseVector(RationalExt.PositiveInfinity))
+ val newA = (A vertcat DenseMatrix.zeros(1, dimension)) horzcat e
+ val newlow = low vertcat Bounds(RationalExt.NegativeInfinity)
+ val newhigh = high vertcat Bounds(RationalExt.PositiveInfinity)
new Property(false, newlow, newA, newhigh)
}
@@ -677,8 +685,8 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
if (isEmpty)
Seq(LinearForm(1))
else {
- val set1 = for (i <- 0 until dimension; if !low(i).isInfinity) yield -LinearForm(-low(i).value +: A(i, ::).t.toScalaVector: _*)
- val set2 = for (i <- 0 until dimension; if !high(i).isInfinity) yield LinearForm(-high(i).value +: A(i, ::).t.toScalaVector: _*)
+ val set1 = for (i <- 0 until dimension; if !low(i).isInfinity) yield -LinearForm(-low(i).value +: A.row(i).toScalaVector: _*)
+ val set2 = for (i <- 0 until dimension; if !high(i).isInfinity) yield LinearForm(-high(i).value +: A.row(i).toScalaVector: _*)
set1 ++ set2
}
}
@@ -686,12 +694,12 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
def isPolyhedral = true
/**
- * @inheritdoc
- * @note @inheritdoc
- * @throws $ILLEGAL
- */
+ * @inheritdoc
+ * @note @inheritdoc
+ * @throws $ILLEGAL
+ */
def delVariable(n: Int): Property = {
- def rowToSeq(M: DenseMatrix[Rational], i: Int, n: Int): Seq[Rational] =
+ def rowToSeq(M: DenseMatrix, i: Int, n: Int): Seq[Rational] =
for (j <- 0 until A.rows; if j != n) yield M(i, j)
if (isEmpty)
@@ -705,36 +713,39 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
}
/**
- * @inheritdoc
- */
+ * @inheritdoc
+ */
def mapVariables(rho: Seq[Int]): Property = {
if (isEmpty)
this
else {
val slice = for (i <- 0 until dimension; j = rho.indexOf(i); if j != -1) yield j
- val newA = A(slice, slice).toDenseMatrix
- val newlow = low(slice).toDenseVector
- val newhigh = high(slice).toDenseVector
+ val newA = A(slice, slice)
+ val newlow = low(slice)
+ val newhigh = high(slice)
new Property(false, newlow, newA, newhigh)
}
}
/**
- * Compute the minimum and maximum value of a linear form in a parallelotope.
- * @todo should be generalized to linear forms over arbitrary types.
- * @return a tuple with two components: the first component is the least value, the second component is the greatest value
- * of the linear form over the box.
- */
+ * Compute the minimum and maximum value of a linear form in a parallelotope.
+ *
+ * @todo should be generalized to linear forms over arbitrary types.
+ * @return a tuple with two components: the first component is the least value, the second component is the greatest value
+ * of the linear form over the box.
+ */
def linearEvaluation(lf: LinearForm): (RationalExt, RationalExt) = {
val tcoeff = lf.homcoeffs
- if (isEmpty && tcoeff.exists { _ != Rational.zero })
+ if (isEmpty && tcoeff.exists {
+ _ != Rational.zero
+ })
(RationalExt.PositiveInfinity, RationalExt.NegativeInfinity)
else if (dimension == 0)
(lf.known, lf.known)
else {
val coeff = tcoeff.padTo(dimension, Rational.zero).toArray
- val vec = DenseVector(coeff)
+ val vec = new DenseVector(coeff)
val newvec = A.t \ vec
val (min, max) = domain.extremalsInBox(newvec, low, high)
(min + lf.known, max + lf.known)
@@ -761,7 +772,8 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
def top = ParallelotopeRationalDomain.this.top(dimension)
def tryCompareTo[B >: Property](that: B)(implicit arg0: (B) => PartiallyOrdered[B]): Option[Int] = that match {
- case that: Property =>
+ // we use ParallelotopeRationalDomain#Property instead of just Property to avoid a warning
+ case that: ParallelotopeRationalDomain#Property =>
val lte = this <= that
val gte = that <= this
if (lte && gte)
@@ -776,20 +788,21 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
}
/**
- * It computes the smallest parallelotope which contains `this` and is definable
- * over a new shape matrix `Aprime`.
- * @param Aprime the new shape matrix.
- * @note `Aprime` should be an invertible matrix of the same dimension as `this`.
- * @throws IllegalArgumentException if `Aprime` is not square or has not the correct dimension.
- */
- def rotate(Aprime: DenseMatrix[Rational]): Property = {
+ * It computes the smallest parallelotope which contains `this` and is definable
+ * over a new shape matrix `Aprime`.
+ *
+ * @param Aprime the new shape matrix.
+ * @note `Aprime` should be an invertible matrix of the same dimension as `this`.
+ * @throws IllegalArgumentException if `Aprime` is not square or has not the correct dimension.
+ */
+ def rotate(Aprime: DenseMatrix): Property = {
require(dimension == Aprime.rows && dimension == Aprime.cols)
if (isEmpty)
this
else {
- val B = Aprime * (A \ DenseMatrix.eye[Rational](dimension))
- val newlow = DenseVector.fill(dimension)(RationalExt.zero)
- val newhigh = DenseVector.fill(dimension)(RationalExt.zero)
+ val B = Aprime * (A \ DenseMatrix.eye(dimension))
+ val newlow = Bounds.fill(dimension)(RationalExt.zero)
+ val newhigh = Bounds.fill(dimension)(RationalExt.zero)
B.foreachPair {
case ((i, j), v) =>
if (v > Rational.zero) {
@@ -804,26 +817,31 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
}
}
- def <=[B >: Property](that: Property)(implicit arg0: (B) => PartiallyOrdered[B]): Boolean = {
- if (isEmpty)
- true
- else if (that.isEmpty)
- false
- else if (that.isTop)
- true
- else {
- val ptemp = this.rotate(that.A)
- (0 to ptemp.low.length - 1) forall { i => ptemp.low(i) >= that.low(i) && ptemp.high(i) <= that.high(i) }
+ override def <=[B >: Property](that: B)(implicit arg0: (B) => PartiallyOrdered[B]): Boolean =
+ that match {
+ // we use ParallelotopeRationalDomain#Property instead of just Property to avoid a warning
+ case that: ParallelotopeRationalDomain#Property =>
+ if (isEmpty)
+ true
+ else if (that.isEmpty)
+ false
+ else if (that.isTop)
+ true
+ else {
+ val ptemp = this.rotate(that.A)
+ (0 to ptemp.low.length - 1) forall { i => ptemp.low(i) >= that.low(i) && ptemp.high(i) <= that.high(i) }
+ }
+ case _ => false
}
- }
- def >=[B >: Property](that: Property)(implicit arg0: (B) => PartiallyOrdered[B]): Boolean =
+
+ override def >=[B >: Property](that: B)(implicit arg0: (B) => PartiallyOrdered[B]): Boolean =
that <= this
- def <[B >: Property](that: Property)(implicit arg0: (B) => PartiallyOrdered[B]): Boolean =
+ override def <[B >: Property](that: B)(implicit arg0: (B) => PartiallyOrdered[B]): Boolean =
(this <= that) && !(this >= that)
- def >[B >: Property](that: Property)(implicit arg0: (B) => PartiallyOrdered[B]): Boolean =
+ override def >[B >: Property](that: B)(implicit arg0: (B) => PartiallyOrdered[B]): Boolean =
(this >= that) && !(this <= that)
def mkString(vars: Seq[String]): String = {
@@ -831,7 +849,7 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
/*
* Returns a string representation of the linear form `lf`.
*/
- def lfToString(lf: DenseVector[Rational]): String = {
+ def lfToString(lf: DenseVector): String = {
var first = true
val s = new StringBuilder
val minusOne = -Rational.one
@@ -860,30 +878,32 @@ class ParallelotopeRationalDomain private (favorAxis: Int) extends NumericalDoma
else {
val eqns = for (i <- 0 until dimension) yield {
if (low(i) < high(i))
- s"${if (low(i).isNegInfinity) "-∞" else low(i)} ≤ ${lfToString(A.t(::, i))} ≤ ${if (high(i).isPosInfinity) "+∞" else high(i)}"
+ s"${if (low(i).isNegInfinity) "-∞" else low(i)} ≤ ${lfToString(A.row(i))} ≤ ${if (high(i).isPosInfinity) "+∞" else high(i)}"
else
- s"${lfToString(A.t(::, i))} = ${high(i)}"
+ s"${lfToString(A.row(i))} = ${high(i)}"
}
eqns.mkString("[ ", " , ", " ]")
}
}
}
+
}
/**
- * Companion class for the parallelotope domain
- */
+ * Companion class for the parallelotope domain
+ */
object ParallelotopeRationalDomain {
private lazy val standard = new ParallelotopeRationalDomain(0) with CachedTopBottom
private lazy val favoring = new ParallelotopeRationalDomain(1) with CachedTopBottom
private lazy val unfavoring = new ParallelotopeRationalDomain(-1) with CachedTopBottom
/**
- * Returns an abstract domain for parallelotopes.
- * @param favorAxis determines whether the heuristics built into the domain should try to keep constraints
- * corresponding to Cartesian axis. If favorAxis is `1`, axis are favorite. The opposite happens when favorAxis
- * is -1. If favorAxis is 0, axis are considered like all the other constraints
- */
+ * Returns an abstract domain for parallelotopes.
+ *
+ * @param favorAxis determines whether the heuristics built into the domain should try to keep constraints
+ * corresponding to Cartesian axis. If favorAxis is `1`, axis are favorite. The opposite happens when favorAxis
+ * is -1. If favorAxis is 0, axis are considered like all the other constraints
+ */
def apply(favorAxis: Int = 0) = favorAxis match {
case -1 => unfavoring
case 0 => standard
diff --git a/core/src/main/scala/it/unich/jandom/domains/numerical/ProductDomain.scala b/core/src/main/scala/it/unich/jandom/domains/numerical/ProductDomain.scala
index 5cb03b16..1abb0300 100644
--- a/core/src/main/scala/it/unich/jandom/domains/numerical/ProductDomain.scala
+++ b/core/src/main/scala/it/unich/jandom/domains/numerical/ProductDomain.scala
@@ -1,5 +1,5 @@
/**
- * Copyright 2013, 2016 Gianluca Amato, Francesca Scozzari
+ * Copyright 2013, 2016 Jandom Team
*
* This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
* JANDOM is free software: you can redistribute it and/or modify
@@ -36,18 +36,17 @@ import it.unich.scalafix.Box
* @author Francesca Scozzari
*/
class ProductDomain[D1 <: NumericalDomain, D2 <: NumericalDomain](val dom1: D1, val dom2: D2)(
- implicit val dom1Todom2: DomainTransformation[D1,D2], val dom2Todom1: DomainTransformation[D2,D1]) extends NumericalDomain {
-
+ implicit val dom1Todom2: DomainTransformation[D1, D2], val dom2Todom1: DomainTransformation[D2, D1]) extends NumericalDomain {
val widenings = {
- for (w1 <- dom1.widenings; w2 <- dom2.widenings) yield
- WideningDescription(s"${w1.name} X ${w2.name}",s"Component-wise combination of the two widenings.",
- Box { (a: Product, b: Product) =>
- new Product( w1.box(a.p1, b.p1), w2.box(a.p2, b.p2) )
- })
+ for (w1 <- dom1.widenings; w2 <- dom2.widenings)
+ yield WideningDescription(s"${w1.name} X ${w2.name}", s"Component-wise combination of the two widenings.",
+ Box { (a: Property, b: Property) =>
+ new Property(w1.box(a.p1, b.p1), w2.box(a.p2, b.p2))
+ })
}
- private val d12 = dom1Todom2(dom1,dom2)
- private val d21 = dom2Todom1(dom2,dom1)
+ private val d12 = dom1Todom2(dom1, dom2)
+ private val d21 = dom2Todom1(dom2, dom1)
type Property = Product
@@ -73,8 +72,8 @@ class ProductDomain[D1 <: NumericalDomain, D2 <: NumericalDomain](val dom1: D1,
def reduce(x1: dom1.Property, x2: dom2.Property): Product = {
if (x1.isEmpty || x2.isEmpty)
- new Product(x1.bottom,x2.bottom)
- else{
+ new Property(x1.bottom, x2.bottom)
+ else {
val y1 = x1.intersection(d21(x2))
val y2 = x2.intersection(d12(x1))
@@ -127,21 +126,21 @@ class ProductDomain[D1 <: NumericalDomain, D2 <: NumericalDomain](val dom1: D1,
}
def minimize(lf: LinearForm) = {
- val q1=p1.minimize(lf)
- val q2=p2.minimize(lf)
+ val q1 = p1.minimize(lf)
+ val q2 = p2.minimize(lf)
q1 max q2
}
def maximize(lf: LinearForm) = {
- val q1=p1.maximize(lf)
- val q2=p2.maximize(lf)
+ val q1 = p1.maximize(lf)
+ val q2 = p2.maximize(lf)
q1 min q2
}
def frequency(lf: LinearForm) = {
- // This could be made more precise when the concrete domain is integer
+ // This could be made more precise when the concrete domain is integer
p1.frequency(lf) match {
- case v@ Some(c) => v
+ case v @ Some(c) => v
case None => p2.frequency(lf)
}
}
@@ -183,20 +182,26 @@ class ProductDomain[D1 <: NumericalDomain, D2 <: NumericalDomain](val dom1: D1,
p1.mkString(vars) + " / " + p2.mkString(vars)
}
- def tryCompareTo[B >: Product](other: B)(implicit arg0: (B) => PartiallyOrdered[B]): Option[Int] = {
- other match {
- case other: Product => {
- val c1 = p1.tryCompareTo(other.p1)
- val c2 = p2.tryCompareTo(other.p2)
- if (c1 == Some(0))
- c2
- else if (c2 == Some(0))
- c1
- else if (c1 == c2)
- c1
+
+ def tryCompareTo[B >: Property](that: B)(implicit arg0: (B) => PartiallyOrdered[B]): Option[Int] = {
+ that match {
+ case that: Property =>
+ if (this.isBottom && that.isBottom)
+ Option(0)
+ else if (this.isBottom)
+ Option(-1)
+ else if (that.isBottom)
+ Option(1)
+ else if (this.isTop && that.isTop)
+ Option(0)
+ else if (this.isTop)
+ Option(1)
+ else if (that.isTop)
+ Option(-1)
+ else if (p1 == this.p1 && p2 == that.p2)
+ Option(0)
else
Option.empty
- }
case _ => Option.empty
}
}
diff --git a/core/src/main/scala/it/unich/jandom/domains/numerical/SumDomain.scala b/core/src/main/scala/it/unich/jandom/domains/numerical/SumDomain.scala
index e17df2c8..eeb0490b 100644
--- a/core/src/main/scala/it/unich/jandom/domains/numerical/SumDomain.scala
+++ b/core/src/main/scala/it/unich/jandom/domains/numerical/SumDomain.scala
@@ -1,5 +1,5 @@
/**
- * Copyright 2014, 2016 Gianluca Amato, Francesca Scozzari, Simone Di Nardo Di Maio
+ * Copyright 2014, 2016 Jandom Team
*
* This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
* JANDOM is free software: you can redistribute it and/or modify
@@ -76,19 +76,16 @@ abstract class SumDomain[D1 <: NumericalDomain, D2 <: NumericalDomain] extends N
def narrowing(that: Property): Property = {
require(dimension == that.dimension)
- SumDomain.this(p1 narrowing that.p1, p2 narrowing that.p2)
+ // we can apply component-wise narrowing only when both components in this w.r.t. those in that
+ if (that.p1 < p1 && that.p2 < p2)
+ SumDomain.this(p1 narrowing that.p1, p2 narrowing that.p2)
+ else
+ this
}
def intersection(that: Property): Property = {
require(dimension == that.dimension)
- if (isEmpty)
- this
- else if (that.isEmpty)
- that
- else if (that.isTop)
- this
- else
- that
+ if (this < that) this else that
}
def nonDeterministicAssignment(n: Int): Property = {
@@ -106,8 +103,8 @@ abstract class SumDomain[D1 <: NumericalDomain, D2 <: NumericalDomain] extends N
// we divide the known coefficient evenly between the two domains
// a better choice could be performed by knowing some info on the two domains
val newlf = new DenseLinearForm(lf.known / 2 +: lf.homcoeffs)
- var q1 = p1.linearAssignment(n, newlf)
- var q2 = p2.linearAssignment(n, newlf)
+ val q1 = p1.linearAssignment(n, newlf)
+ val q2 = p2.linearAssignment(n, newlf)
SumDomain.this(q1, q2)
}
@@ -115,8 +112,8 @@ abstract class SumDomain[D1 <: NumericalDomain, D2 <: NumericalDomain] extends N
if (p1.isEmpty || p2.isEmpty)
this
else {
- var w1 = p1.minimize(lf)
- var w2 = p2.minimize(lf)
+ val w1 = p1.minimize(lf)
+ val w2 = p2.minimize(lf)
if (!w1.isInfinity && !w2.isInfinity) {
val lf_k1 = new DenseLinearForm(w2.value +: lf.homcoeffs)
val lf_k2 = new DenseLinearForm(w1.value +: lf.homcoeffs)
diff --git a/core/src/main/scala/it/unich/jandom/domains/numerical/SumGenericDomain.scala b/core/src/main/scala/it/unich/jandom/domains/numerical/SumGenericDomain.scala
index b369f479..ec51bb17 100644
--- a/core/src/main/scala/it/unich/jandom/domains/numerical/SumGenericDomain.scala
+++ b/core/src/main/scala/it/unich/jandom/domains/numerical/SumGenericDomain.scala
@@ -28,7 +28,6 @@ package it.unich.jandom.domains.numerical
class SumGenericDomain[D1 <: NumericalDomain, D2 <: NumericalDomain](val dom1: D1, val dom2: D2) extends SumDomain[D1,D2] {
type Property = SumGeneric
-
class SumGeneric(val p1: dom1.Property, val p2: dom2.Property) extends Sum
def apply(p1: dom1.Property, p2: dom2.Property) = new SumGeneric(p1, p2)
diff --git a/core/src/main/scala/it/unich/jandom/domains/numerical/SumIntParallelotopeDomain.scala b/core/src/main/scala/it/unich/jandom/domains/numerical/SumIntParallelotopeDomain.scala
index 0961e172..8db728da 100644
--- a/core/src/main/scala/it/unich/jandom/domains/numerical/SumIntParallelotopeDomain.scala
+++ b/core/src/main/scala/it/unich/jandom/domains/numerical/SumIntParallelotopeDomain.scala
@@ -25,33 +25,32 @@ package it.unich.jandom.domains.numerical
* @author Simone Di Nardo Di Maio
*/
-class SumIntParallelotopeDomain(val dom1: BoxDoubleDomain, val dom2: ParallelotopeDomain) extends SumDomain[BoxDoubleDomain, ParallelotopeDomain] {
- type Property = SumIntParallelotope
-
- class SumIntParallelotope(val p1: dom1.Property, val p2: dom2.Property) extends Sum {
+class SumBoxDoubleParallelotopeRationDomain(val dom1: BoxDoubleDomain, val dom2: ParallelotopeRationalDomain) extends SumDomain[BoxDoubleDomain, ParallelotopeRationalDomain] {
+ type Property = SumBoxDoubleParallelotopeRational
+ class SumBoxDoubleParallelotopeRational(val p1: dom1.Property, val p2: dom2.Property) extends Sum {
override def linearAssignment(n: Int, lf: LinearForm): Property = {
if ((n >= lf.homcoeffs.size) || (lf.homcoeffs(n) == 0)) {
val q1 = p1.linearAssignment(n, lf)
val q2 = p2.linearAssignment(n, lf.hom)
- SumIntParallelotopeDomain.this(q1, q2)
+ SumBoxDoubleParallelotopeRationDomain.this(q1, q2)
} else {
val q1 = p1.linearAssignment(n, lf.hom)
val q2 = p2.linearAssignment(n,lf)
- SumIntParallelotopeDomain.this(q1, q2)
+ SumBoxDoubleParallelotopeRationDomain.this(q1, q2)
}
}
}
- def apply(p1: dom1.Property, p2: dom2.Property) = new SumIntParallelotope(p1, p2)
+ def apply(p1: dom1.Property, p2: dom2.Property) = new SumBoxDoubleParallelotopeRational(p1, p2)
}
/**
* Companion class for the Int+Parallelotope domain
*/
-object SumIntParallelotopeDomain {
+object SumBoxDoubleParallelotopeRationDomain {
/**
* Returns the standard Int+Parallelotope Domain
*/
def apply() = v
- private lazy val v = new SumIntParallelotopeDomain(BoxDoubleDomain(), ParallelotopeDomain(favorAxes = true))
+ private lazy val v = new SumBoxDoubleParallelotopeRationDomain(BoxDoubleDomain(), ParallelotopeRationalDomain(favorAxis = 1))
}
diff --git a/core/src/main/scala/it/unich/jandom/domains/objects/AliasingDomain.scala b/core/src/main/scala/it/unich/jandom/domains/objects/AliasingDomain.scala
index 8c5e1d1f..112e4ff4 100644
--- a/core/src/main/scala/it/unich/jandom/domains/objects/AliasingDomain.scala
+++ b/core/src/main/scala/it/unich/jandom/domains/objects/AliasingDomain.scala
@@ -1,5 +1,5 @@
/**
- * Copyright 2014 Gianluca Amato
+ * Copyright 2014, 2016 Gianluca Amato
*
* This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
* JANDOM is free software: you can redistribute it and/or modify
@@ -456,7 +456,7 @@ class AliasingDomain[OM <: ObjectModel](val om: OM) extends ObjectDomain[OM] {
def widening(that: Property): Property = this union that
- def narrowing(that: Property): Property = that
+ def narrowing(that: Property): Property = this intersection that
def union(other: Property): Property = (this unionWithMorphisms other)._1
diff --git a/core/src/main/scala/it/unich/jandom/domains/objects/PairSharingDomain.scala b/core/src/main/scala/it/unich/jandom/domains/objects/PairSharingDomain.scala
index 15d5eabe..c6c02a6e 100644
--- a/core/src/main/scala/it/unich/jandom/domains/objects/PairSharingDomain.scala
+++ b/core/src/main/scala/it/unich/jandom/domains/objects/PairSharingDomain.scala
@@ -1,5 +1,5 @@
/**
- * Copyright 2013 Gianluca Amato
+ * Copyright 2013, 2016 Gianluca Amato
*
* This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
* JANDOM is free software: you can redistribute it and/or modify
@@ -8,7 +8,7 @@
* (at your option) any later version.
*
* JANDOM is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty ofa
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
@@ -107,7 +107,7 @@ class PairSharingDomain[OM <: ObjectModel](val om: OM) extends ObjectDomain[OM]
def widening(that: Property) = union(that)
- def narrowing(that: Property) = that
+ def narrowing(that: Property) = intersection(that)
def addUnknownVariable(t: om.Type) = {
new Property(ps, t +: rtypes)
diff --git a/core/src/main/scala/it/unich/jandom/parsers/FastParser.scala b/core/src/main/scala/it/unich/jandom/parsers/FastParser.scala
index fa8471fc..1ddc8c19 100644
--- a/core/src/main/scala/it/unich/jandom/parsers/FastParser.scala
+++ b/core/src/main/scala/it/unich/jandom/parsers/FastParser.scala
@@ -25,9 +25,7 @@ import it.unich.jandom.targets.Environment
import it.unich.jandom.targets.NumericAssignment
import it.unich.jandom.targets.NumericCondition
import it.unich.jandom.targets.NumericCondition._
-import it.unich.jandom.targets.NumericExpression._
import it.unich.jandom.targets.lts._
-import it.unich.jandom.targets.NumericAssignmentMultiple
/**
* Parser for transition systems as they appear in the Fast analyzer.
diff --git a/core/src/main/scala/it/unich/jandom/parsers/LPInvParser.scala b/core/src/main/scala/it/unich/jandom/parsers/LPInvParser.scala
index 98243aba..14aee117 100644
--- a/core/src/main/scala/it/unich/jandom/parsers/LPInvParser.scala
+++ b/core/src/main/scala/it/unich/jandom/parsers/LPInvParser.scala
@@ -25,7 +25,6 @@ import it.unich.jandom.targets.lts.LTS
import it.unich.jandom.targets.lts.Location
import it.unich.jandom.targets.lts.Transition
import it.unich.jandom.targets.NumericAssignment
-import it.unich.jandom.targets.NumericAssignmentMultiple
/**
* Parser for transition systems as they appear in the [[http://www.cs.colorado.edu/~srirams/Software/lpinv.html LPInv]]
diff --git a/core/src/main/scala/it/unich/jandom/parsers/NumericConditionParser.scala b/core/src/main/scala/it/unich/jandom/parsers/NumericConditionParser.scala
index 93877bb7..b081acc9 100644
--- a/core/src/main/scala/it/unich/jandom/parsers/NumericConditionParser.scala
+++ b/core/src/main/scala/it/unich/jandom/parsers/NumericConditionParser.scala
@@ -19,7 +19,6 @@
package it.unich.jandom.parsers
import scala.util.parsing.combinator.JavaTokenParsers
-import it.unich.jandom.domains.numerical.LinearForm
import it.unich.jandom.targets.NumericExpression
import it.unich.jandom.targets.NumericCondition
import it.unich.jandom.targets.NumericCondition._
diff --git a/core/src/main/scala/it/unich/jandom/targets/EQSSolver.scala b/core/src/main/scala/it/unich/jandom/targets/EQSSolver.scala
new file mode 100644
index 00000000..1f2cfc6e
--- /dev/null
+++ b/core/src/main/scala/it/unich/jandom/targets/EQSSolver.scala
@@ -0,0 +1,67 @@
+/**
+ * Copyright 2016 Gianluca Amato
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
+
+package it.unich.jandom.targets
+
+import it.unich.jandom.targets.parameters.{IterationStrategy, WideningNarrowingLocation, WideningScope}
+import it.unich.scalafix.FixpointSolver._
+import it.unich.scalafix._
+import it.unich.scalafix.finite.{FiniteFixpointSolver, GraphEquationSystem}
+
+/**
+ * This is a solver for equations systems which takes a Parameters object in order to drive
+ * the analysis.
+ */
+
+object EQSSolver {
+ def apply[Tgt <: Target[Tgt]](tgt: Tgt)(dom: tgt.DomainBase)(params: Parameters[Tgt] { val domain: dom.type })(listener: FixpointSolverListener[tgt.ProgramPoint, params.domain.Property] = FixpointSolverListener.EmptyListener)
+ : Assignment[tgt.ProgramPoint, params.domain.Property] = {
+ import params._
+ implicit val scalafixDomain = params.domain.ScalaFixDomain
+
+ if (params.wideningLocation != params.narrowingLocation)
+ throw new IllegalArgumentException("widening and narrowing locations should be the same");
+
+ val boxlocation = wideningLocation match {
+ case WideningNarrowingLocation.None => BoxLocation.None
+ case WideningNarrowingLocation.All => BoxLocation.All
+ case WideningNarrowingLocation.Loop => BoxLocation.Loop
+ }
+
+ val solver = iterationStrategy match {
+ case IterationStrategy.Kleene => Solver.KleeneSolver
+ case IterationStrategy.Worklist => Solver.WorkListSolver
+ }
+
+ val scope = wideningScope match {
+ case WideningScope.Output => BoxScope.Standard
+ case WideningScope.Random => BoxScope.Localized
+ case WideningScope.BackEdges => ???
+ }
+
+ val eqs = tgt.toEQS(params.domain)
+ val eqsParams = FiniteFixpointSolver.CC77[tgt.ProgramPoint, params.domain.Property](solver, widening, narrowing).copy(
+ boxlocation = boxlocation, boxscope = scope, listener = listener
+ )
+
+ eqs match {
+ case eqs: GraphEquationSystem[tgt.ProgramPoint, domain.Property, _] => FiniteFixpointSolver(eqs, eqsParams)
+ case _ => ???
+ }
+ }
+}
diff --git a/core/src/main/scala/it/unich/jandom/targets/NumericAssignment.scala b/core/src/main/scala/it/unich/jandom/targets/NumericAssignment.scala
index e758e2cf..4f8936b7 100644
--- a/core/src/main/scala/it/unich/jandom/targets/NumericAssignment.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/NumericAssignment.scala
@@ -18,8 +18,7 @@
package it.unich.jandom.targets
-import it.unich.jandom.domains.numerical.{ LinearForm, NumericalProperty }
-import it.unich.jandom.targets.NumericExpression._
+import it.unich.jandom.domains.numerical.NumericalProperty
/**
* This is a target class for the numeric assignments "v := exp".
diff --git a/core/src/main/scala/it/unich/jandom/targets/NumericExpression.scala b/core/src/main/scala/it/unich/jandom/targets/NumericExpression.scala
index 64a01116..82b36155 100644
--- a/core/src/main/scala/it/unich/jandom/targets/NumericExpression.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/NumericExpression.scala
@@ -150,9 +150,9 @@ object NumericExpression {
override def lteZero[Property <: NumericalProperty[Property]](input: Property): Property =
input.linearInequality(lf)
- override def ltZero[Property <: NumericalProperty[Property]](input: Property): Property =
+ override def ltZero[Property <: NumericalProperty[Property]](input: Property): Property = {
input.linearInequality(lf)
-
+ }
override def neqZero[Property <: NumericalProperty[Property]](input: Property): Property =
input.linearDisequality(lf)
diff --git a/core/src/main/scala/it/unich/jandom/targets/Parameters.scala b/core/src/main/scala/it/unich/jandom/targets/Parameters.scala
index 318cce52..6e599e57 100644
--- a/core/src/main/scala/it/unich/jandom/targets/Parameters.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/Parameters.scala
@@ -21,8 +21,6 @@ package it.unich.jandom.targets
import it.unich.jandom.targets.parameters._
import it.unich.jandom.targets.parameters.NarrowingSpecs._
import it.unich.jandom.targets.parameters.WideningSpecs._
-import it.unich.jandom.ui.NarrowingStrategies
-import it.unich.jandom.ui.WideningScopes
import it.unich.scalafix.BoxAssignment
/**
@@ -75,7 +73,7 @@ abstract class Parameters[Tgt <: Target[Tgt]] {
/**
* The current narrowing, returned as a box assignment.
*/
- def narrowing = {
+ def narrowing: BoxAssignment[Tgt#ProgramPoint, domain.Property] = {
if (_narrowing == null) _narrowing = DefaultNarrowing.get(domain)
_narrowing
}
diff --git a/core/src/main/scala/it/unich/jandom/targets/Target.scala b/core/src/main/scala/it/unich/jandom/targets/Target.scala
index 9e6d7401..6d5e25c5 100644
--- a/core/src/main/scala/it/unich/jandom/targets/Target.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/Target.scala
@@ -21,6 +21,7 @@ package it.unich.jandom.targets
import scala.collection.mutable.HashMap
import it.unich.jandom.domains.AbstractDomain
+import it.unich.scalafix.EquationSystem
/**
* The abstract class for targets, which are the static analyzers for the
@@ -63,4 +64,9 @@ abstract class Target[Tgt <: Target[Tgt]] {
* @return an annotation for the program
*/
def analyze(params: Parameters): Annotation[ProgramPoint,params.Property]
+
+ /**
+ * Return an Equation System corresponding to the target
+ */
+ def toEQS(dom: DomainBase): EquationSystem[ProgramPoint, dom.Property] = ???
}
diff --git a/core/src/main/scala/it/unich/jandom/targets/cfg/ControlFlowGraph.scala b/core/src/main/scala/it/unich/jandom/targets/cfg/ControlFlowGraph.scala
index 81580332..0f24a504 100644
--- a/core/src/main/scala/it/unich/jandom/targets/cfg/ControlFlowGraph.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/cfg/ControlFlowGraph.scala
@@ -19,7 +19,7 @@
package it.unich.jandom.targets.cfg
import scala.collection.mutable.HashMap
import scala.collection.mutable.Queue
-
+import scala.collection.JavaConverters._
import it.unich.jandom.targets.Annotation
import it.unich.jandom.targets.Target
import soot.toolkits.graph.DirectedGraph
@@ -33,8 +33,6 @@ import soot.toolkits.graph.DirectedGraph
* @author Francesca Scozzari
*/
abstract class ControlFlowGraph[Tgt <: ControlFlowGraph[Tgt, Node], Node] extends Target[Tgt] {
- import scala.collection.JavaConversions._
-
/**
* The `ProgramPoint` type is defined as an alias for the `Node`. We are wondering whether to make
* `ProgramPoint` an alias for `Edge`.
@@ -69,7 +67,7 @@ abstract class ControlFlowGraph[Tgt <: ControlFlowGraph[Tgt, Node], Node] extend
* of the CFG, so be careful to preserve this property.
*/
def extractOutput(params: Parameters)(ann: Annotation[ProgramPoint, params.Property]): params.Property = {
- graph.getTails map { (node) => analyzeBlock(params)(node, ann(node)).last } reduce { _ union _ }
+ graph.getTails.asScala map { (node) => analyzeBlock(params)(node, ann(node)).last } reduce { _ union _ }
}
/**
@@ -98,25 +96,25 @@ abstract class ControlFlowGraph[Tgt <: ControlFlowGraph[Tgt, Node], Node] extend
/**
* Analyzes the target, starting from a given property.
- * @param param the parameters which drive the analyzer
+ * @param params the parameters which drive the analyzer
* @param input the starting property
* @return the resulting annotation
* @note this should be moved in the Target class.
*/
def analyzeFromInput(params: Parameters)(input: params.Property): Annotation[ProgramPoint, params.Property] = {
val ann = getAnnotation[params.Property]
- for (node <- graph.getHeads()) ann(node) = expandPropertyWithLocalVariables(params)(input)
+ for (node <- graph.getHeads().asScala) ann(node) = expandPropertyWithLocalVariables(params)(input)
analyzeFromAnnotation(params)(ann)
}
/**
* Perform a static analysis over the target, from a standard initial annotation
- * @param param the parameters which drive the analyzer
+ * @param params the parameters which drive the analyzer
* @return an annotation for the program
*/
def analyze(params: Parameters): Annotation[ProgramPoint, params.Property] = {
val ann = getAnnotation[params.Property]
- for (node <- graph.getHeads) ann(node) = topProperty(node, params)
+ for (node <- graph.getHeads.asScala) ann(node) = topProperty(node, params)
analyzeFromAnnotation(params)(ann)
}
@@ -125,7 +123,7 @@ abstract class ControlFlowGraph[Tgt <: ControlFlowGraph[Tgt, Node], Node] extend
*/
def analyzeFromAnnotation(params: Parameters)(ann: Annotation[ProgramPoint, params.Property]): Annotation[ProgramPoint, params.Property] = {
val annEdge = HashMap[Edge, params.Property]()
- val taskList = Queue[ProgramPoint](graph.getHeads: _*)
+ val taskList = Queue[ProgramPoint](graph.getHeads.asScala: _*)
// ASCENDING phase
params.log("Ascening Phase\n")
@@ -134,14 +132,13 @@ abstract class ControlFlowGraph[Tgt <: ControlFlowGraph[Tgt, Node], Node] extend
params.log(s"node ${node}input ${ann(node)}\n")
val result = analyzeBlock(params)(node, ann(node))
params.log("result " + result.mkString(",") + "\n")
- for ((succ, out) <- graph.getSuccsOf(node) zip result) {
+ for ((succ, out) <- graph.getSuccsOf(node).asScala zip result) {
annEdge((node, succ)) = out
- if (graph.getPredsOf(succ).length > 1 && (ann contains succ)) {
+ if (graph.getPredsOf(succ).size() > 1 && (ann contains succ)) {
params.log(s"join $succ : ${ann(succ)} with $out")
val succval: params.Property = if (ordering.lteq(succ, node)) {
params.log(s" widening")
- val widening = params.widening(node)
- widening(ann(succ), out)
+ params.widening(node)(ann(succ), out)
} else
ann(succ) union out
if (succval > ann(succ)) {
@@ -159,21 +156,20 @@ abstract class ControlFlowGraph[Tgt <: ControlFlowGraph[Tgt, Node], Node] extend
}
// DESCENDING phase
- taskList.enqueue(graph.toSeq: _*)
+ taskList.enqueue(graph.asScala.toSeq: _*)
params.log("Descending Phase\n")
while (!taskList.isEmpty) {
val node = taskList.dequeue
params.log(s"node ${node} input ${ann(node)} ")
val result = analyzeBlock(params)(node, ann(node))
- params.log("result " + (graph.getSuccsOf(node) zip result).mkString(" ; ") + "\n")
- for ((succ, out) <- graph.getSuccsOf(node) zip result) {
+ params.log("result " + (graph.getSuccsOf(node).asScala zip result).mkString(" ; ") + "\n")
+ for ((succ, out) <- graph.getSuccsOf(node).asScala zip result) {
annEdge((node, succ)) = out
- val newinput = ann(succ) intersection (graph.getPredsOf(succ) map { e => annEdge((e, succ)) } reduce { _ union _ })
+ val newinput = ann(succ) intersection (graph.getPredsOf(succ).asScala map { e => annEdge((e, succ)) } reduce { _ union _ })
params.log(s"narrow $succ : ${ann(succ)} with $newinput ")
// this may probably cause an infinite loop
val succval = if (ordering.lteq(succ, node)) {
- val narrowing = params.narrowing(node)
- narrowing(ann(succ), newinput)
+ params.narrowing(node)(ann(succ), newinput)
} else
newinput
params.log(s"result $succval\n")
diff --git a/core/src/main/scala/it/unich/jandom/targets/jvmasm/AsmMethod.scala b/core/src/main/scala/it/unich/jandom/targets/jvmasm/AsmMethod.scala
index c21608c5..31d7d40d 100644
--- a/core/src/main/scala/it/unich/jandom/targets/jvmasm/AsmMethod.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/jvmasm/AsmMethod.scala
@@ -27,7 +27,6 @@ import org.objectweb.asm._
import org.objectweb.asm.tree._
import org.objectweb.asm.util._
-import it.unich.jandom.domains.numerical.NumericalProperty
import it.unich.jandom.targets.Annotation
import it.unich.jandom.targets.Target
import it.unich.jandom.targets.NumericCondition._
@@ -86,7 +85,7 @@ class AsmMethod(val methodNode: MethodNode) extends Target[AsmMethod] {
import Opcodes._
val s = state.clone
var node = startNode
- var lastNode = endNode.getNext()
+ val lastNode = endNode.getNext()
var exits = Seq[(BasicBlock, Property)]()
while (node != lastNode) {
val op = node.getOpcode
@@ -167,9 +166,6 @@ class AsmMethod(val methodNode: MethodNode) extends Target[AsmMethod] {
* It is called by the constructor.
*/
private def createControlFlowGraph(): (BasicBlock, BasicBlock) = {
- import scala.collection.JavaConversions._
- import AbstractInsnNode._
-
// the use of asInstanceOf is needed because the standard
// asm library in the maven repositories is compiled without
// support for generics
diff --git a/core/src/main/scala/it/unich/jandom/targets/jvmasm/JVMEnvFixedFrame.scala b/core/src/main/scala/it/unich/jandom/targets/jvmasm/JVMEnvFixedFrame.scala
index d4717232..c5ade7bc 100644
--- a/core/src/main/scala/it/unich/jandom/targets/jvmasm/JVMEnvFixedFrame.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/jvmasm/JVMEnvFixedFrame.scala
@@ -18,8 +18,6 @@
package it.unich.jandom.targets.jvmasm
-import scala.collection.mutable.ArrayStack
-
import it.unich.jandom.domains.numerical.LinearForm
import it.unich.jandom.domains.numerical.NumericalDomain
import it.unich.jandom.domains.numerical.NumericalProperty
diff --git a/core/src/main/scala/it/unich/jandom/targets/jvmasm/UnsupportedASMInsnException.scala b/core/src/main/scala/it/unich/jandom/targets/jvmasm/UnsupportedASMInsnException.scala
index 7b6e4bce..3bab84c4 100644
--- a/core/src/main/scala/it/unich/jandom/targets/jvmasm/UnsupportedASMInsnException.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/jvmasm/UnsupportedASMInsnException.scala
@@ -19,7 +19,6 @@
package it.unich.jandom.targets.jvmasm
import org.objectweb.asm.tree._
-import soot.baf.Inst
/**
* This exception is generated by the ASM analyzer when an unknown opcode is
diff --git a/core/src/main/scala/it/unich/jandom/targets/jvmasm/package.scala b/core/src/main/scala/it/unich/jandom/targets/jvmasm/package.scala
deleted file mode 100644
index 21a353bb..00000000
--- a/core/src/main/scala/it/unich/jandom/targets/jvmasm/package.scala
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Copyright 2013 Gianluca Amato
- *
- * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
- * JANDOM is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * JANDOM is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty ofa
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with JANDOM. If not, see .
- */
-
-/**
- * This is the Scala package containing the targets for the analysis of Java bytecode. It uses the
- * libraries ASM and Soot to read class files
- * @author Gianluca Amato
- */
-package it.unich.jandom.targets.jvmasm {
-
-}
diff --git a/core/src/main/scala/it/unich/jandom/targets/jvmsoot/BafMethod.scala b/core/src/main/scala/it/unich/jandom/targets/jvmsoot/BafMethod.scala
index a1d29517..dfa48e15 100644
--- a/core/src/main/scala/it/unich/jandom/targets/jvmsoot/BafMethod.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/jvmsoot/BafMethod.scala
@@ -17,6 +17,8 @@
package it.unich.jandom.targets.jvmsoot
+import scala.collection.JavaConverters._
+
import soot._
import soot.baf._
import soot.jimple._
@@ -30,8 +32,6 @@ import soot.toolkits.graph._
* @author Luca Mangifesta
*/
class BafMethod(method: SootMethod) extends SootCFG[BafMethod, Block](method) {
- import scala.collection.JavaConversions._
-
val body = Baf.v().newBody(method.retrieveActiveBody())
val graph = new soot.jandom.UnitBlockGraph(body)
@@ -62,7 +62,7 @@ class BafMethod(method: SootMethod) extends SootCFG[BafMethod, Block](method) {
case _: IfNullInst => prop.evalNull().testEq
}
- for (unit <- node.iterator())
+ for (unit <- node.iterator().asScala)
currprop = unit match {
case unit: AddInst =>
unit.getOpType() match {
diff --git a/core/src/main/scala/it/unich/jandom/targets/jvmsoot/JimpleMethod.scala b/core/src/main/scala/it/unich/jandom/targets/jvmsoot/JimpleMethod.scala
index d8aa6509..4a978fb8 100644
--- a/core/src/main/scala/it/unich/jandom/targets/jvmsoot/JimpleMethod.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/jvmsoot/JimpleMethod.scala
@@ -18,6 +18,8 @@
package it.unich.jandom.targets.jvmsoot
+import scala.collection.JavaConverters._
+
import it.unich.jandom.domains.numerical.LinearForm
import it.unich.jandom.targets._
import it.unich.jandom.targets.NumericCondition._
@@ -35,8 +37,6 @@ import spire.math.Rational
* @author Francesca Scozzari
*/
class JimpleMethod(method: SootMethod) extends SootCFG[JimpleMethod, Block](method) {
- import scala.collection.JavaConversions._
-
val body = method.retrieveActiveBody()
val graph = new soot.jandom.UnitBlockGraph(body)
@@ -48,7 +48,6 @@ class JimpleMethod(method: SootMethod) extends SootCFG[JimpleMethod, Block](meth
*/
def jimpleExprToLinearForm(v: Value): Option[Array[Rational]] = {
val a = Array.fill(size + 1)(Rational.zero)
- var c = 0.0
v match {
case v: IntConstant =>
a(0) = v.value
@@ -163,7 +162,7 @@ class JimpleMethod(method: SootMethod) extends SootCFG[JimpleMethod, Block](meth
case v: DynamicInvokeExpr =>
throw new IllegalArgumentException("Invoke dynamic not yet supported")
}
- val callprop = v.getArgs().foldLeft(baseprop) { case (p, arg) => analyzeExpr(arg, p) }
+ val callprop = v.getArgs().asScala.foldLeft(baseprop) { case (p, arg) => analyzeExpr(arg, p) }
val inputprop = callprop.extract(v.getArgCount() + implicitArgs)
val exitprop = params.interpretation match {
case Some(inte) => inte(method, inputprop)
@@ -221,7 +220,6 @@ class JimpleMethod(method: SootMethod) extends SootCFG[JimpleMethod, Block](meth
case v: NeExpr => res2.evalNe
}
case v: UnopExpr =>
- val res = analyzeExpr(v.getOp(), prop)
v match {
case v: LengthExpr => prop.evalLength
case v: NegExpr => prop.evalNeg
@@ -236,7 +234,7 @@ class JimpleMethod(method: SootMethod) extends SootCFG[JimpleMethod, Block](meth
var exits = Seq[params.Property]()
var currprop = initprop
- for (unit <- node.iterator())
+ for (unit <- node.asScala)
unit match {
case unit: AssignStmt =>
val expr = analyzeExpr(unit.getRightOp(), currprop)
diff --git a/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootCFG.scala b/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootCFG.scala
index eebdf170..53d46d34 100644
--- a/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootCFG.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootCFG.scala
@@ -20,7 +20,8 @@ package it.unich.jandom.targets.jvmsoot
import java.io._
-import it.unich.jandom.domains.AbstractProperty
+import scala.collection.JavaConverters._
+
import it.unich.jandom.targets.Annotation
import it.unich.jandom.targets.Environment
import it.unich.jandom.targets.cfg.ControlFlowGraph
@@ -40,14 +41,12 @@ import soot.toolkits.graph.PseudoTopologicalOrderer
* @author Francesca Scozzari
*/
abstract class SootCFG[Tgt <: SootCFG[Tgt, Node], Node <: Block](val method: SootMethod) extends ControlFlowGraph[Tgt, Node] {
- import scala.collection.JavaConversions._
-
type DomainBase = SootFrameDomain
val body: Body
// local variables of the method.
- def locals = body.getLocals().toIndexedSeq
+ def locals = body.getLocals().asScala.toIndexedSeq
// These are lazy values since body is not initialized when they are executed
@@ -59,7 +58,7 @@ abstract class SootCFG[Tgt <: SootCFG[Tgt, Node], Node <: Block](val method: Soo
// An ordering on nodes gives by a pseudo-topological orderer
lazy val ordering = new Ordering[Node] {
- val order = new PseudoTopologicalOrderer[Node].newList(graph, false).zipWithIndex.toMap
+ val order = new PseudoTopologicalOrderer[Node].newList(graph, false).asScala.zipWithIndex.toMap
def compare(x: Node, y: Node) = order(x) - order(y)
}
@@ -121,7 +120,7 @@ abstract class SootCFG[Tgt <: SootCFG[Tgt, Node], Node <: Block](val method: Soo
* It expands the input property adding new variables until exhausting locals.
*/
protected def expandPropertyWithLocalVariables(params: Parameters)(input: params.Property): params.Property = {
- body.getLocals.foldLeft(input) { (current, local) => current.evalUnknown(local.getType()) }
+ body.getLocals.asScala.foldLeft(input) { (current, local) => current.evalUnknown(local.getType()) }
}
/**
@@ -147,7 +146,7 @@ abstract class SootCFG[Tgt <: SootCFG[Tgt, Node], Node <: Block](val method: Soo
if (params.io) {
expandPropertyWithLocalVariables(params)(params.domain.top(inputTypes))
} else {
- params.domain.top(method.getActiveBody.getLocals.toSeq map { (l) => l.getType })
+ params.domain.top(method.getActiveBody.getLocals.asScala.toSeq map { (l) => l.getType })
}
}
@@ -235,7 +234,6 @@ object SootCFG {
* - type of return value (only if the return type is not void)
*/
def outputTypes(method: SootMethod) = {
- import scala.collection.JavaConversions._
val returnTypes =
if (method.getReturnType() == VoidType.v())
Seq()
@@ -251,13 +249,12 @@ object SootCFG {
* - types of parameters @parameter0, @parameter1, ...
*/
def inputTypes(method: SootMethod) = {
- import scala.collection.JavaConversions._
val thisType =
if (method.isStatic())
Seq()
else
Seq(method.getDeclaringClass().getType())
- val parameterTypes = method.getParameterTypes().toSeq.asInstanceOf[Seq[Type]]
+ val parameterTypes = method.getParameterTypes().asScala
thisType ++ parameterTypes
}
}
diff --git a/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootFrameDomain.scala b/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootFrameDomain.scala
index 19820c7c..fa8485a7 100644
--- a/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootFrameDomain.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootFrameDomain.scala
@@ -19,8 +19,6 @@
package it.unich.jandom.targets.jvmsoot
import it.unich.jandom.targets.NumericCondition
-import it.unich.jandom.domains.AbstractDomain
-import it.unich.jandom.domains.AbstractProperty
import it.unich.jandom.domains.CartesianFiberedProperty
import it.unich.jandom.domains.CartesianFiberedDomain
diff --git a/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootFrameObjectDomain.scala b/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootFrameObjectDomain.scala
index 1f4d33d8..0c9c74b1 100644
--- a/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootFrameObjectDomain.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootFrameObjectDomain.scala
@@ -66,12 +66,7 @@ class SootFrameObjectDomain(val dom: ObjectDomain[SootObjectModel]) extends Soot
invariantCheck
- /**
- * Returns the SootClass of a given frame variable
- */
- private def classOfVar(i: Int): SootClass = stack(size - i - 1).asInstanceOf[RefType].getSootClass()
-
- /**
+ /**
* Remove the top frame variable.
*/
private def delUntrackedVariable = Property(prop.delVariable(size - 1), stack.tail, globals)
diff --git a/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootInterpretation.scala b/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootInterpretation.scala
index 9edaef43..430d3adb 100644
--- a/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootInterpretation.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootInterpretation.scala
@@ -18,6 +18,8 @@
package it.unich.jandom.targets.jvmsoot
+import scala.collection.JavaConverters._
+
import it.unich.jandom.targets._
import soot.SootMethod
@@ -86,8 +88,6 @@ class JimpleInterpretation[Params <: Parameters[JimpleMethod]](val params: Param
* with a work-list based approach. Each method has a single possible input context, which is top.
*/
class JimpleRecursiveInterpretation[Params <: Parameters[JimpleMethod]](scene: Scene, val params: Params) extends Interpretation[JimpleMethod, Params] {
- import scala.collection.JavaConversions._
-
val inte = scala.collection.mutable.HashMap[SootMethod, params.Property]()
val targets = scala.collection.mutable.HashMap[SootMethod, Option[JimpleMethod]]()
@@ -110,8 +110,8 @@ class JimpleRecursiveInterpretation[Params <: Parameters[JimpleMethod]](scene: S
val tpo = new TopologicalOrderer(cg)
tpo.go()
- val order = tpo.order().reverse // it is enough to get the set of all the elements
- if (order.isEmpty()) order.add(method)
+ val order = tpo.order().asScala.reverse // it is enough to get the set of all the elements
+ if (order.isEmpty) order += method
for (m <- order; if !(targets contains m)) {
targets(m) = if (m.isConcrete()) Some(new JimpleMethod(m)) else None
@@ -133,7 +133,7 @@ class JimpleRecursiveInterpretation[Params <: Parameters[JimpleMethod]](scene: S
if (!(inte(m) >= output)) {
inte(m) = inte(m) widening output
val sources = new Sources(cg.edgesInto(m)).asInstanceOf[java.util.Iterator[SootMethod]]
- worklist.enqueue(sources.toSeq: _*)
+ worklist.enqueue(sources.asScala.toSeq: _*)
}
}
}
diff --git a/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootObjectModel.scala b/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootObjectModel.scala
index 660937cb..bf41964f 100644
--- a/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootObjectModel.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/jvmsoot/SootObjectModel.scala
@@ -18,6 +18,8 @@
package it.unich.jandom.targets.jvmsoot
+import scala.collection.JavaConverters._
+
import it.unich.jandom.objectmodels.ObjectModel
import it.unich.jandom.objectmodels.ObjectModelHelper
@@ -31,7 +33,6 @@ import soot.jandom.MyFastHierarchy
*/
class SootObjectModel(scene: soot.Scene) extends ObjectModel with ObjectModelHelper {
- import scala.collection.JavaConversions._
type Type = soot.Type
@@ -50,7 +51,7 @@ class SootObjectModel(scene: soot.Scene) extends ObjectModel with ObjectModelHel
}
def declaredFields(t: Type) = t match {
- case t: RefType => t.getSootClass().getFields().toSet
+ case t: RefType => t.getSootClass().getFields().asScala.toSet
case _: PrimType => Set()
case _: ArrayType => Set()
case _: NullType => Set()
@@ -91,7 +92,7 @@ class SootObjectModel(scene: soot.Scene) extends ObjectModel with ObjectModelHel
case t: RefType =>
val k = t.getSootClass()
val ifs: Set[Type] = (for {
- i <- k.getInterfaces()
+ i <- k.getInterfaces().asScala
} yield i.getType())(collection.breakOut)
if (k.hasSuperclass())
ifs + k.getSuperclass().getType()
@@ -106,10 +107,10 @@ class SootObjectModel(scene: soot.Scene) extends ObjectModel with ObjectModelHel
case t: RefType =>
val k = t.getSootClass()
if (k.isInterface()) {
- (fh.getAllImplementersOfInterface(k) map { _.getType() }).toSet ++
- (fh.getSubinterfaces(k) map { _.getType() }).toSet
+ (fh.getAllImplementersOfInterface(k).asScala map { _.getType() }).toSet ++
+ (fh.getSubinterfaces(k).asScala map { _.getType() }).toSet
} else {
- (fh.getSubclassesOf(k) map { _.getType() }).toSet
+ (fh.getSubclassesOf(k).asScala map { _.getType() }).toSet
}
case _: PrimType => Set()
case t: ArrayType => children(t.baseType) map { (ArrayType.v(_, t.numDimensions)) }
diff --git a/core/src/main/scala/it/unich/jandom/targets/lts/LTS.scala b/core/src/main/scala/it/unich/jandom/targets/lts/LTS.scala
index c7046072..c2b9bd75 100644
--- a/core/src/main/scala/it/unich/jandom/targets/lts/LTS.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/lts/LTS.scala
@@ -103,11 +103,14 @@ case class LTS(val name: String, val locations: IndexedSeq[Location], val transi
val builder = new StringBuilder()
builder ++= "digraph {\n"
- val initState = regions find { _.name == "init" } flatMap { _.state }
+ val initState = regions find (_.name == "init") flatMap (_.state)
if (initState.isDefined)
- builder ++= s""" "${StringEscapeUtils.escapeJava(initState.get.name)}" [shape=doublecircle]\n"""
+ builder ++= s""" "${initState.get.id}" [shape=doublecircle]\n"""
+ for (l <- locations) {
+ builder ++= s""" "${l.id}" [label="${StringEscapeUtils.escapeJava(l.name)}"]\n"""
+ }
for (t <- transitions) {
- builder ++= s""" "${StringEscapeUtils.escapeJava(t.start.name)}" -> "${ StringEscapeUtils.escapeJava(t.end.name)}" [label="${StringEscapeUtils.escapeJava(t.name)}"]\n"""
+ builder ++= s""" "${t.start.id}" -> "${t.end.id}" [label="${StringEscapeUtils.escapeJava(t.name)}"]\n"""
}
builder ++= "}\n"
builder.toString
@@ -116,7 +119,7 @@ case class LTS(val name: String, val locations: IndexedSeq[Location], val transi
/**
* Converts an LTS into an equation system, given a numerical domain.
*/
- def toEQS(dom: NumericalDomain): GraphEquationSystem[Location, dom.Property, Either[Transition, Location]] = {
+ override def toEQS(dom: NumericalDomain): GraphEquationSystem[Location, dom.Property, Either[Transition, Location]] = {
type Edge = Either[Transition, Location]
implicit val scalafixDomain = dom.ScalaFixDomain
@@ -136,7 +139,6 @@ case class LTS(val name: String, val locations: IndexedSeq[Location], val transi
}
}, locations)
}
- val edges: Set[Edge] = ((transitions map { Left(_) }) ++ (inputlocs map { Right(_) })).toSet
GraphEquationSystem[Location, dom.Property, Edge](
unknowns = locations,
inputUnknowns = inputlocs.toSet,
@@ -194,21 +196,29 @@ case class LTS(val name: String, val locations: IndexedSeq[Location], val transi
var next = initial
var current = initial
+ params.log("Beginning ascending chain\n")
do {
current = next
next = for ((loc, w) <- locations zip widenings) yield {
val propnew = for (t <- loc.incoming) yield t.analyze(current(t.start.id))
- val unionednew = propnew.fold(empty)(_ union _)
- if (w.isEmpty) unionednew else w.get(current(loc.id), unionednew)
+ val unionednew = propnew.fold(initial(loc.id))(_ union _)
+ params.log(s"Node: ${loc.name} Oldvalue: ${current(loc.id).mkString(env.variables)} Newinput: ${unionednew.mkString(env.variables)}")
+ val newvalue = if (w.isEmpty) unionednew else w.get(current(loc.id), unionednew)
+ params.log(s" Newvalue: ${newvalue.mkString(env.variables)}\n")
+ newvalue
}
} while (current != next)
+ params.log("Beginning descending chain\n")
do {
current = next
next = for ((loc, n) <- locations zip narrowings) yield {
val propnew = for (t <- loc.incoming) yield t.analyze(current(t.start.id))
- val unionednew = current(loc.id) intersection (propnew.fold(empty)(_ union _) union initial(loc.id))
- if (n.isEmpty) unionednew else n.get(current(loc.id), unionednew)
+ val unionednew = propnew.fold(initial(loc.id))(_ union _)
+ params.log(s"Node: ${loc.name} Oldvalue: ${current(loc.id).mkString(env.variables)} Newinput: ${unionednew.mkString(env.variables)}")
+ val newvalue = if (n.isEmpty) unionednew else n.get(current(loc.id), unionednew)
+ params.log(s" Newvalue: ${newvalue.mkString(env.variables)}\n")
+ newvalue
}
} while (current != next)
locations.foreach { loc => ann(loc) = current(loc.id) }
@@ -224,29 +234,28 @@ case class LTS(val name: String, val locations: IndexedSeq[Location], val transi
val loc = locations(locid)
val w = widenings(locid)
val propnew = for (t <- loc.incoming) yield t.analyze(current(t.start.id))
- val unionednew = propnew.fold(empty)(_ union _)
+ val unionednew = propnew.fold(initial(locid))(_ union _)
params.log(s"Node: ${loc.name} Oldvalue: ${current(loc.id).mkString(env.variables)} Newinput: ${unionednew.mkString(env.variables)}")
val newvalue = if (w.isEmpty) unionednew else w.get(current(locid), unionednew)
params.log(s" Newvalue: ${newvalue.mkString(env.variables)}\n")
- if (newvalue > current(locid)) {
+ if (newvalue != current(locid)) {
current(locid) = newvalue
for (t <- loc.outgoing) { if (!workList.contains(t.end.id)) workList.enqueue(t.end.id) }
}
}
params.log("Beginning descending chain\n")
-
workList ++= 0 until numlocs
while (!workList.isEmpty) {
val locid = workList.dequeue()
val loc = locations(locid)
val n = narrowings(locid)
val propnew = for (t <- loc.incoming) yield t.analyze(current(t.start.id))
- val unionednew = current(locid) intersection (propnew.fold(empty)(_ union _) union initial(locid))
+ val unionednew = propnew.fold(initial(locid))(_ union _)
params.log(s"Node: ${loc.name} Oldvalue: ${current(loc.id).mkString(env.variables)} Newinput: ${unionednew.mkString(env.variables)}")
val newvalue = if (n.isEmpty) unionednew else n.get(current(locid), unionednew)
params.log(s" Newvalue: ${newvalue.mkString(env.variables)}\n")
- if (newvalue < current(locid)) {
+ if (newvalue != current(locid)) {
current(locid) = newvalue
for (t <- loc.outgoing) { if (!workList.contains(t.end.id)) workList.enqueue(t.end.id) }
}
diff --git a/core/src/main/scala/it/unich/jandom/targets/lts/Transition.scala b/core/src/main/scala/it/unich/jandom/targets/lts/Transition.scala
index ea8e1dda..420deadc 100644
--- a/core/src/main/scala/it/unich/jandom/targets/lts/Transition.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/lts/Transition.scala
@@ -19,9 +19,7 @@
package it.unich.jandom.targets.lts
import it.unich.jandom.domains.numerical.NumericalProperty
-import it.unich.jandom.targets.NumericAssignment
import it.unich.jandom.targets.NumericCondition
-import it.unich.jandom.targets.NumericAssignment
import it.unich.jandom.targets.NumericAssignmentMultiple
/**
diff --git a/core/src/main/scala/it/unich/jandom/targets/parameters/NarrowingSpecs.scala b/core/src/main/scala/it/unich/jandom/targets/parameters/NarrowingSpecs.scala
index 80aeeed7..b18a3b86 100644
--- a/core/src/main/scala/it/unich/jandom/targets/parameters/NarrowingSpecs.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/parameters/NarrowingSpecs.scala
@@ -1,5 +1,5 @@
/**
- * Copyright 2016 Gianluca Amato
+ * Copyright 2016, 2017 Gianluca Amato
*
* This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
* JANDOM is free software: you can redistribute it and/or modify
@@ -18,12 +18,15 @@
package it.unich.jandom.targets.parameters
+import scala.language.implicitConversions
+
import it.unich.jandom.domains.AbstractDomain
import it.unich.scalafix.Box
/**
* This object contains the NarrowingSpec class and its subclasses. They are used
- * to specify which kind of narrowing to use for the analyses.
+ * to specify which kind of narrowing to use for the analyses, in a way which is indepedent
+ * from abstract domains and targets.
* @author Gianluca Amato
*/
object NarrowingSpecs {
@@ -56,9 +59,9 @@ object NarrowingSpecs {
/**
* This always returns its right argument. Therefore, this is not formally a
- * real widening since it may lead to non-terminating computations.
+ * real narrowing since it may lead to non-terminating computations.
*/
- case object LowerBoundNarrowing extends NarrowingSpec {
+ case object RightNarrowing extends NarrowingSpec {
def get(dom: AbstractDomain) = Box.right[dom.Property]
}
@@ -68,4 +71,15 @@ object NarrowingSpecs {
case class DelayedNarrowing(base: NarrowingSpec, d: Int) extends NarrowingSpec {
def get(dom: AbstractDomain) = base.get(dom).delayed(d)
}
+
+ /**
+ * This specified a narrowing given its name
+ */
+ case class NamedNarrowing(name: String) extends NarrowingSpec {
+ def get(dom: AbstractDomain) = dom.narrowing(name)
+
+ }
+
+ implicit def stringToNameNarrowing(name: String): NarrowingSpec = NamedNarrowing(name)
+
}
diff --git a/core/src/main/scala/it/unich/jandom/targets/parameters/WideningSpecs.scala b/core/src/main/scala/it/unich/jandom/targets/parameters/WideningSpecs.scala
index d09a5de3..bfbec81b 100644
--- a/core/src/main/scala/it/unich/jandom/targets/parameters/WideningSpecs.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/parameters/WideningSpecs.scala
@@ -1,5 +1,5 @@
/**
- * Copyright 2016 Gianluca Amato
+ * Copyright 2016, 2017 Gianluca Amato
*
* This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
* JANDOM is free software: you can redistribute it and/or modify
@@ -25,7 +25,8 @@ import it.unich.scalafix.Box
/**
* This object contains the WideningSpec class and its subclasses. They are used
- * to specify which kind of widening to use for the analyses.
+ * to specify which kind of widening to use for the analyses, in a way which is indepedent
+ * from abstract domains and targets.
* @author Gianluca Amato
*/
object WideningSpecs {
diff --git a/core/src/main/scala/it/unich/jandom/targets/slil/AssignStmt.scala b/core/src/main/scala/it/unich/jandom/targets/slil/AssignStmt.scala
index a9239f36..b3018753 100644
--- a/core/src/main/scala/it/unich/jandom/targets/slil/AssignStmt.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/slil/AssignStmt.scala
@@ -19,7 +19,6 @@
package it.unich.jandom.targets.slil
import it.unich.jandom.domains.numerical.NumericalProperty
-import it.unich.jandom.domains.numerical.LinearForm
import it.unich.jandom.targets.Annotation
import AnalysisPhase.AnalysisPhase
import it.unich.jandom.targets.NumericExpression
diff --git a/core/src/main/scala/it/unich/jandom/targets/slil/IfStmt.scala b/core/src/main/scala/it/unich/jandom/targets/slil/IfStmt.scala
index 9de434dd..1b481daf 100644
--- a/core/src/main/scala/it/unich/jandom/targets/slil/IfStmt.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/slil/IfStmt.scala
@@ -43,7 +43,6 @@ case class IfStmt(condition: NumericCondition, then_branch: SLILStmt, else_branc
override def mkString[U <: NumericalProperty[_]](ann: Annotation[ProgramPoint,U], ppspec: SLILPrinterSpec, row: Int, level: Int): String = {
val spaces = ppspec.indent(level)
- val innerspaces = ppspec.indent(level+1)
val then_string = then_branch.mkString(ann, ppspec, row + 1, level + 1)
val else_string = else_branch.mkString(ann, ppspec, row + 2 + then_string.count(_ == '\n'), level + 1)
val s = spaces + "if (" + condition.mkString(ppspec.env.names) + ") {\n" +
diff --git a/core/src/main/scala/it/unich/jandom/targets/slil/SLILProgram.scala b/core/src/main/scala/it/unich/jandom/targets/slil/SLILProgram.scala
index badabab9..64c2a8e1 100644
--- a/core/src/main/scala/it/unich/jandom/targets/slil/SLILProgram.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/slil/SLILProgram.scala
@@ -36,7 +36,6 @@ import it.unich.jandom.targets.slil.AnalysisPhase._
case class SLILProgram(val env: Environment, val inputVars: Seq[Int], val stmt: SLILStmt) extends SLILTarget {
def mkString[U <: NumericalProperty[_]](ann: Annotation[ProgramPoint,U], ppspec: SLILPrinterSpec = SLILPrinterSpecInline(env)) = {
val spaces = ppspec.indent(0)
- val innerspaces = ppspec.indent(1)
spaces + "function (" + (inputVars map { v: Int => env(v) }).mkString(",") + ") {\n" +
stmt.mkString(ann, ppspec, 1, 1) +
spaces + "}\n"
@@ -45,7 +44,7 @@ case class SLILProgram(val env: Environment, val inputVars: Seq[Int], val stmt:
override def analyze(params: Parameters): Annotation[ProgramPoint,params.Property] = {
val input = params.domain.top(env.size)
val ann = getAnnotation[params.Property]
- val output = params.narrowingStrategy match {
+ params.narrowingStrategy match {
case NarrowingStrategy.Separate =>
stmt.analyzeStmt(params)(input, Ascending, ann)
stmt.analyzeStmt(params)(input, Descending, ann)
diff --git a/core/src/main/scala/it/unich/jandom/targets/slil/WhileStmt.scala b/core/src/main/scala/it/unich/jandom/targets/slil/WhileStmt.scala
index f77cc434..2fc42e8a 100644
--- a/core/src/main/scala/it/unich/jandom/targets/slil/WhileStmt.scala
+++ b/core/src/main/scala/it/unich/jandom/targets/slil/WhileStmt.scala
@@ -43,7 +43,6 @@ case class WhileStmt(condition: NumericCondition, body: SLILStmt) extends SLILSt
var lastBodyResult: NumericalProperty[_] = null
override def analyzeStmt(params: Parameters)(input: params.Property, phase: AnalysisPhase, ann: Annotation[ProgramPoint, params.Property]): params.Property = {
-
import WideningScope._
import NarrowingStrategy._
@@ -51,8 +50,8 @@ case class WhileStmt(condition: NumericCondition, body: SLILStmt) extends SLILSt
params.nestingLevel += 1
// Determines widening/narrowing operators to use
- val widening = params.widening((this, 1))
- val narrowing = params.narrowing((this, 1))
+ val widening = params.widening((this,1))
+ val narrowing = params.narrowing((this,1))
// Determines initial values for the analysis, depending on the calling phase
var (bodyResult, invariant) =
@@ -116,6 +115,7 @@ case class WhileStmt(condition: NumericCondition, body: SLILStmt) extends SLILSt
currentPhase = Descending
}
+
if (currentPhase == Descending) {
// Debug
params.log("Beginning Descending Chain\n")
@@ -144,7 +144,6 @@ case class WhileStmt(condition: NumericCondition, body: SLILStmt) extends SLILSt
params.log(s"Final descending invariant: $newinvariant\n")
}
-
// Save current values for later iterations of the loop
lastInvariant = invariant
lastBodyResult = bodyResult
diff --git a/core/src/main/scala/it/unich/jandom/ui/NumericalDomains.scala b/core/src/main/scala/it/unich/jandom/ui/NumericalDomains.scala
index bddabe55..c9e1b79c 100644
--- a/core/src/main/scala/it/unich/jandom/ui/NumericalDomains.scala
+++ b/core/src/main/scala/it/unich/jandom/ui/NumericalDomains.scala
@@ -26,15 +26,22 @@ import it.unipd.jandom.domains.numerical.parity.ParityDomain
import it.unipd.jandom.domains.numerical.constant.ConstantDomain
import it.unipd.jandom.domains.numerical.mod.ModKDomain
import it.unipd.jandom.domains.numerical.sign.{ESeqDomain, ExtendedSigns01Domain, SignDomain}
+import it.unipd.jandom.domains.numerical.box.BoxDomain
+import it.unipd.jandom.domains.numerical.box.BoundedBoxDomain
+import it.unipd.jandom.domains.IntNumber
/**
* The ParameterEnumeration for numerical domains.
*/
+
+
object NumericalDomains extends ParameterEnumeration[NumericalDomain] {
val name = "Domain"
val description = "The numerical domain to use for the analysis."
val values: Buffer[ParameterValue[NumericalDomain]] = Buffer(
+ ParameterValue(BoundedBoxDomain(IntNumber(0),IntNumber(0)), "Bounded Box", "This is a native Scala implementation of the Bounded Box (that is Interval) integer domain. You must provide lower and upper bound which bound the interval analysis."),
+ ParameterValue(BoxDomain(), "Box (Interval) Domain", "This is a native Scala implementation of the Box (that is Interval) integer domain"),
ParameterValue(SignDomain(), "Sign Domain", "This is a native Scala implementation of the simple sign domain " +
"(<0, =0, >0)"),
ParameterValue(ParityDomain(), "Parity Domain", "This is a native Scala implementation of even/odd domain."),
@@ -58,13 +65,20 @@ object NumericalDomains extends ParameterEnumeration[NumericalDomain] {
ParameterValue(SumSignModKDomain(2), "Sign + Parity", "Sum of signs and parity domains."),
ParameterValue(BoxDoubleDomain(overReals=true), "BoxDouble over Reals", "This is a native Scala implementation of boxes. It is safe " +
"w.r.t. reals."),
- ParameterValue(ParallelotopeDomain(), "Parallelotope", "This is a native Scala implementation of parallelotopes. It is " +
- "not safe and should not be used."),
- ParameterValue(SumIntParallelotopeDomain(), "BoxDouble + Parallelotope", "Sum of boxes and parallelotopes."),
- ParameterValue(ParallelotopeRationalDomain(), "Parallelotope over Rationals", "This is a native Scala implementation of parallelotopes using rational numbers.")
+ ParameterValue(ParallelotopeRationalDomain(), "Parallelotope over Rationals", "This is a native Scala implementation of parallelotopes using rational numbers."),
+ ParameterValue(SumBoxDoubleParallelotopeRationDomain(), "BoxDouble + ParallelotopeRational", "Sum of boxes and parallelotopes.")
)
val default = values.last
+ def setBound(m: Int,n: Int) = {
+ for (d <- values) {
+ if (d.value.isInstanceOf[BoundedBoxDomain]) {
+ // println("te chiamo qui" + m + " - " + n)
+ d.value.updateData(m,n)
+ }
+ }
+ }
+
// Load objects PPLUIInitializer and PPLMacroUIInitializer if available
Try ( Class.forName ("it.unich.jandom.ui.PPLUIInitializer$") )
Try ( Class.forName ("it.unich.jandom.ui.PPLMacroUIInitializer$") )
diff --git a/core/src/main/scala/it/unich/jandom/ui/OutputInterface.scala b/core/src/main/scala/it/unich/jandom/ui/OutputInterface.scala
index a4d7cb33..5b31d308 100644
--- a/core/src/main/scala/it/unich/jandom/ui/OutputInterface.scala
+++ b/core/src/main/scala/it/unich/jandom/ui/OutputInterface.scala
@@ -23,13 +23,11 @@ import java.io.IOException
import java.nio.file._
import java.nio.file.attribute.BasicFileAttributes
-import scala.collection.JavaConversions._
+import scala.collection.JavaConverters._
import scala.util.Try
-
import org.objectweb.asm.ClassReader
import org.objectweb.asm.tree.ClassNode
import org.objectweb.asm.tree.MethodNode
-
import it.unich.jandom.domains.numerical.NumericalDomain
import it.unich.jandom.domains.objects.ObjectDomainFactory
import it.unich.jandom.targets.parameters.WideningSpecs._
@@ -43,7 +41,6 @@ import it.unich.jandom.targets.lts._
import it.unich.jandom.targets.slil._
import soot.Scene
import soot.toolkits.graph.Block
-import it.unich.scalafix.Box
/**
* An output interface is a collection of methods for implementing an external interface.
@@ -183,7 +180,7 @@ object OutputInterface {
def getMethods(dir: Path, klassIndex: Int) = {
val scene = getScene(dir)
val sootKlass = scene.loadClassAndSupport(getClasses(dir)(klassIndex))
- sootKlass.getMethods().map(x => x.getName())
+ sootKlass.getMethods().asScala.map(x => x.getName())
}
private def getSootMethods(dir: Path, klassIndex: Int) = {
@@ -235,7 +232,7 @@ object OutputInterface {
}
def getASMMethods(dir: String, klassName: String) = {
- getASMMethodsList(dir, klassName) map { _.name }
+ getASMMethodsList(dir, klassName).asScala map { _.name }
}
def analyzeASM(dir: String, klassName: String, methodIndex: Int, domain: Int, wideningIndex: Int,
@@ -317,7 +314,7 @@ private class ClassFileVisitor(rootPath: Path) extends SimpleFileVisitor[Path] {
private val privateClassNamesList = scala.collection.mutable.SortedSet[String]()
def classNameList = privateClassNamesList.toSeq
override def visitFile(aFile: Path, aAttrs: BasicFileAttributes): FileVisitResult = {
- val relativePath = rootPath.relativize(aFile)
+ val relativePath = rootPath.relativize(aFile).asScala
val className = (relativePath.head.toString /: relativePath.tail)(_ + "." + _.toString)
if (className endsWith ".class")
privateClassNamesList += className stripSuffix ".class"
diff --git a/core/src/main/scala/it/unich/jandom/ui/cli/Conf.scala b/core/src/main/scala/it/unich/jandom/ui/cli/Conf.scala
index 31a66762..1d530325 100644
--- a/core/src/main/scala/it/unich/jandom/ui/cli/Conf.scala
+++ b/core/src/main/scala/it/unich/jandom/ui/cli/Conf.scala
@@ -34,4 +34,5 @@ class Conf(arguments: Seq[String]) extends ScallopConf(arguments) {
val wideningScope = opt[WideningScope.Value]("widening", default = Some(WideningScopes.default.value))(enumConverter(WideningScope))
val narrowingStrategy = opt[NarrowingStrategy.Value]("narrowing", default = Some(NarrowingStrategies.default.value))(enumConverter(NarrowingStrategy))
val file = opt[String]("input", required = true)
+ verify()
}
diff --git a/core/src/main/scala/it/unich/jandom/ui/gui/ASMEditorPane.scala b/core/src/main/scala/it/unich/jandom/ui/gui/ASMEditorPane.scala
index 16c95dbb..264f916d 100644
--- a/core/src/main/scala/it/unich/jandom/ui/gui/ASMEditorPane.scala
+++ b/core/src/main/scala/it/unich/jandom/ui/gui/ASMEditorPane.scala
@@ -18,6 +18,7 @@
package it.unich.jandom.ui.gui
+import scala.collection.JavaConverters._
import java.awt.event.{ InputEvent, KeyEvent }
import java.io.{ File, FileInputStream }
import scala.swing.{Action, BorderPanel, BoxPanel, ComboBox, EditorPane, FileChooser, Label, MenuItem, Orientation, ScrollPane}
@@ -77,8 +78,6 @@ class ASMEditorPane(val frame: MainFrame) extends BorderPanel with TargetPane {
val openAction = new Action("Open...") {
accelerator = Some(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_MASK))
def apply() {
- import scala.collection.JavaConversions._
-
val returnVal = fileChooser.showOpenDialog(ASMEditorPane.this)
if (returnVal != FileChooser.Result.Approve) return ;
val file = fileChooser.selectedFile
@@ -86,7 +85,7 @@ class ASMEditorPane(val frame: MainFrame) extends BorderPanel with TargetPane {
val cr = new ClassReader(is)
val node = new ClassNode()
cr.accept(node, ClassReader.SKIP_DEBUG)
- methodList = node.methods.asInstanceOf[java.util.List[MethodNode]]
+ methodList = node.methods.asScala
methodComboBox = new ComboBox(methodList map { _.name })
methodComboBox.peer.setAction(methodSelectAction.peer)
methodSelector.contents(1) = methodComboBox
diff --git a/core/src/main/scala/it/unich/jandom/ui/gui/ParametersPane.scala b/core/src/main/scala/it/unich/jandom/ui/gui/ParametersPane.scala
index 5fe8a9d4..c63d5308 100644
--- a/core/src/main/scala/it/unich/jandom/ui/gui/ParametersPane.scala
+++ b/core/src/main/scala/it/unich/jandom/ui/gui/ParametersPane.scala
@@ -30,7 +30,6 @@ import it.unich.jandom.targets.parameters.WideningSpecs._
import it.unich.jandom.targets.parameters.NarrowingSpecs._
import javax.swing.JSpinner
import javax.swing.SpinnerNumberModel
-import it.unich.scalafix.Box
class ParametersPane extends GridBagPanel {
border = Swing.EmptyBorder(5, 5, 5, 5)
@@ -39,6 +38,10 @@ class ParametersPane extends GridBagPanel {
val wideningComboBox = addParameterEnumeration(2, WideningScopes)
val narrowingComboBox = addParameterEnumeration(3, NarrowingStrategies)
val delayModel = new SpinnerNumberModel(0, 0, Double.PositiveInfinity, 1)
+ val parameter_m_model = new SpinnerNumberModel(0, Double.NegativeInfinity, Double.PositiveInfinity, 1)
+ val parameter_n_model = new SpinnerNumberModel(0, Double.NegativeInfinity, Double.PositiveInfinity, 1)
+ val parameter_m = Component.wrap(new JSpinner(parameter_m_model))
+ val parameter_n = Component.wrap(new JSpinner(parameter_n_model))
val delay = Component.wrap(new JSpinner(delayModel))
val debug = new CheckBox("Debug")
@@ -46,19 +49,31 @@ class ParametersPane extends GridBagPanel {
GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0)
layout(delay) = new Constraints(1, 4, 1, 1, 0.0, 0.0, GridBagConstraints.WEST,
GridBagConstraints.HORIZONTAL, new Insets(0, 0, 5, 0), 0, 0)
- layout(debug) = new Constraints(0, 5, 2, 1, 0.0, 0.0, GridBagConstraints.BASELINE,
+
+ layout(new Label("Lower bound M:")) = new Constraints(0, 5, 1, 1, 0.0, 0.0, GridBagConstraints.EAST,
+ GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0)
+ layout(parameter_m) = new Constraints(1, 5, 2, 1, 0.0, 0.0, GridBagConstraints.WEST,
+ GridBagConstraints.HORIZONTAL, new Insets(0, 0, 5, 0), 0, 0)
+
+ layout(new Label("Upper bound N:")) = new Constraints(0, 6, 1, 1, 0.0, 0.0, GridBagConstraints.EAST,
+ GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0)
+ layout(parameter_n) = new Constraints(1, 6, 3, 1, 0.0, 0.0, GridBagConstraints.WEST,
+ GridBagConstraints.HORIZONTAL, new Insets(0, 0, 5, 0), 0, 0)
+
+ layout(debug) = new Constraints(0, 7, 2, 1, 0.0, 0.0, GridBagConstraints.BASELINE,
GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)
- layout(Swing.VGlue) = new Constraints(0, 6, 2, 1, 0.0, 1.0, GridBagConstraints.BASELINE,
+ layout(Swing.VGlue) = new Constraints(0, 7, 4, 1, 0.0, 1.0, GridBagConstraints.BASELINE,
GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)
object ParameterRenderer extends Renderer[ParameterValue[_]] {
- val r = implicitly[Renderer[String]]
- def componentFor(list: ListView[_], isSelected: Boolean,
+ private val r = implicitly[Renderer[String]]
+ def componentFor(list: ListView[_ <: ParameterValue[_]], isSelected: Boolean,
focused: Boolean, a: ParameterValue[_], index: Int): Component =
{
- val c = r.componentFor(list, isSelected, focused, a.name, index)
+ // The asInstanceOf in the line below is a bad trick... it works for now.
+ val c = r.componentFor(list.asInstanceOf[ListView[String]], isSelected, focused, a.name, index)
c.tooltip = a.description
- return c
+ c
}
}
@@ -77,17 +92,23 @@ class ParametersPane extends GridBagPanel {
comboBox
}
- def selectedNumericalDomain = NumericalDomains.values(numericalDomainComboBox.selection.index).value
-
- def selectedObjectDomain = ObjectDomains.values(objectDomainComboBox.selection.index).value
-
def setParameters[T <: Target[T]](params: Parameters[T]) {
params.wideningScope = WideningScopes.values(wideningComboBox.selection.index).value
params.narrowingStrategy = NarrowingStrategies.values(narrowingComboBox.selection.index).value
val delay = delayModel.getValue().asInstanceOf[Double].toInt
+ val bound_m = parameter_m_model.getValue().asInstanceOf[Double].toInt
+ val bound_n = parameter_n_model.getValue.asInstanceOf[Double].toInt
+ // print("Bound from graphics ",bound_m,bound_n)
+ NumericalDomains.setBound(bound_m, bound_n)
params.widening = DelayedWidening(DefaultWidening, delay)
params.narrowing = DelayedNarrowing(TrivialNarrowing, 2)
if (debug.selected) params.debugWriter = new java.io.StringWriter
}
+ def selectedNumericalDomain = NumericalDomains.values(numericalDomainComboBox.selection.index).value
+
+ def selectedObjectDomain = ObjectDomains.values(objectDomainComboBox.selection.index).value
+
+
+
}
diff --git a/core/src/main/scala/it/unich/jandom/ui/gui/SootEditorPane.scala b/core/src/main/scala/it/unich/jandom/ui/gui/SootEditorPane.scala
index 6841f0b0..53983419 100644
--- a/core/src/main/scala/it/unich/jandom/ui/gui/SootEditorPane.scala
+++ b/core/src/main/scala/it/unich/jandom/ui/gui/SootEditorPane.scala
@@ -24,7 +24,7 @@ import java.io.File
import java.nio.file._
import java.nio.file.attribute.BasicFileAttributes
-import scala.collection.JavaConversions._
+import scala.collection.JavaConverters._
import scala.swing._
import scala.swing.event.ActionEvent
import scala.swing.event.EditDone
@@ -144,9 +144,9 @@ class SootEditorPane(val frame: MainFrame) extends BorderPanel with TargetPane {
case SelectionChanged(`classComboBox`) =>
val klass = sootScene.loadClassAndSupport(classComboBox.selection.item)
- val methodList = klass.getMethods()
+ val methodList = klass.getMethods().asScala
// these two lines are a mess because Scala Swing does not play well with Java 1.7
- val comboModel = ComboBox.newConstantModel(methodList).asInstanceOf[javax.swing.ComboBoxModel[SootMethod]]
+ val comboModel = ComboBox.newConstantModel(methodList)
methodComboBox.peer.asInstanceOf[javax.swing.JComboBox[SootMethod]].setModel(comboModel)
publish(SelectionChanged(methodComboBox))
@@ -169,7 +169,7 @@ class SootEditorPane(val frame: MainFrame) extends BorderPanel with TargetPane {
private val privateClassNamesList = scala.collection.mutable.SortedSet[String]()
def classNameList = privateClassNamesList.toSeq
override def visitFile(aFile: Path, aAttrs: BasicFileAttributes): FileVisitResult = {
- val relativePath = rootPath.relativize(aFile)
+ val relativePath = rootPath.relativize(aFile).asScala
val className = (relativePath.head.toString /: relativePath.tail)(_ + "." + _.toString)
if (className endsWith ".class")
privateClassNamesList += className stripSuffix ".class"
diff --git a/core/src/main/scala/it/unich/jandom/utils/DisjointSetsImpl.scala b/core/src/main/scala/it/unich/jandom/utils/DisjointSetsImpl.scala
index 1931cd72..48995505 100644
--- a/core/src/main/scala/it/unich/jandom/utils/DisjointSetsImpl.scala
+++ b/core/src/main/scala/it/unich/jandom/utils/DisjointSetsImpl.scala
@@ -19,7 +19,6 @@
package it.unich.jandom.utils
import scala.collection.mutable.{ Map => MMap }
-import scala.collection.TraversableProxy
/**
* This class implements a disjoint-sets algorithm with
@@ -55,8 +54,6 @@ class DisjointSetsImpl[T](initialElements: Seq[T]) extends DisjointSets[T] {
def size = nodes.size
- private def self = nodes.values.toTraversable
-
/**
* Add a new single-node forest to the disjoint-set forests. It will
* be placed into its own set. It returns the new node.
diff --git a/core/src/main/scala/it/unich/jandom/utils/Relation.scala b/core/src/main/scala/it/unich/jandom/utils/Relation.scala
index fa4f939e..5c4c8829 100644
--- a/core/src/main/scala/it/unich/jandom/utils/Relation.scala
+++ b/core/src/main/scala/it/unich/jandom/utils/Relation.scala
@@ -101,7 +101,7 @@ object Relation {
* This is a trait which may be mixed in with a Relation to automatically derive
* compare and equality functions.
*/
- trait AutomaticPartialOrdering[U, V] {
+ trait AutomaticPartialOrdering[U, V] extends PartiallyOrdered[Relation[U,V]] {
original: Relation[U, V] =>
def tryCompareTo[B >: Relation[U, V]](that: B)(implicit arg0: (B) ⇒ PartiallyOrdered[B]): Option[Int] = {
diff --git a/core/src/main/scala/it/unich/jandom/utils/breeze/RationalForBreeze.scala b/core/src/main/scala/it/unich/jandom/utils/breeze/RationalForBreeze.scala
deleted file mode 100644
index 1035d2ef..00000000
--- a/core/src/main/scala/it/unich/jandom/utils/breeze/RationalForBreeze.scala
+++ /dev/null
@@ -1,174 +0,0 @@
-/**
- * Copyright 2016 Gianluca Amato
- *
- * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
- * JANDOM is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * JANDOM is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of a
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with JANDOM. If not, see .
- */
-
-package it.unich.jandom.utils.breeze
-
-import breeze.linalg._
-import breeze.linalg.operators._
-import breeze.linalg.support.CanTraverseValues
-import breeze.linalg.support.CanTraverseValues.ValuesVisitor
-import breeze.math.Field
-import breeze.storage.Zero
-import spire.math.Rational
-import spire.syntax.cfor._
-
-/**
- * This object contains the implicit type classes which are needed to make Rational
- * work with the Breeze library. This is just what is strictly necessary for implementing
- * the ParallelotopeRational domain, and might not work in a different context.
- */
-object RationalForBreeze {
-
- implicit object fieldRational extends Field[Rational] {
- def zero = Rational.zero
-
- def one = Rational.one
-
- def ==(a: Rational, b: Rational) = a == b
-
- def !=(a: Rational, b: Rational) = a != b
-
- def +(a: Rational, b: Rational) = a + b
-
- def -(a: Rational, b: Rational) = a - b
-
- def *(a: Rational, b: Rational) = a * b
-
- def /(a: Rational, b: Rational) = a / b
-
- def %(a: Rational, b: Rational) = Rational.zero
-
- def pow(a: Rational, b: Rational) = ???
-
- def >(a: Rational, b: Rational) = a > b
-
- def >=(a: Rational, b: Rational) = a >= b
-
- def <(a: Rational, b: Rational) = a < b
-
- def <=(a: Rational, b: Rational) = a <= b
-
- def abs(a: Rational) = a.abs
-
- implicit val normImpl: norm.Impl[Rational, Double] = new norm.Impl[Rational, Double] {
- def apply(v: Rational): Double = v.doubleValue()
- }
- }
-
- implicit object Rational_MulMM extends OpMulMatrix.Impl2[Rational, Rational, Rational] { def apply(a: Rational, b: Rational) = a * b }
-
- implicit object Rational_MulDM extends OpDiv.Impl2[Double, Rational, Rational] { def apply(a: Double, b: Rational) = Rational(a) * b }
-
- implicit object RationalIsZero extends Zero[Rational] {
- val zero = Rational.zero
- }
-
- implicit def dv_s_Op_Rational_OpMulMatrix: OpMulMatrix.Impl2[DenseVector[Rational], Rational, DenseVector[Rational]] =
- new OpMulMatrix.Impl2[DenseVector[Rational], Rational, DenseVector[Rational]] {
- def apply(a: DenseVector[Rational], b: Rational): DenseVector[Rational] = {
- val ad = a.data
- var aoff = a.offset
- val result = DenseVector.zeros[Rational](a.length)
- val rd = result.data
- var i = 0
- while (i < a.length) {
- rd(i) = ad(aoff) * b
- aoff += a.stride
- i += 1
- }
- result
- }
- implicitly[BinaryRegistry[Vector[Rational], Rational, OpMulMatrix.type, Vector[Rational]]].register(this)
- }
-
- implicit object Rational_implOpSolveMatrixBy_DRR_DRR_eq_DRR
- extends OpSolveMatrixBy.Impl2[DenseMatrix[Rational], DenseMatrix[Rational], DenseMatrix[Rational]] {
-
- def LUSolveArray(X: Array[Rational], A: Array[Rational], Xrows: Int, Xcols: Int): Array[Rational] = {
- val perm = (0 until Xrows).toArray
- for (i <- 0 until Xrows - 1) {
- val optPivot = (i until Xrows) find { p => !A(perm(p) + i * Xrows).isZero }
- val pivotRow = optPivot.getOrElse(throw new MatrixSingularException())
- val tmp = perm(i)
- perm(i) = perm(pivotRow)
- perm(pivotRow) = tmp
- val pivot = A(perm(i) + i * Xrows)
- for (j <- i + 1 until Xrows) {
- val coeff = A(perm(j) + i * Xrows) / pivot
- cfor(0)(_ < Xrows, _ + 1) { (k) =>
- A(perm(j) + k * Xrows) -= A(perm(i) + k * Xrows) * coeff
- }
- cfor(0)(_ < Xcols, _ + 1) { (k) =>
- X(perm(j) + k * Xrows) -= X(perm(i) + k * Xrows) * coeff
- }
- }
- }
- val X1 = new Array[Rational](Xrows * Xcols)
- for (i <- Xrows - 1 to (0, -1)) {
- cfor(0)(_ < Xcols, _ + 1) { (k) =>
- X1(i + k * Xrows) = X(perm(i) + k * Xrows)
- }
- for (j <- i + 1 until Xrows)
- cfor(0)(_ < Xcols, _ + 1) { (k) =>
- X1(i + k * Xrows) -= X1(j + k * Xrows) * A(perm(i) + j * Xrows)
- }
- cfor(0)(_ < Xcols, _ + 1) { (k) =>
- X1(i + k * Xrows) /= A(perm(i) + i * Xrows)
- }
- }
- X1
- }
-
- def apply(A: DenseMatrix[Rational], V: DenseMatrix[Rational]): DenseMatrix[Rational] = {
- require(A.rows == V.rows, "Non-conformant matrix sizes")
-
- if (A.size == 0) {
- DenseMatrix.zeros[Rational](0, 0)
- } else if (A.rows == A.cols) {
- val X = DenseMatrix.zeros[Rational](V.rows, V.cols)
- val Y = DenseMatrix.zeros[Rational](A.rows, A.cols)
- X := V
- Y := A
- new DenseMatrix(X.rows, X.cols, LUSolveArray(X.data, Y.data, X.rows, X.cols), 0, X.rows)
- } else
- throw new IllegalArgumentException("We only support solving a square matrix")
- }
- }
-
- implicit object Rational_implOpSolveMatrixBy_DMR_DVR_eq_DVR
- extends OpSolveMatrixBy.Impl2[DenseMatrix[Rational], DenseVector[Rational], DenseVector[Rational]] {
-
- def apply(a: DenseMatrix[Rational], b: DenseVector[Rational]): DenseVector[Rational] = {
- val rv: DenseMatrix[Rational] = a \ new DenseMatrix[Rational](b.size, 1, b.data, b.offset, b.stride, true)
- new DenseVector[Rational](rv.data)
- }
- }
-
- implicit def countFromTraverseModRational[T](implicit traverse: CanTraverseValues[T, Rational]): countNonZero.Impl[T, Int] = {
- new countNonZero.Impl[T, Int] {
- def apply(t: T): Int = {
- var count: Int = 0
- traverse.traverse(t, new ValuesVisitor[Rational] {
- def visit(a: Rational) = { if (a != Rational.zero) count += 1 }
- def zeros(count: Int, zeroValue: Rational) {}
- })
- count
- }
- }
- }
-}
diff --git a/core/src/main/scala/it/unich/jandom/utils/breeze/countNonZero.scala b/core/src/main/scala/it/unich/jandom/utils/breeze/countNonZero.scala
deleted file mode 100644
index 6be53f44..00000000
--- a/core/src/main/scala/it/unich/jandom/utils/breeze/countNonZero.scala
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * Copyright 2014 Gianluca Amato
- *
- * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
- * JANDOM is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * JANDOM is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty ofa
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with JANDOM. If not, see .
- */
-
-package it.unich.jandom.utils.breeze
-
-import breeze.generic.UFunc
-import breeze.linalg.support.CanTraverseValues
-import breeze.linalg.support.CanTraverseValues.ValuesVisitor
-
-object countNonZero extends UFunc {
- implicit def countFromTraverseDoubles[T](implicit traverse: CanTraverseValues[T, Double]): Impl[T, Int] = {
- new Impl[T, Int] {
- def apply(t: T): Int = {
- var count: Int = 0
- traverse.traverse(t, new ValuesVisitor[Double] {
- def visit(a: Double) = { if (a != 0) count += 1 }
- def zeros(count: Int, zeroValue: Double) {}
- })
- count
- }
- }
- }
-}
diff --git a/core/src/main/scala/it/unich/jandom/utils/numberext/Bounds.scala b/core/src/main/scala/it/unich/jandom/utils/numberext/Bounds.scala
new file mode 100644
index 00000000..7b990000
--- /dev/null
+++ b/core/src/main/scala/it/unich/jandom/utils/numberext/Bounds.scala
@@ -0,0 +1,91 @@
+/**
+ * Copyright 2016, 2017 Gianluca Amato
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
+
+package it.unich.jandom.utils.numberext
+
+/**
+ * This is a value class which implements some useful methods over arrays of extended rationals.
+ * @param data the underlying array of extended rationals.
+ */
+final class Bounds(val data: Array[RationalExt]) extends AnyVal {
+ /**
+ * Returns the length of the array.
+ */
+ def length = data.length
+
+ /**
+ * Returns the `i`-th element of the array.
+ */
+ def apply(i: Int) = data(i)
+
+ /**
+ * Returns a copy of the array.
+ */
+ def copy = new Bounds(data.clone)
+
+ /**
+ * Update the i-th element of the array with value `v`.
+ */
+ def update(i: Int, v: RationalExt) = data.update(i,v)
+
+ /**
+ * Append `that` to `this`.
+ */
+ def vertcat(that: Bounds) = {
+ val newdata = new Array[RationalExt](data.length + that.data.length)
+ Array.copy(data, 0, newdata, 0, data.length)
+ Array.copy(that.data, 0, newdata, data.length, that.data.length)
+ new Bounds(newdata)
+ }
+
+ /**
+ * Returns a subarray of the elements in the array, whose index is in `slice`.
+ */
+ def apply(slice: Seq[Int]) = {
+ val newdata = new Array[RationalExt](slice.length)
+ for ((idx, i) <- slice.zipWithIndex) {
+ newdata(i) = data(idx)
+ }
+ new Bounds(newdata)
+ }
+
+ /**
+ * Returns true if the map `f` is true for all elements of the array.
+ */
+ def forall(f: RationalExt => Boolean) = data.forall(f)
+}
+
+/**
+ * The compaion object of Bounds.
+ */
+object Bounds {
+ /**
+ * Create a bound vector of dimension `n` filled with `value`.
+ */
+ def fill(n: Int)(value: RationalExt) = new Bounds(Array.fill[RationalExt](n)(value))
+
+ /**
+ * Builds a bound vector for a sequence of extended rationals.
+ */
+ def apply(elem: RationalExt*) = new Bounds(elem.toArray)
+
+ /**
+ * Builds a bound vector for an array of extended rationals.
+ */
+ def apply(data: Array[RationalExt]) = new Bounds(data)
+}
\ No newline at end of file
diff --git a/core/src/main/scala/it/unich/jandom/utils/numberext/DenseMatrix.scala b/core/src/main/scala/it/unich/jandom/utils/numberext/DenseMatrix.scala
new file mode 100644
index 00000000..0346ddc4
--- /dev/null
+++ b/core/src/main/scala/it/unich/jandom/utils/numberext/DenseMatrix.scala
@@ -0,0 +1,418 @@
+/**
+ * Copyright 2016, 2017 Gianluca Amato
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
+
+package it.unich.jandom.utils.numberext
+
+import spire.syntax.cfor._
+import spire.math.Rational
+
+/**
+ * A DenseMatrix is a matrix of rationals. It is implemented as a single array
+ * in column order.
+ * @param data the underlying array containing the data
+ * @param rows the number of rows in the matrix
+ */
+final class DenseMatrix(val data: Array[Rational], val rows: Int) {
+ /**
+ * The number of columns in the matrix.
+ */
+ val cols = if (data.length == 0 && rows == 0) 0 else data.length / rows
+
+ /**
+ * Returns the element in position (`i`,`j`).
+ */
+ def apply(i: Int, j: Int): Rational = data(i + j * rows)
+
+ /**
+ * Modify the element in position (`i`,`j`) with value `v`.
+ */
+ def update(i: Int, j: Int, v: Rational) = data.update(i + j * rows, v)
+
+ /**
+ * Returns a copy of the matrix.
+ */
+ def copy = new DenseMatrix(data.clone, rows)
+
+ /**
+ * Add the matrix `that` to `this`.
+ */
+ def +=(that: DenseMatrix): DenseMatrix = {
+ cfor(0)(_ < data.length, _ + 1) { (i) =>
+ data(i) += that.data(i)
+ }
+ this
+ }
+
+ /**
+ * Subtract the matrix `that` from `this`.
+ */
+ def -=(that: DenseMatrix): DenseMatrix = {
+ cfor(0)(_ < data.length, _ + 1) { (i) =>
+ data(i) -= that.data(i)
+ }
+ this
+ }
+
+ /**
+ * Returns the sum of `this` and `that`.
+ */
+ def +(that: DenseMatrix) = {
+ val result = this.copy
+ result += that
+ }
+
+ /**
+ * Returns the `this` - `that`.
+ */
+ def -(that: DenseMatrix) = {
+ val result = this.copy
+ result -= that
+ }
+
+ /**
+ * Sum the rational `that` to all elements in the matrix.
+ */
+ def +=(that: Rational): DenseMatrix = {
+ cfor(0)(_ < data.length, _ + 1) { (i) =>
+ data(i) += that
+ }
+ this
+ }
+
+ /**
+ * Returns the matrix obtained by summing `that` to all elements in `this`.
+ */
+ def +(that: Rational) = {
+ val result = this.copy
+ result += that
+ }
+
+ /**
+ * Sum the rational `that` from all elements in the matrix.
+ */
+ def -=(that: Rational): DenseMatrix = {
+ cfor(0)(_ < data.length, _ + 1) { (i) =>
+ data(i) -= that
+ }
+ this
+ }
+
+ /**
+ * Returns the matrix obtained by subtracting `that` from all elements in `this`.
+ */
+ def -(that: Rational) = {
+ val result = this.copy
+ result -= that
+ }
+
+ /**
+ * Multiplies all the elements in the matrix by `that`
+ */
+ def *=(that: Rational): DenseMatrix = {
+ cfor(0)(_ < data.length, _ + 1) { (i) =>
+ data(i) *= that
+ }
+ this
+ }
+
+ /**
+ * Returns the matrix obtained by multipling all elements in `this` by `that`.
+ */
+ def *(that: Rational) = {
+ val result = this.copy
+ result *= that
+ }
+
+ /**
+ * Divides all elements in the matrix by `that`
+ */
+ def /=(that: Rational): DenseMatrix = {
+ cfor(0)(_ < data.length, _ + 1) { (i) =>
+ data(i) /= that
+ }
+ this
+ }
+
+ /**
+ * Returns the matrix obtained by dividing all elements in `this` by `that`.
+ */
+ def /(that: Rational) = {
+ val result = this.copy
+ result /= that
+ }
+
+ /**
+ * Returns the row-by-column product of `this` and `that`.
+ */
+ def *(that: DenseMatrix): DenseMatrix = {
+ require(this.cols == that.rows)
+ val result = DenseMatrix.raw(this.rows, that.cols)
+ cfor(0)(_ < rows, _ + 1) { (i) =>
+ cfor(0)(_ < that.cols, _ + 1) { (j) =>
+ result(i, j) = Rational(0)
+ cfor(0)(_ < cols, _ + 1) { (k) =>
+ result(i, j) += this(i, k) * that(k, j)
+ }
+ }
+ }
+ result
+ }
+
+ /**
+ * Returns a matrix `A` such that `this * A = that`.
+ */
+ def \(that: DenseMatrix): DenseMatrix = {
+ require(this.rows == that.rows, "Non-conformant matrices size")
+ if (data.size == 0)
+ DenseMatrix.zeros(0, 0)
+ else {
+ val A = data.clone
+ val X = that.data.clone
+ val Y = DenseMatrix.LUSolveArray(X, A, that.rows, that.cols)
+ new DenseMatrix(Y, rows)
+ }
+ }
+
+ /**
+ * Returns a vector `v` such that `this * v = that`.
+ */
+ def \(that: DenseVector): DenseVector = {
+ val M = new DenseMatrix(that.data, that.length)
+ val res = this \ M
+ new DenseVector(res.data)
+ }
+
+ /**
+ * Returns the transpose of `this`.
+ */
+ def t: DenseMatrix = {
+ val result = new DenseMatrix(new Array[Rational](data.length), cols)
+ cfor(0)(_ < rows, _ + 1) { (i) =>
+ cfor(0)(_ < cols, _ + 1) { (j) =>
+ result(j, i) = this(i, j)
+ }
+ }
+ result
+ }
+
+ /**
+ * Horizontally concatenates `that` to `this`. The two matrices are required to have the same number
+ * of rows, and the columns of `that` are added as additional columns to `this`.
+ */
+ def horzcat(that: DenseMatrix) = {
+ require(rows == that.rows)
+ val result = new DenseMatrix(new Array[Rational](this.rows * (this.cols + that.cols)), rows)
+ Array.copy(this.data, 0, result.data, 0, data.length)
+ Array.copy(that.data, 0, result.data, data.length, that.data.length)
+ result
+ }
+
+ /**
+ * Vertically concatenates `that` to `this`. The two matrices are required to have the same number
+ * of columns, and the rows of `that` are added as additional rows to `this`.
+ */
+ def vertcat(that: DenseMatrix) = {
+ require(cols == that.cols)
+ val result = new DenseMatrix(new Array[Rational]((this.rows + that.rows) * this.cols), this.rows + that.rows)
+ cfor(0)(_ < cols, _ + 1) { (j) =>
+ cfor(0)(_ < this.rows, _ + 1) { (i) =>
+ result(i, j) = this(i, j)
+ }
+ cfor(0)(_ < that.rows, _ + 1) { (i) =>
+ result(i + rows, j) = that(i, j)
+ }
+ }
+ result
+ }
+
+ /**
+ * Returns the `i`-th row of `this` as a vector.
+ */
+ def row(i: Int): DenseVector = {
+ val data = new Array[Rational](cols)
+ cfor(0)(_ < cols, _ + 1) { (j) =>
+ data(j) = this(i, j)
+ }
+ new DenseVector(data)
+ }
+
+ /**
+ * Replaces the `i`-th row of `this` with `v`.
+ */
+ def rowUpdate(i: Int, v: DenseVector): Unit = {
+ cfor(0)(_ < cols, _ + 1) { (j) =>
+ this(i,j) = v(j)
+ }
+ }
+
+ /**
+ * Returns the `i`-th column of `this` as a vector.
+ */
+ def col(j: Int) = {
+ val data = new Array[Rational](rows)
+ cfor(0)(_ < rows, _ + 1) { (i) =>
+ data(i) = this(i, j)
+ }
+ new DenseVector(data)
+ }
+
+ /**
+ * Returns an array `a` such that `a(i)` contains the number of non-zero elements
+ * in the `i`-th row of `this`.
+ */
+ def countNonZeroInRows: Array[Int] = {
+ val res = new Array[Int](rows)
+ var tot = 0
+ cfor(0) (_ < rows, _ +1 ) { (i) =>
+ tot = 0
+ cfor(0) ( _ < cols, _ + 1) { (j) =>
+ if (this(i,j) != 0) tot += 1
+ }
+ res(i) = tot
+ }
+ res
+ }
+
+ /**
+ * Returns a submatrix of `this`.
+ * @param slicer the sequence of rows to extract from `this`
+ * @param slicec the sequence of columns to extract from `this`
+ * @return the resulting submatrix
+ */
+ def apply(slicer: Seq[Int], slicec: Seq[Int]): DenseMatrix = {
+ val result = new DenseMatrix(new Array[Rational](slicer.length*slicec.length), slicer.length)
+ for ((i, idxi) <- slicer.zipWithIndex; (j, idxj) <- slicec.zipWithIndex) {
+ result(idxi,idxj) = this(i, j)
+ }
+ result
+ }
+
+ /**
+ * For each position `(i,j)` in `this`, `f` is called with parameters
+ * `(i,j)` and `this((i,j))`.
+ */
+ def foreachPair(f: ((Int, Int), Rational) => Unit): Unit = {
+ cfor (0)(_ < rows, _ +1) { (i) =>
+ cfor(0) ( _ < cols, _ +1 ) { (j) =>
+ f((i,j), this(i,j))
+ }
+ }
+ }
+
+ override def toString = {
+ val sb = new StringBuilder
+ cfor (0)(_ < rows, _ + 1) { (i) =>
+ cfor (0)(_ < cols, _ + 1) { (j) =>
+ sb ++= this(i,j).toString
+ sb += ' '
+ }
+ sb += '\n'
+ }
+ sb.toString
+ }
+}
+
+/**
+ * The compaion object for DenseMatrix
+ */
+object DenseMatrix {
+
+ /**
+ * Returns a matrix with `n` rows and `m` columns. Elements of the matrix
+ * are not initialized.
+ */
+ def raw(n: Int, m: Int) = new DenseMatrix(new Array[Rational](n * m), n)
+
+ /**
+ * Returns a diagonal matrix of order `n`.
+ */
+ def eye(n: Int) = {
+ val data = new Array[Rational](n * n)
+ cfor(0)(_ < n, _ + 1) { (i) =>
+ cfor(0)(_ < n, _ + 1) { (j) =>
+ data(i + j * n) = if (i == j) Rational.one else Rational.zero
+ }
+ }
+ new DenseMatrix(data, n)
+ }
+
+ /**
+ * Returns a matrix with `n` rows and `m` columns filled with zero.
+ */
+ def zeros(n: Int, m: Int) = {
+ val data = Array.fill[Rational](m * n)(Rational.zero)
+ new DenseMatrix(data, n)
+ }
+
+ /**
+ * Build a matrix from a sequence of vectors. Each vector will be a row
+ * in the resulting matrix.
+ */
+ def apply(rows: DenseVector*) = {
+ if (rows.isEmpty)
+ new DenseMatrix(new Array[Rational](0), 0)
+ else {
+ val cols = rows(0).length
+ val result = new DenseMatrix(new Array[Rational](cols * rows.length), rows.length)
+ for ((row, i) <- rows.zipWithIndex) {
+ cfor(0)(_ < cols, _ + 1) { (j) =>
+ result(i, j) = row(j)
+ }
+ }
+ result
+ }
+ }
+
+ /**
+ * An helper private method which implements Gaussian elimination.
+ */
+ private def LUSolveArray(X: Array[Rational], A: Array[Rational], Xrows: Int, Xcols: Int): Array[Rational] = {
+ val perm = (0 until Xrows).toArray
+ for (i <- 0 until Xrows - 1) {
+ val optPivot = (i until Xrows) find { p => !A(perm(p) + i * Xrows).isZero }
+ val pivotRow = optPivot.getOrElse(throw new IllegalArgumentException("Non invertible matrix"))
+ val tmp = perm(i)
+ perm(i) = perm(pivotRow)
+ perm(pivotRow) = tmp
+ val pivot = A(perm(i) + i * Xrows)
+ for (j <- i + 1 until Xrows) {
+ val coeff = A(perm(j) + i * Xrows) / pivot
+ cfor(0)(_ < Xrows, _ + 1) { (k) =>
+ A(perm(j) + k * Xrows) -= A(perm(i) + k * Xrows) * coeff
+ }
+ cfor(0)(_ < Xcols, _ + 1) { (k) =>
+ X(perm(j) + k * Xrows) -= X(perm(i) + k * Xrows) * coeff
+ }
+ }
+ }
+ val X1 = new Array[Rational](Xrows * Xcols)
+ for (i <- Xrows - 1 to (0, -1)) {
+ cfor(0)(_ < Xcols, _ + 1) { (k) =>
+ X1(i + k * Xrows) = X(perm(i) + k * Xrows)
+ }
+ for (j <- i + 1 until Xrows)
+ cfor(0)(_ < Xcols, _ + 1) { (k) =>
+ X1(i + k * Xrows) -= X1(j + k * Xrows) * A(perm(i) + j * Xrows)
+ }
+ cfor(0)(_ < Xcols, _ + 1) { (k) =>
+ X1(i + k * Xrows) /= A(perm(i) + i * Xrows)
+ }
+ }
+ X1
+ }
+}
diff --git a/core/src/main/scala/it/unich/jandom/utils/numberext/DenseVector.scala b/core/src/main/scala/it/unich/jandom/utils/numberext/DenseVector.scala
new file mode 100644
index 00000000..bf7f9c73
--- /dev/null
+++ b/core/src/main/scala/it/unich/jandom/utils/numberext/DenseVector.scala
@@ -0,0 +1,286 @@
+/**
+ * Copyright 2016, 2017 Gianluca Amato
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
+
+package it.unich.jandom.utils.numberext
+
+import spire.math.Rational
+import spire.syntax.cfor._
+import scala.language.implicitConversions
+
+/**
+ * This is a value class which implements some useful methods over arrays of rationals.
+ * @param data the underlying array containing the data
+ */
+final class DenseVector(val data: Array[Rational]) extends AnyVal {
+ /**
+ * Length of the vector.
+ */
+ def length = data.length
+
+ /**
+ * Returns the `i`-th element of the vector.
+ */
+ def apply(i: Int) = data(i)
+
+ /**
+ * Updates the `i`-th element of the vector with value `v`.
+ */
+ def update(i: Int, v: Rational) = data.update(i, v)
+
+ /**
+ * Returns a copy of the vector.
+ */
+ def copy = new DenseVector(data.clone)
+
+ /**
+ * Add vector `that` to `this`.
+ */
+ def +=(that: DenseVector) = {
+ cfor(0)(_ < data.length, _ + 1) { (i) =>
+ data(i) += that.data(i)
+ }
+ this
+ }
+
+ /**
+ * Subtract vector `that` from `this`.
+ */
+ def -=(that: DenseVector) = {
+ cfor(0)(_ < data.length, _ + 1) { (i) =>
+ data(i) -= that.data(i)
+ }
+ this
+ }
+
+ /**
+ * Component-wise multiply `this` by `that`.
+ */
+ def *=(that: DenseVector) = {
+ cfor(0)(_ < data.length, _ + 1) { (i) =>
+ data(i) *= that.data(i)
+ }
+ this
+ }
+
+ /**
+ * Component-wise divide `this` by `that`.
+ */
+ def /=(that: DenseVector) = {
+ cfor(0)(_ < data.length, _ + 1) { (i) =>
+ data(i) /= that.data(i)
+ }
+ this
+ }
+
+ /**
+ * Add the rational `that` to all elements of `this`.
+ */
+ def +=(that: Rational) = {
+ cfor(0)(_ < data.length, _ + 1) { (i) =>
+ data(i) += that
+ }
+ this
+ }
+
+ /**
+ * Subtract the rational `that` from all elements of `this`.
+ */
+ def -=(that: Rational) = {
+ cfor(0)(_ < data.length, _ + 1) { (i) =>
+ data(i) -= that
+ }
+ this
+ }
+
+ /**
+ * Multiplies all elements of `this` by `that`.
+ */
+ def *=(that: Rational) = {
+ cfor(0)(_ < data.length, _ + 1) { (i) =>
+ data(i) *= that
+ }
+ this
+ }
+
+ /**
+ * Divides all elements of `this` by `that`.
+ */
+ def /=(that: Rational) = {
+ cfor(0)(_ < data.length, _ + 1) { (i) =>
+ data(i) /= that
+ }
+ this
+ }
+
+ /**
+ * Transform `this` into its opposite.
+ */
+ def oppose() = {
+ cfor(0)(_ < data.length, _ + 1) { (i) =>
+ data(i) = -data(i)
+ }
+ this
+ }
+
+ /**
+ * Returns the sum of `this` and `that`.
+ */
+ def +(that: DenseVector) = {
+ val result = this.copy
+ result += that
+ }
+
+ /**
+ * Returns the sum of `this` and `that`.
+ */
+ def -(that: DenseVector) = {
+ val result = this.copy
+ result -= that
+ }
+
+ /**
+ * Returns the component-wise product of `this` and `that`.
+ */
+ def *(that: DenseVector) = {
+ val result = this.copy
+ result *= that
+ }
+
+ /**
+ * Returns the component-wise division of `this` by `that`.
+ */
+ def /(that: DenseVector) = {
+ val result = this.copy
+ result /= that
+ }
+
+ /**
+ * Returns the vector obtained by adding `that` to all elements of `this`.
+ */
+ def +(that: Rational) = {
+ val result = this.copy
+ result += that
+ }
+
+ /**
+ * Returns the vector obtained by subtracting `that` from all elements of `this`.
+ */
+ def -(that: Rational) = {
+ val result = this.copy
+ result -= that
+ }
+
+ /**
+ * Returns the vector obtained by multiplying all elements of `this` with `that`.
+ */
+ def *(that: Rational) = {
+ val result = this.copy
+ result *= that
+ }
+
+ /**
+ * Returns the product of the column vector `this` by matrix `that`.
+ */
+ def *(that: DenseMatrix) = {
+ val m = new DenseMatrix(data, data.length)
+ m * that
+ }
+
+ /**
+ * Returns the vector obtained by dividing all elements of `this` by `that`.
+ */
+ def /(that: Rational) = {
+ val result = this.copy
+ result /= that
+ }
+
+ /**
+ * Returns the opposite of `this`.
+ */
+ def unary_- = {
+ val result = this.copy
+ result.oppose()
+ }
+
+ /**
+ * Returns the number of non-zero elements in `this`.
+ */
+ def countNonZero: Int = {
+ var tot = 0
+ cfor(0)(_ < data.length, _ + 1) { (i) =>
+ if (data(i) != 0) tot += 1
+ }
+ tot
+ }
+
+ /**
+ * Returns the row vector which is the transpose of `t`. The row
+ * vector is represented as a dense matrix.
+ */
+ def t: DenseMatrix = {
+ new DenseMatrix(data.clone, 1)
+ }
+
+ /**
+ * It returns a bound vector obtained by applying `f` to each element
+ * of `this`. The map `f` is called with box the index and the value
+ * of each element.
+ */
+ def mapPairs(f: (Int, Rational) => RationalExt) = {
+ val newdata = new Array[RationalExt](data.length)
+ cfor(0)(_ < data.length, _ + 1) { (i) =>
+ newdata(i) = f(i, data(i))
+ }
+ new Bounds(newdata)
+ }
+
+ /**
+ * Returns `this` as a Scala Vector.
+ */
+ def toScalaVector: Vector[Rational] = Vector(data: _*)
+
+}
+
+/**
+ * The companion object for DenseVector.
+ */
+object DenseVector {
+ /**
+ * Implicit conversion from a pair to a DenseVector.
+ */
+ implicit def fromTuple2(x: Tuple2[Rational, Rational]) = DenseVector(x._1, x._2)
+ implicit def fromTuple3(x: Tuple3[Rational, Rational, Rational]) = DenseVector(x._1, x._2, x._3)
+
+ /**
+ * Builds a DenseVector from a sequence of rationals.
+ */
+ def apply(elem: Rational*): DenseVector = new DenseVector(elem.toArray)
+
+ /**
+ * Builds a DenseVector from an arrray of rationals.
+ */
+ def apply(data: Array[Rational]): DenseVector = new DenseVector(data)
+
+ /**
+ * Returns the null vector of dimension `n`.
+ */
+ def zeros(n: Int) = {
+ val data = Array.fill[Rational](n)(Rational.zero)
+ new DenseVector(data)
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/scala/it/unipd/jandom/domains/Abstraction.scala b/core/src/main/scala/it/unipd/jandom/domains/Abstraction.scala
index b871edbd..c05e3d54 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/Abstraction.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/Abstraction.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains
/**
diff --git a/core/src/main/scala/it/unipd/jandom/domains/CompleteLatticeOperator.scala b/core/src/main/scala/it/unipd/jandom/domains/CompleteLatticeOperator.scala
index 9acd9fb8..f73610c2 100755
--- a/core/src/main/scala/it/unipd/jandom/domains/CompleteLatticeOperator.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/CompleteLatticeOperator.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains
/**
diff --git a/core/src/main/scala/it/unipd/jandom/domains/InfInt.scala b/core/src/main/scala/it/unipd/jandom/domains/InfInt.scala
new file mode 100644
index 00000000..8f13dc48
--- /dev/null
+++ b/core/src/main/scala/it/unipd/jandom/domains/InfInt.scala
@@ -0,0 +1,388 @@
+/**
+ * Copyright 2018 Mattia Bottaro, Mauro Carlin
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
+package it.unipd.jandom.domains
+
+/**
+ * This class manage integer operation avoid overflow.
+ * It defines also a way to manage the "infinite" similar to Double.PositiveInfinity and Double.NegativeInfinity
+ *
+ * @author Mattia Bottaro
+ * @author Mauro Carlin
+ */
+
+trait InfInt {
+
+ def isInfinity : Boolean
+
+ /**
+ * The following method are abstract.
+ * The real implementation can be found in each sub-case class extending this trait
+ */
+
+ /**
+ * Perform the mathematical sum between the object that invoke this method and the param
+ * @param x is the adding
+ * @return the mathematical sum between the object that invoke this method and x.
+ */
+ def +(x: InfInt): InfInt
+
+ /**
+ * Perform the mathematical division between the object that invoke this method and the param
+ * @param x is the divider
+ * @return the mathematical division between the object that invoke this method and x.
+ */
+ def /(x: InfInt): InfInt
+
+ /**
+ * Perform the mathematical multiplication between the object that invoke this method and the param
+ * @param x is the factor
+ * @return the mathematical multiplication between the object that invoke this method and x.
+ */
+ def *(x: InfInt): InfInt
+
+ /**
+ * @param x is the element to compare
+ * @return true if the object that invoke this method is greater then x, false otherwise.
+ */
+ def >(x: InfInt): Boolean
+
+ /**
+ * @param x is the element to compare
+ * @return true if the object that invoke this method is greater or equal then x, false otherwise.
+ */
+ def >=(x: InfInt): Boolean
+
+ /**
+ * @param x is the second argument of max operator
+ * @return the max element between the object that invoke this method and x.
+ */
+ def max(x: InfInt): InfInt
+
+ /**
+ * @param x is the second argument of min operator
+ * @return the min element between the object that invoke this method and x.
+ */
+ def min(x: InfInt): InfInt
+
+ /**
+ * @param x is the element to compare
+ * @return true if the object that invoke this method is equal to x, false otherwise.
+ */
+ def ==(x: InfInt): Boolean
+
+ /**
+ * @return the inverse of the object that invoke this method.
+ */
+ def inverse(): InfInt = {
+ this match {
+ case PositiveInfinity() => NegativeInfinity()
+ case NegativeInfinity() => PositiveInfinity()
+ case IntNumber(x) => IntNumber(-x)
+ }
+ }
+
+
+ /**
+ * Perform the mathematical difference between the object that invoke this method and the param
+ * @param x is the substracting
+ * @return the mathematical difference between the object that invoke this method and x.
+ */
+ def -(x: InfInt): InfInt = {
+ this + x.inverse()
+ }
+
+ /**
+ * Checks if two InfInt are not equal
+ * @param x is the second argument of != operator
+ * @return true if and only if the object that invoke this method is not equal to x.
+ */
+ def !=(x: InfInt): Boolean = {
+ !(this == x)
+ }
+
+ /**
+ * Checks if the object that invoke this method is less than the argument
+ * @param x is the second argument of < operator
+ * @return true if and only if the object that invoke this method is less than x.
+ */
+ def <(x: InfInt): Boolean = {
+ !(this >= x)
+ }
+
+ /**
+ * @param x is the element to compare
+ * @return true if the object that invoke this method is smaller or equal then x, false otherwise.
+ */
+ def <=(x: InfInt): Boolean = {
+ !(this > x)
+ }
+
+}
+
+case class IntNumber(n: Int) extends InfInt {
+
+ def isInfinity = false
+
+ def +(x: InfInt): InfInt = {
+ x match {
+ case NegativeInfinity() => NegativeInfinity()
+ case PositiveInfinity() => PositiveInfinity()
+ case IntNumber(m) => safeAdd(n,m)
+ }
+ }
+
+ def *(x: InfInt): InfInt = {
+ if (n == 0) return IntNumber(0)
+ x match {
+ case IntNumber(m) => safeMul(n,m)
+ case _ =>
+ if (n > 0)
+ return x
+ return x.inverse()
+ }
+ }
+
+ def >(x: InfInt): Boolean = {
+ x match {
+ case PositiveInfinity() => false
+ case IntNumber(m) => n > m
+ case _ => true
+ }
+ }
+
+ def >=(x: InfInt): Boolean = {
+ x match {
+ case IntNumber(m) => n >= m
+ case PositiveInfinity() => false
+ case _ => true
+ }
+ }
+
+ def /(x: InfInt): InfInt = {
+ x match {
+ case IntNumber(m) => IntNumber(n / m)
+ case _ => IntNumber(0)
+ }
+ }
+
+ def ==(x: InfInt): Boolean = {
+ x match {
+ case IntNumber(x) => x == n
+ case _ => false
+ }
+ }
+
+ def max(x: InfInt): InfInt = {
+ x match {
+ case IntNumber(m) => IntNumber(n max m)
+ case PositiveInfinity() => PositiveInfinity()
+ case NegativeInfinity() => IntNumber(n)
+ }
+ }
+
+ def min(x: InfInt): InfInt = {
+ x match {
+ case IntNumber(m) => IntNumber(n min m)
+ case PositiveInfinity() => IntNumber(n)
+ case NegativeInfinity() => NegativeInfinity()
+ }
+ }
+
+ /**
+ * Perform a "safe add", that is a sum that will never do an overflow.
+ * @param x is the adding
+ * @return the safe add between the object that invoke this method and x. If an overflow is detected, an Infinity is returned.
+ */
+ def safeAdd(left: Int, right: Int): InfInt = {
+ if (right > 0 && left > Int.MaxValue - right)
+ return PositiveInfinity()
+
+ if (right < 0 && left < Int.MinValue - right)
+ return NegativeInfinity()
+
+ return IntNumber(left + right)
+ }
+
+ /**
+ * Perform a "safe multiplication", that is a product that will never do an overflow.
+ * @param x is the adding
+ * @return the safe prduct between the object that invoke this method and x. If an overflow is detected, an Infinity is returned.
+ */
+ def safeMul(left: Int, right: Int): InfInt = { // TODO
+ if (right > 0) {
+ if (left > Int.MaxValue / right)
+ return PositiveInfinity()
+ if (left < Int.MinValue / right)
+ return NegativeInfinity()
+ }
+ if (right < -1) {
+ if (left > Int.MinValue / right)
+ return NegativeInfinity()
+ if (left < Int.MaxValue / right)
+ return PositiveInfinity()
+ }
+ if (right == -1) {
+ if (left == Int.MinValue)
+ return PositiveInfinity()
+ if (left == Int.MaxValue)
+ return NegativeInfinity()
+ }
+ return IntNumber(left * right)
+ }
+
+ override def toString : String = n.toString
+}
+
+case class NegativeInfinity() extends InfInt {
+
+ def isInfinity = true
+
+ def +(x: InfInt): InfInt = {
+ x match {
+ case _ => NegativeInfinity()
+ }
+ }
+
+ def *(x: InfInt): InfInt = {
+ x match {
+ case IntNumber(m) =>
+ if (m > 0)
+ return NegativeInfinity()
+ if (m < 0)
+ return PositiveInfinity()
+ return IntNumber(0)
+ case PositiveInfinity() => NegativeInfinity()
+ case NegativeInfinity() => PositiveInfinity()
+ }
+ }
+
+ def >(x: InfInt): Boolean = {
+ x match {
+ case NegativeInfinity() => false
+ case _ => false
+ }
+ }
+
+ def >=(x: InfInt): Boolean = {
+ x match {
+ case NegativeInfinity() => true
+ case _ => false
+ }
+ }
+
+ def /(x: InfInt): InfInt = {
+ x match {
+ case IntNumber(x) =>
+ if(x < 0)
+ return PositiveInfinity()
+ return NegativeInfinity()
+ case _ => IntNumber(0) // Inf / Inf = Inf * (1 / Inf) = Inf * 0
+ }
+ }
+
+ def ==(x: InfInt): Boolean = {
+ x match {
+ case NegativeInfinity() => true
+ case _ => false
+ }
+ }
+
+ def max(x: InfInt): InfInt = {
+ x match {
+ case IntNumber(m) => IntNumber(m)
+ case _ => x
+ }
+ }
+
+ def min(x: InfInt): InfInt = {
+ x match {
+ case _ => NegativeInfinity()
+ }
+ }
+
+ override def toString : String = "-\u221E"
+
+}
+
+case class PositiveInfinity() extends InfInt {
+
+ def isInfinity = true
+
+ def +(x: InfInt): InfInt = {
+ x match {
+ case _ => PositiveInfinity()
+ }
+ }
+
+ def *(x: InfInt): InfInt = {
+ x match {
+ case IntNumber(x) =>
+ if (x > 0)
+ return PositiveInfinity()
+ if (x < 0)
+ return NegativeInfinity()
+ return IntNumber(0)
+ case _ => x
+ }
+ }
+
+ def >(x: InfInt): Boolean = {
+ x match {
+ case NegativeInfinity() => true
+ case _ => false
+ }
+ }
+
+ def >=(x: InfInt): Boolean = {
+ x match {
+ case _ => true
+ }
+ }
+
+ def ==(x: InfInt): Boolean = {
+ x match {
+ case PositiveInfinity() => true
+ case _ => false
+ }
+ }
+
+ def /(x: InfInt): InfInt = {
+ x match {
+ case IntNumber(m) =>
+ if(m < 0)
+ return NegativeInfinity()
+ return PositiveInfinity()
+ case _ => IntNumber(0) // Inf / Inf = Inf * (1 / Inf) = Inf * 0
+ }
+ }
+
+ def max(x: InfInt): InfInt = {
+ x match {
+ case _ => PositiveInfinity()
+ }
+ }
+
+ def min(x: InfInt): InfInt = {
+ x match {
+ case _ => x
+ }
+ }
+
+ override def toString : String = "+\u221E"
+
+}
diff --git a/core/src/main/scala/it/unipd/jandom/domains/IntOperator.scala b/core/src/main/scala/it/unipd/jandom/domains/IntOperator.scala
index 3b762fa3..0dcbadbc 100755
--- a/core/src/main/scala/it/unipd/jandom/domains/IntOperator.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/IntOperator.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains
/**
diff --git a/core/src/main/scala/it/unipd/jandom/domains/NumOperator.scala b/core/src/main/scala/it/unipd/jandom/domains/NumOperator.scala
index 5fb3d93f..64473079 100755
--- a/core/src/main/scala/it/unipd/jandom/domains/NumOperator.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/NumOperator.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains
/**
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/BaseNumericalDomain.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/BaseNumericalDomain.scala
index 64e27fe7..abab50db 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/BaseNumericalDomain.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/BaseNumericalDomain.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical
import it.unich.jandom.domains.WideningDescription
@@ -27,12 +44,14 @@ abstract class BaseNumericalDomain
* @param unreachable tells whether the program point is reachable or not
* @return a new property for the given array
*/
+
def createProperty(elements: Array[T], unreachable: Boolean) : Property
def createProperty(p : BaseProperty): Property =
createProperty(p.elements, p.isEmpty || p.elements.contains(core.bottom))
+ //def updateData(x: Double, y: Double) = core.updateData(x,y)
/**
* Factory method for creating a Property.
@@ -334,11 +353,12 @@ abstract class BaseNumericalDomain
if (unreachable && homcoeffs.exists { _ != 0 })
return core.top
var acc: T = core.alpha(known)
- for (i <- homcoeffs.indices)
- if (homcoeffs(i) < 0)
- acc = core.sum(acc, core.inverse(elements(i)))
- else if(homcoeffs(i) > 0)
- acc = core.sum(acc, elements(i))
+ for (i <- homcoeffs.indices) {
+ if (homcoeffs(i) != 0) {
+ val t = core.mult(core.alpha(homcoeffs(i)), elements(i))
+ acc = core.sum(acc, t)
+ }
+ }
acc
}
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/FullyReducedProductCongruenceBoxDoubleDomain.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/FullyReducedProductCongruenceBoxDoubleDomain.scala
index eacf330c..7c5ba5c7 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/FullyReducedProductCongruenceBoxDoubleDomain.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/FullyReducedProductCongruenceBoxDoubleDomain.scala
@@ -1,10 +1,27 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical
import it.unich.jandom.domains.DomainTransformation
import it.unich.jandom.domains.numerical.ProductDomain
import it.unich.jandom.domains.numerical.BoxDoubleDomain
import it.unipd.jandom.domains.numerical.congruence.Congruence.{Congruence, CongruenceBottom}
-import it.unipd.jandom.domains.numerical.congruence.{Congruence, CongruenceDomain, CongruenceDomainCore}
+import it.unipd.jandom.domains.numerical.congruence.{Congruence, CongruenceDomain}
import it.unipd.jandom.domains.numerical.utils.MathLibrary
/**
@@ -19,7 +36,7 @@ import it.unipd.jandom.domains.numerical.utils.MathLibrary
class FullyReducedProductCongruenceBoxDoubleDomain(override val dom1 : CongruenceDomain, override val dom2 : BoxDoubleDomain) extends ProductDomain[CongruenceDomain, BoxDoubleDomain](dom1, dom2) {
override val dom1Todom2 = DomainTransformation.CongruenceToBoxDouble
override val dom2Todom1 = DomainTransformation.BoxDoubleToCongruence
-
+
override def top(n: Int) =
new FullyReducedProductCongruenceBoxDouble(dom1.top(n), dom2.top(n))
@@ -43,9 +60,8 @@ class FullyReducedProductCongruenceBoxDoubleDomain(override val dom1 : Congruenc
/* Calculate the point-wise fully-reduct product of an array of cogruence and low- and upperbound of box double */
val res : Array[(Congruence, Double, Double)] = (x1.elements, x2.low, x2.high).zipped.map(
(congruence,_low, _high) => {
- var low: Int = _low.toInt
-
- var high: Int = _high.toInt
+ val low: Int = _low.toInt
+ val high: Int = _high.toInt
congruence match {
case Congruence.Mod(a, b) =>
val (a1, b1) = transform(low, high, a, b)
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/ProductCongruenceBoxDoubleDomain.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/ProductCongruenceBoxDoubleDomain.scala
index 4865012c..10491c40 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/ProductCongruenceBoxDoubleDomain.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/ProductCongruenceBoxDoubleDomain.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical
import it.unich.jandom.domains.DomainTransformation
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/ProductESeqParityDomain.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/ProductESeqParityDomain.scala
index 50932bde..681550e1 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/ProductESeqParityDomain.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/ProductESeqParityDomain.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical
import it.unich.jandom.domains.DomainTransformation
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/ProductSignModKDomain.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/ProductSignModKDomain.scala
index 09b4df72..fbbbcb4d 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/ProductSignModKDomain.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/ProductSignModKDomain.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical
import it.unich.jandom.domains.DomainTransformation
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/SumSignModKDomain.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/SumSignModKDomain.scala
index 7573dde7..61510c04 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/SumSignModKDomain.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/SumSignModKDomain.scala
@@ -1,8 +1,24 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical
import it.unich.jandom.domains.numerical.SumDomain
import it.unipd.jandom.domains.numerical.mod.ModKDomain
-import it.unipd.jandom.domains.numerical.parity.ParityDomain
import it.unipd.jandom.domains.numerical.sign.SignDomain
/**
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/box/BoundedBoxDomain.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/box/BoundedBoxDomain.scala
new file mode 100644
index 00000000..6bb094c5
--- /dev/null
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/box/BoundedBoxDomain.scala
@@ -0,0 +1,156 @@
+/**
+ * Copyright 2018 Mattia Bottaro, Mauro Carlin
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical Domains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
+package it.unipd.jandom.domains.numerical.box
+
+import it.unich.jandom.domains.numerical.LinearForm
+import it.unipd.jandom.domains.numerical.BaseNumericalDomain
+import it.unipd.jandom.domains.numerical.box.Box._
+import it.unipd.jandom.domains.numerical.box.BoundedBoxDomainCore._
+import it.unipd.jandom.domains.{InfInt, PositiveInfinity, NegativeInfinity, IntNumber}
+
+/**
+ *
+ * @author Mattia Bottaro
+ * @author Mauro Carlin
+ */
+class BoundedBoxDomain(m : InfInt, n : InfInt) extends BaseNumericalDomain[Box, BoundedBoxDomainCore](BoundedBoxDomainCore(m,n)){
+
+ override def updateData(x: Double, y: Double): Unit = {
+ val new_m = IntNumber(x.toInt)
+ val new_n = IntNumber(y.toInt)
+ BoundedBoxDomainCore.updateData(new_m,new_n)
+ }
+
+ /**
+ * @inheritdoc
+ */
+ override def createProperty(boxes: Array[Box], unreachable: Boolean): Property = {
+ new Property(boxes, unreachable)
+ }
+
+ /**
+ *
+ * @param boxes array of the variables' boxes status
+ * @param unreachable tells if a given program point is unreachable
+ */
+ class Property (boxes : Array[Box], unreachable: Boolean) extends BaseProperty(boxes, unreachable) {
+
+ /**
+ * @param box is an Interval
+ * @return the lower bound of the interval.
+ */
+ private def projectLow (box : Box) : InfInt = {
+
+ box match {
+ case IntervalBottom => PositiveInfinity()
+ case IntervalTop => NegativeInfinity()
+ case Interval(low,high) => low
+ }
+ }
+
+
+ /**
+ * @param box is an Interval
+ * @return the upper bound.
+ */
+ private def projectHigh (box : Box) : InfInt = {
+
+ box match {
+ case IntervalBottom => NegativeInfinity()
+ case IntervalTop => PositiveInfinity()
+ case Interval(low,high) => high
+ }
+ }
+
+ def apply(boxes: Array[Box], unreachable: Boolean) : Property = new Property(boxes, unreachable)
+
+ /**
+ * @inheritdoc
+ */
+ override def linearDisequality(lf: LinearForm): Property = {
+ if (isEmpty)
+ return this
+ val result : Box = linearEvaluation(lf);
+ result match {
+ case IntervalBottom => bottom
+ case Interval(low,high) => if (low == high && low == IntNumber(0)) bottom else this
+ case _ => this
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ override def linearInequality(lf: LinearForm): Property = {
+ if (isEmpty)
+ return this
+ val homcoeffs = lf.homcoeffs.map(_.toInt).toArray
+ val known = IntNumber(lf.known.toInt)
+ val lfMin = projectLow(linearEvaluation(lf))
+ val lfArgmin = linearArgmin(lf);
+ if (lfMin > IntNumber(0))
+ return bottom
+ else {
+ var newboxes = boxes.clone
+ val infinities = (homcoeffs.indices) filter { i => lfArgmin(i).isInfinity && homcoeffs(i) != 0 }
+
+ infinities.size match {
+
+ case 0 => {
+ for (i <- homcoeffs.indices) {
+ if (homcoeffs(i) < 0) newboxes(i) = Interval(projectLow(boxes(i)) max (lfArgmin(i) - (lfMin / IntNumber(homcoeffs(i)))), projectHigh(newboxes(i)))
+ if (homcoeffs(i) > 0) newboxes(i) = Interval(projectLow(newboxes(i)), projectHigh(boxes(i)) min (lfArgmin(i) - (lfMin / IntNumber(homcoeffs(i)))))
+ }
+ }
+ case 1 => {
+ val posinf = infinities.head
+ if (homcoeffs(posinf) < 0) {
+ newboxes(posinf) = Interval(projectLow(boxes(posinf)) max ((dotprod(homcoeffs, lfArgmin, posinf).inverse() - known) / IntNumber(homcoeffs(posinf))), projectHigh(newboxes(posinf)))
+ } else {
+ newboxes(posinf) = Interval(projectLow(boxes(posinf)), projectHigh(boxes(posinf)) min ((dotprod(homcoeffs, lfArgmin, posinf).inverse() - known) / IntNumber(homcoeffs(posinf))))
+ }
+ }
+ case _ =>
+ }
+ new Property(newboxes.map(BoundedBoxDomainCore.norm),false)
+ }
+ }
+
+ private def linearArgmin(lf: LinearForm): Seq[InfInt] = {
+ (lf.homcoeffs.zipWithIndex) map {
+ case (c, i) => if (c > 0) projectLow(boxes(i)) else projectHigh(boxes(i))
+ }
+ }
+
+ private def dotprod(x: Seq[Int], y: Seq[InfInt], remove: Int): InfInt = {
+ var sum: InfInt = IntNumber(0)
+ for (i <- x.indices; if i != remove && x(i) != 0)
+ sum = sum + (IntNumber(x(i)) * y(i))
+ sum
+ }
+
+ } // End of property
+
+} // End of BoundedBoxDomain
+
+object BoundedBoxDomain {
+ /**
+ * Factory method of BoxDomain
+ */
+ def apply(m : InfInt, n : InfInt) = new BoundedBoxDomain(m,n)
+}
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/box/BoundedBoxDomainCore.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/box/BoundedBoxDomainCore.scala
new file mode 100644
index 00000000..70f8b79b
--- /dev/null
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/box/BoundedBoxDomainCore.scala
@@ -0,0 +1,149 @@
+/**
+ * Copyright 2018 Mattia Bottaro, Mauro Carlin
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
+
+package it.unipd.jandom.domains.numerical.box
+
+import it.unipd.jandom.domains.numerical.utils.{MathLibrary => M}
+import it.unipd.jandom.domains.{InfInt, IntNumber, PositiveInfinity, NegativeInfinity}
+import Box._
+
+/*
+ * The bounded Box domain
+ * @author Mattia Bottaro ,
+ * @author Mauro Carlin
+*/
+
+class BoundedBoxDomainCore(bound_m : InfInt, bound_n : InfInt) extends BoxDomainCore{
+
+ var m: InfInt = bound_m
+ var n: InfInt = bound_n
+
+ /**
+ * @inheritdoc
+ */
+ override def sum(x : Box, y : Box) : Box = {
+ val result = super.sum(x,y)
+ normalizeBound(result)
+ }
+
+ /**
+ * @inheritdoc
+ */
+ override def inverse(x : Box) : Box = {
+ val result = super.inverse(x)
+ normalizeBound(result)
+ }
+
+ /**
+ * @inheritdoc
+ */
+ override def mult(x : Box, y : Box) : Box = {
+ val result = super.mult(x,y)
+ normalizeBound(result)
+ }
+
+ /**
+ * @inheritdoc
+ */
+ override def division(x : Box, y : Box) : Box = {
+ val result = super.division(x,y)
+ normalizeBound(result)
+ }
+
+ /**
+ * @inheritdoc
+ */
+ override def remainder(x : Box, y : Box) : Box = {
+ val result = super.remainder(x,y)
+ normalizeBound(result)
+ }
+
+ /**
+ * @inheritdoc
+ */
+ override def lub(x : Box, y : Box) : Box = {
+ val result = super.lub(x,y)
+ normalizeBound(result)
+ }
+
+ /**
+ * @inheritdoc
+ */
+ override def glb(x : Box, y : Box) : Box = {
+ val result = super.glb(x,y)
+ normalizeBound(result)
+ }
+
+ /**
+ * Normalize an interval in order to respect the bound m and n.
+ * If m >= n the domain become the Constant domain.
+ * If m is -Inf and n +Inf it become the Interval domain.
+ *
+ * @param x an Interval
+ * @return the interval bounded with m and n
+ */
+ def normalizeBound(x : Box) : Box = {
+ x match {
+ case Interval(low,high) => {
+ if (low == high)
+ return Interval(low,high)
+
+ if (n > m) {
+ if (high < m)
+ return Interval(NegativeInfinity(),m)
+ if (low > n)
+ return Interval(n,PositiveInfinity())
+
+ var new_low = low
+ var new_high = high
+ if (high > n)
+ new_high = PositiveInfinity()
+ if (low < m)
+ new_low = NegativeInfinity()
+
+ return check(Interval(new_low,new_high))
+ }
+ return IntervalTop
+ }
+ case _ => x
+
+ }
+ }
+
+} // end of BoundedBoxDomainCore class
+
+object BoundedBoxDomainCore {
+ /**
+ * Factory method of BoundedBoxDomainCore
+ */
+ var D: BoundedBoxDomainCore = apply(IntNumber(0),IntNumber(0))
+ def apply(m : InfInt, n : InfInt): BoundedBoxDomainCore = {
+ D = new BoundedBoxDomainCore(m,n)
+ return D
+ }
+
+ def updateData(x: InfInt, y: InfInt) = {
+ D.m = x
+ D.n = y
+ }
+
+ def norm(x : Box) : Box = {
+ D.normalizeBound(x)
+ }
+
+} // end of BoundedBoxDomainCore companion object
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/box/Box.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/box/Box.scala
new file mode 100644
index 00000000..294d47d6
--- /dev/null
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/box/Box.scala
@@ -0,0 +1,45 @@
+/**
+ * Copyright 2017 Mattia Bottaro, Mauro Carlin
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSEin. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
+package it.unipd.jandom.domains.numerical.box
+import it.unipd.jandom.domains.InfInt
+
+/**
+ * The elements of the Interval domain.
+ * This domain is useful for the Interval propagation analysis.
+ *
+ * @author Mattia Bottaro
+ * @author Mauro Carlin
+ */
+object Box {
+ sealed trait Box
+
+ // interval
+ case class Interval (low : InfInt, high : InfInt) extends Box {
+ override def toString : String = "= [" + low.toString + "," + high.toString + "]"
+ }
+
+ // no accurate info available for variable
+ case object IntervalTop extends Box {
+ override def toString : String = "= \u22a4"
+ }
+
+ // no possible value
+ case object IntervalBottom extends Box {
+ override def toString: String = "= \u22a5"
+ }
+}
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/box/BoxDomain.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/box/BoxDomain.scala
new file mode 100644
index 00000000..c6c2277a
--- /dev/null
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/box/BoxDomain.scala
@@ -0,0 +1,219 @@
+/**
+ * Copyright 2018 Mattia Bottaro, Mauro Carlin
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
+package it.unipd.jandom.domains.numerical.box
+
+import it.unich.jandom.domains.numerical.LinearForm
+import it.unipd.jandom.domains.numerical.BaseNumericalDomain
+import it.unipd.jandom.domains.numerical.box.Box._
+import it.unipd.jandom.domains.numerical.box.BoxDomainCore._
+import it.unipd.jandom.domains.{InfInt, PositiveInfinity, NegativeInfinity, IntNumber}
+
+/**
+ * This is the domain of Integer boxes, also known as the interval domain. Bounds are represented by two numbers which type is :InfInt.
+ * InfInt is a particular ad-hoc type that manages normal Int operation better than :Int type. For Example there's no overflow error, but it's
+ * replaced by an "infinity" entity just like happens in :Double type.
+ *
+ * @author Mattia Bottaro
+ * @author Mauro Carlin
+ */
+
+class BoxDomain extends BaseNumericalDomain[Box, BoxDomainCore](BoxDomainCore()) {
+
+ /**
+ * @inheritdoc
+ */
+ override def createProperty(boxes: Array[Box], unreachable: Boolean): Property =
+ new Property(boxes, unreachable)
+
+ /**
+ * Numerical property that tells whether the variables in a certain point of the CFG are an integer interval or not.
+ * @param boxes array of the variables' boxes status
+ * @param unreachable tells if a given program point is unreachable
+ */
+ class Property (boxes : Array[Box], unreachable: Boolean) extends BaseProperty(boxes, unreachable) {
+
+ /**
+ * Returning the lower bound of an interval.
+ * @param box is an Interval
+ * @return the lower bound.
+ */
+ private def projectLow (box : Box) : InfInt = {
+ box match {
+ case IntervalBottom => PositiveInfinity()
+ case IntervalTop => NegativeInfinity()
+ case Interval(low,high) => low
+ }
+ }
+
+
+ /**
+ * Returning the upper bound of an interval.
+ * @param box is an Interval
+ * @return the upper bound.
+ */
+ private def projectHigh (box : Box) : InfInt = {
+ box match {
+ case IntervalBottom => NegativeInfinity()
+ case IntervalTop => PositiveInfinity()
+ case Interval(low,high) => high
+ }
+ }
+
+ def apply(boxes: Array[Box], unreachable: Boolean) : Property = new Property(boxes, unreachable)
+
+ /**
+ * @inheritdoc
+ */
+ override def linearDisequality(lf: LinearForm): Property = {
+ if (isEmpty)
+ return this
+ val result : Box = linearEvaluation(lf);
+ result match {
+ case IntervalBottom => bottom
+ case Interval(low,high) => if (low == high && low == IntNumber(0)) bottom else this
+ case _ => this
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ override def linearInequality(lf: LinearForm): Property = {
+ if (isEmpty)
+ return this
+ val homcoeffs = lf.homcoeffs.map(_.toInt).toArray
+ val known = IntNumber(lf.known.toInt)
+ val lfMin = projectLow(linearEvaluation(lf))
+ val lfArgmin = linearArgmin(lf);
+ if (lfMin > IntNumber(0))
+ return bottom
+ else {
+ var newboxes = boxes.clone
+ val infinities = (homcoeffs.indices) filter { i => lfArgmin(i).isInfinity && homcoeffs(i) != 0 }
+
+ infinities.size match {
+ case 0 => {
+ for (i <- homcoeffs.indices) {
+ if (homcoeffs(i) < 0) newboxes(i) = Interval(projectLow(boxes(i)) max (lfArgmin(i) - (lfMin / IntNumber(homcoeffs(i)))), projectHigh(newboxes(i)))
+ if (homcoeffs(i) > 0) newboxes(i) = Interval(projectLow(newboxes(i)), projectHigh(boxes(i)) min (lfArgmin(i) - (lfMin / IntNumber(homcoeffs(i)))))
+ }
+ }
+ case 1 => {
+ val posinf = infinities.head
+ if (homcoeffs(posinf) < 0) {
+ newboxes(posinf) = Interval(projectLow(boxes(posinf)) max ((dotprod(homcoeffs, lfArgmin, posinf).inverse() - known) / IntNumber(homcoeffs(posinf))), projectHigh(newboxes(posinf)))
+ } else {
+ newboxes(posinf) = Interval(projectLow(boxes(posinf)), projectHigh(boxes(posinf)) min ((dotprod(homcoeffs, lfArgmin, posinf).inverse() - known) / IntNumber(homcoeffs(posinf))))
+ }
+ }
+ case _ =>
+ }
+ new Property(newboxes,false)
+ }
+ }
+
+ /**
+ * Compute the corner of the box which minimizes a linear form.
+ * @param coeff the homogeneous coefficients.
+ * @return the coordinates of the point which minimizes the linear form.
+ */
+ private def linearArgmin(lf: LinearForm): Seq[InfInt] = {
+ (lf.homcoeffs.zipWithIndex) map {
+ case (c, i) => if (c > 0) projectLow(boxes(i)) else projectHigh(boxes(i))
+ }
+ }
+
+ /**
+ * Return the dot product of `x` and `y`.
+ * If element `x(i)` is zero, then `x(i)*y(i)` is `0` independently from the value of `y(i)`.
+ * If `remove` is a valid index in `x` and `y`, the factor `x(remove) * y(remove)` is
+ * removed from the dot product.
+ */
+ private def dotprod(x: Seq[Int], y: Seq[InfInt], remove: Int): InfInt = {
+ var sum: InfInt = IntNumber(0)
+ for (i <- x.indices; if i != remove && x(i) != 0)
+ sum = sum + (IntNumber(x(i)) * y(i))
+ sum
+ }
+
+ /**
+ * Implementing the widening strategy described in
+ * [[https://hal.archives-ouvertes.fr/hal-01657536]] (Tutorial on Static Inference of Numeric Invariants by Abstract Interpretation), page 221
+ *
+ * @param that the abstract object to be widened with `this`. `that` IS assumed to be smaller than `this`.
+ * @return the widening of the two abstract properties.
+ */
+ override def widening(that : Property) : Property = {
+ createProperty((this.elements, that.elements).zipped.map((x, y) => {
+ (x,y) match {
+ case (IntervalBottom, _) => y
+ case (_ , IntervalBottom) => x
+ case (IntervalTop, _) => IntervalTop
+ case (_ , IntervalTop) => IntervalTop
+ case (Interval(low1, high1), Interval(low2,high2)) =>
+ var newhigh = high1
+ var newlow = low1
+
+ if (low2 >= low1)
+ newlow = low1
+ else
+ newlow = NegativeInfinity()
+
+ if (high1 >= high2)
+ newhigh = high1
+ else
+ newhigh = PositiveInfinity()
+
+ Interval(newlow,newhigh)
+ }
+ }), this.isEmpty && that.isEmpty)
+ }
+
+ /**
+ * Implementing the narrowing strategy described in
+ * [[https://hal.archives-ouvertes.fr/hal-01657536]] (Tutorial on Static Inference of Numeric Invariants by Abstract Interpretation), page 230
+ *
+ * @param that the abstract object to be narrowed with `this`. `that` IS assumed to be smaller than `this`.
+ * @return the narrowing of the two abstract properties.
+ */
+ override def narrowing(that : Property) : Property = {
+ createProperty((this.elements, that.elements).zipped.map((x, y) => {
+ (x,y) match {
+ case (IntervalBottom, _) => IntervalBottom
+ case (_ , IntervalBottom) => x
+ case (IntervalTop, _) => y
+ case (_ , IntervalTop) => x
+ case (Interval(low1, high1), Interval(low2,high2)) =>
+ var newlow = low1
+ var newhigh = high1
+ if (low1 == NegativeInfinity()) newlow = low2
+ if (high1 == PositiveInfinity()) newhigh = high2
+ Interval(newlow,newhigh)
+ }
+ }), this.isEmpty && that.isEmpty)
+ }
+
+ } // end of Property
+} // end of BoxDomain (class)
+
+object BoxDomain {
+ /**
+ * Factory method of BoxDomain
+ */
+ def apply() = new BoxDomain()
+}
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/box/BoxDomainCore.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/box/BoxDomainCore.scala
new file mode 100644
index 00000000..21b8ff64
--- /dev/null
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/box/BoxDomainCore.scala
@@ -0,0 +1,225 @@
+/**
+ * Copyright 2018 Mattia Bottaro, Mauro Carlin
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
+
+package it.unipd.jandom.domains.numerical.box
+
+import it.unipd.jandom.domains.numerical.utils.{MathLibrary => M}
+import it.unipd.jandom.domains.{Abstraction, CompleteLatticeOperator, IntOperator, InfInt, IntNumber, PositiveInfinity, NegativeInfinity}
+import Box._
+
+/**
+ * The Box domain
+ */
+
+class BoxDomainCore extends CompleteLatticeOperator[Box]
+ with IntOperator[Box] with Abstraction[Int,Box]{
+
+ /**
+ * @inheritdoc
+ */
+ def alpha(num : Int) : Box = {
+ return Interval(IntNumber(num),IntNumber(num))
+ }
+
+ /**
+ * @inheritdoc
+ */
+ def sum(x : Box, y : Box) : Box = {
+ (x,y) match {
+ case (IntervalBottom, _) => IntervalBottom
+ case (_, IntervalBottom) => IntervalBottom
+ case (IntervalTop, _) => IntervalTop
+ case (_, IntervalTop) => IntervalTop
+ case (Interval(low1,high1),Interval(low2,high2)) => check(Interval(low1 + low2, high1 + high2))
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ def inverse(x : Box) : Box = {
+ x match {
+ case IntervalBottom => IntervalBottom
+ case IntervalTop => IntervalTop
+ case Interval(low,high) => Interval(high.inverse(),low.inverse())
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ def mult(x : Box, y : Box) : Box = {
+ (x,y) match {
+ case (IntervalBottom, _) => IntervalBottom
+ case (_, IntervalBottom) => IntervalBottom
+ case (_, Interval(IntNumber(0),IntNumber(0))) => Interval(IntNumber(0),IntNumber(0))
+ case (Interval(IntNumber(0),IntNumber(0)), _) => Interval(IntNumber(0),IntNumber(0))
+ case (IntervalTop, _) => IntervalTop
+ case (_, IntervalTop) => IntervalTop
+ case (Interval(low1,high1),Interval(low2,high2)) =>
+ val comb = Array(low1 * low2, high1 * high2, low1 * high2, high1 * low2)
+ val new_low = comb.reduceLeft(_ min _)
+ val new_high = comb.reduceLeft(_ max _)
+ return check(Interval(new_low,new_high))
+ }
+ }
+
+ /**
+ * Check if an interval is in the form [-Inf, -Inf], [+Inf, +Inf] or [-Inf, +Inf] to return a sound approsimation in order to avoid
+ * a sum with +Inf and -Inf.
+ *
+ * @param x an interval.
+ * @return a sound approsimation of the interval.
+ */
+ def check(x : Interval) : Box = {
+ x match {
+ case Interval(NegativeInfinity(), NegativeInfinity()) => Interval(NegativeInfinity(),IntNumber(Int.MinValue))
+ case Interval(PositiveInfinity(), PositiveInfinity()) => Interval(IntNumber(Int.MaxValue), PositiveInfinity())
+ case Interval(NegativeInfinity(), PositiveInfinity()) => IntervalTop
+ case _ => x
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ def division(x : Box, y : Box) : Box = {
+ (x,y) match {
+ case (IntervalBottom, _) => IntervalBottom
+ case (_, IntervalBottom) => IntervalBottom
+ case (_, Interval(IntNumber(0),IntNumber(0))) => IntervalBottom
+ case (Interval(IntNumber(0),IntNumber(0)), _) => Interval(IntNumber(0),IntNumber(0))
+ case (IntervalTop, _) => IntervalTop
+ case (_, IntervalTop) => IntervalTop
+ case (Interval (low1, high1), Interval (low2,high2)) =>
+ if (low2 >= IntNumber(1)) {
+ val new_low = (low1 / low2) min (low1 / high2)
+ val new_high = (high1 / low2) max (high1 / high2)
+ return Interval (new_low, new_high)
+ }
+ if (IntNumber(-1) >= high2) {
+ val new_low = (high1 / low2) min (high1 / high2)
+ val new_high = (low1 / low2) max (low1 / high2)
+ return Interval (new_low, new_high)
+ }
+
+ val one_to_infinite = Interval(IntNumber(1),PositiveInfinity())
+ val minus_infinite_to_minus_one = Interval(NegativeInfinity(),IntNumber(-1))
+ return lub (
+ division(Interval (low1, high1), glb(Interval (low2,high2), one_to_infinite)), // first argument
+ division(Interval (low1, high1), glb(Interval (low2,high2), minus_infinite_to_minus_one)) // second argument
+ )
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ def remainder(x : Box, y : Box) : Box = {
+ (x,y) match {
+ case (IntervalBottom, _) => IntervalBottom
+ case (_, IntervalBottom) => IntervalBottom
+ case (_, Interval(IntNumber(0),IntNumber(0))) => IntervalBottom
+ case (Interval(IntNumber(0),IntNumber(0)), _) => Interval(IntNumber(0),IntNumber(0))
+ case (IntervalTop, _) => IntervalTop
+ case (_, IntervalTop) => IntervalTop
+ case (Interval (low1, high1), Interval (low2,high2)) =>
+ if (low2 >= IntNumber(0))
+ return Interval(IntNumber(0), high2 - IntNumber(1))
+ if (high2 <= IntNumber(0))
+ return Interval(low2 + IntNumber(1), IntNumber(0))
+ return Interval(low2 + IntNumber(1), high2 - IntNumber(1))
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ def lub(x : Box, y : Box) : Box = {
+ (x, y) match {
+ case (IntervalTop, _) => IntervalTop
+ case (_, IntervalTop) => IntervalTop
+ case (IntervalBottom, _) => y
+ case (_, IntervalBottom) => x
+ case (Interval (low1, high1), Interval (low2, high2)) =>
+ val new_low = low1 min low2
+ val new_high = high1 max high2
+ return check(Interval (new_low, new_high))
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ def glb(x : Box, y : Box) : Box = {
+ (x, y) match {
+ case (IntervalTop, _) => y
+ case (_, IntervalTop) => x
+ case (IntervalBottom, _) => IntervalBottom
+ case (_, IntervalBottom) => IntervalBottom
+ case (Interval (low1, high1), Interval (low2, high2)) =>
+ val new_low = low1 max low2
+ val new_high = high1 min high2
+ if (new_low > new_high)
+ return IntervalBottom
+
+ return Interval (new_low, new_high)
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ def compare(x : Box, y : Box) : Option[Int] = {
+ (x, y) match {
+ case (IntervalBottom, IntervalBottom) => return Option(0)
+ case (IntervalBottom, _) => return Option(-1)
+ case (_, IntervalBottom) => return Option(1)
+ case (IntervalTop, IntervalTop) => return Option(0)
+ case (IntervalTop, _) => return Option(1);
+ case (_, IntervalTop) => return Option(-1);
+ case (Interval(low1, high1), Interval(low2, high2)) =>
+ if (low1 == low2 && high1 == high2)
+ return Option(0)
+ if (low1 >= low2 && high2 >= high1)
+ return Option(-1)
+ if (low2 >= low1 && high1 >= high2)
+ return Option(1)
+
+ return Option.empty
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ override def top: Box = IntervalTop
+
+ /**
+ * @inheritdoc
+ */
+ override def bottom: Box = IntervalBottom
+
+}
+
+object BoxDomainCore {
+ /**
+ * @inheritdoc
+ */
+ def apply() = new BoxDomainCore
+} // end of BoxDomainCore companion object
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/congruence/Congruence.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/congruence/Congruence.scala
index ef46e785..19621fac 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/congruence/Congruence.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/congruence/Congruence.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical.congruence
/**
@@ -9,7 +26,7 @@ package it.unipd.jandom.domains.numerical.congruence
* @author Sebastiano Valle
*/
object Congruence {
- trait Congruence
+ sealed trait Congruence
/**
* Represents the elements of the domain of the form aZ + b.
@@ -30,7 +47,7 @@ object Congruence {
* @inheritdoc
*/
override def toString: String = {
- var s : String = "\u2208 "
+ val s : String = "\u2208 "
(a, b) match {
case (None, 0) => s + "{0}"
case (None, _) => s + "{" + b + "}"
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/congruence/CongruenceDomain.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/congruence/CongruenceDomain.scala
index 6bda40fa..09979cef 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/congruence/CongruenceDomain.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/congruence/CongruenceDomain.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical.congruence
import it.unich.jandom.domains.numerical.LinearForm
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/congruence/CongruenceDomainCore.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/congruence/CongruenceDomainCore.scala
index 84d5e6e8..c2735ad8 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/congruence/CongruenceDomainCore.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/congruence/CongruenceDomainCore.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical.congruence
import it.unipd.jandom.domains.numerical.utils.{MathLibrary => M}
@@ -46,7 +63,7 @@ class CongruenceDomainCore extends CompleteLatticeOperator[Congruence]
case (Mod(a0, b0), Mod(a1, b1)) =>
val a = M.gcd(a0, a1)
val b = b0 + b1
- alpha(a,b)
+ alpha(a, b)
}
}
@@ -108,7 +125,7 @@ class CongruenceDomainCore extends CompleteLatticeOperator[Congruence]
case (Mod(a0, b0), Mod(a1, b1)) =>
val a = M.gcd(a0,M.gcd(a1, Some(b1)))
val b = b0
- alpha(a,b)
+ alpha(a, b)
}
}
@@ -128,7 +145,7 @@ class CongruenceDomainCore extends CompleteLatticeOperator[Congruence]
}
val a = M.gcd(a0, M.gcd(a1, btmp))
val b = Math.min(b0,b1)
- alpha(a,b)
+ alpha(a, b)
}
}
@@ -202,12 +219,9 @@ class CongruenceDomainCore extends CompleteLatticeOperator[Congruence]
case (_, CongruenceBottom) => Option(1)
case (Mod(a0, b0), Mod(a1, b1)) =>
- var cleqd = false
- var dleqc = false
- if(M.isDivisor(a1, a0) && M.isCongruent(b0,b1,a1))
- cleqd = true
- if(M.isDivisor(a0,a1) && M.isCongruent(b1, b0, a0))
- dleqc = true
+ val cleqd = M.isDivisor(a1, a0) && M.isCongruent(b0, b1, a1)
+ val dleqc = M.isDivisor(a0, a1) && M.isCongruent(b1, b0, a0)
+
if(cleqd && dleqc)
Option(0)
@@ -235,13 +249,15 @@ class CongruenceDomainCore extends CompleteLatticeOperator[Congruence]
/**
* Reduce the congruence abstract domain by removing redundant elements.
* All the congruences are converted in the form:
- * aZ+b with a > 0 and 0<= b < a
+ * aZ+b with a > 0 and 0 <= b < a
*/
private def standardForm(c : Congruence) : Congruence = {
c match {
case CongruenceBottom => CongruenceBottom
case Mod(None, _) => c
- case Mod(Some(a), b) => Mod(Some(a), ((b % a) + a) % a)
+ case Mod(Some(a), b) =>
+ val a1 = Math.abs(a)
+ Mod(Some(a1), ((b % a1) + a1) % a1)
}
}
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/constant/Constant.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/constant/Constant.scala
index 6f52ae73..b040021c 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/constant/Constant.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/constant/Constant.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical.constant
/**
@@ -10,7 +27,7 @@ package it.unipd.jandom.domains.numerical.constant
* @author Sebastiano Valle
*/
object Constant {
- trait Constant
+ sealed trait Constant
// constant value
case class Const (num : Int) extends Constant {
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/constant/ConstantDomain.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/constant/ConstantDomain.scala
index ac1395bb..282cb20c 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/constant/ConstantDomain.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/constant/ConstantDomain.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical.constant
import it.unich.jandom.domains.numerical.LinearForm
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/constant/ConstantDomainCore.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/constant/ConstantDomainCore.scala
index ac5b8fd8..4b689754 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/constant/ConstantDomainCore.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/constant/ConstantDomainCore.scala
@@ -1,10 +1,27 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical.constant
import it.unipd.jandom.domains.{Abstraction, CompleteLatticeOperator, IntOperator}
import Constant._
/**
- * Constant domain, checks if a given variable is constant
+ * Constant domain, checks if a given variable is constant
* (and equal to a value `num`) in a program point.
*
* @author Mirko Bez
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/mod/ModK.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/mod/ModK.scala
index d4c54554..df24eef5 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/mod/ModK.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/mod/ModK.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical.mod
/**
@@ -10,7 +27,7 @@ package it.unipd.jandom.domains.numerical.mod
object ModK {
private var k = 1
- trait ModK
+ sealed trait ModK
/** Represents the elements in the equivalence class num modulo k */
case class RestClass(num : Int) extends ModK {
override def toString: String = k match {
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/mod/ModKDomain.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/mod/ModKDomain.scala
index 14057695..f232ec48 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/mod/ModKDomain.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/mod/ModKDomain.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
/**
* Copyright 201K, 2016 Gianluca Amato
*
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/mod/ModKDomainCore.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/mod/ModKDomainCore.scala
index 4309cec8..f96e82ee 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/mod/ModKDomainCore.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/mod/ModKDomainCore.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical.mod
import it.unipd.jandom.domains.{Abstraction, CompleteLatticeOperator, IntOperator}
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/parity/Parity.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/parity/Parity.scala
index f7555104..19e82558 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/parity/Parity.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/parity/Parity.scala
@@ -1,7 +1,24 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical.parity
object Parity {
- trait Parity
+ sealed trait Parity
// multiples of 2
case object Even extends Parity
// multiples of 2 plus 1
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/parity/ParityDomain.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/parity/ParityDomain.scala
index ef5f410d..9544de74 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/parity/ParityDomain.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/parity/ParityDomain.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
/**
* Copyright 2013, 2016 Gianluca Amato
*
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/parity/ParityDomainCore.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/parity/ParityDomainCore.scala
index f1edbb00..81b59bd0 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/parity/ParityDomainCore.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/parity/ParityDomainCore.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical.parity
import it.unipd.jandom.domains.{Abstraction, CompleteLatticeOperator, IntOperator}
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ES01.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ES01.scala
index 3f2e8c4a..6dc249ae 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ES01.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ES01.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical.sign
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ESeq.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ESeq.scala
index 89cc7e63..dfb17265 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ESeq.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ESeq.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical.sign
import Sign._
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ESeqDomain.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ESeqDomain.scala
index 3f92e071..9a27b0e9 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ESeqDomain.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ESeqDomain.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical.sign
import it.unich.jandom.domains.numerical.LinearForm
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ESeqDomainCore.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ESeqDomainCore.scala
index b10281b8..c164c30b 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ESeqDomainCore.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ESeqDomainCore.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical.sign
import it.unipd.jandom.domains.numerical.sign.Sign._
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ExtendedSigns01Domain.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ExtendedSigns01Domain.scala
index aa9be590..0b0fda7f 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ExtendedSigns01Domain.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ExtendedSigns01Domain.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical.sign
import it.unich.jandom.domains.numerical.LinearForm
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ExtendedSigns01DomainCore.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ExtendedSigns01DomainCore.scala
index abc50070..55eb9029 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ExtendedSigns01DomainCore.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/ExtendedSigns01DomainCore.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical.sign
import it.unipd.jandom.domains.{Abstraction, CompleteLatticeOperator, IntOperator}
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/Sign.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/Sign.scala
index 1358de1c..e1113eec 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/Sign.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/Sign.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical.sign
/**
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/SignDomain.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/SignDomain.scala
index 9e911637..cc2df048 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/SignDomain.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/SignDomain.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
/**
* Copyright 2013, 2016 Gianluca Amato
*
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/SignDomainCore.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/SignDomainCore.scala
index 0f67fe6c..54ea4028 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/SignDomainCore.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/sign/SignDomainCore.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical.sign
import it.unipd.jandom.domains.{Abstraction, CompleteLatticeOperator, IntOperator}
diff --git a/core/src/main/scala/it/unipd/jandom/domains/numerical/utils/MathLibrary.scala b/core/src/main/scala/it/unipd/jandom/domains/numerical/utils/MathLibrary.scala
index 85b5e446..5e920057 100644
--- a/core/src/main/scala/it/unipd/jandom/domains/numerical/utils/MathLibrary.scala
+++ b/core/src/main/scala/it/unipd/jandom/domains/numerical/utils/MathLibrary.scala
@@ -1,3 +1,20 @@
+/**
+ * Copyright 2017 Mirko Bez, Stefano Munari, Sebastiano Valle
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You shosuld have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
package it.unipd.jandom.domains.numerical.utils
/**
diff --git a/core/src/test/ppl/it/unich/jandom/domains/numerical/ppl/PPLDomainSuite.scala b/core/src/test/ppl/it/unich/jandom/domains/numerical/ppl/PPLDomainSuite.scala
index 9d7f61af..e9d03294 100644
--- a/core/src/test/ppl/it/unich/jandom/domains/numerical/ppl/PPLDomainSuite.scala
+++ b/core/src/test/ppl/it/unich/jandom/domains/numerical/ppl/PPLDomainSuite.scala
@@ -85,8 +85,6 @@ class PPLDomainSuiteOctagon extends { val dom = PPLDomain[Octagonal_Shape_double
}
describe("Test for various operations") {
- val obj = full.linearAssignment(0, 0)
- val obj2 = full.linearAssignment(1, 0)
val obj3 = full.linearAssignment(2, 0)
val obj4 = full.linearAssignment(2, 1)
val obj5 = obj4 union obj3
@@ -110,7 +108,7 @@ class PPLDomainSuiteOctagon extends { val dom = PPLDomain[Octagonal_Shape_double
describe("Test that disequality do not crash") {
val obj = full.linearAssignment(0, 0)
- val dis = obj.linearDisequality(LinearForm(0, 1, 0, 0))
+ obj.linearDisequality(LinearForm(0, 1, 0, 0))
}
describe("Test string conversion") {
@@ -121,8 +119,8 @@ class PPLDomainSuiteOctagon extends { val dom = PPLDomain[Octagonal_Shape_double
}
describe("Test string conversion for high-dimensional spaces") {
- val a = Array.fill(34)(0.0)
- a(27) = 1.0
+ val a = Array.fill(34)(0)
+ a(27) = 1
val obj3 = dom.top(33).linearInequality(LinearForm.v(27))
assertResult("[ -v27 >= 0 ]") { obj3.toString }
}
diff --git a/core/src/test/ppl/it/unich/jandom/targets/JVMSootSuite.scala b/core/src/test/ppl/it/unich/jandom/targets/JVMSootSuite.scala
index 88e8f14a..242dd555 100644
--- a/core/src/test/ppl/it/unich/jandom/targets/JVMSootSuite.scala
+++ b/core/src/test/ppl/it/unich/jandom/targets/JVMSootSuite.scala
@@ -18,6 +18,7 @@
package it.unich.jandom.targets
+import scala.collection.JavaConverters._
import org.scalatest.FunSuite
import it.unich.jandom.domains.numerical.ppl.PPLDomain
import it.unich.jandom.domains.objects.PairSharingDomain
@@ -25,7 +26,6 @@ import it.unich.jandom.domains.objects.UP
import it.unich.jandom.parsers.NumericalPropertyParser
import it.unich.jandom.targets.jvmsoot._
import parma_polyhedra_library.C_Polyhedron
-import soot._
import it.unich.jandom.domains.objects.PairSharingDomain
/**
@@ -35,7 +35,6 @@ import it.unich.jandom.domains.objects.PairSharingDomain
*
*/
class JVMSootSuite extends FunSuite with SootTests {
- import scala.collection.JavaConversions._
val scene = initSoot()
val c = scene.loadClassAndSupport("javatest.SimpleTest")
@@ -95,7 +94,7 @@ class JVMSootSuite extends FunSuite with SootTests {
val inte = new JimpleRecursiveInterpretation[params.type](scene, params)
params.interpretation = Some(inte)
test(s"Jimple inter-procedural sharing analysis: ${methodName}") {
- val input = params.domain.top(c.getMethodByName(methodName).getParameterTypes().asInstanceOf[java.util.List[Type]])
+ val input = params.domain.top(c.getMethodByName(methodName).getParameterTypes().asScala)
try {
inte.compute(method, input)
assert(inte(method, input).prop === psdom(prop, jmethod.outputTypes))
@@ -116,7 +115,6 @@ class JVMSootSuite extends FunSuite with SootTests {
for ((methodName, propString) <- jimpleNumericalTests) {
val method = c.getMethodByName(methodName)
- val jmethod = new JimpleMethod(method)
val params = new Parameters[JimpleMethod] {
val domain = new SootFrameNumericalDomain(JVMSootSuite.this.numdomain)
io = true
diff --git a/core/src/test/ppl/it/unich/jandom/targets/SootFrameNumericalDomainSuite.scala b/core/src/test/ppl/it/unich/jandom/targets/SootFrameNumericalDomainSuite.scala
index a799096e..2595e9a9 100644
--- a/core/src/test/ppl/it/unich/jandom/targets/SootFrameNumericalDomainSuite.scala
+++ b/core/src/test/ppl/it/unich/jandom/targets/SootFrameNumericalDomainSuite.scala
@@ -46,11 +46,9 @@ class SootFrameNumericalDomainSuite extends FunSuite {
val env = Environment()
val parser = new NumericalPropertyParser(env)
val prop = parser.parseProperty("v0 == v0 && v1 + v2 == 0 && v1 <= 4", dom.numdom).get
- val absframe = dom(prop, types)
intercept[AssertionError] { dom(prop, Seq(soot.IntType.v(), classAType, soot.DoubleType.v())) }
intercept[AssertionError] { dom(prop, Seq(soot.IntType.v(), soot.DoubleType.v(), classAType)) }
intercept[AssertionError] { dom(prop, Seq(classAType, soot.IntType.v())) }
- val fullnumframe = dom(prop, soot.IntType.v())
intercept[AssertionError] { dom(prop, classAType) }
}
diff --git a/core/src/test/scala/it/unich/jandom/JandomFasterBench.scala b/core/src/test/scala/it/unich/jandom/JandomFasterBench.scala
index e7a064c1..38c201b3 100644
--- a/core/src/test/scala/it/unich/jandom/JandomFasterBench.scala
+++ b/core/src/test/scala/it/unich/jandom/JandomFasterBench.scala
@@ -1,51 +1,46 @@
/**
- * Copyright 2014, 2016 Gianluca Amato
- *
- * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
- * JANDOM is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * JANDOM is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of a
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with JANDOM. If not, see .
- */
+ * Copyright 2014, 2016, 2017 Gianluca Amato
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+
package it.unich.jandom
-import java.io.File
-import java.io.FileReader
-
-import it.unich.jandom.domains.numerical.BoxDoubleDomain
-import it.unich.jandom.parsers.FastParser
+import it.unich.jandom.benchmark.FASTLoader
+import it.unich.jandom.domains.numerical.NumericalDomain
+import it.unich.jandom.domains.numerical.ppl.PPLDomainMacro
import it.unich.jandom.targets.lts.LTS
import it.unich.jandom.targets.parameters.IterationStrategy
import it.unich.jandom.targets.parameters.NarrowingSpecs._
import it.unich.jandom.targets.parameters.WideningSpecs._
-import it.unich.jandom.domains.numerical.ppl.PPLDomainMacro
import parma_polyhedra_library.C_Polyhedron
-/**
- * Example program using ''Jandom'' to analyze the Alice benchmarks and
- * compare the results with different parameters. In this moment, it compares
- * the result of the analyisis with standard Kleene iteration and worklist
- * based ones.
- */
-object JandomFasterBench extends App {
- def fastModelAnalyze(model: File) = {
- println(s"------>${model}")
+ * Example program using ''Jandom'' to analyze the Alice benchmarks and
+ * compare the results with different parameters. In this moment, it compares
+ * the result of the analyisis with standard Kleene iteration and worklist
+ * based ones.
+
+object JandomFasterBench extends App with FASTLoader {
- val source = new FileReader(model)
- val parsed = FastParser().parse(source)
- source.close()
- val program = parsed.get
- val params = new targets.Parameters[LTS] { val domain = PPLDomainMacro[C_Polyhedron] }
+ def fastModelAnalyze(program: LTS) {
+ println(s"------> ${program.name}")
+
+ val params = new targets.Parameters[LTS] {
+ val domain: NumericalDomain = PPLDomainMacro[C_Polyhedron]
+ }
// We specify some parameters for the analysis, although these are the standard ones.
params.widening = DefaultWidening
@@ -68,8 +63,8 @@ object JandomFasterBench extends App {
// params.debugWriter.flush()
if (program.locations exists (loc => ann(loc) != ann2(loc))) {
- println("DIFFERENT BEHAVIOURS: " + model)
- println(s"Times: ${tann1} vs ${tann2}")
+ println("DIFFERENT BEHAVIOURS: " + program.name)
+ println(s"Times: $tann1 vs $tann2")
println("WIDENINGS: " + program.locations.filter(program.isJoinNode).map(_.name).mkString(", "))
println("BETTER 1: " + program.locations.filter(loc => ann(loc) < ann2(loc)).map(_.name).mkString(", "))
println("BETTER 2: " + program.locations.filter(loc => ann(loc) > ann2(loc)).map(_.name).mkString(", "))
@@ -78,11 +73,6 @@ object JandomFasterBench extends App {
}
}
- val resources = getClass.getResource("/fast/").toURI;
-
- // This analyzes all models (does not terminate for descending2 with
- for (model <- new File(resources).listFiles()) fastModelAnalyze(model)
-
- // This is if we want to analyze a specificic model
- // fastModelAnalyze(new File(resources.resolve("descending.fst")))
+ for (lts <- ltss) fastModelAnalyze(lts)
}
+*/
\ No newline at end of file
diff --git a/core/src/test/scala/it/unich/jandom/JandomParallelotopeBench.scala b/core/src/test/scala/it/unich/jandom/JandomParallelotopeBench.scala
index 5b42f07e..adb1562d 100644
--- a/core/src/test/scala/it/unich/jandom/JandomParallelotopeBench.scala
+++ b/core/src/test/scala/it/unich/jandom/JandomParallelotopeBench.scala
@@ -1,44 +1,39 @@
/**
- * Copyright 2016 Jandom Team
- *
- * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
- * JANDOM is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * JANDOM is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of a
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with JANDOM. If not, see .
- */
+ * Copyright 2016, 2017 Jandom Team
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+
package it.unich.jandom
-import java.io.File
-
+import it.unich.jandom.benchmark.FASTLoader
import it.unich.jandom.domains.DimensionFiberedProperty
-import it.unich.jandom.domains.numerical.BoxRationalDomain
-import it.unich.jandom.domains.numerical.LinearForm
-import it.unich.jandom.domains.numerical.ParallelotopeRationalDomain
-import it.unich.jandom.domains.numerical.ProductDomain
+import it.unich.jandom.domains.numerical._
import it.unich.jandom.domains.numerical.ppl.PPLDomain
-import it.unich.jandom.parsers.FastParser
import it.unich.jandom.targets.lts.LTS
import it.unich.jandom.targets.parameters.NarrowingSpecs._
import it.unich.jandom.targets.parameters.WideningSpecs._
import parma_polyhedra_library.C_Polyhedron
-/**
- * Example program using ''Jandom'' to analyze the Alice benchmarks and
- * compare the results with different parameters. At the moment, it compares
- * the result of separately computing using box and parallelotope with respect
- * to using their product.
- */
-object JandomParallelotopeBench extends App {
+
+ * Example program using ''Jandom'' to analyze the Alice benchmarks and
+ * compare the results with different parameters. At the moment, it compares
+ * the result of separately computing using box and parallelotope with respect
+ * to using their product.
+
+object JandomParallelotopeBench extends App with FASTLoader {
var totalEquals = 0
var totalBestReduced = 0
@@ -47,7 +42,7 @@ object JandomParallelotopeBench extends App {
var totalPrograms = 0
def CStoPolyehdra(dimension: Int, c: Seq[LinearForm]) = {
- val d = PPLDomain[C_Polyhedron]
+ val d = PPLDomain[C_Polyhedron]()
c.foldLeft(d.top(dimension)) { (p: d.Property, lf: LinearForm) => p.linearInequality(lf) }
}
@@ -55,17 +50,15 @@ object JandomParallelotopeBench extends App {
(for ((loc, prop) <- m) yield loc.name + " => " + prop.mkString(program.env.variables)).mkString(", ")
}
- def fastModelAnalyze(model: File) = {
+ def fastModelAnalyze(program: LTS) {
totalPrograms += 1
- println(s"------>${model}")
-
- val source = scala.io.Source.fromFile(model).getLines.mkString("\n")
- val parsed = FastParser().parse(source)
- val program = parsed.get
+ println(s"------>${program.name}")
println("WIDENINGS: " + program.locations.filter(program.isJoinNode).map(_.name).mkString(", "))
- val params1 = new targets.Parameters[LTS] { val domain = new ProductDomain(BoxRationalDomain(), ParallelotopeRationalDomain(-1)) }
+ val params1 = new targets.Parameters[LTS] {
+ val domain = new ProductDomain(BoxRationalDomain(), ParallelotopeRationalDomain(-1))
+ }
params1.widening = DelayedWidening(DefaultWidening, 1)
params1.narrowing = DelayedNarrowing(DefaultNarrowing, 1)
//params1.debugWriter = new java.io.PrintWriter(System.out)
@@ -74,20 +67,24 @@ object JandomParallelotopeBench extends App {
val t1 = System.currentTimeMillis
val productAnn = program.analyze(params1)
- val tann1 = System.currentTimeMillis - t1
+ val tann1 = System.currentTimeMillis - t1
- val params2 = new targets.Parameters[LTS] { val domain = BoxRationalDomain() }
+ val params2 = new targets.Parameters[LTS] {
+ val domain = BoxRationalDomain()
+ }
params2.widening = DelayedWidening(DefaultWidening, 1)
params2.narrowing = DelayedNarrowing(DefaultNarrowing, 1)
// params2.debugWriter = new java.io.PrintWriter(System.out)
- program.analyze(params2) // warmup JVM
+ program.analyze(params2) // warmup JVMunchecked
//params2.debugWriter.flush()
val t2 = System.currentTimeMillis
val boxAnn = program.analyze(params2)
val tann2 = System.currentTimeMillis - t2
- val params3 = new targets.Parameters[LTS] { val domain = ParallelotopeRationalDomain(1) }
+ val params3 = new targets.Parameters[LTS] {
+ val domain = ParallelotopeRationalDomain(1)
+ }
params3.widening = DelayedWidening(DefaultWidening, 1)
params3.narrowing = DelayedNarrowing(DefaultNarrowing, 1)
//params6Bis.debugWriter = new java.io.PrintWriter(System.out)
@@ -98,7 +95,7 @@ object JandomParallelotopeBench extends App {
val parAnn = program.analyze(params3)
val tann3 = System.currentTimeMillis - t3
- val cprod = productAnn mapValues { p => CStoPolyehdra(p.p1.dimension, p.p1.constraints) intersection (CStoPolyehdra(p.p2.dimension, p.p2.constraints)) }
+ val cprod = productAnn mapValues { p => CStoPolyehdra(p.p1.dimension, p.p1.constraints) intersection CStoPolyehdra(p.p2.dimension, p.p2.constraints) }
val cbox = boxAnn mapValues { p => CStoPolyehdra(p.dimension, p.constraints) }
val cpar = parAnn mapValues { p => CStoPolyehdra(p.dimension, p.constraints) }
@@ -109,29 +106,29 @@ object JandomParallelotopeBench extends App {
print("Product: ")
println(mkString(program, cprod))
- val comp = cprod map { case (loc, v) => (loc -> v.tryCompareTo(cbox(loc) intersection (cpar(loc)))) }
-
- println("COUNT EQUALS: " + comp.count(_._2 == Some(0)))
- println("COUNT BETTER REDUCED PRODUCT: " + comp.count(_._2 == Some(-1)))
- println("COUNT BETTER SEPARATE ANALYSIS: " + comp.count(_._2 == Some(1)))
- println("COUNT UNCOMPARABLES: " + comp.count(_._2 == None))
- totalEquals += comp.count(_._2 == Some(0))
- totalBestReduced += comp.count(_._2 == Some(-1))
- totalBestSeparate += comp.count(_._2 == Some(1))
- totalUncomparable += comp.count(_._2 == None)
-
- println("EQUALS: " + program.locations.filter(comp(_) == Some(0)).map(_.name).mkString(", "))
- println("BETTER PRO: " + program.locations.filter(comp(_) == Some(-1)).map(_.name).mkString(", "))
- println("BETTER INT: " + program.locations.filter(comp(_) == Some(1)).map(_.name).mkString(", "))
- println("UNCOMPARABLES: " + program.locations.filter(comp(_) == None).map(_.name).mkString(", "))
+ val comp = cprod map { case (loc, v) => loc -> v.tryCompareTo(cbox(loc) intersection cpar(loc)) }
+
+ println(s"TIME REQUIRED: product: $tann1 box: $tann2 ptope: $tann3")
+ println("COUNT EQUALS: " + comp.count(_._2 contains 0))
+ println("COUNT BETTER REDUCED PRODUCT: " + comp.count(_._2 contains -1))
+ println("COUNT BETTER SEPARATE ANALYSIS: " + comp.count(_._2 contains 1))
+ println("COUNT UNCOMPARABLES: " + comp.count(_._2.isEmpty))
+ totalEquals += comp.count(_._2 contains 0)
+ totalBestReduced += comp.count(_._2 contains -1)
+ totalBestSeparate += comp.count(_._2 contains 1)
+ totalUncomparable += comp.count(_._2.isEmpty)
+
+ println("EQUALS: " + program.locations.filter(comp(_) contains 0).map(_.name).mkString(", "))
+ println("BETTER PRO: " + program.locations.filter(comp(_) contains -1).map(_.name).mkString(", "))
+ println("BETTER INT: " + program.locations.filter(comp(_) contains 1).map(_.name).mkString(", "))
+ println("UNCOMPARABLES: " + program.locations.filter(comp(_).isEmpty).map(_.name).mkString(", "))
}
val program: Option[String] = None
- var badPrograms = Seq[File]()
+ var badPrograms = Seq[LTS]()
if (program.isEmpty) {
- val resources = getClass.getResource("/fast/").toURI;
- for (model <- new File(resources).listFiles()) {
+ for (model <- ltss) {
try {
fastModelAnalyze(model)
} catch {
@@ -140,17 +137,17 @@ object JandomParallelotopeBench extends App {
}
}
} else {
- val resources2 = getClass.getResource("/fast/"+program.get).toURI;
- val file = new File(resources2)
- fastModelAnalyze(file)
+ val model = ltss find (lts => program contains lts.name)
+ model foreach fastModelAnalyze
}
println("\nFinal results:")
println("---------------")
- println(s"Number of programs: ${totalPrograms}")
+ println(s"Number of programs: $totalPrograms")
println(s"Bad programs: ${badPrograms.mkString("\n")}")
- println(s"Total equals: ${totalEquals}")
- println(s"Total best reduced product: ${totalBestReduced}")
- println(s"Total best separate analysis: ${totalBestSeparate}")
- println(s"Total uncomparables: ${totalUncomparable}")
+ println(s"Total equals: $totalEquals")
+ println(s"Total best reduced product: $totalBestReduced")
+ println(s"Total best separate analysis: $totalBestSeparate")
+ println(s"Total uncomparables: $totalUncomparable")
}
+*/
\ No newline at end of file
diff --git a/core/src/test/scala/it/unich/jandom/JandomSumBench.scala b/core/src/test/scala/it/unich/jandom/JandomSumBench.scala
index 6ace694c..3bdf539f 100644
--- a/core/src/test/scala/it/unich/jandom/JandomSumBench.scala
+++ b/core/src/test/scala/it/unich/jandom/JandomSumBench.scala
@@ -1,44 +1,38 @@
/**
- * Copyright 2014, 2016 Gianluca Amato
- *
- * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
- * JANDOM is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * JANDOM is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of a
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with JANDOM. If not, see .
- */
+ * Copyright 2014, 2016, 2017 Gianluca Amato
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+
package it.unich.jandom
-import java.io.File
-import java.io.FileReader
-
+import it.unich.jandom.benchmark.FASTLoader
import it.unich.jandom.domains.DimensionFiberedProperty
-import it.unich.jandom.domains.numerical.BoxDoubleDomain
-import it.unich.jandom.domains.numerical.LinearForm
-import it.unich.jandom.domains.numerical.ParallelotopeDomain
-import it.unich.jandom.domains.numerical.SumIntParallelotopeDomain
+import it.unich.jandom.domains.numerical._
import it.unich.jandom.domains.numerical.ppl.PPLDomain
-import it.unich.jandom.parsers.FastParser
import it.unich.jandom.targets.lts.LTS
import it.unich.jandom.targets.parameters.WideningSpecs._
import parma_polyhedra_library.C_Polyhedron
-/**
- * Example program using ''Jandom'' to analyze the Alice benchmarks and
- * compare the results with different parameters. In this moment, it compares
- * the result of the analyisis with standard Kleene iteration and worklist
- * based ones.
- */
-object JandomSumBench extends App {
+
+ * Example program using ''Jandom'' to analyze the Alice benchmarks and
+ * compare the results with different parameters. In this moment, it compares
+ * the result of the analyisis with standard Kleene iteration and worklist
+ * based ones.
+
+object JandomSumBench extends App with FASTLoader {
var totalEquals = 0
var totalBestSum = 0
@@ -47,7 +41,7 @@ object JandomSumBench extends App {
var totalPrograms = 0
def CStoPolyehdra(dimension: Int, c: Seq[LinearForm]) = {
- val d = PPLDomain[C_Polyhedron]
+ val d = PPLDomain[C_Polyhedron]()
c.foldLeft(d.top(dimension)) { (p: d.Property, lf: LinearForm) => p.linearInequality(lf) }
}
@@ -55,18 +49,15 @@ object JandomSumBench extends App {
(for ((loc, prop) <- m) yield loc.name + " => " + prop.mkString(program.env.variables)).mkString(", ")
}
- def fastModelAnalyze(model: File) = {
+ def fastModelAnalyze(program: LTS) {
totalPrograms += 1
- println(s"------>${model}")
-
- val source = new FileReader(model)
- val parsed = FastParser().parse(source)
- source.close()
- val program = parsed.get
+ println(s"------>${program.name}")
println("WIDENINGS: " + program.locations.filter(program.isJoinNode).map(_.name).mkString(", "))
- val params = new targets.Parameters[LTS] { val domain = BoxDoubleDomain(false) }
+ val params = new targets.Parameters[LTS] {
+ val domain = BoxDoubleDomain()
+ }
params.widening = DelayedWidening(DefaultWidening, 3) // needed for parallelotopes
program.analyze(params) // warmup JVM
@@ -74,7 +65,9 @@ object JandomSumBench extends App {
val ann1 = program.analyze(params)
val tann1 = System.currentTimeMillis - t1
- val params2 = new targets.Parameters[LTS] { val domain = SumIntParallelotopeDomain() }
+ val params2 = new targets.Parameters[LTS] {
+ val domain = SumBoxDoubleParallelotopeRationDomain()
+ }
params2.widening = DelayedWidening(DefaultWidening, 3) // needed for parallelotopes
//params2.debugWriter = new java.io.PrintWriter(System.out)
program.analyze(params2) // warmup JVM
@@ -84,9 +77,11 @@ object JandomSumBench extends App {
val ann2 = program.analyze(params2)
val tann2 = System.currentTimeMillis - t2
- val params3 = new targets.Parameters[LTS] { val domain = ParallelotopeDomain() }
+ val params3 = new targets.Parameters[LTS] {
+ val domain = ParallelotopeRationalDomain()
+ }
params3.widening = DelayedWidening(DefaultWidening, 3) // needed for parallelotopes
- //params3.debugWriter = new java.io.PrintWriter(System.out)
+ //params3.debugWriter = tann1new java.io.PrintWriter(System.out)
program.analyze(params3) // warmup JVM
//params3.debugWriter.flush()
@@ -99,7 +94,7 @@ object JandomSumBench extends App {
val cann2 = ann2 mapValues { p => CStoPolyehdra(p.dimension, p.constraints) }
val cann3 = ann3 mapValues { p => CStoPolyehdra(p.dimension, p.constraints) }
- println(s"Times: ${tann1} vs ${tann2}")
+ println(s"Times: box $tann1 sum: $tann2 ptope: $tann3")
print("Box: ")
println(mkString(program, cann1))
print("PTope: ")
@@ -108,7 +103,7 @@ object JandomSumBench extends App {
println(mkString(program, cann2))
// SOSTITUIRE cann1 con cann3 se si vuole il confronto con i Parallelotopi.
- val comp = cann2 map { case (loc, v) => (loc -> v.tryCompareTo(cann1(loc) intersection cann3(loc))) }
+ val comp = cann2 map { case (loc, v) => loc -> v.tryCompareTo(cann1(loc) intersection cann3(loc)) }
//comparing sum with box
//val comp = cann2 map { case (loc, v) => (loc -> v.tryCompareTo(cann1(loc))) }
@@ -116,32 +111,30 @@ object JandomSumBench extends App {
//comparing sum with parallelotope
//val comp = cann2 map { case (loc, v) => (loc -> v.tryCompareTo(cann3(loc))) }
- println("COUNT EQUALS: " + comp.count(_._2 == Some(0)))
- println("COUNT BETTER SUM: " + comp.count(_._2 == Some(-1)))
- println("COUNT BETTER OTHER: " + comp.count(_._2 == Some(1)))
- println("COUNT UNCOMPARABLES: " + comp.count(_._2 == None))
+ println("COUNT EQUALS: " + comp.count(_._2 contains 0))
+ println("COUNT BETTER SUM: " + comp.count(_._2 contains -1))
+ println("COUNT BETTER OTHER: " + comp.count(_._2 contains 1))
+ println("COUNT UNCOMPARABLES: " + comp.count(_._2.isEmpty))
- totalEquals += comp.count(_._2 == Some(0))
- totalBestSum += comp.count(_._2 == Some(-1))
- totalBestOther += comp.count(_._2 == Some(1))
- totalUncomparable += comp.count(_._2 == None)
+ totalEquals += comp.count(_._2 contains 0)
+ totalBestSum += comp.count(_._2 contains -1)
+ totalBestOther += comp.count(_._2 contains 1)
+ totalUncomparable += comp.count(_._2.isEmpty)
//println("DIFFERENT BEHAVIOURS: " + model)
//println(s"Times: ${tann1} vs ${tann2}")
//println("WIDENINGS: " + program.locations.filter(program.isJoinNode).map(_.name).mkString(", "))
- println("EQUALS: " + program.locations.filter(comp(_) == Some(0)).map(_.name).mkString(", "))
- println("BETTER SUM: " + program.locations.filter(comp(_) == Some(-1)).map(_.name).mkString(", "))
- println("BETTER OTHER: " + program.locations.filter(comp(_) == Some(1)).map(_.name).mkString(", "))
- println("UNCOMPARABLES: " + program.locations.filter(comp(_) == None).map(_.name).mkString(", "))
+ println("EQUALS: " + program.locations.filter(comp(_) contains 0).map(_.name).mkString(", "))
+ println("BETTER SUM: " + program.locations.filter(comp(_) contains -1).map(_.name).mkString(", "))
+ println("BETTER OTHER: " + program.locations.filter(comp(_) contains 1).map(_.name).mkString(", "))
+ println("UNCOMPARABLES: " + program.locations.filter(comp(_).isEmpty).map(_.name).mkString(", "))
}
- val resources = getClass.getResource("/fast/").toURI;
-
- var badPrograms = Seq[File]()
+ var badPrograms = Seq[LTS]()
// This analyzes all models (does not terminate for descending2 with
- for (model <- new File(resources).listFiles()) {
+ for (model <- ltss) {
try {
fastModelAnalyze(model)
} catch {
@@ -155,11 +148,11 @@ object JandomSumBench extends App {
println("\nFinal results:")
println("---------------")
- println(s"Number of programs: ${totalPrograms}")
+ println(s"Number of programs: $totalPrograms")
println(s"""Bad programs: ${badPrograms.mkString("\n")}""")
- println(s"Total equals: ${totalEquals}")
- println(s"Total best sum: ${totalBestSum}")
- println(s"Total best other: ${totalBestOther}")
- println(s"Total uncomparables: ${totalUncomparable}")
-
+ println(s"Total equals: $totalEquals")
+ println(s"Total best sum: $totalBestSum")
+ println(s"Total best other: $totalBestOther")
+ println(s"Total uncomparables: $totalUncomparable")
}
+*/
diff --git a/core/src/test/scala/it/unich/jandom/domains/AbstractDomainSuite.scala b/core/src/test/scala/it/unich/jandom/domains/AbstractDomainSuite.scala
index d18871ef..49098935 100644
--- a/core/src/test/scala/it/unich/jandom/domains/AbstractDomainSuite.scala
+++ b/core/src/test/scala/it/unich/jandom/domains/AbstractDomainSuite.scala
@@ -1,5 +1,5 @@
/**
- * Copyright 2014 Gianluca Amato
+ * Copyright 2014, 2016 Gianluca Amato
*
* This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
* JANDOM is free software: you can redistribute it and/or modify
@@ -26,7 +26,7 @@ import org.scalatest.prop.{TableDrivenPropertyChecks, TableFor1, TableFor2}
* @author Gianluca Amato
*/
trait AbstractDomainSuite extends FunSpec with TableDrivenPropertyChecks {
-
+
/**
* The abstract domain to test
*/
@@ -118,11 +118,10 @@ trait AbstractDomainSuite extends FunSpec with TableDrivenPropertyChecks {
describe("The narrowing method") {
it("it returns an abstract object which is a possible lower bound of the first parameter") {
forAll(someCoupleProperties) { (p1, p2) =>
- if (p2 <= p1) {
- // the check is convoluted since we only have an approximation of the abstract ordering
- assert(!((p1 narrowing p2) > p1))
- assert(!((p1 narrowing p2) < p2))
- }
+ // the check is convoluted since we only have an approximation of the abstract ordering
+ assert(!((p1 narrowing p2) > p1))
+ // the following test depends on the fact that intersection is precise enough
+ assert(!((p1 narrowing p2) < (p1 intersection p2)))
}
}
}
diff --git a/core/src/test/scala/it/unich/jandom/domains/DomainTransformationSuite.scala b/core/src/test/scala/it/unich/jandom/domains/DomainTransformationSuite.scala
index 79f5e35b..da2e1952 100644
--- a/core/src/test/scala/it/unich/jandom/domains/DomainTransformationSuite.scala
+++ b/core/src/test/scala/it/unich/jandom/domains/DomainTransformationSuite.scala
@@ -20,11 +20,10 @@ package it.unich.jandom.domains
import org.scalatest.FunSuite
-import breeze.linalg.DenseMatrix
-import breeze.linalg.DenseVector
+import it.unich.jandom.utils.numberext._
import it.unich.jandom.domains.numerical.BoxDoubleDomain
import it.unich.jandom.domains.numerical.NumericalDomain
-import it.unich.jandom.domains.numerical.ParallelotopeDomain
+import it.unich.jandom.domains.numerical.ParallelotopeRationalDomain
/**
* The test suite for domain transformations.
@@ -32,32 +31,31 @@ import it.unich.jandom.domains.numerical.ParallelotopeDomain
*/
class DomainTransformationSuite extends FunSuite {
val boxdom = BoxDoubleDomain()
- val pardom = ParallelotopeDomain()
+ val pardom = ParallelotopeRationalDomain()
test("Parallelotope to BoxDouble") {
- val transform = implicitly[DomainTransformation[ParallelotopeDomain, BoxDoubleDomain]]
- val diamond = pardom(DenseVector(-1, -1), DenseMatrix((1.0, 1.0), (1.0, -1.0)), DenseVector(1, 1))
+ val transform = implicitly[DomainTransformation[ParallelotopeRationalDomain, BoxDoubleDomain]]
+ val diamond = pardom(Bounds(-1, -1), DenseMatrix(DenseVector(1.0, 1.0), DenseVector(1.0, -1.0)), Bounds(1, 1))
val box = boxdom(Array(-1, -1), Array(1, 1))
assertResult(box) { transform(pardom,boxdom)(diamond) }
}
test("Parallelotope to Parallelotope") {
- val transform = implicitly[DomainTransformation[ParallelotopeDomain, ParallelotopeDomain]]
- val diamond = pardom(DenseVector(-1, -1), DenseMatrix((1.0, 1.0), (1.0, -1.0)), DenseVector(1, 1))
+ val transform = implicitly[DomainTransformation[ParallelotopeRationalDomain, ParallelotopeRationalDomain]]
+ val diamond = pardom(Bounds(-1, -1), DenseMatrix(DenseVector(1.0, 1.0), DenseVector(1.0, -1.0)), Bounds(1, 1))
assertResult(diamond) { transform(pardom,pardom)(diamond) }
}
test("Box to Parallelotope") {
- val transform = implicitly[DomainTransformation[BoxDoubleDomain, ParallelotopeDomain]]
- val boxptope = pardom(DenseVector(-1, -1), DenseMatrix.eye(2), DenseVector(1, 1))
+ val transform = implicitly[DomainTransformation[BoxDoubleDomain, ParallelotopeRationalDomain]]
+ val boxptope = pardom(Bounds(-1, -1), DenseMatrix.eye(2), Bounds(1, 1))
val box = boxdom(Array(-1, -1), Array(1, 1))
assertResult(boxptope) { transform(boxdom,pardom)(box) }
}
test("General transformation to Box") {
val transform = new DomainTransformation.TopTransformation[NumericalDomain, BoxDoubleDomain]
- val diamond = pardom(DenseVector(-1, -1), DenseMatrix((1.0, 1.0), (1.0, -1.0)), DenseVector(1, 1))
- val box = boxdom(Array(-1, -1), Array(1, 1))
+ val diamond = pardom(Bounds(-1, -1), DenseMatrix(DenseVector(1.0, 1.0), DenseVector(1.0, -1.0)), Bounds(1, 1))
assertResult(boxdom.top(2)) { transform(pardom,boxdom)(diamond) }
}
}
diff --git a/core/src/test/scala/it/unich/jandom/domains/numerical/LinearFormSuite.scala b/core/src/test/scala/it/unich/jandom/domains/numerical/LinearFormSuite.scala
index 4b377f2e..c0c399ce 100644
--- a/core/src/test/scala/it/unich/jandom/domains/numerical/LinearFormSuite.scala
+++ b/core/src/test/scala/it/unich/jandom/domains/numerical/LinearFormSuite.scala
@@ -28,7 +28,7 @@ import org.scalatest.FunSuite
class LinearFormSuite extends FunSuite {
test("Variable constructor") {
- var lf = LinearForm.v(1)
+ val lf = LinearForm.v(1)
assertResult(LinearForm(0, 0, 1)) { lf }
}
@@ -50,7 +50,6 @@ class LinearFormSuite extends FunSuite {
test("Arithmetic operations") {
val lf1 = LinearForm(1, 2, -1)
val lf2 = LinearForm(1, 0, 3)
- val lf3 = LinearForm(2, 2, 2)
assertResult(LinearForm(-1, -2, 1)) { -lf1 }
assertResult(LinearForm(2, 2, 2)) { lf1 + lf2 }
assertResult(LinearForm(0, 2, -4)) { lf1 - lf2 }
diff --git a/core/src/test/scala/it/unich/jandom/domains/numerical/ParallelotopeDomainSuite.scala b/core/src/test/scala/it/unich/jandom/domains/numerical/ParallelotopeDomainSuite.scala
deleted file mode 100644
index c55a6d38..00000000
--- a/core/src/test/scala/it/unich/jandom/domains/numerical/ParallelotopeDomainSuite.scala
+++ /dev/null
@@ -1,211 +0,0 @@
-/**
- * Copyright 2013, 2016 Gianluca Amato
- *
- * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
- * JANDOM is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * JANDOM is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of a
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with JANDOM. If not, see .
- */
-
-package it.unich.jandom.domains.numerical
-
-import breeze.linalg.DenseMatrix
-import breeze.linalg.DenseVector
-import it.unich.jandom.domains.EmptyExistsSuite
-import it.unich.jandom.domains.SeparatedTopAndBottomSuite
-
-/**
- * Test suite for the parallelotope domain.
- * @author Gianluca Amato
- */
-class ParallelotopeDomainSuite extends NumericalDomainSuite with SeparatedTopAndBottomSuite with EmptyExistsSuite {
- lazy val dom = ParallelotopeDomain()
-
- val box = dom(DenseVector(-1, -1), DenseMatrix.eye(2), DenseVector(1, 1))
- val diamond = dom(DenseVector(-1, -1), DenseMatrix((1.0, 1.0), (1.0, -1.0)), DenseVector(1, 1))
- val empty = dom.bottom(2)
- val full = dom.top(2)
-
- describe("constructors") {
- they("should only work with compatible sizes of bounds and shapes") {
- intercept[IllegalArgumentException] { dom(DenseVector(0, 2), DenseMatrix.eye(2), DenseVector(0, 2, 3)) }
- }
- }
-
- describe("constructors and extractors for non-trivial parallelotopes") {
- assertResult(2) { box.dimension }
- assertResult(false) { box.isEmpty }
- assertResult(false) { box.isTop }
- }
-
- describe("constructors and extractors for full parallelotopes") {
- assertResult(2) { full.dimension }
- assertResult(false) { full.isEmpty }
- assertResult(true) { full.isTop }
- }
-
- describe("constructors and extractors for empty parallelotopes") {
- assertResult(2) { empty.dimension }
- assertResult(true) { empty.isEmpty }
- assertResult(false) { empty.isTop }
- }
-
- describe("comparison of parallelotopes") {
- assert(empty < box)
- assert(box < full)
- assert(empty < full)
- assert(diamond < box)
- assert(diamond <= box)
- assert(box > diamond)
- assert(box >= diamond)
- assertResult(Some(1)) { box.tryCompareTo(diamond) }
- assertResult(Some(-1)) { diamond.tryCompareTo(box) }
- assert(box == box)
- assertResult(Some(0)) { box.tryCompareTo(box) }
- val box2 = dom(DenseVector(-0.5, -0.5), DenseMatrix.eye(2), DenseVector(0.5, 0.5))
- assert(box2 <= box)
- assert(box >= box2)
- assert(box2 < box)
- assert(box > box2)
- val box3 = dom(DenseVector(0, 0), DenseMatrix.eye(2), DenseVector(2, 2))
- assertResult(None) { box.tryCompareTo(box3) }
- }
-
- describe("rotation of shapes") {
- val m = DenseMatrix((1.0, 1.0), (-1.0, 1.0))
- val protcalc = box.rotate(m)
- val protdef = dom(DenseVector(-2, -2), m, DenseVector(2, 2))
- assertResult(protdef) { protcalc }
- }
-
- describe("linear invertible assignment") {
- val li1 = dom(DenseVector(0, -1), DenseMatrix((1.0, -1.0), (0.0, 1.0)), DenseVector(2, 1))
- assertResult(li1) { box.linearAssignment(0, LinearForm(1, 1, 1)) }
- val li2 = dom(DenseVector(1, -1), DenseMatrix((1.0, 0.0), (-1.0, 1.0)), DenseVector(1, 0))
- val li3 = dom(DenseVector(2, -2), DenseMatrix((1.0, 0.0), (-1.0, 1.0)), DenseVector(2, -1))
- assertResult(li3) { li2.linearAssignment(0, LinearForm(1, 1, 0)) }
- assertResult(li3) { li2.linearAssignment(0, LinearForm(1, 1)) }
- val li4 = dom(DenseVector(-1, -2), DenseMatrix((1.0, 0.0), (-1.0, 1.0)), DenseVector(1, 2))
- assertResult(li4) { box.linearAssignment(1, LinearForm(0, 1, 2)) }
- assert(empty.linearAssignment(1, LinearForm(0.0, 1, 1)).isEmpty)
- }
-
- describe("non-invertible linear assignment") {
- val ln1 = dom(DenseVector(2, -1), DenseMatrix((1.0, -1.0), (0.0, 1.0)), DenseVector(2, 1))
- assertResult(ln1) { box.linearAssignment(0, LinearForm(2, 0, 1)) }
- val ln2 = dom(DenseVector(0, Double.NegativeInfinity), DenseMatrix((-1.0, 1.0), (0.0, 1.0)), DenseVector(0, Double.PositiveInfinity))
- val ln3 = dom(DenseVector(Double.NegativeInfinity, 0), DenseMatrix((1.0, -1.0), (0.0, 1.0)), DenseVector(Double.PositiveInfinity, 0))
- assertResult(ln2) { ln3.linearAssignment(1, LinearForm(0, 1, 0)) }
- assertResult(ln2) { ln3.linearAssignment(1, LinearForm(0, 1)) }
- assert(empty.linearAssignment(1, LinearForm(0, 1, 0)).isEmpty)
- }
-
- describe("non-deterministic assignment") {
- val nd1 = dom(DenseVector(Double.NegativeInfinity, -1), DenseMatrix.eye(2), DenseVector(Double.PositiveInfinity, 1))
- assertResult(nd1) { box.nonDeterministicAssignment(0) }
- assertResult(nd1) { nd1.nonDeterministicAssignment(0) }
- assertResult(nd1) { diamond.nonDeterministicAssignment(0) }
- val nd2 = dom(DenseVector(0, 0), DenseMatrix((2.0, 1.0), (2.0, -1.0)), DenseVector(1, 1))
- val nd3 = dom(DenseVector(Double.NegativeInfinity, -1), DenseMatrix((2.0, 1.0), (0.0, -2.0)), DenseVector(Double.PositiveInfinity, 1))
- assertResult(nd3) { nd2.nonDeterministicAssignment(0) }
- val nd4 = dom(DenseVector(Double.NegativeInfinity, 0), DenseMatrix((2.0, 1.0), (4.0, 0.0)), DenseVector(Double.PositiveInfinity, 2))
- assertResult(nd4) { nd2.nonDeterministicAssignment(1) }
- val nd5 = dom(DenseVector(10, -1), DenseMatrix((1.0, 0.0), (1.0, 1.0)), DenseVector(10, 1))
- val nd6 = dom(DenseVector(Double.NegativeInfinity, -11), DenseMatrix.eye(2), DenseVector(Double.PositiveInfinity, -9))
- assertResult(nd6) { nd5.nonDeterministicAssignment(0) }
- assert(empty.nonDeterministicAssignment(0).isEmpty)
- }
-
- describe("linear inequalities") {
- val li1 = dom(DenseVector(-1, -1), DenseMatrix((1.0, 1.0), (1.0, -1.0)), DenseVector(0, 0))
- assertResult(li1) { diamond.linearInequality(LinearForm(1, 2, 0)) }
- assertResult(li1) { diamond.linearInequality(LinearForm(1, 2)) }
- assert(empty.linearInequality(LinearForm(-1, 1, 0)).isEmpty)
- }
-
- describe("linear disequalities") {
- val li1 = dom(DenseVector(-1, 0), DenseMatrix((1.0, 1.0), (1.0, -2.0)), DenseVector(0, 0))
- assertResult(li1) { li1.linearDisequality(1.0) }
- assertResult(empty) { li1.linearDisequality(0.0) }
- assertResult(li1) { li1.linearDisequality(LinearForm(1, 0, 1)) }
- assertResult(li1) { li1.linearDisequality(LinearForm(0.5, 1, -2)) }
- assertResult(empty) { li1.linearDisequality(LinearForm(0, 1, -2)) }
- }
-
- describe("union") {
- val u1 = dom(DenseVector(2, 0), DenseMatrix.eye(2), DenseVector(4, 2))
- val u2 = dom(DenseVector(-4, -1), DenseMatrix((-1.0, 3.0), (0.0, 1.0)), DenseVector(4, 2))
- assertResult(u2) { box union u1 }
- val u3 = dom(DenseVector(-1, -1), DenseMatrix((0.0, 1.0), (1.0, -1.0)), DenseVector(2, 4))
- assertResult(u3) { u1 union diamond }
- val u4 = dom(DenseVector(-4, 0), DenseMatrix.eye(2), DenseVector(-2, 2))
- val u5 = dom(DenseVector(-4, 0), DenseMatrix.eye(2), DenseVector(4, 2))
- assertResult(u5) { u4 union u1 }
- val u6 = dom(DenseVector(1, Double.NegativeInfinity), DenseMatrix((1.0, 0.0), (1.0, -1.0)), DenseVector(1, 1))
- val u7 = dom(DenseVector(0, Double.NegativeInfinity), DenseMatrix((1.0, 0.0), (0.0, -1.0)), DenseVector(0, 0))
- val u8 = dom(DenseVector(0, 0), DenseMatrix.eye(2), DenseVector(1, Double.PositiveInfinity))
- assertResult(u8) { u6 union u7 }
- val u9 = dom(DenseVector(0, 0), DenseMatrix.eye(2), DenseVector(0, Double.PositiveInfinity))
- assertResult(u8) { u9 union u8 }
- assertResult(u8) { u8 union u9 }
- val u10 = dom(DenseVector(2, 0), DenseMatrix.eye(2), DenseVector(2, 0))
- val u11 = dom(DenseVector(0, 2), DenseMatrix((0.0, 1.0), (1.0, -2.0)), DenseVector(1, 6))
- assertResult(u11) { u10 union u11 }
- }
-
- describe("minimization, maximization and frequency") {
- val i = dom(DenseVector(-4, -1, 0), DenseMatrix((-1.0, 3.0, 0.0), (0.0, 1.0, 0.0), (-1.0, -1.0, 1.0)), DenseVector(4, 2, 0))
- assertResult(12)(i.maximize(LinearForm(0, 1, 1, 0)))
- assertResult(-8)(i.minimize(LinearForm(0, 1, 1, 0)))
- assertResult(None)(i.frequency(LinearForm(0, 1, 1, 0)))
- assertResult(Some(0))(i.frequency(LinearForm(0, -1, -1, 1)))
- }
-
- describe("dimensional variation") {
- val i = diamond
- val j = dom(DenseVector(-1, -1, Double.NegativeInfinity), DenseMatrix((1.0, 1.0, 0.0),
- (1.0, -1.0, 0.0), (0.0, 0.0, 1.0)), DenseVector(1, 1, Double.PositiveInfinity))
- val h = dom(DenseVector(-1, Double.NegativeInfinity), DenseMatrix((1.0, 0.0),
- (0.0, 1.0)), DenseVector(1, Double.PositiveInfinity))
- assertResult(j)(i.addVariable())
- assertResult(h)(j.delVariable(0))
- assertResult(h)(j.delVariable(1))
- assertResult(i)(j.delVariable(2))
- }
-
- describe("dimensional maps") {
- val i = diamond
- val h = dom(DenseVector(-1), DenseMatrix((1.0)), DenseVector(1))
- assertResult(diamond)(diamond.mapVariables(Seq(1, 0)))
- assertResult(diamond)(i.mapVariables(Seq(0, 1)))
- assertResult(h)(i.mapVariables(Seq(-1, 0)))
- assertResult(diamond)(diamond.addVariable.mapVariables(Seq(1, 0, -1)))
- }
-
- describe("string representation") {
- assertResult("[ -1.0 ≤ x+y ≤ 1.0 , -1.0 ≤ x-y ≤ 1.0 ]") { diamond.mkString(Seq("x", "y")) }
- assertResult("empty") { empty.toString }
- assertResult("[ -∞ ≤ v0 ≤ +∞ , -∞ ≤ v1 ≤ +∞ ]", full.toString) { full.toString }
- }
-
- describe("all parallelotopes are polyhedral") {
- forAll(someProperties) { (p) => assert(p.isPolyhedral) }
- }
-
- // I am not sure it works for all possible cases due to rounding errors.
- describe("all parallelotopes may be rebuilt from constraints") {
- forAll(someProperties) { (p) =>
- assertResult(p) { p.constraints.foldLeft(p.top) { (prop, lf) => prop.linearInequality(lf) } }
- }
- }
-
-}
diff --git a/core/src/test/scala/it/unich/jandom/domains/numerical/ParallelotopeRationalDomainSuite.scala b/core/src/test/scala/it/unich/jandom/domains/numerical/ParallelotopeRationalDomainFastSuite.scala
similarity index 62%
rename from core/src/test/scala/it/unich/jandom/domains/numerical/ParallelotopeRationalDomainSuite.scala
rename to core/src/test/scala/it/unich/jandom/domains/numerical/ParallelotopeRationalDomainFastSuite.scala
index 70440dc7..d1cd17bd 100644
--- a/core/src/test/scala/it/unich/jandom/domains/numerical/ParallelotopeRationalDomainSuite.scala
+++ b/core/src/test/scala/it/unich/jandom/domains/numerical/ParallelotopeRationalDomainFastSuite.scala
@@ -1,5 +1,5 @@
/**
- * Copyright 2013 Gianluca Amato
+ * Copyright 2017 Gianluca Amato
*
* This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
* JANDOM is free software: you can redistribute it and/or modify
@@ -8,7 +8,7 @@
* (at your option) any later version.
*
* JANDOM is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty ofa
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
@@ -20,24 +20,23 @@ package it.unich.jandom.domains.numerical
import scala.language.implicitConversions
-import breeze.linalg.DenseMatrix
-import breeze.linalg.DenseVector
import it.unich.jandom.domains.EmptyExistsSuite
import it.unich.jandom.domains.SeparatedTopAndBottomSuite
-import it.unich.jandom.utils.breeze.RationalForBreeze._
import it.unich.jandom.utils.numberext.RationalExt
-import spire.math.Rational
+import it.unich.jandom.utils.numberext.Bounds
+import it.unich.jandom.utils.numberext.DenseMatrix
+import it.unich.jandom.utils.numberext.Bounds
import spire.syntax.literals._
/**
* Test suite for the parallelotope domain over rationals.
* @author Gianluca Amato
*/
-class ParallelotopeRationalDomainSuite extends NumericalDomainSuite with SeparatedTopAndBottomSuite with EmptyExistsSuite {
+class ParallelotopeRationalDomainFastSuite extends NumericalDomainSuite with SeparatedTopAndBottomSuite with EmptyExistsSuite {
lazy val dom = ParallelotopeRationalDomain()
- val box = dom(DenseVector(r"-1",r"-1"), DenseMatrix.eye[Rational](2), DenseVector(r"1", r"1"))
- val diamond = dom(DenseVector(r"-1", r"-1"), DenseMatrix((r"1", r"1"), (r"1", r"-1")), DenseVector(r"1", r"1"))
+ val box = dom(Bounds(r"-1",r"-1"), DenseMatrix.eye(2), Bounds(r"1", r"1"))
+ val diamond = dom(Bounds(r"-1", r"-1"), DenseMatrix((r"1", r"1"), (r"1", r"-1")), Bounds(r"1", r"1"))
val empty = dom.bottom(2)
val full = dom.top(2)
@@ -48,7 +47,7 @@ class ParallelotopeRationalDomainSuite extends NumericalDomainSuite with Separat
describe("constructors") {
they("should only work with compatible sizes of bounds and shapes") {
- intercept[IllegalArgumentException] { dom(DenseVector(r"0", r"2"), DenseMatrix.eye(2), DenseVector(r"0", r"2", r"3")) }
+ intercept[IllegalArgumentException] { dom(Bounds(r"0", r"2"), DenseMatrix.eye(2), Bounds(r"0", r"2", r"3")) }
}
}
@@ -89,12 +88,12 @@ class ParallelotopeRationalDomainSuite extends NumericalDomainSuite with Separat
assertResult(Some(-1)) { diamond.tryCompareTo(box) }
assert(box == box)
assertResult(Some(0)) { box.tryCompareTo(box) }
- val box2 = dom(DenseVector(r"-1/2", r"-1/2"), DenseMatrix.eye(2), DenseVector(r"1/2", r"1/2"))
+ val box2 = dom(Bounds(r"-1/2", r"-1/2"), DenseMatrix.eye(2), Bounds(r"1/2", r"1/2"))
assert(box2 <= box)
assert(box >= box2)
assert(box2 < box)
assert(box > box2)
- val box3 = dom(DenseVector(r"0", r"0"), DenseMatrix.eye(2), DenseVector(r"2", r"2"))
+ val box3 = dom(Bounds(r"0", r"0"), DenseMatrix.eye(2), Bounds(r"2", r"2"))
assertResult(None) { box.tryCompareTo(box3) }
}
}
@@ -102,23 +101,23 @@ class ParallelotopeRationalDomainSuite extends NumericalDomainSuite with Separat
describe("rotation of shapes") {
it("should behave as expected") {
val m = DenseMatrix((r"1", r"1"), (r"-1", r"1"))
- val m1 = DenseMatrix.zeros[Rational](m.rows, m.cols)
+ val m1 = DenseMatrix.zeros(m.rows, m.cols)
for (i <- 0 until m.rows) { for (j <- 0 until m.cols) { m1(i, j) = m(i, j) } }
val protcalc = box.rotate(m1)
- val protdef = dom(DenseVector(r"-2", r"-2"), m, DenseVector(r"2", r"2"))
+ val protdef = dom(Bounds(r"-2", r"-2"), m, Bounds(r"2", r"2"))
assertResult(protdef) { protcalc }
}
}
describe("linear invertible assignment") {
they("should behave as expected") {
- val li1 = dom(DenseVector(r"0", r"-1"), DenseMatrix((r"1", -r"1"), (r"0", r"1")), DenseVector(r"2", r"1"))
+ val li1 = dom(Bounds(r"0", r"-1"), DenseMatrix((r"1", -r"1"), (r"0", r"1")), Bounds(r"2", r"1"))
assertResult(li1) { box.linearAssignment(0, LinearForm(1, 1, 1)) }
- val li2 = dom(DenseVector(r"1", r"-1"), DenseMatrix((r"1", r"0"), (r"-1", r"1")), DenseVector(r"1", r"0"))
- val li3 = dom(DenseVector(r"2", r"-2"), DenseMatrix((r"1", r"0"), (r"-1", r"1")), DenseVector(r"2", r"-1"))
+ val li2 = dom(Bounds(r"1", r"-1"), DenseMatrix((r"1", r"0"), (r"-1", r"1")), Bounds(r"1", r"0"))
+ val li3 = dom(Bounds(r"2", r"-2"), DenseMatrix((r"1", r"0"), (r"-1", r"1")), Bounds(r"2", r"-1"))
assertResult(li3) { li2.linearAssignment(0, LinearForm(1, 1, 0)) }
assertResult(li3) { li2.linearAssignment(0, LinearForm(1, 1)) }
- val li4 = dom(DenseVector(r"-1", r"-2"), DenseMatrix((r"1", r"0"), (r"-1", r"1")), DenseVector(r"1", r"2"))
+ val li4 = dom(Bounds(r"-1", r"-2"), DenseMatrix((r"1", r"0"), (r"-1", r"1")), Bounds(r"1", r"2"))
assertResult(li4) { box.linearAssignment(1, LinearForm(0, 1, 2)) }
assert(empty.linearAssignment(1, LinearForm(0, 1, 1)).isEmpty)
}
@@ -126,10 +125,10 @@ class ParallelotopeRationalDomainSuite extends NumericalDomainSuite with Separat
describe("non-invertible linear assignment") {
they("should behave as expected") {
- val ln1 = dom(DenseVector(r"2", r"-1"), DenseMatrix((r"1", r"-1"), (r"0", r"1")), DenseVector(r"2", r"1"))
+ val ln1 = dom(Bounds(r"2", r"-1"), DenseMatrix((r"1", r"-1"), (r"0", r"1")), Bounds(r"2", r"1"))
assertResult(ln1) { box.linearAssignment(0, LinearForm(2, 0, 1)) }
- val ln2 = dom(DenseVector(r"0", RationalExt.NegativeInfinity), DenseMatrix((r"-1", r"1"), (r"0", r"1")), DenseVector(r"0", RationalExt.PositiveInfinity))
- val ln3 = dom(DenseVector(RationalExt.NegativeInfinity, r"0"), DenseMatrix((r"1", r"-1"), (r"0", r"1")), DenseVector(RationalExt.PositiveInfinity, r"0"))
+ val ln2 = dom(Bounds(r"0", RationalExt.NegativeInfinity), DenseMatrix((r"-1", r"1"), (r"0", r"1")), Bounds(r"0", RationalExt.PositiveInfinity))
+ val ln3 = dom(Bounds(RationalExt.NegativeInfinity, r"0"), DenseMatrix((r"1", r"-1"), (r"0", r"1")), Bounds(RationalExt.PositiveInfinity, r"0"))
assertResult(ln2) { ln3.linearAssignment(1, LinearForm(0, 1, 0)) }
assertResult(ln2) { ln3.linearAssignment(1, LinearForm(0, 1)) }
assert(empty.linearAssignment(1, LinearForm(0, 1, 0)).isEmpty)
@@ -138,19 +137,19 @@ class ParallelotopeRationalDomainSuite extends NumericalDomainSuite with Separat
describe("non-deterministic assignment") {
they("should behave as expected") {
- val nd1 = dom(DenseVector(RationalExt.NegativeInfinity, r"-1"), DenseMatrix.eye(2), DenseVector(RationalExt.PositiveInfinity, r"1"))
+ val nd1 = dom(Bounds(RationalExt.NegativeInfinity, r"-1"), DenseMatrix.eye(2), Bounds(RationalExt.PositiveInfinity, r"1"))
assert(nd1<=box.nonDeterministicAssignment(0))
assert(nd1>=box.nonDeterministicAssignment(0))
assertResult(nd1) { box.nonDeterministicAssignment(0) }
assertResult(nd1) { nd1.nonDeterministicAssignment(0) }
assertResult(nd1) { diamond.nonDeterministicAssignment(0) }
- val nd2 = dom(DenseVector(r"0", r"0"), DenseMatrix((r"2", r"1"), (r"2", -r"1")), DenseVector(r"1", r"1"))
- val nd3 = dom(DenseVector(RationalExt.NegativeInfinity, r"-1"), DenseMatrix((r"2", r"1"), (r"0", r"-2")), DenseVector(RationalExt.PositiveInfinity, r"1"))
+ val nd2 = dom(Bounds(r"0", r"0"), DenseMatrix((r"2", r"1"), (r"2", -r"1")), Bounds(r"1", r"1"))
+ val nd3 = dom(Bounds(RationalExt.NegativeInfinity, r"-1"), DenseMatrix((r"2", r"1"), (r"0", r"-2")), Bounds(RationalExt.PositiveInfinity, r"1"))
assertResult(nd3) { nd2.nonDeterministicAssignment(0) }
- val nd4 = dom(DenseVector(RationalExt.NegativeInfinity, r"0"), DenseMatrix((r"2", r"1"), (r"4", r"0")), DenseVector(RationalExt.PositiveInfinity, r"2"))
+ val nd4 = dom(Bounds(RationalExt.NegativeInfinity, r"0"), DenseMatrix((r"2", r"1"), (r"4", r"0")), Bounds(RationalExt.PositiveInfinity, r"2"))
assertResult(nd4) { nd2.nonDeterministicAssignment(1) }
- val nd5 = dom(DenseVector(r"10", r"-1"), DenseMatrix((r"1", r"0"), (r"1", r"1")), DenseVector(r"10", r"1"))
- val nd6 = dom(DenseVector(RationalExt.NegativeInfinity, r"-11"), DenseMatrix.eye[Rational](2), DenseVector(RationalExt.PositiveInfinity, r"-9"))
+ val nd5 = dom(Bounds(r"10", r"-1"), DenseMatrix((r"1", r"0"), (r"1", r"1")), Bounds(r"10", r"1"))
+ val nd6 = dom(Bounds(RationalExt.NegativeInfinity, r"-11"), DenseMatrix.eye(2), Bounds(RationalExt.PositiveInfinity, r"-9"))
assertResult(nd6) { nd5.nonDeterministicAssignment(0) }
assert(empty.nonDeterministicAssignment(0).isEmpty)
}
@@ -158,7 +157,7 @@ class ParallelotopeRationalDomainSuite extends NumericalDomainSuite with Separat
describe("linear inequalities") {
they("should behave as expected") {
- val li1 = dom(DenseVector(r"-1", r"-1"), DenseMatrix((r"1", r"1"), (r"1", r"-1")), DenseVector(r"0", r"0"))
+ val li1 = dom(Bounds(r"-1", r"-1"), DenseMatrix((r"1", r"1"), (r"1", r"-1")), Bounds(r"0", r"0"))
assertResult(li1) { diamond.linearInequality(LinearForm(1, 2, 0)) }
assertResult(li1) { diamond.linearInequality(LinearForm(1, 2)) }
assert(empty.linearInequality(LinearForm(-1, 1, 0)).isEmpty)
@@ -167,7 +166,7 @@ class ParallelotopeRationalDomainSuite extends NumericalDomainSuite with Separat
describe("linear disequalities") {
they("should behave as expected") {
- val li1 = dom(DenseVector(r"-1", r"0"), DenseMatrix((r"1",r"1"),(r"1",r"-2")), DenseVector(r"0", r"0"))
+ val li1 = dom(Bounds(r"-1", r"0"), DenseMatrix((r"1",r"1"),(r"1",r"-2")), Bounds(r"0", r"0"))
assertResult(li1) { li1.linearDisequality(1) }
assertResult(empty) { li1.linearDisequality(0) }
assertResult(li1) { li1.linearDisequality(LinearForm(1, 0, 1)) }
@@ -178,30 +177,30 @@ class ParallelotopeRationalDomainSuite extends NumericalDomainSuite with Separat
describe("union") {
it("should behave as expected") {
- val u1 = dom(DenseVector(2, 0), DenseMatrix.eye(2), DenseVector(4, 2))
- val u2 = dom(DenseVector(-4, -1), DenseMatrix((r"-1",r"3"), (r"0",r"1")), DenseVector(4, 2))
+ val u1 = dom(Bounds(2, 0), DenseMatrix.eye(2), Bounds(4, 2))
+ val u2 = dom(Bounds(-4, -1), DenseMatrix((r"-1",r"3"), (r"0",r"1")), Bounds(4, 2))
assertResult(u2) { box union u1 }
- val u3 = dom(DenseVector(-1, -1), DenseMatrix((r"0",r"1"), (r"1", r"-1")), DenseVector(2, 4))
+ val u3 = dom(Bounds(-1, -1), DenseMatrix((r"0",r"1"), (r"1", r"-1")), Bounds(2, 4))
assertResult(u3) { u1 union diamond }
- val u4 = dom(DenseVector(-4, 0), DenseMatrix.eye(2), DenseVector(-2, 2))
- val u5 = dom(DenseVector(-4, 0), DenseMatrix.eye(2), DenseVector(4, 2))
+ val u4 = dom(Bounds(-4, 0), DenseMatrix.eye(2), Bounds(-2, 2))
+ val u5 = dom(Bounds(-4, 0), DenseMatrix.eye(2), Bounds(4, 2))
assertResult(u5) { u4 union u1 }
- val u6 = dom(DenseVector(1, RationalExt.NegativeInfinity), DenseMatrix((r"1", r"0"), (r"1", r"-1")), DenseVector(1, 1))
- val u7 = dom(DenseVector(0, RationalExt.NegativeInfinity), DenseMatrix((r"1", r"0"), (r"0", r"-1")), DenseVector(0, 0))
- val u8 = dom(DenseVector(0, 0), DenseMatrix.eye(2), DenseVector(1, RationalExt.PositiveInfinity))
+ val u6 = dom(Bounds(1, RationalExt.NegativeInfinity), DenseMatrix((r"1", r"0"), (r"1", r"-1")), Bounds(1, 1))
+ val u7 = dom(Bounds(0, RationalExt.NegativeInfinity), DenseMatrix((r"1", r"0"), (r"0", r"-1")), Bounds(0, 0))
+ val u8 = dom(Bounds(0, 0), DenseMatrix.eye(2), Bounds(1, RationalExt.PositiveInfinity))
assertResult(u8) { u6 union u7 }
- val u9 = dom(DenseVector(0, 0), DenseMatrix.eye(2), DenseVector(0, RationalExt.PositiveInfinity))
+ val u9 = dom(Bounds(0, 0), DenseMatrix.eye(2), Bounds(0, RationalExt.PositiveInfinity))
assertResult(u8) { u9 union u8 }
assertResult(u8) { u8 union u9 }
- val u10 = dom(DenseVector(2, 0), DenseMatrix.eye(2), DenseVector(2, 0))
- val u11 = dom(DenseVector(0, 2), DenseMatrix((r"0", r"1"), (r"1", r"-2")), DenseVector(1, 6))
+ val u10 = dom(Bounds(2, 0), DenseMatrix.eye(2), Bounds(2, 0))
+ val u11 = dom(Bounds(0, 2), DenseMatrix((r"0", r"1"), (r"1", r"-2")), Bounds(1, 6))
assertResult(u11) { u10 union u11 }
}
}
describe("minimization, maximization and frequency methods") {
they("should behave as expected") {
- val i = dom(DenseVector(-4, -1, 0), DenseMatrix((r"-1", r"3", r"0"), (r"0", r"1", r"0"), (r"-1", r"-1", r"1")), DenseVector(4, 2, 0))
+ val i = dom(Bounds(-4, -1, 0), DenseMatrix((r"-1", r"3", r"0"), (r"0", r"1", r"0"), (r"-1", r"-1", r"1")), Bounds(4, 2, 0))
assertResult(12)(i.maximize(LinearForm(0, 1, 1, 0)))
assertResult(-8)(i.minimize(LinearForm(0, 1, 1, 0)))
assertResult(None)(i.frequency(LinearForm(0, 1, 1, 0)))
@@ -212,10 +211,10 @@ class ParallelotopeRationalDomainSuite extends NumericalDomainSuite with Separat
describe("dimensional variation") {
it("should behave as expected") {
val i = diamond
- val j = dom(DenseVector(-1, -1, RationalExt.NegativeInfinity), DenseMatrix((r"1",r"1",r"0"),
- (r"1",r"-1",r"0"), (r"0",r"0",r"1")), DenseVector(1, 1, RationalExt.PositiveInfinity))
- val h = dom(DenseVector(-1, RationalExt.NegativeInfinity), DenseMatrix((r"1", r"0"),
- (r"0",r"1")), DenseVector(1, RationalExt.PositiveInfinity))
+ val j = dom(Bounds(-1, -1, RationalExt.NegativeInfinity), DenseMatrix((r"1",r"1",r"0"),
+ (r"1",r"-1",r"0"), (r"0",r"0",r"1")), Bounds(1, 1, RationalExt.PositiveInfinity))
+ val h = dom(Bounds(-1, RationalExt.NegativeInfinity), DenseMatrix((r"1", r"0"),
+ (r"0",r"1")), Bounds(1, RationalExt.PositiveInfinity))
assertResult(j)(i.addVariable())
assertResult(h)(j.delVariable(0))
assertResult(h)(j.delVariable(1))
@@ -226,7 +225,7 @@ class ParallelotopeRationalDomainSuite extends NumericalDomainSuite with Separat
describe("dimensional maps") {
they("should behave as expected") {
val i = diamond
- val h = dom(DenseVector(-1), DenseMatrix.eye(1), DenseVector(1))
+ val h = dom(Bounds(-1), DenseMatrix.eye(1), Bounds(1))
assertResult(diamond)(diamond.mapVariables(Seq(1, 0)))
assertResult(diamond)(i.mapVariables(Seq(0, 1)))
assertResult(h)(i.mapVariables(Seq(-1, 0)))
diff --git a/core/src/test/scala/it/unich/jandom/domains/numerical/ProductDomainSuite.scala b/core/src/test/scala/it/unich/jandom/domains/numerical/ProductDomainSuite.scala
index b4f3f304..4cd7db42 100644
--- a/core/src/test/scala/it/unich/jandom/domains/numerical/ProductDomainSuite.scala
+++ b/core/src/test/scala/it/unich/jandom/domains/numerical/ProductDomainSuite.scala
@@ -24,7 +24,7 @@ package it.unich.jandom.domains.numerical
*/
class ProductDomainSuite extends NumericalDomainSuite {
- val dom = new ProductDomain(BoxDoubleDomain(), ParallelotopeDomain())
+ val dom = new ProductDomain(BoxDoubleDomain(), ParallelotopeRationalDomain())
val n = 2
@@ -65,16 +65,16 @@ class ProductDomainSuite extends NumericalDomainSuite {
}
describe("assignment on product") {
- val x2 = full.linearAssignment(0, 0.0)
+ val x2 = full.linearAssignment(0, 0)
assertResult(x2) {
- new dom.Product(
- dom.dom1.top(2).linearAssignment(0, 0.0),
- ptopeFull.linearAssignment(0, 0.0))
+ new dom.Property(
+ dom.dom1.top(2).linearAssignment(0, 0),
+ ptopeFull.linearAssignment(0, 0))
}
}
describe("dimension on product") {
- val x2 = full.linearAssignment(0, 0.0)
+ val x2 = full.linearAssignment(0, 0)
assertResult(3) { x2.addVariable().dimension }
assertResult(n + 1) { full.addVariable().dimension }
}
diff --git a/core/src/test/scala/it/unich/jandom/domains/numerical/SumIntParallelotopeDomainSuite.scala b/core/src/test/scala/it/unich/jandom/domains/numerical/SumIntParallelotopeDomainSuite.scala
index c7bb752e..444fc431 100644
--- a/core/src/test/scala/it/unich/jandom/domains/numerical/SumIntParallelotopeDomainSuite.scala
+++ b/core/src/test/scala/it/unich/jandom/domains/numerical/SumIntParallelotopeDomainSuite.scala
@@ -19,23 +19,20 @@
package it.unich.jandom.domains.numerical
import org.scalatest.FunSpec
-
import it.unich.jandom.domains.{EmptyExistsSuite, SeparatedTopAndBottomSuite}
-
-import breeze.linalg.DenseMatrix
-import breeze.linalg.DenseVector
+import it.unich.jandom.utils.numberext.{Bounds, DenseMatrix, DenseVector}
/**
* Test suite for the sum of interval and parallelotope domains.
* @author Gianluca Amato
*/
class SumIntParallelotopeDomainSuite extends FunSpec with NumericalDomainSuite with SeparatedTopAndBottomSuite with EmptyExistsSuite {
- lazy val dom = SumIntParallelotopeDomain()
+ lazy val dom = SumBoxDoubleParallelotopeRationDomain()
val box1 = dom.dom1(Array(-1, -1),Array(1,1))
- val par1 = dom.dom2(DenseVector(-1,-1), DenseMatrix.eye(2), DenseVector(1,1))
- val par2 = dom.dom2(DenseVector(-1, -1), DenseMatrix((1.0, 1.0), (1.0, -1.0)), DenseVector(1, 1))
+ val par1 = dom.dom2(Bounds(-1,-1), DenseMatrix.eye(2), Bounds(1,1))
+ val par2 = dom.dom2(Bounds(-1, -1), DenseMatrix(DenseVector(1.0, 1.0), DenseVector(1.0, -1.0)), Bounds(1, 1))
override lazy val someProperties = Table("property", dom.bottom(0), dom.bottom(1), dom.bottom(2), dom.bottom(3), dom.bottom(4), dom.bottom(4),
dom.top(0), dom.top(1), dom.top(2), dom.top(3), dom.top(4), dom.top(5), dom(box1, par1), dom(box1, par2))
diff --git a/core/src/test/scala/it/unich/jandom/domains/objects/ObjectDomainSuite.scala b/core/src/test/scala/it/unich/jandom/domains/objects/ObjectDomainSuite.scala
index 1c306a6b..a4ccff74 100644
--- a/core/src/test/scala/it/unich/jandom/domains/objects/ObjectDomainSuite.scala
+++ b/core/src/test/scala/it/unich/jandom/domains/objects/ObjectDomainSuite.scala
@@ -20,7 +20,6 @@ package it.unich.jandom.domains.objects
import org.scalatest.FunSpec
import org.scalatest.prop.TableDrivenPropertyChecks
-import org.scalatest.prop.TableFor1
import it.unich.jandom.domains.CartesianFiberedDomainSuite
import it.unich.jandom.objectmodels.ObjectModel
diff --git a/core/src/test/scala/it/unich/jandom/domains/objects/PairSharingSuite.scala b/core/src/test/scala/it/unich/jandom/domains/objects/PairSharingSuite.scala
index bf084240..5c7ff34d 100644
--- a/core/src/test/scala/it/unich/jandom/domains/objects/PairSharingSuite.scala
+++ b/core/src/test/scala/it/unich/jandom/domains/objects/PairSharingSuite.scala
@@ -95,7 +95,6 @@ class PairSharingSuite extends FunSuite {
test("Delete variables in the middle") {
val ps1 = dom(Set((0, 0), (0, 1), (1, 1), (3, 1), (3, 3)), 4)
assertResult(dom(Set((0, 0), (1, 1)), 2))(ps1.delVariables(1 to 2))
- val ps2 = dom(Set((0, 0), (0, 1), (1, 1), (3, 1), (3, 3)), 4)
assertResult(dom(Set((0, 0), (2, 2)), 3))(ps1.delVariable(1))
}
diff --git a/core/src/test/scala/it/unich/jandom/domains/objects/PreciseDefiniteNullness.scala b/core/src/test/scala/it/unich/jandom/domains/objects/PreciseDefiniteNullness.scala
index 93ea2472..20b79773 100644
--- a/core/src/test/scala/it/unich/jandom/domains/objects/PreciseDefiniteNullness.scala
+++ b/core/src/test/scala/it/unich/jandom/domains/objects/PreciseDefiniteNullness.scala
@@ -1,9 +1,6 @@
package it.unich.jandom.domains.objects
-import org.scalatest.FunSpec
-import org.scalatest.prop.TableFor1
-
/**
* This suite implements tests for those object domain which precisely track
* definite nullness.
diff --git a/core/src/test/scala/it/unich/jandom/domains/objects/PreciseObjectDomain.scala b/core/src/test/scala/it/unich/jandom/domains/objects/PreciseObjectDomain.scala
index 0c1340d4..c9aa5dd5 100644
--- a/core/src/test/scala/it/unich/jandom/domains/objects/PreciseObjectDomain.scala
+++ b/core/src/test/scala/it/unich/jandom/domains/objects/PreciseObjectDomain.scala
@@ -18,10 +18,6 @@
package it.unich.jandom.domains.objects
-import org.scalatest.FunSpec
-import org.scalatest.prop.TableDrivenPropertyChecks
-import org.scalatest.prop.TableFor1
-
/**
* A test trait for object domains with precise operators.
* @author Gianluca Amato
diff --git a/core/src/test/scala/it/unich/jandom/objectmodels/ObjectModelSuite.scala b/core/src/test/scala/it/unich/jandom/objectmodels/ObjectModelSuite.scala
index e5f99f7f..c8a72155 100644
--- a/core/src/test/scala/it/unich/jandom/objectmodels/ObjectModelSuite.scala
+++ b/core/src/test/scala/it/unich/jandom/objectmodels/ObjectModelSuite.scala
@@ -53,7 +53,7 @@ trait ObjectModelSuite extends FunSpec with TableDrivenPropertyChecks {
for (t <- someTypes) {
val fields = declaredFields(t)
// I want to check absence of exception, I do not know if there is a standard method
- val types = fields map { typeOf(_) }
+ fields map { typeOf(_) }
}
}
}
diff --git a/core/src/test/scala/it/unich/jandom/objectmodels/TestObjectModelSuite.scala b/core/src/test/scala/it/unich/jandom/objectmodels/TestObjectModelSuite.scala
index 1d05d11d..8888b415 100644
--- a/core/src/test/scala/it/unich/jandom/objectmodels/TestObjectModelSuite.scala
+++ b/core/src/test/scala/it/unich/jandom/objectmodels/TestObjectModelSuite.scala
@@ -19,7 +19,6 @@
package it.unich.jandom.objectmodels
import org.scalatest.FunSpec
-import org.scalatest.prop.TableFor1
/**
* A test for the TestObjectModel.
diff --git a/core/src/test/scala/it/unich/jandom/objectmodels/TrivialObjectModelSuite.scala b/core/src/test/scala/it/unich/jandom/objectmodels/TrivialObjectModelSuite.scala
index 9f1caca5..21250e0a 100644
--- a/core/src/test/scala/it/unich/jandom/objectmodels/TrivialObjectModelSuite.scala
+++ b/core/src/test/scala/it/unich/jandom/objectmodels/TrivialObjectModelSuite.scala
@@ -19,7 +19,6 @@
package it.unich.jandom.objectmodels
import org.scalatest.FunSpec
-import org.scalacheck.Gen
/**
* A test for the TrivialObjectModel.
diff --git a/core/src/test/scala/it/unich/jandom/targets/JVMASMSuite.scala b/core/src/test/scala/it/unich/jandom/targets/JVMASMSuite.scala
index 2c5a9e50..4ac145ba 100644
--- a/core/src/test/scala/it/unich/jandom/targets/JVMASMSuite.scala
+++ b/core/src/test/scala/it/unich/jandom/targets/JVMASMSuite.scala
@@ -18,16 +18,14 @@
package it.unich.jandom.targets
-import scala.collection.JavaConversions.asScalaBuffer
+import scala.collection.JavaConverters._
import org.objectweb.asm.ClassReader
-import org.objectweb.asm.tree.{ClassNode, MethodNode}
+import org.objectweb.asm.tree.ClassNode
import org.scalatest.FunSuite
import it.unich.jandom.domains.numerical.BoxDoubleDomain
import it.unich.jandom.targets.jvmasm.{AsmMethod, JVMEnvFixedFrame, JVMEnvFixedFrameDomain, UnsupportedASMInsnException}
-import polyglot.util.Base64.InputStream
class JVMASMSuite extends FunSuite {
- import scala.collection.JavaConversions.asScalaBuffer
val BoxDouble = BoxDoubleDomain()
test("simple method analysis") {
@@ -35,7 +33,7 @@ class JVMASMSuite extends FunSuite {
val cr = new ClassReader(is)
val node = new ClassNode()
cr.accept(node, ClassReader.SKIP_DEBUG)
- val methodList = node.methods.asInstanceOf[java.util.List[MethodNode]]
+ val methodList = node.methods.asScala
val method = new AsmMethod(methodList.find(_.name == "conditional").get)
val params = new Parameters[AsmMethod] {
val domain = new JVMEnvFixedFrameDomain(BoxDouble)
diff --git a/core/src/test/scala/it/unich/jandom/targets/JimpleParametersSuite.scala b/core/src/test/scala/it/unich/jandom/targets/JimpleParametersSuite.scala
index f5acfe86..c9be53c6 100644
--- a/core/src/test/scala/it/unich/jandom/targets/JimpleParametersSuite.scala
+++ b/core/src/test/scala/it/unich/jandom/targets/JimpleParametersSuite.scala
@@ -21,7 +21,6 @@ package it.unich.jandom.targets
import org.scalatest.FunSuite
import it.unich.jandom.domains.numerical.BoxDoubleDomain
import it.unich.jandom.domains.objects.PairSharingDomain
-import it.unich.jandom.parsers.NumericalPropertyParser
import it.unich.jandom.targets.jvmsoot._
import soot._
import it.unich.jandom.parsers.PairSharingParser
diff --git a/core/src/test/scala/it/unich/jandom/targets/LTSSuite.scala b/core/src/test/scala/it/unich/jandom/targets/LTSSuite.scala
index a0047186..f57b7c2d 100644
--- a/core/src/test/scala/it/unich/jandom/targets/LTSSuite.scala
+++ b/core/src/test/scala/it/unich/jandom/targets/LTSSuite.scala
@@ -54,8 +54,10 @@ class LTSSuite extends FunSuite {
test("dot translation") {
val output = """digraph {
- | "start" -> "ciclo" [label="init"]
- | "ciclo" -> "ciclo" [label="loop"]
+ | "0" [label="start"]
+ | "1" [label="ciclo"]
+ | "0" -> "1" [label="init"]
+ | "1" -> "1" [label="loop"]
|}
|""".stripMargin('|')
assertResult(output)(LTS1.lts.toDot)
diff --git a/core/src/test/scala/it/unich/jandom/targets/SootObjectModelSuite.scala b/core/src/test/scala/it/unich/jandom/targets/SootObjectModelSuite.scala
index 6d8a5cc2..2cdb427b 100644
--- a/core/src/test/scala/it/unich/jandom/targets/SootObjectModelSuite.scala
+++ b/core/src/test/scala/it/unich/jandom/targets/SootObjectModelSuite.scala
@@ -19,7 +19,6 @@
package it.unich.jandom.targets
import org.scalatest._
-import org.scalacheck._
import it.unich.jandom.targets.jvmsoot.SootObjectModel
import it.unich.jandom.objectmodels.ObjectModelSuite
diff --git a/core/src/test/scala/it/unich/jandom/utils/breeze/CountNonZeroTestSuite.scala b/core/src/test/scala/it/unich/jandom/utils/breeze/CountNonZeroTestSuite.scala
deleted file mode 100644
index 53119e54..00000000
--- a/core/src/test/scala/it/unich/jandom/utils/breeze/CountNonZeroTestSuite.scala
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * Copyright 2014 Gianluca Amato
- *
- * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
- * JANDOM is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * JANDOM is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty ofa
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with JANDOM. If not, see .
- */
-
-package it.unich.jandom.utils.breeze
-
-import org.scalatest.FunSuite
-
-/**
- * Test suite for the countNonZero universal function.
- */
-class CountNonZeroTestSuite extends FunSuite {
-
- test("countNonZero only counts non-zero elements") {
- assertResult(2) { countNonZero(Seq[Double](0,1,2))}
- assertResult(3) { countNonZero(Seq[Double](1,1,2))}
- assertResult(0) { countNonZero(Seq[Double](0,0,0))}
- }
-
-}
diff --git a/core/src/test/scala/it/unipd/jandom/domains/numerical/box/BoundedBoxDomainCoreSuite.scala b/core/src/test/scala/it/unipd/jandom/domains/numerical/box/BoundedBoxDomainCoreSuite.scala
new file mode 100644
index 00000000..915b0061
--- /dev/null
+++ b/core/src/test/scala/it/unipd/jandom/domains/numerical/box/BoundedBoxDomainCoreSuite.scala
@@ -0,0 +1,240 @@
+package it.unipd.jandom.domains.numerical.box
+
+import it.unipd.jandom.domains.{InfInt, IntNumber, PositiveInfinity, NegativeInfinity}
+import it.unipd.jandom.domains.numerical.box.Box._
+import it.unipd.jandom.domains.numerical.box.BoundedBoxDomainCore._
+import org.scalatest.FlatSpec
+/**
+ * Unit Test - Bounded Box Domain Core
+ *
+ * @author Mauro Carlin <>
+ * @author Mattia Bottaro <>
+ */
+
+class BoundedBoxDomainCoreSuite extends FlatSpec {
+ val m = IntNumber(-10)
+ val n = IntNumber(10)
+ val bc = BoundedBoxDomainCore(m,n)
+
+ val Zero = Box.Interval(IntNumber(0), IntNumber(0))
+ val One = Box.Interval(IntNumber(1), IntNumber(1))
+ val Seven = Box.Interval(IntNumber(7), IntNumber(7))
+ val fourTeen = Box.Interval(IntNumber(14), IntNumber(14))
+ val Mone = Box.Interval(IntNumber(-1), IntNumber(-1))
+ val zeroTen = Box.Interval(IntNumber(0), IntNumber(10))
+ val MtenZero = Box.Interval(IntNumber(-10), IntNumber(0))
+ val MtenTen = Box.Interval(IntNumber(-10), IntNumber(10))
+ val oneInf = Box.Interval(IntNumber(1), PositiveInfinity())
+ val MinfMone = Box.Interval(NegativeInfinity(), IntNumber(-1))
+ val MinfZero = Box.Interval(NegativeInfinity(), IntNumber(0))
+ val nInf = Box.Interval(n, PositiveInfinity())
+ val MinfM = Box.Interval(NegativeInfinity(), m)
+
+ "BoundedBoxDomainCore.alpha" should
+ " - return the corresponding abstract value" in {
+ assert(bc.alpha(1) === One)
+ assert(bc.alpha(0) === Zero)
+ assert(bc.alpha(15) !== One)
+ }
+
+ "BoundedBoxDomainCore.sum" should
+ " - return the sum of the two Boxs given as input" in {
+ val sevenInf = Box.Interval(IntNumber(7), PositiveInfinity())
+ // IntervalBottom
+ assert(bc.sum(IntervalBottom, zeroTen) === IntervalBottom)
+ assert(bc.sum(IntervalBottom, IntervalTop) === IntervalBottom)
+ assert(bc.sum(oneInf, IntervalBottom) === IntervalBottom)
+ assert(bc.sum(IntervalTop, IntervalBottom) === IntervalBottom)
+ assert(bc.sum(IntervalBottom, IntervalBottom) === IntervalBottom)
+ // IntervalTop
+ assert(bc.sum(IntervalTop, MtenZero) === IntervalTop)
+ assert(bc.sum(Zero, IntervalTop) === IntervalTop)
+ assert(bc.sum(IntervalTop, IntervalTop) === IntervalTop)
+ // Interval
+ assert(bc.sum(One, Zero) === One)
+ assert(bc.sum(zeroTen, Seven) === sevenInf)
+ assert(bc.sum(Seven, zeroTen) === sevenInf)
+ assert(bc.sum(Seven, Seven) === fourTeen)
+ assert(bc.sum(fourTeen, zeroTen) === nInf)
+ assert(bc.sum(MinfMone, One) === MinfZero)
+ assert(bc.sum(Zero, oneInf) === oneInf)
+ assert(bc.sum(oneInf, Zero) === oneInf)
+ assert(bc.sum(oneInf, MinfMone) === IntervalTop)
+ assert(bc.sum(MinfMone, oneInf) === IntervalTop)
+
+ }
+
+ "BoundedBoxDomainCore.inverse" should
+ " - return the inverse of the Box given as input" in {
+ val elevenTwelve = Box.Interval(IntNumber(11), IntNumber(12))
+ // IntervalBottom
+ assert(bc.inverse(IntervalBottom) === IntervalBottom)
+ // IntervalTop
+ assert(bc.inverse(IntervalTop) === IntervalTop)
+ // Interval
+ assert(bc.inverse(One) === Mone)
+ assert(bc.inverse(Mone) === One)
+ assert(bc.inverse(zeroTen) === MtenZero)
+ assert(bc.inverse(MtenZero) === zeroTen)
+ assert(bc.inverse(MtenTen) === MtenTen)
+ assert(bc.inverse(MinfMone) === oneInf)
+ assert(bc.inverse(oneInf) === MinfMone)
+ assert(bc.inverse(elevenTwelve) === MinfM)
+ }
+
+
+ "BoundedBoxDomainCore.mult" should
+ " - return the mult of the two Boxs given as input" in {
+ val MinfZero = Box.Interval(NegativeInfinity(), IntNumber(0))
+ val MhudredHundred = Box.Interval(IntNumber(-100), IntNumber(100))
+ // IntervalBottom
+ assert(bc.mult(IntervalBottom, One) === IntervalBottom)
+ assert(bc.mult(IntervalBottom, IntervalTop) === IntervalBottom)
+ assert(bc.mult(MtenTen, IntervalBottom) === IntervalBottom)
+ assert(bc.mult(IntervalTop, IntervalBottom) === IntervalBottom)
+ assert(bc.mult(IntervalBottom, IntervalBottom) === IntervalBottom)
+ // IntervalTop
+ assert(bc.mult(IntervalTop, Mone) === IntervalTop)
+ assert(bc.mult(Mone, IntervalTop) === IntervalTop)
+ assert(bc.mult(IntervalTop, IntervalTop) === IntervalTop)
+ // Interval 0
+ assert(bc.mult(IntervalTop, Zero) === Zero)
+ assert(bc.mult(Zero, IntervalTop) === Zero)
+ assert(bc.mult(IntervalBottom, Zero) === IntervalBottom)
+ assert(bc.mult(Zero, IntervalBottom) === IntervalBottom)
+ assert(bc.mult(Zero, nInf) === Zero)
+ assert(bc.mult(nInf, Zero) === Zero)
+ assert(bc.mult(One, Zero) === Zero)
+ assert(bc.mult(Zero, One) === Zero)
+ // Interval
+ assert(bc.mult(zeroTen, MtenZero) === MinfZero)
+ assert(bc.mult(MtenZero, zeroTen) === MinfZero)
+ assert(bc.mult(MinfMone, One) === MinfMone)
+ assert(bc.mult(One, MinfMone) === MinfMone)
+ assert(bc.mult(MtenTen, MtenTen) === IntervalTop)
+ assert(bc.mult(oneInf, MinfMone) === MinfMone)
+ assert(bc.mult(MinfMone, oneInf) === MinfMone)
+ assert(bc.mult(oneInf, Mone) === MinfMone)
+ assert(bc.mult(Mone, oneInf) === MinfMone)
+ }
+
+ "BoundedBoxDomainCore.division" should
+ " - return the division of the two Boxs given as input" in {
+ val twoThree = Box.Interval(IntNumber(2), IntNumber(3))
+ val twoThirteen = Box.Interval(IntNumber(2), IntNumber(13))
+ val zeroSix = Box.Interval(IntNumber(0), IntNumber(6))
+ // IntervalBottom
+ assert(bc.division(IntervalBottom, MtenTen) === IntervalBottom)
+ assert(bc.division(IntervalBottom, IntervalTop) === IntervalBottom)
+ assert(bc.division(MtenTen, IntervalBottom) === IntervalBottom)
+ assert(bc.division(IntervalTop, IntervalBottom) === IntervalBottom)
+ assert(bc.division(IntervalBottom, IntervalBottom) === IntervalBottom)
+ // IntervalTop
+ assert(bc.division(IntervalTop, One) === IntervalTop)
+ assert(bc.division(One, IntervalTop) === IntervalTop)
+ assert(bc.division(IntervalTop, IntervalTop) === IntervalTop)
+ // Interval [0,0])
+ assert(bc.division(IntervalTop, Zero) === IntervalBottom)
+ assert(bc.division(Zero, IntervalTop) === Zero)
+ assert(bc.division(Zero, MtenTen) === Zero)
+ assert(bc.division(MtenTen, Zero) === IntervalBottom)
+
+ // Interval
+ assert(bc.division(fourTeen, One) === fourTeen)
+ assert(bc.division(twoThirteen, twoThree) === zeroSix)
+ }
+
+ "BoundedBoxDomainCore.remainder" should
+ " - return the remainder of the two Boxs given as input" in {
+ val twoThree = Box.Interval(IntNumber(2), IntNumber(3))
+ val MnineNine = Box.Interval(IntNumber(-9), IntNumber(9))
+ val zeroTwo = Box.Interval(IntNumber(0), IntNumber(2))
+ val MnineMseven = Box.Interval(IntNumber(-9), IntNumber(-7))
+ val MeightZero = Box.Interval(IntNumber(-8), IntNumber(0))
+ val MtwelveMseven = Box.Interval(IntNumber(-12), IntNumber(-7))
+ //IntervalBottom
+ assert(bc.remainder(IntervalBottom, One) === IntervalBottom)
+ assert(bc.remainder(IntervalBottom, IntervalTop) === IntervalBottom)
+ assert(bc.remainder(One, IntervalBottom) === IntervalBottom)
+ assert(bc.remainder(IntervalTop, IntervalBottom) === IntervalBottom)
+ // IntervalTop
+ assert(bc.remainder(IntervalTop, MtenTen) === IntervalTop)
+ assert(bc.remainder(MtenTen, IntervalTop) === IntervalTop)
+ assert(bc.remainder(IntervalTop, IntervalTop) === IntervalTop)
+ // Interval(0)
+ assert(bc.remainder(IntervalTop, Zero) === IntervalBottom)
+ assert(bc.remainder(Zero, IntervalTop) === Zero)
+ assert(bc.remainder(Zero, MtenTen) === Zero)
+ assert(bc.remainder(MtenTen, Zero) === IntervalBottom)
+ assert(bc.remainder(Zero, Zero) === IntervalBottom)
+ // Interval
+ assert(bc.remainder(MtenTen, MtenTen) === MnineNine)
+ assert(bc.remainder(MtenTen, twoThree) === zeroTwo)
+ assert(bc.remainder(MtenTen, MnineMseven) === MeightZero)
+ assert(bc.remainder(MtenTen, MtwelveMseven) === MinfZero)
+ }
+
+ "BoundedBoxDomainCore.lub" should
+ " - return the least upper bound of the two Boxs given as input" in {
+ val MinfTen = Box.Interval(NegativeInfinity(), IntNumber(10))
+ val zeroOne = Box.Interval(IntNumber(0), IntNumber(1))
+ // IntervalBottom
+ assert(bc.lub(IntervalBottom, MtenTen) === MtenTen)
+ assert(bc.lub(MtenTen, IntervalBottom) === MtenTen)
+ assert(bc.lub(IntervalBottom, IntervalBottom) === IntervalBottom)
+ // IntervalTop
+ assert(bc.lub(IntervalTop, One) === IntervalTop)
+ assert(bc.lub(One, IntervalTop) === IntervalTop)
+ assert(bc.lub(IntervalTop, IntervalBottom) === IntervalTop)
+ assert(bc.lub(IntervalBottom, IntervalTop) === IntervalTop)
+ assert(bc.lub(IntervalTop, IntervalTop) === IntervalTop)
+ // Interval
+ assert(bc.lub(oneInf, MinfMone) === IntervalTop)
+ assert(bc.lub(MinfMone, oneInf) === IntervalTop)
+ assert(bc.lub(MinfMone, MtenTen) === MinfTen)
+ assert(bc.lub(MtenTen, MinfMone) === MinfTen)
+ assert(bc.lub(Zero, One) === zeroOne)
+ assert(bc.lub(One, Zero) === zeroOne)
+ }
+
+ "BoundedBoxDomainCore.glb" should
+ " - return the greatest lower bound between the two Boxs given as input" in {
+ val MtenMone = Box.Interval(IntNumber(-10), IntNumber(-1))
+ // IntervalBottom
+ assert(bc.glb(IntervalBottom, MtenTen) === IntervalBottom)
+ assert(bc.glb(MtenTen, IntervalBottom) === IntervalBottom)
+ assert(bc.glb(IntervalBottom, IntervalBottom) === IntervalBottom)
+ // IntervalTop
+ assert(bc.glb(IntervalTop, One) === One)
+ assert(bc.glb(One, IntervalTop) === One)
+ assert(bc.glb(IntervalTop, IntervalBottom) === IntervalBottom)
+ assert(bc.glb(IntervalBottom, IntervalTop) === IntervalBottom)
+ assert(bc.glb(IntervalTop, IntervalTop) === IntervalTop)
+ // Interval
+ assert(bc.glb(oneInf, MinfMone) === IntervalBottom)
+ assert(bc.glb(MinfMone, oneInf) === IntervalBottom)
+ assert(bc.glb(MinfMone, MtenTen) === MtenMone)
+ assert(bc.glb(MtenTen, MinfMone) === MtenMone)
+ assert(bc.glb(Zero, One) === IntervalBottom)
+ assert(bc.glb(One, Zero) === IntervalBottom)
+ }
+
+ "BoundedBoxDomainCore.compare" should
+ " - return the comparison between the two Boxs given as input" in {
+ // IntervalTop
+ assert(bc.compare(IntervalTop, IntervalTop) === Option(0))
+ assert(bc.compare(IntervalTop, MtenTen) === Option(1))
+ assert(bc.compare(IntervalTop, IntervalBottom) === Option(1))
+ assert(bc.compare(MtenTen, IntervalTop) === Option(-1))
+ assert(bc.compare(IntervalBottom, IntervalTop) === Option(-1))
+ // IntervalBottom
+ assert(bc.compare(IntervalBottom, IntervalBottom) === Option(0))
+ assert(bc.compare(IntervalBottom, MinfMone) === Option(-1))
+ assert(bc.compare(MinfMone, IntervalBottom) === Option(1))
+ // Interval
+ assert(bc.compare(One, Zero) === Option.empty)
+ assert(bc.compare(MinfMone, oneInf) === Option.empty)
+ assert(bc.compare(MtenTen, MtenTen) === Option(0))
+ assert(bc.compare(nInf,nInf) === Option(0))
+ }
+} // end of BoundedBoxDomainCoreSuite
diff --git a/core/src/test/scala/it/unipd/jandom/domains/numerical/box/BoxDomainCoreSuite.scala b/core/src/test/scala/it/unipd/jandom/domains/numerical/box/BoxDomainCoreSuite.scala
new file mode 100644
index 00000000..b1e61298
--- /dev/null
+++ b/core/src/test/scala/it/unipd/jandom/domains/numerical/box/BoxDomainCoreSuite.scala
@@ -0,0 +1,227 @@
+package it.unipd.jandom.domains.numerical.box
+
+import it.unipd.jandom.domains.{InfInt, IntNumber, PositiveInfinity, NegativeInfinity}
+import it.unipd.jandom.domains.numerical.box.Box._
+import it.unipd.jandom.domains.numerical.box.BoxDomainCore._
+import org.scalatest.FlatSpec
+/**
+ * Unit Test - Box Domain Core
+ *
+ * @author Mauro Carlin <>
+ * @author Mattia Bottaro <>
+ */
+
+class BoxDomainCoreSuite extends FlatSpec {
+ val bc = BoxDomainCore()
+
+ val Zero = Box.Interval(IntNumber(0), IntNumber(0))
+ val One = Box.Interval(IntNumber(1), IntNumber(1))
+ val Mone = Box.Interval(IntNumber(-1), IntNumber(-1))
+ val zeroTen = Box.Interval(IntNumber(0), IntNumber(10))
+ val MtenZero = Box.Interval(IntNumber(-10), IntNumber(0))
+ val MtenTen = Box.Interval(IntNumber(-10), IntNumber(10))
+ val oneInf = Box.Interval(IntNumber(1), PositiveInfinity())
+ val MinfMone = Box.Interval(NegativeInfinity(), IntNumber(-1))
+ val MinfZero = Box.Interval(NegativeInfinity(), IntNumber(0))
+
+ "BoxDomainCore.alpha" should
+ " - return the corresponding abstract value" in {
+ assert(bc.alpha(1) === One)
+ assert(bc.alpha(0) === Zero)
+ assert(bc.alpha(15) !== One)
+ }
+
+ "BoxDomainCore.sum" should
+ " - return the sum of the two Boxs given as input" in {
+ // IntervalBottom
+ assert(bc.sum(IntervalBottom, zeroTen) === IntervalBottom)
+ assert(bc.sum(IntervalBottom, IntervalTop) === IntervalBottom)
+ assert(bc.sum(oneInf, IntervalBottom) === IntervalBottom)
+ assert(bc.sum(IntervalTop, IntervalBottom) === IntervalBottom)
+ assert(bc.sum(IntervalBottom, IntervalBottom) === IntervalBottom)
+ // IntervalTop
+ assert(bc.sum(IntervalTop, MtenZero) === IntervalTop)
+ assert(bc.sum(Zero, IntervalTop) === IntervalTop)
+ assert(bc.sum(IntervalTop, IntervalTop) === IntervalTop)
+ // Interval
+ assert(bc.sum(One, Zero) === One)
+ assert(bc.sum(zeroTen, MtenZero) === MtenTen)
+ assert(bc.sum(One, MinfMone) === MinfZero)
+ assert(bc.sum(MinfMone, One) === MinfZero)
+ assert(bc.sum(Zero, oneInf) === oneInf)
+ assert(bc.sum(oneInf, Zero) === oneInf)
+ assert(bc.sum(oneInf, MinfMone) === IntervalTop)
+ assert(bc.sum(MinfMone, oneInf) === IntervalTop)
+ }
+
+ "BoxDomainCore.inverse" should
+ " - return the inverse of the Box given as input" in {
+ // IntervalBottom
+ assert(bc.inverse(IntervalBottom) === IntervalBottom)
+ // IntervalTop
+ assert(bc.inverse(IntervalTop) === IntervalTop)
+ // Interval
+ assert(bc.inverse(One) === Mone)
+ assert(bc.inverse(Mone) === One)
+ assert(bc.inverse(zeroTen) === MtenZero)
+ assert(bc.inverse(MtenZero) === zeroTen)
+ assert(bc.inverse(MtenTen) === MtenTen)
+ assert(bc.inverse(MinfMone) === oneInf)
+ assert(bc.inverse(oneInf) === MinfMone)
+ }
+
+
+ "BoxDomainCore.mult" should
+ " - return the mult of the two Boxs given as input" in {
+ val MhundredZero = Box.Interval(IntNumber(-100), IntNumber(0))
+ val MhudredHundred = Box.Interval(IntNumber(-100), IntNumber(100))
+ // IntervalBottom
+ assert(bc.mult(IntervalBottom, One) === IntervalBottom)
+ assert(bc.mult(IntervalBottom, IntervalTop) === IntervalBottom)
+ assert(bc.mult(MtenTen, IntervalBottom) === IntervalBottom)
+ assert(bc.mult(IntervalTop, IntervalBottom) === IntervalBottom)
+ assert(bc.mult(IntervalBottom, IntervalBottom) === IntervalBottom)
+ // IntervalTop
+ assert(bc.mult(IntervalTop, Mone) === IntervalTop)
+ assert(bc.mult(Mone, IntervalTop) === IntervalTop)
+ assert(bc.mult(IntervalTop, IntervalTop) === IntervalTop)
+ // Interval 0
+ assert(bc.mult(IntervalTop, Zero) === Zero)
+ assert(bc.mult(Zero, IntervalTop) === Zero)
+ assert(bc.mult(IntervalBottom, Zero) === IntervalBottom)
+ assert(bc.mult(Zero, IntervalBottom) === IntervalBottom)
+ assert(bc.mult(Zero, oneInf) === Zero)
+ assert(bc.mult(oneInf, Zero) === Zero)
+ assert(bc.mult(One, Zero) === Zero)
+ assert(bc.mult(Zero, One) === Zero)
+ // Interval
+ assert(bc.mult(zeroTen, MtenZero) === MhundredZero)
+ assert(bc.mult(MtenZero, zeroTen) === MhundredZero)
+ assert(bc.mult(MinfMone, One) === MinfMone)
+ assert(bc.mult(One, MinfMone) === MinfMone)
+ assert(bc.mult(MtenTen, MtenTen) === MhudredHundred)
+ assert(bc.mult(oneInf, MinfMone) === MinfMone)
+ assert(bc.mult(MinfMone, oneInf) === MinfMone)
+ assert(bc.mult(oneInf, Mone) === MinfMone)
+ assert(bc.mult(Mone, oneInf) === MinfMone)
+ }
+
+ "BoxDomainCore.division" should
+ " - return the division of the two Boxs given as input" in {
+ val twoThree = Box.Interval(IntNumber(2), IntNumber(3))
+ val twoThirteen = Box.Interval(IntNumber(2), IntNumber(13))
+ val zeroSix = Box.Interval(IntNumber(0), IntNumber(6))
+ // IntervalBottom
+ assert(bc.division(IntervalBottom, MtenTen) === IntervalBottom)
+ assert(bc.division(IntervalBottom, IntervalTop) === IntervalBottom)
+ assert(bc.division(MtenTen, IntervalBottom) === IntervalBottom)
+ assert(bc.division(IntervalTop, IntervalBottom) === IntervalBottom)
+ assert(bc.division(IntervalBottom, IntervalBottom) === IntervalBottom)
+ // IntervalTop
+ assert(bc.division(IntervalTop, One) === IntervalTop)
+ assert(bc.division(One, IntervalTop) === IntervalTop)
+ assert(bc.division(IntervalTop, IntervalTop) === IntervalTop)
+ // Interval [0,0])
+ assert(bc.division(IntervalTop, Zero) === IntervalBottom)
+ assert(bc.division(Zero, IntervalTop) === Zero)
+ assert(bc.division(Zero, MtenTen) === Zero)
+ assert(bc.division(MtenTen, Zero) === IntervalBottom)
+
+ // Interval
+ assert(bc.division(MtenTen, MtenTen) === MtenTen)
+ assert(bc.division(twoThirteen, twoThree) === zeroSix)
+ }
+
+ "BoxDomainCore.remainder" should
+ " - return the remainder of the two Boxs given as input" in {
+ val twoThree = Box.Interval(IntNumber(2), IntNumber(3))
+ val MnineNine = Box.Interval(IntNumber(-9), IntNumber(9))
+ val zeroTwo = Box.Interval(IntNumber(0), IntNumber(2))
+ val MnineMseven = Box.Interval(IntNumber(-9), IntNumber(-7))
+ val MeightZero = Box.Interval(IntNumber(-8), IntNumber(0))
+ val zeroInf = Box.Interval(IntNumber(0), PositiveInfinity())
+ //IntervalBottom
+ assert(bc.remainder(IntervalBottom, One) === IntervalBottom)
+ assert(bc.remainder(IntervalBottom, IntervalTop) === IntervalBottom)
+ assert(bc.remainder(One, IntervalBottom) === IntervalBottom)
+ assert(bc.remainder(IntervalTop, IntervalBottom) === IntervalBottom)
+ // IntervalTop
+ assert(bc.remainder(IntervalTop, MtenTen) === IntervalTop)
+ assert(bc.remainder(MtenTen, IntervalTop) === IntervalTop)
+ assert(bc.remainder(IntervalTop, IntervalTop) === IntervalTop)
+ // Interval(0)
+ assert(bc.remainder(IntervalTop, Zero) === IntervalBottom)
+ assert(bc.remainder(Zero, IntervalTop) === Zero)
+ assert(bc.remainder(Zero, MtenTen) === Zero)
+ assert(bc.remainder(MtenTen, Zero) === IntervalBottom)
+ assert(bc.remainder(Zero, Zero) === IntervalBottom)
+ // Interval
+ assert(bc.remainder(MtenTen, MtenTen) === MnineNine)
+ assert(bc.remainder(MtenTen, twoThree) === zeroTwo)
+ assert(bc.remainder(MtenTen, MnineMseven) === MeightZero)
+ assert(bc.remainder(MtenTen, oneInf) === zeroInf)
+ }
+
+ "BoxDomainCore.lub" should
+ " - return the least upper bound of the two Boxs given as input" in {
+ val MinfTen = Box.Interval(NegativeInfinity(), IntNumber(10))
+ val zeroOne = Box.Interval(IntNumber(0), IntNumber(1))
+ // IntervalBottom
+ assert(bc.lub(IntervalBottom, MtenTen) === MtenTen)
+ assert(bc.lub(MtenTen, IntervalBottom) === MtenTen)
+ assert(bc.lub(IntervalBottom, IntervalBottom) === IntervalBottom)
+ // IntervalTop
+ assert(bc.lub(IntervalTop, One) === IntervalTop)
+ assert(bc.lub(One, IntervalTop) === IntervalTop)
+ assert(bc.lub(IntervalTop, IntervalBottom) === IntervalTop)
+ assert(bc.lub(IntervalBottom, IntervalTop) === IntervalTop)
+ assert(bc.lub(IntervalTop, IntervalTop) === IntervalTop)
+ // Interval
+ assert(bc.lub(oneInf, MinfMone) === IntervalTop)
+ assert(bc.lub(MinfMone, oneInf) === IntervalTop)
+ assert(bc.lub(MinfMone, MtenTen) === MinfTen)
+ assert(bc.lub(MtenTen, MinfMone) === MinfTen)
+ assert(bc.lub(Zero, One) === zeroOne)
+ assert(bc.lub(One, Zero) === zeroOne)
+ }
+
+ "BoxDomainCore.glb" should
+ " - return the greatest lower bound between the two Boxs given as input" in {
+ val MtenMone = Box.Interval(IntNumber(-10), IntNumber(-1))
+ // IntervalBottom
+ assert(bc.glb(IntervalBottom, MtenTen) === IntervalBottom)
+ assert(bc.glb(MtenTen, IntervalBottom) === IntervalBottom)
+ assert(bc.glb(IntervalBottom, IntervalBottom) === IntervalBottom)
+ // IntervalTop
+ assert(bc.glb(IntervalTop, One) === One)
+ assert(bc.glb(One, IntervalTop) === One)
+ assert(bc.glb(IntervalTop, IntervalBottom) === IntervalBottom)
+ assert(bc.glb(IntervalBottom, IntervalTop) === IntervalBottom)
+ assert(bc.glb(IntervalTop, IntervalTop) === IntervalTop)
+ // Interval
+ assert(bc.glb(oneInf, MinfMone) === IntervalBottom)
+ assert(bc.glb(MinfMone, oneInf) === IntervalBottom)
+ assert(bc.glb(MinfMone, MtenTen) === MtenMone)
+ assert(bc.glb(MtenTen, MinfMone) === MtenMone)
+ assert(bc.glb(Zero, One) === IntervalBottom)
+ assert(bc.glb(One, Zero) === IntervalBottom)
+ }
+
+ "BoxDomainCore.compare" should
+ " - return the comparison between the two Boxs given as input" in {
+ // IntervalTop
+ assert(bc.compare(IntervalTop, IntervalTop) === Option(0))
+ assert(bc.compare(IntervalTop, MtenTen) === Option(1))
+ assert(bc.compare(IntervalTop, IntervalBottom) === Option(1))
+ assert(bc.compare(MtenTen, IntervalTop) === Option(-1))
+ assert(bc.compare(IntervalBottom, IntervalTop) === Option(-1))
+ // IntervalBottom
+ assert(bc.compare(IntervalBottom, IntervalBottom) === Option(0))
+ assert(bc.compare(IntervalBottom, MinfMone) === Option(-1))
+ assert(bc.compare(MinfMone, IntervalBottom) === Option(1))
+ // Interval
+ assert(bc.compare(One, Zero) === Option.empty)
+ assert(bc.compare(MinfMone, oneInf) === Option.empty)
+ assert(bc.compare(MtenTen, MtenTen) === Option(0))
+ }
+} // end of BoxDomainCoreSuite
diff --git a/core/src/test/scala/soot/jandom/BriefBigBlockGraphSuite.scala b/core/src/test/scala/soot/jandom/BriefBigBlockGraphSuite.scala
index f1b17110..a7324476 100644
--- a/core/src/test/scala/soot/jandom/BriefBigBlockGraphSuite.scala
+++ b/core/src/test/scala/soot/jandom/BriefBigBlockGraphSuite.scala
@@ -18,8 +18,9 @@
package soot.jandom
+import scala.collection.JavaConverters._
+
import org.scalatest.FunSpec
-import soot._
import it.unich.jandom.targets.SootTests
/**
@@ -32,10 +33,8 @@ class BriefBigBlockGraphSuite extends FunSpec with SootTests {
val c = scene.loadClassAndSupport("javatest.SimpleTest")
describe("The BriefBigBlockGraph for the nested method") {
- import scala.collection.JavaConversions._
-
val body = c.getMethodByName("nested").retrieveActiveBody()
- val graph = new BriefBigBlockGraph(body)
+ val graph = new BriefBigBlockGraph(body).asScala
val expectedGraph = Seq(
(Seq(), Seq(1)),
(Seq(0,3), Seq(2,4)),
@@ -43,11 +42,11 @@ class BriefBigBlockGraphSuite extends FunSpec with SootTests {
(Seq(2), Seq(1)),
(Seq(1), Seq()))
- it("should have five nodes") { assert(graph.size() === expectedGraph.length ) }
+ it("should have five nodes") { assert(graph.size === expectedGraph.length ) }
it("should be isomorphic to the expected graph") {
for ( (block, (preds, succs)) <- graph zip expectedGraph) {
- assert ( (block.getPreds() map { _.getIndexInMethod() }) === preds)
- assert ( ( block.getSuccs() map { _.getIndexInMethod() }) === succs)
+ assert ( (block.getPreds().asScala map { _.getIndexInMethod() }) === preds)
+ assert ( ( block.getSuccs().asScala map { _.getIndexInMethod() }) === succs)
}
}
}
diff --git a/core/src/test/scala/soot/jandom/UnitBlockGraphSuite.scala b/core/src/test/scala/soot/jandom/UnitBlockGraphSuite.scala
index f8df0009..9fa63428 100644
--- a/core/src/test/scala/soot/jandom/UnitBlockGraphSuite.scala
+++ b/core/src/test/scala/soot/jandom/UnitBlockGraphSuite.scala
@@ -18,12 +18,10 @@
package soot.jandom
+import scala.collection.JavaConverters._
+
import org.scalatest.FunSpec
-import soot.Scene
-import soot.Unit
import soot.toolkits.graph.BriefUnitGraph
-import soot.toolkits.graph.Block
-import soot.options.Options
import it.unich.jandom.targets.SootTests
/**
@@ -33,26 +31,24 @@ import it.unich.jandom.targets.SootTests
*/
class UnitBlockGraphSuite extends FunSpec with SootTests {
- import scala.collection.JavaConversions._
-
val scene = initSoot()
val c = scene.loadClassAndSupport("javatest.SimpleTest")
- for (m <- c.getMethods(); body = m.retrieveActiveBody()) {
+ for (m <- c.getMethods().asScala; body = m.retrieveActiveBody()) {
describe("The UnitBlockGraph for the "+m.getName()+" method") {
val graph = new UnitBlockGraph(body)
val unitGraph = new BriefUnitGraph(body)
it("should only have blocks with head equal to tail") {
- for (b <- graph) assert(b.getHead() === b.getTail())
+ for (b <- graph.asScala) assert(b.getHead() === b.getTail())
}
it("should be isomorphic to the unit graph") {
assert(graph.size() === unitGraph.size())
- for (b <- graph; u = b.getHead()) {
- assert((graph.getPredsOf(b) map { _.getHead() }) === asScalaBuffer(unitGraph.getPredsOf(u)))
- assert((graph.getSuccsOf(b) map { _.getHead() }) === asScalaBuffer(unitGraph.getSuccsOf(u)))
+ for (b <- graph.asScala; u = b.getHead()) {
+ assert((graph.getPredsOf(b).asScala map { _.getHead() }) === unitGraph.getPredsOf(u).asScala)
+ assert((graph.getSuccsOf(b).asScala map { _.getHead() }) === unitGraph.getSuccsOf(u).asScala)
}
}
}
diff --git a/extended/.gitignore b/extended/.gitignore
deleted file mode 100644
index 4c4e7f96..00000000
--- a/extended/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/target.eclipse/
-/bin/
diff --git a/extended/build.sbt b/extended/build.sbt
index 6a745a6b..c31993cf 100644
--- a/extended/build.sbt
+++ b/extended/build.sbt
@@ -1,3 +1,5 @@
+import CustomKeys._
+
//*** Additional source directories for PPL
unmanagedSourceDirectories in Compile ++= (pplJar.value map { _ => (sourceDirectory in Compile).value / "ppl" }).toSeq
@@ -6,23 +8,26 @@ unmanagedSourceDirectories in Test ++= (pplJar.value map { _ => (sourceDirectory
//*** Assembly plugin
-test in assembly := {}
+test in assembly := { }
-mergeStrategy in assembly <<= (mergeStrategy in assembly) { (old) =>
- {
+assemblyMergeStrategy in assembly ~= { (oldStrategy) => {
case PathList(ps @ _*) if ps.last.endsWith(".class") => MergeStrategy.last
- case x => old(x)
+ case x => oldStrategy(x)
}
}
-//*** Cappi plugin
+//*** Eclipse plugin
-cappiSettings
+EclipseKeys.configurations += Jmh
-//*** Eclipse plugin
+//*** IDEA plugin
+
+ideOutputDirectory in Compile := Some(file("extended/target/idea/classes"))
+
+ideOutputDirectory in Test := Some(file("extended/target/idea/test-classes"))
-EclipseKeys.executionEnvironment := Some(EclipseExecutionEnvironment.JavaSE17)
+//*** JMH Plugin
-EclipseKeys.eclipseOutput := Some("target.eclipse")
+enablePlugins(JmhPlugin)
-incOptions := incOptions.value.withLogRecompileOnMacro(false)
\ No newline at end of file
+dependencyClasspath in Jmh ++= (exportedProducts in Test).value
diff --git a/extended/src/jmh/scala/it/unich/jandom/benchmarks/BoxDoubleBenchmark.scala b/extended/src/jmh/scala/it/unich/jandom/benchmarks/BoxDoubleBenchmark.scala
new file mode 100644
index 00000000..0fcda4dd
--- /dev/null
+++ b/extended/src/jmh/scala/it/unich/jandom/benchmarks/BoxDoubleBenchmark.scala
@@ -0,0 +1,133 @@
+/**
+ * Copyright 2013, 2016 Gianluca Amato
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
+
+package it.unich.jandom.benchmarks
+
+import it.unich.jandom.domains.numerical._
+import it.unich.jandom.domains.numerical.ppl._
+import org.openjdk.jmh.annotations._
+import parma_polyhedra_library._
+import it.unich.jandom.domains.numerical.LinearForm.c
+
+/**
+ * This benchmark compare some operations on the interval domain. This
+ * shows that PPL is very slow in Jandom, and Reflexive PPL is even
+ * slower.
+ * @author Gianluca Amato
+ */
+@State(Scope.Thread)
+@Warmup(iterations = 5)
+class BoxDoubleBenchmark {
+ private val numvars = 100
+ private val numpoints = 10
+ private val BoxDouble = BoxDoubleDomain()
+
+ PPLInitializer
+
+ @Benchmark
+ def timePPL() {
+ // create an empty box
+ val db = new Double_Box(numvars, Degenerate_Element.EMPTY)
+
+ // initialize a list of linear form (one for each variable)
+ val vars = new Array[Linear_Expression_Variable](numvars)
+ for (v <- 0 until numvars) vars(v) = new Linear_Expression_Variable(new Variable(v))
+
+ // initialize the linear form x_1 + ... + x_n
+ val diagonal = vars.reduceRight[Linear_Expression](_.sum(_))
+ val gs = new Generator_System()
+ for (i <- 1 to numpoints) {
+ val point = Generator.point(diagonal times (new Coefficient(i)), new Coefficient(1))
+ gs.clear
+ gs.add(point)
+ val point_box = new Double_Box(gs)
+ db.upper_bound_assign(point_box)
+ }
+ }
+
+ @Benchmark
+ def timePPL2() {
+ val db = new Double_Box(numvars, Degenerate_Element.EMPTY)
+ val v0 = new Variable(0)
+ val vlast = new Variable(numvars - 1)
+ val expr = (new Linear_Expression_Variable(v0)) sum (new Linear_Expression_Variable(vlast))
+ val gs = new Generator_System()
+ val point = Generator.point(expr, new Coefficient(1))
+ gs.add(point)
+ db.upper_bound_assign(new Double_Box(gs))
+ val denominator = new Coefficient(1)
+ for (i <- 1 to numpoints) {
+ val dbnew = new Double_Box(db)
+ dbnew.affine_image(v0, expr, denominator)
+ db.upper_bound_assign(dbnew)
+ }
+ }
+
+ @Benchmark
+ def timeJandomNoPPLOptimized() {
+ var db = BoxDouble.bottom(numvars)
+ for (i <- 1 to numpoints) {
+ val point = Array.fill(numvars)(i.toDouble)
+ db = db union BoxDouble(point)
+ }
+ }
+
+ @Benchmark
+ def timeJandomNoPPL() {
+ var db = BoxDouble.bottom(numvars)
+ val full = BoxDouble.top(numvars)
+ for (i <- 1 to numpoints) {
+ val point = (0 until numvars).foldLeft(full) { (box, v) => box.linearAssignment(v, i.toDouble) }
+ db = db union point
+ }
+ }
+
+ @Benchmark
+ def timeJandomPPL() {
+ val PPLBoxDouble = PPLBoxDoubleDomain()
+ var db = PPLBoxDouble.bottom(numvars)
+ val full = PPLBoxDouble.top(numvars)
+ for (i <- 1 to numpoints) {
+ val point = (0 until numvars).foldLeft(full) { (box, v) => box.linearAssignment(v, i.toDouble) }
+ db = db union point
+ }
+ }
+
+ @Benchmark
+ def timeJandomPPLReflexive() {
+ val domain = PPLDomain[Octagonal_Shape_double]()
+ var db = domain.bottom(numvars)
+ val full = domain.top(numvars)
+ for (i <- 1 to numpoints) {
+ val point = (0 until numvars).foldLeft(full) { (box, v) => box.linearAssignment(v, i.toDouble) }
+ db = db union point
+ }
+ }
+
+ @Benchmark
+ def timeJandomPPLMacro() {
+ // we explicitly type domain in order to avoid generation of existential types.
+ val domain: NumericalDomain = PPLDomainMacro[Double_Box]
+ var db = domain.bottom(numvars)
+ val full = domain.top(numvars)
+ for (i <- 1 to numpoints) {
+ val point = (0 until numvars).foldLeft(full) { (box, v) => box.linearAssignment(v, i.toDouble) }
+ db = db union point
+ }
+ }
+}
diff --git a/extended/src/jmh/scala/it/unich/jandom/benchmarks/FASTBenchmark.scala b/extended/src/jmh/scala/it/unich/jandom/benchmarks/FASTBenchmark.scala
new file mode 100644
index 00000000..e5fa96a2
--- /dev/null
+++ b/extended/src/jmh/scala/it/unich/jandom/benchmarks/FASTBenchmark.scala
@@ -0,0 +1,91 @@
+/**
+ * Copyright 2015, 2016 Gianluca Amato
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
+
+package it.unich.jandom.benchmarks
+
+import it.unich.jandom.benchmark.FASTLoader
+import it.unich.jandom.domains.numerical.{BoxDoubleDomain, NumericalDomain}
+import it.unich.jandom.targets.Parameters
+import it.unich.jandom.targets.lts.{LTS, Location}
+import it.unich.scalafix.FixpointSolver._
+import it.unich.scalafix.finite.FiniteFixpointSolver
+import it.unich.scalafix.lattice.Domain
+import org.openjdk.jmh.annotations._
+
+/**
+ * This is a program which analyzes the Alice benchmarks with different settings and compares the execution time.
+ */
+@State(Scope.Thread)
+@Warmup(iterations = 5)
+class FASTBenchmark extends FASTLoader {
+
+ val dom = BoxDoubleDomain()
+
+ private implicit val scalafixDomain: Domain[dom.Property] = dom.ScalaFixDomain
+ private val wideningBox = { (x: dom.Property, y: dom.Property) => x widening y }
+ private val narrowingBox = { (x: dom.Property, y: dom.Property) => x narrowing y }
+ private val CC77 = FiniteFixpointSolver.CC77[Location, dom.Property](Solver.WorkListSolver, wideningBox, narrowingBox)
+
+ @Benchmark
+ def timeLTS() {
+ val params = new Parameters[LTS] {
+ val domain: NumericalDomain = dom
+ }
+ for (lts <- ltss) lts.analyze(params)
+ }
+
+ @Benchmark
+ def timeEQSKleene() {
+ for (lts <- ltss) {
+ val eqs = lts.toEQS(dom)
+ FiniteFixpointSolver(eqs, CC77.copy(solver = Solver.KleeneSolver))
+ }
+ }
+
+ @Benchmark
+ def timeEQSRoundRobin() {
+ for (lts <- ltss) {
+ val eqs = lts.toEQS(dom)
+ FiniteFixpointSolver(eqs, CC77.copy(solver = Solver.RoundRobinSolver))
+ }
+ }
+
+ @Benchmark
+ def timeEQSDefault() {
+ for (lts <- ltss) {
+ val eqs = lts.toEQS(dom)
+ FiniteFixpointSolver(eqs, CC77)
+ }
+ }
+
+ @Benchmark
+ def timeEQSLocalized() {
+ for (lts <- ltss) {
+ val eqs = lts.toEQS(dom)
+ FiniteFixpointSolver(eqs, CC77.copy(boxscope = BoxScope.Localized))
+ }
+ }
+
+ @Benchmark
+ def timeEQSMixedLocalized() {
+ for (lts <- ltss) {
+ val eqs = lts.toEQS(dom)
+ FiniteFixpointSolver(eqs, CC77.copy(boxscope = BoxScope.Localized, boxstrategy = BoxStrategy.Warrowing))
+ }
+ }
+}
diff --git a/extended/src/test/ppl/it/unich/jandom/JandomBenchmark.scala b/extended/src/test/ppl/it/unich/jandom/JandomBenchmark.scala
deleted file mode 100644
index 61efb465..00000000
--- a/extended/src/test/ppl/it/unich/jandom/JandomBenchmark.scala
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * Copyright 2013 Gianluca Amato
- *
- * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
- * JANDOM is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * JANDOM is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty ofa
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with JANDOM. If not, see .
- */
-
-package it.unich.jandom
-
-import com.google.caliper.SimpleBenchmark
-
-/**
- * The benchmark suite for Jandom. This is currently only a dummy test.
- * @author Gianluca Amato
- *
- */
-
-class JandomBenchmark extends SimpleBenchmark {
- def timeDummy(reps: Int) {
- for (i <- 0 until reps) System.nanoTime()
- }
-}
diff --git a/extended/src/test/ppl/it/unich/jandom/domains/numerical/ppl/BoxDoubleBenchmark.scala b/extended/src/test/ppl/it/unich/jandom/domains/numerical/ppl/BoxDoubleBenchmark.scala
deleted file mode 100644
index 8dd95937..00000000
--- a/extended/src/test/ppl/it/unich/jandom/domains/numerical/ppl/BoxDoubleBenchmark.scala
+++ /dev/null
@@ -1,143 +0,0 @@
-/**
- * Copyright 2013 Gianluca Amato
- *
- * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
- * JANDOM is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * JANDOM is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty ofa
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with JANDOM. If not, see .
- */
-
-package it.unich.jandom.domains.numerical.ppl
-
-import com.google.caliper.SimpleBenchmark
-
-import it.unich.jandom.domains.numerical._
-
-import parma_polyhedra_library._
-
-/**
- * This benchmark compare some operations on the interval domain. This
- * shows that PPL is very slow in Jandom, and Reflexive PPL is even
- * slower.
- * @author Gianluca Amato
- *
- */
-
-class BoxDoubleBenchmark extends SimpleBenchmark {
- private val numvars = 100
- private val numpoints = 10
- private val BoxDouble = BoxDoubleDomain()
-
- PPLInitializer
-
- def timePPL(reps: Int) {
- for (iter <- 1 to reps) {
- // create an empty box
- val db = new Double_Box(numvars, Degenerate_Element.EMPTY)
-
- // initialize a list of linear form (one for each variable)
- val vars = new Array[Linear_Expression_Variable](numvars)
- for (v <- 0 until numvars) vars(v) = new Linear_Expression_Variable(new Variable(v))
-
- // initialize the linear form x_1 + ... + x_n
- val diagonal = vars.reduceRight[Linear_Expression](_.sum(_))
- val gs = new Generator_System()
- for (i <- 1 to numpoints) {
- val point = Generator.point(diagonal times (new Coefficient(i)), new Coefficient(1))
- gs.clear
- gs.add(point)
- val point_box = new Double_Box(gs)
- db.upper_bound_assign(point_box)
- }
- }
- }
-
- def timePPL2(reps: Int) {
- for (iter <- 1 to reps) {
- val db = new Double_Box(numvars, Degenerate_Element.EMPTY)
- val v0 = new Variable(0)
- val vlast = new Variable(numvars - 1)
- val expr = (new Linear_Expression_Variable(v0)) sum (new Linear_Expression_Variable(vlast))
- val gs = new Generator_System()
- val point = Generator.point(expr, new Coefficient(1))
- gs.add(point)
- db.upper_bound_assign(new Double_Box(gs))
- val denominator = new Coefficient(1)
- for (i <- 1 to numpoints) {
- val dbnew = new Double_Box(db)
- dbnew.affine_image(v0, expr, denominator)
- db.upper_bound_assign(dbnew)
- }
- }
- }
-
- def timeJandomNoPPLOptimized(reps: Int) {
- for (iter <- 1 to reps) {
- var db = BoxDouble.bottom(numvars)
- for (i <- 1 to numpoints) {
- val point = Array.fill(numvars)(i.toDouble)
- db = db union BoxDouble(point)
- }
- println(db)
- }
- }
-
- def timeJandomNoPPL(reps: Int) {
- for (iter <- 1 to reps) {
- var db = BoxDouble.bottom(numvars)
- val zero = Array.fill(numvars)(0.0)
- val full = BoxDouble.top(numvars)
- for (i <- 1 to numpoints) {
- val point = (0 until numvars).foldLeft(full) { (box, v) => box.linearAssignment(v, i.toDouble) }
- db = db union point
- }
- }
- }
-
- def timeJandomPPL(reps: Int) {
- val PPLBoxDouble = PPLBoxDoubleDomain()
- for (iter <- 1 to reps) {
- var db = PPLBoxDouble.bottom(numvars)
- val full = PPLBoxDouble.top(numvars)
- for (i <- 1 to numpoints) {
- val point = (0 until numvars).foldLeft(full) { (box, v) => box.linearAssignment(v, i.toDouble) }
- db = db union point
- }
- }
- }
-
- def timeJandomPPLReflexive(reps: Int) {
- for (iter <- 1 to reps) {
- val domain = PPLDomain[Octagonal_Shape_double]()
- var db = domain.bottom(numvars)
- val full = domain.top(numvars)
- for (i <- 1 to numpoints) {
- val point = (0 until numvars).foldLeft(full) { (box, v) => box.linearAssignment(v, i.toDouble) }
- db = db union point
- }
- }
- }
-
- def timeJandomPPLMacro(reps: Int) {
- for (iter <- 1 to reps) {
- // we explicitly type domain in order to avoid generation of existential types.
- val domain: NumericalDomain = PPLDomainMacro[Double_Box]
- var db = domain.bottom(numvars)
- val zero = Array.fill(numvars)(0.0)
- val full = domain.top(numvars)
- for (i <- 1 to numpoints) {
- val point = (0 until numvars).foldLeft(full) { (box, v) => box.linearAssignment(v, i.toDouble) }
- db = db union point
- }
- }
- }
-}
diff --git a/extended/src/test/ppl/it/unich/jandom/domains/numerical/ppl/PPLMacroPropertySuite.scala b/extended/src/test/ppl/it/unich/jandom/domains/numerical/ppl/PPLMacroPropertySuite.scala
index 948f574c..cafc9269 100644
--- a/extended/src/test/ppl/it/unich/jandom/domains/numerical/ppl/PPLMacroPropertySuite.scala
+++ b/extended/src/test/ppl/it/unich/jandom/domains/numerical/ppl/PPLMacroPropertySuite.scala
@@ -69,8 +69,6 @@ class PPLMacroPropertySuite extends FunSuite {
}
test("various operations") {
- val obj = full.linearAssignment(0, 0.0)
- val obj2 = full.linearAssignment(1, 0.0)
val obj3 = full.linearAssignment(2, 0.0)
val obj4 = full.linearAssignment(2, 1.0)
val obj5 = obj4 union obj3
@@ -83,8 +81,7 @@ class PPLMacroPropertySuite extends FunSuite {
test("disequality do not crash") {
val obj = full.linearAssignment(0, 0.0)
- val dis = obj.linearDisequality(LinearForm(0, 1, 0, 0))
- assert(true)
+ obj.linearDisequality(LinearForm(0, 1, 0, 0))
}
test("disequality is precise on boxes") {
diff --git a/extended/src/test/scala/it/unich/jandom/benchmarks/EQSLegacyFASTComparison.scala b/extended/src/test/scala/it/unich/jandom/benchmarks/EQSLegacyFASTComparison.scala
new file mode 100644
index 00000000..e54166a9
--- /dev/null
+++ b/extended/src/test/scala/it/unich/jandom/benchmarks/EQSLegacyFASTComparison.scala
@@ -0,0 +1,106 @@
+/**
+ * Copyright 2016, 2017 Gianluca Amato
+ *
+ * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
+ * JANDOM is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * JANDOM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of a
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with JANDOM. If not, see .
+ */
+
+package it.unich.jandom.benchmarks
+
+import it.unich.jandom.benchmark.FASTLoader
+import it.unich.jandom.domains.numerical.ParallelotopeRationalDomain
+import it.unich.jandom.targets.lts._
+import it.unich.jandom.targets.parameters._
+import it.unich.jandom.targets.{EQSSolver, Parameters}
+import it.unich.scalafix.{Assignment, FixpointSolverListener}
+
+/**
+ * This program compares standard (legacy) analyzer with the new one based on Scalafix for
+ * the LTS target. The aim is to compare both precision of results and speed. This should be used to
+ * guide the progressive removal of legacy analyzers.
+ */
+object EQSLegacyFASTComparison extends App with FASTLoader {
+
+ val dom = ParallelotopeRationalDomain()
+
+ def compareResults(locations: Seq[Location], ann1: Assignment[Location, dom.Property], ann2: Assignment[Location, dom.Property]) = {
+ var lt, eq, gt, un = 0
+ for (l <- locations) {
+ val result = ann1(l) tryCompareTo ann2(l)
+ result match {
+ case None =>
+ un += 1
+ //println(s"location ${l}: ${ann1(l)} vs ${ann2(l)}")
+ case Some(0) => eq += 1
+ case Some(x) if x < 0 =>
+ lt += 1
+ //println(s"location ${l}: ${ann1(l)} vs ${ann2(l)}")
+ case Some(x) if x > 0 =>
+ gt += 1
+ //println(s"location ${l}: ${ann1(l)} vs ${ann2(l)}")
+ }
+ }
+ (eq, lt, gt, un)
+ }
+
+ val paramsList = Seq(
+ ("standard", new Parameters[LTS] {
+ val domain: dom.type = dom
+ }),
+ ("kleene standard", new Parameters[LTS] {
+ val domain: dom.type = dom
+ iterationStrategy = IterationStrategy.Kleene
+ }),
+ ("all widening", new Parameters[LTS] {
+ val domain: dom.type = dom
+ wideningLocation = WideningNarrowingLocation.All
+ narrowingLocation = WideningNarrowingLocation.All
+ }),
+ ("kleene all widening", new Parameters[LTS] {
+ val domain: dom.type = dom
+ wideningLocation = WideningNarrowingLocation.All
+ narrowingLocation = WideningNarrowingLocation.All
+ iterationStrategy = IterationStrategy.Kleene
+ })
+ )
+
+ for ((name, params) <- paramsList) {
+ var timeEQS = 0.0
+ var timeLTS = 0.0
+ var timeTemp = 0.0
+ var globaleq, globallt, globalgt, globalun = 0
+ for (lts <- ltss) {
+ timeTemp = java.lang.System.currentTimeMillis()
+ val res1 = EQSSolver(lts)(dom)(params)(FixpointSolverListener.EmptyListener)
+ timeEQS += (java.lang.System.currentTimeMillis() - timeTemp)
+ timeTemp = java.lang.System.currentTimeMillis()
+ val res2 = lts.analyze(params)
+ timeLTS += (java.lang.System.currentTimeMillis() - timeTemp)
+ val comparison = compareResults(lts.locations, res1, res2)
+ globaleq += comparison._1
+ globallt += comparison._2
+ globalgt += comparison._3
+ globalun += comparison._4
+ if (comparison._2 != 0 || comparison._3 != 0 || comparison._4 != 0)
+ println(s"Found differences in ${lts.name}")
+ }
+ println(s"\n-------------------")
+ println(s"$name EQS vs Legacy")
+ println(s"Time ${timeEQS}ms vs ${timeLTS}ms")
+ println("Equal : " + globaleq)
+ println("First Better: " + globallt)
+ println("Second Better: " + globalgt)
+ println("Uncomparable: " + globalun)
+ }
+}
diff --git a/extended/src/test/scala/it/unich/jandom/benchmarks/FASTBenchmark.scala b/extended/src/test/scala/it/unich/jandom/benchmarks/FASTBenchmark.scala
deleted file mode 100644
index 8d853d2e..00000000
--- a/extended/src/test/scala/it/unich/jandom/benchmarks/FASTBenchmark.scala
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * Copyright 2015 Gianluca Amato
- *
- * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
- * JANDOM is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * JANDOM is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of a
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with JANDOM. If not, see .
- */
-
-package it.unich.jandom.benchmarks
-
-import com.google.caliper.SimpleBenchmark
-
-import it.unich.jandom.domains.numerical.BoxDoubleDomain
-import it.unich.jandom.targets.Parameters
-import it.unich.jandom.targets.lts.LTS
-import it.unich.jandom.targets.lts.Location
-import it.unich.scalafix.Box.apply
-import it.unich.scalafix.FixpointSolver._
-import it.unich.scalafix.finite.FiniteFixpointSolver
-
-/**
- * This is a program which analyzes the Alice benchmarks with different settings and compares the execution time.
- */
-class FASTBenchmark extends SimpleBenchmark with FASTLoader {
-
- val dom = BoxDoubleDomain()
-
- implicit val scalafixDomain = dom.ScalaFixDomain
- val wideningBox = { (x: dom.Property, y: dom.Property) => x widening y }
- val narrowingBox = { (x: dom.Property, y: dom.Property) => x narrowing y }
- val CC77 = FiniteFixpointSolver.CC77[Location, dom.Property](Solver.WorkListSolver, wideningBox, narrowingBox)
-
- def timeLTS(reps: Int) {
- for (_ <- 1 to reps) {
- for (lts <- ltss) {
- val params = new Parameters[LTS] { val domain = dom }
- val ann = lts.analyze(params)
- }
- }
- }
-
- def timeEQSKleene(reps: Int) {
- for (_ <- 1 to reps) {
- for (lts <- ltss) {
- val eqs = lts.toEQS(dom)
- val ann = FiniteFixpointSolver(eqs, CC77.copy(solver = Solver.KleeneSolver))
- }
- }
- }
-
- def timeEQSRoundRobin(reps: Int) {
- for (_ <- 1 to reps) {
- for (lts <- ltss) {
- val eqs = lts.toEQS(dom)
- val ann = FiniteFixpointSolver(eqs, CC77.copy(solver = Solver.RoundRobinSolver))
- }
- }
- }
-
- def timeEQSDefault(reps: Int) {
- for (_ <- 1 to reps) {
- for (lts <- ltss) {
- val eqs = lts.toEQS(dom)
- val ann = FiniteFixpointSolver(eqs, CC77)
- }
- }
- }
-
- def timeEQSLocalized(reps: Int) {
- for (_ <- 1 to reps) {
- for (lts <- ltss) {
- val eqs = lts.toEQS(dom)
- val ann = FiniteFixpointSolver(eqs, CC77.copy(boxscope = BoxScope.Localized))
- }
- }
- }
-
- def timeEQSMixedLocalized(reps: Int) {
- for (_ <- 1 to reps) {
- for (lts <- ltss) {
- val eqs = lts.toEQS(dom)
- val ann = FiniteFixpointSolver(eqs, CC77.copy(boxscope = BoxScope.Localized, boxstrategy = BoxStrategy.Warrowing))
- }
- }
- }
-
-}
diff --git a/extended/src/test/scala/it/unich/jandom/benchmarks/FASTComparison.scala b/extended/src/test/scala/it/unich/jandom/benchmarks/FASTComparison.scala
index 44364949..ed081424 100644
--- a/extended/src/test/scala/it/unich/jandom/benchmarks/FASTComparison.scala
+++ b/extended/src/test/scala/it/unich/jandom/benchmarks/FASTComparison.scala
@@ -1,5 +1,5 @@
/**
- * Copyright 2015 Gianluca Amato
+ * Copyright 2015, 2017 Gianluca Amato
*
* This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
* JANDOM is free software: you can redistribute it and/or modify
@@ -18,12 +18,13 @@
package it.unich.jandom.benchmarks
+import it.unich.jandom.benchmark.FASTLoader
import it.unich.jandom.domains.numerical.BoxDoubleDomain
import it.unich.jandom.targets.lts.Location
-import it.unich.scalafix.Box.apply
import it.unich.scalafix.FixpointSolver._
import it.unich.scalafix.FixpointSolverListener.PerformanceListener
import it.unich.scalafix.finite.FiniteFixpointSolver
+import it.unich.scalafix.lattice.Domain
/**
* An example application which compares the precision of different analysis for Alice benchmarks.
@@ -32,7 +33,7 @@ object FASTComparison extends App with FASTLoader {
//val dom = PPLDomain[C_Polyhedron]
val dom = BoxDoubleDomain()
- implicit val scalafixDomain = dom.ScalaFixDomain
+ implicit val scalafixDomain: Domain[dom.Property] = dom.ScalaFixDomain
val widening = { (x: dom.Property, y: dom.Property) => x widening y }
val narrowing = { (x: dom.Property, y: dom.Property) => x narrowing y }
@@ -44,7 +45,7 @@ object FASTComparison extends App with FASTLoader {
("localized", CC77.copy(boxscope = BoxScope.Localized)),
("mixed", SCP),
("mixed localized", SCP.copy(boxscope = BoxScope.Localized)),
- ("mixed localized restart", SCP.copy(boxscope = BoxScope.Localized, restartstrategy = true)))
+ ("mixed localized restart", SCP.copy(boxscope = BoxScope.Localized, restartstrategy = RestartStrategy.Restart)))
val results = (for (lts <- ltss; eqs = lts.toEQS(dom); (name, p) <- parameters) yield {
val l = new PerformanceListener
@@ -55,10 +56,10 @@ object FASTComparison extends App with FASTLoader {
for ((name, _) <- parameters) {
var numiters = 0
for (l <- ltss) numiters += results((l, name))._2
- println(s"solver ${name} iterations ${numiters}")
+ println(s"solver $name iterations $numiters")
}
- for (i <- 0 until parameters.size; j <- i + 1 until parameters.size) {
+ for (i <- parameters.indices; j <- i + 1 until parameters.size) {
val name1 = parameters(i)._1
val name2 = parameters(j)._1
var globalun, globaleq, globallt, globalgt = 0
@@ -95,7 +96,7 @@ object FASTComparison extends App with FASTLoader {
}
// for comparison, the old solver integrated in the LTS class has 1170 evaluations for worklist based analysis and 1706 evaluations for Kleene.
println(s"\n-------------------")
- println(s"${name1} vs ${name2}")
+ println(s"$name1 vs $name2")
println("Uncomparable: " + globalun)
println("Equal : " + globaleq)
println("First Better: " + globallt)
@@ -105,9 +106,9 @@ object FASTComparison extends App with FASTLoader {
for (lts <- ltss; if lts.name.indexOf("amato") >= 0) {
println(lts.name)
for ((name, _) <- parameters) {
- print(s"Solver ${name} -> ")
+ print(s"Solver $name -> ")
val result = results((lts, name))
- for (l <- lts.locations) print(s"${l} : ${result._1(l)} ")
+ for (l <- lts.locations) print(s"$l : ${result._1(l)} ")
println("")
}
}
diff --git a/extended/src/test/scala/it/unich/jandom/benchmarks/FASTLoader.scala b/extended/src/test/scala/it/unich/jandom/benchmarks/FASTLoader.scala
deleted file mode 100644
index d86b1395..00000000
--- a/extended/src/test/scala/it/unich/jandom/benchmarks/FASTLoader.scala
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * Copyright 2015, 2016 Gianluca Amato
- *
- * This file is part of JANDOM: JVM-based Analyzer for Numerical DOMains
- * JANDOM is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * JANDOM is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of a
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with JANDOM. If not, see .
- */
-
-package it.unich.jandom.benchmarks
-
-import java.io.File
-import java.io.FileReader
-
-import it.unich.jandom.parsers.FastParser
-
-/**
- * This trait loads and parser all models in Alice directory.
- * @author Gianluca Amato
- */
-
-trait FASTLoader {
- /**
- * The directory from where benchmarks are loaded
- */
- val dir = new File(getClass.getResource("/fast/").toURI);
-
- /**
- * A sequence of Alice models.
- */
- val ltss = for (model <- dir.listFiles()) yield {
- val source = new FileReader(model)
- val result = FastParser().parse(source).get
- source.close()
- // add filename to the model name to have an unique identifier
- result.copy(name = s"${result.name} -- ${model.getName}")
- }
-}
diff --git a/project/Build.scala b/project/CustomKeys.scala
similarity index 82%
rename from project/Build.scala
rename to project/CustomKeys.scala
index d13d8607..2db3c65a 100644
--- a/project/Build.scala
+++ b/project/CustomKeys.scala
@@ -1,8 +1,7 @@
import sbt._
import Keys._
-object JandomBuild extends Build {
+object CustomKeys {
val pplJar = settingKey[Option[String]]("Location of the PPL library")
val gitHeadCommitSHA = taskKey[String]("Current git commit SHA")
}
-
diff --git a/project/assembly.sbt b/project/assembly.sbt
deleted file mode 100644
index 39c1bb84..00000000
--- a/project/assembly.sbt
+++ /dev/null
@@ -1 +0,0 @@
-addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.3")
diff --git a/project/build.properties b/project/build.properties
index 35c88bab..b7dd3cb2 100644
--- a/project/build.properties
+++ b/project/build.properties
@@ -1 +1 @@
-sbt.version=0.13.12
+sbt.version=1.0.2
diff --git a/project/buildinfo.sbt b/project/buildinfo.sbt
deleted file mode 100644
index 04935e45..00000000
--- a/project/buildinfo.sbt
+++ /dev/null
@@ -1 +0,0 @@
-addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.6.1")
diff --git a/project/caliper.sbt b/project/caliper.sbt
deleted file mode 100644
index 167d9211..00000000
--- a/project/caliper.sbt
+++ /dev/null
@@ -1,6 +0,0 @@
-resolvers += Resolver.url(
- "bintray-sbt-plugin-releases",
- url("http://dl.bintray.com/content/sbt/sbt-plugin-releases"))(
- Resolver.ivyStylePatterns)
-
-addSbtPlugin("me.lessis" % "cappi" % "0.1.1")
diff --git a/project/eclipse.sbt b/project/eclipse.sbt
deleted file mode 100644
index 2728de12..00000000
--- a/project/eclipse.sbt
+++ /dev/null
@@ -1 +0,0 @@
-addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "5.0.1")
diff --git a/project/plugins.sbt b/project/plugins.sbt
new file mode 100644
index 00000000..2b511cc7
--- /dev/null
+++ b/project/plugins.sbt
@@ -0,0 +1,5 @@
+addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.5")
+addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.7.0")
+addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "5.2.2")
+addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.2.27")
+addSbtPlugin("org.jetbrains" % "sbt-ide-settings" % "1.0.0")