diff --git a/build.gradle.kts b/build.gradle.kts index 7b3b832b9b..834767ac52 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -28,7 +28,7 @@ buildscript { allprojects { group = "hu.bme.mit.theta" - version = "5.4.0" + version = "6.0.0" apply(from = rootDir.resolve("gradle/shared-with-buildSrc/mirrors.gradle.kts")) } diff --git a/buildSrc/gradle.properties b/buildSrc/gradle.properties index 68276da2bc..499eb7e837 100644 --- a/buildSrc/gradle.properties +++ b/buildSrc/gradle.properties @@ -25,6 +25,16 @@ junitVersion=5.9.3 junit4Version=4.12 jacocoVersion=0.8.8 mockitoVersion=2.2.11 +pnmlFrameworkVersion=2.2.12 +emfCommonVersion=2.10.1 +emfCodegenVersion=2.10.0 +emfCodegenEcoreVersion=2.10.2-v20150123-0452 +emfEcoreVersion=2.10.2-v20150123-0348 +axiomVersion=1.2.20 +jingVersion=20091111 +kolobokeVersion=1.0.0 +deltaVersion=0.0.1 +deltaCollectionsVersion=0.0.1 gsonVersion=2.9.1 javasmtVersion=4.1.1 sosylabVersion=0.3000-569-g89796f98 \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/Deps.kt b/buildSrc/src/main/kotlin/Deps.kt index 86c5f2cd09..ab28cb0deb 100644 --- a/buildSrc/src/main/kotlin/Deps.kt +++ b/buildSrc/src/main/kotlin/Deps.kt @@ -36,6 +36,29 @@ object Deps { val jcommander = "com.beust:jcommander:${Versions.jcommander}" + val pnmlCore = "fr.lip6.pnml:fr.lip6.pnml.framework.coremodel:${Versions.pnmlFramework}" + val pnmlPtnet = "fr.lip6.pnml:fr.lip6.pnml.framework.ptnet:${Versions.pnmlFramework}" + val pnmlSymmetric = "fr.lip6.pnml:fr.lip6.pnml.framework.symmetricnet:${Versions.pnmlFramework}" + val pnmlHlpn = "fr.lip6.pnml:fr.lip6.pnml.framework.hlpn:${Versions.pnmlFramework}" + val pnmlPthlpng = "fr.lip6.pnml:fr.lip6.pnml.framework.pthlpng:${Versions.pnmlFramework}" + val pnmlUtils = "fr.lip6.pnml:fr.lip6.pnml.framework.utils:${Versions.pnmlFramework}" + val pnmlNupn = "fr.lip6.pnml:fr.lip6.pnml.nupn.toolinfo:${Versions.pnmlFramework}" + + val emfCommon = "org.eclipse.emf:org.eclipse.emf.common:${Versions.emfCommon}" + val emfCodegen = "org.eclipse.emf:org.eclipse.emf.codegen:${Versions.emfCodegen}" + val emfCodegenEcore = "org.eclipse.emf:org.eclipse.emf.codegen.ecore:${Versions.emfCodegenEcore}" + val emfEcore = "org.eclipse.emf:org.eclipse.emf.ecore:${Versions.emfEcore}" + val emfEcoreXmi = "org.eclipse.emf:org.eclipse.emf.ecore.xmi:${Versions.emfEcore}" + + val axiomApi = "org.apache.ws.commons.axiom:axiom-api:${Versions.axiom}" + val axiomImpl = "org.apache.ws.commons.axiom:axiom-impl:${Versions.axiom}" + val jing = "com.thaiopensource:jing:${Versions.jing}" + + val delta = "lib/hu.bme.mit.delta" + val deltaCollections = "lib/hu.bme.mit.delta.collections:${Versions.deltaCollections}" + + val koloboke = "com.koloboke:koloboke-api-jdk8:${Versions.koloboke}" + val junit4 = "junit:junit:${Versions.junit4}" val junit4engine = "org.junit.vintage:junit-vintage-engine" val junit5 = "org.junit.jupiter:junit-jupiter-api:${Versions.junit}" diff --git a/buildSrc/src/main/kotlin/java-common.gradle.kts b/buildSrc/src/main/kotlin/java-common.gradle.kts index dbc37729e0..4981d2394a 100644 --- a/buildSrc/src/main/kotlin/java-common.gradle.kts +++ b/buildSrc/src/main/kotlin/java-common.gradle.kts @@ -47,6 +47,7 @@ tasks { withType() { environment["PATH"] = execPath environment["LD_LIBRARY_PATH"] = libPath + enableAssertions = true } named("jacocoTestReport") { diff --git a/lib/hu.bme.mit.delta-0.0.1-all.jar b/lib/hu.bme.mit.delta-0.0.1-all.jar new file mode 100644 index 0000000000..d12caa97cc Binary files /dev/null and b/lib/hu.bme.mit.delta-0.0.1-all.jar differ diff --git a/settings.gradle.kts b/settings.gradle.kts index 5abd19937b..5421f34ea0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -23,6 +23,9 @@ include( "common/multi-tests", "frontends/c-frontend", + "frontends/petrinet-frontend/petrinet-model", + "frontends/petrinet-frontend/petrinet-analysis", + "frontends/petrinet-frontend/petrinet-xsts", "frontends/chc-frontend", "frontends/llvm", diff --git a/subprojects/cfa/cfa-analysis/README.md b/subprojects/cfa/cfa-analysis/README.md index 3442dd6ecb..1a7cd78736 100644 --- a/subprojects/cfa/cfa-analysis/README.md +++ b/subprojects/cfa/cfa-analysis/README.md @@ -1,9 +1,11 @@ ## Overview -This project contains analysis modules related to the Control Flow Automata (CFA) formalism. Its main purpose is to enable the algorithms to operate over CFA models. +This project contains analysis modules related to the Control Flow Automata (CFA) formalism. Its +main purpose is to enable the algorithms to operate over CFA models. ### Related projects * [`analysis`](../../common/analysis/README.md): Common analysis modules. -* [`cfa`](../cfa/README.md): Classes to represent CFAs and a domain specific language (DSL) to parse CFAs from a textual representation. +* [`cfa`](../cfa/README.md): Classes to represent CFAs and a domain specific language (DSL) to parse + CFAs from a textual representation. * [`cfa-cli`](../cfa-cli/README.md): An executable tool (command line) for running analyses on CFAs. \ No newline at end of file diff --git a/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/DistToErrComparator.java b/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/DistToErrComparator.java index 258e699c8a..ffdc127294 100644 --- a/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/DistToErrComparator.java +++ b/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/DistToErrComparator.java @@ -25,8 +25,8 @@ import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.State; -import hu.bme.mit.theta.analysis.algorithm.ArgNode; -import hu.bme.mit.theta.analysis.algorithm.ArgNodeComparators.ArgNodeComparator; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNode; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNodeComparators.ArgNodeComparator; import hu.bme.mit.theta.cfa.CFA; import hu.bme.mit.theta.cfa.CFA.Edge; import hu.bme.mit.theta.cfa.CFA.Loc; diff --git a/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/config/CfaConfig.java b/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/config/CfaConfig.java index 76006d80fd..299bc4a494 100644 --- a/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/config/CfaConfig.java +++ b/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/config/CfaConfig.java @@ -15,28 +15,27 @@ */ package hu.bme.mit.theta.cfa.analysis.config; -import hu.bme.mit.theta.analysis.Action; -import hu.bme.mit.theta.analysis.Prec; -import hu.bme.mit.theta.analysis.State; +import hu.bme.mit.theta.analysis.*; import hu.bme.mit.theta.analysis.algorithm.SafetyChecker; import hu.bme.mit.theta.analysis.algorithm.SafetyResult; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; public final class CfaConfig { - private final SafetyChecker checker; + private final SafetyChecker, Trace, P> checker; private final P initPrec; - private CfaConfig(final SafetyChecker checker, final P initPrec) { + private CfaConfig(final SafetyChecker, Trace, P> checker, final P initPrec) { this.checker = checker; this.initPrec = initPrec; } public static CfaConfig create( - final SafetyChecker checker, final P initPrec) { + final SafetyChecker, Trace, P> checker, final P initPrec) { return new CfaConfig<>(checker, initPrec); } - public SafetyResult check() { + public SafetyResult, Trace> check() { return checker.check(initPrec); } diff --git a/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/config/CfaConfigBuilder.java b/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/config/CfaConfigBuilder.java index ef0b0dfca7..932f6fe932 100644 --- a/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/config/CfaConfigBuilder.java +++ b/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/config/CfaConfigBuilder.java @@ -15,13 +15,11 @@ */ package hu.bme.mit.theta.cfa.analysis.config; -import hu.bme.mit.theta.analysis.Action; -import hu.bme.mit.theta.analysis.Analysis; -import hu.bme.mit.theta.analysis.Prec; -import hu.bme.mit.theta.analysis.State; -import hu.bme.mit.theta.analysis.algorithm.ArgBuilder; -import hu.bme.mit.theta.analysis.algorithm.ArgNodeComparators; -import hu.bme.mit.theta.analysis.algorithm.ArgNodeComparators.ArgNodeComparator; +import hu.bme.mit.theta.analysis.*; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgBuilder; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNodeComparators; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNodeComparators.ArgNodeComparator; import hu.bme.mit.theta.analysis.algorithm.SafetyChecker; import hu.bme.mit.theta.analysis.algorithm.cegar.Abstractor; import hu.bme.mit.theta.analysis.algorithm.cegar.BasicAbstractor; @@ -431,7 +429,7 @@ public CfaConfig, CfaAction, CfaPrec

> buildConfig(CFA.Loc errLoc) .stopCriterion(refinement.getStopCriterion()) .logger(logger).build(); final Refiner, CfaAction, CfaPrec

> refiner = refinement.getRefiner(this); - final SafetyChecker, CfaAction, CfaPrec

> checker = CegarChecker.create( + final SafetyChecker, CfaAction>, Trace, CfaAction>, CfaPrec

> checker = CegarChecker.create( abstractor, refiner, logger); return CfaConfig.create(checker, createInitPrec()); diff --git a/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/impact/ImpactChecker.java b/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/impact/ImpactChecker.java index d3c83553d7..8aa315a5ab 100644 --- a/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/impact/ImpactChecker.java +++ b/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/impact/ImpactChecker.java @@ -24,18 +24,18 @@ import hu.bme.mit.theta.analysis.Prec; import hu.bme.mit.theta.analysis.State; import hu.bme.mit.theta.analysis.Trace; -import hu.bme.mit.theta.analysis.algorithm.ARG; -import hu.bme.mit.theta.analysis.algorithm.ArgBuilder; -import hu.bme.mit.theta.analysis.algorithm.ArgNode; -import hu.bme.mit.theta.analysis.algorithm.ArgTrace; -import hu.bme.mit.theta.analysis.algorithm.SafetyChecker; import hu.bme.mit.theta.analysis.algorithm.SafetyResult; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgBuilder; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNode; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgTrace; +import hu.bme.mit.theta.analysis.algorithm.SafetyChecker; import hu.bme.mit.theta.analysis.reachedset.ReachedSet; import hu.bme.mit.theta.analysis.waitlist.FifoWaitlist; import hu.bme.mit.theta.analysis.waitlist.Waitlist; public final class ImpactChecker implements - SafetyChecker { + SafetyChecker, Trace, P> { private final ArgBuilder argBuilder; private final ImpactRefiner refiner; @@ -57,7 +57,7 @@ public static ImpactChecker< //// @Override - public SafetyResult check(final P prec) { + public SafetyResult, Trace> check(final P prec) { return new CheckMethod(prec).run(); } @@ -76,7 +76,7 @@ private CheckMethod(final P prec) { reachedSet = ImpactReachedSet.create(partitioning); } - private SafetyResult run() { + private SafetyResult, Trace> run() { final Optional> unsafeNode = unwind(); if (unsafeNode.isPresent()) { diff --git a/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/impact/ImpactReachedSet.java b/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/impact/ImpactReachedSet.java index 82753c530d..1324239d88 100644 --- a/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/impact/ImpactReachedSet.java +++ b/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/impact/ImpactReachedSet.java @@ -29,7 +29,7 @@ import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.State; -import hu.bme.mit.theta.analysis.algorithm.ArgNode; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNode; import hu.bme.mit.theta.analysis.reachedset.ReachedSet; public final class ImpactReachedSet implements diff --git a/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/impact/PredImpactChecker.java b/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/impact/PredImpactChecker.java index 05102cda2a..81882c1683 100644 --- a/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/impact/PredImpactChecker.java +++ b/subprojects/cfa/cfa-analysis/src/main/java/hu/bme/mit/theta/cfa/analysis/impact/PredImpactChecker.java @@ -17,9 +17,11 @@ import hu.bme.mit.theta.analysis.Analysis; import hu.bme.mit.theta.analysis.LTS; -import hu.bme.mit.theta.analysis.algorithm.ArgBuilder; +import hu.bme.mit.theta.analysis.Trace; import hu.bme.mit.theta.analysis.algorithm.SafetyChecker; import hu.bme.mit.theta.analysis.algorithm.SafetyResult; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgBuilder; import hu.bme.mit.theta.analysis.expr.ExprAction; import hu.bme.mit.theta.analysis.impl.PrecMappingAnalysis; import hu.bme.mit.theta.analysis.pred.PredAbstractors; @@ -42,7 +44,7 @@ import static hu.bme.mit.theta.core.type.booltype.BoolExprs.True; import static java.util.Collections.emptySet; -public final class PredImpactChecker implements SafetyChecker, CfaAction, UnitPrec> { +public final class PredImpactChecker implements SafetyChecker, CfaAction>, Trace, CfaAction>, UnitPrec> { private final ImpactChecker, CfaAction, UnitPrec> checker; @@ -82,7 +84,7 @@ public static PredImpactChecker create(final LTS, Cf } @Override - public SafetyResult, CfaAction> check(final UnitPrec prec) { + public SafetyResult, CfaAction>, Trace, CfaAction>> check(final UnitPrec prec) { return checker.check(prec); } diff --git a/subprojects/cfa/cfa-analysis/src/test/java/hu/bme/mit/theta/cfa/analysis/CfaTest.java b/subprojects/cfa/cfa-analysis/src/test/java/hu/bme/mit/theta/cfa/analysis/CfaTest.java index 2b9040c954..a996b3fc83 100644 --- a/subprojects/cfa/cfa-analysis/src/test/java/hu/bme/mit/theta/cfa/analysis/CfaTest.java +++ b/subprojects/cfa/cfa-analysis/src/test/java/hu/bme/mit/theta/cfa/analysis/CfaTest.java @@ -20,6 +20,7 @@ import hu.bme.mit.theta.analysis.State; import hu.bme.mit.theta.analysis.Trace; import hu.bme.mit.theta.analysis.algorithm.SafetyResult; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; import hu.bme.mit.theta.analysis.expl.ExplState; import hu.bme.mit.theta.cfa.CFA; import hu.bme.mit.theta.cfa.analysis.config.CfaConfig; @@ -172,11 +173,11 @@ public void test() throws Exception { CfaConfig config = new CfaConfigBuilder(domain, refinement, solverFactory).build(cfa, cfa.getErrorLoc().get()); - SafetyResult result = config.check(); + SafetyResult result = config.check(); Assert.assertEquals(isSafe, result.isSafe()); if (result.isUnsafe()) { Trace, CfaAction> trace = CfaTraceConcretizer.concretize( - (Trace, CfaAction>) result.asUnsafe().getTrace(), + (Trace, CfaAction>) result.asUnsafe().getCex(), solverFactory); Assert.assertEquals(cexLength, trace.length()); } diff --git a/subprojects/cfa/cfa-analysis/src/test/java/hu/bme/mit/theta/cfa/analysis/impact/CfaPredImpactCheckerTest.java b/subprojects/cfa/cfa-analysis/src/test/java/hu/bme/mit/theta/cfa/analysis/impact/CfaPredImpactCheckerTest.java index 317e0f3ec1..4204a3785d 100644 --- a/subprojects/cfa/cfa-analysis/src/test/java/hu/bme/mit/theta/cfa/analysis/impact/CfaPredImpactCheckerTest.java +++ b/subprojects/cfa/cfa-analysis/src/test/java/hu/bme/mit/theta/cfa/analysis/impact/CfaPredImpactCheckerTest.java @@ -21,12 +21,16 @@ import java.io.FileNotFoundException; import java.io.IOException; +import hu.bme.mit.theta.analysis.Trace; +import hu.bme.mit.theta.analysis.algorithm.SafetyResult; +import hu.bme.mit.theta.analysis.pred.PredState; +import hu.bme.mit.theta.cfa.analysis.CfaAction; +import hu.bme.mit.theta.cfa.analysis.CfaState; import hu.bme.mit.theta.solver.Solver; import org.junit.Test; -import hu.bme.mit.theta.analysis.algorithm.ARG; -import hu.bme.mit.theta.analysis.algorithm.ArgChecker; -import hu.bme.mit.theta.analysis.algorithm.SafetyResult; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgChecker; import hu.bme.mit.theta.analysis.expr.ExprAction; import hu.bme.mit.theta.analysis.expr.ExprState; import hu.bme.mit.theta.analysis.unit.UnitPrec; @@ -54,13 +58,13 @@ public void test() throws FileNotFoundException, IOException { l -> l.equals(cfa.getErrorLoc().get()), abstractionSolver, refinementSolver); // Act - final SafetyResult status = checker.check( + final SafetyResult, CfaAction>, Trace, CfaAction>> status = checker.check( UnitPrec.getInstance()); // Assert assertTrue(status.isSafe()); - final ARG arg = status.getArg(); + final ARG arg = status.getWitness(); arg.minimize(); final ArgChecker argChecker = ArgChecker.create(abstractionSolver); diff --git a/subprojects/cfa/cfa-cli/README.md b/subprojects/cfa/cfa-cli/README.md index 8b9d53b38f..a13d29e3e8 100644 --- a/subprojects/cfa/cfa-cli/README.md +++ b/subprojects/cfa/cfa-cli/README.md @@ -1,44 +1,63 @@ ## Overview -The `cfa-cli` project is an executable (command line) tool for running CEGAR-based location-reachability analyses on CFAs. +The `cfa-cli` project is an executable (command line) tool for running CEGAR-based +location-reachability analyses on CFAs. Furthermore, it also includes some utilities, such as calculating metrics or visualizing the CFA. -For more information about the CFA formalism and its supported language elements, take a look at the [`cfa`](../cfa/README.md) project. +For more information about the CFA formalism and its supported language elements, take a look at +the [`cfa`](../cfa/README.md) project. ### Related projects -* [`cfa`](../cfa/README.md): Classes to represent CFAs and a domain specific language (DSL) to parse CFAs from a textual representation. -* [`cfa-analysis`](../cfa-analysis/README.md): CFA specific analysis modules enabling the algorithms to operate on them. +* [`cfa`](../cfa/README.md): Classes to represent CFAs and a domain specific language (DSL) to parse + CFAs from a textual representation. +* [`cfa-analysis`](../cfa-analysis/README.md): CFA specific analysis modules enabling the algorithms + to operate on them. ### Frontends -* [Gazer](https://github.com/ftsrg/gazer) is an [LLVM](https://llvm.org/)-based frontend to verify C programs using theta-cfa-cli, also giving support towards [SV-COMP](https://sv-comp.sosy-lab.org/2021/). See our [tool paper at TACAS](https://ftsrg.mit.bme.hu/theta/publications/tacas2021.pdf) for more information. -* [PLCverif](https://cern.ch/plcverif) is a tool developed at CERN for the formal specification and verification of PLC (Programmable Logic Controller) programs, supporting theta-cfa-cli as one of its verification backends. +* [Gazer](https://github.com/ftsrg/gazer) is an [LLVM](https://llvm.org/)-based frontend to verify C + programs using theta-cfa-cli, also giving support + towards [SV-COMP](https://sv-comp.sosy-lab.org/2021/). See + our [tool paper at TACAS](https://ftsrg.mit.bme.hu/theta/publications/tacas2021.pdf) for more + information. +* [PLCverif](https://cern.ch/plcverif) is a tool developed at CERN for the formal specification and + verification of PLC (Programmable Logic Controller) programs, supporting theta-cfa-cli as one of + its verification backends. ## Using the tool 1. First, get the tool. * The easiest way is to download a [pre-built release](https://github.com/ftsrg/theta/releases). - * You can also [build](../../../doc/Build.md) the tool yourself. The runnable jar file will appear under _build/libs/_ with the name _theta-cfa-cli-\-all.jar_, you can simply rename it to _theta-cfa-cli.jar_. + * You can also [build](../../../doc/Build.md) the tool yourself. The runnable jar file will + appear under _build/libs/_ with the name _theta-cfa-cli-\-all.jar_, you can simply + rename it to _theta-cfa-cli.jar_. * Alternatively, you can use our docker image (see below). 2. Running the tool requires Java (JRE) 17. -3. The tool also requires the [Z3 SMT solver libraries](../../../doc/Build.md) to be available on `PATH`. +3. The tool also requires the [Z3 SMT solver libraries](../../../doc/Build.md) to be available + on `PATH`. 4. The tool can be executed with `java -jar theta-cfa-cli.jar [ARGUMENTS]`. - * If no arguments are given, a help screen is displayed about the arguments and their possible values. - More information can also be found below. - * For example `java -jar theta-cfa-cli.jar --model counter.cfa --loglevel INFO` runs the default analysis with logging on the `counter.cfa` input file. + * If no arguments are given, a help screen is displayed about the arguments and their possible + values. + More information can also be found below. + * For example `java -jar theta-cfa-cli.jar --model counter.cfa --loglevel INFO` runs the default + analysis with logging on the `counter.cfa` input file. ### Docker A Dockerfile is also available under the _docker_ directory in the root of the repository. The image can be built using the following command (from the root of the repository): + ``` docker build -t theta-cfa-cli -f docker/theta-cfa-cli.Dockerfile . ``` -The script `run-theta-cfa-cli.sh` can be used for running the containerized version on models residing on the host: +The script `run-theta-cfa-cli.sh` can be used for running the containerized version on models +residing on the host: + ``` ./docker/run-theta-cfa-cli.sh model.cfa [OTHER ARGUMENTS] ``` + Note that the model must be given as the first positional argument (without `--model`). ## Arguments @@ -46,22 +65,30 @@ Note that the model must be given as the first positional argument (without `--m All arguments are optional, except `--model`. * `--model`: Path of the input CFA model (mandatory). -* `--errorloc`: Name of the error (target) location in the CFA, which is checked for reachability. The CFA is safe if the error location is not reachable, and unsafe otherwise. This argument can be omitted if a location in the CFA is marked with the error keyword. If there is an error location marked in the CFA and this argument is also given, the argument has priority. -* `--cex`: Output file where the counterexample is written (if the result is unsafe). If the argument is not given (default) the counterexample is not printed. Use `CON` (Windows) or `/dev/stdout` (Linux) as argument to print to the standard output. +* `--errorloc`: Name of the error (target) location in the CFA, which is checked for reachability. + The CFA is safe if the error location is not reachable, and unsafe otherwise. This argument can be + omitted if a location in the CFA is marked with the error keyword. If there is an error location + marked in the CFA and this argument is also given, the argument has priority. +* `--cex`: Output file where the counterexample is written (if the result is unsafe). If the + argument is not given (default) the counterexample is not printed. Use `CON` (Windows) + or `/dev/stdout` (Linux) as argument to print to the standard output. * `--loglevel`: Detailedness of logging. - * Possible values (from the least to the most detailed): `RESULT`, `MAINSTEP`, `SUBSTEP` (default), `INFO`, `DETAIL`, `VERBOSE`. + * Possible values (from the least to the most detailed): `RESULT`, `MAINSTEP`, `SUBSTEP` ( + default), `INFO`, `DETAIL`, `VERBOSE`. * `--metrics`: Print metrics about the CFA without running the algorithm. * `--visualize`: Visualize the CFA without running the algorithm. -If the extension of the output file is `pdf`, `png` or `svg` an automatic visualization is performed, for which [GraphViz](../../../doc/Build.md) has to be available on `PATH`. -Otherwise, the output is simply in `dot` format. + If the extension of the output file is `pdf`, `png` or `svg` an automatic visualization is + performed, for which [GraphViz](../../../doc/Build.md) has to be available on `PATH`. + Otherwise, the output is simply in `dot` format. * `--version`: Print version info (in this case `--model` is of course not required). -The arguments related to the algorithm are described in more detail (along with best practices) in [CEGAR-algorithms.md](../../../doc/CEGAR-algorithms.md). +The arguments related to the algorithm are described in more detail (along with best practices) +in [CEGAR-algorithms.md](../../../doc/CEGAR-algorithms.md). ### For developer usage -| Flag | Description | -|--|--| -| `--stacktrace` | Print full stack trace for exceptions. | -| `--benchmark` | Benchmark mode, only print metrics in csv format. | -| `--header` | Print the header for the benchmark mode csv format. | +| Flag | Description | +|----------------|-----------------------------------------------------| +| `--stacktrace` | Print full stack trace for exceptions. | +| `--benchmark` | Benchmark mode, only print metrics in csv format. | +| `--header` | Print the header for the benchmark mode csv format. | diff --git a/subprojects/cfa/cfa-cli/src/main/java/hu/bme/mit/theta/cfa/cli/CfaCli.java b/subprojects/cfa/cfa-cli/src/main/java/hu/bme/mit/theta/cfa/cli/CfaCli.java index cdc5296979..bb5a27107d 100644 --- a/subprojects/cfa/cfa-cli/src/main/java/hu/bme/mit/theta/cfa/cli/CfaCli.java +++ b/subprojects/cfa/cfa-cli/src/main/java/hu/bme/mit/theta/cfa/cli/CfaCli.java @@ -21,7 +21,7 @@ import com.google.common.base.Stopwatch; import hu.bme.mit.theta.analysis.Trace; import hu.bme.mit.theta.analysis.algorithm.SafetyResult; -import hu.bme.mit.theta.analysis.algorithm.SafetyResult.Unsafe; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; import hu.bme.mit.theta.analysis.algorithm.cegar.CegarStatistics; import hu.bme.mit.theta.analysis.expl.ExplState; import hu.bme.mit.theta.analysis.expr.refinement.PruneStrategy; @@ -233,7 +233,7 @@ private void run() { refinementSolverFactory = SolverManager.resolveSolverFactory(solver); } - final SafetyResult status; + final SafetyResult, ? extends Trace> status; if (algorithm == Algorithm.CEGAR) { final CfaConfig configuration = buildConfiguration(cfa, errLoc, abstractionSolverFactory, refinementSolverFactory); status = check(configuration); @@ -282,7 +282,7 @@ private CFA loadModel() throws Exception { } } - private SafetyResult check(CfaConfig configuration) throws Exception { + private SafetyResult, ? extends Trace> check(CfaConfig configuration) throws Exception { try { return configuration.check(); } catch (final Exception ex) { @@ -293,7 +293,7 @@ private CFA loadModel() throws Exception { } } - private void printResult(final SafetyResult status, final long totalTimeMs) { + private void printResult(final SafetyResult, ? extends Trace> status, final long totalTimeMs) { final CegarStatistics stats = (CegarStatistics) status.getStats().orElse(new CegarStatistics(0, 0, 0, 0)); if (benchmarkMode) { @@ -303,11 +303,11 @@ private void printResult(final SafetyResult status, final long totalTimeMs writer.cell(stats.getAbstractorTimeMs()); writer.cell(stats.getRefinerTimeMs()); writer.cell(stats.getIterations()); - writer.cell(status.getArg().size()); - writer.cell(status.getArg().getDepth()); - writer.cell(status.getArg().getMeanBranchingFactor()); + writer.cell(status.getWitness().size()); + writer.cell(status.getWitness().getDepth()); + writer.cell(status.getWitness().getMeanBranchingFactor()); if (status.isUnsafe()) { - writer.cell(status.asUnsafe().getTrace().length() + ""); + writer.cell(status.asUnsafe().getCex().length() + ""); } else { writer.cell(""); } @@ -333,8 +333,8 @@ private void printError(final Throwable ex) { } } - private void writeCex(final Unsafe status) throws FileNotFoundException { - @SuppressWarnings("unchecked") final Trace, CfaAction> trace = (Trace, CfaAction>) status.getTrace(); + private void writeCex(final SafetyResult.Unsafe status) throws FileNotFoundException { + @SuppressWarnings("unchecked") final Trace, CfaAction> trace = (Trace, CfaAction>) status.getCex(); final Trace, CfaAction> concrTrace = CfaTraceConcretizer.concretize( trace, Z3LegacySolverFactory.getInstance()); final File file = new File(cexfile); diff --git a/subprojects/cfa/cfa/README.md b/subprojects/cfa/cfa/README.md index ec1c12891d..71351f4907 100644 --- a/subprojects/cfa/cfa/README.md +++ b/subprojects/cfa/cfa/README.md @@ -1,13 +1,17 @@ ## Overview -This project contains the Control Flow Automata (CFA) formalism. Its main purpose is to describe programs as a graphs, where nodes correspond to program locations and edges are annotated with program statements. +This project contains the Control Flow Automata (CFA) formalism. Its main purpose is to describe +programs as a graphs, where nodes correspond to program locations and edges are annotated with +program statements. The project contains: + * Classes to represent CFAs. * A domain specific language (DSL) to parse CFAs from a textual representation. ### Related projects -* [`cfa-analysis`](../cfa-analysis/README.md): CFA specific analysis modules enabling the algorithms to operate on them. +* [`cfa-analysis`](../cfa-analysis/README.md): CFA specific analysis modules enabling the algorithms + to operate on them. * [`cfa-cli`](../cfa-cli/README.md): An executable (command line) tool for running analyses on CFAs. ## CFA formalism @@ -15,60 +19,99 @@ The project contains: A CFA is a directed graph (`V`, `L`, `E`) with * variables `V = {v1, v2, ..., vn}`, -* locations `L`, with a dedicated initial (`l0`) location and optionally with dedicated final (`lf`) and error (`le`) locations, +* locations `L`, with a dedicated initial (`l0`) location and optionally with dedicated final (`lf`) + and error (`le`) locations, * edges `E` between locations, labeled with statements over the variables. Currently, there are three kind of supported statements. -* Assignments have the form `v := expr`, where `expr` is a side-effect free expression with the same type as `v`. -After performing the assignment statement, the value of variable `v` is the result of evaluating `expr`. -For example, if `x` is `1` and the assignment `x := x + 1` is performed, `x` becomes `2` (and the rest of the variables are unchanged). + +* Assignments have the form `v := expr`, where `expr` is a side-effect free expression with the same + type as `v`. + After performing the assignment statement, the value of variable `v` is the result of + evaluating `expr`. + For example, if `x` is `1` and the assignment `x := x + 1` is performed, `x` becomes `2` (and the + rest of the variables are unchanged). * Assumptions have the form `assume expr`, where `expr` is a side-effect free Boolean expression. -It is only possible to take the edge if `expr` evaluates to true. -For example, `assume x == 0` can be taken if and only if `x` equals `0`. -After the assumption, variables are unchanged. + It is only possible to take the edge if `expr` evaluates to true. + For example, `assume x == 0` can be taken if and only if `x` equals `0`. + After the assumption, variables are unchanged. * Havocs have the form `havoc v`. -After performing the havoc, `v` is assigned a non-deterministic value. -This can be used to simulate non-deterministic input from the user or the environment. + After performing the havoc, `v` is assigned a non-deterministic value. + This can be used to simulate non-deterministic input from the user or the environment. -Algorithms are usually interested in proving that the error location (given in the CFA or as a separate argument) is not reachable. -For more information see Section 2 of the [Software Verification Supplementary Material](https://ftsrg.mit.bme.hu/software-verification-notes/software-verification.pdf), which also includes examples on how to encode programs as CFA. +Algorithms are usually interested in proving that the error location (given in the CFA or as a +separate argument) is not reachable. +For more information see Section 2 of +the [Software Verification Supplementary Material](https://ftsrg.mit.bme.hu/software-verification-notes/software-verification.pdf), +which also includes examples on how to encode programs as CFA. Variables of the CFA can have the following types. + * `bool`: Booleans. * `int`: Mathematical, unbounded SMT integers. * `rat`: Rational numbers (implemented as SMT reals). * `[K] -> V`: SMT arrays (associative maps) from a given key type `K` to a value type `V`. -* `bv[L]`: Bitvector of given length `L`. _This is an experimental feature. See the [details](doc/bitvectors.md) for more information._ -* `fp[E:S]`: Floating point of given size exponent `E` and significand `S`. Significand size should include the hidden bit as well. The type corresponds to the FloatingPoint type in the [SMT-LIB theory](https://smtlib.cs.uiowa.edu/theories-FloatingPoint.shtml). _Note that this feature currently only works on Linux and Windows due to the required MPFR library. Using this feature on Windows is experimental, and can cause cryptic exceptions to occur in native code (such as an assertion failure in an init.c file). _ +* `bv[L]`: Bitvector of given length `L`. _This is an experimental feature. See + the [details](doc/bitvectors.md) for more information._ +* `fp[E:S]`: Floating point of given size exponent `E` and significand `S`. Significand size should + include the hidden bit as well. The type corresponds to the FloatingPoint type in + the [SMT-LIB theory](https://smtlib.cs.uiowa.edu/theories-FloatingPoint.shtml). _Note that this + feature currently only works on Linux and Windows due to the required MPFR library. Using this + feature on Windows is experimental, and can cause cryptic exceptions to occur in native code (such + as an assertion failure in an init.c file). _ Expressions of the CFA include the following. + * Identifiers (variables). * Literals, e.g., `true`, `false` (Bool), `0`, `123` (integer), `4 % 5` (rational). - * Array literals can be given by listing the key-value pairs and the (mandatory) default element, e.g., `[0 <- 182, 1 <- 41, default <- 75]`. If there are no elements, the key type has to be given before the default element, e.g., `[default <- 75]`. Note that any expression can be used as a value, but this will only result in an ArrayLitExpr when all operands are literals, or can be simplified to literals. Otherwise, this construct will yield an `ArrayInitExpr`, which is semantically equivalent to successive writes to an otherwise empty array, containing only the _else_ value for every index. - * Bitvector literals can be given by stating the length and the exact value of the bitvector in binary, decimal or hexadecimal form. (E.g. `4'd5` is a 4-bit-long bitvector with the decimal value 5.) _This is an experimental feature. See the [details](doc/bitvectors.md) for more information._ - * Floating point literals can be given in the following form: `[+-]?bitvector.bitvector`, defining the optional sign (+/-), exponent and significand in this order. (E.g. `+5'b10000.10'd0` is `+2.0f` of type `fp[5:11]` (half-precision IEEE-754 float)). The value is calculated the following way (using `e` for exponent size, and `E`, `S` for values, `h` for sign): `value = (-1)^h * 1.S * 2^(E-2^(e-1)+1)` + * Array literals can be given by listing the key-value pairs and the (mandatory) default + element, e.g., `[0 <- 182, 1 <- 41, default <- 75]`. If there are no elements, the key type + has to be given before the default element, e.g., `[default <- 75]`. Note that any + expression can be used as a value, but this will only result in an ArrayLitExpr when all + operands are literals, or can be simplified to literals. Otherwise, this construct will yield + an `ArrayInitExpr`, which is semantically equivalent to successive writes to an otherwise + empty array, containing only the _else_ value for every index. + * Bitvector literals can be given by stating the length and the exact value of the bitvector in + binary, decimal or hexadecimal form. (E.g. `4'd5` is a 4-bit-long bitvector with the decimal + value 5.) _This is an experimental feature. See the [details](doc/bitvectors.md) for more + information._ + * Floating point literals can be given in the following form: `[+-]?bitvector.bitvector`, + defining the optional sign (+/-), exponent and significand in this order. ( + E.g. `+5'b10000.10'd0` is `+2.0f` of type `fp[5:11]` (half-precision IEEE-754 float)). The + value is calculated the following way (using `e` for exponent size, and `E`, `S` for + values, `h` for sign): `value = (-1)^h * 1.S * 2^(E-2^(e-1)+1)` * Comparison, e.g., `=`, `/=`, `<`, `>`, `<=`, `>=`. * Boolean operators, e.g., `and`, `or`, `xor`, `not`, `imply`, `iff`. * Arithmetic, e.g., `+`, `-`, `/`, `*`, `mod`, `rem`. * Conditional: `if . then . else .`. * Array read (`a[i]`) and write (`a[i <- v]`). -* Bitvector specific operators, e.g., `bvand`, `bvor`, `bvxor`, `bvshl`, `bvashr`, `bvlshr`, `bvrol`, `bvror`, `bvnot`, etc. _This is an experimental feature. See the [details](doc/bitvectors.md) for more information._ -* Floating point operators are special in the sense that extra arguments can be passed to them via brackets. - * Arithmetic: `fprem[ROUNDING?]`, `fpsub[ROUNDING?]`, `fpadd[ROUNDING?]`, `fpmul[ROUNDING?]`, `fpdiv[ROUNDING?]`, `fppos[ROUNDING?]`, `fpneg[ROUNDING?]` - * Conversion: `fpfrombv[FPTYPE][SIGNEDNESS][ROUNDING?]`, `fptobv[BVTYPE][ROUNDING?]`, `fptofp[FPTYPE][ROUNDING?]` - * Unary functions: `fpisnan`, `fpabs`, `fproundtoint[ROUNDING?]`, `fpsqrt[ROUNDING?` - * Binary functions: `fpmin[ROUNDING?]`, `fpmax[ROUNDING?]` - * Where - * `ROUNDING` is one of {RNE, RNA, RTP, RTZ, RTN}, - * `FPTYPE` is of the form `[exp:sig]`, - * `SIGNEDNESS` is either `u` or `s`, - * `BVTYPE` is of the form `size'SIGNEDNESS`. - * E.g. `fpfrombv[5:11][u][RNE]` creates an `FpFromBvExpr` with rounding mode `RNE` that transforms an `unsigned` bitvector into a half-precision IEEE-754 float. The same happens when `[RNE]` is omitted in `fpfrombv[5:11][u]`, as `RNE` is the default rounding mode. - * Note that the regular operators (`=`, `+`, `*`, etc.; except for `mod` and `rem`) still work for FpTypes with a default rounding mode of RNE. +* Bitvector specific operators, + e.g., `bvand`, `bvor`, `bvxor`, `bvshl`, `bvashr`, `bvlshr`, `bvrol`, `bvror`, `bvnot`, etc. _This + is an experimental feature. See the [details](doc/bitvectors.md) for more information._ +* Floating point operators are special in the sense that extra arguments can be passed to them via + brackets. + * + Arithmetic: `fprem[ROUNDING?]`, `fpsub[ROUNDING?]`, `fpadd[ROUNDING?]`, `fpmul[ROUNDING?]`, `fpdiv[ROUNDING?]`, `fppos[ROUNDING?]`, `fpneg[ROUNDING?]` + * + Conversion: `fpfrombv[FPTYPE][SIGNEDNESS][ROUNDING?]`, `fptobv[BVTYPE][ROUNDING?]`, `fptofp[FPTYPE][ROUNDING?]` + * Unary functions: `fpisnan`, `fpabs`, `fproundtoint[ROUNDING?]`, `fpsqrt[ROUNDING?` + * Binary functions: `fpmin[ROUNDING?]`, `fpmax[ROUNDING?]` + * Where + * `ROUNDING` is one of {RNE, RNA, RTP, RTZ, RTN}, + * `FPTYPE` is of the form `[exp:sig]`, + * `SIGNEDNESS` is either `u` or `s`, + * `BVTYPE` is of the form `size'SIGNEDNESS`. + * E.g. `fpfrombv[5:11][u][RNE]` creates an `FpFromBvExpr` with rounding mode `RNE` that + transforms an `unsigned` bitvector into a half-precision IEEE-754 float. The same happens + when `[RNE]` is omitted in `fpfrombv[5:11][u]`, as `RNE` is the default rounding mode. + * Note that the regular operators (`=`, `+`, `*`, etc.; except for `mod` and `rem`) still work + for FpTypes with a default rounding mode of RNE. ### Textual representation (DSL) -As an example, consider a simple program (written in a C-like language) that counts up to 5 and asserts the result to be less than or equal to 5: +As an example, consider a simple program (written in a C-like language) that counts up to 5 and +asserts the result to be less than or equal to 5: + ```c int x = 0; while (x < 5) { @@ -78,6 +121,7 @@ assert x <= 5; ``` The program above can be represented by the following CFA: + ``` main process counter { var x : int @@ -97,19 +141,24 @@ main process counter { L3 -> ERR { assume not (x <= 5) } } ``` + Note that for example the loop in the program appears as a cycle (`L1 -> L2 -> L1`) in the CFA. -The assertion is modeled with a branching in the CFA: if it holds, `L3 -> END` is taken, otherwise `L3 -> ERR`. +The assertion is modeled with a branching in the CFA: if it holds, `L3 -> END` is taken, +otherwise `L3 -> ERR`. -Variables can be defined by `var : `, locations by `(init|final|error|) loc `, and edges by ` -> {}`. +Variables can be defined by `var : `, locations by `(init|final|error|) loc `, +and edges by ` -> {}`. As a syntactic sugar, it is possible to include multiple statements on one edge (in new lines). In this case, anonymus intermediate locations will automatically be introduced when parsing the CFA. For example, + ``` L0 -> L1 { x := 0 assume x >= 0 } ``` + introduces an intermediate location `""` (with an empty string as name) between `L0` and `L1`. There will be an edge `x := 0` from `L0`to `""` and an edge `assume x >= 0` from `""` to `L1`. @@ -117,5 +166,11 @@ See _src/test/resources_ for more examples and _src/main/antlr_ for the full gra ### Frontends -* [Gazer](https://github.com/ftsrg/gazer) is an [LLVM](https://llvm.org/)-based frontend to verify C programs using theta-cfa-cli, also giving support towards [SV-COMP](https://sv-comp.sosy-lab.org/2021/). See our [tool paper at TACAS](https://ftsrg.mit.bme.hu/theta/publications/tacas2021.pdf) for more information. -* [PLCverif](https://cern.ch/plcverif) is a tool developed at CERN for the formal specification and verification of PLC (Programmable Logic Controller) programs, supporting theta-cfa-cli as one of its verification backends. +* [Gazer](https://github.com/ftsrg/gazer) is an [LLVM](https://llvm.org/)-based frontend to verify C + programs using theta-cfa-cli, also giving support + towards [SV-COMP](https://sv-comp.sosy-lab.org/2021/). See + our [tool paper at TACAS](https://ftsrg.mit.bme.hu/theta/publications/tacas2021.pdf) for more + information. +* [PLCverif](https://cern.ch/plcverif) is a tool developed at CERN for the formal specification and + verification of PLC (Programmable Logic Controller) programs, supporting theta-cfa-cli as one of + its verification backends. diff --git a/subprojects/cfa/cfa/doc/bitvectors.md b/subprojects/cfa/cfa/doc/bitvectors.md index dbab527f46..612d481715 100644 --- a/subprojects/cfa/cfa/doc/bitvectors.md +++ b/subprojects/cfa/cfa/doc/bitvectors.md @@ -4,9 +4,15 @@ As of now, Theta has basic bitvector support for the CFA formalism. ## Overview -In Theta, every bitvector has a positive length. It follows, that the range of every bitvector has a size of 2n. There are different operations that are available for bitvectors. It is important to note, that (usually) only operations between bitvectors with the same size are valid. +In Theta, every bitvector has a positive length. It follows, that the range of every bitvector has a +size of 2n. There are different operations that are available for bitvectors. It is +important to note, that (usually) only operations between bitvectors with the same size are valid. -Bitvectors have n bits. Interpreting the signedness (signed/unsigned) of bitvectors depend on the operations (e.g., signed greater vs unsigned greater). If the bitvector is interpreted as an unsigned number then the values of the bits are interpreted as the binary representation of the underlying number. However, if the bitvector is interpreted as a signed number then the values of the bits are interpreted as the two's complement representation of the underlying number. +Bitvectors have n bits. Interpreting the signedness (signed/unsigned) of bitvectors depend on the +operations (e.g., signed greater vs unsigned greater). If the bitvector is interpreted as an +unsigned number then the values of the bits are interpreted as the binary representation of the +underlying number. However, if the bitvector is interpreted as a signed number then the values of +the bits are interpreted as the two's complement representation of the underlying number. ## Declaring bitvector variables @@ -19,20 +25,24 @@ var x2 : bv[7] // 7-bit-long bitvector ## Bitvector literals -There is a new literal, the bitvector literal that can be used to create bitvectors. Each literal defines the size of the literal. Moreover, each literal can be entered using three different formats: +There is a new literal, the bitvector literal that can be used to create bitvectors. Each literal +defines the size of the literal. Moreover, each literal can be entered using three different +formats: - The bitwise precise binary form - The bitwise precise hexadecimal form - And the non-bitwise-precise, although user-friendly decimal form -The two bitwise precise forms specify the value for all bits directly. These are useful for "unsigned" bitvectors, where there is no two's complement behavior (e.g. bitfields). +The two bitwise precise forms specify the value for all bits directly. These are useful for " +unsigned" bitvectors, where there is no two's complement behavior (e.g. bitfields). ``` 4'b0010 // 4-bit-long bitvector literal (binary form) 8'xAF // 8-bit-long bitvector literal (hexadecimal form) ``` -The non-bitwise-precise decimal form can be used to create bitvectors that are based on numbers. This form is recommended for "signed" bitvectors, or "unsigned" bitvectors that are not bitfields. +The non-bitwise-precise decimal form can be used to create bitvectors that are based on numbers. +This form is recommended for "signed" bitvectors, or "unsigned" bitvectors that are not bitfields. ``` 4'd5 // 4-bit-long bitvector literal (decimal form, positive value) @@ -41,27 +51,38 @@ The non-bitwise-precise decimal form can be used to create bitvectors that are b ## Operations on bitvectors -The following operations are defined on bitvectors. As a general rule, every binary operation requires the bitvector on the left-hand side and the bitvector on the right-hand side to have the same size. +The following operations are defined on bitvectors. As a general rule, every binary operation +requires the bitvector on the left-hand side and the bitvector on the right-hand side to have the +same size. -The operators and their precedence are based on the [operators in C langauge](https://en.cppreference.com/w/c/language/operator_precedence). +The operators and their precedence are based on +the [operators in C langauge](https://en.cppreference.com/w/c/language/operator_precedence). ### Basic arithmetic operations -These operations perform basic arithmetic operations on bitvectors. These operations require that the bitvector on the left-hand side and the bitvector on the right-hand side have the same size. These operations overflow! +These operations perform basic arithmetic operations on bitvectors. These operations require that +the bitvector on the left-hand side and the bitvector on the right-hand side have the same size. +These operations overflow! - **Addition:** Adds two bitvectors; `a bvadd b` - **Subtraction:** Subtracts a from b; `a bvsub b` - **Multiplication:** Multiplies two bitvectors; `a bvmul b` -- **Unsigned integer division:** Divides two bitvectors interpreted as unsigned numbers, and takes the integer part of the result; `a bvudiv b` -- **Signed integer division:** Divides two bitvectors interpreted as signed numbers, and takes the integer part of the result; `a bvsdiv b` +- **Unsigned integer division:** Divides two bitvectors interpreted as unsigned numbers, and takes + the integer part of the result; `a bvudiv b` +- **Signed integer division:** Divides two bitvectors interpreted as signed numbers, and takes the + integer part of the result; `a bvsdiv b` - **(Signed) Modulo:** Calculates (a mod b); `a bvsmod b` -- **Unsigned remainder:** Calculates the remainder of a / b interpreted as unsigned numbers; `a bvurem b` -- **Signed remainder:** Calculates the remainder of a / b interpreted as signed numbers; `a bvsrem b` +- **Unsigned remainder:** Calculates the remainder of a / b interpreted as unsigned + numbers; `a bvurem b` +- **Signed remainder:** Calculates the remainder of a / b interpreted as signed + numbers; `a bvsrem b` - **Negate:** Negates the value of a (only valid for signed bitvectors); `bvneg a` ### Bitvector specific operations -These operations are specific to bitvectors only. These operations require that the bitvector on the left-hand side and the bitvector on the right-hand side have the same size. For the exact semantics check out the respective operators in C. These operations overflow! +These operations are specific to bitvectors only. These operations require that the bitvector on the +left-hand side and the bitvector on the right-hand side have the same size. For the exact semantics +check out the respective operators in C. These operations overflow! - **Bitwise and**: Ands two bitvectors; `a bvand b` - **Bitwise or**: Ors two bitvectors; `a bvor b` @@ -75,28 +96,45 @@ These operations are specific to bitvectors only. These operations require that The following four operators are special operators specific to bitvectors. -- **Concatenation**: Concatenates two bitvectors. The bitvectors do not have to be the same size; `a ++ b` -- **Extraction**: Extracts a part of the bitvector. The indexes must be constant integer literals. Parameter from is interpreted as the starting index (with the least significant bit being 0), while parameter until is interpreted as the (exclusive) ending index (with the least significant bit being 0). The result is a bitvector of length _until-from_; `a[until:from]` -- **Zero extend**: Extends the size of the bitvector to size N. The new bits will have the value 0; `a bv_zero_extend bv[N]` -- **Sign extend**: Extends the size of the bitvector to size N. The new bits will have the value of the most significant bit of a; `a bv_sign_extend bv[N]` +- **Concatenation**: Concatenates two bitvectors. The bitvectors do not have to be the same + size; `a ++ b` +- **Extraction**: Extracts a part of the bitvector. The indexes must be constant integer literals. + Parameter from is interpreted as the starting index (with the least significant bit being 0), + while parameter until is interpreted as the (exclusive) ending index (with the least significant + bit being 0). The result is a bitvector of length _until-from_; `a[until:from]` +- **Zero extend**: Extends the size of the bitvector to size N. The new bits will have the value + 0; `a bv_zero_extend bv[N]` +- **Sign extend**: Extends the size of the bitvector to size N. The new bits will have the value of + the most significant bit of a; `a bv_sign_extend bv[N]` ### Relational operations -These operations encode relational operations between bitvectors. These operations require that the bitvector on the left-hand side and the bitvector on the right-hand side have the same size. +These operations encode relational operations between bitvectors. These operations require that the +bitvector on the left-hand side and the bitvector on the right-hand side have the same size. - **Equality**: Checks if a equals to b; `a = b` - **Non-equality**: Checks if a does not equal to b; `a /= b` -- **Unsigned greater than or equals to**: Checks if a is greater than or equals to b (a and b are interpreted as unsigned numbers); `a bvuge b` -- **Unsigned greater than**: Checks if a is greater than b (a and b are interpreted as unsigned numbers); `a bvugt b` -- **Unsigned less than or equals to**: Checks if a is less than or equals to b (a and b are interpreted as unsigned numbers); `a bvule b` -- **Unsigned less than**: Checks if a is less than b (a and b are interpreted as unsigned numbers); `a bvult b` -- **Signed greater than or equals to**: Checks if a is greater than or equals to b (a and b are interpreted as signed numbers); `a bvsge b` -- **Signed greater than**: Checks if a is greater than b (a and b are interpreted as signed numbers); `a bvsgt b` -- **Signed less than or equals to**: Checks if a is less than or equals to b (a and b are interpreted as signed numbers); `a bvsle b` -- **Signed less than**: Checks if a is less than b (a and b are interpreted as signed numbers); `a bvslt b` +- **Unsigned greater than or equals to**: Checks if a is greater than or equals to b (a and b are + interpreted as unsigned numbers); `a bvuge b` +- **Unsigned greater than**: Checks if a is greater than b (a and b are interpreted as unsigned + numbers); `a bvugt b` +- **Unsigned less than or equals to**: Checks if a is less than or equals to b (a and b are + interpreted as unsigned numbers); `a bvule b` +- **Unsigned less than**: Checks if a is less than b (a and b are interpreted as unsigned + numbers); `a bvult b` +- **Signed greater than or equals to**: Checks if a is greater than or equals to b (a and b are + interpreted as signed numbers); `a bvsge b` +- **Signed greater than**: Checks if a is greater than b (a and b are interpreted as signed + numbers); `a bvsgt b` +- **Signed less than or equals to**: Checks if a is less than or equals to b (a and b are + interpreted as signed numbers); `a bvsle b` +- **Signed less than**: Checks if a is less than b (a and b are interpreted as signed + numbers); `a bvslt b` ## Algorithmic support for verification with bitvectors -The CEGAR algorithms use Z3 as an SMT solver, which does not support interpolation when bitvectors are involved. +The CEGAR algorithms use Z3 as an SMT solver, which does not support interpolation when bitvectors +are involved. Therefore, refinement algorithms involving interpolation (`--refinement *_ITP`) do not work. -However, there are other refinement algorithms (e.g., `UNSAT_CORE`, `UCB` or `NWT_*`) that do not rely on interpolation and work for bitvectors as well. +However, there are other refinement algorithms (e.g., `UNSAT_CORE`, `UCB` or `NWT_*`) that do not +rely on interpolation and work for bitvectors as well. diff --git a/subprojects/common/analysis/README.md b/subprojects/common/analysis/README.md index 764f0e4c43..12477d4508 100644 --- a/subprojects/common/analysis/README.md +++ b/subprojects/common/analysis/README.md @@ -1 +1,3 @@ -This project contains the analysis algorithms and their components, e.g., abstract domains, abstract reachability graphs, refinement strategies, precisions, etc. The formalism specific components (e.g., the interpreter) are implemented in separate projects for the given formalism. \ No newline at end of file +This project contains the analysis algorithms and their components, e.g., abstract domains, abstract +reachability graphs, refinement strategies, precisions, etc. The formalism specific components ( +e.g., the interpreter) are implemented in separate projects for the given formalism. \ No newline at end of file diff --git a/subprojects/common/analysis/build.gradle.kts b/subprojects/common/analysis/build.gradle.kts index 6b3894f0be..b11621e1c0 100644 --- a/subprojects/common/analysis/build.gradle.kts +++ b/subprojects/common/analysis/build.gradle.kts @@ -19,6 +19,7 @@ plugins { } dependencies { + implementation(files(rootDir.resolve(Deps.delta))) implementation(project(":theta-common")) implementation(project(":theta-core")) implementation(project(":theta-solver")) diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/Cex.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/Cex.java new file mode 100644 index 0000000000..0b933821b5 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/Cex.java @@ -0,0 +1,21 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis; + +public interface Cex { + + int length(); +} diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/elements/PnmlPlace.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/EmptyCex.java similarity index 65% rename from subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/elements/PnmlPlace.java rename to subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/EmptyCex.java index c77beb2315..ddb6c2cb2a 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/elements/PnmlPlace.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/EmptyCex.java @@ -13,18 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.xsts.pnml.elements; +package hu.bme.mit.theta.analysis; -public class PnmlPlace extends PnmlNode { +public class EmptyCex implements Cex { - private final int initialMarking; + private final static EmptyCex empty = new EmptyCex(); - public PnmlPlace(final String name, final String id, int initialMarking) { - super(name, id); - this.initialMarking = initialMarking; + private EmptyCex() { } - public int getInitialMarking() { - return initialMarking; + public static EmptyCex getInstance() { + return empty; + } + + @Override + public int length() { + return 0; } } diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/Trace.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/Trace.java index 47b1a868f6..e1e32d60eb 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/Trace.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/Trace.java @@ -30,7 +30,7 @@ * Action, State) sequence. A trace always contains at least one state and the number of actions is * one less than the number of states. */ -public final class Trace { +public final class Trace implements Cex { private final ImmutableList states; private final ImmutableList actions; @@ -56,6 +56,7 @@ public static Trace of(final List states, /** * Gets the length of the trace, which is the number of actions. */ + @Override public int length() { return actions.size(); } diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/Checker.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/Checker.java new file mode 100644 index 0000000000..e1a86bee69 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/Checker.java @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm; + +public interface Checker { + + Result check(I input); + +} diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/elements/PnmlNet.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/EmptyWitness.java similarity index 57% rename from subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/elements/PnmlNet.java rename to subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/EmptyWitness.java index a16e4a3201..49794dd84e 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/elements/PnmlNet.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/EmptyWitness.java @@ -13,25 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.xsts.pnml.elements; +package hu.bme.mit.theta.analysis.algorithm; -import java.util.List; +public class EmptyWitness implements Witness { -public class PnmlNet { + private final static EmptyWitness empty = new EmptyWitness(); - private final List places; - private final List transitions; - - public PnmlNet(final List places, final List transitions) { - this.places = places; - this.transitions = transitions; + private EmptyWitness() { } - public List getPlaces() { - return places; + public static EmptyWitness getInstance() { + return empty; } - public List getTransitions() { - return transitions; - } } diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/Result.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/Result.java new file mode 100644 index 0000000000..0c81bf5836 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/Result.java @@ -0,0 +1,26 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm; + +import java.util.Optional; + +public interface Result { + + W getWitness(); + + Optional getStats(); + +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/SafetyChecker.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/SafetyChecker.java index 8ef5560d14..4f13fac64c 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/SafetyChecker.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/SafetyChecker.java @@ -15,16 +15,18 @@ */ package hu.bme.mit.theta.analysis.algorithm; -import hu.bme.mit.theta.analysis.Action; -import hu.bme.mit.theta.analysis.Prec; -import hu.bme.mit.theta.analysis.State; +import hu.bme.mit.theta.analysis.*; +import hu.bme.mit.theta.analysis.algorithm.Checker; +import hu.bme.mit.theta.analysis.algorithm.SafetyResult; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; @FunctionalInterface -public interface SafetyChecker { +public interface SafetyChecker extends Checker { - SafetyResult check(final P prec); + @Override + SafetyResult check(final I input); - default SafetyResult check() { + default SafetyResult check() { return check(null); } diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/SafetyResult.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/SafetyResult.java index ebc215711c..a78effd15e 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/SafetyResult.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/SafetyResult.java @@ -16,77 +16,56 @@ package hu.bme.mit.theta.analysis.algorithm; import hu.bme.mit.theta.analysis.Action; +import hu.bme.mit.theta.analysis.Cex; import hu.bme.mit.theta.analysis.State; -import hu.bme.mit.theta.analysis.Trace; import hu.bme.mit.theta.common.Utils; import java.util.Optional; import static com.google.common.base.Preconditions.checkNotNull; -public abstract class SafetyResult { - - private final Optional> arg; +public abstract class SafetyResult implements Result { + private final W witness; private final Optional stats; - private SafetyResult(final ARG arg, final Optional stats) { - this.arg = Optional.of(arg); + private SafetyResult(final W witness, final Optional stats) { + this.witness = checkNotNull(witness); this.stats = checkNotNull(stats); } private SafetyResult() { - this.arg = Optional.empty(); + this.witness = null; this.stats = Optional.empty(); } - - public boolean hasArg() { - return arg.isPresent(); - } - - public ARG getArg() { - return arg.orElseThrow(); + @Override + public W getWitness() { + return witness; } + @Override public Optional getStats() { return stats; } - // Factory methods - - public static Safe safe(final ARG arg, - final Statistics stats) { - return new Safe<>(arg, Optional.of(stats)); - } - - public static Safe safe(final ARG arg) { - return new Safe<>(arg, Optional.empty()); - } - - public static Safe safe() { - return new Safe<>(); + public static Safe safe(final W witness) { + return new Safe<>(witness, Optional.empty()); } - public static Unsafe unsafe(final Trace cex, - final ARG arg, - final Statistics stats) { - return new Unsafe<>(cex, arg, Optional.of(stats)); + public static Unsafe unsafe(final C cex, final W witness) { + return new Unsafe<>(cex, witness, Optional.empty()); } - public static Unsafe unsafe(final Trace cex, - final ARG arg) { - return new Unsafe<>(cex, arg, Optional.empty()); + public static Safe safe(final W witness, final Statistics stats) { + return new Safe<>(witness, Optional.of(stats)); } - public static Unsafe unsafe(final Trace cex) { - return new Unsafe<>(cex); + public static Unsafe unsafe(final C cex, final W witness, + final Statistics stats) { + return new Unsafe<>(cex, witness, Optional.of(stats)); } - public static Unsafe unsafe() { - return new Unsafe<>(); - } - - public static Unknown unknown() { + public static Unknown unknown() { return new Unknown<>(); } @@ -94,19 +73,15 @@ public static Unknown unknown() { public abstract boolean isUnsafe(); - public abstract Safe asSafe(); + public abstract Safe asSafe(); - public abstract Unsafe asUnsafe(); + public abstract Unsafe asUnsafe(); //// - public static final class Safe extends SafetyResult { - - private Safe(final ARG arg, final Optional stats) { - super(arg, stats); - } - - private Safe() { + public static final class Safe extends SafetyResult { + private Safe(final W witness, final Optional stats) { + super(witness, stats); } @Override @@ -120,49 +95,33 @@ public boolean isUnsafe() { } @Override - public Safe asSafe() { + public Safe asSafe() { return this; } @Override - public Unsafe asUnsafe() { + public Unsafe asUnsafe() { throw new ClassCastException( - "Cannot cast " + Safe.class.getSimpleName() + " to " - + Unsafe.class.getSimpleName()); + "Cannot cast " + Safe.class.getSimpleName() + " to " + Unsafe.class.getSimpleName()); } @Override public String toString() { - return Utils.lispStringBuilder(SafetyResult.class.getSimpleName()) - .add(Safe.class.getSimpleName()) + return Utils.lispStringBuilder(SafetyResult.class.getSimpleName()).add(Safe.class.getSimpleName()) .toString(); } } - public static final class Unsafe extends SafetyResult { - - private final Optional> cex; - - private Unsafe(final Trace cex, final ARG arg, - final Optional stats) { - super(arg, stats); - this.cex = Optional.of(cex); - } - - private Unsafe(final Trace cex) { - this.cex = Optional.of(cex); - } - - private Unsafe() { - this.cex = Optional.empty(); - } + public static final class Unsafe extends SafetyResult { + private final C cex; - public boolean hasTrace() { - return cex.isPresent(); + private Unsafe(final C cex, final W witness, final Optional stats) { + super(witness, stats); + this.cex = checkNotNull(cex); } - public Trace getTrace() { - return cex.orElseThrow(); + public C getCex() { + return cex; } @Override @@ -176,26 +135,25 @@ public boolean isUnsafe() { } @Override - public Safe asSafe() { + public Safe asSafe() { throw new ClassCastException( - "Cannot cast " + Unsafe.class.getSimpleName() + " to " - + Safe.class.getSimpleName()); + "Cannot cast " + Unsafe.class.getSimpleName() + " to " + Safe.class.getSimpleName()); } @Override - public Unsafe asUnsafe() { + public Unsafe asUnsafe() { return this; } @Override public String toString() { - return Utils.lispStringBuilder(SafetyResult.class.getSimpleName()) - .add(Unsafe.class.getSimpleName()) - .add("Trace length: " + cex.map(Trace::length).orElse(-1)).toString(); + return Utils.lispStringBuilder(SafetyResult.class.getSimpleName()).add(Unsafe.class.getSimpleName()) + .add("Trace length: " + cex.length()).toString(); } } - public static final class Unknown extends SafetyResult { + public static final class Unknown extends SafetyResult { + @Override public boolean isSafe() { return false; @@ -207,12 +165,12 @@ public boolean isUnsafe() { } @Override - public Safe asSafe() { + public Safe asSafe() { return null; } @Override - public Unsafe asUnsafe() { + public Unsafe asUnsafe() { return null; } diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/Witness.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/Witness.java new file mode 100644 index 0000000000..ff6157e1e3 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/Witness.java @@ -0,0 +1,19 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm; + +public interface Witness { +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ARG.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ARG.java similarity index 96% rename from subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ARG.java rename to subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ARG.java index 2e1da1acb6..b43fb37e35 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ARG.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ARG.java @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.analysis.algorithm; +package hu.bme.mit.theta.analysis.algorithm.arg; import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.PartialOrd; import hu.bme.mit.theta.analysis.State; -import hu.bme.mit.theta.analysis.algorithm.debug.ARGWebDebugger; +import hu.bme.mit.theta.analysis.algorithm.Witness; +import hu.bme.mit.theta.analysis.algorithm.arg.debug.ARGWebDebugger; import hu.bme.mit.theta.common.container.Containers; import java.util.Collection; @@ -35,7 +36,7 @@ * Represents an abstract reachability graph (ARG). See the related class * ArgBuilder. */ -public final class ARG { +public final class ARG implements Witness { private final Collection> initNodes; public boolean initialized; // Set by ArgBuilder diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgBuilder.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgBuilder.java similarity index 98% rename from subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgBuilder.java rename to subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgBuilder.java index 66f1edab8d..a261489c38 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgBuilder.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgBuilder.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.analysis.algorithm; +package hu.bme.mit.theta.analysis.algorithm.arg; import hu.bme.mit.theta.analysis.*; diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgChecker.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgChecker.java similarity index 98% rename from subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgChecker.java rename to subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgChecker.java index ae808df90e..5cbe09c120 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgChecker.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgChecker.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.analysis.algorithm; +package hu.bme.mit.theta.analysis.algorithm.arg; import static com.google.common.base.Preconditions.checkNotNull; import static java.util.stream.Collectors.toList; diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgEdge.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgEdge.java similarity index 96% rename from subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgEdge.java rename to subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgEdge.java index 1ea32902d3..e2609303ae 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgEdge.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgEdge.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.analysis.algorithm; +package hu.bme.mit.theta.analysis.algorithm.arg; import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.State; diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgNode.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgNode.java similarity index 99% rename from subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgNode.java rename to subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgNode.java index bcf8da92cd..435193fa23 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgNode.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgNode.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.analysis.algorithm; +package hu.bme.mit.theta.analysis.algorithm.arg; import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.State; diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgNodeComparators.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgNodeComparators.java similarity index 99% rename from subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgNodeComparators.java rename to subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgNodeComparators.java index fde6fb2f56..d9ab01928c 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgNodeComparators.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgNodeComparators.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.analysis.algorithm; +package hu.bme.mit.theta.analysis.algorithm.arg; import java.io.Serializable; import java.util.Comparator; diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgStructuralEquality.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgStructuralEquality.java similarity index 99% rename from subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgStructuralEquality.java rename to subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgStructuralEquality.java index 8003232ff9..b8249aa378 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgStructuralEquality.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgStructuralEquality.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package hu.bme.mit.theta.analysis.algorithm; +package hu.bme.mit.theta.analysis.algorithm.arg; import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.State; diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgTrace.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgTrace.java similarity index 98% rename from subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgTrace.java rename to subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgTrace.java index 8595ed5893..6c21ce9bc8 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgTrace.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgTrace.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.analysis.algorithm; +package hu.bme.mit.theta.analysis.algorithm.arg; import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.State; diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgUtils.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgUtils.java similarity index 95% rename from subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgUtils.java rename to subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgUtils.java index e9c1ffab5b..d5471c2f5a 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/ArgUtils.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgUtils.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.analysis.algorithm; +package hu.bme.mit.theta.analysis.algorithm.arg; import hu.bme.mit.theta.analysis.expr.ExprAction; import hu.bme.mit.theta.analysis.expr.ExprState; diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/SearchStrategy.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/SearchStrategy.java similarity index 93% rename from subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/SearchStrategy.java rename to subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/SearchStrategy.java index 92016c78de..2aed37ee5d 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/SearchStrategy.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/SearchStrategy.java @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.analysis.algorithm; +package hu.bme.mit.theta.analysis.algorithm.arg; import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.State; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNode; import hu.bme.mit.theta.analysis.waitlist.FifoWaitlist; import hu.bme.mit.theta.analysis.waitlist.LifoWaitlist; import hu.bme.mit.theta.analysis.waitlist.RandomWaitlist; diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/debug/ARGWebDebugger.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/debug/ARGWebDebugger.java similarity index 96% rename from subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/debug/ARGWebDebugger.java rename to subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/debug/ARGWebDebugger.java index bb3e365aff..7b6d100d5c 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/debug/ARGWebDebugger.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/arg/debug/ARGWebDebugger.java @@ -14,14 +14,14 @@ * limitations under the License. */ -package hu.bme.mit.theta.analysis.algorithm.debug; +package hu.bme.mit.theta.analysis.algorithm.arg.debug; import com.corundumstudio.socketio.Configuration; import com.corundumstudio.socketio.SocketIOServer; import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.State; -import hu.bme.mit.theta.analysis.algorithm.ArgEdge; -import hu.bme.mit.theta.analysis.algorithm.ArgNode; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgEdge; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNode; import java.util.LinkedList; import java.util.List; diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/bounded/BoundedChecker.kt b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/bounded/BoundedChecker.kt index e381a327ea..a300cb72a6 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/bounded/BoundedChecker.kt +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/bounded/BoundedChecker.kt @@ -17,6 +17,7 @@ package hu.bme.mit.theta.analysis.algorithm.bounded import hu.bme.mit.theta.analysis.Trace +import hu.bme.mit.theta.analysis.algorithm.EmptyWitness import hu.bme.mit.theta.analysis.algorithm.SafetyChecker import hu.bme.mit.theta.analysis.algorithm.SafetyResult import hu.bme.mit.theta.analysis.expr.ExprAction @@ -70,7 +71,7 @@ class BoundedChecker @JvmOverloads constructor( private val valToState: (Valuation) -> S, private val biValToAction: (Valuation, Valuation) -> A, private val logger: Logger, -) : SafetyChecker { +) : SafetyChecker, UnitPrec> { private val vars = monolithicExpr.vars() private val unfoldedInitExpr = PathUtils.unfold(monolithicExpr.initExpr, 0) @@ -85,7 +86,7 @@ class BoundedChecker @JvmOverloads constructor( check(itpSolver != indSolver || itpSolver == null) { "Use distinct solvers for IMC and KInd!" } } - override fun check(prec: UnitPrec?): SafetyResult { + override fun check(prec: UnitPrec?): SafetyResult> { var iteration = 0 val isBmcEnabled = bmcEnabled() // we don't allow per-iteration setting of bmc enabledness @@ -118,7 +119,7 @@ class BoundedChecker @JvmOverloads constructor( return SafetyResult.unknown() } - private fun bmc(): SafetyResult? { + private fun bmc(): SafetyResult>? { val bmcSolver = this.bmcSolver!! logger.write(Logger.Level.MAINSTEP, "\tStarting BMC\n") @@ -136,7 +137,7 @@ class BoundedChecker @JvmOverloads constructor( if (bmcSolver.check().isUnsat) { logger.write(Logger.Level.MAINSTEP, "Safety proven in BMC step\n") - return SafetyResult.safe() + return SafetyResult.safe(EmptyWitness.getInstance()) } } @@ -146,12 +147,12 @@ class BoundedChecker @JvmOverloads constructor( if (bmcSolver.check().isSat) { val trace = getTrace(bmcSolver.model) logger.write(Logger.Level.MAINSTEP, "CeX found in BMC step (length ${trace.length()})\n") - SafetyResult.unsafe(trace) + SafetyResult.unsafe(trace, EmptyWitness.getInstance()) } else null } } - private fun kind(): SafetyResult? { + private fun kind(): SafetyResult>? { val indSolver = this.indSolver!! logger.write(Logger.Level.MAINSTEP, "\tStarting k-induction\n") @@ -164,12 +165,12 @@ class BoundedChecker @JvmOverloads constructor( if (indSolver.check().isUnsat) { logger.write(Logger.Level.MAINSTEP, "Safety proven in k-induction step\n") - SafetyResult.safe() + SafetyResult.safe(EmptyWitness.getInstance()) } else null } } - private fun itp(): SafetyResult? { + private fun itp(): SafetyResult>? { val itpSolver = this.itpSolver!! logger.write(Logger.Level.MAINSTEP, "\tStarting IMC\n") @@ -200,7 +201,7 @@ class BoundedChecker @JvmOverloads constructor( itpSolver.pop() itpSolver.pop() logger.write(Logger.Level.MAINSTEP, "Safety proven in IMC/BMC step\n") - return SafetyResult.safe() + return SafetyResult.safe(EmptyWitness.getInstance()) } itpSolver.pop() } @@ -214,7 +215,7 @@ class BoundedChecker @JvmOverloads constructor( logger.write(Logger.Level.MAINSTEP, "CeX found in IMC/BMC step (length ${trace.length()})\n") itpSolver.pop() itpSolver.pop() - return SafetyResult.unsafe(trace) + return SafetyResult.unsafe(trace, EmptyWitness.getInstance()) } var img = unfoldedInitExpr @@ -231,7 +232,7 @@ class BoundedChecker @JvmOverloads constructor( logger.write(Logger.Level.MAINSTEP, "Safety proven in IMC step\n") itpSolver.pop() itpSolver.pop() - return SafetyResult.safe() + return SafetyResult.safe(EmptyWitness.getInstance()) } itpSolver.pop() img = Or(img, itpFormula) diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/Abstractor.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/Abstractor.java index 2e37785599..a7eb473efd 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/Abstractor.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/Abstractor.java @@ -18,7 +18,7 @@ import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.Prec; import hu.bme.mit.theta.analysis.State; -import hu.bme.mit.theta.analysis.algorithm.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; /** * Common interface for the abstractor component. It can create an initial ARG and check an ARG with diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/BasicAbstractor.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/BasicAbstractor.java index 1c4b8fb959..42eb1487e1 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/BasicAbstractor.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/BasicAbstractor.java @@ -18,9 +18,9 @@ import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.Prec; import hu.bme.mit.theta.analysis.State; -import hu.bme.mit.theta.analysis.algorithm.ARG; -import hu.bme.mit.theta.analysis.algorithm.ArgBuilder; -import hu.bme.mit.theta.analysis.algorithm.ArgNode; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgBuilder; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNode; import hu.bme.mit.theta.analysis.algorithm.cegar.abstractor.StopCriterion; import hu.bme.mit.theta.analysis.algorithm.cegar.abstractor.StopCriterions; import hu.bme.mit.theta.analysis.reachedset.Partition; diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/CegarChecker.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/CegarChecker.java index b571287dce..af69cd7121 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/CegarChecker.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/CegarChecker.java @@ -19,9 +19,10 @@ import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.Prec; import hu.bme.mit.theta.analysis.State; -import hu.bme.mit.theta.analysis.algorithm.ARG; -import hu.bme.mit.theta.analysis.algorithm.SafetyChecker; +import hu.bme.mit.theta.analysis.Trace; import hu.bme.mit.theta.analysis.algorithm.SafetyResult; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; +import hu.bme.mit.theta.analysis.algorithm.SafetyChecker; import hu.bme.mit.theta.analysis.runtimemonitor.MonitorCheckpoint; import hu.bme.mit.theta.analysis.utils.ArgVisualizer; import hu.bme.mit.theta.common.Utils; @@ -42,7 +43,7 @@ * check counterexamples and refine them if needed. It also provides certain * statistics about its execution. */ -public final class CegarChecker implements SafetyChecker { +public final class CegarChecker implements SafetyChecker, Trace, P> { private final Abstractor abstractor; private final Refiner refiner; @@ -71,7 +72,7 @@ public ARG getArg() { } @Override - public SafetyResult check(final P initPrec) { + public SafetyResult, Trace> check(final P initPrec) { logger.write(Level.INFO, "Configuration: %s%n", this); final Stopwatch stopwatch = Stopwatch.createStarted(); long abstractorTime = 0; @@ -122,7 +123,7 @@ public SafetyResult check(final P initPrec) { } while (!abstractorResult.isSafe() && !refinerResult.isUnsafe()); stopwatch.stop(); - SafetyResult cegarResult = null; + SafetyResult, Trace> cegarResult = null; final CegarStatistics stats = new CegarStatistics(stopwatch.elapsed(TimeUnit.MILLISECONDS), abstractorTime, refinerTime, iteration); diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/Refiner.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/Refiner.java index e2b7608221..0bbfe07f1d 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/Refiner.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/Refiner.java @@ -18,7 +18,7 @@ import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.Prec; import hu.bme.mit.theta.analysis.State; -import hu.bme.mit.theta.analysis.algorithm.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; /** * Common interface for refiners. It takes an ARG and a precision, checks if the counterexample in diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/abstractor/StopCriterion.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/abstractor/StopCriterion.java index ca22aa27cb..fc5d1c00ed 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/abstractor/StopCriterion.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/abstractor/StopCriterion.java @@ -17,8 +17,8 @@ import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.State; -import hu.bme.mit.theta.analysis.algorithm.ARG; -import hu.bme.mit.theta.analysis.algorithm.ArgNode; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNode; import java.util.Collection; diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/abstractor/StopCriterions.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/abstractor/StopCriterions.java index 10a0c80c3f..e8cdf50e57 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/abstractor/StopCriterions.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/cegar/abstractor/StopCriterions.java @@ -17,8 +17,8 @@ import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.State; -import hu.bme.mit.theta.analysis.algorithm.ARG; -import hu.bme.mit.theta.analysis.algorithm.ArgNode; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNode; import hu.bme.mit.theta.common.Utils; import java.util.Collection; diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mcm/analysis/FiniteStateChecker.kt b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mcm/analysis/FiniteStateChecker.kt index 99cdbc84f7..05c02303c3 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mcm/analysis/FiniteStateChecker.kt +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mcm/analysis/FiniteStateChecker.kt @@ -16,9 +16,11 @@ package hu.bme.mit.theta.analysis.algorithm.mcm.analysis +import hu.bme.mit.theta.analysis.EmptyCex import hu.bme.mit.theta.analysis.InitFunc import hu.bme.mit.theta.analysis.LTS import hu.bme.mit.theta.analysis.TransFunc +import hu.bme.mit.theta.analysis.algorithm.EmptyWitness import hu.bme.mit.theta.analysis.algorithm.SafetyChecker import hu.bme.mit.theta.analysis.algorithm.SafetyResult import hu.bme.mit.theta.analysis.algorithm.mcm.interpreter.MemoryEventProvider @@ -44,9 +46,9 @@ class FiniteStateChecker( private val memoryEventProvider: MemoryEventProvider, private val graphPatternCompiler: GraphPatternCompiler, private val graphPatternSolver: GraphSolver -) : SafetyChecker { +) : SafetyChecker { - override fun check(prec: ExplPrec): SafetyResult { + override fun check(prec: ExplPrec): SafetyResult { val eventIds = LinkedList() val rels = LinkedList>() val lastIds = LinkedHashMap() @@ -72,7 +74,7 @@ class FiniteStateChecker( initStates.addAll(nextStates) } // PartialSolver(mcm, CandidateExecutionGraph(eventIds, rels)) - return SafetyResult.unsafe(null, null) + return SafetyResult.unsafe(EmptyCex.getInstance(), EmptyWitness.getInstance()) } diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddAnalysisStatistics.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddAnalysisStatistics.java new file mode 100644 index 0000000000..2f3cc7978b --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddAnalysisStatistics.java @@ -0,0 +1,62 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd; + +import hu.bme.mit.theta.analysis.algorithm.Statistics; + +public class MddAnalysisStatistics extends Statistics { + + private final Long violatingSize; + private final Long stateSpaceSize; + private final Long hitCount; + private final Long queryCount; + private final Long cacheSize; + + + public MddAnalysisStatistics(Long violatingSize, Long stateSpaceSize, Long hitCount, Long queryCount, Long cacheSize) { + this.violatingSize = violatingSize; + this.stateSpaceSize = stateSpaceSize; + this.hitCount = hitCount; + this.queryCount = queryCount; + this.cacheSize = cacheSize; + + addStat("ViolatingSize", this::getViolatingSize); + addStat("StateSpaceSize", this::getStateSpaceSize); + addStat("HitCount", this::getHitCount); + addStat("QueryCount", this::getQueryCount); + addStat("CacheSize", this::getCacheSize); + } + + public Long getViolatingSize() { + return violatingSize; + } + + public Long getStateSpaceSize() { + return stateSpaceSize; + } + + public Long getHitCount() { + return hitCount; + } + + public Long getQueryCount() { + return queryCount; + } + + public Long getCacheSize() { + return cacheSize; + } +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddCex.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddCex.java new file mode 100644 index 0000000000..0e5f51a40a --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddCex.java @@ -0,0 +1,46 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd; + +import hu.bme.mit.delta.java.mdd.MddHandle; +import hu.bme.mit.delta.mdd.MddInterpreter; +import hu.bme.mit.theta.analysis.Cex; + +public class MddCex implements Cex { + + private final MddHandle violatingStates; + + private MddCex(MddHandle violatingStates) { + this.violatingStates = violatingStates; + } + + public static MddCex of(MddHandle violatingStates) { + return new MddCex(violatingStates); + } + + @Override + public int length() { + return -1; + } + + public Long size() { + return MddInterpreter.calculateNonzeroCount(violatingStates); + } + + public MddHandle getMdd() { + return violatingStates; + } +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddChecker.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddChecker.java new file mode 100644 index 0000000000..85097df1f1 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddChecker.java @@ -0,0 +1,184 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd; + +import hu.bme.mit.delta.collections.impl.RecursiveIntObjMapViews; +import hu.bme.mit.delta.java.mdd.*; +import hu.bme.mit.delta.mdd.MddInterpreter; +import hu.bme.mit.delta.mdd.MddVariableDescriptor; +import hu.bme.mit.theta.analysis.algorithm.SafetyResult; +import hu.bme.mit.theta.analysis.algorithm.SafetyChecker; +import hu.bme.mit.theta.analysis.algorithm.mdd.fixedpoint.BfsProvider; +import hu.bme.mit.theta.analysis.algorithm.mdd.fixedpoint.GeneralizedSaturationProvider; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor; +import hu.bme.mit.theta.analysis.algorithm.mdd.fixedpoint.SimpleSaturationProvider; +import hu.bme.mit.theta.common.logging.Logger.Level; +import hu.bme.mit.theta.solver.SolverPool; +import hu.bme.mit.theta.analysis.algorithm.mdd.expressionnode.ExprLatticeDefinition; +import hu.bme.mit.theta.analysis.algorithm.mdd.expressionnode.MddExpressionTemplate; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.impl.MddNodeInitializer; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.impl.MddNodeNextStateDescriptor; +import hu.bme.mit.theta.analysis.expr.ExprAction; +import hu.bme.mit.theta.analysis.utils.MddNodeVisualizer; +import hu.bme.mit.theta.common.logging.Logger; +import hu.bme.mit.theta.common.visualization.Graph; +import hu.bme.mit.theta.common.visualization.writer.GraphvizWriter; +import hu.bme.mit.theta.core.decl.Decl; +import hu.bme.mit.theta.core.decl.VarDecl; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.booltype.BoolType; +import hu.bme.mit.theta.core.utils.ExprUtils; +import hu.bme.mit.theta.core.utils.PathUtils; +import hu.bme.mit.theta.core.utils.indexings.VarIndexing; +import hu.bme.mit.theta.core.utils.indexings.VarIndexingFactory; +import hu.bme.mit.theta.solver.SolverFactory; + +import java.io.FileNotFoundException; +import java.util.List; +import java.util.Set; + +import static hu.bme.mit.theta.core.type.booltype.SmartBoolExprs.Not; + +public class MddChecker implements SafetyChecker { + + private final Expr initRel; + private final VarIndexing initIndexing; + private final A transRel; + private final Expr safetyProperty; + private final SolverPool solverPool; + private final Logger logger; + private IterationStrategy iterationStrategy = IterationStrategy.GSAT; + + public enum IterationStrategy { + BFS, SAT, GSAT + } + + private MddChecker(Expr initRel, + VarIndexing initIndexing, + A transRel, + Expr safetyProperty, + SolverPool solverPool, + Logger logger, + IterationStrategy iterationStrategy) { + this.initRel = initRel; + this.initIndexing = initIndexing; + this.transRel = transRel; + this.safetyProperty = safetyProperty; + this.solverPool = solverPool; + this.logger = logger; + this.iterationStrategy = iterationStrategy; + } + + public static MddChecker create(Expr initRel, + VarIndexing initIndexing, + A transRel, + Expr safetyProperty, + SolverPool solverPool, + Logger logger) { + return new MddChecker(initRel, initIndexing, transRel, safetyProperty, solverPool, logger, IterationStrategy.GSAT); + } + + public static MddChecker create(Expr initRel, + VarIndexing initIndexing, + A transRel, + Expr safetyProperty, + SolverPool solverPool, + Logger logger, + IterationStrategy iterationStrategy) { + return new MddChecker(initRel, initIndexing, transRel, safetyProperty, solverPool, logger, iterationStrategy); + } + + @Override + public SafetyResult check(Void input) { + + final MddGraph mddGraph = JavaMddFactory.getDefault().createMddGraph(ExprLatticeDefinition.forExpr()); + + final MddVariableOrder stateOrder = JavaMddFactory.getDefault().createMddVariableOrder(mddGraph); + final MddVariableOrder transOrder = JavaMddFactory.getDefault().createMddVariableOrder(mddGraph); + + final Set> vars = ExprUtils.getVars(List.of(initRel, transRel.toExpr(), safetyProperty)); + for (var v : vars) { + final var domainSize = v.getType() instanceof BoolType ? 2 : 0; + + stateOrder.createOnTop(MddVariableDescriptor.create(v.getConstDecl(initIndexing.get(v)), domainSize)); + + transOrder.createOnTop(MddVariableDescriptor.create(v.getConstDecl(transRel.nextIndexing().get(v)), domainSize)); + transOrder.createOnTop(MddVariableDescriptor.create(v.getConstDecl(0), domainSize)); + } + + final var stateSig = stateOrder.getDefaultSetSignature(); + final var transSig = transOrder.getDefaultSetSignature(); + + final Expr initExpr = PathUtils.unfold(initRel, initIndexing); + final MddHandle initNode = stateSig.getTopVariableHandle().checkInNode(MddExpressionTemplate.of(initExpr, o -> (Decl) o, solverPool)); + + logger.write(Level.INFO, "Created initial node"); + + final Expr transExpr = PathUtils.unfold(transRel.toExpr(), VarIndexingFactory.indexing(0)); + final MddHandle transitionNode = transSig.getTopVariableHandle().checkInNode(MddExpressionTemplate.of(transExpr, o -> (Decl) o, solverPool)); + final AbstractNextStateDescriptor nextStates = MddNodeNextStateDescriptor.of(transitionNode); + + logger.write(Level.INFO, "Created next-state node, starting fixed point calculation"); + + final MddHandle stateSpace; + final Cache cache; + switch (iterationStrategy) { + case BFS -> { + final var bfs = new BfsProvider(stateSig.getVariableOrder()); + stateSpace = bfs.compute(MddNodeInitializer.of(initNode), nextStates, stateSig.getTopVariableHandle()); + cache = bfs.getRelProdCache(); + } + case SAT -> { + final var sat = new SimpleSaturationProvider(stateSig.getVariableOrder()); + stateSpace = sat.compute(MddNodeInitializer.of(initNode), nextStates, stateSig.getTopVariableHandle()); + cache = sat.getSaturateCache(); + } + case GSAT -> { + final var gsat = new GeneralizedSaturationProvider(stateSig.getVariableOrder()); + stateSpace = gsat.compute(MddNodeInitializer.of(initNode), nextStates, stateSig.getTopVariableHandle()); + cache = gsat.getSaturateCache(); + + } + default -> throw new IllegalStateException("Unexpected value: " + iterationStrategy); + } + + logger.write(Level.INFO, "Enumerated state-space"); + + final Expr negatedPropExpr = PathUtils.unfold(Not(safetyProperty), initIndexing); + final MddHandle propNode = stateSig.getTopVariableHandle().checkInNode(MddExpressionTemplate.of(negatedPropExpr, o -> (Decl) o, solverPool)); + + final MddHandle propViolating = (MddHandle) stateSpace.intersection(propNode); + + logger.write(Level.INFO, "Calculated violating states"); + + final Long violatingSize = MddInterpreter.calculateNonzeroCount(propViolating); + logger.write(Level.INFO, "States violating the property: " + violatingSize); + + final Long stateSpaceSize = MddInterpreter.calculateNonzeroCount(stateSpace); + logger.write(Level.DETAIL, "State space size: " + stateSpaceSize); + + final MddAnalysisStatistics statistics = new MddAnalysisStatistics(violatingSize, stateSpaceSize, cache.getHitCount(), cache.getQueryCount(), cache.getCacheSize()); + + final SafetyResult result; + if (violatingSize != 0) { + result = SafetyResult.unsafe(MddCex.of(propViolating), MddWitness.of(stateSpace), statistics); + } else { + result = SafetyResult.safe(MddWitness.of(stateSpace), statistics); + } + logger.write(Level.RESULT, "%s%n", result); + return result; + } +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddValuationCollector.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddValuationCollector.java new file mode 100644 index 0000000000..71960a234f --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddValuationCollector.java @@ -0,0 +1,103 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd; + +import hu.bme.mit.delta.collections.RecursiveIntObjCursor; +import hu.bme.mit.delta.java.mdd.MddNode; +import hu.bme.mit.theta.analysis.algorithm.mdd.expressionnode.LitExprConverter; +import hu.bme.mit.theta.analysis.algorithm.mdd.expressionnode.MddExpressionRepresentation; +import hu.bme.mit.theta.common.container.Containers; +import hu.bme.mit.theta.core.decl.Decl; +import hu.bme.mit.theta.core.model.ImmutableValuation; +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.LitExpr; + +import java.util.Set; +import java.util.Stack; + +/** + * A utility class for collecting all vectors from a subtree represented by a symbolic node. + * Only works with finite diagrams, but can handle default edges. + */ +public class MddValuationCollector { + + private static class Assignment { + final Decl decl; + final LitExpr value; + + private Assignment(Decl decl, LitExpr value) { + this.decl = decl; + this.value = value; + } + } + + /** + * Collect all vectors from the subtree represented by a symbolic node. + * + * @param node the node + * @return the set of vectors represented by the node + */ + public static Set collect(MddNode node) { + final Stack assignments = new Stack<>(); + final Set valuations = Containers.createSet(); + + try (var cursor = node.cursor()) { + collect(node, cursor, assignments, valuations); + } + + return valuations; + } + + private static void collect(MddNode node, RecursiveIntObjCursor cursor, Stack assignments, Set valuations) { + if (node.isTerminal()) { + valuations.add(toValuation(assignments)); + } else { + if (node.defaultValue() != null) { + cursor.moveNext(); + + try (var valueCursor = cursor.valueCursor()) { + collect(node.defaultValue(), valueCursor, assignments, valuations); + } + + } else { + while (cursor.moveNext()) { + assert cursor.value() != null; + + if (node.getRepresentation() instanceof MddExpressionRepresentation) { + final MddExpressionRepresentation representation = (MddExpressionRepresentation) node.getRepresentation(); + assignments.push(new Assignment(representation.getDecl(), LitExprConverter.toLitExpr(cursor.key(), representation.getDecl().getType()))); + } + + try (var valueCursor = cursor.valueCursor()) { + collect(cursor.value(), valueCursor, assignments, valuations); + } + + if (node.getRepresentation() instanceof MddExpressionRepresentation) + assignments.pop(); + + } + } + } + } + + private static Valuation toValuation(Stack assignments) { + final var builder = ImmutableValuation.builder(); + assignments.stream().forEach(ass -> builder.put(ass.decl, ass.value)); + return builder.build(); + } + + +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddWitness.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddWitness.java new file mode 100644 index 0000000000..300dc6579f --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddWitness.java @@ -0,0 +1,41 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd; + +import hu.bme.mit.delta.java.mdd.MddHandle; +import hu.bme.mit.delta.mdd.MddInterpreter; +import hu.bme.mit.theta.analysis.algorithm.Witness; + +public class MddWitness implements Witness { + + private final MddHandle stateSpace; + + private MddWitness(MddHandle stateSpace) { + this.stateSpace = stateSpace; + } + + public static MddWitness of(MddHandle stateSpace) { + return new MddWitness(stateSpace); + } + + public Long size() { + return MddInterpreter.calculateNonzeroCount(stateSpace); + } + + public MddHandle getMdd() { + return stateSpace; + } +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/AbstractNextStateDescriptor.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/AbstractNextStateDescriptor.java new file mode 100644 index 0000000000..9268baf638 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/AbstractNextStateDescriptor.java @@ -0,0 +1,203 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.ansd; + +import hu.bme.mit.delta.collections.IntObjMapView; +import hu.bme.mit.delta.collections.impl.IntObjMapViews; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.impl.EmptyNextStateDescriptor; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.impl.IdentityNextStateDescriptor; + +import java.io.Closeable; +import java.util.Optional; + +public interface AbstractNextStateDescriptor { + + interface Precondition extends AbstractNextStateDescriptor { + IntObjMapView getValuations(StateSpaceInfo localStateSpace); + + @Override + default boolean isNextStateDefined() { + return false; + } + + @Override + default IntObjMapView getDiagonal(StateSpaceInfo localStateSpace) { + return getValuations(localStateSpace); + } + + @Override + default IntObjMapView> getOffDiagonal(StateSpaceInfo localStateSpace) { + // keep lambda to avoid confusion with overloads + //noinspection Convert2MethodRef + return new IntObjMapViews.Transforming<>(getValuations(localStateSpace), v -> IntObjMapView.empty(v)); + } + } + + interface Postcondition extends AbstractNextStateDescriptor { + IntObjMapView getValuations(StateSpaceInfo localStateSpace); + + @Override + default boolean isSourceStateDefined() { + return false; + } + + @Override + default IntObjMapView getDiagonal(StateSpaceInfo localStateSpace) { + return getValuations(localStateSpace); + } + + @Override + default IntObjMapView> getOffDiagonal(StateSpaceInfo localStateSpace) { + return IntObjMapView.empty(getValuations(localStateSpace)); + } + + static AbstractNextStateDescriptor.Postcondition terminalEmpty() { + return new AbstractNextStateDescriptor.Postcondition() { + @Override + public IntObjMapView getValuations(StateSpaceInfo localStateSpace) { + return IntObjMapView.empty(terminalEmpty()); + } + + @Override + public Optional> split() { + return Optional.empty(); + } + + @Override + public boolean evaluate() { + return false; + } + }; + } + } + + static AbstractNextStateDescriptor terminalIdentity() { + return IdentityNextStateDescriptor.TERMINAL_IDENTITY; + } + + static AbstractNextStateDescriptor terminalEmpty() { + return EmptyNextStateDescriptor.INSTANCE; + } + + default boolean isSourceStateDefined() { + return true; + } + + default boolean isNextStateDefined() { + return true; + } + + + IntObjMapView getDiagonal(StateSpaceInfo localStateSpace); + + + IntObjMapView> getOffDiagonal(StateSpaceInfo localStateSpace); + + default Optional> split() { + return Optional.empty(); + } + + // Should return true only if there is a valuation that is accepted by the relation and false if there is not. + // Must throw an exception if undecidable. + default boolean evaluate() { + throw new IllegalStateException("Evaluated before reaching a terminal descriptor."); + } + + default boolean isLocallyIdentity(final StateSpaceInfo stateSpaceInfo) { + final IntObjMapView diagonal = getDiagonal(stateSpaceInfo); + final IntObjMapView> offDiagonal = getOffDiagonal(stateSpaceInfo); + return offDiagonal.isEmpty() && isNullOrEmpty(offDiagonal.defaultValue()) && diagonal.isEmpty(); + } + + static boolean isNullOrEmpty(AbstractNextStateDescriptor ns) { + return ns == null || ns == terminalEmpty(); + } + + static boolean isNullOrEmpty(IntObjMapView ns) { + return ns == null || (ns.isEmpty() && isNullOrEmpty(ns.defaultValue())); + } + + interface Cursor extends Closeable { + + int key(); + + AbstractNextStateDescriptor value(); + + boolean moveNext(); + + boolean moveTo(int key); + + Cursor valueCursor(int from, StateSpaceInfo localStateSpace); + + void close(); + + default Optional> split() { + return Optional.empty(); + } + + class Singleton implements Cursor { + + private final AbstractNextStateDescriptor value; + + private int currentPosition; + + public Singleton(AbstractNextStateDescriptor value) { + this.value = value; + this.currentPosition = -1; + } + + @Override + public int key() { + return 0; + } + + @Override + public AbstractNextStateDescriptor value() { + return value; + } + + @Override + public boolean moveNext() { + currentPosition++; + return currentPosition == 0; + } + + @Override + public boolean moveTo(int key) { + return false; + } + + @Override + public Cursor valueCursor(int from, StateSpaceInfo localStateSpace) { + return value.cursor(from, localStateSpace); + } + + @Override + public void close() { + + } + } + + } + + default Cursor cursor(int from, StateSpaceInfo localStateSpace) { + throw new UnsupportedOperationException("Not yet implemented"); + } + + default Cursor rootCursor() { + return new Cursor.Singleton(this); + } +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/StateSpaceInfo.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/StateSpaceInfo.java new file mode 100644 index 0000000000..e610450c69 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/StateSpaceInfo.java @@ -0,0 +1,75 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.ansd; + +import hu.bme.mit.delta.collections.IntSetView; +import hu.bme.mit.delta.java.mdd.MddNode; + +/** + * Represents a sub-state space of the system under analysis. Instances of this + * type have some sort of a decision diagram node underneath to represent the + * reachable substates. + * + * @author Vince Molnar + */ +public interface StateSpaceInfo { + /** + * Gets the trace info associated with the currently processed variable. + * + * @return The current trace info. + */ + Object getTraceInfo(); + + default T getTraceInfo(Class typeToken) { + return typeToken.cast(getTraceInfo()); + } + + /** + * Returns true if the underlying component is known to have specific reachable states, + * false if its state space is undefined, that is, it can be in any state. + * + * @return True if the underlying component has specific reachable states, false + * if its state space is undefined. + */ + public boolean hasInfiniteStates(); + + /** + * Gets the local states of the underlying component that are contained in the + * current sub-state space. Returns {@code null} if + * {@link #hasInfiniteStates()} returns false. + * + * @return The local states of the underlying component that are contained in + * the current sub-state space or {@code null} if the state space is + * undefined. + */ + public IntSetView getLocalStateSpace(); + + // TODO: possible tweaking. When is it worth it to traverse the MDD and collect + // the actual states instead of relying on the domain registry? + + /** + * Gets the local states of {@code someLowerComponent} that are contained in the + * current sub-state space. Returns {@code null} if + * the state space of {@code someLowerComponent} is undefined. + * + * @return The local states of the underlying component that are contained in + * the current sub-state space or {@code null} if the state space is + * undefined. + */ + public StateSpaceInfo getLocalStateSpace(Object someLowerComponent); + + public MddNode toStructuralRepresentation(); +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/impl/AnyNextStateDescriptor.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/impl/AnyNextStateDescriptor.java new file mode 100644 index 0000000000..9db4726d48 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/impl/AnyNextStateDescriptor.java @@ -0,0 +1,60 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.ansd.impl; + +import java.util.Optional; + +import hu.bme.mit.delta.collections.IntObjMapView; +import hu.bme.mit.delta.collections.UniqueTable; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.StateSpaceInfo; + +public class AnyNextStateDescriptor implements AbstractNextStateDescriptor { + private static final UniqueTable uniqueTable = UniqueTable.newInstance(); + + public static AbstractNextStateDescriptor withChild(AbstractNextStateDescriptor child) { + return uniqueTable.checkIn(new AnyNextStateDescriptor(child)); + } + + private final AbstractNextStateDescriptor child; + + private AnyNextStateDescriptor(AbstractNextStateDescriptor child) { + this.child = child; + } + + @Override + public boolean isNextStateDefined() { + return false; + } + + @Override + public IntObjMapView getDiagonal(StateSpaceInfo localStateSpace) { + return IntObjMapView.empty(child); + } + + @Override + public IntObjMapView> getOffDiagonal( + final StateSpaceInfo localStateSpace) { + return IntObjMapView.empty(IntObjMapView.empty(child)); + } + + @Override + public Optional> split() { + // TODO: this might be a performance overhead + return Optional.empty(); + } + +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/impl/EmptyNextStateDescriptor.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/impl/EmptyNextStateDescriptor.java new file mode 100644 index 0000000000..41c69d9c4a --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/impl/EmptyNextStateDescriptor.java @@ -0,0 +1,52 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.ansd.impl; + +import java.util.Optional; + +import hu.bme.mit.delta.collections.IntObjMapView; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.StateSpaceInfo; + +public final class EmptyNextStateDescriptor implements AbstractNextStateDescriptor { + private EmptyNextStateDescriptor() { + } + + public static final EmptyNextStateDescriptor INSTANCE = new EmptyNextStateDescriptor(); + + @Override + public IntObjMapView getDiagonal(StateSpaceInfo localStateSpace) { + // TODO: cache this instead of creating on demand + return IntObjMapView.empty(INSTANCE); + } + + @Override + public IntObjMapView> getOffDiagonal( + StateSpaceInfo localStateSpace) { + // TODO: cache this instead of creating on demand + return IntObjMapView.empty(IntObjMapView.empty(INSTANCE)); + } + + @Override + public Optional> split() { + return Optional.empty(); + } + + @Override + public boolean evaluate() { + return false; + } +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/impl/IdentityNextStateDescriptor.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/impl/IdentityNextStateDescriptor.java new file mode 100644 index 0000000000..9a1e4a93f7 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/impl/IdentityNextStateDescriptor.java @@ -0,0 +1,67 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.ansd.impl; + +import java.util.Optional; + +import hu.bme.mit.delta.collections.IntObjMapView; +import hu.bme.mit.delta.collections.UniqueTable; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.StateSpaceInfo; + +public final class IdentityNextStateDescriptor implements AbstractNextStateDescriptor { + private static final UniqueTable uniqueTable = UniqueTable.newInstance(); + + public static final AbstractNextStateDescriptor TERMINAL_IDENTITY = new IdentityNextStateDescriptor(); + + public static AbstractNextStateDescriptor withChild(AbstractNextStateDescriptor child) { + return uniqueTable.checkIn(new IdentityNextStateDescriptor(child)); + } + + private final AbstractNextStateDescriptor child; + + private IdentityNextStateDescriptor(AbstractNextStateDescriptor child) { + this.child = child; + } + + private IdentityNextStateDescriptor() { + this.child = this; + } + + @Override + public IntObjMapView getDiagonal(StateSpaceInfo localStateSpace) { + // TODO: cache this instead of creating on demand + return IntObjMapView.empty(child); + } + + @Override + public IntObjMapView> getOffDiagonal( + StateSpaceInfo localStateSpace) { + // TODO: cache this instead of creating on demand + return IntObjMapView.empty(IntObjMapView.empty(AbstractNextStateDescriptor.terminalEmpty())); + } + + @Override + public Optional> split() { + // TODO: this might be a performance overhead + return Optional.empty(); + } + + @Override + public boolean evaluate() { + return true; + } +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/impl/MddNodeInitializer.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/impl/MddNodeInitializer.java new file mode 100644 index 0000000000..c2cd39380d --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/impl/MddNodeInitializer.java @@ -0,0 +1,61 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.ansd.impl; + +import com.google.common.base.Preconditions; +import hu.bme.mit.delta.collections.IntObjMapView; +import hu.bme.mit.delta.collections.impl.IntObjMapViews; +import hu.bme.mit.delta.java.mdd.MddHandle; +import hu.bme.mit.delta.java.mdd.MddNode; +import hu.bme.mit.delta.java.mdd.MddVariableHandle; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.StateSpaceInfo; + +public class MddNodeInitializer implements AbstractNextStateDescriptor.Postcondition { + + private final MddNode node; + + private final MddVariableHandle variableHandle; + + private MddNodeInitializer(final MddNode node, final MddVariableHandle variableHandle) { + this.node = Preconditions.checkNotNull(node); + this.variableHandle = Preconditions.checkNotNull(variableHandle); + Preconditions.checkArgument((variableHandle.isTerminal() && node.isTerminal()) || node.isOn(variableHandle.getVariable().orElseThrow())); + + } + + private static AbstractNextStateDescriptor.Postcondition of(final MddNode node, final MddVariableHandle variableHandle) { + if (node == null || node == variableHandle.getMddGraph().getTerminalZeroNode()) { + return AbstractNextStateDescriptor.Postcondition.terminalEmpty(); + } else { + return new MddNodeInitializer(node, variableHandle); + } + } + + public static AbstractNextStateDescriptor.Postcondition of(final MddHandle handle) { + return of(handle.getNode(), handle.getVariableHandle()); + } + + @Override + public boolean evaluate() { + return true; + } + + @Override + public IntObjMapView getValuations(StateSpaceInfo localStateSpace) { + return new IntObjMapViews.Transforming<>(node, n -> of(n, variableHandle.getLower().orElseThrow())); + } +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/impl/MddNodeNextStateDescriptor.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/impl/MddNodeNextStateDescriptor.java new file mode 100644 index 0000000000..83378ca593 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/impl/MddNodeNextStateDescriptor.java @@ -0,0 +1,292 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.ansd.impl; + +import com.google.common.base.Preconditions; +import hu.bme.mit.delta.collections.IntObjCursor; +import hu.bme.mit.delta.collections.IntObjMapView; +import hu.bme.mit.delta.collections.RecursiveIntObjCursor; +import hu.bme.mit.delta.collections.impl.IntObjMapViews; +import hu.bme.mit.delta.java.mdd.MddHandle; +import hu.bme.mit.delta.java.mdd.MddNode; +import hu.bme.mit.delta.java.mdd.MddVariableHandle; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.StateSpaceInfo; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +public class MddNodeNextStateDescriptor implements AbstractNextStateDescriptor { + + private final MddNode node; + + private final MddVariableHandle variableHandle; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MddNodeNextStateDescriptor that = (MddNodeNextStateDescriptor) o; + return Objects.equals(node, that.node) && Objects.equals(variableHandle, that.variableHandle); + } + + @Override + public int hashCode() { + return Objects.hash(node, variableHandle); + } + + private MddNodeNextStateDescriptor(MddNode node, MddVariableHandle variableHandle) { + this.node = Preconditions.checkNotNull(node); + this.variableHandle = Preconditions.checkNotNull(variableHandle); + Preconditions.checkArgument((variableHandle.isTerminal() && node.isTerminal()) || node.isOn(variableHandle.getVariable().orElseThrow())); + } + + private static AbstractNextStateDescriptor of(MddNode node, MddVariableHandle variableHandle) { + return (node == null || node == variableHandle.getMddGraph().getTerminalZeroNode()) ? AbstractNextStateDescriptor.terminalEmpty() : new MddNodeNextStateDescriptor(node, variableHandle); + } + + public static AbstractNextStateDescriptor of(MddHandle handle) { + return of(handle.getNode(), handle.getVariableHandle()); + } + + @Override + public boolean evaluate() { + return true; + } + + @Override + public IntObjMapView getDiagonal(StateSpaceInfo localStateSpace) { + final MddNode constraint = localStateSpace.toStructuralRepresentation(); + return new ConstrainedIntObjMapView<>(new IntObjMapViews.Transforming<>(node, (n, key) -> { + if (key == null) return AbstractNextStateDescriptor.terminalEmpty(); + else + return MddNodeNextStateDescriptor.of(n.get(key), variableHandle.getLower().orElseThrow().getLower().orElseThrow()); + }), constraint); + } + + @Override + public IntObjMapView> getOffDiagonal(StateSpaceInfo localStateSpace) { + final MddNode constraint = localStateSpace.toStructuralRepresentation(); + return new IntObjMapViews.Transforming<>(node, + outerNode -> new ConstrainedIntObjMapView<>(new IntObjMapViews.Transforming<>(outerNode, mddNode -> MddNodeNextStateDescriptor.of(mddNode, variableHandle.getLower().orElseThrow().getLower().orElseThrow())), constraint)); + } + + @Override + public AbstractNextStateDescriptor.Cursor rootCursor() { + return new Cursor(RecursiveIntObjCursor.singleton(0, this.node), this.variableHandle); + } + + public class Cursor implements AbstractNextStateDescriptor.Cursor { + private final RecursiveIntObjCursor wrapped; + + private final MddVariableHandle variableHandle; + + private final Runnable closer; + + private Cursor(RecursiveIntObjCursor wrapped, MddVariableHandle variableHandle, Runnable closer) { + this.wrapped = wrapped; + this.variableHandle = variableHandle; + this.closer = closer; + } + + private Cursor(RecursiveIntObjCursor wrapped, MddVariableHandle variableHandle) { + this(wrapped, variableHandle, () -> { + }); + } + + @Override + public int key() { + return wrapped.key(); + } + + @Override + public AbstractNextStateDescriptor value() { + return MddNodeNextStateDescriptor.of(wrapped.value(), Cursor.this.variableHandle); + } + + @Override + public boolean moveNext() { + return wrapped.moveNext(); + } + + @Override + public boolean moveTo(int key) { + return wrapped.moveTo(key); + } + +// @Override +// public AbstractNextStateDescriptor.Cursor valueCursor(int from) { +// var fromCursor = wrapped.valueCursor(); +// if (fromCursor.moveTo(from)) { +// return new Cursor(fromCursor.valueCursor(), Cursor.this.variableHandle.getLower().orElseThrow().getLower().orElseThrow(), () -> fromCursor.close()); +// } else return new EmptyCursor(() -> fromCursor.close()); +// } + + @Override + public AbstractNextStateDescriptor.Cursor valueCursor(int from, StateSpaceInfo localStateSpace) { + final MddNode constraint = localStateSpace.toStructuralRepresentation(); + // TODO the valueCursor call of the wrapped cursor has to propagate the constraint + var fromCursor = wrapped.valueCursor(); + if (fromCursor.moveTo(from)) { + return new Cursor(fromCursor.valueCursor(), Cursor.this.variableHandle.getLower().orElseThrow().getLower().orElseThrow(), () -> fromCursor.close()); + } else return new EmptyCursor(() -> fromCursor.close()); + } + + @Override + public void close() { + wrapped.close(); + closer.run(); + } + + @Override + public Optional> split() { + return Optional.of(List.of(this)); + } + } + +// public class Cursor extends CursorBase { +// +// private final RecursiveIntObjCursor fromCursor; +// +// private Cursor(RecursiveIntObjCursor wrapped, RecursiveIntObjCursor fromCursor){ +// super(wrapped); +// this.fromCursor = fromCursor; +// } +// +// @Override +// public void close() { +// super.close(); +// fromCursor.close(); +// } +// } +// +// public class RootCursor extends CursorBase { +// +// private final MddNodeNextStateDescriptor descriptor; +// +// private int currentPosition; +// +// public RootCursor(MddNodeNextStateDescriptor descriptor) { +// super(descriptor.node.cursor()); +// this.descriptor = descriptor; +// this.currentPosition = -1; +// } +// +// @Override +// public int key() { +// throw new UnsupportedOperationException("This operation is not supported on the root cursor"); +// } +// +// @Override +// public AbstractNextStateDescriptor value() { +// return descriptor; +// } +// +// @Override +// public boolean moveNext() { +// currentPosition++; +// return currentPosition == 0; +// } +// +// @Override +// public boolean moveTo(int key) { +// throw new UnsupportedOperationException("This operation is not supported on the root cursor"); +// } +// +// @Override +// public AbstractNextStateDescriptor.Cursor valueCursor(int from) { +// var fromCursor = descriptor.node.cursor(); +// if(fromCursor.moveTo(from)) { +// return new Cursor(fromCursor.valueCursor(), fromCursor); +// } else { +// return EmptyCursor.INSTANCE; +// } +// +// } +// +// @Override +// public void close() {} +// +// } + + public static class EmptyCursor implements AbstractNextStateDescriptor.Cursor { + + private final Runnable closer; + + public EmptyCursor(Runnable closer) { + this.closer = closer; + } + + + @Override + public int key() { + throw new UnsupportedOperationException("This operation is not supported on the root cursor"); + } + + @Override + public AbstractNextStateDescriptor value() { + throw new UnsupportedOperationException("This operation is not supported on the root cursor"); + } + + @Override + public boolean moveNext() { + return false; + } + + @Override + public boolean moveTo(int key) { + return false; + } + + @Override + public AbstractNextStateDescriptor.Cursor valueCursor(int from, StateSpaceInfo localStateSpace) { + throw new UnsupportedOperationException("This operation is not supported on the root cursor"); + } + + @Override + public void close() { + this.closer.run(); + } + + @Override + public Optional> split() { + return Optional.of(List.of(this)); + } + + } + + private class ConstrainedIntObjMapView extends IntObjMapViews.ForwardingBase implements IntObjMapView { + + private final IntObjMapView target; + private final IntObjMapView constraint; + + public ConstrainedIntObjMapView(IntObjMapView target, IntObjMapView constraint) { + this.target = target; + this.constraint = constraint; + } + + @Override + public IntObjMapView getForwardingTarget() { + return this.target; + } + + @Override + public IntObjCursor cursor() { + return target.cursor(constraint); + } + } +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/impl/OrNextStateDescriptor.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/impl/OrNextStateDescriptor.java new file mode 100644 index 0000000000..3274bfbd6c --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/ansd/impl/OrNextStateDescriptor.java @@ -0,0 +1,346 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.ansd.impl; + +import com.koloboke.collect.map.IntObjMap; +import com.koloboke.collect.map.hash.HashIntObjMaps; +import com.koloboke.collect.map.hash.HashObjObjMaps; +import hu.bme.mit.delta.collections.IntObjCursor; +import hu.bme.mit.delta.collections.IntObjMapView; +import hu.bme.mit.delta.collections.UniqueTable; +import hu.bme.mit.delta.collections.impl.MapUniqueTable; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.StateSpaceInfo; + +import java.util.*; +import java.util.stream.Collectors; + +public class OrNextStateDescriptor implements AbstractNextStateDescriptor { + private static final UniqueTable uniqueTable = new MapUniqueTable<>(); + + public static void clearUniqueTable() { + uniqueTable.clear(); + } + + private List operands; + + private Map> diagonalCache = HashObjObjMaps.newUpdatableMap(); + //private IntObjMap> offDiagonalCache = HashIntObjMaps.newUpdatableMap(); + + public static OrNextStateDescriptor create(final List operands) { + final ArrayList ops = new ArrayList<>(operands); + ops.sort(Comparator.comparingInt(Object::hashCode)); + + return uniqueTable.checkIn(new OrNextStateDescriptor(ops)); + } + + private OrNextStateDescriptor(final List operands) { + this.operands = operands; + } + + @Override + public IntObjMapView getDiagonal(final StateSpaceInfo localStateSpace) { + class Diagonal implements IntObjMapView { + private final StateSpaceInfo localStateSpace; + List> diagonals = new ArrayList<>(); + + private IntObjMap cache = HashIntObjMaps.newUpdatableMap(); + private AbstractNextStateDescriptor defaultValue = null; + + Diagonal(List operands, StateSpaceInfo localStateSpace) { + this.localStateSpace = localStateSpace; + for (AbstractNextStateDescriptor ns : operands) { + diagonals.add(ns.getDiagonal(localStateSpace)); + } + } + + @Override + public boolean isEmpty() { + for (IntObjMapView diagonal : diagonals) { + if (!diagonal.isEmpty()) { + return false; + } + } + return true; + } + + @Override + public boolean isProcedural() { + return true; + } + + @Override + public boolean containsKey(final int key) { + for (IntObjMapView diagonal : diagonals) { + if (diagonal.containsKey(key)) { + return true; + } + } + return false; + } + + @Override + public AbstractNextStateDescriptor get(final int key) { + AbstractNextStateDescriptor ret = cache.get(key); + if (ret != null) { + return ret; + } + List results = new ArrayList<>(); + for (IntObjMapView diagonal : diagonals) { + final AbstractNextStateDescriptor value = diagonal.get(key); + if (!AbstractNextStateDescriptor.isNullOrEmpty(value)) { + results.add(value); + } + } + if (results.isEmpty()) { + ret = AbstractNextStateDescriptor.terminalEmpty(); + } else if (results.size() == 1) { + ret = results.get(0); + } else { + ret = OrNextStateDescriptor.create(results); + } + + cache.put(key, ret); + return ret; + } + + @Override + public AbstractNextStateDescriptor defaultValue() { + if (defaultValue != null) { + return defaultValue; + } + List results = new ArrayList<>(); + for (IntObjMapView diagonal : diagonals) { + final AbstractNextStateDescriptor value = diagonal.defaultValue(); + if (!AbstractNextStateDescriptor.isNullOrEmpty(value)) { + results.add(value); + } + } + + AbstractNextStateDescriptor ret; + + if (results.isEmpty()) { + ret = AbstractNextStateDescriptor.terminalEmpty(); + } else if (results.size() == 1) { + ret = results.get(0); + } else { + ret = OrNextStateDescriptor.create(results); + } + defaultValue = ret; + return ret; + } + + @Override + public IntObjCursor cursor() { + // TODO: Auto-generated method stub. + throw new UnsupportedOperationException("Not (yet) implemented."); + //return 0; + } + + @Override + public int size() { + // TODO: Auto-generated method stub. + throw new UnsupportedOperationException("Not (yet) implemented."); + //return 0; + } + } + ; + + IntObjMapView ret = diagonalCache.computeIfAbsent(localStateSpace.getTraceInfo(), + (o) -> new Diagonal(operands, + localStateSpace)); + + return ret; + } + + @Override + public IntObjMapView> getOffDiagonal(final StateSpaceInfo localStateSpace) { + // TODO: Auto-generated method stub. + throw new UnsupportedOperationException("Not (yet) implemented."); + //return null; + } + + @Override + public Optional> split() { + return Optional.of(operands); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof OrNextStateDescriptor)) return false; + + final OrNextStateDescriptor that = (OrNextStateDescriptor) o; + + return operands.equals(that.operands); + } + + private int hashCode = 0; + + @Override + public int hashCode() { + if (hashCode != 0) { + return hashCode; + } + return hashCode = operands.hashCode(); + } + + @Override + public String toString() { + return operands.stream().map(ns -> ns.toString()).collect(Collectors.joining(", ")); + } + + @Override + public Cursor cursor(int from, StateSpaceInfo localStateSpace) { + return AbstractNextStateDescriptor.super.cursor(from, localStateSpace); + } + + @Override + public Cursor rootCursor() { + return RootOrCursor.of(operands.stream().map(AbstractNextStateDescriptor::rootCursor).toList()); + } + + public static class RootOrCursor implements AbstractNextStateDescriptor.Cursor { + + private final List cursors; + + private int currentPosition; + + private RootOrCursor(final List cursors) { + this.cursors = cursors; + this.currentPosition = -1; + } + + public static AbstractNextStateDescriptor.Cursor of(final List cursors) { + if (cursors.size() == 1) return cursors.get(0); + else return new RootOrCursor(cursors); + } + + @Override + public int key() { + throw new UnsupportedOperationException("Not (yet) implemented"); + } + + @Override + public AbstractNextStateDescriptor value() { + throw new UnsupportedOperationException("Not (yet) implemented"); + } + + @Override + public boolean moveNext() { + currentPosition++; + this.cursors.forEach(AbstractNextStateDescriptor.Cursor::moveNext); + return currentPosition == 0; + } + + @Override + public boolean moveTo(int key) { + throw new UnsupportedOperationException("Not (yet) implemented"); + } + + @Override + public Cursor valueCursor(int from, StateSpaceInfo localStateSpace) { + return OrCursor.of(cursors.stream().map(c -> c.valueCursor(from, localStateSpace)).toList()); + } + + @Override + public void close() { + cursors.forEach(AbstractNextStateDescriptor.Cursor::close); + } + + @Override + public Optional> split() { + return Optional.of(cursors); + } + + } + + public static class OrCursor implements AbstractNextStateDescriptor.Cursor { + + private final List cursors; + + private List activeCursors; + private Optional key; + + private OrCursor(final List cursors) { + this.cursors = cursors; + this.activeCursors = new ArrayList<>(); + this.key = Optional.empty(); + } + + public static AbstractNextStateDescriptor.Cursor of(final List cursors) { + if (cursors.size() == 1) return cursors.get(0); + else return new OrCursor(cursors); + } + + @Override + public int key() { + return key.orElseThrow(); + } + + @Override + public AbstractNextStateDescriptor value() { + AbstractNextStateDescriptor ret; + + if (activeCursors.isEmpty()) { + ret = AbstractNextStateDescriptor.terminalEmpty(); + } else if (activeCursors.size() == 1) { + ret = activeCursors.get(0).value(); + } else { + ret = OrNextStateDescriptor.create(activeCursors.stream().map(AbstractNextStateDescriptor.Cursor::value).toList()); + } + return ret; + } + + @Override + public boolean moveNext() { + throw new UnsupportedOperationException("Not (yet) implemented"); + } + + @Override + public boolean moveTo(int key) { + boolean res = false; + this.activeCursors = new ArrayList<>(); + for (AbstractNextStateDescriptor.Cursor cursor : cursors) { + if (cursor.moveTo(key)) { + activeCursors.add(cursor); + res = true; + } + } + if (res) { + this.key = Optional.of(key); + } else { + this.key = Optional.empty(); + } + return res; + } + + @Override + public AbstractNextStateDescriptor.Cursor valueCursor(int from, StateSpaceInfo localStateSpace) { + return OrCursor.of(activeCursors.stream().map(c -> c.valueCursor(from, localStateSpace)).toList()); + } + + @Override + public void close() { + cursors.forEach(AbstractNextStateDescriptor.Cursor::close); + } + + @Override + public Optional> split() { + return Optional.of(activeCursors); + } + } +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/expressionnode/ExprLatticeDefinition.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/expressionnode/ExprLatticeDefinition.java new file mode 100644 index 0000000000..7c67ea0d3a --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/expressionnode/ExprLatticeDefinition.java @@ -0,0 +1,41 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.expressionnode; + +import hu.bme.mit.delta.mdd.LatticeDefinition; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.booltype.SmartBoolExprs; + +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.False; +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.True; +import static hu.bme.mit.theta.core.type.booltype.SmartBoolExprs.And; +import static hu.bme.mit.theta.core.type.booltype.SmartBoolExprs.Not; + + +public class ExprLatticeDefinition { + + public static LatticeDefinition forExpr() { + return new LatticeDefinition<>( + Expr.class, + False(), + True(), + SmartBoolExprs::Or, + SmartBoolExprs::And, + (a, b) -> And(a, Not(b)) + ); + } + +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/expressionnode/LitExprConverter.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/expressionnode/LitExprConverter.java new file mode 100644 index 0000000000..3be2042cf3 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/expressionnode/LitExprConverter.java @@ -0,0 +1,84 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.expressionnode; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import hu.bme.mit.theta.core.type.LitExpr; +import hu.bme.mit.theta.core.type.Type; +import hu.bme.mit.theta.core.type.anytype.InvalidLitExpr; +import hu.bme.mit.theta.core.type.arraytype.ArrayLitExpr; +import hu.bme.mit.theta.core.type.arraytype.ArrayType; +import hu.bme.mit.theta.core.type.booltype.BoolLitExpr; +import hu.bme.mit.theta.core.type.booltype.BoolType; +import hu.bme.mit.theta.core.type.enumtype.EnumLitExpr; +import hu.bme.mit.theta.core.type.enumtype.EnumType; +import hu.bme.mit.theta.core.type.inttype.IntLitExpr; +import hu.bme.mit.theta.core.type.inttype.IntType; + +import java.math.BigInteger; + +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; + +/** + * Util class for converting between integers and {@link LitExpr} + */ +public class LitExprConverter { + + private static int cnt = 0; + private final static BiMap objToInt = HashBiMap.create(); + + public static int toInt(LitExpr litExpr) { + if (litExpr instanceof IntLitExpr) { + return ((IntLitExpr) litExpr).getValue().intValue(); + } + if (litExpr instanceof BoolLitExpr) { + return ((BoolLitExpr) litExpr).getValue() ? 1 : 0; + } + if (litExpr instanceof ArrayLitExpr) { + if (objToInt.get(litExpr) != null) { + return objToInt.get(litExpr); + } + final int id = cnt++; + objToInt.put(litExpr, id); + return id; + } + if (litExpr instanceof EnumLitExpr) { + return ((EnumLitExpr) litExpr).getType().getIntValue((EnumLitExpr) litExpr); + } + throw new UnsupportedOperationException("Unsupported type"); + } + + public static LitExpr toLitExpr(int integer, Type type) { + if (type instanceof IntType) { + return IntLitExpr.of(BigInteger.valueOf(integer)); + } + if (type instanceof BoolType) { + if (integer > 1 || integer < 0) { + return new InvalidLitExpr<>(Bool()); + } + return BoolLitExpr.of(integer != 0); + } + if (type instanceof ArrayType) { + return (LitExpr) objToInt.inverse().get(integer); + } + if (type instanceof EnumType) { + return ((EnumType) type).litFromIntValue(integer); + } + throw new UnsupportedOperationException("Unsupported type"); + } + +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/expressionnode/MddExpressionRepresentation.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/expressionnode/MddExpressionRepresentation.java new file mode 100644 index 0000000000..74415db439 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/expressionnode/MddExpressionRepresentation.java @@ -0,0 +1,730 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.expressionnode; + +import com.google.common.base.Preconditions; +import com.koloboke.collect.map.hash.HashIntObjMap; +import com.koloboke.collect.map.hash.HashIntObjMaps; +import hu.bme.mit.delta.collections.*; +import hu.bme.mit.delta.java.mdd.MddGraph; +import hu.bme.mit.delta.java.mdd.MddNode; +import hu.bme.mit.delta.java.mdd.MddVariable; +import hu.bme.mit.theta.solver.SolverPool; +import hu.bme.mit.theta.common.GrowingIntArray; +import hu.bme.mit.theta.core.decl.Decl; +import hu.bme.mit.theta.core.model.ImmutableValuation; +import hu.bme.mit.theta.core.model.MutableValuation; +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.LitExpr; +import hu.bme.mit.theta.core.type.booltype.BoolType; +import hu.bme.mit.theta.core.type.booltype.FalseExpr; +import hu.bme.mit.theta.core.type.enumtype.EnumType; +import hu.bme.mit.theta.core.utils.ExprUtils; +import hu.bme.mit.theta.solver.Solver; +import hu.bme.mit.theta.solver.SolverStatus; +import hu.bme.mit.theta.solver.utils.WithPushPop; + +import java.io.Closeable; +import java.util.*; + +import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.*; +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.True; +import static hu.bme.mit.theta.core.type.booltype.SmartBoolExprs.And; + +public class MddExpressionRepresentation implements RecursiveIntObjMapView { + + private final Expr expr; + private final Decl decl; + private final MddVariable mddVariable; + + private Traverser lazyTraverser; + private final ExplicitRepresentation explicitRepresentation; + + private final SolverPool solverPool; + + private MddExpressionRepresentation(final Expr expr, final Decl decl, final MddVariable mddVariable, final SolverPool solverPool) { + this.expr = expr; + this.decl = decl; + this.mddVariable = mddVariable; + this.solverPool = solverPool; + this.explicitRepresentation = new ExplicitRepresentation(); + } + + //TODO only for debugging + public ExplicitRepresentation getExplicitRepresentation() { + return explicitRepresentation; + } + + public static MddExpressionRepresentation of(final Expr expr, final Decl decl, final MddVariable mddVariable, final SolverPool solverPool) { + return new MddExpressionRepresentation(expr, decl, mddVariable, solverPool); + } + + public static MddExpressionRepresentation ofDefault(final Expr expr, final Decl decl, final MddVariable mddVariable, final SolverPool solverPool, final MddNode defaultValue) { + final MddExpressionRepresentation representation = new MddExpressionRepresentation(expr, decl, mddVariable, solverPool); + representation.explicitRepresentation.cacheDefault(defaultValue); + representation.explicitRepresentation.setComplete(); + return representation; + } + + public Expr getExpr() { + return expr; + } + + public Decl getDecl() { + return decl; + } + + public MddVariable getMddVariable() { + return mddVariable; + } + + private Traverser getLazyTraverser() { + if (lazyTraverser == null) lazyTraverser = Traverser.create(this, solverPool); + return lazyTraverser; + } + + @Override + public boolean isEmpty() { +// return false; + return explicitRepresentation.isComplete() && size() == 0; + } + + @Override + public boolean isProcedural() { + return !explicitRepresentation.isComplete(); + } + + @Override + public boolean containsKey(int key) { + return getLazyTraverser().queryEdge(key); + } + + public static int getCounter = 0; + + @Override + public MddNode get(int key) { + final var cached = explicitRepresentation.getCacheView().get(key); + if (cached != null || this.explicitRepresentation.isComplete()) return cached; + // TODO: this way null values are never cached and have to be recomputed every time + + final MutableValuation val = new MutableValuation(); + final LitExpr litExpr = LitExprConverter.toLitExpr(key, decl.getType()); + if (litExpr.isInvalid()) { + return null; + } + + val.put(decl, litExpr); + final Expr simplifiedExpr = ExprUtils.simplify(expr, val); + + final MddNode childNode; + if (mddVariable.getLower().isPresent()) { + final MddExpressionTemplate template = MddExpressionTemplate.of(simplifiedExpr, o -> (Decl) o, solverPool); + childNode = mddVariable.getLower().get().checkInNode(template); + } else { + final Expr canonizedExpr = ExprUtils.canonize(ExprUtils.simplify(simplifiedExpr)); + MddGraph mddGraph = (MddGraph) mddVariable.getMddGraph(); + + if (canonizedExpr instanceof FalseExpr) { + childNode = null; + } else { + var solver = solverPool.requestSolver(); + try (var wpp = new WithPushPop(solver)) { + solver.add(canonizedExpr); + if (solver.check().isSat()) { + childNode = mddGraph.getNodeFor(canonizedExpr); + } else { + childNode = null; + } + } + } + } + if (!mddVariable.isNullOrZero(childNode)) explicitRepresentation.cacheNode(key, childNode); + return childNode; + } + + @Override + public MddNode defaultValue() { + return explicitRepresentation.getCacheView().defaultValue(); + } + + @Override + public RecursiveIntObjCursor cursor() { + return new Cursor(null, Traverser.create(this, solverPool)); + } + + @Override + public RecursiveIntObjCursor cursor(RecursiveIntObjMapView constraint) { + Preconditions.checkArgument(constraint instanceof MddNode); + final MddNode mddNodeConstraint = (MddNode) constraint; + final List> exprs = new ArrayList<>(); + + if (mddVariable.getLower().isPresent()) { + MddVariable variable = mddVariable.getLower().get(); + MddNode mddNode = mddNodeConstraint.get(mddNodeConstraint.statistics().lowestValue()); + while (true) { + + // This is needed because the constraint node might contain level-skips: of the domain is bounded, then default values are detected + if (mddNode.isTerminal()) break; + + final IntStatistics statistics = mddNode.statistics(); + final Decl decl = variable.getTraceInfo(Decl.class); + final LitExpr lowerBound = LitExprConverter.toLitExpr(statistics.lowestValue(), decl.getType()); + final LitExpr upperBound = LitExprConverter.toLitExpr(statistics.highestValue(), decl.getType()); + if (!decl.getType().equals(BoolType.getInstance()) && !(decl.getType() instanceof EnumType)) { // TODO delete + if (lowerBound.equals(upperBound)) { + exprs.add(Eq(decl.getRef(), lowerBound)); + } else { + exprs.add(And(Geq(decl.getRef(), lowerBound), Leq(decl.getRef(), upperBound))); + } + } + + + if (variable.getLower().isEmpty() || variable.getLower().get().getLower().isEmpty()) { + break; + } else { + variable = variable.getLower().get().getLower().get(); + mddNode = mddNode.get(statistics.lowestValue()); // TODO we assume here that all edges point to the same node + } + + } + } +// System.out.println(exprs); + return new Cursor(null, Traverser.createConstrained(this, And(exprs), solverPool)); + } + + @Override + public int size() { + if (explicitRepresentation.isComplete()) + return explicitRepresentation.getCacheView().size(); + return -1; + } + + @Override + public String toString() { + return expr.toString() + ", " + decl.toString(); + } + + @Override + public boolean equals(Object that) { + if (this == that) return true; + if (that instanceof MddExpressionRepresentation) { + return Objects.equals(expr, ((MddExpressionRepresentation) that).expr) && + Objects.equals(decl, ((MddExpressionRepresentation) that).decl) && + Objects.equals(mddVariable, ((MddExpressionRepresentation) that).mddVariable); + } + if (that instanceof MddNode) { + return this.equals(((MddNode) that).getRepresentation()); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(expr, decl, mddVariable); + + } + + public static class ExplicitRepresentation { + private final HashIntObjMap cache; + private final GrowingIntArray edgeOrdering; + private MddNode defaultValue; + private boolean complete; + + public ExplicitRepresentation() { + this.cache = HashIntObjMaps.newUpdatableMap(); + this.edgeOrdering = new GrowingIntArray(100, 100); + this.defaultValue = null; + this.complete = false; + } + + public void cacheNode(int key, MddNode node) { + Preconditions.checkState(!complete); + Preconditions.checkState(defaultValue == null); + this.cache.put(key, node); + this.edgeOrdering.add(key); + } + + public void cacheDefault(MddNode defaultValue) { + Preconditions.checkState(!complete); + this.defaultValue = defaultValue; + } + + public void setComplete() { + this.complete = true; + } + + public IntObjMapView getCacheView() { + return IntObjMapView.of(cache, defaultValue); + } + + public boolean isComplete() { + return complete; + } + + public int getEdge(int index) { + return edgeOrdering.get(index); + } + + public int getSize() { + return edgeOrdering.getSize(); + } + } + + private static class Traverser implements Closeable { + + private MddExpressionRepresentation currentRepresentation; + + private final SolverPool solverPool; + private Solver solver; + + private final Stack stack; + private int pushedNegatedAssignments = 0; + + private final boolean constrained; + + private Traverser(MddExpressionRepresentation rootRepresentation, Expr constraint, SolverPool solverPool, boolean constrained) { + this.solverPool = solverPool; + this.solver = solverPool.requestSolver(); + this.stack = new Stack<>(); + this.constrained = constrained; + + solver.push(); + solver.add(rootRepresentation.expr); + solver.add(constraint); + setCurrentRepresentation(Preconditions.checkNotNull(rootRepresentation)); + } + + public static Traverser createConstrained(MddExpressionRepresentation rootRepresentation, Expr constraint, SolverPool solverPool) { + return new Traverser(rootRepresentation, constraint, solverPool, true); + } + + public static Traverser create(MddExpressionRepresentation rootRepresentation, SolverPool solverPool) { + return new Traverser(rootRepresentation, True(), solverPool, false); + } + + public MddExpressionRepresentation moveUp() { + Preconditions.checkState(stack.size() > 0); + popNegatedAssignments(); + solver.pop(); // pop assignment that brought us here + setCurrentRepresentation(stack.pop()); + return currentRepresentation; + } + + public boolean queryEdge(int assignment) { + if (currentRepresentation.explicitRepresentation.getCacheView().keySet().contains(assignment) || currentRepresentation.explicitRepresentation.getCacheView().defaultValue() != null) + return true; + else if (!currentRepresentation.explicitRepresentation.isComplete()) { + final SolverStatus status; + final Valuation model; + final LitExpr litExpr = LitExprConverter.toLitExpr(assignment, currentRepresentation.decl.getType()); + try (WithPushPop wpp = new WithPushPop(solver)) { + solver.add(Eq(currentRepresentation.decl.getRef(), litExpr)); + solver.check(); + status = solver.getStatus(); + model = status.isSat() ? solver.getModel() : null; + } + Preconditions.checkNotNull(status); + if (status.isSat()) { + cacheModel(model); + solver.add(Neq(currentRepresentation.decl.getRef(), litExpr)); + pushedNegatedAssignments++; + return true; + } + } + return false; + } + + public MddNode peekDown(int assignment) { + queryEdge(assignment); + return currentRepresentation.explicitRepresentation.getCacheView().get(assignment); + } + + public QueryResult queryEdge() { + if (!currentRepresentation.explicitRepresentation.isComplete()) { + if (pushedNegatedAssignments != currentRepresentation.explicitRepresentation.getCacheView().keySet().size()) { + popNegatedAssignments(); + pushNegatedAssignments(); + } + solver.check(); + if (solver.getStatus().isSat()) { + final Valuation model = solver.getModel(); + final Decl decl = currentRepresentation.decl; + final Optional> optionalLitExpr = model.eval(decl); + + final LitExpr literal; + final Valuation modelToCache; + if (optionalLitExpr.isPresent()) { + literal = optionalLitExpr.get(); + modelToCache = model; + } else { + final int newValue; + if (currentRepresentation.mddVariable.isBounded()) { + final IntSetView domain = IntSetView.range(0, currentRepresentation.mddVariable.getDomainSize()); + final IntSetView remaining = domain.minus(currentRepresentation.explicitRepresentation.getCacheView().keySet()); + if (remaining.isEmpty()) { + currentRepresentation.explicitRepresentation.setComplete(); + return QueryResult.failed(); + } else { + final var cur = remaining.cursor(); + Preconditions.checkState(cur.moveNext()); + newValue = cur.elem(); + } + } else { + // only visited once per node, because of the negated assignment that is pushed to the solver + final IntSetView cachedKeys = currentRepresentation.explicitRepresentation.getCacheView().keySet(); + newValue = cachedKeys.isEmpty() ? 0 : cachedKeys.statistics().highestValue() + 1; + } + literal = LitExprConverter.toLitExpr(newValue, decl.getType()); + final var extendedModel = MutableValuation.copyOf(model); + extendedModel.put(decl, literal); + modelToCache = extendedModel; + } + + solver.add(Neq(decl.getRef(), literal)); + pushedNegatedAssignments++; + cacheModel(modelToCache); + return QueryResult.singleEdge(LitExprConverter.toInt(literal)); + } else { + if (constrained) { + return QueryResult.constrainedFailed(); + } else { + currentRepresentation.explicitRepresentation.setComplete(); + } + } + } + return QueryResult.failed(); + } + + // TODO összevonni queryChilddal + public MddNode moveDown(int assignment) { + if (queryEdge(assignment)) { + popNegatedAssignments(); + solver.push(); + solver.add(Eq(currentRepresentation.decl.getRef(), LitExprConverter.toLitExpr(assignment, currentRepresentation.decl.getType()))); + stack.push(currentRepresentation); + final MddNode childNode = currentRepresentation.explicitRepresentation.getCacheView().get(assignment); + Preconditions.checkArgument(childNode.getRepresentation() instanceof MddExpressionRepresentation); + setCurrentRepresentation((MddExpressionRepresentation) childNode.getRepresentation()); + return childNode; + } else return null; + } + + private void pushNegatedAssignments() { + solver.push(); + final var negatedAssignments = new ArrayList>(); + for (var cur = currentRepresentation.explicitRepresentation.getCacheView().cursor(); cur.moveNext(); ) { + negatedAssignments.add(Neq(currentRepresentation.decl.getRef(), LitExprConverter.toLitExpr(cur.key(), currentRepresentation.decl.getType()))); + pushedNegatedAssignments++; + } + solver.add(And(negatedAssignments)); + } + + private void popNegatedAssignments() { + solver.pop(); + pushedNegatedAssignments = 0; + } + + private void cacheModel(Valuation valuation) { + MddExpressionRepresentation representation = currentRepresentation; + + while (true) { + + final MddNode childNode; + if (representation.explicitRepresentation.getCacheView().defaultValue() != null) { + + childNode = representation.explicitRepresentation.getCacheView().defaultValue(); + + } else { + + final Optional lower = representation.mddVariable.getLower(); + final LitExpr literalToCache = determineLiteralToCache(representation, valuation); + + if (representation.explicitRepresentation.getCacheView().containsKey(LitExprConverter.toInt(literalToCache))) { + + childNode = representation.explicitRepresentation.getCacheView().get(LitExprConverter.toInt(literalToCache)); + assert lower.isEmpty() || childNode.isOn(lower.get()); + + } else { + + final Expr substitutedExpr = ExprUtils.simplify(representation.expr, ImmutableValuation.builder().put(representation.getDecl(), literalToCache).build()); + if (lower.isPresent()) { + final MddExpressionTemplate template = MddExpressionTemplate.of(substitutedExpr, o -> (Decl) o, representation.solverPool); + childNode = lower.get().checkInNode(template); + } else { + final Expr canonizedExpr = ExprUtils.canonize(substitutedExpr); + MddGraph mddGraph = (MddGraph) representation.mddVariable.getMddGraph(); + assert !(canonizedExpr instanceof FalseExpr); + childNode = mddGraph.getNodeFor(canonizedExpr); + } + + assert !representation.mddVariable.isNullOrZero(childNode) : "This would mean the model returned by the solver is incorrect"; + representation.explicitRepresentation.cacheNode(LitExprConverter.toInt(literalToCache), childNode); + // TODO update domainSize + } + } + + if (childNode.isTerminal()) break; + + //Preconditions.checkArgument(childNode.getRepresentation() instanceof MddExpressionRepresentation); + // TODO assert + representation = (MddExpressionRepresentation) childNode.getRepresentation(); + } + } + + private static LitExpr determineLiteralToCache(MddExpressionRepresentation representation, Valuation valuation) { + final Decl decl = representation.getDecl(); + final Optional> literal = valuation.eval(decl); + + if (literal.isPresent()) { + return literal.get(); + } else { + return LitExprConverter.toLitExpr(generateMissingLiteral(representation), decl.getType()); + } + } + + private static int generateMissingLiteral(MddExpressionRepresentation representation) { + final int newValue; + if (representation.mddVariable.isBounded()) { + final IntSetView domain = IntSetView.range(0, representation.mddVariable.getDomainSize()); + final IntSetView remaining = domain.minus(representation.explicitRepresentation.getCacheView().keySet()); + if (remaining.isEmpty()) { + representation.explicitRepresentation.setComplete(); + // Return the first element + newValue = representation.explicitRepresentation.getCacheView().keySet().statistics().lowestValue(); + } else { + final var cur = remaining.cursor(); + Preconditions.checkState(cur.moveNext()); + newValue = cur.elem(); + } + } else { + final IntSetView cachedKeys = representation.explicitRepresentation.getCacheView().keySet(); + newValue = cachedKeys.isEmpty() ? 0 : cachedKeys.statistics().highestValue() + 1; + } + return newValue; + } + + private void setCurrentRepresentation(MddExpressionRepresentation representation) { + this.currentRepresentation = representation; + pushNegatedAssignments(); + } + + @Override + public void close() { + popNegatedAssignments(); + solver.pop(); // pop base expression + solverPool.returnSolver(this.solver); + this.solver = null; + } + + private static class QueryResult { + private final QueryResult.Status status; + + private final int key; + + private QueryResult(int key, QueryResult.Status status) { + this.status = status; + this.key = key; + } + + public static QueryResult singleEdge(int key) { + return new QueryResult(key, QueryResult.Status.SINGLE_EDGE); + } + + public static QueryResult constrainedFailed() { + return new QueryResult(-1, Status.CONSTRAINED_FAILED); + } + + public static QueryResult failed() { + return new QueryResult(-1, QueryResult.Status.FAILED); + } + + public static QueryResult defaultEdge() { + return new QueryResult(-1, QueryResult.Status.DEFAULT_EDGE); + } + + public int getKey() { + return key; + } + + public QueryResult.Status getStatus() { + return status; + } + + /** + * The status of the result. + * FAILED: no further edges are possible + * SINGLE_EDGE: a single edge was found + * DEFAULT_EDGE: the node is a level-skip and has a default value + */ + public enum Status { + FAILED, SINGLE_EDGE, DEFAULT_EDGE, CONSTRAINED_FAILED + } + + } + } + + private static class Cursor implements RecursiveIntObjCursor { + + // Fields for node enumeration + private final Traverser traverser; + + + // Fields for the recursive cursor structure + private final Cursor parent; + private boolean blocked = false; + private boolean closed = false; + + + // Common cursor fields + private int index; + private int key; + private MddNode value; + private boolean initialized = false; + + // Fields for constrained cursors + private boolean constrainedFailed = false; + + public Cursor(final Cursor parent, final Traverser traverser) { + this.parent = parent; + this.traverser = traverser; + this.index = -1; + this.key = -1; + this.value = null; + } + + private static class Terminal implements RecursiveIntObjCursor { + + private final Cursor parent; + + private Terminal(final Cursor parent) { + this.parent = parent; + } + + @Override + public boolean moveTo(int i) { + return false; + } + + @Override + public void close() { + parent.unblock(); + } + + // TODO: exception + @Override + public int key() { + return 0; + } + + // TODO: exception + @Override + public MddNode value() { + return null; + } + + @Override + public boolean moveNext() { + return false; + } + } + + @Override + public boolean moveTo(int key) { + Preconditions.checkState(!blocked, "Cursor can't be moved until its children are disposed of"); + Preconditions.checkState(!closed, "Cursor can't be moved if it was closed"); + + var currentRepresentation = traverser.currentRepresentation; + if (currentRepresentation.explicitRepresentation.getCacheView().containsKey(key) || !currentRepresentation.explicitRepresentation.isComplete() && traverser.queryEdge(key)) { + this.key = key; + this.value = currentRepresentation.get(key); + this.initialized = true; + return true; + } + return false; + + } + + @Override + public RecursiveIntObjCursor valueCursor() { + Preconditions.checkState(!blocked, "Can't provide value cursor for blocked cursor"); + Preconditions.checkState(!closed, "Can't provide value cursor for closed cursor"); + + this.blocked = true; + final MddNode childNode = this.traverser.peekDown(key); + if (childNode.isTerminal()) { + return new Terminal(this); + } else { + this.traverser.moveDown(key); + return new Cursor(this, traverser); + } + } + + @Override + public int key() { + Preconditions.checkState(initialized, "Cursor is not initialized"); + return key; + } + + @Override + public MddNode value() { + Preconditions.checkState(initialized, "Cursor is not initialized"); + return value; + } + + @Override + public boolean moveNext() { + Preconditions.checkState(!blocked, "Cursor can't be moved until its children are not closed"); + Preconditions.checkState(!closed, "Cursor can't be moved if it was closed"); + + var currentRepresentation = traverser.currentRepresentation; + if (index < currentRepresentation.explicitRepresentation.getSize() - 1) { + index++; + key = currentRepresentation.explicitRepresentation.getEdge(index); + value = currentRepresentation.explicitRepresentation.getCacheView().get(key); + initialized = true; + return true; + } else if (!currentRepresentation.explicitRepresentation.isComplete() && !constrainedFailed) { + final MddExpressionRepresentation.Traverser.QueryResult queryResult = traverser.queryEdge(); + if (queryResult.getStatus() == MddExpressionRepresentation.Traverser.QueryResult.Status.SINGLE_EDGE) { + index++; + key = queryResult.getKey(); + value = currentRepresentation.explicitRepresentation.getCacheView().get(key); + initialized = true; + return true; + } else if (queryResult.getStatus() == Traverser.QueryResult.Status.CONSTRAINED_FAILED) { + this.constrainedFailed = true; + } + } + return false; + } + + @Override + public void close() { + this.closed = true; + if (parent != null) { + traverser.moveUp(); + parent.unblock(); + } else { + traverser.close(); + } + } + + private void unblock() { + this.blocked = false; + } + } +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/expressionnode/MddExpressionTemplate.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/expressionnode/MddExpressionTemplate.java new file mode 100644 index 0000000000..97340dfbf4 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/expressionnode/MddExpressionTemplate.java @@ -0,0 +1,99 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.expressionnode; + +import hu.bme.mit.delta.collections.RecursiveIntObjMapView; +import hu.bme.mit.delta.java.mdd.MddCanonizationStrategy; +import hu.bme.mit.delta.java.mdd.MddGraph; +import hu.bme.mit.delta.java.mdd.MddNode; +import hu.bme.mit.delta.java.mdd.MddVariable; +import hu.bme.mit.theta.solver.SolverPool; +import hu.bme.mit.theta.core.decl.Decl; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.booltype.BoolType; +import hu.bme.mit.theta.core.type.booltype.FalseExpr; +import hu.bme.mit.theta.core.utils.ExprUtils; +import hu.bme.mit.theta.solver.Solver; +import hu.bme.mit.theta.solver.utils.WithPushPop; + +import java.util.function.Function; + +public class MddExpressionTemplate implements MddNode.Template { + + private final Expr expr; + private final Function extractDecl; + private final SolverPool solverPool; + + private static Solver lazySolver; + + private static boolean isSat(Expr expr, SolverPool solverPool) { + if (lazySolver == null) lazySolver = solverPool.requestSolver(); + boolean res; + try (var wpp = new WithPushPop(lazySolver)) { + lazySolver.add(expr); + res = lazySolver.check().isSat(); + } + return res; + } + + private MddExpressionTemplate(Expr expr, Function extractDecl, SolverPool solverPool) { + this.expr = expr; + this.extractDecl = extractDecl; + this.solverPool = solverPool; + } + + public static MddExpressionTemplate of(Expr expr, Function extractDecl, SolverPool solverPool) { + return new MddExpressionTemplate(expr, extractDecl, solverPool); + } + + @Override + public RecursiveIntObjMapView toCanonicalRepresentation(MddVariable mddVariable, MddCanonizationStrategy mddCanonizationStrategy) { + final Decl decl = extractDecl.apply(mddVariable.getTraceInfo()); + + final Expr canonizedExpr = ExprUtils.canonize(ExprUtils.simplify(expr)); + +// // TODO: we might not need this +// // Check if terminal 1 +// if (ExprUtils.getConstants(canonizedExpr).isEmpty()) { +// if (canonizedExpr instanceof FalseExpr) { +// return mddVariable.getMddGraph().getTerminalZeroNode(); +// } /*else { +// final MddGraph mddGraph = (MddGraph) mddVariable.getMddGraph(); +// return mddGraph.getNodeFor(canonizedExpr); +// }*/ +// } + + // Check if terminal 0 + if (canonizedExpr instanceof FalseExpr || !isSat(canonizedExpr, solverPool)) { + return null; + } + + // Check if default + if (mddVariable.getDomainSize() == 0 && !ExprUtils.getConstants(canonizedExpr).contains(decl)) { + final MddNode childNode; + if (mddVariable.getLower().isPresent()) { + childNode = mddVariable.getLower().get().checkInNode(new MddExpressionTemplate(canonizedExpr, o -> (Decl) o, solverPool)); + } else { + final MddGraph mddGraph = (MddGraph) mddVariable.getMddGraph(); + childNode = mddGraph.getNodeFor(canonizedExpr); + } + return MddExpressionRepresentation.ofDefault(canonizedExpr, decl, mddVariable, solverPool, childNode); + } + + return MddExpressionRepresentation.of(canonizedExpr, decl, mddVariable, solverPool); + + } +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/BfsProvider.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/BfsProvider.java new file mode 100644 index 0000000000..8214ca8712 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/BfsProvider.java @@ -0,0 +1,138 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.fixedpoint; + +import hu.bme.mit.delta.java.mdd.*; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor; + +import java.util.Optional; + +public final class BfsProvider implements MddTransformationProvider { + public static boolean verbose = false; + + private final CacheManager> cacheManager = new CacheManager<>( + v -> new BinaryOperationCache<>()); + private final MddVariableOrder variableOrder; + private final RelationalProductProvider relProdProvider; + + public BfsProvider(final MddVariableOrder variableOrder) { + this(variableOrder, new LegacyRelationalProductProvider(variableOrder)); + } + + public BfsProvider(final MddVariableOrder variableOrder, final RelationalProductProvider relProdProvider) { + this.variableOrder = variableOrder; + this.relProdProvider = relProdProvider; + this.variableOrder.getMddGraph().registerCleanupListener(this); + } + + public MddHandle compute( + AbstractNextStateDescriptor.Postcondition initializer, + AbstractNextStateDescriptor nextStateRelation, + MddVariableHandle highestAffectedVariable + ) { + + final MddHandle initialStates = relProdProvider.compute(variableOrder.getMddGraph().getHandleForTop(), initializer, highestAffectedVariable); + + MddNode result; + + if (highestAffectedVariable.getVariable().isPresent()) { + final MddVariable variable = highestAffectedVariable.getVariable().get(); + result = this.compute(initialStates.getNode(), nextStateRelation, variable); + } else { + result = this.computeTerminal(initialStates.getNode(), nextStateRelation, + highestAffectedVariable.getMddGraph()); + } + + + return highestAffectedVariable.getHandleFor(result); + } + + @Override + public MddNode compute( + final MddNode mddNode, + final AbstractNextStateDescriptor nextStateRelation, + final MddVariable mddVariable + ) { + MddNode res = variableOrder.getMddGraph().getTerminalZeroNode(); + MddNode nextLayer = mddNode; + + while (res != nextLayer) { + if (verbose) { + System.out.println("Starting new layer..."); + // System.out.println("Previous result: " + res); + // System.out.println(GraphvizSerializer.serialize(variableOrder.getDefaultSetSignature().getTopVariableHandle().getHandleFor(res))); + // System.out.println("New result: " + nextLayer); + // System.out.println(GraphvizSerializer.serialize(variableOrder.getDefaultSetSignature().getTopVariableHandle().getHandleFor(nextLayer))); + } + res = nextLayer; + final Optional> splitNS = nextStateRelation.split(); + if (splitNS.isPresent()) { + for (AbstractNextStateDescriptor next : splitNS.get()) { + if (verbose) { + System.out.println("Applying transition: " + next); + } + nextLayer = mddVariable.union(nextLayer, relProdProvider.compute(nextLayer, next, mddVariable)); + } + } else { + if (verbose) { + System.out.println("Applying transition: " + nextStateRelation); + } + nextLayer = mddVariable.union(nextLayer, relProdProvider.compute(nextLayer, nextStateRelation, mddVariable)); + } + } + + return res; + } + + @Override + public MddNode computeTerminal( + final MddNode mddNode, final AbstractNextStateDescriptor nextStateRelation, final MddGraph mddGraph + ) { + MddNode res = variableOrder.getMddGraph().getTerminalZeroNode(); + MddNode nextLayer = mddNode; + + while (res != nextLayer) { + nextLayer = mddGraph.unionTerminal( + res, + relProdProvider.computeTerminal(res, nextStateRelation, mddGraph) + ); + } + + return res; + } + + @Override + public void dispose() { + this.variableOrder.getMddGraph().unregisterCleanupListener(this); + } + + @Override + public void clear() { + this.cacheManager.clearAll(); + } + + @Override + public void cleanup() { + this.cacheManager.forEachCache((cache) -> cache.clearSelectively((source, ns, result) -> source.getReferenceCount() == + 0 || + result.getReferenceCount() == + 0)); + } + + public Cache getRelProdCache() { + return relProdProvider.getRelProdCache(); + } +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/CursorGeneralizedSaturationProvider.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/CursorGeneralizedSaturationProvider.java new file mode 100644 index 0000000000..faeb8e8dd4 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/CursorGeneralizedSaturationProvider.java @@ -0,0 +1,587 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.fixedpoint; + +import com.google.common.base.Preconditions; +import com.koloboke.collect.set.hash.HashObjSets; +import hu.bme.mit.delta.collections.IntObjCursor; +import hu.bme.mit.delta.collections.IntObjMapView; +import hu.bme.mit.delta.java.mdd.*; +import hu.bme.mit.delta.java.mdd.impl.MddStructuralTemplate; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor; + +import java.util.Optional; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.ToLongFunction; + +public final class CursorGeneralizedSaturationProvider implements MddTransformationProvider { + public static boolean verbose = false; + + private MddVariableOrder variableOrder; + private RelationalProductProvider relProdProvider; + private final CacheManager cacheManager = new CacheManager<>(v -> new SaturationCache()); + private MddNode terminalZeroNode; + + public CursorGeneralizedSaturationProvider(final MddVariableOrder variableOrder) { + this(variableOrder, new LegacyRelationalProductProvider(variableOrder)); + } + + public CursorGeneralizedSaturationProvider( + final MddVariableOrder variableOrder, final RelationalProductProvider relProdProvider + ) { + this.variableOrder = variableOrder; + this.relProdProvider = relProdProvider; + this.variableOrder.getMddGraph().registerCleanupListener(this); + this.terminalZeroNode = variableOrder.getMddGraph().getTerminalZeroNode(); + } + + public MddHandle compute( + AbstractNextStateDescriptor.Postcondition initializer, + AbstractNextStateDescriptor nextStateRelation, + MddVariableHandle highestAffectedVariable + ) { + final MddHandle initialStates = relProdProvider.compute(variableOrder.getMddGraph().getHandleForTop(), initializer, highestAffectedVariable); + + MddNode result; + + if (highestAffectedVariable.getVariable().isPresent()) { + final MddVariable variable = highestAffectedVariable.getVariable().get(); + result = this.compute(initialStates.getNode(), nextStateRelation, variable); + } else { + result = this.computeTerminal(initialStates.getNode(), + nextStateRelation, + highestAffectedVariable.getMddGraph() + ); + } + + return highestAffectedVariable.getHandleFor(result); + } + + private MddNode recurse( + final MddNode mddNode, + final AbstractNextStateDescriptor nextState, + MddVariable currentVariable, + final CacheManager>.CacheHolder cache + ) { + if (currentVariable.getLower().isPresent()) { + return compute(mddNode, nextState, currentVariable.getLower().get()); + } else { + return computeTerminal(mddNode, nextState, currentVariable.getMddGraph()); + } + } + + private MddNode unionChildren( + final MddNode lhs, final MddNode rhs, MddVariable currentVariable + ) { + if (currentVariable.getLower().isPresent()) { + return currentVariable.getLower().get().union(lhs, rhs); + } else { + return currentVariable.getMddGraph().unionTerminal(lhs, rhs); + } + } + + @Override + public MddNode compute( + final MddNode mddNode, final AbstractNextStateDescriptor nextState, final MddVariable mddVariable + ) { + try (var nextStateCursor = nextState.rootCursor()) { + Preconditions.checkState(nextStateCursor.moveNext()); + return saturate(mddNode, nextState, nextStateCursor, mddVariable, cacheManager.getCacheFor(mddVariable)); + } + } + + private MddNode saturate( + final MddNode n, + AbstractNextStateDescriptor d, + AbstractNextStateDescriptor.Cursor dCursor, + MddVariable variable, + CacheManager.CacheHolder cache + ) { + if (n.isTerminal() || + d == AbstractNextStateDescriptor.terminalIdentity() || + d == AbstractNextStateDescriptor.terminalEmpty()) { + // TODO this does not handle level skips + return n; + } + + MddNode ret = cache.getCache().getSaturateCache().getOrNull(n, d); + if (ret != null) { + return ret; + } + + if (verbose) { + printIndent(); + System.out.println("Saturating on level " + variable.getTraceInfo() + " with " + d); + + } + // indent++; + + final MddStateSpaceInfo stateSpaceInfo = new MddStateSpaceInfo(variable, n); + +// IntObjMapView satTemplate = new IntObjMapViews.Transforming(n, +// (node, key) -> node == null ? null : terminalZeroToNull(saturate(node, +// d.getDiagonal(stateSpaceInfo).get(key), +// variable.getLower().orElse(null), +// cache.getLower() +// )) +// ); +// +// MddNode nsat = variable.checkInNode(MddStructuralTemplate.of(satTemplate)); + + MddUnsafeTemplateBuilder templateBuilder = JavaMddFactory.getDefault().createUnsafeTemplateBuilder(); + + for (IntObjCursor cFrom = n.cursor(); cFrom.moveNext(); ) { + try (var cTo = dCursor.valueCursor(cFrom.key(), stateSpaceInfo)) { + MddNode s = saturate(cFrom.value(), + cTo.moveTo(cFrom.key()) ? cTo.value() : AbstractNextStateDescriptor.terminalEmpty(), + cTo, + variable.getLower().orElse(null), + cache.getLower() + ); + + templateBuilder.set(cFrom.key(), + terminalZeroToNull(unionChildren(templateBuilder.get(cFrom.key()), s, variable)) + ); + + } + } + + MddNode nsat = variable.checkInNode(MddStructuralTemplate.of(templateBuilder.buildAndReset())); + + boolean changed; + + do { + changed = false; + +// final Optional> splitNS = d.split(); + final Optional> splitNSCursor = dCursor.split(); + if (splitNSCursor.isPresent()) { + for (AbstractNextStateDescriptor.Cursor dfireCursor : splitNSCursor.get()) { + //System.out.println("Applying transition: " + dfire); + if (dfireCursor.value().isLocallyIdentity(stateSpaceInfo)) { + continue; + } + + MddNode nfire = satFire(nsat, d, dfireCursor.value(), dfireCursor, variable, cache); + nfire = variable.union(nsat, nfire); + + if (nfire != nsat) { + nsat = nfire; + changed = true; + } + + + } + } else if (!d.isLocallyIdentity(stateSpaceInfo)) { + //System.out.println("Applying transition: " + d); +// try(var dCursor = d.rootCursor()){ +// Preconditions.checkState(dCursor.moveNext()); + MddNode nfire = satFire(nsat, d, d, dCursor, variable, cache); + nfire = variable.union(nsat, nfire); + + if (nfire != nsat) { + nsat = nfire; + changed = true; + } +// } + + } + } while (changed); + + cache.getCache().getSaturateCache().addToCache(n, d, nsat); + + if (verbose) { + indent--; + printIndent(); + System.out.println("Done Saturating on level " + variable.getTraceInfo() + " resulting in " + nsat); + } + + // indent--; + // printIndent(); + // System.out.println("Saturated level " + variable.getTraceInfo() + ", domain size is " + variable.getDomainSize()); + // + return nsat; + } + + private MddNode satFire( + MddNode n, + AbstractNextStateDescriptor dsat, + AbstractNextStateDescriptor dfire, + AbstractNextStateDescriptor.Cursor dfireCursor, + MddVariable variable, + CacheManager.CacheHolder cache + ) { + if (n == terminalZeroNode || dfire == AbstractNextStateDescriptor.terminalEmpty()) { + return terminalZeroNode; + } + + if (dfire == AbstractNextStateDescriptor.terminalIdentity()) { + return n; + } + + if (verbose) { + printIndent(); + System.out.println("SatFire on level " + + variable.getTraceInfo() + + " with dsat=" + + dsat + + "; dfire=" + + dfire); + indent++; + } + + MddUnsafeTemplateBuilder templateBuilder = JavaMddFactory.getDefault().createUnsafeTemplateBuilder(); + + final var stateSpaceInfo = new MddStateSpaceInfo(variable, n); + + final IntObjMapView> offDiagonal = dfire.getOffDiagonal( + stateSpaceInfo); + + for (IntObjCursor cFrom = n.cursor(); cFrom.moveNext(); ) { + try (var cTo = dfireCursor.valueCursor(cFrom.key(), stateSpaceInfo)) { + while (cTo.moveNext()) { + if (cFrom.key() == cTo.key()) { + continue; + } + + if (verbose) { + System.out.println("Potential step: " + cFrom.key() + "->" + cTo.key()); + } + + assert cFrom.value() != terminalZeroNode; + assert cTo.value() != AbstractNextStateDescriptor.terminalEmpty(); + + MddNode s = relProd(cFrom.value(), + dsat.getDiagonal(stateSpaceInfo).get(cTo.key()), + cTo.value(), + cTo, + variable.getLower().orElse(null), + cache.getLower() + ); + + if (s != terminalZeroNode) { + confirm(variable, cTo.key()); + + templateBuilder.set(cTo.key(), + terminalZeroToNull(unionChildren(templateBuilder.get(cTo.key()), s, variable)) + ); + } + } + } + } + + MddNode ret = variable.checkInNode(MddStructuralTemplate.of(templateBuilder.buildAndReset())); + + if (verbose) { + indent--; + printIndent(); + System.out.println("Done SatFire on level " + variable.getTraceInfo() + " resulting in " + ret); + } + + return ret; + } + + private MddNode relProd( + MddNode n, + AbstractNextStateDescriptor dsat, + AbstractNextStateDescriptor dfire, + AbstractNextStateDescriptor.Cursor dfireCursor, + MddVariable variable, + CacheManager.CacheHolder cache + ) { + if (n == terminalZeroNode || dfire == AbstractNextStateDescriptor.terminalEmpty()) { + return terminalZeroNode; + } + + if (dfire == AbstractNextStateDescriptor.terminalIdentity()) { + return n; + } + + if (n.isTerminal() && dfire.evaluate()) { + return n; + } + + final MddStateSpaceInfo stateSpaceInfo = new MddStateSpaceInfo(variable, n); + + MddNode ret = cache.getCache().getRelProdCache().getOrNull(n, dsat, dfire); + if (ret != null) { + return ret; + } + + if (verbose) { + printIndent(); + System.out.println("SatRelProd on level " + + variable.getTraceInfo() + + ", node=" + + n + + ", with dsat=" + + dsat + + "; dfire" + + "=" + + dfire); + indent++; + } + + MddUnsafeTemplateBuilder templateBuilder = JavaMddFactory.getDefault().createUnsafeTemplateBuilder(); + + final IntObjMapView diagonal = dfire.getDiagonal(stateSpaceInfo); + final IntObjMapView> offDiagonal = dfire.getOffDiagonal( + stateSpaceInfo); + + for (IntObjCursor cFrom = n.cursor(); cFrom.moveNext(); ) { + // Identity step +// final AbstractNextStateDescriptor diagonalContinuation = diagonal.get(cFrom.key()); +// if (!AbstractNextStateDescriptor.isNullOrEmpty(diagonalContinuation)) { +// +// if (verbose) { +// System.out.println("Potential step: " + cFrom.key() + "->" + cFrom.key()); +// } +// +// MddNode s = relProd(cFrom.value(), +// dsat.getDiagonal(stateSpaceInfo).get(cFrom.key()), +// diagonalContinuation, +// variable.getLower().orElse(null), +// cache.getLower() +// ); +// +// if (s != terminalZeroNode) { +// // confirm(variable, cFrom.key()); +// +// templateBuilder.set(cFrom.key(), +// terminalZeroToNull(unionChildren(templateBuilder.get(cFrom.key()), s, variable)) +// ); +// } +// } + try (var cTo = dfireCursor.valueCursor(cFrom.key(), stateSpaceInfo)) { + if (cTo.moveTo(cFrom.key())) { + + if (verbose) { + System.out.println("Potential step: " + cFrom.key() + "->" + cFrom.key()); + } + + MddNode s = relProd(cFrom.value(), + dsat.getDiagonal(stateSpaceInfo).get(cFrom.key()), + cTo.value(), + cTo, + variable.getLower().orElse(null), + cache.getLower() + ); + + if (s != terminalZeroNode) { + // confirm(variable, cFrom.key()); + + templateBuilder.set(cFrom.key(), + terminalZeroToNull(unionChildren(templateBuilder.get(cFrom.key()), s, variable)) + ); + } + } + } + + try (var cTo = dfireCursor.valueCursor(cFrom.key(), stateSpaceInfo)) { + while (cTo.moveNext()) { + if (cFrom.key() == cTo.key()) { + continue; + } + + if (verbose) { + System.out.println("Potential step: " + cFrom.key() + "->" + cTo.key()); + } + + assert cFrom.value() != terminalZeroNode; + assert cTo.value() != AbstractNextStateDescriptor.terminalEmpty(); + + MddNode s = relProd(cFrom.value(), + dsat.getDiagonal(stateSpaceInfo).get(cTo.key()), + cTo.value(), + cTo, + variable.getLower().orElse(null), + cache.getLower() + ); + + if (s != terminalZeroNode) { + confirm(variable, cTo.key()); + + templateBuilder.set(cTo.key(), + terminalZeroToNull(unionChildren(templateBuilder.get(cTo.key()), s, variable)) + ); + } + } + } + + } + + ret = variable.checkInNode(MddStructuralTemplate.of(templateBuilder.buildAndReset())); + + try (var dsatCursor = dsat.rootCursor()) { + Preconditions.checkState(dsatCursor.moveNext()); + ret = saturate(ret, dsat, dsatCursor, variable, cache); + } + + cache.getCache().getRelProdCache().addToCache(n, dsat, dfire, ret); + + if (verbose) { + indent--; + printIndent(); + System.out.println("Done SatRelProd on level " + variable.getTraceInfo() + " resulting in " + ret); + } + + return ret; + } + + private void confirm(final MddVariable variable, final int key) { + + } + + @Override + public MddNode computeTerminal( + final MddNode mddNode, final AbstractNextStateDescriptor nextState, final MddGraph mddGraph + ) { + return mddNode; + } + + private MddNode terminalZeroToNull(MddNode node) { + return node == terminalZeroNode ? null : node; + } + + private int indent = 0; + + private void printIndent() { + for (int i = 0; i < indent; ++i) { + System.out.print(" "); + } + } + + @Override + public void dispose() { + this.variableOrder.getMddGraph().unregisterCleanupListener(this); + } + + @Override + public void clear() { + cacheManager.clearAll(); + } + + @Override + public void cleanup() { + this.cacheManager.forEachCache((cache) -> { + cache.getSaturateCache().clearSelectively((source, ns1, result) -> source.getReferenceCount() == 0 || + result.getReferenceCount() == 0); + cache.getRelProdCache().clearSelectively((source, ns1, ns2, result) -> source.getReferenceCount() == 0 || + result.getReferenceCount() == 0); + }); + } + + private class Aggregator implements Consumer { + public long result = 0; + private final ToLongFunction extractor; + + private Aggregator(final ToLongFunction extractor) { + this.extractor = extractor; + } + + @Override + public void accept(final SaturationCache cache) { + result += extractor.applyAsLong(cache); + } + } + + public Cache getSaturateCache() { + class SaturateCache implements Cache { + private final CacheManager cacheManager; + + SaturateCache(final CacheManager cacheManager) { + this.cacheManager = cacheManager; + } + + @Override + public void clear() { + cacheManager.forEachCache(cache -> cache.getSaturateCache().clear()); + } + + @Override + public long getCacheSize() { + Aggregator a = new Aggregator(c -> c.getSaturateCache().getCacheSize()); + cacheManager.forEachCache(a); + return a.result; + } + + @Override + public long getQueryCount() { + Aggregator a = new Aggregator(c -> c.getSaturateCache().getQueryCount()); + cacheManager.forEachCache(a); + return a.result; + } + + @Override + public long getHitCount() { + Aggregator a = new Aggregator(c -> c.getSaturateCache().getHitCount()); + cacheManager.forEachCache(a); + return a.result; + } + } + + return new SaturateCache(cacheManager); + } + + // TODO: HAXXXX DON'T DO THIS EVER AGAIN + public Set getSaturatedNodes() { + final Set ret = HashObjSets.newUpdatableSet(); + cacheManager.forEachCache((c) -> c.getSaturateCache().clearSelectively((source, ns, result) -> { + ret.add(result); + return false; + })); + return ret; + } + + public Cache getRelProdCache() { + class RelProdCache implements Cache { + private final CacheManager cacheManager; + + RelProdCache(final CacheManager cacheManager) { + this.cacheManager = cacheManager; + } + + @Override + public void clear() { + cacheManager.forEachCache(cache -> cache.getRelProdCache().clear()); + } + + @Override + public long getCacheSize() { + Aggregator a = new Aggregator(c -> c.getRelProdCache().getCacheSize()); + cacheManager.forEachCache(a); + return a.result; + } + + @Override + public long getQueryCount() { + Aggregator a = new Aggregator(c -> c.getRelProdCache().getQueryCount()); + cacheManager.forEachCache(a); + return a.result; + } + + @Override + public long getHitCount() { + Aggregator a = new Aggregator(c -> c.getRelProdCache().getHitCount()); + cacheManager.forEachCache(a); + return a.result; + } + } + + return new RelProdCache(cacheManager); + } +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/CursorRelationalProductProvider.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/CursorRelationalProductProvider.java new file mode 100644 index 0000000000..ce44869028 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/CursorRelationalProductProvider.java @@ -0,0 +1,218 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.fixedpoint; + +import hu.bme.mit.delta.collections.IntObjCursor; +import hu.bme.mit.delta.collections.IntObjMapView; +import hu.bme.mit.delta.collections.impl.IntObjMapViews; +import hu.bme.mit.delta.java.mdd.*; +import hu.bme.mit.delta.java.mdd.impl.MddStructuralTemplate; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor; + +import java.util.function.Consumer; +import java.util.function.ToLongFunction; + +public final class CursorRelationalProductProvider implements RelationalProductProvider { + private final CacheManager> cacheManager = new CacheManager<>(v -> new BinaryOperationCache<>()); + private final MddVariableOrder variableOrder; + + public CursorRelationalProductProvider(final MddVariableOrder variableOrder) { + this.variableOrder = variableOrder; + this.variableOrder.getMddGraph().registerCleanupListener(this); + } + + private MddNode recurse(final MddNode mddNode, final AbstractNextStateDescriptor nextState, final AbstractNextStateDescriptor.Cursor nextStateCursor, MddVariable currentVariable, final CacheManager>.CacheHolder currentCache) { + if (currentVariable.getLower().isPresent()) { + return doCompute(mddNode, nextState, nextStateCursor, currentVariable.getLower().get(), currentCache.getLower()); + } else { + return computeTerminal(mddNode, nextState, currentVariable.getMddGraph()); + } + } + + private MddNode unionChildren(final MddNode lhs, final MddNode rhs, MddVariable currentVariable) { + if (currentVariable.getLower().isPresent()) { + return currentVariable.getLower().get().union(lhs, rhs); + } else { + return currentVariable.getMddGraph().unionTerminal(lhs, rhs); + } + } + + @Override + public MddNode compute(final MddNode mddNode, final AbstractNextStateDescriptor abstractNextStateDescriptor, final MddVariable mddVariable) { + return doCompute(mddNode, abstractNextStateDescriptor, abstractNextStateDescriptor.rootCursor(), mddVariable, cacheManager.getCacheFor(mddVariable)); + } + + private MddNode doCompute(final MddNode lhs, final AbstractNextStateDescriptor nextState, final AbstractNextStateDescriptor.Cursor nextStateCursor, final MddVariable variable, final CacheManager>.CacheHolder cache) { + assert cache != null : "Invalid behavior for CacheManager: should have assigned a cache to every variable."; + if (variable.isNullOrZero(lhs) || nextState == AbstractNextStateDescriptor.terminalIdentity()) { + return lhs; + } + if (nextState == null || nextState == AbstractNextStateDescriptor.terminalEmpty()) { + return variable.getMddGraph().getTerminalZeroNode(); + } + + boolean lhsSkipped = !lhs.isOn(variable); + + if ((lhsSkipped || !variable.isNullOrZero(lhs.defaultValue())) && !(lhs.isTerminal() && nextState instanceof AbstractNextStateDescriptor.Postcondition)) { + throw new UnsupportedOperationException("Default values are not yet supported in relational product."); + } + + MddNode ret = cache.getCache().getOrNull(lhs, nextState); + if (ret != null) { + return ret; + } + + final MddStateSpaceInfo stateSpaceInfo = new MddStateSpaceInfo(variable, lhs); + + final IntObjMapView diagonal = nextState.getDiagonal(stateSpaceInfo); + final IntObjMapView> offDiagonal = nextState.getOffDiagonal(stateSpaceInfo); + + IntObjMapView template; + + // Patch to enable initializers + if (lhs.isTerminal() && nextState instanceof AbstractNextStateDescriptor.Postcondition) { + template = new IntObjMapViews.Transforming(nextState.getDiagonal(stateSpaceInfo), ns -> ns == null ? null : terminalZeroToNull(recurse(lhs, ns, nextStateCursor, variable, cache), variable.getMddGraph().getTerminalZeroNode())); + // } else if (diagonal.isEmpty() && offDiagonal.isEmpty() && AbstractNextStateDescriptor.isNullOrEmpty( + // offDiagonal.defaultValue())) { + // // Either the ANSD does not affect this level or it is not fireable - will be evaluated in the next call + // // TODO: THIS IS GONNA BE TERRIBLY SLOW + // template = new IntObjMapViews.Transforming(lhs, + // (child) -> child == null ? null : terminalZeroToNull( + // recurse(child, diagonal.defaultValue(), variable, cache), + // variable.getMddGraph().getTerminalZeroNode() + // )); + } else { + MddUnsafeTemplateBuilder templateBuilder = JavaMddFactory.getDefault().createUnsafeTemplateBuilder(); + for (IntObjCursor c = lhs.cursor(); c.moveNext(); ) { + // TODO we might not need this +// try(var valueCursor = nextStateCursor.valueCursor(c.key())) { +// valueCursor.moveTo(c.key()); +// final MddNode res = recurse(c.value(), diagonal.get(c.key()), valueCursor, variable, cache); +// final MddNode unioned = unionChildren(res, templateBuilder.get(c.key()), variable); +// +// templateBuilder.set(c.key(), terminalZeroToNull(unioned, variable.getMddGraph().getTerminalZeroNode())); +// } + try (var valueCursor = nextStateCursor.valueCursor(c.key(), stateSpaceInfo)) { +// for (IntObjCursor next = offDiagonal.get(c.key()).cursor(); next.moveNext(); ) { + for (; valueCursor.moveNext(); ) { + + final MddNode res1 = recurse(c.value(), valueCursor.value(), valueCursor, variable, cache); + final MddNode unioned1 = unionChildren(res1, templateBuilder.get(valueCursor.key()), variable); + + templateBuilder.set(valueCursor.key(), terminalZeroToNull(unioned1, variable.getMddGraph().getTerminalZeroNode())); + } + } + + +// for (IntObjCursor next = offDiagonal.get(c.key()).cursor(); +// next.moveNext(); ) { +// final MddNode res1 = recurse(c.value(), next.value(), variable, cache); +// final MddNode unioned1 = unionChildren(res1, templateBuilder.get(next.key()), variable); +// +// templateBuilder.set(next.key(), +// terminalZeroToNull(unioned1, variable.getMddGraph().getTerminalZeroNode()) +// ); +// } + } + template = templateBuilder.buildAndReset(); + } + + ret = variable.checkInNode(MddStructuralTemplate.of(template)); + + cache.getCache().addToCache(lhs, nextState, ret); + + return ret; + } + + @Override + public MddNode computeTerminal(final MddNode mddNode, final AbstractNextStateDescriptor abstractNextStateDescriptor, final MddGraph mddGraph) { + if (mddNode == mddGraph.getTerminalZeroNode() || !abstractNextStateDescriptor.evaluate()) { + return mddGraph.getTerminalZeroNode(); + } + return mddNode; + } + + private MddNode terminalZeroToNull(MddNode node, MddNode terminalZero) { + return node == terminalZero ? null : node; + } + + @Override + public void dispose() { + this.variableOrder.getMddGraph().unregisterCleanupListener(this); + } + + @Override + public void clear() { + this.cacheManager.clearAll(); + } + + @Override + public void cleanup() { + this.cacheManager.forEachCache((cache) -> cache.clearSelectively((source, ns, result) -> source.getReferenceCount() == 0 || result.getReferenceCount() == 0)); + } + + private class Aggregator implements Consumer> { + public long result = 0; + private final ToLongFunction> extractor; + + private Aggregator(final ToLongFunction> extractor) { + this.extractor = extractor; + } + + @Override + public void accept(final BinaryOperationCache cache) { + result += extractor.applyAsLong(cache); + } + } + + public Cache getRelProdCache() { + class RelProdCache implements Cache { + private final CacheManager> cacheManager; + + RelProdCache(final CacheManager> cacheManager) { + this.cacheManager = cacheManager; + } + + @Override + public void clear() { + cacheManager.forEachCache(cache -> cache.clear()); + } + + @Override + public long getCacheSize() { + Aggregator a = new Aggregator(c -> c.getCacheSize()); + cacheManager.forEachCache(a); + return a.result; + } + + @Override + public long getQueryCount() { + Aggregator a = new Aggregator(c -> c.getQueryCount()); + cacheManager.forEachCache(a); + return a.result; + } + + @Override + public long getHitCount() { + Aggregator a = new Aggregator(c -> c.getHitCount()); + cacheManager.forEachCache(a); + return a.result; + } + } + + return new RelProdCache(cacheManager); + } +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/GeneralizedSaturationProvider.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/GeneralizedSaturationProvider.java new file mode 100644 index 0000000000..69e650188e --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/GeneralizedSaturationProvider.java @@ -0,0 +1,544 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.fixedpoint; + +import com.koloboke.collect.set.hash.HashObjSets; +import hu.bme.mit.delta.collections.IntObjCursor; +import hu.bme.mit.delta.collections.IntObjMapView; +import hu.bme.mit.delta.java.mdd.*; +import hu.bme.mit.delta.java.mdd.impl.MddStructuralTemplate; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor; + +import java.util.Optional; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.ToLongFunction; + +public final class GeneralizedSaturationProvider implements MddTransformationProvider { + public static boolean verbose = false; + + private MddVariableOrder variableOrder; + private RelationalProductProvider relProdProvider; + private final CacheManager cacheManager = new CacheManager<>(v -> new SaturationCache()); + private MddNode terminalZeroNode; + + public GeneralizedSaturationProvider(final MddVariableOrder variableOrder) { + this(variableOrder, new LegacyRelationalProductProvider(variableOrder)); + } + + public GeneralizedSaturationProvider( + final MddVariableOrder variableOrder, final RelationalProductProvider relProdProvider + ) { + this.variableOrder = variableOrder; + this.relProdProvider = relProdProvider; + this.variableOrder.getMddGraph().registerCleanupListener(this); + this.terminalZeroNode = variableOrder.getMddGraph().getTerminalZeroNode(); + } + + public MddHandle compute( + AbstractNextStateDescriptor.Postcondition initializer, + AbstractNextStateDescriptor nextStateRelation, + MddVariableHandle highestAffectedVariable + ) { + final MddHandle initialStates = relProdProvider.compute(variableOrder.getMddGraph().getHandleForTop(), initializer, highestAffectedVariable); + + MddNode result; + + if (highestAffectedVariable.getVariable().isPresent()) { + final MddVariable variable = highestAffectedVariable.getVariable().get(); + result = this.compute(initialStates.getNode(), nextStateRelation, variable); + } else { + result = this.computeTerminal(initialStates.getNode(), + nextStateRelation, + highestAffectedVariable.getMddGraph() + ); + } + + return highestAffectedVariable.getHandleFor(result); + } + + private MddNode recurse( + final MddNode mddNode, + final AbstractNextStateDescriptor nextState, + MddVariable currentVariable, + final CacheManager>.CacheHolder cache + ) { + if (currentVariable.getLower().isPresent()) { + return compute(mddNode, nextState, currentVariable.getLower().get()); + } else { + return computeTerminal(mddNode, nextState, currentVariable.getMddGraph()); + } + } + + private MddNode unionChildren( + final MddNode lhs, final MddNode rhs, MddVariable currentVariable + ) { + if (currentVariable.getLower().isPresent()) { + return currentVariable.getLower().get().union(lhs, rhs); + } else { + return currentVariable.getMddGraph().unionTerminal(lhs, rhs); + } + } + + @Override + public MddNode compute( + final MddNode mddNode, final AbstractNextStateDescriptor nextState, final MddVariable mddVariable + ) { + return saturate(mddNode, nextState, mddVariable, cacheManager.getCacheFor(mddVariable)); + } + + private MddNode saturate( + final MddNode n, + AbstractNextStateDescriptor d, + MddVariable variable, + CacheManager.CacheHolder cache + ) { + if (n.isTerminal() || + d == AbstractNextStateDescriptor.terminalIdentity() || + d == AbstractNextStateDescriptor.terminalEmpty()) { + // TODO this does not handle level skips + return n; + } + + MddNode ret = cache.getCache().getSaturateCache().getOrNull(n, d); + if (ret != null) { + return ret; + } + + if (verbose) { + printIndent(); + System.out.println("Saturating on level " + variable.getTraceInfo() + " with " + d); + + } + // indent++; + + final MddStateSpaceInfo stateSpaceInfo = new MddStateSpaceInfo(variable, n); + +// +// IntObjMapView satTemplate = new IntObjMapViews.Transforming(n, +// (node, key) -> node == null ? null : terminalZeroToNull(saturate(node, +// d.getDiagonal(stateSpaceInfo).get(key), +// variable.getLower().orElse(null), +// cache.getLower() +// )) +// ); +// +// MddNode nsat = variable.checkInNode(MddStructuralTemplate.of(satTemplate)); + + + MddUnsafeTemplateBuilder templateBuilder = JavaMddFactory.getDefault().createUnsafeTemplateBuilder(); + + for (IntObjCursor cFrom = n.cursor(); cFrom.moveNext(); ) { + + MddNode s = saturate(cFrom.value(), + d.getDiagonal(stateSpaceInfo).get(cFrom.key()), + variable.getLower().orElse(null), + cache.getLower() + ); + + templateBuilder.set(cFrom.key(), + terminalZeroToNull(unionChildren(templateBuilder.get(cFrom.key()), s, variable)) + ); + + } + + MddNode nsat = variable.checkInNode(MddStructuralTemplate.of(templateBuilder.buildAndReset())); + + boolean changed; + + do { + changed = false; + + final Optional> splitNS = d.split(); + if (splitNS.isPresent()) { + for (AbstractNextStateDescriptor dfire : splitNS.get()) { + //System.out.println("Applying transition: " + dfire); + if (dfire.isLocallyIdentity(stateSpaceInfo)) { + continue; + } + MddNode nfire = satFire(nsat, d, dfire, variable, cache); + nfire = variable.union(nsat, nfire); + + if (nfire != nsat) { + nsat = nfire; + changed = true; + } + } + } else if (!d.isLocallyIdentity(stateSpaceInfo)) { + //System.out.println("Applying transition: " + d); + MddNode nfire = satFire(nsat, d, d, variable, cache); + nfire = variable.union(nsat, nfire); + + if (nfire != nsat) { + nsat = nfire; + changed = true; + } + } + } while (changed); + + cache.getCache().getSaturateCache().addToCache(n, d, nsat); + + if (verbose) { + indent--; + printIndent(); + System.out.println("Done Saturating on level " + variable.getTraceInfo() + " resulting in " + nsat); + } + + // indent--; + // printIndent(); + // System.out.println("Saturated level " + variable.getTraceInfo() + ", domain size is " + variable.getDomainSize()); + // + return nsat; + } + + private MddNode satFire( + MddNode n, + AbstractNextStateDescriptor dsat, + AbstractNextStateDescriptor dfire, + MddVariable variable, + CacheManager.CacheHolder cache + ) { + if (n == terminalZeroNode || dfire == AbstractNextStateDescriptor.terminalEmpty()) { + return terminalZeroNode; + } + + if (dfire == AbstractNextStateDescriptor.terminalIdentity()) { + return n; + } + + if (verbose) { + printIndent(); + System.out.println("SatFire on level " + + variable.getTraceInfo() + + " with dsat=" + + dsat + + "; dfire=" + + dfire); + indent++; + } + + MddUnsafeTemplateBuilder templateBuilder = JavaMddFactory.getDefault().createUnsafeTemplateBuilder(); + +// final IntObjMapView diagonal = dfire.getDiagonal( +// stateSpaceInfo); +// var c = diagonal.cursor(); + + final var stateSpaceInfo = new MddStateSpaceInfo(variable, n); + + final IntObjMapView> offDiagonal = dfire.getOffDiagonal( + stateSpaceInfo); + + for (IntObjCursor cFrom = n.cursor(); cFrom.moveNext(); ) { + for (IntObjCursor cTo = offDiagonal.get( + cFrom.key()).cursor(); cTo.moveNext(); ) { + if (cFrom.key() == cTo.key()) { + continue; + } + + if (verbose) { + System.out.println("Potential step: " + cFrom.key() + "->" + cTo.key()); + } + + assert cFrom.value() != terminalZeroNode; + assert cTo.value() != AbstractNextStateDescriptor.terminalEmpty(); + + MddNode s = relProd(cFrom.value(), + dsat.getDiagonal(stateSpaceInfo).get(cTo.key()), + cTo.value(), + variable.getLower().orElse(null), + cache.getLower() + ); + + if (s != terminalZeroNode) { + confirm(variable, cTo.key()); + + templateBuilder.set(cTo.key(), + terminalZeroToNull(unionChildren(templateBuilder.get(cTo.key()), s, variable)) + ); + } + } + } + + MddNode ret = variable.checkInNode(MddStructuralTemplate.of(templateBuilder.buildAndReset())); + + if (verbose) { + indent--; + printIndent(); + System.out.println("Done SatFire on level " + variable.getTraceInfo() + " resulting in " + ret); + } + + return ret; + } + + private MddNode relProd( + MddNode n, + AbstractNextStateDescriptor dsat, + AbstractNextStateDescriptor dfire, + MddVariable variable, + CacheManager.CacheHolder cache + ) { + if (n == terminalZeroNode || dfire == AbstractNextStateDescriptor.terminalEmpty()) { + return terminalZeroNode; + } + + if (dfire == AbstractNextStateDescriptor.terminalIdentity()) { + return n; + } + + if (n.isTerminal() && dfire.evaluate()) { + return n; + } + + final MddStateSpaceInfo stateSpaceInfo = new MddStateSpaceInfo(variable, n); + + MddNode ret = cache.getCache().getRelProdCache().getOrNull(n, dsat, dfire); + if (ret != null) { + return ret; + } + + if (verbose) { + printIndent(); + System.out.println("SatRelProd on level " + + variable.getTraceInfo() + + ", node=" + + n + + ", with dsat=" + + dsat + + "; dfire" + + "=" + + dfire); + indent++; + } + + MddUnsafeTemplateBuilder templateBuilder = JavaMddFactory.getDefault().createUnsafeTemplateBuilder(); + + final IntObjMapView diagonal = dfire.getDiagonal(stateSpaceInfo); + final IntObjMapView> offDiagonal = dfire.getOffDiagonal( + stateSpaceInfo); + + for (IntObjCursor cFrom = n.cursor(); cFrom.moveNext(); ) { + // Identity step + final AbstractNextStateDescriptor diagonalContinuation = diagonal.get(cFrom.key()); + if (!AbstractNextStateDescriptor.isNullOrEmpty(diagonalContinuation)) { + + if (verbose) { + System.out.println("Potential step: " + cFrom.key() + "->" + cFrom.key()); + } + + MddNode s = relProd(cFrom.value(), + dsat.getDiagonal(stateSpaceInfo).get(cFrom.key()), + diagonalContinuation, + variable.getLower().orElse(null), + cache.getLower() + ); + + if (s != terminalZeroNode) { + // confirm(variable, cFrom.key()); + + templateBuilder.set(cFrom.key(), + terminalZeroToNull(unionChildren(templateBuilder.get(cFrom.key()), s, variable)) + ); + } + } + + for (IntObjCursor cTo = offDiagonal.get(cFrom.key()).cursor(); + cTo.moveNext(); ) { + if (cFrom.key() == cTo.key()) { + continue; + } + + if (verbose) { + System.out.println("Potential step: " + cFrom.key() + "->" + cTo.key()); + } + + assert cFrom.value() != terminalZeroNode; + assert cTo.value() != AbstractNextStateDescriptor.terminalEmpty(); + + MddNode s = relProd(cFrom.value(), + dsat.getDiagonal(stateSpaceInfo).get(cTo.key()), + cTo.value(), + variable.getLower().orElse(null), + cache.getLower() + ); + + if (s != terminalZeroNode) { + confirm(variable, cTo.key()); + + templateBuilder.set(cTo.key(), + terminalZeroToNull(unionChildren(templateBuilder.get(cTo.key()), s, variable)) + ); + } + } + } + + ret = variable.checkInNode(MddStructuralTemplate.of(templateBuilder.buildAndReset())); + + ret = saturate(ret, dsat, variable, cache); + + cache.getCache().getRelProdCache().addToCache(n, dsat, dfire, ret); + + if (verbose) { + indent--; + printIndent(); + System.out.println("Done SatRelProd on level " + variable.getTraceInfo() + " resulting in " + ret); + } + + return ret; + } + + private void confirm(final MddVariable variable, final int key) { + + } + + @Override + public MddNode computeTerminal( + final MddNode mddNode, final AbstractNextStateDescriptor nextState, final MddGraph mddGraph + ) { + return mddNode; + } + + private MddNode terminalZeroToNull(MddNode node) { + return node == terminalZeroNode ? null : node; + } + + private int indent = 0; + + private void printIndent() { + for (int i = 0; i < indent; ++i) { + System.out.print(" "); + } + } + + @Override + public void dispose() { + this.variableOrder.getMddGraph().unregisterCleanupListener(this); + } + + @Override + public void clear() { + cacheManager.clearAll(); + } + + @Override + public void cleanup() { + this.cacheManager.forEachCache((cache) -> { + cache.getSaturateCache().clearSelectively((source, ns1, result) -> source.getReferenceCount() == 0 || + result.getReferenceCount() == 0); + cache.getRelProdCache().clearSelectively((source, ns1, ns2, result) -> source.getReferenceCount() == 0 || + result.getReferenceCount() == 0); + }); + } + + private class Aggregator implements Consumer { + public long result = 0; + private final ToLongFunction extractor; + + private Aggregator(final ToLongFunction extractor) { + this.extractor = extractor; + } + + @Override + public void accept(final SaturationCache cache) { + result += extractor.applyAsLong(cache); + } + } + + public Cache getSaturateCache() { + class SaturateCache implements Cache { + private final CacheManager cacheManager; + + SaturateCache(final CacheManager cacheManager) { + this.cacheManager = cacheManager; + } + + @Override + public void clear() { + cacheManager.forEachCache(cache -> cache.getSaturateCache().clear()); + } + + @Override + public long getCacheSize() { + Aggregator a = new Aggregator(c -> c.getSaturateCache().getCacheSize()); + cacheManager.forEachCache(a); + return a.result; + } + + @Override + public long getQueryCount() { + Aggregator a = new Aggregator(c -> c.getSaturateCache().getQueryCount()); + cacheManager.forEachCache(a); + return a.result; + } + + @Override + public long getHitCount() { + Aggregator a = new Aggregator(c -> c.getSaturateCache().getHitCount()); + cacheManager.forEachCache(a); + return a.result; + } + } + + return new SaturateCache(cacheManager); + } + + // TODO: HAXXXX DON'T DO THIS EVER AGAIN + public Set getSaturatedNodes() { + final Set ret = HashObjSets.newUpdatableSet(); + cacheManager.forEachCache((c) -> c.getSaturateCache().clearSelectively((source, ns, result) -> { + ret.add(result); + return false; + })); + return ret; + } + + public Cache getRelProdCache() { + class RelProdCache implements Cache { + private final CacheManager cacheManager; + + RelProdCache(final CacheManager cacheManager) { + this.cacheManager = cacheManager; + } + + @Override + public void clear() { + cacheManager.forEachCache(cache -> cache.getRelProdCache().clear()); + } + + @Override + public long getCacheSize() { + Aggregator a = new Aggregator(c -> c.getRelProdCache().getCacheSize()); + cacheManager.forEachCache(a); + return a.result; + } + + @Override + public long getQueryCount() { + Aggregator a = new Aggregator(c -> c.getRelProdCache().getQueryCount()); + cacheManager.forEachCache(a); + return a.result; + } + + @Override + public long getHitCount() { + Aggregator a = new Aggregator(c -> c.getRelProdCache().getHitCount()); + cacheManager.forEachCache(a); + return a.result; + } + } + + return new RelProdCache(cacheManager); + } +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/LegacyRelationalProductProvider.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/LegacyRelationalProductProvider.java new file mode 100644 index 0000000000..807360e81b --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/LegacyRelationalProductProvider.java @@ -0,0 +1,227 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.fixedpoint; + +import hu.bme.mit.delta.collections.IntObjCursor; +import hu.bme.mit.delta.collections.IntObjMapView; +import hu.bme.mit.delta.collections.impl.IntObjMapViews; +import hu.bme.mit.delta.java.mdd.*; +import hu.bme.mit.delta.java.mdd.impl.MddStructuralTemplate; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor; + +import java.util.function.Consumer; +import java.util.function.ToLongFunction; + +public final class LegacyRelationalProductProvider implements RelationalProductProvider { + private final CacheManager> cacheManager = new CacheManager<>( + v -> new BinaryOperationCache<>()); + private final MddVariableOrder variableOrder; + + public LegacyRelationalProductProvider(final MddVariableOrder variableOrder) { + this.variableOrder = variableOrder; + this.variableOrder.getMddGraph().registerCleanupListener(this); + } + + private MddNode recurse(final MddNode mddNode, final AbstractNextStateDescriptor nextState, + MddVariable currentVariable, final CacheManager>.CacheHolder currentCache) { + if (currentVariable.getLower().isPresent()) { + return doCompute(mddNode, nextState, currentVariable.getLower().get(), currentCache.getLower()); + } else { + return computeTerminal(mddNode, nextState, currentVariable.getMddGraph()); + } + } + + private MddNode unionChildren(final MddNode lhs, final MddNode rhs, + MddVariable currentVariable) { + if (currentVariable.getLower().isPresent()) { + return currentVariable.getLower().get().union(lhs, rhs); + } else { + return currentVariable.getMddGraph().unionTerminal(lhs, rhs); + } + } + + @Override + public MddNode compute( + final MddNode mddNode, + final AbstractNextStateDescriptor abstractNextStateDescriptor, + final MddVariable mddVariable + ) { + return doCompute(mddNode, abstractNextStateDescriptor, mddVariable, cacheManager.getCacheFor(mddVariable)); + } + + private MddNode doCompute( + final MddNode lhs, + final AbstractNextStateDescriptor nextState, + final MddVariable variable, + final CacheManager>.CacheHolder cache + ) { + assert cache != null : "Invalid behavior for CacheManager: should have assigned a cache to every variable."; + if (variable.isNullOrZero(lhs) || nextState == AbstractNextStateDescriptor.terminalIdentity()) { + return lhs; + } + if (nextState == null || nextState == AbstractNextStateDescriptor.terminalEmpty()) { + return variable.getMddGraph().getTerminalZeroNode(); + } + + boolean lhsSkipped = !lhs.isOn(variable); + + if ((lhsSkipped || !variable.isNullOrZero(lhs.defaultValue())) && + !(lhs.isTerminal() && nextState instanceof AbstractNextStateDescriptor.Postcondition)) { + throw new UnsupportedOperationException("Default values are not yet supported in relational product."); + } + + MddNode ret = cache.getCache().getOrNull(lhs, nextState); + if (ret != null) { + return ret; + } + + final MddStateSpaceInfo stateSpaceInfo = new MddStateSpaceInfo(variable, lhs); + + final IntObjMapView diagonal = nextState.getDiagonal(stateSpaceInfo); + final IntObjMapView> offDiagonal = nextState.getOffDiagonal( + stateSpaceInfo); + + IntObjMapView template; + + // Patch to enable initializers + if (lhs.isTerminal() && nextState instanceof AbstractNextStateDescriptor.Postcondition) { + template = new IntObjMapViews.Transforming(nextState.getDiagonal( + stateSpaceInfo), ns -> ns == null ? null : terminalZeroToNull(recurse(lhs, ns, variable, cache), + variable.getMddGraph().getTerminalZeroNode())); + // } else if (diagonal.isEmpty() && offDiagonal.isEmpty() && AbstractNextStateDescriptor.isNullOrEmpty( + // offDiagonal.defaultValue())) { + // // Either the ANSD does not affect this level or it is not fireable - will be evaluated in the next call + // // TODO: THIS IS GONNA BE TERRIBLY SLOW + // template = new IntObjMapViews.Transforming(lhs, + // (child) -> child == null ? null : terminalZeroToNull( + // recurse(child, diagonal.defaultValue(), variable, cache), + // variable.getMddGraph().getTerminalZeroNode() + // )); + } else { + MddUnsafeTemplateBuilder templateBuilder = JavaMddFactory.getDefault().createUnsafeTemplateBuilder(); + for (IntObjCursor c = lhs.cursor(); c.moveNext(); ) { + final MddNode res = recurse(c.value(), diagonal.get(c.key()), variable, cache); + final MddNode unioned = unionChildren(res, templateBuilder.get(c.key()), variable); + + templateBuilder.set(c.key(), + terminalZeroToNull(unioned, variable.getMddGraph().getTerminalZeroNode()) + ); + + for (IntObjCursor next = offDiagonal.get(c.key()).cursor(); + next.moveNext(); ) { + final MddNode res1 = recurse(c.value(), next.value(), variable, cache); + final MddNode unioned1 = unionChildren(res1, templateBuilder.get(next.key()), variable); + + templateBuilder.set(next.key(), + terminalZeroToNull(unioned1, variable.getMddGraph().getTerminalZeroNode()) + ); + } + } + template = templateBuilder.buildAndReset(); + } + + ret = variable.checkInNode(MddStructuralTemplate.of(template)); + + cache.getCache().addToCache(lhs, nextState, ret); + + return ret; + } + + @Override + public MddNode computeTerminal( + final MddNode mddNode, final AbstractNextStateDescriptor abstractNextStateDescriptor, final MddGraph mddGraph + ) { + if (mddNode == mddGraph.getTerminalZeroNode() || !abstractNextStateDescriptor.evaluate()) { + return mddGraph.getTerminalZeroNode(); + } + return mddNode; + } + + private MddNode terminalZeroToNull(MddNode node, MddNode terminalZero) { + return node == terminalZero ? null : node; + } + + @Override + public void dispose() { + this.variableOrder.getMddGraph().unregisterCleanupListener(this); + } + + @Override + public void clear() { + this.cacheManager.clearAll(); + } + + @Override + public void cleanup() { + this.cacheManager.forEachCache((cache) -> cache.clearSelectively((source, ns, result) -> source.getReferenceCount() == + 0 || + result.getReferenceCount() == + 0)); + } + + private class Aggregator implements Consumer> { + public long result = 0; + private final ToLongFunction> extractor; + + private Aggregator(final ToLongFunction> extractor) { + this.extractor = extractor; + } + + @Override + public void accept(final BinaryOperationCache cache) { + result += extractor.applyAsLong(cache); + } + } + + public Cache getRelProdCache() { + class RelProdCache implements Cache { + private final CacheManager> cacheManager; + + RelProdCache(final CacheManager> cacheManager) { + this.cacheManager = cacheManager; + } + + @Override + public void clear() { + cacheManager.forEachCache(cache -> cache.clear()); + } + + @Override + public long getCacheSize() { + Aggregator a = new Aggregator(c -> c.getCacheSize()); + cacheManager.forEachCache(a); + return a.result; + } + + @Override + public long getQueryCount() { + Aggregator a = new Aggregator(c -> c.getQueryCount()); + cacheManager.forEachCache(a); + return a.result; + } + + @Override + public long getHitCount() { + Aggregator a = new Aggregator(c -> c.getHitCount()); + cacheManager.forEachCache(a); + return a.result; + } + } + + return new RelProdCache(cacheManager); + } +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/MddStateSpaceInfo.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/MddStateSpaceInfo.java new file mode 100644 index 0000000000..c41c4d5d47 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/MddStateSpaceInfo.java @@ -0,0 +1,216 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.fixedpoint; + +import com.google.common.base.Preconditions; +import com.koloboke.collect.map.ObjIntMap; +import com.koloboke.collect.map.hash.HashObjIntMaps; +import com.koloboke.collect.set.ObjSet; +import com.koloboke.collect.set.hash.HashObjSets; +import hu.bme.mit.delta.collections.IntObjMapView; +import hu.bme.mit.delta.collections.IntSetView; +import hu.bme.mit.delta.collections.IntStatistics; +import hu.bme.mit.delta.collections.impl.IntObjMapViews; +import hu.bme.mit.delta.java.mdd.MddGraph; +import hu.bme.mit.delta.java.mdd.MddNode; +import hu.bme.mit.delta.java.mdd.MddVariable; +import hu.bme.mit.delta.java.mdd.impl.MddStructuralTemplate; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.StateSpaceInfo; +import hu.bme.mit.theta.common.container.Containers; +import hu.bme.mit.delta.Pair; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.booltype.BoolType; + +import java.util.Objects; +import java.util.Optional; + +import java.util.Set; + +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.True; + +public final class MddStateSpaceInfo implements StateSpaceInfo { + private final MddVariable variable; + private final MddNode mddNode; + + private MddNode structuralRepresentation = null; + + public MddStateSpaceInfo(final MddVariable variable, final MddNode mddNode) { + this.variable = variable; + this.mddNode = mddNode; + + for (var c = mddNode.cursor(); c.moveNext(); ) { + } // TODO delete later + } + + @Override + public Object getTraceInfo() { + return variable.getTraceInfo(); + } + + // @Override + // public ElementChain getComponentChain() { + // class TraceInfoChain implements ElementChain { + // private final MddVariableHandle mddVariableHandle; + // + // TraceInfoChain(MddVariableHandle mddVariableHandle) { + // Preconditions.checkArgument(mddVariableHandle.getVariable().isPresent()); + // this.mddVariableHandle = mddVariableHandle; + // } + // + // @Override + // public Object getElement() { + // return mddVariableHandle.getVariable().orElseThrow(AssertionError::new).getTraceInfo(); + // } + // + // @Override + // public ElementChain next() { + // if (mddVariableHandle.getLower().isPresent()) { + // return new TraceInfoChain(mddVariableHandle.getLower().orElseThrow(AssertionError::new)); + // } else { + // return null; + // } + // } + // } + // + // return new TraceInfoChain(variableHandle); + // } + + // TODO: else nodes are problematic, better not use them for now + @Override + public boolean hasInfiniteStates() { + if (mddNode.isTerminal()) { + return true; + } else if (mddNode.isBelow(variable)) { + return true; + } else { + return !variable.isNullOrZero(mddNode.defaultValue()); + } + } + + @Override + public IntSetView getLocalStateSpace() { + return mddNode.keySet(); + } + + @Override + public StateSpaceInfo getLocalStateSpace(final Object someLowerComponent) { + // TODO: Auto-generated method stub. + throw new UnsupportedOperationException("Not (yet) implemented."); + //return null; + } + + @Override + public MddNode toStructuralRepresentation() { + if (structuralRepresentation == null) { + final BoundsCollector boundsCollector = new BoundsCollector(mddNode, variable); + structuralRepresentation = representBounds(variable, boundsCollector); + } + return structuralRepresentation; + + } + + private MddNode representBounds(MddVariable variable, BoundsCollector boundsCollector) { + final MddNode continuation; + if (variable.getLower().isPresent()) { + continuation = representBounds(variable.getLower().get(), boundsCollector); + } else { + final MddGraph> mddGraph = (MddGraph>) variable.getMddGraph(); + continuation = mddGraph.getNodeFor(True()); + } + final var bounds = boundsCollector.getBoundsFor(variable); + final IntObjMapView template; + if (bounds.isPresent()) { + if (Objects.equals(bounds.get().first, bounds.get().second)) { + template = IntObjMapView.singleton(bounds.get().first, continuation); + } else { + // TODO: canonization of trimmed intobjmapviews could be improved + template = new IntObjMapViews.Trimmed<>( + IntObjMapView.empty(continuation), + IntSetView.range(bounds.get().first, bounds.get().second + 1) + ); + } + } else { + template = IntObjMapView.empty(continuation); + } + + return variable.checkInNode(MddStructuralTemplate.of(template)); + + } +// private MddNode collapseEdges(MddNode parent) { +// +// IntSetView setView = IntSetView.empty(); +// for (var c = parent.cursor(); c.moveNext(); ) { +// setView = setView.union(c.value().keySet()); +// } +// +// } + + private class BoundsCollector { + + private final ObjIntMap lowerBounds; + private final ObjIntMap upperBounds; + private final ObjSet hasDefaultValue; + + public BoundsCollector(MddNode rootNode, MddVariable variable) { + Preconditions.checkNotNull(rootNode); + this.lowerBounds = HashObjIntMaps.newUpdatableMap(); + this.upperBounds = HashObjIntMaps.newUpdatableMap(); + this.hasDefaultValue = HashObjSets.newUpdatableSet(); + + final Set traversed = Containers.createSet(); + traverse(rootNode, variable, traversed); + } + + private void traverse(final MddNode node, final MddVariable variable, + final Set traversed) { + if (traversed.contains(node) || node.isTerminal()) { + return; + } else { + traversed.add(node); + } + + for (var c = node.cursor(); c.moveNext(); ) { + } // TODO delete later + + if (node.defaultValue() != null) { + final MddNode defaultValue = node.defaultValue(); + traverse(defaultValue, variable.getLower().orElse(null), traversed); + hasDefaultValue.add(variable); + } else { + final IntStatistics statistics = node.statistics(); + if (variable != null) { + lowerBounds.put(variable, Math.min(lowerBounds.getOrDefault(variable, Integer.MAX_VALUE), statistics.lowestValue())); + upperBounds.put(variable, Math.max(upperBounds.getOrDefault(variable, Integer.MIN_VALUE), statistics.highestValue())); + } + + for (var cur = node.cursor(); cur.moveNext(); ) { + if (cur.value() != null) { + traverse(cur.value(), variable.getLower().orElse(null), traversed); + } + } + } + } + + + public Optional> getBoundsFor(MddVariable variable) { + if (hasDefaultValue.contains(variable)) return Optional.empty(); + if (!lowerBounds.containsKey(variable) || !upperBounds.containsKey(variable)) + return Optional.empty(); + return Optional.of(new Pair<>(lowerBounds.getInt(variable), upperBounds.getInt(variable))); + } + } + +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/RelationalProductProvider.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/RelationalProductProvider.java new file mode 100644 index 0000000000..ff92e29b71 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/RelationalProductProvider.java @@ -0,0 +1,26 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.fixedpoint; + +import hu.bme.mit.delta.java.mdd.Cache; +import hu.bme.mit.delta.java.mdd.MddTransformationProvider; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor; + +public interface RelationalProductProvider extends MddTransformationProvider { + + Cache getRelProdCache(); + +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/SaturationCache.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/SaturationCache.java new file mode 100644 index 0000000000..b36f6a68a6 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/SaturationCache.java @@ -0,0 +1,56 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.fixedpoint; + +import hu.bme.mit.delta.java.mdd.BinaryOperationCache; +import hu.bme.mit.delta.java.mdd.Cache; +import hu.bme.mit.delta.java.mdd.MddNode; +import hu.bme.mit.delta.java.mdd.TernaryOperationCache; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor; + +public final class SaturationCache implements Cache { + private final BinaryOperationCache saturateCache = new BinaryOperationCache<>(); + private final TernaryOperationCache relProdCache = new TernaryOperationCache<>(); + + public BinaryOperationCache getSaturateCache() { + return saturateCache; + } + + public TernaryOperationCache getRelProdCache() { + return relProdCache; + } + + @Override + public void clear() { + saturateCache.clear(); + relProdCache.clear(); + } + + @Override + public long getCacheSize() { + return saturateCache.getCacheSize() + relProdCache.getCacheSize(); + } + + @Override + public long getQueryCount() { + return saturateCache.getQueryCount() + relProdCache.getQueryCount(); + } + + @Override + public long getHitCount() { + return saturateCache.getHitCount() + relProdCache.getHitCount(); + } +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/SimpleSaturationProvider.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/SimpleSaturationProvider.java new file mode 100644 index 0000000000..adf4e47688 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/SimpleSaturationProvider.java @@ -0,0 +1,549 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd.fixedpoint; + +import com.koloboke.collect.set.hash.HashObjSets; +import hu.bme.mit.delta.collections.IntObjCursor; +import hu.bme.mit.delta.collections.IntObjMapView; +import hu.bme.mit.delta.collections.impl.IntObjMapViews; +import hu.bme.mit.delta.java.mdd.*; +import hu.bme.mit.delta.java.mdd.impl.MddStructuralTemplate; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor; + +import java.util.Optional; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.ToLongFunction; + +public final class SimpleSaturationProvider implements MddTransformationProvider { + public static boolean verbose = false; + + private MddVariableOrder variableOrder; + private RelationalProductProvider relProdProvider; + private final CacheManager cacheManager = new CacheManager<>(v -> new SaturationCache()); + private MddNode terminalZeroNode; + + public SimpleSaturationProvider(final MddVariableOrder variableOrder) { + this(variableOrder, new LegacyRelationalProductProvider(variableOrder)); + } + + public SimpleSaturationProvider( + final MddVariableOrder variableOrder, final RelationalProductProvider relProdProvider + ) { + this.variableOrder = variableOrder; + this.relProdProvider = relProdProvider; + this.variableOrder.getMddGraph().registerCleanupListener(this); + this.terminalZeroNode = variableOrder.getMddGraph().getTerminalZeroNode(); + } + + public MddHandle compute( + AbstractNextStateDescriptor.Postcondition initializer, + AbstractNextStateDescriptor nextStateRelation, + MddVariableHandle highestAffectedVariable + ) { + final MddHandle initialStates = relProdProvider.compute(variableOrder.getMddGraph().getHandleForTop(), initializer, highestAffectedVariable); + + MddNode result; + + if (highestAffectedVariable.getVariable().isPresent()) { + final MddVariable variable = highestAffectedVariable.getVariable().get(); + result = this.compute(initialStates.getNode(), nextStateRelation, variable); + } else { + result = this.computeTerminal(initialStates.getNode(), + nextStateRelation, + highestAffectedVariable.getMddGraph() + ); + } + + return highestAffectedVariable.getHandleFor(result); + } + + private MddNode recurse( + final MddNode mddNode, + final AbstractNextStateDescriptor nextState, + MddVariable currentVariable, + final CacheManager>.CacheHolder cache + ) { + if (currentVariable.getLower().isPresent()) { + return compute(mddNode, nextState, currentVariable.getLower().get()); + } else { + return computeTerminal(mddNode, nextState, currentVariable.getMddGraph()); + } + } + + private MddNode unionChildren( + final MddNode lhs, final MddNode rhs, MddVariable currentVariable + ) { + if (currentVariable.getLower().isPresent()) { + return currentVariable.getLower().get().union(lhs, rhs); + } else { + return currentVariable.getMddGraph().unionTerminal(lhs, rhs); + } + } + + @Override + public MddNode compute( + final MddNode mddNode, final AbstractNextStateDescriptor nextState, final MddVariable mddVariable + ) { + return saturate(mddNode, nextState, mddVariable, cacheManager.getCacheFor(mddVariable)); + } + + private MddNode saturate( + final MddNode n, + AbstractNextStateDescriptor d, + MddVariable variable, + CacheManager.CacheHolder cache + ) { + if (n.isTerminal() || + d == AbstractNextStateDescriptor.terminalIdentity() || + d == AbstractNextStateDescriptor.terminalEmpty()) { + // TODO this does not handle level skips + return n; + } + + MddNode ret = cache.getCache().getSaturateCache().getOrNull(n, d); + if (ret != null) { + return ret; + } + + if (verbose) { + printIndent(); + System.out.println("Saturating on level " + variable.getTraceInfo() + " with " + d); + } + // indent++; + + final MddStateSpaceInfo stateSpaceInfo = new MddStateSpaceInfo(variable, n); + + IntObjMapView satTemplate = new IntObjMapViews.Transforming(n, + (node, key) -> node == null ? null : terminalZeroToNull(saturate(node, + d.getDiagonal(stateSpaceInfo).get(key), + variable.getLower().orElse(null), + cache.getLower() + )) + ); + + MddNode nsat = variable.checkInNode(MddStructuralTemplate.of(satTemplate)); + + boolean changed; + + do { + changed = false; + + final Optional> splitNS = d.split(); + if (splitNS.isPresent()) { + for (AbstractNextStateDescriptor dfire : splitNS.get()) { + //System.out.println("Applying transition: " + dfire); + if (dfire.isLocallyIdentity(stateSpaceInfo)) { + continue; + } + MddNode nfire = satFire(nsat, d, dfire, variable, cache, stateSpaceInfo); + + nfire = variable.union(nsat, nfire); + + if (nfire != nsat) { + nsat = nfire; + changed = true; + } + } + } else if (!d.isLocallyIdentity(stateSpaceInfo)) { + //System.out.println("Applying transition: " + d); + MddNode nfire = satFire(nsat, d, d, variable, cache, stateSpaceInfo); + + nfire = variable.union(nsat, nfire); + + if (nfire != nsat) { + nsat = nfire; + changed = true; + } + } + } while (changed); + + cache.getCache().getSaturateCache().addToCache(n, d, nsat); + + if (verbose) { + indent--; + printIndent(); + System.out.println("Done Saturating on level " + variable.getTraceInfo() + " resulting in " + nsat); + } + + // indent--; + // printIndent(); + // System.out.println("Saturated level " + variable.getTraceInfo() + ", domain size is " + variable.getDomainSize()); + // + return nsat; + } + + private MddNode satFire( + MddNode n, + AbstractNextStateDescriptor dsat, + AbstractNextStateDescriptor dfire, + MddVariable variable, + CacheManager.CacheHolder cache, + final MddStateSpaceInfo stateSpaceInfo + ) { + if (n == terminalZeroNode || dfire == AbstractNextStateDescriptor.terminalEmpty()) { + return terminalZeroNode; + } + + if (dfire == AbstractNextStateDescriptor.terminalIdentity()) { + return n; + } + + if (verbose) { + printIndent(); + System.out.println("SatFire on level " + + variable.getTraceInfo() + + " with dsat=" + + dsat + + "; dfire=" + + dfire); + indent++; + } + + MddUnsafeTemplateBuilder templateBuilder = JavaMddFactory.getDefault().createUnsafeTemplateBuilder(); + + final IntObjMapView diagonal = dfire.getDiagonal(stateSpaceInfo); + final IntObjMapView> offDiagonal = dfire.getOffDiagonal( + stateSpaceInfo); + + for (IntObjCursor cFrom = n.cursor(); cFrom.moveNext(); ) { + + // Identity step + final AbstractNextStateDescriptor diagonalContinuation = diagonal.get(cFrom.key()); + if (!AbstractNextStateDescriptor.isNullOrEmpty(diagonalContinuation)) { + + if (verbose) { + System.out.println("Potential step: " + cFrom.key() + "->" + cFrom.key()); + } + + MddNode s = relProd(cFrom.value(), + dsat.getDiagonal(stateSpaceInfo).defaultValue(), + diagonalContinuation, + variable.getLower().orElse(null), + cache.getLower() + ); + + if (s != terminalZeroNode) { + // confirm(variable, cFrom.key()); + + templateBuilder.set(cFrom.key(), + terminalZeroToNull(unionChildren(templateBuilder.get(cFrom.key()), s, variable)) + ); + } + } + + for (IntObjCursor cTo = offDiagonal.get( + cFrom.key()).cursor(); cTo.moveNext(); ) { + if (cFrom.key() == cTo.key()) { + continue; + } + + if (verbose) { + System.out.println("Potential step: " + cFrom.key() + "->" + cTo.key()); + } + + assert cFrom.value() != terminalZeroNode; + assert cTo.value() != AbstractNextStateDescriptor.terminalEmpty(); + + MddNode s = relProd(cFrom.value(), + // Level skip will be encoded as default value + dsat.getDiagonal(stateSpaceInfo).defaultValue(), + cTo.value(), + variable.getLower().orElse(null), + cache.getLower() + ); + + if (s != terminalZeroNode) { + confirm(variable, cTo.key()); + + templateBuilder.set(cTo.key(), + terminalZeroToNull(unionChildren(templateBuilder.get(cTo.key()), s, variable)) + ); + } + } + } + + MddNode ret = variable.checkInNode(MddStructuralTemplate.of(templateBuilder.buildAndReset())); + + if (verbose) { + indent--; + printIndent(); + System.out.println("Done SatFire on level " + variable.getTraceInfo() + " resulting in " + ret); + } + + return ret; + } + + private MddNode relProd( + MddNode n, + AbstractNextStateDescriptor dsat, + AbstractNextStateDescriptor dfire, + MddVariable variable, + CacheManager.CacheHolder cache + ) { + if (n == terminalZeroNode || dfire == AbstractNextStateDescriptor.terminalEmpty()) { + return terminalZeroNode; + } + + if (dfire == AbstractNextStateDescriptor.terminalIdentity()) { + return n; + } + + if (n.isTerminal() && dfire.evaluate()) { + return n; + } + + final MddStateSpaceInfo stateSpaceInfo = new MddStateSpaceInfo(variable, n); + + MddNode ret = cache.getCache().getRelProdCache().getOrNull(n, dsat, dfire); + if (ret != null) { + return ret; + } + + if (verbose) { + printIndent(); + System.out.println("SatRelProd on level " + + variable.getTraceInfo() + + ", node=" + + n + + ", with dsat=" + + dsat + + "; dfire" + + "=" + + dfire); + indent++; + } + + MddUnsafeTemplateBuilder templateBuilder = JavaMddFactory.getDefault().createUnsafeTemplateBuilder(); + + final IntObjMapView diagonal = dfire.getDiagonal(stateSpaceInfo); + final IntObjMapView> offDiagonal = dfire.getOffDiagonal( + stateSpaceInfo); + + for (IntObjCursor cFrom = n.cursor(); cFrom.moveNext(); ) { + // Identity step + final AbstractNextStateDescriptor diagonalContinuation = diagonal.get(cFrom.key()); + if (!AbstractNextStateDescriptor.isNullOrEmpty(diagonalContinuation)) { + + if (verbose) { + System.out.println("Potential step: " + cFrom.key() + "->" + cFrom.key()); + } + + MddNode s = relProd(cFrom.value(), + dsat.getDiagonal(stateSpaceInfo).defaultValue(), + diagonalContinuation, + variable.getLower().orElse(null), + cache.getLower() + ); + + if (s != terminalZeroNode) { + // confirm(variable, cFrom.key()); + + templateBuilder.set(cFrom.key(), + terminalZeroToNull(unionChildren(templateBuilder.get(cFrom.key()), s, variable)) + ); + } + } + + for (IntObjCursor cTo = offDiagonal.get(cFrom.key()).cursor(); + cTo.moveNext(); ) { + if (cFrom.key() == cTo.key()) { + continue; + } + + if (verbose) { + System.out.println("Potential step: " + cFrom.key() + "->" + cTo.key()); + } + + assert cFrom.value() != terminalZeroNode; + assert cTo.value() != AbstractNextStateDescriptor.terminalEmpty(); + + MddNode s = relProd(cFrom.value(), + dsat.getDiagonal(stateSpaceInfo).defaultValue(), + cTo.value(), + variable.getLower().orElse(null), + cache.getLower() + ); + + if (s != terminalZeroNode) { + confirm(variable, cTo.key()); + + templateBuilder.set(cTo.key(), + terminalZeroToNull(unionChildren(templateBuilder.get(cTo.key()), s, variable)) + ); + } + } + } + + ret = variable.checkInNode(MddStructuralTemplate.of(templateBuilder.buildAndReset())); + + ret = saturate(ret, dsat, variable, cache); + + cache.getCache().getRelProdCache().addToCache(n, dsat, dfire, ret); + + if (verbose) { + indent--; + printIndent(); + System.out.println("Done SatRelProd on level " + variable.getTraceInfo() + " resulting in " + ret); + } + + return ret; + } + + private void confirm(final MddVariable variable, final int key) { + + } + + @Override + public MddNode computeTerminal( + final MddNode mddNode, final AbstractNextStateDescriptor nextState, final MddGraph mddGraph + ) { + return mddNode; + } + + private MddNode terminalZeroToNull(MddNode node) { + return node == terminalZeroNode ? null : node; + } + + private int indent = 0; + + private void printIndent() { + for (int i = 0; i < indent; ++i) { + System.out.print(" "); + } + } + + @Override + public void dispose() { + this.variableOrder.getMddGraph().unregisterCleanupListener(this); + } + + @Override + public void clear() { + cacheManager.clearAll(); + } + + @Override + public void cleanup() { + this.cacheManager.forEachCache((cache) -> { + cache.getSaturateCache().clearSelectively((source, ns1, result) -> source.getReferenceCount() == 0 || + result.getReferenceCount() == 0); + cache.getRelProdCache().clearSelectively((source, ns1, ns2, result) -> source.getReferenceCount() == 0 || + result.getReferenceCount() == 0); + }); + } + + private class Aggregator implements Consumer { + public long result = 0; + private final ToLongFunction extractor; + + private Aggregator(final ToLongFunction extractor) { + this.extractor = extractor; + } + + @Override + public void accept(final SaturationCache cache) { + result += extractor.applyAsLong(cache); + } + } + + public Cache getSaturateCache() { + class SaturateCache implements Cache { + private final CacheManager cacheManager; + + SaturateCache(final CacheManager cacheManager) { + this.cacheManager = cacheManager; + } + + @Override + public void clear() { + cacheManager.forEachCache(cache -> cache.getSaturateCache().clear()); + } + + @Override + public long getCacheSize() { + Aggregator a = new Aggregator(c -> c.getSaturateCache().getCacheSize()); + cacheManager.forEachCache(a); + return a.result; + } + + @Override + public long getQueryCount() { + Aggregator a = new Aggregator(c -> c.getSaturateCache().getQueryCount()); + cacheManager.forEachCache(a); + return a.result; + } + + @Override + public long getHitCount() { + Aggregator a = new Aggregator(c -> c.getSaturateCache().getHitCount()); + cacheManager.forEachCache(a); + return a.result; + } + } + + return new SaturateCache(cacheManager); + } + + + // TODO: HAXXXX DON'T DO THIS EVER AGAIN + public Set getSaturatedNodes() { + final Set ret = HashObjSets.newUpdatableSet(); + cacheManager.forEachCache((c) -> c.getSaturateCache().clearSelectively((source, ns, result) -> { + ret.add(result); + return false; + })); + return ret; + } + + public Cache getRelProdCache() { + class RelProdCache implements Cache { + private final CacheManager cacheManager; + + RelProdCache(final CacheManager cacheManager) { + this.cacheManager = cacheManager; + } + + @Override + public void clear() { + cacheManager.forEachCache(cache -> cache.getRelProdCache().clear()); + } + + @Override + public long getCacheSize() { + Aggregator a = new Aggregator(c -> c.getRelProdCache().getCacheSize()); + cacheManager.forEachCache(a); + return a.result; + } + + @Override + public long getQueryCount() { + Aggregator a = new Aggregator(c -> c.getRelProdCache().getQueryCount()); + cacheManager.forEachCache(a); + return a.result; + } + + @Override + public long getHitCount() { + Aggregator a = new Aggregator(c -> c.getRelProdCache().getHitCount()); + cacheManager.forEachCache(a); + return a.result; + } + } + + return new RelProdCache(cacheManager); + } +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/expr/refinement/AasporRefiner.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/expr/refinement/AasporRefiner.java index f18d4b23d2..8f2f499547 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/expr/refinement/AasporRefiner.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/expr/refinement/AasporRefiner.java @@ -16,8 +16,8 @@ package hu.bme.mit.theta.analysis.expr.refinement; import hu.bme.mit.theta.analysis.Prec; -import hu.bme.mit.theta.analysis.algorithm.ARG; -import hu.bme.mit.theta.analysis.algorithm.ArgNode; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNode; import hu.bme.mit.theta.analysis.algorithm.cegar.Refiner; import hu.bme.mit.theta.analysis.algorithm.cegar.RefinerResult; import hu.bme.mit.theta.analysis.expr.ExprAction; diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/expr/refinement/MultiExprTraceRefiner.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/expr/refinement/MultiExprTraceRefiner.java index 67d6a3c58e..72c516adef 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/expr/refinement/MultiExprTraceRefiner.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/expr/refinement/MultiExprTraceRefiner.java @@ -17,9 +17,9 @@ import hu.bme.mit.theta.analysis.Prec; import hu.bme.mit.theta.analysis.Trace; -import hu.bme.mit.theta.analysis.algorithm.ARG; -import hu.bme.mit.theta.analysis.algorithm.ArgNode; -import hu.bme.mit.theta.analysis.algorithm.ArgTrace; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNode; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgTrace; import hu.bme.mit.theta.analysis.algorithm.cegar.Refiner; import hu.bme.mit.theta.analysis.algorithm.cegar.RefinerResult; import hu.bme.mit.theta.analysis.expr.ExprAction; diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/expr/refinement/NodePruner.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/expr/refinement/NodePruner.java index 4eae7e6e80..2073ef2141 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/expr/refinement/NodePruner.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/expr/refinement/NodePruner.java @@ -15,8 +15,8 @@ */ package hu.bme.mit.theta.analysis.expr.refinement; -import hu.bme.mit.theta.analysis.algorithm.ARG; -import hu.bme.mit.theta.analysis.algorithm.ArgNode; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNode; import hu.bme.mit.theta.analysis.expr.ExprAction; import hu.bme.mit.theta.analysis.expr.ExprState; diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/expr/refinement/SingleExprTraceRefiner.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/expr/refinement/SingleExprTraceRefiner.java index bf1559800c..ac06cf2a87 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/expr/refinement/SingleExprTraceRefiner.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/expr/refinement/SingleExprTraceRefiner.java @@ -17,9 +17,9 @@ import hu.bme.mit.theta.analysis.Prec; import hu.bme.mit.theta.analysis.Trace; -import hu.bme.mit.theta.analysis.algorithm.ARG; -import hu.bme.mit.theta.analysis.algorithm.ArgNode; -import hu.bme.mit.theta.analysis.algorithm.ArgTrace; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNode; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgTrace; import hu.bme.mit.theta.analysis.algorithm.cegar.Refiner; import hu.bme.mit.theta.analysis.algorithm.cegar.RefinerResult; import hu.bme.mit.theta.analysis.expr.ExprAction; diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/reachedset/ReachedSet.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/reachedset/ReachedSet.java index 7b65926024..54272de4a4 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/reachedset/ReachedSet.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/reachedset/ReachedSet.java @@ -19,7 +19,7 @@ import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.State; -import hu.bme.mit.theta.analysis.algorithm.ArgNode; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNode; public interface ReachedSet { diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/runtimemonitor/CexMonitor.kt b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/runtimemonitor/CexMonitor.kt index 65ff75d6cf..32c78c9b0e 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/runtimemonitor/CexMonitor.kt +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/runtimemonitor/CexMonitor.kt @@ -17,8 +17,8 @@ package hu.bme.mit.theta.analysis.runtimemonitor import hu.bme.mit.theta.analysis.Action import hu.bme.mit.theta.analysis.State -import hu.bme.mit.theta.analysis.algorithm.ARG -import hu.bme.mit.theta.analysis.algorithm.ArgTrace +import hu.bme.mit.theta.analysis.algorithm.arg.ARG +import hu.bme.mit.theta.analysis.algorithm.arg.ArgTrace import hu.bme.mit.theta.analysis.runtimemonitor.container.CexHashStorage import hu.bme.mit.theta.common.exception.NotSolvableException import hu.bme.mit.theta.common.logging.Logger diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/runtimemonitor/container/CexHashStorage.kt b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/runtimemonitor/container/CexHashStorage.kt index 646f1f689e..d199287c94 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/runtimemonitor/container/CexHashStorage.kt +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/runtimemonitor/container/CexHashStorage.kt @@ -17,8 +17,8 @@ package hu.bme.mit.theta.analysis.runtimemonitor.container import hu.bme.mit.theta.analysis.Action import hu.bme.mit.theta.analysis.State -import hu.bme.mit.theta.analysis.algorithm.ArgStructuralEquality -import hu.bme.mit.theta.analysis.algorithm.ArgTrace +import hu.bme.mit.theta.analysis.algorithm.arg.ArgStructuralEquality +import hu.bme.mit.theta.analysis.algorithm.arg.ArgTrace class CexHashStorage : RuntimeDataCollection?> { diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/utils/ArgVisualizer.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/utils/ArgVisualizer.java index d1e3c3f6c2..9992e5a3e7 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/utils/ArgVisualizer.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/utils/ArgVisualizer.java @@ -28,9 +28,9 @@ import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.State; -import hu.bme.mit.theta.analysis.algorithm.ARG; -import hu.bme.mit.theta.analysis.algorithm.ArgEdge; -import hu.bme.mit.theta.analysis.algorithm.ArgNode; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgEdge; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNode; import hu.bme.mit.theta.common.visualization.EdgeAttributes; import hu.bme.mit.theta.common.visualization.Graph; import hu.bme.mit.theta.common.visualization.LineStyle; diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/utils/MddNodeCacheVisualizer.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/utils/MddNodeCacheVisualizer.java new file mode 100644 index 0000000000..b3fe19d596 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/utils/MddNodeCacheVisualizer.java @@ -0,0 +1,144 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.utils; + +import com.google.common.base.Preconditions; +import hu.bme.mit.delta.java.mdd.MddNode; +import hu.bme.mit.theta.analysis.algorithm.mdd.expressionnode.MddExpressionRepresentation; +import hu.bme.mit.theta.common.container.Containers; +import hu.bme.mit.theta.common.visualization.EdgeAttributes; +import hu.bme.mit.theta.common.visualization.Graph; +import hu.bme.mit.theta.common.visualization.LineStyle; +import hu.bme.mit.theta.common.visualization.NodeAttributes; + +import java.awt.*; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; + +import static hu.bme.mit.theta.common.visualization.Alignment.LEFT; +import static hu.bme.mit.theta.common.visualization.Shape.RECTANGLE; + +public class MddNodeCacheVisualizer { + + private static final LineStyle CHILD_EDGE_STYLE = LineStyle.NORMAL; + private static final LineStyle DEFAULT_EDGE_STYLE = LineStyle.DOTTED; + private static final String SYMBOLIC_NODE_LABEL = ""; + private static final String SYMBOLIC_NODE_ID = "symbolicnode"; + private static final String FONT = "courier"; + private static final String NODE_ID_PREFIX = "node_"; + private static final Color FILL_COLOR = Color.WHITE; + private static final Color LINE_COLOR = Color.BLACK; + + private final Function nodeToString; + + private static final Map registry = new IdentityHashMap<>(); + private static long nextId = 0; + + public static long idFor(MddNode n) { + Long l = registry.get(n); + if (l == null) + registry.put(n, l = nextId++); + return l; + } + + private static class LazyHolderDefault { + static final MddNodeCacheVisualizer INSTANCE = new MddNodeCacheVisualizer(n -> n.toString()); + } + + private static class LazyHolderStructureOnly { + static final MddNodeCacheVisualizer INSTANCE = new MddNodeCacheVisualizer(n -> ""); + } + + public MddNodeCacheVisualizer(final Function nodeToString) { + this.nodeToString = nodeToString; + } + + public static MddNodeCacheVisualizer create( + final Function nodeToString) { + return new MddNodeCacheVisualizer(nodeToString); + } + + public static MddNodeCacheVisualizer getDefault() { + return LazyHolderDefault.INSTANCE; + } + + public static MddNodeCacheVisualizer getStructureOnly() { + return LazyHolderStructureOnly.INSTANCE; + } + + public Graph visualize(final MddNode rootNode) { + final Graph graph = new Graph(SYMBOLIC_NODE_ID, SYMBOLIC_NODE_LABEL); + + final Set traversed = Containers.createSet(); + + traverse(graph, rootNode, traversed); + + return graph; + } + + private void traverse(final Graph graph, final MddNode node, + final Set traversed) { + if (traversed.contains(node)) { + return; + } else { + traversed.add(node); + } + final String nodeId = NODE_ID_PREFIX + idFor(node); + final LineStyle lineStyle = CHILD_EDGE_STYLE; + + final int peripheries = 1; +// final int peripheries = node.isComplete()?2:1; + + final NodeAttributes nAttributes = NodeAttributes.builder().label(nodeToString.apply(node)) + .alignment(LEFT).shape(RECTANGLE).font(FONT).fillColor(FILL_COLOR).lineColor(LINE_COLOR) + .peripheries(peripheries).lineStyle(lineStyle).build(); + + graph.addNode(nodeId, nAttributes); + + if (node.defaultValue() != null) { + final MddNode defaultValue = node.defaultValue(); + traverse(graph, defaultValue, traversed); + + final String sourceId = NODE_ID_PREFIX + idFor(node); + final String targetId = NODE_ID_PREFIX + idFor(defaultValue); + final EdgeAttributes eAttributes = EdgeAttributes.builder() + .alignment(LEFT).font(FONT).color(LINE_COLOR).lineStyle(DEFAULT_EDGE_STYLE).build(); + graph.addEdge(sourceId, targetId, eAttributes); + } else { + if (!(node.isTerminal())) { + var representation = node.getRepresentation(); + Preconditions.checkState(representation instanceof MddExpressionRepresentation); + var expressionRepresentation = (MddExpressionRepresentation) representation; + for (var cursor = expressionRepresentation.getExplicitRepresentation().getCacheView().cursor(); cursor.moveNext(); ) { + if (cursor.value() != null) { + traverse(graph, cursor.value(), traversed); + + final String sourceId = NODE_ID_PREFIX + idFor(node); + final String targetId = NODE_ID_PREFIX + idFor(cursor.value()); + final EdgeAttributes eAttributes = EdgeAttributes.builder().label(cursor.key() + "") + .alignment(LEFT).font(FONT).color(LINE_COLOR).lineStyle(CHILD_EDGE_STYLE).build(); + graph.addEdge(sourceId, targetId, eAttributes); + } + + } + } + } + + } + +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/utils/MddNodeVisualizer.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/utils/MddNodeVisualizer.java new file mode 100644 index 0000000000..dcaed9e3f9 --- /dev/null +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/utils/MddNodeVisualizer.java @@ -0,0 +1,151 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.utils; + +import hu.bme.mit.delta.collections.RecursiveIntObjCursor; +import hu.bme.mit.delta.collections.impl.RecursiveIntObjMapViews; +import hu.bme.mit.delta.java.mdd.MddNode; +import hu.bme.mit.theta.common.container.Containers; +import hu.bme.mit.theta.common.visualization.EdgeAttributes; +import hu.bme.mit.theta.common.visualization.Graph; +import hu.bme.mit.theta.common.visualization.LineStyle; +import hu.bme.mit.theta.common.visualization.NodeAttributes; + +import java.awt.*; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; + +import static hu.bme.mit.theta.common.visualization.Alignment.LEFT; +import static hu.bme.mit.theta.common.visualization.Shape.RECTANGLE; + +public class MddNodeVisualizer { + + private static final LineStyle CHILD_EDGE_STYLE = LineStyle.NORMAL; + private static final LineStyle DEFAULT_EDGE_STYLE = LineStyle.DOTTED; + private static final String SYMBOLIC_NODE_LABEL = ""; + private static final String SYMBOLIC_NODE_ID = "symbolicnode"; + private static final String FONT = "courier"; + private static final String NODE_ID_PREFIX = "node_"; + private static final Color FILL_COLOR = Color.WHITE; + private static final Color LINE_COLOR = Color.BLACK; + + private final Function nodeToString; + + private static final Map registry = new IdentityHashMap<>(); + private static long nextId = 0; + + public static long idFor(MddNode n) { + Long l = registry.get(n); + if (l == null) + registry.put(n, l = nextId++); + return l; + } + + private static class LazyHolderDefault { + static final MddNodeVisualizer INSTANCE = new MddNodeVisualizer(n -> n.toString()); + } + + private static class LazyHolderStructureOnly { + static final MddNodeVisualizer INSTANCE = new MddNodeVisualizer(n -> ""); + } + + private MddNodeVisualizer(final Function nodeToString) { + this.nodeToString = nodeToString; + } + + public static MddNodeVisualizer create( + final Function nodeToString) { + return new MddNodeVisualizer(nodeToString); + } + + public static MddNodeVisualizer create() { + return new MddNodeVisualizer(MddNodeVisualizer::nodeToString); + } + + public static MddNodeVisualizer getDefault() { + return LazyHolderDefault.INSTANCE; + } + + public static MddNodeVisualizer getStructureOnly() { + return LazyHolderStructureOnly.INSTANCE; + } + + public Graph visualize(final MddNode rootNode) { + final Graph graph = new Graph(SYMBOLIC_NODE_ID, SYMBOLIC_NODE_LABEL); + + final Set traversed = Containers.createSet(); + + traverse(graph, rootNode, rootNode.cursor(), traversed); + + return graph; + } + + private void traverse(final Graph graph, final MddNode node, RecursiveIntObjCursor cursor, + final Set traversed) { + if (traversed.contains(node)) { + return; + } else { + traversed.add(node); + } + final String nodeId = NODE_ID_PREFIX + idFor(node); + final LineStyle lineStyle = CHILD_EDGE_STYLE; + + final int peripheries = 1; +// final int peripheries = node.isComplete()?2:1; + + final NodeAttributes nAttributes = NodeAttributes.builder().label(nodeToString.apply(node)) + .alignment(LEFT).shape(RECTANGLE).font(FONT).fillColor(FILL_COLOR).lineColor(LINE_COLOR) + .peripheries(peripheries).lineStyle(lineStyle).build(); + + graph.addNode(nodeId, nAttributes); + + if (node.defaultValue() != null) { + final MddNode defaultValue = node.defaultValue(); + try (var valueCursor = cursor.valueCursor()) { + traverse(graph, defaultValue, valueCursor, traversed); + } + final String sourceId = NODE_ID_PREFIX + idFor(node); + final String targetId = NODE_ID_PREFIX + idFor(defaultValue); + final EdgeAttributes eAttributes = EdgeAttributes.builder() + .alignment(LEFT).font(FONT).color(LINE_COLOR).lineStyle(DEFAULT_EDGE_STYLE).build(); + graph.addEdge(sourceId, targetId, eAttributes); + } else { + while (cursor.moveNext()) { + if (cursor.value() != null) { + try (var valueCursor = cursor.valueCursor()) { + traverse(graph, cursor.value(), valueCursor, traversed); + } + final String sourceId = NODE_ID_PREFIX + idFor(node); + final String targetId = NODE_ID_PREFIX + idFor(cursor.value()); + final EdgeAttributes eAttributes = EdgeAttributes.builder().label(cursor.key() + "") + .alignment(LEFT).font(FONT).color(LINE_COLOR).lineStyle(CHILD_EDGE_STYLE).build(); + graph.addEdge(sourceId, targetId, eAttributes); + } + + } + } + + } + + private static String nodeToString(MddNode node) { + if (node.getRepresentation() instanceof RecursiveIntObjMapViews.OfIntObjMapView) + return ""; + return node instanceof MddNode.Terminal ? ((MddNode.Terminal) node).getTerminalData().toString() : node.getRepresentation().toString(); + } + +} diff --git a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/waitlist/PriorityWaitlist.java b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/waitlist/PriorityWaitlist.java index 868e7c33d6..183ea2f19a 100644 --- a/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/waitlist/PriorityWaitlist.java +++ b/subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/waitlist/PriorityWaitlist.java @@ -22,7 +22,7 @@ import java.util.PriorityQueue; import java.util.stream.Stream; -import hu.bme.mit.theta.analysis.algorithm.ArgNodeComparators; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNodeComparators; import hu.bme.mit.theta.common.Utils; /** diff --git a/subprojects/common/analysis/src/main/kotlin/hu/bme/mit/theta/analysis/multi/config/MultiConfig.kt b/subprojects/common/analysis/src/main/kotlin/hu/bme/mit/theta/analysis/multi/config/MultiConfig.kt index 2a31051182..74ce991c0a 100644 --- a/subprojects/common/analysis/src/main/kotlin/hu/bme/mit/theta/analysis/multi/config/MultiConfig.kt +++ b/subprojects/common/analysis/src/main/kotlin/hu/bme/mit/theta/analysis/multi/config/MultiConfig.kt @@ -19,8 +19,10 @@ package hu.bme.mit.theta.analysis.multi.config import hu.bme.mit.theta.analysis.Action import hu.bme.mit.theta.analysis.Prec import hu.bme.mit.theta.analysis.State +import hu.bme.mit.theta.analysis.Trace import hu.bme.mit.theta.analysis.algorithm.SafetyChecker import hu.bme.mit.theta.analysis.algorithm.SafetyResult +import hu.bme.mit.theta.analysis.algorithm.arg.ARG import hu.bme.mit.theta.analysis.multi.MultiAction import hu.bme.mit.theta.analysis.multi.MultiPrec import hu.bme.mit.theta.analysis.multi.MultiState @@ -31,9 +33,9 @@ class MultiConfig< LPrec : Prec, RPrec : Prec, DataPrec : Prec, MState : MultiState, MAction : MultiAction>( - val checker: SafetyChecker>, + val checker: SafetyChecker, Trace, MultiPrec>, val initPrec: MultiPrec ) { - fun check(): SafetyResult = checker.check(initPrec) + fun check(): SafetyResult, Trace> = checker.check(initPrec) } \ No newline at end of file diff --git a/subprojects/common/analysis/src/main/kotlin/hu/bme/mit/theta/analysis/multi/config/StmtMultiConfigBuilder.kt b/subprojects/common/analysis/src/main/kotlin/hu/bme/mit/theta/analysis/multi/config/StmtMultiConfigBuilder.kt index 87399b70e0..2e7f57a91a 100644 --- a/subprojects/common/analysis/src/main/kotlin/hu/bme/mit/theta/analysis/multi/config/StmtMultiConfigBuilder.kt +++ b/subprojects/common/analysis/src/main/kotlin/hu/bme/mit/theta/analysis/multi/config/StmtMultiConfigBuilder.kt @@ -17,7 +17,7 @@ package hu.bme.mit.theta.analysis.multi.config import hu.bme.mit.theta.analysis.Prec -import hu.bme.mit.theta.analysis.algorithm.ArgBuilder +import hu.bme.mit.theta.analysis.algorithm.arg.ArgBuilder import hu.bme.mit.theta.analysis.algorithm.cegar.BasicAbstractor import hu.bme.mit.theta.analysis.algorithm.cegar.CegarChecker import hu.bme.mit.theta.analysis.expr.ExprState diff --git a/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/ArgCexTest.java b/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgCexTest.java similarity index 91% rename from subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/ArgCexTest.java rename to subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgCexTest.java index 257dbf24c2..63c3c25212 100644 --- a/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/ArgCexTest.java +++ b/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgCexTest.java @@ -13,7 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.analysis.algorithm; +package hu.bme.mit.theta.analysis.algorithm.arg; + +import java.util.List; +import java.util.stream.Collectors; + +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNode; +import org.junit.Assert; +import org.junit.Test; import com.google.common.collect.ImmutableList; import hu.bme.mit.theta.analysis.Action; diff --git a/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/ArgNodeComparatorsTest.java b/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgNodeComparatorsTest.java similarity index 77% rename from subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/ArgNodeComparatorsTest.java rename to subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgNodeComparatorsTest.java index 7b7c556c94..fc575df02b 100644 --- a/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/ArgNodeComparatorsTest.java +++ b/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgNodeComparatorsTest.java @@ -13,7 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.analysis.algorithm; +package hu.bme.mit.theta.analysis.algorithm.arg; + +import static hu.bme.mit.theta.analysis.algorithm.arg.ArgNodeComparators.bfs; +import static hu.bme.mit.theta.analysis.algorithm.arg.ArgNodeComparators.combine; +import static hu.bme.mit.theta.analysis.algorithm.arg.ArgNodeComparators.creationAsc; +import static hu.bme.mit.theta.analysis.algorithm.arg.ArgNodeComparators.creationDesc; +import static hu.bme.mit.theta.analysis.algorithm.arg.ArgNodeComparators.dfs; +import static hu.bme.mit.theta.analysis.algorithm.arg.ArgNodeComparators.targetFirst; + +import java.util.List; +import java.util.stream.Collectors; + +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNode; +import org.junit.Assert; +import org.junit.Test; import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.State; @@ -26,7 +41,7 @@ import java.util.List; import java.util.stream.Collectors; -import static hu.bme.mit.theta.analysis.algorithm.ArgNodeComparators.*; +import static hu.bme.mit.theta.analysis.algorithm.arg.ArgNodeComparators.*; public class ArgNodeComparatorsTest { diff --git a/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/ArgPruningTest.java b/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgPruningTest.java similarity index 92% rename from subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/ArgPruningTest.java rename to subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgPruningTest.java index 5ba3784073..2f119ffdc9 100644 --- a/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/ArgPruningTest.java +++ b/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgPruningTest.java @@ -13,7 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.analysis.algorithm; +package hu.bme.mit.theta.analysis.algorithm.arg; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNode; +import org.junit.Test; import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.State; diff --git a/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/ArgStructuralEqualityTest.java b/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgStructuralEqualityTest.java similarity index 98% rename from subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/ArgStructuralEqualityTest.java rename to subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgStructuralEqualityTest.java index a2b020770a..6a4f2990f4 100644 --- a/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/ArgStructuralEqualityTest.java +++ b/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/arg/ArgStructuralEqualityTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.analysis.algorithm; +package hu.bme.mit.theta.analysis.algorithm.arg; import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.State; diff --git a/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddCheckerTest.java b/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddCheckerTest.java new file mode 100644 index 0000000000..070daeb91f --- /dev/null +++ b/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddCheckerTest.java @@ -0,0 +1,172 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd; + +import hu.bme.mit.theta.analysis.algorithm.SafetyResult; +import hu.bme.mit.theta.analysis.expr.ExprAction; +import hu.bme.mit.theta.common.logging.ConsoleLogger; +import hu.bme.mit.theta.common.logging.Logger; +import hu.bme.mit.theta.core.decl.Decls; +import hu.bme.mit.theta.core.decl.VarDecl; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.booltype.BoolType; +import hu.bme.mit.theta.core.type.inttype.IntExprs; +import hu.bme.mit.theta.core.type.inttype.IntType; +import hu.bme.mit.theta.core.utils.indexings.VarIndexing; +import hu.bme.mit.theta.core.utils.indexings.VarIndexingFactory; +import hu.bme.mit.theta.solver.SolverPool; +import hu.bme.mit.theta.solver.z3legacy.Z3LegacySolverFactory; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; + +import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.*; +import static hu.bme.mit.theta.core.type.anytype.Exprs.Prime; +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.And; +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Not; +import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +@RunWith(value = Parameterized.class) + +public class MddCheckerTest { + + private static final VarDecl X = Decls.Var("x", IntType.getInstance()); + private static final VarDecl Y = Decls.Var("y", IntType.getInstance()); + private static final VarDecl Z = Decls.Var("z", IntType.getInstance()); + + + @Parameterized.Parameter(value = 0) + public Expr initExpr; + + @Parameterized.Parameter(value = 1) + public Expr tranExpr; + + @Parameterized.Parameter(value = 2) + public Expr propExpr; + + @Parameterized.Parameter(value = 3) + public boolean safe; + + @Parameterized.Parameter(value = 4) + public Long stateSpaceSize; + + @Parameterized.Parameters(name = "{index}: {0}, {1}, {2}, {3}, {4}") + public static Collection data() { + return Arrays.asList(new Object[][]{ + + {Eq(X.getRef(), Int(0)), // x = 0 + Eq(Prime(X.getRef()), X.getRef()), // x'=x + Not(Eq(X.getRef(), Int(5))), // not x = 5 + true, + 1L}, + + {Eq(X.getRef(), Int(0)), + Eq(Prime(X.getRef()), X.getRef()), + Not(Eq(X.getRef(), Int(0))), + false, + 1L}, + + {Eq(X.getRef(), Int(0)), // x = 0 + And(Eq(Prime(X.getRef()), Add(X.getRef(), Int(1))), Leq(Prime(X.getRef()), Int(10))), // x' = x + 1 & x' <= 10 + Not(Eq(X.getRef(), Int(5))), + false, + 11L}, + + {Eq(X.getRef(), Int(0)), + And(Eq(Prime(X.getRef()), Add(X.getRef(), Int(1))), Leq(Prime(X.getRef()), Int(5))), + Not(Eq(X.getRef(), Int(5))), + false, + 6L}, + + {Eq(X.getRef(), Int(0)), + And(Eq(Prime(X.getRef()), Add(X.getRef(), Int(1))), Leq(Prime(X.getRef()), Int(4))), + Not(Eq(X.getRef(), Int(5))), + true, + 5L}, + + {And(Eq(X.getRef(), Int(0)), Eq(Y.getRef(), Int(0)), Eq(Z.getRef(), Int(0))), + And(And(Eq(Prime(X.getRef()), Add(Y.getRef(), Int(1))), Eq(Prime(Y.getRef()), Add(Z.getRef(), Int(1))), Eq(Prime(Z.getRef()), Add(Z.getRef(), Int(1)))), IntExprs.Lt(Prime(Z.getRef()), Int(10))), + Not(Eq(X.getRef(), Int(5))), + false, + 10L}, + + {And(Eq(X.getRef(), Int(0)), Eq(Y.getRef(), Int(0)), Eq(Z.getRef(), Int(0))), + And(And(Eq(Prime(X.getRef()), Add(Y.getRef(), Int(1))), Eq(Prime(Y.getRef()), Add(Z.getRef(), Int(1))), Eq(Prime(Z.getRef()), Add(Z.getRef(), Int(1)))), IntExprs.Lt(Prime(Z.getRef()), Int(6))), + Not(Eq(X.getRef(), Int(5))), + false, + 6L}, + + {And(Eq(X.getRef(), Int(0)), Eq(Y.getRef(), Int(0)), Eq(Z.getRef(), Int(0))), + And(And(Eq(Prime(X.getRef()), Add(Y.getRef(), Int(1))), Eq(Prime(Y.getRef()), Add(Z.getRef(), Int(1))), Eq(Prime(Z.getRef()), Add(Z.getRef(), Int(1)))), IntExprs.Lt(Prime(Z.getRef()), Int(5))), + Not(Eq(X.getRef(), Int(5))), + true, + 5L}, + + }); + } + + @Test + public void testBfs() throws Exception { + testWithIterationStrategy(MddChecker.IterationStrategy.BFS); + } + + @Test + public void testSat() throws Exception { + testWithIterationStrategy(MddChecker.IterationStrategy.SAT); + } + + @Test + public void testGsat() throws Exception { + testWithIterationStrategy(MddChecker.IterationStrategy.GSAT); + } + + public void testWithIterationStrategy(MddChecker.IterationStrategy iterationStrategy) throws Exception { + + final Logger logger = new ConsoleLogger(Logger.Level.SUBSTEP); + + final SafetyResult status; + try (var solverPool = new SolverPool(Z3LegacySolverFactory.getInstance())) { + final MddChecker checker = MddChecker.create(initExpr, VarIndexingFactory.indexing(0), new ExprAction() { + @Override + public Expr toExpr() { + return tranExpr; + } + + @Override + public VarIndexing nextIndexing() { + return VarIndexingFactory.indexing(1); + } + }, propExpr, solverPool, logger, iterationStrategy); + status = checker.check(null); + } + + if (safe) { + assertTrue(status.isSafe()); + } else { + assertTrue(status.isUnsafe()); + } + assertEquals(stateSpaceSize, status.getWitness().size()); + + + } + +} diff --git a/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddExpressionTest.java b/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddExpressionTest.java new file mode 100644 index 0000000000..feae90917b --- /dev/null +++ b/subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddExpressionTest.java @@ -0,0 +1,304 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.analysis.algorithm.mdd; + +import hu.bme.mit.delta.java.mdd.*; +import hu.bme.mit.delta.mdd.MddVariableDescriptor; +import hu.bme.mit.theta.solver.SolverPool; +import hu.bme.mit.theta.analysis.algorithm.mdd.expressionnode.ExprLatticeDefinition; +import hu.bme.mit.theta.analysis.algorithm.mdd.expressionnode.MddExpressionTemplate; +import hu.bme.mit.theta.analysis.utils.MddNodeVisualizer; +import hu.bme.mit.theta.common.visualization.Graph; +import hu.bme.mit.theta.common.visualization.writer.GraphvizWriter; +import hu.bme.mit.theta.core.decl.ConstDecl; +import hu.bme.mit.theta.core.decl.Decl; +import hu.bme.mit.theta.core.decl.Decls; +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.booltype.BoolType; +import hu.bme.mit.theta.core.type.inttype.IntType; +import hu.bme.mit.theta.solver.z3legacy.Z3LegacySolverFactory; +import org.junit.Test; + +import java.io.FileNotFoundException; +import java.util.Set; + +import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.*; +import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Leq; +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.*; +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Not; +import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; +import static org.junit.Assert.assertEquals; + +public class MddExpressionTest { + + @Test + public void exprNodeTest1() { + + MddGraph mddGraph = JavaMddFactory.getDefault().createMddGraph(ExprLatticeDefinition.forExpr()); + MddVariableOrder varOrder = JavaMddFactory.getDefault().createMddVariableOrder(mddGraph); + + ConstDecl declX = Decls.Const("x", Int()); + ConstDecl declY = Decls.Const("y", Int()); + ConstDecl declZ = Decls.Const("z", Int()); + + MddVariable z = varOrder.createOnTop(MddVariableDescriptor.create(declZ, 0)); + MddVariable y = varOrder.createOnTop(MddVariableDescriptor.create(declY, 0)); + MddVariable x = varOrder.createOnTop(MddVariableDescriptor.create(declX, 0)); + + // x >= 2 && y = x + 1 && x <= 6 + Expr expr = And(Geq(declX.getRef(), Int(2)), Eq(declY.getRef(), Add(declX.getRef(), Int(1))), Leq(declX.getRef(), Int(6))); + + SolverPool solverPool = new SolverPool(Z3LegacySolverFactory.getInstance()); + MddNode rootNode = x.checkInNode(MddExpressionTemplate.of(expr, o -> (Decl) o, solverPool)); + + var interpreter = x.getNodeInterpreter(rootNode); + + var recursiveCursor = interpreter.cursor(); + recursiveCursor.moveNext(); + recursiveCursor.moveNext(); + recursiveCursor.moveNext(); + + try (var childCursor = recursiveCursor.valueCursor()) { + childCursor.moveNext(); + childCursor.moveNext(); + } + + recursiveCursor.moveNext(); + + try (var childCursor2 = recursiveCursor.valueCursor()) { + childCursor2.moveNext(); + childCursor2.moveNext(); + } + + recursiveCursor.moveNext(); + recursiveCursor.moveNext(); + + final Set valuations = MddValuationCollector.collect(rootNode); + + assertEquals(valuations.size(), 5); + } + + @Test + public void exprNodeTest2() { + + MddGraph mddGraph = JavaMddFactory.getDefault().createMddGraph(ExprLatticeDefinition.forExpr()); + MddVariableOrder varOrder = JavaMddFactory.getDefault().createMddVariableOrder(mddGraph); + + ConstDecl declA = Decls.Const("a", Bool()); + ConstDecl declB = Decls.Const("b", Bool()); + ConstDecl declX = Decls.Const("x", Int()); + + MddVariable x = varOrder.createOnTop(MddVariableDescriptor.create(declX, 0)); + MddVariable b = varOrder.createOnTop(MddVariableDescriptor.create(declB, 2)); + MddVariable a = varOrder.createOnTop(MddVariableDescriptor.create(declA, 2)); + + Expr expr = And(Or(declA.getRef(), Not(declB.getRef())), Eq(declX.getRef(), Int(2))); + + SolverPool solverPool = new SolverPool(Z3LegacySolverFactory.getInstance()); + MddNode rootNode = a.checkInNode(MddExpressionTemplate.of(expr, o -> (Decl) o, solverPool)); + + for (var c = rootNode.cursor(); c.moveNext(); ) { + } + + var node2 = rootNode.get(0); + + for (var c = node2.cursor(); c.moveNext(); ) { + } + + var node3 = node2.get(0); + + for (var c = node3.cursor(); c.moveNext(); ) { + } + + var node4 = rootNode.get(1); + + for (var c = node4.cursor(); c.moveNext(); ) { + } + + final Set valuations = MddValuationCollector.collect(rootNode); + + // TODO This might be 2 if default values are enabled + assertEquals(valuations.size(), 3); + } + + @Test + public void exprNodeTest3() { + + // TODO need to fix nodeinterpreters and cursors + + MddGraph mddGraph = JavaMddFactory.getDefault().createMddGraph(ExprLatticeDefinition.forExpr()); + MddVariableOrder varOrder = JavaMddFactory.getDefault().createMddVariableOrder(mddGraph); + + ConstDecl declX = Decls.Const("x", Int()); + ConstDecl declY = Decls.Const("y", Int()); + ConstDecl declZ = Decls.Const("z", Int()); + + MddVariable z = varOrder.createOnTop(MddVariableDescriptor.create(declZ, 0)); + MddVariable y = varOrder.createOnTop(MddVariableDescriptor.create(declY, 0)); + MddVariable x = varOrder.createOnTop(MddVariableDescriptor.create(declX, 0)); + + // y >= 2 && z = y + 1 && y <= 6 + Expr expr = And(Geq(declY.getRef(), Int(2)), Eq(declZ.getRef(), Add(declY.getRef(), Int(1))), Leq(declY.getRef(), Int(6))); + + SolverPool solverPool = new SolverPool(Z3LegacySolverFactory.getInstance()); + MddNode rootNode = x.checkInNode(MddExpressionTemplate.of(expr, o -> (Decl) o, solverPool)); + + var interpreter = x.getNodeInterpreter(rootNode); + + var recursiveCursor = interpreter.cursor(); + recursiveCursor.moveNext(); + + try (var childCursor = recursiveCursor.valueCursor()) { + childCursor.moveNext(); + childCursor.moveNext(); + childCursor.moveNext(); + childCursor.moveNext(); + } + + final Set valuations = MddValuationCollector.collect(rootNode); + + assertEquals(valuations.size(), 5); + + } + + @Test + public void exprNodeTest4() { + + MddGraph mddGraph = JavaMddFactory.getDefault().createMddGraph(ExprLatticeDefinition.forExpr()); + MddVariableOrder varOrder = JavaMddFactory.getDefault().createMddVariableOrder(mddGraph); + + ConstDecl declX = Decls.Const("x", Int()); + ConstDecl declY = Decls.Const("y", Int()); + ConstDecl declZ = Decls.Const("z", Int()); + + MddVariable y = varOrder.createOnTop(MddVariableDescriptor.create(declY, 0)); + MddVariable x = varOrder.createOnTop(MddVariableDescriptor.create(declX, 0)); + + // x >= 2 && y = x + 1 && x <= 6 && z = y + 2 + Expr expr = And(Geq(declX.getRef(), Int(2)), Eq(declY.getRef(), Add(declX.getRef(), Int(1))), Leq(declX.getRef(), Int(6)), Eq(declZ.getRef(), Add(declY.getRef(), Int(2)))); + + SolverPool solverPool = new SolverPool(Z3LegacySolverFactory.getInstance()); + MddNode rootNode = x.checkInNode(MddExpressionTemplate.of(expr, o -> (Decl) o, solverPool)); + + var interpreter = x.getNodeInterpreter(rootNode); + + var recursiveCursor = interpreter.cursor(); + recursiveCursor.moveNext(); + recursiveCursor.moveNext(); + recursiveCursor.moveNext(); + + try (var childCursor = recursiveCursor.valueCursor()) { + childCursor.moveNext(); + childCursor.moveNext(); + } + + recursiveCursor.moveNext(); + + try (var childCursor2 = recursiveCursor.valueCursor()) { + childCursor2.moveNext(); + childCursor2.moveNext(); + } + + recursiveCursor.moveNext(); + recursiveCursor.moveNext(); + + final Set valuations = MddValuationCollector.collect(rootNode); + + assertEquals(valuations.size(), 5); + + } + + @Test + public void exprNodeTest5() { + + MddGraph mddGraph = JavaMddFactory.getDefault().createMddGraph(ExprLatticeDefinition.forExpr()); + MddVariableOrder varOrder = JavaMddFactory.getDefault().createMddVariableOrder(mddGraph); + + ConstDecl declX = Decls.Const("x", Int()); + ConstDecl declY = Decls.Const("y", Int()); + ConstDecl declZ = Decls.Const("z", Int()); + + MddVariable z = varOrder.createOnTop(MddVariableDescriptor.create(declZ, 0)); + MddVariable y = varOrder.createOnTop(MddVariableDescriptor.create(declY, 0)); + MddVariable x = varOrder.createOnTop(MddVariableDescriptor.create(declX, 0)); + + // x = y && y = z && z = 2 + Expr expr = And(Eq(declX.getRef(), declY.getRef()), And(Eq(declY.getRef(), declZ.getRef()), Eq(declZ.getRef(), Int(2)))); + + SolverPool solverPool = new SolverPool(Z3LegacySolverFactory.getInstance()); + MddNode rootNode = x.checkInNode(MddExpressionTemplate.of(expr, o -> (Decl) o, solverPool)); + + var interpreter = x.getNodeInterpreter(rootNode); + + var recursiveCursor = interpreter.cursor(); + recursiveCursor.moveNext(); + recursiveCursor.moveNext(); + recursiveCursor.moveNext(); + + final Set valuations = MddValuationCollector.collect(rootNode); + + assertEquals(valuations.size(), 1); + + } + + @Test + public void exprNodeTest6() { + + MddGraph mddGraph = JavaMddFactory.getDefault().createMddGraph(ExprLatticeDefinition.forExpr()); + MddVariableOrder varOrder = JavaMddFactory.getDefault().createMddVariableOrder(mddGraph); + + ConstDecl declX = Decls.Const("x", Int()); + ConstDecl declY = Decls.Const("y", Int()); + ConstDecl declZ = Decls.Const("z", Int()); + + MddVariable z = varOrder.createOnTop(MddVariableDescriptor.create(declZ, 0)); + MddVariable y = varOrder.createOnTop(MddVariableDescriptor.create(declY, 0)); + MddVariable x = varOrder.createOnTop(MddVariableDescriptor.create(declX, 0)); + + // x >= 0 && x <= 2 && y >= x && y <= x + 2 && z >= y && z <= y + 2 + Expr expr = And(And(Geq(declX.getRef(), Int(0)), Leq(declX.getRef(), Int(2))), And(Geq(declY.getRef(), declX.getRef()), Leq(declY.getRef(), Add(declX.getRef(), Int(2)))), And(Geq(declZ.getRef(), declY.getRef()), Leq(declZ.getRef(), Add(declY.getRef(), Int(2))))); + + SolverPool solverPool = new SolverPool(Z3LegacySolverFactory.getInstance()); + MddNode rootNode = x.checkInNode(MddExpressionTemplate.of(expr, o -> (Decl) o, solverPool)); + + var interpreter = x.getNodeInterpreter(rootNode); + + var recursiveCursor = interpreter.cursor(); + recursiveCursor.moveNext(); + + try (var childCursor = recursiveCursor.valueCursor()) { + childCursor.moveNext(); + childCursor.moveNext(); + } + + recursiveCursor.moveNext(); + + try (var childCursor2 = recursiveCursor.valueCursor()) { + childCursor2.moveNext(); + childCursor2.moveNext(); + } + + recursiveCursor.moveNext(); + recursiveCursor.moveNext(); + + final Set valuations = MddValuationCollector.collect(rootNode); + + assertEquals(27, valuations.size()); + + } + +} diff --git a/subprojects/common/common/README.md b/subprojects/common/common/README.md index 1e4de07a68..76677718f5 100644 --- a/subprojects/common/common/README.md +++ b/subprojects/common/common/README.md @@ -1 +1,2 @@ -This project provides data structures and utilities that are related to development in general. Some examples are tuples, logging and visualization. \ No newline at end of file +This project provides data structures and utilities that are related to development in general. Some +examples are tuples, logging and visualization. \ No newline at end of file diff --git a/subprojects/common/common/src/main/java/hu/bme/mit/theta/common/GrowingIntArray.java b/subprojects/common/common/src/main/java/hu/bme/mit/theta/common/GrowingIntArray.java new file mode 100644 index 0000000000..c896a29971 --- /dev/null +++ b/subprojects/common/common/src/main/java/hu/bme/mit/theta/common/GrowingIntArray.java @@ -0,0 +1,60 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.common; + +public class GrowingIntArray { + private final int defaultSize; + private final int growingAmount; + + private int lastIndex; + + private int[] array; + + public GrowingIntArray() { + this(100, 100); + } + + public GrowingIntArray(int defaultSize, int growingAmount) { + this.defaultSize = defaultSize; + this.growingAmount = growingAmount; + this.array = new int[defaultSize]; + this.lastIndex = -1; + } + + public int get(int index) { + if (index <= lastIndex) return array[index]; + throw new ArrayIndexOutOfBoundsException(); + } + + public int getSize() { + return lastIndex + 1; + } + + public void add(int value) { + if (lastIndex >= array.length - 1) { + grow(); + } + array[lastIndex + 1] = value; + lastIndex++; + } + + private void grow() { + int[] newArray = new int[array.length + growingAmount]; + System.arraycopy(array, 0, newArray, 0, array.length); + array = newArray; + } + +} diff --git a/subprojects/common/core/README.md b/subprojects/common/core/README.md index 9f7ba668ca..86e9cc3a4f 100644 --- a/subprojects/common/core/README.md +++ b/subprojects/common/core/README.md @@ -1,16 +1,25 @@ -This project provides classes and utilities to build and manipulate first order logic (FOL) expressions, statements and related concepts, which serve as a basis for the formalisms and analyses. +This project provides classes and utilities to build and manipulate first order logic (FOL) +expressions, statements and related concepts, which serve as a basis for the formalisms and +analyses. Classes include + * types (e.g., Boolean, integer, rational, array, bitvector), -see the [`package-info.java`](src/main/java/hu/bme/mit/theta/core/type/package-info.java) for more details, + see the [`package-info.java`](src/main/java/hu/bme/mit/theta/core/type/package-info.java) for more + details, * declarations (e.g., constants, variables), -see the [`package-info.java`](src/main/java/hu/bme/mit/theta/core/decl/package-info.java) for more details, + see the [`package-info.java`](src/main/java/hu/bme/mit/theta/core/decl/package-info.java) for more + details, * expressions (e.g., logical connectives, arithmetic operations), -see the [`package-info.java`](src/main/java/hu/bme/mit/theta/core/type/package-info.java) for more details, + see the [`package-info.java`](src/main/java/hu/bme/mit/theta/core/type/package-info.java) for more + details, * models (e.g., assignments, valuations), -see the [`package-info.java`](src/main/java/hu/bme/mit/theta/core/model/package-info.java) for more details, + see the [`package-info.java`](src/main/java/hu/bme/mit/theta/core/model/package-info.java) for + more details, * statements (e.g., assign, assume, havoc), -see the [`package-info.java`](src/main/java/hu/bme/mit/theta/core/stmt/package-info.java) for more details. + see the [`package-info.java`](src/main/java/hu/bme/mit/theta/core/stmt/package-info.java) for more + details. Utilities include folding, unfolding, collecting atoms, collecting variables, etc., -see the [`package-info.java`](src/main/java/hu/bme/mit/theta/core/utils/package-info.java) for more details. +see the [`package-info.java`](src/main/java/hu/bme/mit/theta/core/utils/package-info.java) for more +details. diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/Expr.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/Expr.java index 75ccd8a3af..bbcae821fe 100644 --- a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/Expr.java +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/Expr.java @@ -32,6 +32,15 @@ public interface Expr { List> getOps(); + default boolean isInvalid() { + for (var op : getOps()) { + if (op.isInvalid()) { + return true; + } + } + return false; + } + Expr withOps(List> ops); default Expr map(final Function, ? extends Expr> function) { diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/anytype/InvalidLitExpr.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/anytype/InvalidLitExpr.java new file mode 100644 index 0000000000..baa3ea487b --- /dev/null +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/anytype/InvalidLitExpr.java @@ -0,0 +1,51 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.core.type.anytype; + +import com.google.common.base.Preconditions; +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.LitExpr; +import hu.bme.mit.theta.core.type.NullaryExpr; +import hu.bme.mit.theta.core.type.Type; + +public class InvalidLitExpr extends NullaryExpr implements LitExpr { + + private final ExprType type; + + public InvalidLitExpr(ExprType type) { + this.type = Preconditions.checkNotNull(type); + } + + @Override + public ExprType getType() { + return type; + } + + @Override + public LitExpr eval(Valuation val) { + return this; + } + + @Override + public boolean isInvalid() { + return true; + } + + @Override + public boolean equals(Object obj) { + return false; + } +} diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumType.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumType.java index bbf47e3d49..b8c8ebb5c0 100644 --- a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumType.java +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumType.java @@ -17,10 +17,12 @@ import hu.bme.mit.theta.core.type.DomainSize; import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.LitExpr; import hu.bme.mit.theta.core.type.Type; import hu.bme.mit.theta.core.type.abstracttype.EqExpr; import hu.bme.mit.theta.core.type.abstracttype.Equational; import hu.bme.mit.theta.core.type.abstracttype.NeqExpr; +import hu.bme.mit.theta.core.type.anytype.InvalidLitExpr; import java.util.Collection; import java.util.LinkedHashMap; @@ -89,12 +91,16 @@ public String getName() { return name; } + public int getIntValue(EnumLitExpr literal) { + return getIntValue(literal.getValue()); + } + public int getIntValue(String literal) { checkArgument(literals.containsKey(literal), String.format("Enum type %s does not contain literal '%s'", name, literal)); return literals.get(literal); } - public EnumLitExpr litFromLongName(String longName) { + public LitExpr litFromLongName(String longName) { if (!longName.contains(FULLY_QUALIFIED_NAME_SEPARATOR)) throw new RuntimeException(String.format("%s is an invalid enum longname")); String[] parts = longName.split(Pattern.quote(FULLY_QUALIFIED_NAME_SEPARATOR)); @@ -107,6 +113,15 @@ public EnumLitExpr litFromLongName(String longName) { } } + public LitExpr litFromIntValue(int value) { + for (Map.Entry entry : literals.entrySet()) { + if (entry.getValue() == value) { + return EnumLitExpr.of(this, entry.getKey()); + } + } + return new InvalidLitExpr<>(this); + } + @Override public String toString() { return String.format("EnumType{%s}", name); diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java index cbdee2d98b..f46173b44b 100644 --- a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java @@ -23,6 +23,7 @@ import hu.bme.mit.theta.core.type.LitExpr; import hu.bme.mit.theta.core.type.Type; import hu.bme.mit.theta.core.type.anytype.Dereference; +import hu.bme.mit.theta.core.type.anytype.InvalidLitExpr; import hu.bme.mit.theta.core.type.anytype.IteExpr; import hu.bme.mit.theta.core.type.anytype.RefExpr; import hu.bme.mit.theta.core.type.arraytype.ArrayInitExpr; @@ -70,6 +71,9 @@ public static ExprSimplifier create(final SimplifierLevel level) { @SuppressWarnings("unchecked") public Expr simplify(final Expr expr, final Valuation valuation) { + if (expr.isInvalid()) { + return new InvalidLitExpr<>(expr.getType()); + } return (Expr) TABLE.dispatch(expr, valuation); } diff --git a/subprojects/common/grammar/src/main/java/hu/bme/mit/theta/grammar/dsl/stmt/StmtParser.kt b/subprojects/common/grammar/src/main/java/hu/bme/mit/theta/grammar/dsl/stmt/StmtParser.kt index f06550fdab..09ea6e8f9d 100644 --- a/subprojects/common/grammar/src/main/java/hu/bme/mit/theta/grammar/dsl/stmt/StmtParser.kt +++ b/subprojects/common/grammar/src/main/java/hu/bme/mit/theta/grammar/dsl/stmt/StmtParser.kt @@ -70,8 +70,8 @@ class StatementWrapper(val content: String, scope: Scope) { private val env: Env init { - this.scope = Preconditions.checkNotNull(scope) - this.env = Preconditions.checkNotNull(env) + this.scope = scope!! // TODO replaced a checkNotNull with !! here + this.env = env!! // TODO replaced a checkNotNull with !! here } override fun visitSkipStmt(ctx: SkipStmtContext): Stmt { diff --git a/subprojects/common/grammar/src/main/java/hu/bme/mit/theta/grammar/gson/ArgAdapter.kt b/subprojects/common/grammar/src/main/java/hu/bme/mit/theta/grammar/gson/ArgAdapter.kt index 3eee50d6ea..a05598f87e 100644 --- a/subprojects/common/grammar/src/main/java/hu/bme/mit/theta/grammar/gson/ArgAdapter.kt +++ b/subprojects/common/grammar/src/main/java/hu/bme/mit/theta/grammar/gson/ArgAdapter.kt @@ -23,7 +23,7 @@ import com.google.gson.stream.JsonWriter import hu.bme.mit.theta.analysis.Action import hu.bme.mit.theta.analysis.PartialOrd import hu.bme.mit.theta.analysis.State -import hu.bme.mit.theta.analysis.algorithm.ARG +import hu.bme.mit.theta.analysis.algorithm.arg.ARG import java.lang.reflect.Type class ArgAdapter(val gsonSupplier: () -> Gson, diff --git a/subprojects/common/grammar/src/main/java/hu/bme/mit/theta/grammar/gson/ArgAdapterHelper.kt b/subprojects/common/grammar/src/main/java/hu/bme/mit/theta/grammar/gson/ArgAdapterHelper.kt index 84d2880624..f00ff2ac89 100644 --- a/subprojects/common/grammar/src/main/java/hu/bme/mit/theta/grammar/gson/ArgAdapterHelper.kt +++ b/subprojects/common/grammar/src/main/java/hu/bme/mit/theta/grammar/gson/ArgAdapterHelper.kt @@ -19,8 +19,8 @@ package hu.bme.mit.theta.grammar.gson import hu.bme.mit.theta.analysis.Action import hu.bme.mit.theta.analysis.PartialOrd import hu.bme.mit.theta.analysis.State -import hu.bme.mit.theta.analysis.algorithm.ARG -import hu.bme.mit.theta.analysis.algorithm.ArgNode +import hu.bme.mit.theta.analysis.algorithm.arg.ARG +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNode data class ArgAdapterHelper( val initNodes: Map>, diff --git a/subprojects/common/grammar/src/main/java/hu/bme/mit/theta/grammar/gson/SafetyResultAdapter.kt b/subprojects/common/grammar/src/main/java/hu/bme/mit/theta/grammar/gson/SafetyResultAdapter.kt index d3d9647f3e..6829d577c0 100644 --- a/subprojects/common/grammar/src/main/java/hu/bme/mit/theta/grammar/gson/SafetyResultAdapter.kt +++ b/subprojects/common/grammar/src/main/java/hu/bme/mit/theta/grammar/gson/SafetyResultAdapter.kt @@ -24,7 +24,7 @@ import com.google.gson.stream.JsonWriter import hu.bme.mit.theta.analysis.Action import hu.bme.mit.theta.analysis.State import hu.bme.mit.theta.analysis.Trace -import hu.bme.mit.theta.analysis.algorithm.ARG +import hu.bme.mit.theta.analysis.algorithm.arg.ARG import hu.bme.mit.theta.analysis.algorithm.SafetyResult import hu.bme.mit.theta.analysis.algorithm.Statistics import java.lang.reflect.Type @@ -34,17 +34,18 @@ class SafetyResultAdapter( val gsonSupplier: () -> Gson, private val argTypeSupplier: () -> Type, private val traceTypeSupplier: () -> Type, -) : TypeAdapter>() { +) : TypeAdapter, Trace>>() { private lateinit var gson: Gson private lateinit var argType: Type private lateinit var traceType: Type - override fun write(writer: JsonWriter, value: SafetyResult) { + override fun write(writer: JsonWriter, + value: SafetyResult, Trace>) { initGson() writer.beginObject() writer.name("arg") - gson.toJson(gson.toJsonTree(value.arg), writer) + gson.toJson(gson.toJsonTree(value.witness), writer) writer.name("stats") // gson.toJson(gson.toJsonTree(value.stats), writer) gson.toJson(gson.toJsonTree(Optional.empty()), writer) @@ -54,12 +55,12 @@ class SafetyResultAdapter( val unsafe = value.asUnsafe() writer.name("safe").value(false) writer.name("trace") - gson.toJson(gson.toJsonTree(unsafe.trace), writer) + gson.toJson(gson.toJsonTree(unsafe.cex), writer) } writer.endObject() } - override fun read(reader: JsonReader): SafetyResult { + override fun read(reader: JsonReader): SafetyResult, Trace> { initGson() initTypes() lateinit var arg: ARG diff --git a/subprojects/common/grammar/src/test/java/hu/bme/mit/theta/grammar/gson/TestGson.kt b/subprojects/common/grammar/src/test/java/hu/bme/mit/theta/grammar/gson/TestGson.kt index 0fddcb4d8b..cb6ca93071 100644 --- a/subprojects/common/grammar/src/test/java/hu/bme/mit/theta/grammar/gson/TestGson.kt +++ b/subprojects/common/grammar/src/test/java/hu/bme/mit/theta/grammar/gson/TestGson.kt @@ -24,7 +24,7 @@ import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonWriter import hu.bme.mit.theta.analysis.PartialOrd import hu.bme.mit.theta.analysis.Trace -import hu.bme.mit.theta.analysis.algorithm.ARG +import hu.bme.mit.theta.analysis.algorithm.arg.ARG import hu.bme.mit.theta.analysis.algorithm.SafetyResult import hu.bme.mit.theta.analysis.expl.ExplOrd import hu.bme.mit.theta.analysis.expl.ExplState diff --git a/subprojects/common/multi-tests/src/test/kotlin/multi/MultiAlternatingTest.kt b/subprojects/common/multi-tests/src/test/kotlin/multi/MultiAlternatingTest.kt index e325f3a933..0e22456a0d 100644 --- a/subprojects/common/multi-tests/src/test/kotlin/multi/MultiAlternatingTest.kt +++ b/subprojects/common/multi-tests/src/test/kotlin/multi/MultiAlternatingTest.kt @@ -107,7 +107,7 @@ class MultiAlternatingTest { val result = multiConfigBuilder.build().check() assertTrue(result.isUnsafe) - assertEquals(8, result.asUnsafe().trace.length()) + assertEquals(8, result.asUnsafe().cex.length()) } @Test diff --git a/subprojects/frontends/c-frontend/README.md b/subprojects/frontends/c-frontend/README.md index afee8c8893..02a5b36fe2 100644 --- a/subprojects/frontends/c-frontend/README.md +++ b/subprojects/frontends/c-frontend/README.md @@ -1,20 +1,26 @@ # ANTLR-Based C-Frontend for Verification -This subproject adds an ANTLR-grammar based C-Frontend to Theta. This is independent of any formalism, and aims to be as widely applicable as possible. +This subproject adds an ANTLR-grammar based C-Frontend to Theta. This is independent of any +formalism, and aims to be as widely applicable as possible. ## Features This frontend can handle preprocessed .c or .i file with the following features: -* Basic C support: global declarations (functions and variables), function definitions, loops, various data types, global typedefs, etc. -* Integer- and bitvector-arithmetic support based on required features (e.g. for floats or bitwise operators bitvector precision is necessary) +* Basic C support: global declarations (functions and variables), function definitions, loops, + various data types, global typedefs, etc. +* Integer- and bitvector-arithmetic support based on required features (e.g. for floats or bitwise + operators bitvector precision is necessary) * Basic struct and array support * Basic (and experimental) flat-memory based pointer handling * ILP32 and LP64 type system support (with possible extensibility) ## Limitations, known bugs -A number of features are either not well tested or in certain aspects buggy. Error handling is done on a best-effort level as the C specification is way too complex to handle entirely correctly. In most cases an error, or a warning message is displayed, but in some unexpected situations a silent failure is also possible. +A number of features are either not well tested or in certain aspects buggy. Error handling is done +on a best-effort level as the C specification is way too complex to handle entirely correctly. In +most cases an error, or a warning message is displayed, but in some unexpected situations a silent +failure is also possible. In particular, the following features are either not implemented or can produce buggy models: @@ -27,10 +33,15 @@ In particular, the following features are either not implemented or can produce * Using a non-specific subtype of `char` (produces a warning) - use `(un)signed char` instead * Includes and other preprocessor directives (produces an exception or fails silently!) * Arrays are not pointers and pointers cannot be used as arrays (produces an exception) -* Memory access is _not_ checked, and therefore it is easy to receive a faulty value by over-indexing an array (fails silently!) -* Array elements are not range-checked and therefore false positives are possible (consider `char c[2]; if(c[1] > 500) reach_error()`) +* Memory access is _not_ checked, and therefore it is easy to receive a faulty value by + over-indexing an array (fails silently!) +* Array elements are not range-checked and therefore false positives are possible ( + consider `char c[2]; if(c[1] > 500) reach_error()`) -Note that only program elements that are (transitively) reachable from main() are checked against any violation of the above criteria, i.e. a program containing unsupported elements that are not utilized is handled correctly. This is necessary for handling most preprocessed (.i) files, as the standard library includes a lot of complex and unsupported code. +Note that only program elements that are (transitively) reachable from main() are checked against +any violation of the above criteria, i.e. a program containing unsupported elements that are not +utilized is handled correctly. This is necessary for handling most preprocessed (.i) files, as the +standard library includes a lot of complex and unsupported code. ## High-Level Process @@ -45,10 +56,10 @@ The workflow to get a formal model from a C file is the following: The _IM_ is an interlinked model of the following elements: * CAssignment: variable assignment -* CAssume: an assumption over the range of a variable +* CAssume: an assumption over the range of a variable * CBreak: the _break_ C instruction * CCall: function call to a C-type function -* CCase: a branch (_case_) of a switch-case statement +* CCase: a branch (_case_) of a switch-case statement * CCompound: a compound statement (0..* statements inside braces) * CContinue: the _continue_ C instruction * CDecls: variable declarations @@ -60,9 +71,12 @@ The _IM_ is an interlinked model of the following elements: * CGoto: _goto_ statement * CIf: a conditional branching statement * CInitializerList: initializer list for arrays, structs and other complex structures -* CProgram: the root element +* CProgram: the root element * CRet: return statement from a function * CSwitch: a switch-case statement * CWhile: a while loop statement -To map these statements to elements of a formal model, the `hu.bme.mit.theta.frontend.transformation.model.statements.CStatementVisitorBase` class can be used through inheritance. An example can be found in `hu.bme.mit.theta.xcfa.model.utils.FrontendXcfaBuilder`. +To map these statements to elements of a formal model, +the `hu.bme.mit.theta.frontend.transformation.model.statements.CStatementVisitorBase` class can be +used through inheritance. An example can be found +in `hu.bme.mit.theta.xcfa.model.utils.FrontendXcfaBuilder`. diff --git a/subprojects/frontends/c-frontend/src/main/java/hu/bme/mit/theta/frontend/transformation/Readme.md b/subprojects/frontends/c-frontend/src/main/java/hu/bme/mit/theta/frontend/transformation/Readme.md index 8aeb2758f4..70cbcb3260 100644 --- a/subprojects/frontends/c-frontend/src/main/java/hu/bme/mit/theta/frontend/transformation/Readme.md +++ b/subprojects/frontends/c-frontend/src/main/java/hu/bme/mit/theta/frontend/transformation/Readme.md @@ -1,10 +1,15 @@ # Antlr-based C frontend -This package is responsible for the transformation of C language programs to formal models. The overview of this process is the following: +This package is responsible for the transformation of C language programs to formal models. The +overview of this process is the following: 1. The C file (.c/.h/.i) is parsed by the following classes: - 1. FunctionVisitor - this provides CStatements, such as CPrograms, CFunctions and regular C-like statements (assignments, function calls, etc) + 1. FunctionVisitor - this provides CStatements, such as CPrograms, CFunctions and regular C-like + statements (assignments, function calls, etc) 2. TypeVisitor - this provides CType information, such as ints, enums, floats, arrays, etc. - 3. ExpressionVisitor - this provides Theta Expr instances that represent expressions in the source file - 4. DeclarationVisitor - this provides CDecl instances, which provide information on declared variables -2. The topmost CStatement (a CProgram instance) can be _built_, i.e. transformed into a formal model. This will recursively instantiate parts of the model until all statements are consumed. + 3. ExpressionVisitor - this provides Theta Expr instances that represent expressions in the + source file + 4. DeclarationVisitor - this provides CDecl instances, which provide information on declared + variables +2. The topmost CStatement (a CProgram instance) can be _built_, i.e. transformed into a formal + model. This will recursively instantiate parts of the model until all statements are consumed. diff --git a/subprojects/frontends/llvm/README.md b/subprojects/frontends/llvm/README.md index 20e54f117a..d0785d2a34 100644 --- a/subprojects/frontends/llvm/README.md +++ b/subprojects/frontends/llvm/README.md @@ -1,38 +1,72 @@ # Theta C Frontend -This repository contains a library, which enables Theta to parse C programs into the XCFA or CFA format using LLVM. + +This repository contains a library, which enables Theta to parse C programs into the XCFA or CFA +format using LLVM. # Motivation -Trying to directly transform a C program into a formal representation comes with several problems due to the complexity of the C language. Using an assembly-like internal representation, such as LLVM IR can largely decrease this complexity. -Currently there is no official LLVM Java API, thus a C++ project is necessary to handle the parsing of LLVM bytecode. +Trying to directly transform a C program into a formal representation comes with several problems +due to the complexity of the C language. Using an assembly-like internal representation, such as +LLVM IR can largely decrease this complexity. + +Currently there is no official LLVM Java API, thus a C++ project is necessary to handle the parsing +of LLVM bytecode. # Connection with Theta + [Link to Theta](https://github.com/ftsrg/theta) -Theta is a configurable and modular, CEGAR-based verification framework. It is capable of handling several formalisms, including Control Flow Automaton *(CFA)* and an extended version of CFA, called XCFA. *(The latter can handle functions and (concurrent) processes.)* +Theta is a configurable and modular, CEGAR-based verification framework. It is capable of handling +several formalisms, including Control Flow Automaton *(CFA)* and an extended version of CFA, called +XCFA. *(The latter can handle functions and (concurrent) processes.)* -Theta has a CLI tool and a module for parsing CFA/XCFA files and can convert an XCFA to a CFA, if it is possible *(if it has only one function and one process)*, but has no capability to transform C programs or any other representation of them to these formalisms. +Theta has a CLI tool and a module for parsing CFA/XCFA files and can convert an XCFA to a CFA, if it +is possible *(if it has only one function and one process)*, but has no capability to transform C +programs or any other representation of them to these formalisms. # Connection with Gazer -[Link to Gazer](https://github.com/ftsrg/gazer) - -Gazer is a BMC verification tool and Theta frontend written in C++, using the LLVM framework. It handles the transformation to CFA from the C program by itself with an intermediate CFA representation used in its BMC engine. It works as a literal frontend, a CLI tool which handles the transformation and which can call Theta for analysis, parsing and using it's output to get a counterexample. -Gazer is the predecessor of this library. Many of this its techniques and implementation details are used in this library, but this project has a different, simpler approach. It aims to carry out only a fraction of Gazer's functionality, namely it has no BMC engine, so it cannot carry out software verification and it will not output a CFA or an XCFA in any way. It carries out only the transformation of a C program to an intermediate representation containing the necessary information for the construction of an XCFA, adding some LLVM passes on the way. +[Link to Gazer](https://github.com/ftsrg/gazer) -As opposed to Gazer, this library approaches its usage in a reversed manner, being called and used by Theta as a native C++ library, not the other way around. It's long term goal is to be a fairly static library in a way, that extensions and implementation of new features related to the formalisms or the analysis can happen mainly in Theta, as it has better maintainability and is actively developed. +Gazer is a BMC verification tool and Theta frontend written in C++, using the LLVM framework. It +handles the transformation to CFA from the C program by itself with an intermediate CFA +representation used in its BMC engine. It works as a literal frontend, a CLI tool which handles the +transformation and which can call Theta for analysis, parsing and using it's output to get a +counterexample. + +Gazer is the predecessor of this library. Many of this its techniques and implementation details are +used in this library, but this project has a different, simpler approach. It aims to carry out only +a fraction of Gazer's functionality, namely it has no BMC engine, so it cannot carry out software +verification and it will not output a CFA or an XCFA in any way. It carries out only the +transformation of a C program to an intermediate representation containing the necessary information +for the construction of an XCFA, adding some LLVM passes on the way. + +As opposed to Gazer, this library approaches its usage in a reversed manner, being called and used +by Theta as a native C++ library, not the other way around. It's long term goal is to be a fairly +static library in a way, that extensions and implementation of new features related to the +formalisms or the analysis can happen mainly in Theta, as it has better maintainability and is +actively developed. # Transforming the program + ![architecture](doc/theta-c-arch.png) -*The red parts are modules/classes of Theta, the green ones are of this project and the blue ones are yet to be implemented - they are not properly connected yet, as their place in the project isn't certain yet* +*The red parts are modules/classes of Theta, the green ones are of this project and the blue ones +are yet to be implemented - they are not properly connected yet, as their place in the project isn't +certain yet* ## Input -The input file can either be bitcode (`.ll` pr `.bc`, LLVM passes are not used in this case) or a C program (a single `.c` or `.i` file). Implementing a linking step of more than one input files is not yet implemented. *(But it is an important feature for the future.)* + +The input file can either be bitcode (`.ll` pr `.bc`, LLVM passes are not used in this case) or a C +program (a single `.c` or `.i` file). Implementing a linking step of more than one input files is +not yet implemented. *(But it is an important feature for the future.)* ## Compilation (clang) -This is a simple step - we just call clang with a few flags to compile the C program to bitcode. We use O0, as most optimization passes that we benefit from are executed in the next step. + +This is a simple step - we just call clang with a few flags to compile the C program to bitcode. We +use O0, as most optimization passes that we benefit from are executed in the next step. ## Documentation of the remaining steps + [Our intermediate representation](doc/intermediate-representation.md) [Passes and optimizations](doc/passes.md) diff --git a/subprojects/frontends/llvm/doc/analysis.md b/subprojects/frontends/llvm/doc/analysis.md index e9af4a0144..a238009fa4 100644 --- a/subprojects/frontends/llvm/doc/analysis.md +++ b/subprojects/frontends/llvm/doc/analysis.md @@ -1,14 +1,22 @@ ## What analysis steps mean in this case -These are simple "checks", executed while the IR is parsed into our representation (so we won't need to explicitly iterate through it twice). + +These are simple "checks", executed while the IR is parsed into our representation (so we won't need +to explicitly iterate through it twice). ### Struct check -Using an `llvm::Typefinder`, we check if there are any struct (or union) type definitions in the module. This information is then stored and can be queried. + +Using an `llvm::Typefinder`, we check if there are any struct (or union) type definitions in the +module. This information is then stored and can be queried. ### Logical operator check -This check is called for each instruction. The goal of this check is to decide, if Theta can use integer arithmetics or only the more costly bitwise arithmetics. + +This check is called for each instruction. The goal of this check is to decide, if Theta can use +integer arithmetics or only the more costly bitwise arithmetics. #### How it works + Steps executed on each instruction: + - Is it an `and/or/xor` operation? - If **yes**, is it only used later in `icmp` operations with 0 as the other operand? - If **yes**, *integer arithmetics* are suitable @@ -17,4 +25,5 @@ Steps executed on each instruction: - If **yes**, we'll need *bitwise arithmetics* - If **no**, *integer arithmetics* are suitable -*Clarification: this is a global attribute in the sense, that if any instruction requires integer arithmetics, then the whole program has to be handled that way.* +*Clarification: this is a global attribute in the sense, that if any instruction requires integer +arithmetics, then the whole program has to be handled that way.* diff --git a/subprojects/frontends/llvm/doc/intermediate-representation.md b/subprojects/frontends/llvm/doc/intermediate-representation.md index 3b249ded38..4e4cf37a63 100644 --- a/subprojects/frontends/llvm/doc/intermediate-representation.md +++ b/subprojects/frontends/llvm/doc/intermediate-representation.md @@ -1,10 +1,25 @@ ## Intermediate representation between LLVM IR and the XCFA models -As we can see in the architecture, the C input program is compiled into LLVM IR. LLVM intermediate representation is an assembly-like representation with around 60 instructions and lots of possibilities for adding metadata. -It can be easily parsed through the LLVM API, but contains a large quantity of complex information, from which we only need to extract particular elements required for the XCFA and the projection of counterexamples on to the original program. To accomplish this we use a simpler representation, which is in many points similar to the programmatic representation of LLVM IR, but differs in some particular places and contains no superfluous data (from our standpoint). +As we can see in the architecture, the C input program is compiled into LLVM IR. LLVM intermediate +representation is an assembly-like representation with around 60 instructions and lots of +possibilities for adding metadata. -The classes for this representation can be found in the [types](https://github.com/ftsrg/theta-c-frontend/tree/master/src/types) directory. +It can be easily parsed through the LLVM API, but contains a large quantity of complex information, +from which we only need to extract particular elements required for the XCFA and the projection of +counterexamples on to the original program. To accomplish this we use a simpler representation, +which is in many points similar to the programmatic representation of LLVM IR, but differs in some +particular places and contains no superfluous data (from our standpoint). -It is similar to LLVM IR in that there is a module, which contains global variables and functions. Functions contain basic blocks, basic blocks are made of instructions, which have operands. It differs in that there are no explicit metadata classes, rather the above mentioned classes contain metadata about themselves. +The classes for this representation can be found in +the [types](https://github.com/ftsrg/theta-c-frontend/tree/master/src/types) directory. -Furthermore on instruction level the LLVM IR has no classes explicitly representing (virtual) registers and instruction operands - these are handled as instructions, constants or other appropriate types. In our representation instruction contains Operands, an abstract class and parent class of Register, BasicBlockOperand and StringOperand. The latter is used to handle function operands in `call` instructions and special strings like the condition code in `icmp` operations. +It is similar to LLVM IR in that there is a module, which contains global variables and functions. +Functions contain basic blocks, basic blocks are made of instructions, which have operands. It +differs in that there are no explicit metadata classes, rather the above mentioned classes contain +metadata about themselves. + +Furthermore on instruction level the LLVM IR has no classes explicitly representing (virtual) +registers and instruction operands - these are handled as instructions, constants or other +appropriate types. In our representation instruction contains Operands, an abstract class and parent +class of Register, BasicBlockOperand and StringOperand. The latter is used to handle function +operands in `call` instructions and special strings like the condition code in `icmp` operations. diff --git a/subprojects/frontends/llvm/doc/jni-interface.md b/subprojects/frontends/llvm/doc/jni-interface.md index 4c7af9f1a1..d94fbfa23f 100644 --- a/subprojects/frontends/llvm/doc/jni-interface.md +++ b/subprojects/frontends/llvm/doc/jni-interface.md @@ -1,21 +1,35 @@ ## JNI Interface -*"In software design, the Java Native Interface (JNI) is a foreign function interface programming framework that enables Java code running in a Java virtual machine (JVM) to call and be called by native applications (programs specific to a hardware and operating system platform) and libraries written in other languages such as C, C++ and assembly."* (from [wikipedia](https://en.wikipedia.org/wiki/Java_Native_Interface)) -This project behaves as a native library of the Theta framework and communicates through a JNI interface. Although it is possible to send objects through a native interface, we are currently not using that feature. +*"In software design, the Java Native Interface (JNI) is a foreign function interface programming +framework that enables Java code running in a Java virtual machine (JVM) to call and be called by +native applications (programs specific to a hardware and operating system platform) and libraries +written in other languages such as C, C++ and assembly."* ( +from [wikipedia](https://en.wikipedia.org/wiki/Java_Native_Interface)) -The easiest way to get familiar with the interface is to check out the C++ side [here](https://github.com/ftsrg/theta-c-frontend/blob/master/src/hu_bme_mit_theta_llvm2xcfa_LlvmIrProvider.h) and the Java side in Theta (`LllvmIrProvider` class of the XCFA subproject). +This project behaves as a native library of the Theta framework and communicates through a JNI +interface. Although it is possible to send objects through a native interface, we are currently not +using that feature. + +The easiest way to get familiar with the interface is to check out the C++ +side [here](https://github.com/ftsrg/theta-c-frontend/blob/master/src/hu_bme_mit_theta_llvm2xcfa_LlvmIrProvider.h) +and the Java side in Theta (`LllvmIrProvider` class of the XCFA subproject). ### Configuring passes and parsing the input program + Currently there are four switches to configure pass groups (the rest of the passes are mandatory). + - Function inlining (we do not inline global variables) - Cleanup passes - Optimizations - Debug printing pass -After configuration the native function `JniParseIr` has to be called to let the frontend iterate through the LLVM IR. +After configuration the native function `JniParseIr` has to be called to let the frontend iterate +through the LLVM IR. ### Querying the resulting data + The data can be queried based on these groups: + - global variables - functions - basic blocks diff --git a/subprojects/frontends/llvm/doc/passes.md b/subprojects/frontends/llvm/doc/passes.md index bd2e3c86b6..0b4fa2f9f6 100644 --- a/subprojects/frontends/llvm/doc/passes.md +++ b/subprojects/frontends/llvm/doc/passes.md @@ -1,22 +1,53 @@ ## Passes used + ### About LLVM passes in general -Passes provide a system to run optimization, transformation and analysis steps on LLVM IR. These can be LLVMs official passes, but custom passes as well. This project uses both. + +Passes provide a system to run optimization, transformation and analysis steps on LLVM IR. These can +be LLVMs official passes, but custom passes as well. This project uses both. [more on LLVM passes](https://llvm.org/docs/Passes.html) -This part of the project adopts the most from Gazer. LLVM and custom passes are used there similarly as well, although Gazer has a more complex and less naive approach, e.g. using early and late optimization sets. In this project we are approaching the problems and functionality in a direct manner, thus we have only a simpler, single execution line of passes. +This part of the project adopts the most from Gazer. LLVM and custom passes are used there similarly +as well, although Gazer has a more complex and less naive approach, e.g. using early and late +optimization sets. In this project we are approaching the problems and functionality in a direct +manner, thus we have only a simpler, single execution line of passes. ### What are we using passes for + 1. Optimizations -2. Transformations +2. Transformations 3. Annotations -*Disclaimer: this part of the project isn't static, as we are constantly experimenting with changing/adding new passes. Due to this, some important custom passes are described here, but to get the precise state of what passes we use and what they do, start from [this](https://github.com/ftsrg/theta-c-frontend/blob/master/src/utilities/CPipeline.cpp) source file.* +*Disclaimer: this part of the project isn't static, as we are constantly experimenting with +changing/adding new passes. Due to this, some important custom passes are described here, but to get +the precise state of what passes we use and what they do, start +from [this](https://github.com/ftsrg/theta-c-frontend/blob/master/src/utilities/CPipeline.cpp) +source file.* + ### Custom passes + - **Toposort pass** - Strongly connected components (e.g. loops) of basic blocks aren't necessarily in topological order in LLVM IR as this way it is possible to iterate through the blocks in order and have unknown values only in phi nodes, which makes the model transformation in Theta simpler + Strongly connected components (e.g. loops) of basic blocks aren't necessarily in topological order + in LLVM IR as this way it is possible to iterate through the blocks in order and have unknown + values only in phi nodes, which makes the model transformation in Theta simpler - **Eliminate GEP instructions pass** - The getelementptr instruction is a special instruction in LLVM IR, which usually pairs with one or more store and load instructions to get/set memory values. In the XCFA this instruction pair is handled as a single instruction on a single edge, but transforming to this format is complex. Instead of that we use this transformation pass to combine the information from these pairs into a single `theta.dbg.getArrayElement_typename` or `theta.dbg.setArrayElement_typename` function calls while removing the `getelementptr` and `load/store` instructions. *Support in this pass is currently incomplete, as there can be special parametrizations in these instructions when structs or unions are used, so that has to be added when extending the frontend with struct support in the future.* + The getelementptr instruction is a special instruction in LLVM IR, which usually pairs with one or + more store and load instructions to get/set memory values. In the XCFA this instruction pair is + handled as a single instruction on a single edge, but transforming to this format is complex. + Instead of that we use this transformation pass to combine the information from these pairs into a + single `theta.dbg.getArrayElement_typename` or `theta.dbg.setArrayElement_typename` function calls + while removing the `getelementptr` and `load/store` instructions. *Support in this pass is + currently incomplete, as there can be special parametrizations in these instructions when structs + or unions are used, so that has to be added when extending the frontend with struct support in the + future.* - **Eliminate Phi nodes pass** - When verifying a model with CEGAR, the number of variables can be a crucial point. Phi nodes can basically add a variable per each node, although it wasn't present in the original program and wouldn't be necessary. This pass eliminates these unnecessary variables, where possible and uses a global variable with unique identifiers to store these values instead. + When verifying a model with CEGAR, the number of variables can be a crucial point. Phi nodes can + basically add a variable per each node, although it wasn't present in the original program and + wouldn't be necessary. This pass eliminates these unnecessary variables, where possible and uses a + global variable with unique identifiers to store these values instead. - **Branch dbg call pass** *(work in progress)* - This pass adds a function called `theta.dbg.control` before each `br` *(branch)* instruction. On one hand, adding metadata to this call will make it easier to add *control* information to witnesses, on the other hand it tones down the CFG simplification pass, which is an important optimization, but can also be quite aggressive when merging control flow branches with which we lose *(or even get wrong)* program line metadata. False information on program lines can lead to unusable witnesses. + This pass adds a function called `theta.dbg.control` before each `br` *(branch)* instruction. On + one hand, adding metadata to this call will make it easier to add *control* information to + witnesses, on the other hand it tones down the CFG simplification pass, which is an important + optimization, but can also be quite aggressive when merging control flow branches with which we + lose *(or even get wrong)* program line metadata. False information on program lines can lead to + unusable witnesses. diff --git a/subprojects/frontends/llvm/doc/simple-example.md b/subprojects/frontends/llvm/doc/simple-example.md index d35c76d922..f527aebb21 100644 --- a/subprojects/frontends/llvm/doc/simple-example.md +++ b/subprojects/frontends/llvm/doc/simple-example.md @@ -1,6 +1,9 @@ ## A simple example + ### Input + Let's give a simple example program as input: + ``` C #include @@ -15,8 +18,11 @@ int main() { ``` ### LLVM IR + After compilation with clang and executing the passes, we get the following LLVM IR: -*(Note: LLVM IR is rather verbose, so some attributes have been cut out from the middle, as they are insignificant in this example)* +*(Note: LLVM IR is rather verbose, so some attributes have been cut out from the middle, as they are +insignificant in this example)* + ```llvm ; ModuleID = 'example.bc' source_filename = "example.c" @@ -73,22 +79,40 @@ declare void @llvm.dbg.value(metadata, metadata, metadata) #2 !20 = !DILocation(line: 9, column: 5, scope: !9) ``` + There are two important parts in the IR: -- the IR version of the main function, starting from `define dso_local i32 @main() local_unnamed_addr #0 !dbg !9 {` -- and the metadata in the second half - each line starting with a `!` and a number represents some kind of metadata, e.g. `!14 = !DILocalVariable(name: "a", scope: !9, file: !10, line: 4, type: !13)` tells us, that the register annotated with `!14` is connected to the local variable `a`. -We can also notice the SSA (single static assignment) nature of LLVM IR in this example: `!17` shows in `main` more than once, as each time `b` has a new value assigned, a new register has to be created, as virtual registers in LLVM can only be assigned once. +- the IR version of the main function, starting + from `define dso_local i32 @main() local_unnamed_addr #0 !dbg !9 {` +- and the metadata in the second half - each line starting with a `!` and a number represents some + kind of metadata, + e.g. `!14 = !DILocalVariable(name: "a", scope: !9, file: !10, line: 4, type: !13)` tells us, that + the register annotated with `!14` is connected to the local variable `a`. + +We can also notice the SSA (single static assignment) nature of LLVM IR in this example: `!17` shows +in `main` more than once, as each time `b` has a new value assigned, a new register has to be +created, as virtual registers in LLVM can only be assigned once. ### Our intermediate representation -The customized representation we use has no textual syntax, as it would be superfluous, rather it can be shown as a class hierarchy, loosely following that of LLVM IR. + +The customized representation we use has no textual syntax, as it would be superfluous, rather it +can be shown as a class hierarchy, loosely following that of LLVM IR. It is noteworthy to mention some of the differences here: + - LLVM IR has no register/operand classes, only instructions -- We have no separate metadata classes, e.g. the register class contains the above mentioned DILocalVariable itself in the form of the variable name -- We handle only the fraction of information contained in LLVM IR, e.g. we only store the `name: "a"` part of the `!DILocalVariable` metadata, even though it contains a scope, line, filename, etc. -![type-classes](type-classes.png) +- We have no separate metadata classes, e.g. the register class contains the above mentioned + DILocalVariable itself in the form of the variable name +- We handle only the fraction of information contained in LLVM IR, e.g. we only store + the `name: "a"` part of the `!DILocalVariable` metadata, even though it contains a scope, line, + filename, etc. + ![type-classes](type-classes.png) ### XCFA -At the end of our example execution we get the XCFA from Theta, which van be printed into a graphviz (dot) format: + +At the end of our example execution we get the XCFA from Theta, which van be printed into a +graphviz (dot) format: ![xcfa](xcfa.png) -Although in the representation before the xcfa we had the registers representing `b`, during the XCFA transformation in Theta the `b = a + 2; main_ret = b` sequence was merged into `main_ret = a + 2`. +Although in the representation before the xcfa we had the registers representing `b`, during the +XCFA transformation in Theta the `b = a + 2; main_ret = b` sequence was merged +into `main_ret = a + 2`. diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/build.gradle.kts b/subprojects/frontends/petrinet-frontend/petrinet-analysis/build.gradle.kts new file mode 100644 index 0000000000..e81d02f70c --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/build.gradle.kts @@ -0,0 +1,29 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +plugins { + id("java-common") +} + +dependencies { + implementation(Deps.axiomApi) + implementation(Deps.axiomImpl) + implementation(Deps.jing) + + implementation(project(":theta-core")) + implementation(project(":theta-common")) + implementation(project(":theta-analysis")) + implementation(project(":theta-petrinet-model")) +} \ No newline at end of file diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/main/java/hu/bme/mit/theta/frontend/petrinet/analysis/ModelProperties.java b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/main/java/hu/bme/mit/theta/frontend/petrinet/analysis/ModelProperties.java new file mode 100644 index 0000000000..21cf7ccff1 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/main/java/hu/bme/mit/theta/frontend/petrinet/analysis/ModelProperties.java @@ -0,0 +1,51 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.frontend.petrinet.analysis; + +import hu.bme.mit.theta.common.table.TableWriter; + +import java.util.Arrays; + +public final class ModelProperties { + private static final String[] headers = new String[]{"id", "Name", "Type", "#Place", "#Transition", "#Arc", + "HasReadOnlyEffect", + "HasReadOnlyEffectOnTop"}; + + private final PtNetSystem model; + private final String id; + + public ModelProperties(final PtNetSystem model, String id) { + this.model = model; + this.id = id; + } + + public static void printHeader(TableWriter writer) { + writer.cells(Arrays.asList(headers)); + writer.newRow(); + } + + public void printData(TableWriter writer) { + writer.cell(id); + writer.cell(model.getName()); + writer.cell("P/T net"); + writer.cell(model.getPlaceCount()); + writer.cell(model.getTransitionCount()); + writer.cell(model.getArcCount()); + writer.cell(model.hasReadOnlyEffect); + writer.cell(model.hasReadOnlyEffectOnTop); + writer.newRow(); + } +} diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/main/java/hu/bme/mit/theta/frontend/petrinet/analysis/PtNetDependency2Gxl.java b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/main/java/hu/bme/mit/theta/frontend/petrinet/analysis/PtNetDependency2Gxl.java new file mode 100644 index 0000000000..1df02156e0 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/main/java/hu/bme/mit/theta/frontend/petrinet/analysis/PtNetDependency2Gxl.java @@ -0,0 +1,209 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.frontend.petrinet.analysis; + +import com.koloboke.collect.set.hash.HashObjSets; +import hu.bme.mit.theta.frontend.petrinet.model.Place; +import hu.bme.mit.theta.frontend.petrinet.model.Transition; + +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +public final class PtNetDependency2Gxl { + private static final int K = 100; + + private static class DepEdge { + public final PlaceRef a; + public final PlaceRef b; + public final int weight; + + private DepEdge(final PlaceRef a, final PlaceRef b) { + this(a, b, 1); + // this.a = a.getId().compareTo(b.getId()) < 0 ? a : b; + // this.b = a.getId().compareTo(b.getId()) < 0 ? b : a; + } + + private DepEdge(final PlaceRef a, final PlaceRef b, int weight) { + this.a = a; + this.b = b; + this.weight = weight; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof DepEdge)) return false; + + final DepEdge depEdge = (DepEdge) o; + + if (!a.equals(depEdge.a)) return false; + if (weight != depEdge.weight) return false; + return b.equals(depEdge.b); + } + + @Override + public int hashCode() { + int result = a.hashCode(); + result = 31 * result + b.hashCode(); + result = 31 * result + weight; + return result; + } + } + + private static class PlaceRef { + private final Place ref; + private final String id; + + private PlaceRef(String id) { + this.ref = null; + this.id = id; + } + + private PlaceRef(final Place ref) { + this.ref = ref; + this.id = ref.getId(); + } + + @Override + public int hashCode() { + return ref == null ? id.hashCode() : ref.hashCode(); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) return true; + if (obj instanceof PlaceRef) { + PlaceRef other = (PlaceRef) obj; + return Objects.equals(ref, other.ref) && Objects.equals(id, other.id); + } + return false; + } + + private String getId() { + return id; + } + } + + public static String toGxl(PtNetSystem system, final boolean omitReadOnly) { + final Map> depMat = system.getDependencyMatrix(); + + Set nodes = HashObjSets.newUpdatableSet(); + Set edges = HashObjSets.newUpdatableSet(); + // if (omitReadOnly) { + // PlaceRef rootNode = new PlaceRef("_______aux_"); + // nodes.add(rootNode); + // for (Place p : system.getPetriNet().getPlaces()) { + // final PlaceRef pRef = new PlaceRef(p); + // nodes.add(pRef); + // edges.add(new DepEdge(rootNode, pRef, system.getPlaceCount())); + // } + // } else { + for (Place p : system.getPetriNet().getPlaces()) { + final PlaceRef pRef = new PlaceRef(p); + nodes.add(pRef); + } + // } + + for (Map.Entry> t : depMat.entrySet()) { + Set inPlaces = HashObjSets.newUpdatableSet(); + Set outPlaces = HashObjSets.newUpdatableSet(); + //Set readOnlyPlaces = HashObjSets.newUpdatableSet(); + for (Map.Entry e : t.getValue().entrySet()) { + if (e.getValue().takes == e.getValue().puts) { + //readOnlyPlaces.add(e.getKey()); + if (omitReadOnly) { + continue; + } + } + if (e.getValue().takes > 0 || e.getValue().inhibits < Integer.MAX_VALUE) { + inPlaces.add(e.getKey()); + } + if (e.getValue().puts > 0) { + outPlaces.add(e.getKey()); + } + } + + if (t.getValue().size() > K) { + PlaceRef transitionNode = new PlaceRef("_______aux_" + t.getKey().getId()); + nodes.add(transitionNode); + + for (Place p : inPlaces) { + edges.add(new DepEdge(new PlaceRef(p), transitionNode)); + } + + for (Place p : outPlaces) { + edges.add(new DepEdge(new PlaceRef(p), transitionNode)); + } + } else { + for (Place p1 : inPlaces) { + for (Place p2 : outPlaces) { + edges.add(new DepEdge(new PlaceRef(p1), new PlaceRef(p2))); + } + } + } + } + + return serializeGxl(system.getPetriNet().getName(), nodes, edges); + } + + private static String serializeGxl( + final String name, final Set nodes, final Set edges + ) { + StringBuilder sb = new StringBuilder(); + sb.append("\n"); + sb.append("\n"); + + for (PlaceRef node : nodes) { + sb.append("\n"); + } + + for (DepEdge edge : edges) { + // if (edge.weight == 1) { + sb.append("\n"); + // } else { + // sb.append("\n") + // .append("\n" + "") + // .append(edge.weight) + // .append("\n") + // .append(""); + // } + } + + sb.append("\n"); + sb.append("\n"); + + return sb.toString(); + } +} diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/main/java/hu/bme/mit/theta/frontend/petrinet/analysis/PtNetInitializer.java b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/main/java/hu/bme/mit/theta/frontend/petrinet/analysis/PtNetInitializer.java new file mode 100644 index 0000000000..a2bf01d332 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/main/java/hu/bme/mit/theta/frontend/petrinet/analysis/PtNetInitializer.java @@ -0,0 +1,44 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.frontend.petrinet.analysis; + +import hu.bme.mit.delta.collections.IntObjMapView; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.StateSpaceInfo; +import hu.bme.mit.theta.frontend.petrinet.model.Place; + +public final class PtNetInitializer implements AbstractNextStateDescriptor.Postcondition { + private Place assignedPlace; + private int initialMarking; + private AbstractNextStateDescriptor continuation; + + public PtNetInitializer( + final Place assignedPlace, final int initialMarking, final AbstractNextStateDescriptor continuation + ) { + this.assignedPlace = assignedPlace; + this.initialMarking = initialMarking; + this.continuation = continuation; + } + + @Override + public IntObjMapView getValuations(final StateSpaceInfo localStateSpace) { + if (assignedPlace == localStateSpace.getTraceInfo()) { + return IntObjMapView.singleton(initialMarking, continuation); + } else { + return IntObjMapView.empty(continuation); + } + } +} diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/main/java/hu/bme/mit/theta/frontend/petrinet/analysis/PtNetSystem.java b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/main/java/hu/bme/mit/theta/frontend/petrinet/analysis/PtNetSystem.java new file mode 100644 index 0000000000..4b53d5c82d --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/main/java/hu/bme/mit/theta/frontend/petrinet/analysis/PtNetSystem.java @@ -0,0 +1,300 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.frontend.petrinet.analysis; + +import com.google.common.collect.ImmutableBiMap; +import com.koloboke.collect.map.ObjIntMap; +import com.koloboke.collect.map.hash.HashObjIntMaps; +import com.koloboke.collect.map.hash.HashObjObjMap; +import com.koloboke.collect.map.hash.HashObjObjMaps; +import hu.bme.mit.delta.collections.UniqueTable; +import hu.bme.mit.delta.collections.impl.MapUniqueTable; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.impl.OrNextStateDescriptor; +import hu.bme.mit.theta.frontend.petrinet.model.*; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +public final class PtNetSystem { + public static class TransitionEffect { + public static final TransitionEffect INDEPENDENT = new TransitionEffect(0, Integer.MAX_VALUE, 0); + + public final int takes; + public final int inhibits; + public final int puts; + + public TransitionEffect(final int takes, final int inhibits, final int puts) { + this.takes = takes; + this.inhibits = inhibits; + this.puts = puts; + } + + public boolean isDependent() { + return takes != 0 || puts != 0 || inhibits != Integer.MAX_VALUE; + } + + public boolean reads() { + return inhibits != Integer.MAX_VALUE || (takes == puts && takes > 0); + } + + public boolean writes() { + return takes != puts; + } + + public String toString() { + if (writes()) { + return "rw"; + } else if (reads()) { + return "r"; + } else { + return ""; + } + } + } + + private PetriNet petriNet; + private final List placeOrdering; + + private Map> dependencyMatrix = HashObjObjMaps.newUpdatableMap(); + private ObjIntMap transitionTop = HashObjIntMaps.newUpdatableMap(); + boolean hasReadOnlyEffect = false; + boolean hasReadOnlyEffectOnTop = false; + + private AbstractNextStateDescriptor.Postcondition initializer; + private AbstractNextStateDescriptor transitions; + + public PtNetSystem(final PetriNet petriNet, List placeOrdering) { + if (petriNet.getPlaces().size() != placeOrdering.size()) { + throw new IllegalArgumentException(); + } + if (placeOrdering.isEmpty()) { + throw new IllegalArgumentException(); + } + this.petriNet = petriNet; + this.placeOrdering = placeOrdering; + initializer = createInitializer(); + transitions = createTransitions(); + + for (Place p : petriNet.getPlaces()) { + if (!placeOrdering.contains(p)) { + throw new IllegalArgumentException("Ordering does not contain place " + p.getId()); + } + } + } + + private AbstractNextStateDescriptor.Postcondition createInitializer() { + PtNetInitializer current = new PtNetInitializer(placeOrdering.get(0), + Math.toIntExact(placeOrdering.get(0).getInitialMarking()), + AbstractNextStateDescriptor.terminalIdentity() + ); + for (int i = 1; i < placeOrdering.size(); ++i) { + current = new PtNetInitializer(placeOrdering.get(i), + Math.toIntExact(placeOrdering.get(i).getInitialMarking()), + current + ); + } + return current; + } + + private AbstractNextStateDescriptor createTransitions() { + List descriptors = new ArrayList<>(); + UniqueTable uniqueTable = new MapUniqueTable<>(); + for (Transition t : petriNet.getTransitions()) { + descriptors.add(createTransition(t, uniqueTable)); + } + return OrNextStateDescriptor.create(descriptors); + } + + private AbstractNextStateDescriptor createTransition( + final Transition t, final UniqueTable uniqueTable + ) { + ObjIntMap takes = HashObjIntMaps.newUpdatableMap(t.getIncomingArcs().size()); + ObjIntMap puts = HashObjIntMaps.newUpdatableMap(t.getOutgoingArcs().size()); + ObjIntMap inhibits = HashObjIntMaps.newUpdatableMap(); + + for (PTArc arc : t.getIncomingArcs()) { + if (arc.isInhibitor()) { + inhibits.put(arc.getSource(), Math.toIntExact(arc.getWeight())); + } else { + takes.put(arc.getSource(), Math.toIntExact(arc.getWeight())); + } + } + for (TPArc arc : t.getOutgoingArcs()) { + puts.put(arc.getTarget(), Math.toIntExact(arc.getWeight())); + } + + final HashObjObjMap transitionDependecies = HashObjObjMaps.newUpdatableMap(); + + boolean readOnlyOnTop = false; + + AbstractNextStateDescriptor current = AbstractNextStateDescriptor.terminalIdentity(); + for (int i = 0; i < placeOrdering.size(); ++i) { + final int nTakes = takes.getOrDefault(placeOrdering.get(i), 0); + final int nInhibits = inhibits.getOrDefault(placeOrdering.get(i), Integer.MAX_VALUE); + final int nPuts = puts.getOrDefault(placeOrdering.get(i), 0); + + if (nTakes != 0 || nPuts != 0 || nInhibits != Integer.MAX_VALUE) { + final TransitionEffect effect = new TransitionEffect(nTakes, nInhibits, nPuts); + transitionDependecies.put(placeOrdering.get(i), effect); + transitionTop.put(t, i); + + if (effect.reads() && !effect.writes()) { + hasReadOnlyEffect = true; + readOnlyOnTop = true; + } else { + readOnlyOnTop = false; + } + + current = uniqueTable.checkIn(new PtNetTransitionNextStateDescriptor(t, + placeOrdering.get(i), + nTakes, + nInhibits, + nPuts, + current + )); + } + } + + hasReadOnlyEffectOnTop = hasReadOnlyEffectOnTop || readOnlyOnTop; + + dependencyMatrix.put(t, transitionDependecies); + + return current; + } + + public AbstractNextStateDescriptor.Postcondition getInitializer() { + return initializer; + } + + public AbstractNextStateDescriptor getTransitions() { + return transitions; + } + + public String printDependencyMatrixCsv() { + StringBuilder sb = new StringBuilder(); + for (Place p : placeOrdering) { + sb.append(';'); + sb.append('"'); + sb.append(p.getId()); + sb.append('"'); + } + sb.append('\n'); + List transitionLines = new ArrayList<>(getTransitionCount()); + for (Transition t : petriNet.getTransitions()) { + StringBuilder sb2 = new StringBuilder(); + sb2.append('"'); + sb2.append(t.getId()); + sb2.append('"'); + + for (Place p : placeOrdering) { + sb2.append(';'); + sb2.append(dependencyMatrix.getOrDefault(t, Map.of()) + .getOrDefault(p, TransitionEffect.INDEPENDENT) + .toString()); + } + sb2.append('\n'); + transitionLines.add(sb2.toString()); + } + + transitionLines.sort((a, b) -> String.CASE_INSENSITIVE_ORDER.compare(reverseString(a), reverseString(b))); + + for (String line : transitionLines) { + sb.append(line); + } + + return sb.toString(); + } + + public static String reverseString(String str) { + StringBuilder sb = new StringBuilder(str); + sb.reverse(); + return sb.toString(); + } + + public BufferedImage dependencyMatrixImage(final int blockWidth) { + int width = placeOrdering.size() * blockWidth, height = petriNet.getTransitions().size() * blockWidth; + + // TYPE_INT_ARGB specifies the image format: 8-bit RGBA packed + // into integer pixels + BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + + Graphics2D graphics = bi.createGraphics(); + + final List transitions = new ArrayList<>(petriNet.getTransitions()); + transitions.sort(Comparator.comparingInt(t -> transitionTop.getOrDefault(t, -1))); + for (int y = 0; y < transitions.size(); y++) { + final Transition t = transitions.get(y); + + for (int x = 0; x < placeOrdering.size(); x++) { + final Place p = placeOrdering.get(x); + final TransitionEffect effect = dependencyMatrix.getOrDefault(t, Map.of()).getOrDefault(p, + TransitionEffect.INDEPENDENT + ); + + if (effect.writes()) { + graphics.setPaint(Color.RED); + } else if (effect.reads()) { + graphics.setPaint(Color.GREEN); + } else { + graphics.setPaint(Color.WHITE); + } + + graphics.fillRect(x * blockWidth, y * blockWidth, blockWidth, blockWidth); + // graphics.setPaint(Color.LIGHT_GRAY); + // graphics.drawRect(x*blockWidth, y*blockWidth, blockWidth + 1, blockWidth + 1); + } + } + + return bi; + } + + public String getName() { + return petriNet.getName() == null ? petriNet.getId() : petriNet.getName(); + } + + public boolean hasReadOnlyEffect() { + return hasReadOnlyEffect; + } + + public boolean hasReadOnlyEffectOnTop() { + return hasReadOnlyEffectOnTop; + } + + public int getPlaceCount() { + return petriNet.getPlaces().size(); + } + + public int getTransitionCount() { + return petriNet.getTransitions().size(); + } + + public int getArcCount() { + return petriNet.getPtArcs().size() + petriNet.getTpArcs().size(); + } + + public Map> getDependencyMatrix() { + return ImmutableBiMap.copyOf(dependencyMatrix); + } + + public PetriNet getPetriNet() { + return petriNet; + } +} diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/main/java/hu/bme/mit/theta/frontend/petrinet/analysis/PtNetTransitionNextStateDescriptor.java b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/main/java/hu/bme/mit/theta/frontend/petrinet/analysis/PtNetTransitionNextStateDescriptor.java new file mode 100644 index 0000000000..f58192dfa8 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/main/java/hu/bme/mit/theta/frontend/petrinet/analysis/PtNetTransitionNextStateDescriptor.java @@ -0,0 +1,291 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.frontend.petrinet.analysis; + +import hu.bme.mit.delta.collections.IntObjCursor; +import hu.bme.mit.delta.collections.IntObjMapView; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor; +import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.StateSpaceInfo; +import hu.bme.mit.theta.frontend.petrinet.model.Place; +import hu.bme.mit.theta.frontend.petrinet.model.Transition; + +import java.util.NoSuchElementException; + + +public final class PtNetTransitionNextStateDescriptor implements AbstractNextStateDescriptor { + private Transition representedTransition; + private Place affectedPlace; + private int takes; + private int inhibits = Integer.MAX_VALUE; + private int puts; + private AbstractNextStateDescriptor continuation; + private int hashCode = 0; + + public PtNetTransitionNextStateDescriptor( + final Transition representedTransition, + final Place affectedPlace, + final int takes, + final int inhibits, + final int puts, + final AbstractNextStateDescriptor continuation + ) { + this.representedTransition = representedTransition; + this.affectedPlace = affectedPlace; + this.takes = takes; + this.inhibits = inhibits; + this.puts = puts; + this.continuation = continuation; + } + + @Override + public IntObjMapView getDiagonal(final StateSpaceInfo localStateSpace) { + if (localStateSpace.getTraceInfo() == affectedPlace) { + return new IntObjMapView() { + @Override + public boolean isEmpty() { + // diagonal is empty if edge is not test or never enabled + return takes != puts || takes >= inhibits; + } + + @Override + public boolean isProcedural() { + return true; + } + + @Override + public boolean containsKey(final int key) { + return !isEmpty() && key >= takes && key < inhibits; + } + + @Override + public AbstractNextStateDescriptor get(final int key) { + if (containsKey(key)) { + return continuation; + } else { + return defaultValue(); + } + } + + @Override + public AbstractNextStateDescriptor defaultValue() { + return AbstractNextStateDescriptor.terminalEmpty(); + } + + @Override + public IntObjCursor cursor() { + return new IntObjCursor() { + int current = takes - 1; + + @Override + public int key() { + if (!containsKey(current)) { + throw new NoSuchElementException(); + } + return current; + } + + @Override + public AbstractNextStateDescriptor value() { + if (!containsKey(current)) { + throw new NoSuchElementException(); + } + return continuation; + } + + @Override + public boolean moveNext() { + return ++current < inhibits; + } + }; + } + + @Override + public int size() { + return (inhibits == Integer.MAX_VALUE) ? -1 : inhibits - takes; + } + }; + } else { + return IntObjMapView.empty(this); + } + } + + @Override + public IntObjMapView> getOffDiagonal(final StateSpaceInfo localStateSpace) { + if (localStateSpace.getTraceInfo() == affectedPlace) { + return new IntObjMapView>() { + @Override + public boolean isEmpty() { + // diagonal is empty if edge is not test or never enabled + return takes == puts || takes >= inhibits; + } + + @Override + public boolean isProcedural() { + return true; + } + + @Override + public boolean containsKey(final int key) { + return !isEmpty() && key >= takes && key < inhibits; + } + + @Override + public IntObjMapView get(final int from) { + if (containsKey(from)) { + return new IntObjMapView() { + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean isProcedural() { + return false; + } + + @Override + public boolean containsKey(final int to) { + return to == from - takes + puts; + } + + @Override + public AbstractNextStateDescriptor get(final int to) { + if (containsKey(to)) { + return continuation; + } else { + return defaultValue(); + } + } + + @Override + public AbstractNextStateDescriptor defaultValue() { + return AbstractNextStateDescriptor.terminalEmpty(); + } + + @Override + public IntObjCursor cursor() { + return new IntObjCursor() { + int current = from - takes + puts - 1; + + @Override + public int key() { + if (!containsKey(current)) { + throw new NoSuchElementException(); + } + return current; + } + + @Override + public AbstractNextStateDescriptor value() { + if (!containsKey(current)) { + throw new NoSuchElementException(); + } + return continuation; + } + + @Override + public boolean moveNext() { + return ++current <= from - takes + puts; + } + }; + } + + @Override + public int size() { + return 1; + } + }; + } else { + return defaultValue(); + } + } + + @Override + public IntObjMapView defaultValue() { + return IntObjMapView.empty(); + } + + @Override + public IntObjCursor> cursor() { + return new IntObjCursor>() { + int current = takes - 1; + + @Override + public int key() { + if (!containsKey(current)) { + throw new NoSuchElementException(); + } + return current; + } + + @Override + public IntObjMapView value() { + if (!containsKey(current)) { + throw new NoSuchElementException(); + } + return get(current); + } + + @Override + public boolean moveNext() { + return ++current < inhibits; + } + }; + } + + @Override + public int size() { + return (inhibits == Integer.MAX_VALUE) ? -1 : inhibits - takes; + } + }; + } else { + return IntObjMapView.empty(IntObjMapView.empty(AbstractNextStateDescriptor.terminalEmpty())); + } + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof PtNetTransitionNextStateDescriptor)) return false; + + final PtNetTransitionNextStateDescriptor that = (PtNetTransitionNextStateDescriptor) o; + + if (takes != that.takes) return false; + if (inhibits != that.inhibits) return false; + if (puts != that.puts) return false; + if (affectedPlace != null ? !affectedPlace.equals(that.affectedPlace) : that.affectedPlace != null) + return false; + return continuation != null ? continuation.equals(that.continuation) : that.continuation == null; + } + + @Override + public int hashCode() { + if (hashCode != 0) { + return hashCode; + } + hashCode = affectedPlace != null ? affectedPlace.hashCode() : 0; + hashCode = 31 * hashCode + takes; + hashCode = 31 * hashCode + inhibits; + hashCode = 31 * hashCode + puts; + hashCode = 31 * hashCode + (continuation != null ? continuation.hashCode() : 0); + return hashCode; + } + + @Override + public String toString() { + return representedTransition.toString(); + } +} diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/main/java/hu/bme/mit/theta/frontend/petrinet/analysis/VariableOrderingFactory.java b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/main/java/hu/bme/mit/theta/frontend/petrinet/analysis/VariableOrderingFactory.java new file mode 100644 index 0000000000..6c4654a470 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/main/java/hu/bme/mit/theta/frontend/petrinet/analysis/VariableOrderingFactory.java @@ -0,0 +1,55 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.frontend.petrinet.analysis; + +import com.koloboke.collect.map.hash.HashObjObjMaps; +import hu.bme.mit.theta.frontend.petrinet.model.PetriNet; +import hu.bme.mit.theta.frontend.petrinet.model.Place; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public final class VariableOrderingFactory { + public static List fromFile(String orderingPath, PetriNet petriNet) throws Exception { + final File orderingFile = new File(orderingPath); + if (!orderingFile.exists()) { + throw new IOException("Cannot open ordering file: " + orderingPath); + } + List orderingIds = Files.readAllLines(orderingFile.toPath()); + orderingIds.removeIf(s -> s.trim().isEmpty()); + if (orderingIds.size() != petriNet.getPlaces().size()) { + throw new Exception("The ordering does not match the net: different number of entries"); + } + Map placeIdMap = HashObjObjMaps.newImmutableMap(petriNet + .getPlaces() + .stream() + .collect(Collectors.toMap(p -> p.getId(), p -> p))); + final List ordering = new ArrayList<>(orderingIds.size()); + for (String s : orderingIds) { + Place p = placeIdMap.get(s); + if (p == null) { + throw new Exception("The ordering does not match the net: no place for ID " + s); + } + ordering.add(p); + } + return ordering; + } +} diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/java/hu/bme/mit/theta/frontend/petrinet/analysis/BfsTest.java b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/java/hu/bme/mit/theta/frontend/petrinet/analysis/BfsTest.java new file mode 100644 index 0000000000..02bbb83780 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/java/hu/bme/mit/theta/frontend/petrinet/analysis/BfsTest.java @@ -0,0 +1,79 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.frontend.petrinet.analysis; + +import hu.bme.mit.delta.java.mdd.GraphvizSerializer; +import hu.bme.mit.delta.java.mdd.JavaMddFactory; +import hu.bme.mit.delta.java.mdd.MddHandle; +import hu.bme.mit.delta.java.mdd.MddVariableOrder; +import hu.bme.mit.delta.mdd.LatticeDefinition; +import hu.bme.mit.delta.mdd.MddInterpreter; +import hu.bme.mit.delta.mdd.MddVariableDescriptor; +import hu.bme.mit.theta.analysis.algorithm.mdd.fixedpoint.BfsProvider; +import hu.bme.mit.theta.analysis.algorithm.mdd.fixedpoint.LegacyRelationalProductProvider; +import hu.bme.mit.theta.frontend.petrinet.model.PetriNet; +import hu.bme.mit.theta.frontend.petrinet.model.Place; +import hu.bme.mit.theta.frontend.petrinet.pnml.PetriNetParser; +import org.junit.Test; + +import java.io.File; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public final class BfsTest { + public static String reverseString(String str) { + StringBuilder sb = new StringBuilder(str); + sb.reverse(); + return sb.toString(); + } + + @Test + public void testBfs() throws Exception { + final File pnmlFile = new File(getClass().getResource(TestData.MODELPATH).toURI()); + final List petriNets = PetriNetParser.loadPnml(pnmlFile).parsePTNet(); + + assertEquals(1, petriNets.size()); + + final List ordering = VariableOrderingFactory.fromFile(getClass().getResource(TestData.ORDERINGPATH).toURI().getPath(), petriNets.get(0)); + // ordering = new ArrayList<>(petriNets.get(0).getPlaces()); + // ordering.sort((p1, p2) -> String.CASE_INSENSITIVE_ORDER.compare(reverseString(p1.getId()), + // reverseString(p2.getId()))); + + PtNetSystem system = new PtNetSystem(petriNets.get(0), ordering); + + System.out.println(system.printDependencyMatrixCsv()); + + MddVariableOrder variableOrder = + JavaMddFactory.getDefault().createMddVariableOrder(LatticeDefinition.forSets()); + for (Place p : ordering) { + variableOrder.createOnTop(MddVariableDescriptor.create(p)); + } + + BfsProvider bfs = new BfsProvider(variableOrder, new LegacyRelationalProductProvider(variableOrder)); + + final MddHandle stateSpace = bfs.compute(system.getInitializer(), + system.getTransitions(), + variableOrder.getDefaultSetSignature().getTopVariableHandle() + ); + + System.out.println(GraphvizSerializer.serialize(stateSpace)); + + final Long stateSpaceSize = MddInterpreter.calculateNonzeroCount(stateSpace); + assertEquals(TestData.STATESPACESIZE, stateSpaceSize.longValue()); + System.out.println("Size of state space: " + stateSpaceSize); + } +} diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/java/hu/bme/mit/theta/frontend/petrinet/analysis/GeneralizedSaturationTest.java b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/java/hu/bme/mit/theta/frontend/petrinet/analysis/GeneralizedSaturationTest.java new file mode 100644 index 0000000000..a802d0028d --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/java/hu/bme/mit/theta/frontend/petrinet/analysis/GeneralizedSaturationTest.java @@ -0,0 +1,89 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.frontend.petrinet.analysis; + +import hu.bme.mit.delta.java.mdd.GraphvizSerializer; +import hu.bme.mit.delta.java.mdd.JavaMddFactory; +import hu.bme.mit.delta.java.mdd.MddHandle; +import hu.bme.mit.delta.java.mdd.MddVariableOrder; +import hu.bme.mit.delta.mdd.LatticeDefinition; +import hu.bme.mit.delta.mdd.MddInterpreter; +import hu.bme.mit.delta.mdd.MddVariableDescriptor; +import hu.bme.mit.theta.analysis.algorithm.mdd.fixedpoint.GeneralizedSaturationProvider; +import hu.bme.mit.theta.analysis.algorithm.mdd.fixedpoint.CursorRelationalProductProvider; +import hu.bme.mit.theta.frontend.petrinet.model.PetriNet; +import hu.bme.mit.theta.frontend.petrinet.model.Place; +import hu.bme.mit.theta.frontend.petrinet.pnml.PetriNetParser; +import org.junit.Test; + +import java.io.File; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public final class GeneralizedSaturationTest { + public static String reverseString(String str) { + StringBuilder sb = new StringBuilder(str); + sb.reverse(); + return sb.toString(); + } + + @Test + public void testGS() throws Exception { + final File pnmlFile = new File(getClass().getResource(TestData.MODELPATH).toURI()); + final List petriNets = PetriNetParser.loadPnml(pnmlFile).parsePTNet(); + + assertEquals(1, petriNets.size()); + + final List ordering = VariableOrderingFactory.fromFile(getClass().getResource(TestData.ORDERINGPATH).toURI().getPath(), petriNets.get(0)); + // ordering = new ArrayList<>(petriNets.get(0).getPlaces()); + // ordering.sort((p1, p2) -> String.CASE_INSENSITIVE_ORDER.compare(reverseString(p1.getId()), + // reverseString(p2.getId()))); + // ordering.sort((p1, p2) -> String.CASE_INSENSITIVE_ORDER.compare(p1.getId(), + // p2.getId())); + + PtNetSystem system = new PtNetSystem(petriNets.get(0), ordering); + + System.out.println(system.printDependencyMatrixCsv()); + + //new BufferedReader(new InputStreamReader(System.in)).readLine(); + + MddVariableOrder variableOrder = + JavaMddFactory.getDefault().createMddVariableOrder(LatticeDefinition.forSets()); + for (Place p : ordering) { + variableOrder.createOnTop(MddVariableDescriptor.create(p)); + } + + GeneralizedSaturationProvider gs = new GeneralizedSaturationProvider(variableOrder, + new CursorRelationalProductProvider(variableOrder)); + + final MddHandle stateSpace = gs.compute(system.getInitializer(), + system.getTransitions(), + variableOrder.getDefaultSetSignature().getTopVariableHandle() + ); + + String dot = GraphvizSerializer.serialize(stateSpace); + System.out.println(dot); + +// StringSelection stringSelection = new StringSelection(dot); +// Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); +// clipboard.setContents(stringSelection, null); + + final Long stateSpaceSize = MddInterpreter.calculateNonzeroCount(stateSpace); + assertEquals(TestData.STATESPACESIZE, stateSpaceSize.longValue()); + System.out.println("Size of state space: " + stateSpaceSize); + } +} diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/java/hu/bme/mit/theta/frontend/petrinet/analysis/RelationalProductTest.java b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/java/hu/bme/mit/theta/frontend/petrinet/analysis/RelationalProductTest.java new file mode 100644 index 0000000000..62d8cc61ea --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/java/hu/bme/mit/theta/frontend/petrinet/analysis/RelationalProductTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.frontend.petrinet.analysis; + +import hu.bme.mit.delta.java.mdd.JavaMddFactory; +import hu.bme.mit.delta.java.mdd.MddGraph; +import hu.bme.mit.delta.java.mdd.MddSignature; +import hu.bme.mit.delta.java.mdd.MddVariableOrder; +import hu.bme.mit.delta.mdd.LatticeDefinition; +import hu.bme.mit.delta.mdd.MddVariableDescriptor; +import org.junit.Before; + +public final class RelationalProductTest { + private static final int[] tupleSignature = new int[]{0, 0, 0}; + + private MddGraph graph; + private MddVariableOrder order; + private MddSignature signature; + + @Before + public void prepare() { + System.out.println("Preparing..."); + graph = JavaMddFactory.getDefault().createMddGraph(LatticeDefinition.forSets()); + order = JavaMddFactory.getDefault().createMddVariableOrder(graph); + for (int i = 0; i < tupleSignature.length; i++) { + order.createOnTop(MddVariableDescriptor.create("x" + i, tupleSignature[tupleSignature.length - i - 1])); + } + signature = order.getDefaultSetSignature(); + } +} diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/java/hu/bme/mit/theta/frontend/petrinet/analysis/SimpleSaturationTest.java b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/java/hu/bme/mit/theta/frontend/petrinet/analysis/SimpleSaturationTest.java new file mode 100644 index 0000000000..a3c7cfb1fc --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/java/hu/bme/mit/theta/frontend/petrinet/analysis/SimpleSaturationTest.java @@ -0,0 +1,90 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.frontend.petrinet.analysis; + +import hu.bme.mit.delta.java.mdd.JavaMddFactory; +import hu.bme.mit.delta.java.mdd.MddHandle; +import hu.bme.mit.delta.java.mdd.MddVariableOrder; +import hu.bme.mit.delta.mdd.LatticeDefinition; +import hu.bme.mit.delta.mdd.MddInterpreter; +import hu.bme.mit.delta.mdd.MddVariableDescriptor; +import hu.bme.mit.theta.analysis.algorithm.mdd.fixedpoint.SimpleSaturationProvider; +import hu.bme.mit.theta.frontend.petrinet.model.PetriNet; +import hu.bme.mit.theta.frontend.petrinet.model.Place; +import hu.bme.mit.theta.frontend.petrinet.pnml.PetriNetParser; +import org.junit.Test; + +import java.io.File; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public final class SimpleSaturationTest { + public static String reverseString(String str) { + StringBuilder sb = new StringBuilder(str); + sb.reverse(); + return sb.toString(); + } + + @Test + public void testSS() throws Exception { + final File pnmlFile = new File(getClass().getResource(TestData.MODELPATH).toURI()); + final List petriNets = PetriNetParser.loadPnml(pnmlFile).parsePTNet(); + + assertEquals(1, petriNets.size()); + + final List ordering = + VariableOrderingFactory.fromFile(getClass().getResource(TestData.ORDERINGPATH).toURI().getPath(), + petriNets.get(0)); + // ordering = new ArrayList<>(petriNets.get(0).getPlaces()); + // ordering.sort((p1, p2) -> String.CASE_INSENSITIVE_ORDER.compare(reverseString(p1.getId()), + // reverseString(p2.getId()))); + //ordering.sort((p1, p2) -> String.CASE_INSENSITIVE_ORDER.compare(p1.getId(), + // p2.getId())); + + PtNetSystem system = new PtNetSystem(petriNets.get(0), ordering); + + System.out.println(system.printDependencyMatrixCsv()); + + //new BufferedReader(new InputStreamReader(System.in)).readLine(); + + MddVariableOrder variableOrder = + JavaMddFactory.getDefault().createMddVariableOrder(LatticeDefinition.forSets()); + for (Place p : ordering) { + variableOrder.createOnTop(MddVariableDescriptor.create(p)); + } + + SimpleSaturationProvider ss = new SimpleSaturationProvider(variableOrder); + + final MddHandle stateSpace = ss.compute(system.getInitializer(), + system.getTransitions(), + variableOrder.getDefaultSetSignature().getTopVariableHandle() + ); + + //String dot = GraphvizSerializer.serialize(stateSpace); + //System.out.println(dot); + + System.out.println(ss.getSaturatedNodes().size()); + + // StringSelection stringSelection = new StringSelection(dot); + // Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + // clipboard.setContents(stringSelection, null); + + final Long stateSpaceSize = MddInterpreter.calculateNonzeroCount(stateSpace); + assertEquals(TestData.STATESPACESIZE, stateSpaceSize.longValue()); + System.out.println("Size of state space: " + stateSpaceSize); + } +} diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/java/hu/bme/mit/theta/frontend/petrinet/analysis/TestData.java b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/java/hu/bme/mit/theta/frontend/petrinet/analysis/TestData.java new file mode 100644 index 0000000000..1fb502d870 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/java/hu/bme/mit/theta/frontend/petrinet/analysis/TestData.java @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.frontend.petrinet.analysis; + +public final class TestData { + public static final String MODELPATH = "/dekker-10.pnml"; + public static final String ORDERINGPATH = "/dekker-10.pnml.gsat.order"; + public static final long STATESPACESIZE = 6144; +} diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/MAPK-53-1-0.pnml b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/MAPK-53-1-0.pnml new file mode 100644 index 0000000000..789c3f1c87 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/MAPK-53-1-0.pnml @@ -0,0 +1,1269 @@ + + + +DefaultPageAKT=01 +AKT_equals_1 +AP1_equals_01 +AP1_equals_1 +ATF2_equals_01 +ATF2_equals_1 +ATM_equals_01 +ATM_equals_1 +Apoptosis_equals_01 +Apoptosis_equals_1 +BCL2_equals_01 +BCL2_equals_1 +CREB_equals_01 +CREB_equals_1 +DNA_damage_equals_01 +DNA_damage_equals_1 +DUSP1_equals_01 +DUSP1_equals_1 +EGFR_equals_01 +EGFR_equals_1 +EGFR_stimulus_equals_0 +EGFR_stimulus_equals_11 +ELK1_equals_01 +ELK1_equals_1 +ERK_equals_01 +ERK_equals_1 +FGFR3_equals_01 +FGFR3_equals_1 +FGFR3_stimulus_equals_01 +FGFR3_stimulus_equals_1 +FOS_equals_01 +FOS_equals_1 +FOXO3_equals_01 +FOXO3_equals_1 +FRS2_equals_01 +FRS2_equals_1 +GAB1_equals_01 +GAB1_equals_1 +GADD45_equals_01 +GADD45_equals_1 +GRB2_equals_01 +GRB2_equals_1 +Growth_Arrest_equals_01 +Growth_Arrest_equals_1 +JNK_equals_01 +JNK_equals_1 +JUN_equals_01 +JUN_equals_1 +MAP3K1_3_equals_01 +MAP3K1_3_equals_1 +MAX_equals_01 +MAX_equals_1 +MDM2_equals_01 +MDM2_equals_1 +MEK1_2_equals_01 +MEK1_2_equals_1 +MSK_equals_01 +MSK_equals_1 +MTK1_equals_01 +MTK1_equals_1 +MYC_equals_01 +MYC_equals_1 +PDK1_equals_01 +PDK1_equals_1 +PI3K_equals_01 +PI3K_equals_1 +PKC_equals_01 +PKC_equals_1 +PLCG_equals_01 +PLCG_equals_1 +PPP2CA_equals_01 +PPP2CA_equals_1 +PTEN_equals_01 +PTEN_equals_1 +Proliferation_equals_01 +Proliferation_equals_1 +RAF_equals_01 +RAF_equals_1 +RAS_equals_01 +RAS_equals_1 +RSK_equals_01 +RSK_equals_1 +SMAD_equals_01 +SMAD_equals_1 +SOS_equals_01 +SOS_equals_1 +SPRY_equals_01 +SPRY_equals_1 +TAK1_equals_01 +TAK1_equals_1 +TAOK_equals_01 +TAOK_equals_1 +TGFBR_equals_01 +TGFBR_equals_1 +TGFBR_stimulus_equals_01 +TGFBR_stimulus_equals_1 +p14_equals_01 +p14_equals_1 +p21_equals_01 +p21_equals_1 +p38_equals_01 +p38_equals_1 +p53_equals_01 +p53_equals_1 +p70_equals_01 +p70_equals_1 +AKT_equals_0_to_AKT_equals_1_when_PDK1_equals_1_and_PTEN_equals_0 +AKT_equals_1_to_AKT_equals_0_when_PDK1_equals_0 +AKT_equals_1_to_AKT_equals_0_when_PTEN_equals_1 +AP1_equals_0_to_AP1_equals_1_when_ATF2_equals_0_and_FOS_equals_1_and_JUN_equals_1 +AP1_equals_0_to_AP1_equals_1_when_ATF2_equals_1_and_JUN_equals_1 +AP1_equals_1_to_AP1_equals_0_when_ATF2_equals_0_and_FOS_equals_0 +AP1_equals_1_to_AP1_equals_0_when_JUN_equals_0 +ATF2_equals_0_to_ATF2_equals_1_when_JNK_equals_1 +ATF2_equals_0_to_ATF2_equals_1_when_p38_equals_1 +ATF2_equals_1_to_ATF2_equals_0_when_JNK_equals_0_and_p38_equals_0 +ATM_equals_0_to_ATM_equals_1_when_DNA_damage_equals_1 +ATM_equals_1_to_ATM_equals_0_when_DNA_damage_equals_0 +Apoptosis_equals_0_to_Apoptosis_equals_1_when_BCL2_equals_0_and_ERK_equals_0_and_FOXO3_equals_1_and_p53_equals_1 +Apoptosis_equals_1_to_Apoptosis_equals_0_when_BCL2_equals_1 +Apoptosis_equals_1_to_Apoptosis_equals_0_when_ERK_equals_1 +Apoptosis_equals_1_to_Apoptosis_equals_0_when_FOXO3_equals_0 +Apoptosis_equals_1_to_Apoptosis_equals_0_when_p53_equals_0 +BCL2_equals_0_to_BCL2_equals_1_when_AKT_equals_1_and_CREB_equals_1 +BCL2_equals_1_to_BCL2_equals_0_when_AKT_equals_0 +BCL2_equals_1_to_BCL2_equals_0_when_CREB_equals_0 +CREB_equals_0_to_CREB_equals_1_when_MSK_equals_1 +CREB_equals_1_to_CREB_equals_0_when_MSK_equals_0 +DUSP1_equals_0_to_DUSP1_equals_1_when_CREB_equals_1 +DUSP1_equals_1_to_DUSP1_equals_0_when_CREB_equals_0 +EGFR_equals_0_to_EGFR_equals_1_when_EGFR_stimulus_equals_0_and_GRB2_equals_0_and_PKC_equals_0_and_SPRY_equals_1 +EGFR_equals_0_to_EGFR_equals_1_when_EGFR_stimulus_equals_1_and_GRB2_equals_0_and_PKC_equals_0 +EGFR_equals_1_to_EGFR_equals_0_when_EGFR_stimulus_equals_0_and_SPRY_equals_0 +EGFR_equals_1_to_EGFR_equals_0_when_GRB2_equals_1 +EGFR_equals_1_to_EGFR_equals_0_when_PKC_equals_1 +ELK1_equals_0_to_ELK1_equals_1_when_ERK_equals_1 +ELK1_equals_0_to_ELK1_equals_1_when_JNK_equals_1 +ELK1_equals_0_to_ELK1_equals_1_when_p38_equals_1 +ELK1_equals_1_to_ELK1_equals_0_when_ERK_equals_0_and_JNK_equals_0_and_p38_equals_0 +ERK_equals_0_to_ERK_equals_1_when_MEK1_2_equals_1 +ERK_equals_1_to_ERK_equals_0_when_MEK1_2_equals_0 +FGFR3_equals_0_to_FGFR3_equals_1_when_FGFR3_stimulus_equals_1_and_GRB2_equals_0_and_PKC_equals_0 +FGFR3_equals_1_to_FGFR3_equals_0_when_FGFR3_stimulus_equals_0 +FGFR3_equals_1_to_FGFR3_equals_0_when_GRB2_equals_1 +FGFR3_equals_1_to_FGFR3_equals_0_when_PKC_equals_1 +FOS_equals_0_to_FOS_equals_1_when_CREB_equals_0_and_ELK1_equals_1_and_ERK_equals_1_and_RSK_equals_1 +FOS_equals_0_to_FOS_equals_1_when_CREB_equals_1_and_ERK_equals_1_and_RSK_equals_1 +FOS_equals_1_to_FOS_equals_0_when_CREB_equals_0_and_ELK1_equals_0 +FOS_equals_1_to_FOS_equals_0_when_ERK_equals_0 +FOS_equals_1_to_FOS_equals_0_when_RSK_equals_0 +FOXO3_equals_0_to_FOXO3_equals_1_when_AKT_equals_0_and_JNK_equals_1 +FOXO3_equals_1_to_FOXO3_equals_0_when_AKT_equals_1 +FOXO3_equals_1_to_FOXO3_equals_0_when_JNK_equals_0 +FRS2_equals_0_to_FRS2_equals_1_when_FGFR3_equals_1_and_GRB2_equals_0_and_SPRY_equals_0 +FRS2_equals_1_to_FRS2_equals_0_when_FGFR3_equals_0 +FRS2_equals_1_to_FRS2_equals_0_when_GRB2_equals_1 +FRS2_equals_1_to_FRS2_equals_0_when_SPRY_equals_1 +GAB1_equals_0_to_GAB1_equals_1_when_GRB2_equals_1 +GAB1_equals_0_to_GAB1_equals_1_when_PI3K_equals_1 +GAB1_equals_1_to_GAB1_equals_0_when_GRB2_equals_0_and_PI3K_equals_0 +GADD45_equals_0_to_GADD45_equals_1_when_SMAD_equals_1 +GADD45_equals_0_to_GADD45_equals_1_when_p53_equals_1 +GADD45_equals_1_to_GADD45_equals_0_when_SMAD_equals_0_and_p53_equals_0 +GRB2_equals_0_to_GRB2_equals_1_when_EGFR_equals_1 +GRB2_equals_0_to_GRB2_equals_1_when_FRS2_equals_1 +GRB2_equals_0_to_GRB2_equals_1_when_TGFBR_equals_1 +GRB2_equals_1_to_GRB2_equals_0_when_EGFR_equals_0_and_FRS2_equals_0_and_TGFBR_equals_0 +Growth_Arrest_equals_0_to_Growth_Arrest_equals_1_when_p21_equals_1 +Growth_Arrest_equals_1_to_Growth_Arrest_equals_0_when_p21_equals_0 +JNK_equals_0_to_JNK_equals_1_when_DUSP1_equals_0_and_MAP3K1_3_equals_1 +JNK_equals_0_to_JNK_equals_1_when_DUSP1_equals_0_and_MTK1_equals_1 +JNK_equals_0_to_JNK_equals_1_when_DUSP1_equals_0_and_TAK1_equals_1 +JNK_equals_0_to_JNK_equals_1_when_DUSP1_equals_0_and_TAOK_equals_1 +JNK_equals_0_to_JNK_equals_1_when_DUSP1_equals_1_and_MAP3K1_3_equals_0_and_MTK1_equals_0_and_TAK1_equals_1_and_TAOK_equals_1 +JNK_equals_0_to_JNK_equals_1_when_DUSP1_equals_1_and_MAP3K1_3_equals_0_and_MTK1_equals_1_and_TAK1_equals_1 +JNK_equals_0_to_JNK_equals_1_when_DUSP1_equals_1_and_MAP3K1_3_equals_0_and_MTK1_equals_1_and_TAOK_equals_1 +JNK_equals_0_to_JNK_equals_1_when_DUSP1_equals_1_and_MAP3K1_3_equals_1_and_MTK1_equals_1 +JNK_equals_0_to_JNK_equals_1_when_DUSP1_equals_1_and_MAP3K1_3_equals_1_and_TAK1_equals_1 +JNK_equals_0_to_JNK_equals_1_when_DUSP1_equals_1_and_MAP3K1_3_equals_1_and_TAOK_equals_1 +JNK_equals_1_to_JNK_equals_0_when_DUSP1_equals_0_and_MAP3K1_3_equals_0_and_MTK1_equals_0_and_TAK1_equals_0_and_TAOK_equals_0 +JNK_equals_1_to_JNK_equals_0_when_DUSP1_equals_1_and_MAP3K1_3_equals_0_and_MTK1_equals_0_and_TAK1_equals_0 +JNK_equals_1_to_JNK_equals_0_when_DUSP1_equals_1_and_MAP3K1_3_equals_0_and_MTK1_equals_0_and_TAOK_equals_0 +JNK_equals_1_to_JNK_equals_0_when_DUSP1_equals_1_and_MAP3K1_3_equals_0_and_MTK1_equals_1_and_TAK1_equals_0_and_TAOK_equals_0 +JNK_equals_1_to_JNK_equals_0_when_DUSP1_equals_1_and_MAP3K1_3_equals_1_and_MTK1_equals_0_and_TAK1_equals_0_and_TAOK_equals_0 +JUN_equals_0_to_JUN_equals_1_when_JNK_equals_1 +JUN_equals_1_to_JUN_equals_0_when_JNK_equals_0 +MAP3K1_3_equals_0_to_MAP3K1_3_equals_1_when_RAS_equals_1 +MAP3K1_3_equals_1_to_MAP3K1_3_equals_0_when_RAS_equals_0 +MAX_equals_0_to_MAX_equals_1_when_p38_equals_1 +MAX_equals_1_to_MAX_equals_0_when_p38_equals_0 +MDM2_equals_0_to_MDM2_equals_1_when_AKT_equals_0_and_p14_equals_0_and_p53_equals_1 +MDM2_equals_0_to_MDM2_equals_1_when_AKT_equals_1_and_p14_equals_0 +MDM2_equals_1_to_MDM2_equals_0_when_AKT_equals_0_and_p53_equals_0 +MDM2_equals_1_to_MDM2_equals_0_when_p14_equals_1 +MEK1_2_equals_0_to_MEK1_2_equals_1_when_AP1_equals_0_and_MAP3K1_3_equals_0_and_PPP2CA_equals_0_and_RAF_equals_1 +MEK1_2_equals_0_to_MEK1_2_equals_1_when_AP1_equals_0_and_MAP3K1_3_equals_1_and_PPP2CA_equals_0 +MEK1_2_equals_1_to_MEK1_2_equals_0_when_AP1_equals_1 +MEK1_2_equals_1_to_MEK1_2_equals_0_when_MAP3K1_3_equals_0_and_RAF_equals_0 +MEK1_2_equals_1_to_MEK1_2_equals_0_when_PPP2CA_equals_1 +MSK_equals_0_to_MSK_equals_1_when_ERK_equals_1 +MSK_equals_0_to_MSK_equals_1_when_p38_equals_1 +MSK_equals_1_to_MSK_equals_0_when_ERK_equals_0_and_p38_equals_0 +MTK1_equals_0_to_MTK1_equals_1_when_GADD45_equals_1 +MTK1_equals_1_to_MTK1_equals_0_when_GADD45_equals_0 +MYC_equals_0_to_MYC_equals_1_when_AKT_equals_0_and_MAX_equals_1_and_MSK_equals_1 +MYC_equals_0_to_MYC_equals_1_when_AKT_equals_1_and_MSK_equals_1 +MYC_equals_1_to_MYC_equals_0_when_AKT_equals_0_and_MAX_equals_0 +MYC_equals_1_to_MYC_equals_0_when_MSK_equals_0 +PDK1_equals_0_to_PDK1_equals_1_when_PI3K_equals_1 +PDK1_equals_1_to_PDK1_equals_0_when_PI3K_equals_0 +PI3K_equals_0_to_PI3K_equals_1_when_GAB1_equals_1 +PI3K_equals_0_to_PI3K_equals_1_when_RAS_equals_1_and_SOS_equals_1 +PI3K_equals_1_to_PI3K_equals_0_when_GAB1_equals_0_and_RAS_equals_0 +PI3K_equals_1_to_PI3K_equals_0_when_GAB1_equals_0_and_SOS_equals_0 +PKC_equals_0_to_PKC_equals_1_when_PLCG_equals_1 +PKC_equals_1_to_PKC_equals_0_when_PLCG_equals_0 +PLCG_equals_0_to_PLCG_equals_1_when_EGFR_equals_1 +PLCG_equals_0_to_PLCG_equals_1_when_FGFR3_equals_1 +PLCG_equals_1_to_PLCG_equals_0_when_EGFR_equals_0_and_FGFR3_equals_0 +PPP2CA_equals_0_to_PPP2CA_equals_1_when_p38_equals_1 +PPP2CA_equals_1_to_PPP2CA_equals_0_when_p38_equals_0 +PTEN_equals_0_to_PTEN_equals_1_when_p53_equals_1 +PTEN_equals_1_to_PTEN_equals_0_when_p53_equals_0 +Proliferation_equals_0_to_Proliferation_equals_1_when_MYC_equals_1_and_p21_equals_0_and_p70_equals_1 +Proliferation_equals_1_to_Proliferation_equals_0_when_MYC_equals_0 +Proliferation_equals_1_to_Proliferation_equals_0_when_p21_equals_1 +Proliferation_equals_1_to_Proliferation_equals_0_when_p70_equals_0 +RAF_equals_0_to_RAF_equals_1_when_AKT_equals_0_and_ERK_equals_0_and_PKC_equals_1 +RAF_equals_0_to_RAF_equals_1_when_AKT_equals_0_and_ERK_equals_0_and_RAS_equals_1 +RAF_equals_1_to_RAF_equals_0_when_AKT_equals_1 +RAF_equals_1_to_RAF_equals_0_when_ERK_equals_1 +RAF_equals_1_to_RAF_equals_0_when_PKC_equals_0_and_RAS_equals_0 +RAS_equals_0_to_RAS_equals_1_when_PLCG_equals_1 +RAS_equals_0_to_RAS_equals_1_when_SOS_equals_1 +RAS_equals_1_to_RAS_equals_0_when_PLCG_equals_0_and_SOS_equals_0 +RSK_equals_0_to_RSK_equals_1_when_ERK_equals_1 +RSK_equals_1_to_RSK_equals_0_when_ERK_equals_0 +SMAD_equals_0_to_SMAD_equals_1_when_TGFBR_equals_1 +SMAD_equals_1_to_SMAD_equals_0_when_TGFBR_equals_0 +SOS_equals_0_to_SOS_equals_1_when_GRB2_equals_1_and_RSK_equals_0 +SOS_equals_1_to_SOS_equals_0_when_GRB2_equals_0 +SOS_equals_1_to_SOS_equals_0_when_RSK_equals_1 +SPRY_equals_0_to_SPRY_equals_1_when_ERK_equals_1 +SPRY_equals_1_to_SPRY_equals_0_when_ERK_equals_0 +TAK1_equals_0_to_TAK1_equals_1_when_TGFBR_equals_1 +TAK1_equals_1_to_TAK1_equals_0_when_TGFBR_equals_0 +TAOK_equals_0_to_TAOK_equals_1_when_ATM_equals_1 +TAOK_equals_1_to_TAOK_equals_0_when_ATM_equals_0 +TGFBR_equals_0_to_TGFBR_equals_1_when_TGFBR_stimulus_equals_1 +TGFBR_equals_1_to_TGFBR_equals_0_when_TGFBR_stimulus_equals_0 +p14_equals_0_to_p14_equals_1_when_MYC_equals_1 +p14_equals_1_to_p14_equals_0_when_MYC_equals_0 +p21_equals_0_to_p21_equals_1_when_AKT_equals_0_and_p53_equals_1 +p21_equals_1_to_p21_equals_0_when_AKT_equals_1 +p21_equals_1_to_p21_equals_0_when_p53_equals_0 +p38_equals_0_to_p38_equals_1_when_DUSP1_equals_0_and_MAP3K1_3_equals_1 +p38_equals_0_to_p38_equals_1_when_DUSP1_equals_0_and_MTK1_equals_1 +p38_equals_0_to_p38_equals_1_when_DUSP1_equals_0_and_TAK1_equals_1 +p38_equals_0_to_p38_equals_1_when_DUSP1_equals_0_and_TAOK_equals_1 +p38_equals_0_to_p38_equals_1_when_DUSP1_equals_1_and_MAP3K1_3_equals_0_and_MTK1_equals_0_and_TAK1_equals_1_and_TAOK_equals_1 +p38_equals_0_to_p38_equals_1_when_DUSP1_equals_1_and_MAP3K1_3_equals_0_and_MTK1_equals_1_and_TAK1_equals_1 +p38_equals_0_to_p38_equals_1_when_DUSP1_equals_1_and_MAP3K1_3_equals_0_and_MTK1_equals_1_and_TAOK_equals_1 +p38_equals_0_to_p38_equals_1_when_DUSP1_equals_1_and_MAP3K1_3_equals_1_and_MTK1_equals_1 +p38_equals_0_to_p38_equals_1_when_DUSP1_equals_1_and_MAP3K1_3_equals_1_and_TAK1_equals_1 +p38_equals_0_to_p38_equals_1_when_DUSP1_equals_1_and_MAP3K1_3_equals_1_and_TAOK_equals_1 +p38_equals_1_to_p38_equals_0_when_DUSP1_equals_0_and_MAP3K1_3_equals_0_and_MTK1_equals_0_and_TAK1_equals_0_and_TAOK_equals_0 +p38_equals_1_to_p38_equals_0_when_DUSP1_equals_1_and_MAP3K1_3_equals_0_and_MTK1_equals_0_and_TAK1_equals_0 +p38_equals_1_to_p38_equals_0_when_DUSP1_equals_1_and_MAP3K1_3_equals_0_and_MTK1_equals_0_and_TAOK_equals_0 +p38_equals_1_to_p38_equals_0_when_DUSP1_equals_1_and_MAP3K1_3_equals_0_and_MTK1_equals_1_and_TAK1_equals_0_and_TAOK_equals_0 +p38_equals_1_to_p38_equals_0_when_DUSP1_equals_1_and_MAP3K1_3_equals_1_and_MTK1_equals_0_and_TAK1_equals_0_and_TAOK_equals_0 +p53_equals_0_to_p53_equals_1_when_ATM_equals_0_and_MDM2_equals_0_and_p38_equals_1 +p53_equals_0_to_p53_equals_1_when_ATM_equals_1_and_MDM2_equals_0 +p53_equals_0_to_p53_equals_1_when_ATM_equals_1_and_p38_equals_1 +p53_equals_1_to_p53_equals_0_when_ATM_equals_0_and_MDM2_equals_1 +p53_equals_1_to_p53_equals_0_when_ATM_equals_0_and_p38_equals_0 +p53_equals_1_to_p53_equals_0_when_ATM_equals_1_and_MDM2_equals_1_and_p38_equals_0 +p70_equals_0_to_p70_equals_1_when_ERK_equals_1_and_PDK1_equals_1 +p70_equals_1_to_p70_equals_0_when_ERK_equals_0 +p70_equals_1_to_p70_equals_0_when_PDK1_equals_0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +MAPKbis-PT-5310 diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/Philosophers-5.pnml b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/Philosophers-5.pnml new file mode 100644 index 0000000000..49e2eaf7e5 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/Philosophers-5.pnml @@ -0,0 +1,623 @@ + + + + + + DefaultPage + + + + + + + Think_1 + + + + + + + + + 1 + + + + + + + + Think_2 + + + + + + + + + 1 + + + + + + + + Think_3 + + + + + + + + + 1 + + + + + + + + Think_4 + + + + + + + + + 1 + + + + + + + + Think_5 + + + + + + + + + 1 + + + + + + + + Fork_1 + + + + + + + + + 1 + + + + + + + + Fork_2 + + + + + + + + + 1 + + + + + + + + Fork_3 + + + + + + + + + 1 + + + + + + + + Fork_4 + + + + + + + + + 1 + + + + + + + + Fork_5 + + + + + + + + + 1 + + + + + + + + Catch1_1 + + + + + + + + + + + Catch1_2 + + + + + + + + + + + Catch1_3 + + + + + + + + + + + Catch1_5 + + + + + + + + + + + Catch1_4 + + + + + + + + + + + Catch2_2 + + + + + + + + + + + Catch2_1 + + + + + + + + + + + Catch2_4 + + + + + + + + + + + Catch2_3 + + + + + + + + + + + Eat_1 + + + + + + + + + + + Catch2_5 + + + + + + + + + + + Eat_3 + + + + + + + + + + + Eat_2 + + + + + + + + + + + Eat_5 + + + + + + + + + + + Eat_4 + + + + + + + + + + + FF1a_2 + + + + + + + + + + + FF1a_1 + + + + + + + + + + + FF1a_4 + + + + + + + + + + + FF1a_3 + + + + + + + + + + + FF1b_2 + + + + + + + + + + + FF1b_3 + + + + + + + + + + + FF1a_5 + + + + + + + + + + + FF1b_1 + + + + + + + + + + + FF2a_1 + + + + + + + + + + + FF2a_2 + + + + + + + + + + + FF1b_4 + + + + + + + + + + + FF1b_5 + + + + + + + + + + + FF2a_5 + + + + + + + + + + + FF2b_1 + + + + + + + + + + + FF2a_3 + + + + + + + + + + + FF2a_4 + + + + + + + + + + + FF2b_4 + + + + + + + + + + + FF2b_5 + + + + + + + + + + + FF2b_2 + + + + + + + + + + + FF2b_3 + + + + + + + + + + + End_4 + + + + + + + + + + + End_3 + + + + + + + + + + + End_2 + + + + + + + + + + + End_1 + + + + + + + + + + + End_5 + + + + + + + + Philosophers-PT-000005 + + + diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/Philosophers-5.pnml.order b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/Philosophers-5.pnml.order new file mode 100644 index 0000000000..75e25c15fc --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/Philosophers-5.pnml.order @@ -0,0 +1,25 @@ +Think_1 +Fork_1 +Catch1_1 +Catch2_1 +Eat_1 +Think_2 +Fork_2 +Catch1_2 +Catch2_2 +Eat_2 +Think_3 +Fork_3 +Catch1_3 +Catch2_3 +Eat_3 +Think_4 +Fork_4 +Catch1_4 +Catch2_4 +Eat_4 +Think_5 +Fork_5 +Catch1_5 +Catch2_5 +Eat_5 \ No newline at end of file diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/Philosophers-50.pnml b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/Philosophers-50.pnml new file mode 100644 index 0000000000..59b3b6a391 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/Philosophers-50.pnml @@ -0,0 +1,6113 @@ + + + + + + DefaultPage + + + + + + + Eat_1 + + + + + + + + + + + Eat_2 + + + + + + + + + + + Eat_3 + + + + + + + + + + + Eat_4 + + + + + + + + + + + Eat_5 + + + + + + + + + + + Eat_6 + + + + + + + + + + + Eat_7 + + + + + + + + + + + Eat_8 + + + + + + + + + + + Eat_9 + + + + + + + + + + + Eat_10 + + + + + + + + + + + Eat_11 + + + + + + + + + + + Eat_12 + + + + + + + + + + + Eat_13 + + + + + + + + + + + Eat_15 + + + + + + + + + + + Eat_14 + + + + + + + + + + + Eat_17 + + + + + + + + + + + Eat_16 + + + + + + + + + + + Eat_19 + + + + + + + + + + + Eat_18 + + + + + + + + + + + Eat_21 + + + + + + + + + + + Eat_20 + + + + + + + + + + + Eat_23 + + + + + + + + + + + Eat_22 + + + + + + + + + + + Eat_25 + + + + + + + + + + + Eat_24 + + + + + + + + + + + Eat_27 + + + + + + + + + + + Eat_26 + + + + + + + + + + + Eat_29 + + + + + + + + + + + Eat_28 + + + + + + + + + + + Eat_32 + + + + + + + + + + + Eat_33 + + + + + + + + + + + Eat_30 + + + + + + + + + + + Eat_31 + + + + + + + + + + + Eat_36 + + + + + + + + + + + Eat_37 + + + + + + + + + + + Eat_34 + + + + + + + + + + + Eat_35 + + + + + + + + + + + Eat_40 + + + + + + + + + + + Eat_41 + + + + + + + + + + + Eat_38 + + + + + + + + + + + Eat_39 + + + + + + + + + + + Eat_44 + + + + + + + + + + + Eat_45 + + + + + + + + + + + Eat_42 + + + + + + + + + + + Eat_43 + + + + + + + + + + + Eat_49 + + + + + + + + + + + Eat_48 + + + + + + + + + + + Eat_47 + + + + + + + + + + + Eat_46 + + + + + + + + + + + Fork_3 + + + + + + + + + 1 + + + + + + + + Fork_2 + + + + + + + + + 1 + + + + + + + + Fork_1 + + + + + + + + + 1 + + + + + + + + Eat_50 + + + + + + + + + + + Fork_7 + + + + + + + + + 1 + + + + + + + + Fork_6 + + + + + + + + + 1 + + + + + + + + Fork_5 + + + + + + + + + 1 + + + + + + + + Fork_4 + + + + + + + + + 1 + + + + + + + + Fork_11 + + + + + + + + + 1 + + + + + + + + Fork_10 + + + + + + + + + 1 + + + + + + + + Fork_9 + + + + + + + + + 1 + + + + + + + + Fork_8 + + + + + + + + + 1 + + + + + + + + Fork_16 + + + + + + + + + 1 + + + + + + + + Fork_17 + + + + + + + + + 1 + + + + + + + + Fork_18 + + + + + + + + + 1 + + + + + + + + Fork_19 + + + + + + + + + 1 + + + + + + + + Fork_12 + + + + + + + + + 1 + + + + + + + + Fork_13 + + + + + + + + + 1 + + + + + + + + Fork_14 + + + + + + + + + 1 + + + + + + + + Fork_15 + + + + + + + + + 1 + + + + + + + + Fork_24 + + + + + + + + + 1 + + + + + + + + Fork_25 + + + + + + + + + 1 + + + + + + + + Fork_26 + + + + + + + + + 1 + + + + + + + + Fork_27 + + + + + + + + + 1 + + + + + + + + Fork_20 + + + + + + + + + 1 + + + + + + + + Fork_21 + + + + + + + + + 1 + + + + + + + + Fork_22 + + + + + + + + + 1 + + + + + + + + Fork_23 + + + + + + + + + 1 + + + + + + + + Fork_33 + + + + + + + + + 1 + + + + + + + + Fork_32 + + + + + + + + + 1 + + + + + + + + Fork_35 + + + + + + + + + 1 + + + + + + + + Fork_34 + + + + + + + + + 1 + + + + + + + + Fork_29 + + + + + + + + + 1 + + + + + + + + Fork_28 + + + + + + + + + 1 + + + + + + + + Fork_31 + + + + + + + + + 1 + + + + + + + + Fork_30 + + + + + + + + + 1 + + + + + + + + Fork_41 + + + + + + + + + 1 + + + + + + + + Fork_40 + + + + + + + + + 1 + + + + + + + + Fork_43 + + + + + + + + + 1 + + + + + + + + Fork_42 + + + + + + + + + 1 + + + + + + + + Fork_37 + + + + + + + + + 1 + + + + + + + + Fork_36 + + + + + + + + + 1 + + + + + + + + Fork_39 + + + + + + + + + 1 + + + + + + + + Fork_38 + + + + + + + + + 1 + + + + + + + + Fork_50 + + + + + + + + + 1 + + + + + + + + Think_1 + + + + + + + + + 1 + + + + + + + + Fork_48 + + + + + + + + + 1 + + + + + + + + Fork_49 + + + + + + + + + 1 + + + + + + + + Fork_46 + + + + + + + + + 1 + + + + + + + + Fork_47 + + + + + + + + + 1 + + + + + + + + Fork_44 + + + + + + + + + 1 + + + + + + + + Fork_45 + + + + + + + + + 1 + + + + + + + + Think_8 + + + + + + + + + 1 + + + + + + + + Think_9 + + + + + + + + + 1 + + + + + + + + Think_6 + + + + + + + + + 1 + + + + + + + + Think_7 + + + + + + + + + 1 + + + + + + + + Think_4 + + + + + + + + + 1 + + + + + + + + Think_5 + + + + + + + + + 1 + + + + + + + + Think_2 + + + + + + + + + 1 + + + + + + + + Think_3 + + + + + + + + + 1 + + + + + + + + Think_17 + + + + + + + + + 1 + + + + + + + + Think_16 + + + + + + + + + 1 + + + + + + + + Think_15 + + + + + + + + + 1 + + + + + + + + Think_14 + + + + + + + + + 1 + + + + + + + + Think_13 + + + + + + + + + 1 + + + + + + + + Think_12 + + + + + + + + + 1 + + + + + + + + Think_11 + + + + + + + + + 1 + + + + + + + + Think_10 + + + + + + + + + 1 + + + + + + + + Think_25 + + + + + + + + + 1 + + + + + + + + Think_24 + + + + + + + + + 1 + + + + + + + + Think_23 + + + + + + + + + 1 + + + + + + + + Think_22 + + + + + + + + + 1 + + + + + + + + Think_21 + + + + + + + + + 1 + + + + + + + + Think_20 + + + + + + + + + 1 + + + + + + + + Think_19 + + + + + + + + + 1 + + + + + + + + Think_18 + + + + + + + + + 1 + + + + + + + + Think_35 + + + + + + + + + 1 + + + + + + + + Think_34 + + + + + + + + + 1 + + + + + + + + Think_37 + + + + + + + + + 1 + + + + + + + + Think_36 + + + + + + + + + 1 + + + + + + + + Think_39 + + + + + + + + + 1 + + + + + + + + Think_38 + + + + + + + + + 1 + + + + + + + + Think_41 + + + + + + + + + 1 + + + + + + + + Think_40 + + + + + + + + + 1 + + + + + + + + Think_27 + + + + + + + + + 1 + + + + + + + + Think_26 + + + + + + + + + 1 + + + + + + + + Think_29 + + + + + + + + + 1 + + + + + + + + Think_28 + + + + + + + + + 1 + + + + + + + + Think_31 + + + + + + + + + 1 + + + + + + + + Think_30 + + + + + + + + + 1 + + + + + + + + Think_33 + + + + + + + + + 1 + + + + + + + + Think_32 + + + + + + + + + 1 + + + + + + + + Think_50 + + + + + + + + + 1 + + + + + + + + Catch2_1 + + + + + + + + + + + Catch2_2 + + + + + + + + + + + Catch2_3 + + + + + + + + + + + Catch2_4 + + + + + + + + + + + Catch2_5 + + + + + + + + + + + Catch2_6 + + + + + + + + + + + Catch2_7 + + + + + + + + + + + Think_42 + + + + + + + + + 1 + + + + + + + + Think_43 + + + + + + + + + 1 + + + + + + + + Think_44 + + + + + + + + + 1 + + + + + + + + Think_45 + + + + + + + + + 1 + + + + + + + + Think_46 + + + + + + + + + 1 + + + + + + + + Think_47 + + + + + + + + + 1 + + + + + + + + Think_48 + + + + + + + + + 1 + + + + + + + + Think_49 + + + + + + + + + 1 + + + + + + + + Catch2_19 + + + + + + + + + + + Catch2_18 + + + + + + + + + + + Catch2_17 + + + + + + + + + + + Catch2_16 + + + + + + + + + + + Catch2_23 + + + + + + + + + + + Catch2_22 + + + + + + + + + + + Catch2_21 + + + + + + + + + + + Catch2_20 + + + + + + + + + + + Catch2_11 + + + + + + + + + + + Catch2_10 + + + + + + + + + + + Catch2_9 + + + + + + + + + + + Catch2_8 + + + + + + + + + + + Catch2_15 + + + + + + + + + + + Catch2_14 + + + + + + + + + + + Catch2_13 + + + + + + + + + + + Catch2_12 + + + + + + + + + + + Catch2_34 + + + + + + + + + + + Catch2_35 + + + + + + + + + + + Catch2_32 + + + + + + + + + + + Catch2_33 + + + + + + + + + + + Catch2_38 + + + + + + + + + + + Catch2_39 + + + + + + + + + + + Catch2_36 + + + + + + + + + + + Catch2_37 + + + + + + + + + + + Catch2_26 + + + + + + + + + + + Catch2_27 + + + + + + + + + + + Catch2_24 + + + + + + + + + + + Catch2_25 + + + + + + + + + + + Catch2_30 + + + + + + + + + + + Catch2_31 + + + + + + + + + + + Catch2_28 + + + + + + + + + + + Catch2_29 + + + + + + + + + + + Catch1_3 + + + + + + + + + + + Catch1_2 + + + + + + + + + + + Catch1_5 + + + + + + + + + + + Catch1_4 + + + + + + + + + + + Catch2_49 + + + + + + + + + + + Catch2_48 + + + + + + + + + + + Catch1_1 + + + + + + + + + + + Catch2_50 + + + + + + + + + + + Catch2_45 + + + + + + + + + + + Catch2_44 + + + + + + + + + + + Catch2_47 + + + + + + + + + + + Catch2_46 + + + + + + + + + + + Catch2_41 + + + + + + + + + + + Catch2_40 + + + + + + + + + + + Catch2_43 + + + + + + + + + + + Catch2_42 + + + + + + + + + + + Catch1_18 + + + + + + + + + + + Catch1_19 + + + + + + + + + + + Catch1_20 + + + + + + + + + + + Catch1_21 + + + + + + + + + + + Catch1_14 + + + + + + + + + + + Catch1_15 + + + + + + + + + + + Catch1_16 + + + + + + + + + + + Catch1_17 + + + + + + + + + + + Catch1_10 + + + + + + + + + + + Catch1_11 + + + + + + + + + + + Catch1_12 + + + + + + + + + + + Catch1_13 + + + + + + + + + + + Catch1_6 + + + + + + + + + + + Catch1_7 + + + + + + + + + + + Catch1_8 + + + + + + + + + + + Catch1_9 + + + + + + + + + + + Catch1_37 + + + + + + + + + + + Catch1_36 + + + + + + + + + + + Catch1_35 + + + + + + + + + + + Catch1_34 + + + + + + + + + + + Catch1_33 + + + + + + + + + + + Catch1_32 + + + + + + + + + + + Catch1_31 + + + + + + + + + + + Catch1_30 + + + + + + + + + + + Catch1_29 + + + + + + + + + + + Catch1_28 + + + + + + + + + + + Catch1_27 + + + + + + + + + + + Catch1_26 + + + + + + + + + + + Catch1_25 + + + + + + + + + + + Catch1_24 + + + + + + + + + + + Catch1_23 + + + + + + + + + + + Catch1_22 + + + + + + + + + + + Catch1_50 + + + + + + + + + + + Catch1_48 + + + + + + + + + + + Catch1_49 + + + + + + + + + + + Catch1_46 + + + + + + + + + + + Catch1_47 + + + + + + + + + + + Catch1_44 + + + + + + + + + + + Catch1_45 + + + + + + + + + + + Catch1_42 + + + + + + + + + + + Catch1_43 + + + + + + + + + + + Catch1_40 + + + + + + + + + + + Catch1_41 + + + + + + + + + + + Catch1_38 + + + + + + + + + + + Catch1_39 + + + + + + + + + + + End_2 + + + + + + + + + + + End_3 + + + + + + + + + + + End_1 + + + + + + + + + + + End_23 + + + + + + + + + + + End_22 + + + + + + + + + + + End_21 + + + + + + + + + + + End_20 + + + + + + + + + + + End_27 + + + + + + + + + + + End_26 + + + + + + + + + + + End_25 + + + + + + + + + + + End_24 + + + + + + + + + + + End_31 + + + + + + + + + + + End_30 + + + + + + + + + + + End_29 + + + + + + + + + + + End_28 + + + + + + + + + + + End_35 + + + + + + + + + + + End_34 + + + + + + + + + + + End_33 + + + + + + + + + + + End_32 + + + + + + + + + + + End_6 + + + + + + + + + + + End_7 + + + + + + + + + + + End_4 + + + + + + + + + + + End_5 + + + + + + + + + + + End_10 + + + + + + + + + + + End_11 + + + + + + + + + + + End_8 + + + + + + + + + + + End_9 + + + + + + + + + + + End_14 + + + + + + + + + + + End_15 + + + + + + + + + + + End_12 + + + + + + + + + + + End_13 + + + + + + + + + + + End_18 + + + + + + + + + + + End_19 + + + + + + + + + + + End_16 + + + + + + + + + + + End_17 + + + + + + + + + + + FF2b_3 + + + + + + + + + + + FF2b_2 + + + + + + + + + + + FF2b_5 + + + + + + + + + + + FF2b_4 + + + + + + + + + + + FF2b_7 + + + + + + + + + + + FF2b_6 + + + + + + + + + + + FF2b_9 + + + + + + + + + + + FF2b_8 + + + + + + + + + + + FF2b_11 + + + + + + + + + + + FF2b_10 + + + + + + + + + + + FF2b_13 + + + + + + + + + + + FF2b_12 + + + + + + + + + + + FF2b_15 + + + + + + + + + + + FF2b_14 + + + + + + + + + + + FF2b_17 + + + + + + + + + + + FF2b_16 + + + + + + + + + + + End_36 + + + + + + + + + + + End_37 + + + + + + + + + + + End_38 + + + + + + + + + + + End_39 + + + + + + + + + + + End_40 + + + + + + + + + + + End_41 + + + + + + + + + + + End_42 + + + + + + + + + + + End_43 + + + + + + + + + + + End_44 + + + + + + + + + + + End_45 + + + + + + + + + + + End_46 + + + + + + + + + + + End_47 + + + + + + + + + + + End_48 + + + + + + + + + + + End_49 + + + + + + + + + + + End_50 + + + + + + + + + + + FF2b_1 + + + + + + + + + + + FF2b_41 + + + + + + + + + + + FF2b_40 + + + + + + + + + + + FF2b_39 + + + + + + + + + + + FF2b_38 + + + + + + + + + + + FF2b_37 + + + + + + + + + + + FF2b_36 + + + + + + + + + + + FF2b_35 + + + + + + + + + + + FF2b_34 + + + + + + + + + + + FF2b_49 + + + + + + + + + + + FF2b_48 + + + + + + + + + + + FF2b_47 + + + + + + + + + + + FF2b_46 + + + + + + + + + + + FF2b_45 + + + + + + + + + + + FF2b_44 + + + + + + + + + + + FF2b_43 + + + + + + + + + + + FF2b_42 + + + + + + + + + + + FF2b_24 + + + + + + + + + + + FF2b_25 + + + + + + + + + + + FF2b_22 + + + + + + + + + + + FF2b_23 + + + + + + + + + + + FF2b_20 + + + + + + + + + + + FF2b_21 + + + + + + + + + + + FF2b_18 + + + + + + + + + + + FF2b_19 + + + + + + + + + + + FF2b_32 + + + + + + + + + + + FF2b_33 + + + + + + + + + + + FF2b_30 + + + + + + + + + + + FF2b_31 + + + + + + + + + + + FF2b_28 + + + + + + + + + + + FF2b_29 + + + + + + + + + + + FF2b_26 + + + + + + + + + + + FF2b_27 + + + + + + + + + + + FF2a_21 + + + + + + + + + + + FF2a_20 + + + + + + + + + + + FF2a_23 + + + + + + + + + + + FF2a_22 + + + + + + + + + + + FF2a_17 + + + + + + + + + + + FF2a_16 + + + + + + + + + + + FF2a_19 + + + + + + + + + + + FF2a_18 + + + + + + + + + + + FF2a_29 + + + + + + + + + + + FF2a_28 + + + + + + + + + + + FF2a_31 + + + + + + + + + + + FF2a_30 + + + + + + + + + + + FF2a_25 + + + + + + + + + + + FF2a_24 + + + + + + + + + + + FF2a_27 + + + + + + + + + + + FF2a_26 + + + + + + + + + + + FF2a_4 + + + + + + + + + + + FF2a_5 + + + + + + + + + + + FF2a_6 + + + + + + + + + + + FF2a_7 + + + + + + + + + + + FF2b_50 + + + + + + + + + + + FF2a_1 + + + + + + + + + + + FF2a_2 + + + + + + + + + + + FF2a_3 + + + + + + + + + + + FF2a_12 + + + + + + + + + + + FF2a_13 + + + + + + + + + + + FF2a_14 + + + + + + + + + + + FF2a_15 + + + + + + + + + + + FF2a_8 + + + + + + + + + + + FF2a_9 + + + + + + + + + + + FF2a_10 + + + + + + + + + + + FF2a_11 + + + + + + + + + + + FF1b_8 + + + + + + + + + + + FF1b_9 + + + + + + + + + + + FF1b_6 + + + + + + + + + + + FF1b_7 + + + + + + + + + + + FF1b_12 + + + + + + + + + + + FF1b_13 + + + + + + + + + + + FF1b_10 + + + + + + + + + + + FF1b_11 + + + + + + + + + + + FF2a_50 + + + + + + + + + + + FF1b_1 + + + + + + + + + + + FF2a_48 + + + + + + + + + + + FF2a_49 + + + + + + + + + + + FF1b_4 + + + + + + + + + + + FF1b_5 + + + + + + + + + + + FF1b_2 + + + + + + + + + + + FF1b_3 + + + + + + + + + + + FF2a_43 + + + + + + + + + + + FF2a_42 + + + + + + + + + + + FF2a_41 + + + + + + + + + + + FF2a_40 + + + + + + + + + + + FF2a_47 + + + + + + + + + + + FF2a_46 + + + + + + + + + + + FF2a_45 + + + + + + + + + + + FF2a_44 + + + + + + + + + + + FF2a_35 + + + + + + + + + + + FF2a_34 + + + + + + + + + + + FF2a_33 + + + + + + + + + + + FF2a_32 + + + + + + + + + + + FF2a_39 + + + + + + + + + + + FF2a_38 + + + + + + + + + + + FF2a_37 + + + + + + + + + + + FF2a_36 + + + + + + + + + + + FF1b_38 + + + + + + + + + + + FF1b_39 + + + + + + + + + + + FF1b_40 + + + + + + + + + + + FF1b_41 + + + + + + + + + + + FF1b_42 + + + + + + + + + + + FF1b_43 + + + + + + + + + + + FF1b_44 + + + + + + + + + + + FF1b_45 + + + + + + + + + + + FF1b_30 + + + + + + + + + + + FF1b_31 + + + + + + + + + + + FF1b_32 + + + + + + + + + + + FF1b_33 + + + + + + + + + + + FF1b_34 + + + + + + + + + + + FF1b_35 + + + + + + + + + + + FF1b_36 + + + + + + + + + + + FF1b_37 + + + + + + + + + + + FF1b_23 + + + + + + + + + + + FF1b_22 + + + + + + + + + + + FF1b_25 + + + + + + + + + + + FF1b_24 + + + + + + + + + + + FF1b_27 + + + + + + + + + + + FF1b_26 + + + + + + + + + + + FF1b_29 + + + + + + + + + + + FF1b_28 + + + + + + + + + + + FF1b_15 + + + + + + + + + + + FF1b_14 + + + + + + + + + + + FF1b_17 + + + + + + + + + + + FF1b_16 + + + + + + + + + + + FF1b_19 + + + + + + + + + + + FF1b_18 + + + + + + + + + + + FF1b_21 + + + + + + + + + + + FF1b_20 + + + + + + + + + + + FF1a_26 + + + + + + + + + + + FF1a_27 + + + + + + + + + + + FF1a_24 + + + + + + + + + + + FF1a_25 + + + + + + + + + + + FF1a_22 + + + + + + + + + + + FF1a_23 + + + + + + + + + + + FF1a_20 + + + + + + + + + + + FF1a_21 + + + + + + + + + + + FF1a_18 + + + + + + + + + + + FF1a_19 + + + + + + + + + + + FF1a_16 + + + + + + + + + + + FF1a_17 + + + + + + + + + + + FF1a_14 + + + + + + + + + + + FF1a_15 + + + + + + + + + + + FF1a_12 + + + + + + + + + + + FF1a_13 + + + + + + + + + + + FF1a_11 + + + + + + + + + + + FF1a_10 + + + + + + + + + + + FF1a_9 + + + + + + + + + + + FF1a_8 + + + + + + + + + + + FF1a_7 + + + + + + + + + + + FF1a_6 + + + + + + + + + + + FF1a_5 + + + + + + + + + + + FF1a_4 + + + + + + + + + + + FF1a_3 + + + + + + + + + + + FF1a_2 + + + + + + + + + + + FF1a_1 + + + + + + + + + + + FF1b_50 + + + + + + + + + + + FF1b_49 + + + + + + + + + + + FF1b_48 + + + + + + + + + + + FF1b_47 + + + + + + + + + + + FF1b_46 + + + + + + + + + + + FF1a_48 + + + + + + + + + + + FF1a_49 + + + + + + + + + + + FF1a_50 + + + + + + + + + + + FF1a_44 + + + + + + + + + + + FF1a_45 + + + + + + + + + + + FF1a_46 + + + + + + + + + + + FF1a_47 + + + + + + + + + + + FF1a_41 + + + + + + + + + + + FF1a_40 + + + + + + + + + + + FF1a_43 + + + + + + + + + + + FF1a_42 + + + + + + + + + + + FF1a_37 + + + + + + + + + + + FF1a_36 + + + + + + + + + + + FF1a_39 + + + + + + + + + + + FF1a_38 + + + + + + + + + + + FF1a_33 + + + + + + + + + + + FF1a_32 + + + + + + + + + + + FF1a_35 + + + + + + + + + + + FF1a_34 + + + + + + + + + + + FF1a_29 + + + + + + + + + + + FF1a_28 + + + + + + + + + + + FF1a_31 + + + + + + + + + + + FF1a_30 + + + + + + + + Philosophers-PT-000050 + + + diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/Philosophers-50.pnml.gsat.order b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/Philosophers-50.pnml.gsat.order new file mode 100644 index 0000000000..f7162c17b9 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/Philosophers-50.pnml.gsat.order @@ -0,0 +1,250 @@ +Think_28 +Catch2_28 +Catch1_28 +Eat_28 +Fork_28 +Catch1_29 +Think_29 +Catch2_29 +Eat_29 +Fork_27 +Catch2_27 +Think_27 +Catch1_27 +Eat_27 +Fork_29 +Catch1_30 +Think_30 +Catch2_30 +Eat_30 +Fork_26 +Catch2_26 +Think_26 +Catch1_26 +Eat_26 +Fork_30 +Catch1_31 +Think_31 +Catch2_31 +Eat_31 +Fork_25 +Catch2_25 +Think_25 +Catch1_25 +Eat_25 +Fork_31 +Catch1_32 +Think_32 +Catch2_32 +Eat_32 +Fork_24 +Catch2_24 +Think_24 +Catch1_24 +Eat_24 +Fork_32 +Catch1_33 +Think_33 +Catch2_33 +Eat_33 +Fork_23 +Catch2_23 +Think_23 +Catch1_23 +Eat_23 +Fork_33 +Catch1_34 +Think_34 +Catch2_34 +Eat_34 +Fork_22 +Catch2_22 +Think_22 +Catch1_22 +Eat_22 +Fork_34 +Catch1_35 +Think_35 +Catch2_35 +Eat_35 +Fork_21 +Catch2_21 +Think_21 +Catch1_21 +Eat_21 +Fork_35 +Catch1_36 +Think_36 +Catch2_36 +Eat_36 +Fork_20 +Catch2_20 +Think_20 +Catch1_20 +Eat_20 +Fork_36 +Catch1_37 +Think_37 +Catch2_37 +Eat_37 +Fork_19 +Catch2_19 +Think_19 +Catch1_19 +Eat_19 +Fork_37 +Catch1_38 +Think_38 +Catch2_38 +Eat_38 +Fork_18 +Catch2_18 +Think_18 +Catch1_18 +Eat_18 +Fork_38 +Catch1_39 +Think_39 +Catch2_39 +Eat_39 +Fork_17 +Catch2_17 +Think_17 +Catch1_17 +Eat_17 +Fork_39 +Catch1_40 +Think_40 +Catch2_40 +Eat_40 +Fork_16 +Catch2_16 +Think_16 +Catch1_16 +Eat_16 +Fork_40 +Catch1_41 +Think_41 +Catch2_41 +Eat_41 +Fork_15 +Catch2_15 +Think_15 +Catch1_15 +Eat_15 +Fork_41 +Catch1_42 +Think_42 +Catch2_42 +Eat_42 +Fork_14 +Catch2_14 +Think_14 +Catch1_14 +Eat_14 +Fork_42 +Catch1_43 +Think_43 +Catch2_43 +Eat_43 +Fork_13 +Catch2_13 +Think_13 +Catch1_13 +Eat_13 +Fork_43 +Catch1_44 +Think_44 +Catch2_44 +Eat_44 +Fork_12 +Catch2_12 +Think_12 +Catch1_12 +Eat_12 +Fork_44 +Catch1_45 +Think_45 +Catch2_45 +Eat_45 +Fork_11 +Catch2_11 +Think_11 +Catch1_11 +Eat_11 +Fork_45 +Catch1_46 +Think_46 +Catch2_46 +Eat_46 +Fork_10 +Catch2_10 +Think_10 +Catch1_10 +Eat_10 +Fork_46 +Catch1_47 +Think_47 +Catch2_47 +Eat_47 +Fork_9 +Catch2_9 +Think_9 +Catch1_9 +Eat_9 +Fork_47 +Catch1_48 +Think_48 +Catch2_48 +Eat_48 +Fork_8 +Catch2_8 +Think_8 +Catch1_8 +Eat_8 +Fork_48 +Catch1_49 +Think_49 +Catch2_49 +Eat_49 +Fork_7 +Catch2_7 +Think_7 +Catch1_7 +Eat_7 +Fork_49 +Catch1_50 +Think_50 +Catch2_50 +Eat_50 +Fork_6 +Catch2_6 +Think_6 +Catch1_6 +Eat_6 +Fork_50 +Catch1_1 +Think_1 +Catch2_1 +Eat_1 +Fork_5 +Catch2_5 +Think_5 +Catch1_5 +Eat_5 +Fork_1 +Catch1_2 +Think_2 +Catch2_2 +Eat_2 +Fork_4 +Catch2_4 +Think_4 +Catch1_4 +Eat_4 +Fork_2 +Fork_3 +Catch1_3 +Catch2_3 +Eat_3 +Think_3 diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/aslink_01_a.pnml b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/aslink_01_a.pnml new file mode 100644 index 0000000000..b4942dc60f --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/aslink_01_a.pnml @@ -0,0 +1,4323 @@ + + + +ASLink-PT-01a + +1p0 +p1 +p2 +p3 +p4 +p5 +p6 +p7 +p8 +p9 +p10 +p11 +p12 +p13 +p14 +p15 +p16 +p17 +p18 +p19 +p20 +p21 +p22 +p23 +p24 +p25 +p26 +p27 +p28 +p29 +p30 +p31 +p32 +p33 +p34 +p35 +p36 +p37 +p38 +p39 +p40 +p41 +p42 +p43 +p44 +p45 +p46 +p47 +p48 +p49 +p50 +p51 +p52 +p53 +p54 +p55 +p56 +p57 +p58 +p59 +p60 +p61 +p62 +p63 +p64 +p65 +p66 +p67 +p68 +p69 +p70 +p71 +p72 +p73 +p74 +p75 +p76 +p77 +p78 +p79 +p80 +p81 +p82 +p83 +p84 +p85 +p86 +p87 +p88 +p89 +p90 +p91 +p92 +p93 +p94 +p95 +p96 +p97 +p98 +p99 +p100 +p101 +p102 +p103 +p104 +p105 +p106 +p107 +p108 +p109 +p110 +p111 +p112 +p113 +p114 +p115 +p116 +p117 +p118 +p119 +p120 +p121 +p122 +p123 +p124 +p125 +p126 +p127 +p128 +p129 +p130 +p131 +p132 +p133 +p134 +p135 +p136 +p137 +p138 +p139 +p140 +p141 +p142 +p143 +p144 +p145 +p146 +p147 +p148 +p149 +p150 +p151 +p152 +p153 +p154 +p155 +p156 +p157 +p158 +p159 +p160 +p161 +p162 +p163 +p164 +p165 +p166 +p167 +p168 +p169 +p170 +p171 +p172 +p173 +p174 +p175 +p176 +p177 +p178 +p179 +p180 +p181 +p182 +p183 +p184 +p185 +p186 +p187 +p188 +p189 +p190 +p191 +p192 +p193 +p194 +p195 +p196 +p197 +p198 +p199 +p200 +p201 +p202 +p203 +p204 +p205 +p206 +p207 +p208 +p209 +p210 +p211 +p212 +p213 +p214 +p215 +p216 +p217 +p218 +p219 +p220 +p221 +p222 +p223 +p224 +p225 +p226 +p227 +p228 +p229 +p230 +p231 +p232 +p233 +p234 +p235 +p236 +p237 +p238 +p239 +p240 +p241 +p242 +p243 +p244 +p245 +p246 +p247 +p248 +p249 +p250 +p251 +p252 +p253 +p254 +p255 +p256 +p257 +p258 +p259 +p260 +p261 +p262 +p263 +p264 +p265 +p266 +p267 +p268 +p269 +p270 +p271 +p272 +p273 +p274 +p275 +p276 +p277 +p278 +p279 +p280 +p281 +p282 +p283 +p284 +p285 +p286 +p287 +p288 +p289 +p290 +p291 +p292 +p293 +p294 +p295 +p296 +p297 +p298 +p299 +p300 +p301 +p302 +p303 +p304 +p305 +p306 +p307 +p308 +p309 +p310 +p311 +p312 +p313 +p314 +p315 +p316 +p317 +p318 +p319 +p320 +p321 +p322 +p323 +p324 +p325 +p326 +p327 +p328 +p329 +p330 +p331 +p332 +p333 +p334 +p335 +p336 +p337 +p338 +p339 +p340 +p341 +p342 +p343 +p344 +p345 +p346 +p347 +p348 +p349 +p350 +p351 +p352 +p353 +p354 +p355 +p356 +p357 +p358 +p359 +p360 +p361 +p362 +p363 +p364 +p365 +p366 +p367 +p368 +p369 +p370 +p371 +p372 +p373 +p374 +p375 +p376 +p377 +p378 +p379 +p380 +p381 +p382 +p383 +p384 +p385 +p386 +p387 +p388 +p389 +p390 +p391 +p392 +p393 +p394 +p395 +p396 +p397 +p398 +p399 +p400 +p401 +p402 +p403 +p404 +p405 +p406 +p407 +p408 +p409 +p410 +p411 +p412 +p413 +p414 +p415 +p416 +p417 +p418 +p419 +p420 +p421 +p422 +p423 +p424 +p425 +p426 +p427 +p428 +p429 +p430 +t0 + + + +t1 + + + +t2 + + + +t3 + + + +t4 + + + +t5 + + + +t6 + + + +t7 + + + +t8 + + + + +t9 + + + + +t10 + + + + +t11 + + + +t12 + + + + +t13 + + + +t14 + + + + + +t15 + + + + +t16 + + + + +t17 + + + + +t18 + + + + + +t19 + + + + +t20 + + + + +t21 + + + + +t22 + + + + + + + + + + + + + + + + + + +t23 + + + + +t24 + + + +t25 + + +t26 + + +t27 + + +t28 + + +t29 + + +t30 + + + +t31 + + + +t32 + + + +t33 + + + + +t34 + + + +t35 + + + +t36 + + + +t37 + + + +t38 + + + +t39 + + +t40 + + +t41 + + +t42 + + +t43 + + + +t44 + + +t45 + + + +t46 + + +t47 + + + +t48 + + +t49 + + + +t50 + + +t51 + + +t52 + + +t53 + + +t54 + + +t55 + + +t56 + + +t57 + + +t58 + + +t59 + + +t60 + + +t61 + + +t62 + + +t63 + + +t64 + + +t65 + + +t66 + + +t67 + + +t68 + + +t69 + + +t70 + + +t71 + + +t72 + + +t73 + + +t74 + + +t75 + + +t76 + + +t77 + + +t78 + + +t79 + + +t80 + + +t81 + + +t82 + + +t83 + + +t84 + + +t85 + + +t86 + + +t87 + + +t88 + + +t89 + + +t90 + + +t91 + + +t92 + + +t93 + + +t94 + + +t95 + + +t96 + + +t97 + + + +t98 + + +t99 + + +t100 + + + +t101 + + + +t102 + + +t103 + + + +t104 + + +t105 + + +t106 + + + +t107 + + + +t108 + + +t109 + + + +t110 + + +t111 + + +t112 + + + +t113 + + + +t114 + + +t115 + + +t116 + + + + + +t117 + + + + + +t118 + + + + +t119 + + + + +t120 + + + + +t121 + + + + +t122 + + + + +t123 + + + + +t124 + + + + +t125 + + + + +t126 + + + + +t127 + + + + +t128 + + + + +t129 + + + + +t130 + + + + +t131 + + + + +t132 + + + + +t133 + + + + +t134 + + + + +t135 + + + + +t136 + + + + +t137 + + + + +t138 + + + + +t139 + + + + +t140 + + + + +t141 + + + + +t142 + + + + +t143 + + + + +t144 + + + + +t145 + + + + +t146 + + + + +t147 + + + + +t148 + + + + +t149 + + + + +t150 + + + + +t151 + + + + +t152 + + + + +t153 + + + + +t154 + + + + +t155 + + + + +t156 + + + + +t157 + + + + +t158 + + + + +t159 + + + + +t160 + + + + +t161 + + + + +t162 + + + + +t163 + + + + +t164 + + + + +t165 + + + + +t166 + + + + +t167 + + + + +t168 + + + + +t169 + + + + +t170 + + + + +t171 + + + + +t172 + + + + +t173 + + + + +t174 + + + + +t175 + + + + +t176 + + + + +t177 + + + + +t178 + + + + +t179 + + + + +t180 + + + + +t181 + + + + +t182 + + + + +t183 + + + + +t184 + + + + +t185 + + + + +t186 + + + + +t187 + + + + +t188 + + + + +t189 + + + + +t190 + + + + +t191 + + + + +t192 + + + + +t193 + + + + +t194 + + + + +t195 + + + + +t196 + + + + +t197 + + + + +t198 + + + + +t199 + + + + +t200 + + + + +t201 + + + + +t202 + + + + +t203 + + + + +t204 + + + + +t205 + + + + +t206 + + + + +t207 + + + + +t208 + + + + +t209 + + + + +t210 + + + + +t211 + + + + +t212 + + + + +t213 + + + + +t214 + + + + +t215 + + + + +t216 + + + + +t217 + + + + +t218 + + + + +t219 + + + + +t220 + + + + +t221 + + + + +t222 + + + + +t223 + + + + +t224 + + + + +t225 + + + + +t226 + + + + +t227 + + + + +t228 + + + + +t229 + + + + +t230 + + + + +t231 + + + + +t232 + + + + +t233 + + + + +t234 + + + + +t235 + + + + +t236 + + + + +t237 + + + + +t238 + + + + +t239 + + + + +t240 + + + + +t241 + + + + +t242 + + + + +t243 + + + + +t244 + + + + +t245 + + + + +t246 + + + + +t247 + + + + +t248 + + + + +t249 + + + + +t250 + + + + +t251 + + + + +t252 + + + + +t253 + + + + +t254 + + + + +t255 + + + + +t256 + + + + +t257 + + + + +t258 + + + + +t259 + + + + +t260 + + + + +t261 + + + + +t262 + + + + +t263 + + + + +t264 + + + + +t265 + + + + +t266 + + + + +t267 + + + + +t268 + + + + +t269 + + + + +t270 + + + + +t271 + + + + +t272 + + + + +t273 + + + + +t274 + + + + +t275 + + + + +t276 + + + + +t277 + + + + +t278 + + + + +t279 + + + + +t280 + + + + +t281 + + + + +t282 + + + + +t283 + + + + +t284 + + + + +t285 + + + + +t286 + + + + +t287 + + + + +t288 + + + + +t289 + + + + +t290 + + + + +t291 + + + + +t292 + + + + +t293 + + + + +t294 + + + + +t295 + + + + +t296 + + + + +t297 + + + + +t298 + + + + +t299 + + + + +t300 + + + + +t301 + + + + +t302 + + + + +t303 + + + + +t304 + + + + +t305 + + + + +t306 + + + + +t307 + + + + +t308 + + + + +t309 + + + + +t310 + + + + +t311 + + + + +t312 + + + + +t313 + + + + +t314 + + + + +t315 + + + + +t316 + + + + +t317 + + + + +t318 + + + + +t319 + + + + +t320 + + + + +t321 + + + + +t322 + + + + +t323 + + + + +t324 + + + + +t325 + + + + +t326 + + + + +t327 + + + + +t328 + + + + +t329 + + + + +t330 + + + + +t331 + + + + +t332 + + + + +t333 + + + + +t334 + + + + +t335 + + + + +t336 + + + + +t337 + + + + +t338 + + + + +t339 + + + + +t340 + + + + +t341 + + + + +t342 + + + + +t343 + + + + +t344 + + + + +t345 + + + + +t346 + + + + +t347 + + + + +t348 + + + + +t349 + + + + +t350 + + + + +t351 + + + + +t352 + + + + +t353 + + + + +t354 + + + + +t355 + + + + +t356 + + + + +t357 + + + + +t358 + + + + +t359 + + + + +t360 + + + + +t361 + + + + +t362 + + + + +t363 + + + + +t364 + + + + +t365 + + + + +t366 + + + + +t367 + + + + +t368 + + + + +t369 + + + + +t370 + + + + +t371 + + + + +t372 + + + + +t373 + + + + +t374 + + + + +t375 + + + + +t376 + + + + +t377 + + + + +t378 + + + + +t379 + + + + +t380 + + + + +t381 + + + + +t382 + + + + +t383 + + + + +t384 + + + + +t385 + + + + +t386 + + + + +t387 + + + + +t388 + + + + +t389 + + + + +t390 + + + + +t391 + + + + +t392 + + + + +t393 + + + + +t394 + + + + +t395 + + + + +t396 + + + + +t397 + + + + +t398 + + + + +t399 + + + + +t400 + + + + +t401 + + + + +t402 + + + + +t403 + + + + +t404 + + + + +t405 + + + + +t406 + + + + +t407 + + + + +t408 + + + + +t409 + + + + +t410 + + + + +t411 + + + + +t412 + + + + +t413 + + + + +t414 + + + + +t415 + + + + +t416 + + + + +t417 + + + + +t418 + + + + +t419 + + + + +t420 + + + + +t421 + + + + +t422 + + + + +t423 + + + + +t424 + + + + +t425 + + + + +t426 + + + + +t427 + + + + +t428 + + + + +t429 + + + + +t430 + + + + +t431 + + + + +t432 + + + + +t433 + + + + +t434 + + + + +t435 + + + + +t436 + + + + +t437 + + + + +t438 + + + + +t439 + + + + +t440 + + + + +t441 + + + + +t442 + + + + +t443 + + + + +t444 + + + + +t445 + + + + +t446 + + + + +t447 + + + + +t448 + + + + +t449 + + + + +t450 + + + + +t451 + + + + +t452 + + + + +t453 + + + + +t454 + + + + +t455 + + + + +t456 + + + + +t457 + + + + +t458 + + + + +t459 + + + + +t460 + + + + +t461 + + + + +t462 + + + + +t463 + + + + +t464 + + + + +t465 + + + + +t466 + + + + +t467 + + + + +t468 + + + + +t469 + + + + +t470 + + + + +t471 + + + + +t472 + + + + +t473 + + + + +t474 + + + + +t475 + + + + +t476 + + + + +t477 + + + + +t478 + + + + +t479 + + + + +t480 + + + + +t481 + + + + +t482 + + + + +t483 + + + + +t484 + + + + +t485 + + + + +t486 + + + + +t487 + + + + +t488 + + + + +t489 + + + + +t490 + + + + +t491 + + + + +t492 + + + + +t493 + + + + +t494 + + + + +t495 + + + + +t496 + + + + +t497 + + + + +t498 + + + + +t499 + + + + +t500 + + + + +t501 + + + + +t502 + + + + +t503 + + + + +t504 + + + + +t505 + + + + +t506 + + + + +t507 + + + + +t508 + + + + +t509 + + + + +t510 + + + + +t511 + + + + +t512 + + + + +t513 + + + + +t514 + + + + +t515 + + + + +t516 + + + + +t517 + + + + +t518 + + + + +t519 + + + + +t520 + + + + +t521 + + + + +t522 + + + + +t523 + + + + +t524 + + + + +t525 + + + + +t526 + + + + +t527 + + + + +t528 + + + + +t529 + + + + +t530 + + + + +t531 + + + + +t532 + + + + +t533 + + + + +t534 + + + + +t535 + + + + +t536 + + + + +t537 + + + + +t538 + + + + +t539 + + + + +t540 + + + + +t541 + + + + +t542 + + + + +t543 + + + + +t544 + + + + +t545 + + + + +t546 + + + + +t547 + + + + +t548 + + + + +t549 + + + + +t550 + + + + +t551 + + + + +t552 + + + + +t553 + + + + +t554 + + + + +t555 + + + + +t556 + + + + +t557 + + + + +t558 + + + + +t559 + + + + +t560 + + + + +t561 + + + + +t562 + + + + +t563 + + + + +t564 + + + + +t565 + + + + +t566 + + + + +t567 + + + + +t568 + + + + +t569 + + + + +t570 + + + + +t571 + + + + +t572 + + + + +t573 + + + + +t574 + + + + +t575 + + + + +t576 + + + + +t577 + + + + +t578 + + + + +t579 + + + + +t580 + + + + +t581 + + + + +t582 + + + + +t583 + + + + +t584 + + + + +t585 + + + + +t586 + + + + +t587 + + + + +t588 + + + + +t589 + + + + +t590 + + + + +t591 + + + + +t592 + + + + +t593 + + + + +t594 + + + + +t595 + + + + +t596 + + + + +t597 + + + + +t598 + + + + +t599 + + + + +t600 + + + + +t601 + + + + +t602 + + + + +t603 + + + + +t604 + + + + +t605 + + + + +t606 + + + + +t607 + + + + +t608 + + + + +t609 + + + + +t610 + + + + +t611 + + + + +t612 + + + + +t613 + + + + +t614 + + + + +t615 + + + + +t616 + + + + +t617 + + + + +t618 + + + + +t619 + + + + +t620 + + + + +t621 + + + + +t622 + + + + +t623 + + + + +t624 + + + + +t625 + + + + +t626 + + + + +t627 + + + + +t628 + + + + +t629 + + + + +t630 + + + + +t631 + + + + +t632 + + + + +t633 + + + + +t634 + + + + +t635 + + + + +t636 + + + + + +t637 + + + + +t638 + + + + +t639 + + + + +t640 + + + + +t641 + + + + +t642 + + + + +t643 + + + +t644 + + + +t645 + + + + +t646 + + + + +t647 + + + + +t648 + + + + +t649 + + + + +t650 + + + + +t651 + + + + +t652 + + + + +t653 + + + + +t654 + + + + +t655 + + + + +t656 + + + + +t657 + + + + +t658 + + + + +t659 + + + + +t660 + + + + +t661 + + + + +t662 + + + + +t663 + + + + +t664 + + + + +t665 + + + + +t666 + + + + +t667 + + + + +t668 + + + + +t669 + + + + +t670 + + + + +t671 + + + + +t672 + + + + +t673 + + + + +t674 + + + + +t675 + + + + +t676 + + + + +t677 + + + + +t678 + + + + +t679 + + + + +t680 + + + + +t681 + + + + +t682 + + + + +t683 + + + + +t684 + + + + +t685 + + + + +t686 + + + + +t687 + + + + +t688 + + + + +t689 + + + + +t690 + + + + +t691 + + + + +t692 + + + + +t693 + + + + +t694 + + + + +t695 + + + + +t696 + + + + +t697 + + + + +t698 + + + + +t699 + + + + +t700 + + + + +t701 + + + + +t702 + + + + +t703 + + + + +t704 + + + + +t705 + + + + +t706 + + + + +t707 + + + + +t708 + + + + +t709 + + + + +t710 + + + + +t711 + + + + +t712 + + + + +t713 + + + + + + +t714 + + + + + + +t715 + + + + + + +t716 + + + + + + +t717 + + + + + + +t718 + + + + + + +t719 + + + + + + +t720 + + + + + + +t721 + + + +t722 + + + +t723 + + + + +t724 + + + + +t725 + + + + +t726 + + + + +t727 + + + + +t728 + + + + +t729 + + + + +t730 + + + + +t731 + + + + +t732 + + + + +t733 + + + + +t734 + + + + + + + + +p0 +u1 u2 u3 u4 u5 u6 u7 u32 u35 u36 u37 u38 u39 u40 u41 u42 + u43 + + +p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 p12 p13 p14 p15 p16 + p17 p18 + + + +p19 p20 p21 + + + +p22 p23 p24 p25 p26 p27 p28 p29 p30 p31 p32 p33 p34 + + + +p35 p36 p37 p38 p39 p40 p41 p42 p43 p44 p45 p46 p47 p48 p49 p50 + p51 p52 p53 + + + +p54 p55 p56 p57 p58 p59 p60 p61 p62 p63 p64 p65 p66 p67 p68 p69 + p70 p71 + + + +p72 p73 p74 p75 p76 p77 p78 p79 p80 p81 p82 p83 p84 p85 p86 p87 + p88 p89 + + + +p90 p91 p92 p93 p94 p95 p96 +u8 u9 u13 u14 u18 u19 u23 u24 u28 u29 u30 u31 + + +p97 p98 p99 p100 p101 + + + +p102 p103 p104 p105 p106 p107 p108 p109 p110 p111 +u10 u11 u12 + + +p112 p113 p114 + + + +p115 p116 p117 + + + +p118 p119 p120 + + + +p121 p122 p123 p124 p125 p126 p127 p128 p129 p130 p131 p132 p133 p134 p135 + + + +p136 p137 +u15 u16 u17 + + +p138 p139 p140 + + + +p141 p142 p143 + + + +p144 p145 p146 + + + +p147 p148 p149 p150 p151 p152 p153 p154 p155 p156 p157 + + + +p158 p159 +u20 u21 u22 + + +p160 p161 p162 + + + +p163 p164 p165 + + + +p166 p167 p168 + + + +p169 p170 p171 p172 p173 p174 p175 p176 p177 + + + +p178 p179 +u25 u26 u27 + + +p180 p181 p182 + + + +p183 p184 p185 + + + +p186 p187 p188 + + + +p189 p190 p191 p192 + + + +p193 p194 p195 p196 p197 + + + +p198 p199 p200 + + + +p201 p202 p203 + + + +p204 +u33 u34 + + +p205 p206 + + + +p207 p208 p209 + + + +p210 p211 p212 p213 p214 p215 p216 p217 p218 p219 + + + +p220 p221 p222 + + + +p223 p224 p225 p226 + + + +p227 p228 + + + +p229 p230 p231 p232 p233 p234 p235 p236 p237 p238 p239 p240 p241 p242 p243 p244 + p245 p246 p247 p248 p249 p250 p251 p252 p253 p254 p255 p256 p257 p258 p259 p260 + p261 p262 p263 + + + +p264 p265 p266 p267 p268 p269 p270 p271 p272 p273 p274 p275 p276 p277 p278 p279 + p280 p281 p282 p283 p284 p285 p286 + + + +p287 p288 p289 + + + +p290 p291 p292 + + + +p293 p294 p295 p296 p297 p298 p299 p300 p301 p302 p303 p304 p305 p306 p307 p308 + p309 +u44 u45 u46 u47 u48 u49 u50 u51 u52 u53 u54 u55 u56 u57 u58 u59 + u60 u61 u62 u63 u64 u65 u66 u67 u68 u69 u70 u71 u72 u73 u74 u75 + u76 u77 u78 u79 u80 u81 u82 + + +p310 p311 p312 p313 p314 + + + +p315 p316 p317 + + + +p318 p319 p320 p321 p322 + + + +p323 p324 p325 + + + +p326 p327 p328 + + + +p329 p330 p331 + + + +p332 p333 p334 + + + +p335 p336 p337 + + + +p338 p339 p340 + + + +p341 p342 p343 + + + +p344 p345 p346 + + + +p347 p348 p349 + + + +p350 p351 p352 p353 p354 + + + +p355 p356 p357 + + + +p358 p359 p360 + + + +p361 p362 p363 + + + +p364 p365 p366 + + + +p367 p368 p369 + + + +p370 p371 p372 p373 p374 + + + +p375 p376 p377 + + + +p378 p379 p380 + + + +p381 p382 p383 + + + +p384 p385 p386 + + + +p387 p388 p389 + + + +p390 p391 p392 + + + +p393 p394 p395 + + + +p396 p397 p398 + + + +p399 p400 p401 + + + +p402 p403 p404 + + + +p405 p406 + + + +p407 p408 + + + +p409 p410 + + + +p411 p412 p413 p414 + + + +p415 p416 p417 + + + +p418 p419 p420 + + + +p421 p422 p423 + + + +p424 p425 p426 + + + +p427 p428 + + + +p429 p430 + + + + + + + diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/dekker-10.pnml b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/dekker-10.pnml new file mode 100644 index 0000000000..292bc7c3d4 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/dekker-10.pnml @@ -0,0 +1,1575 @@ + + + + Dekker-PT-010 + + + + +flag=0/0 + 1 + + +flag=1/0 + 0 + + +flag=0/1 + 1 + + +flag=1/1 + 0 + + +flag=0/2 + 1 + + +flag=1/2 + 0 + + +flag=0/3 + 1 + + +flag=1/3 + 0 + + +flag=0/4 + 1 + + +flag=1/4 + 0 + + +flag=0/5 + 1 + + +flag=1/5 + 0 + + +flag=0/6 + 1 + + +flag=1/6 + 0 + + +flag=0/7 + 1 + + +flag=1/7 + 0 + + +flag=0/8 + 1 + + +flag=1/8 + 0 + + +flag=0/9 + 1 + + +flag=1/9 + 0 + + +p0/0 + 1 + + +p1/0 + 0 + + +p3/0 + 0 + + +p0/1 + 1 + + +p1/1 + 0 + + +p3/1 + 0 + + +p0/2 + 1 + + +p1/2 + 0 + + +p3/2 + 0 + + +p0/3 + 1 + + +p1/3 + 0 + + +p3/3 + 0 + + +p0/4 + 1 + + +p1/4 + 0 + + +p3/4 + 0 + + +p0/5 + 1 + + +p1/5 + 0 + + +p3/5 + 0 + + +p0/6 + 1 + + +p1/6 + 0 + + +p3/6 + 0 + + +p0/7 + 1 + + +p1/7 + 0 + + +p3/7 + 0 + + +p0/8 + 1 + + +p1/8 + 0 + + +p3/8 + 0 + + +p0/9 + 1 + + +p1/9 + 0 + + +p3/9 + 0 + + + + +withdraw/0/1 + + +withdraw/0/2 + + +withdraw/0/3 + + +withdraw/0/4 + + +withdraw/0/5 + + +withdraw/0/6 + + +withdraw/0/7 + + +withdraw/0/8 + + +withdraw/0/9 + + +try/0 + + +enter/0 + + +exit/0 + + +withdraw/1/0 + + +withdraw/1/2 + + +withdraw/1/3 + + +withdraw/1/4 + + +withdraw/1/5 + + +withdraw/1/6 + + +withdraw/1/7 + + +withdraw/1/8 + + +withdraw/1/9 + + +try/1 + + +enter/1 + + +exit/1 + + +withdraw/2/0 + + +withdraw/2/1 + + +withdraw/2/3 + + +withdraw/2/4 + + +withdraw/2/5 + + +withdraw/2/6 + + +withdraw/2/7 + + +withdraw/2/8 + + +withdraw/2/9 + + +try/2 + + +enter/2 + + +exit/2 + + +withdraw/3/0 + + +withdraw/3/1 + + +withdraw/3/2 + + +withdraw/3/4 + + +withdraw/3/5 + + +withdraw/3/6 + + +withdraw/3/7 + + +withdraw/3/8 + + +withdraw/3/9 + + +try/3 + + +enter/3 + + +exit/3 + + +withdraw/4/0 + + +withdraw/4/1 + + +withdraw/4/2 + + +withdraw/4/3 + + +withdraw/4/5 + + +withdraw/4/6 + + +withdraw/4/7 + + +withdraw/4/8 + + +withdraw/4/9 + + +try/4 + + +enter/4 + + +exit/4 + + +withdraw/5/0 + + +withdraw/5/1 + + +withdraw/5/2 + + +withdraw/5/3 + + +withdraw/5/4 + + +withdraw/5/6 + + +withdraw/5/7 + + +withdraw/5/8 + + +withdraw/5/9 + + +try/5 + + +enter/5 + + +exit/5 + + +withdraw/6/0 + + +withdraw/6/1 + + +withdraw/6/2 + + +withdraw/6/3 + + +withdraw/6/4 + + +withdraw/6/5 + + +withdraw/6/7 + + +withdraw/6/8 + + +withdraw/6/9 + + +try/6 + + +enter/6 + + +exit/6 + + +withdraw/7/0 + + +withdraw/7/1 + + +withdraw/7/2 + + +withdraw/7/3 + + +withdraw/7/4 + + +withdraw/7/5 + + +withdraw/7/6 + + +withdraw/7/8 + + +withdraw/7/9 + + +try/7 + + +enter/7 + + +exit/7 + + +withdraw/8/0 + + +withdraw/8/1 + + +withdraw/8/2 + + +withdraw/8/3 + + +withdraw/8/4 + + +withdraw/8/5 + + +withdraw/8/6 + + +withdraw/8/7 + + +withdraw/8/9 + + +try/8 + + +enter/8 + + +exit/8 + + +withdraw/9/0 + + +withdraw/9/1 + + +withdraw/9/2 + + +withdraw/9/3 + + +withdraw/9/4 + + +withdraw/9/5 + + +withdraw/9/6 + + +withdraw/9/7 + + +withdraw/9/8 + + +try/9 + + +enter/9 + + +exit/9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/dekker-10.pnml.gsat.order b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/dekker-10.pnml.gsat.order new file mode 100644 index 0000000000..00a1be8faf --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/dekker-10.pnml.gsat.order @@ -0,0 +1,50 @@ +flag_1_3 +p3_3 +p0_3 +flag_0_3 +p1_3 +flag_1_4 +p34 +flag_0_4 +p0_4 +p1_4 +flag_1_1 +p3_1 +p0_1 +flag_0_1 +p1_1 +flag_1_8 +p3_8 +p0_8 +flag_0_8 +p1_8 +flag_1_6 +p1_6 +p0_6 +flag_0_6 +p3_6 +flag_1_0 +p1_0 +flag_0_0 +p0_0 +p3_0 +flag_1_5 +p1_5 +flag_0_5 +p0_5 +p3_5 +flag_1_2 +p1_2 +p0_2 +flag_0_2 +p3_2 +flag_1_9 +p1_9 +p0_9 +flag_0_9 +p3_9 +flag_1_7 +p1_7 +p0_7 +flag_0_7 +p3_7 diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/dekker-10.pnml.order b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/dekker-10.pnml.order new file mode 100644 index 0000000000..2310823379 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/dekker-10.pnml.order @@ -0,0 +1,50 @@ +p0_0 +p0_3 +p0_1 +p0_2 +p0_8 +p0_7 +p0_9 +p0_4 +p0_6 +p0_5 +p3_6 +p34 +p3_9 +p3_7 +p3_8 +p3_2 +p3_1 +p3_3 +p1_0 +p3_0 +p1_3 +p1_1 +p1_2 +p1_8 +p1_7 +p1_9 +p1_4 +p1_6 +flag_1_5 +flag_1_6 +flag_1_4 +flag_1_9 +flag_1_7 +flag_1_8 +flag_1_2 +flag_1_1 +flag_1_3 +flag_1_0 +p1_5 +flag_0_5 +flag_0_3 +flag_0_1 +flag_0_2 +flag_0_7 +flag_0_4 +flag_0_0 +flag_0_9 +flag_0_8 +flag_0_6 +p3_5 diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/dekker-15.pnml b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/dekker-15.pnml new file mode 100644 index 0000000000..ac04d0aff7 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/dekker-15.pnml @@ -0,0 +1,3330 @@ + + + + Dekker-PT-015 + + + + +flag=0/0 + 1 + + +flag=1/0 + 0 + + +flag=0/1 + 1 + + +flag=1/1 + 0 + + +flag=0/2 + 1 + + +flag=1/2 + 0 + + +flag=0/3 + 1 + + +flag=1/3 + 0 + + +flag=0/4 + 1 + + +flag=1/4 + 0 + + +flag=0/5 + 1 + + +flag=1/5 + 0 + + +flag=0/6 + 1 + + +flag=1/6 + 0 + + +flag=0/7 + 1 + + +flag=1/7 + 0 + + +flag=0/8 + 1 + + +flag=1/8 + 0 + + +flag=0/9 + 1 + + +flag=1/9 + 0 + + +flag=0/10 + 1 + + +flag=1/10 + 0 + + +flag=0/11 + 1 + + +flag=1/11 + 0 + + +flag=0/12 + 1 + + +flag=1/12 + 0 + + +flag=0/13 + 1 + + +flag=1/13 + 0 + + +flag=0/14 + 1 + + +flag=1/14 + 0 + + +p0/0 + 1 + + +p1/0 + 0 + + +p3/0 + 0 + + +p0/1 + 1 + + +p1/1 + 0 + + +p3/1 + 0 + + +p0/2 + 1 + + +p1/2 + 0 + + +p3/2 + 0 + + +p0/3 + 1 + + +p1/3 + 0 + + +p3/3 + 0 + + +p0/4 + 1 + + +p1/4 + 0 + + +p3/4 + 0 + + +p0/5 + 1 + + +p1/5 + 0 + + +p3/5 + 0 + + +p0/6 + 1 + + +p1/6 + 0 + + +p3/6 + 0 + + +p0/7 + 1 + + +p1/7 + 0 + + +p3/7 + 0 + + +p0/8 + 1 + + +p1/8 + 0 + + +p3/8 + 0 + + +p0/9 + 1 + + +p1/9 + 0 + + +p3/9 + 0 + + +p0/10 + 1 + + +p1/10 + 0 + + +p3/10 + 0 + + +p0/11 + 1 + + +p1/11 + 0 + + +p3/11 + 0 + + +p0/12 + 1 + + +p1/12 + 0 + + +p3/12 + 0 + + +p0/13 + 1 + + +p1/13 + 0 + + +p3/13 + 0 + + +p0/14 + 1 + + +p1/14 + 0 + + +p3/14 + 0 + + + + +withdraw/0/1 + + +withdraw/0/2 + + +withdraw/0/3 + + +withdraw/0/4 + + +withdraw/0/5 + + +withdraw/0/6 + + +withdraw/0/7 + + +withdraw/0/8 + + +withdraw/0/9 + + +withdraw/0/10 + + +withdraw/0/11 + + +withdraw/0/12 + + +withdraw/0/13 + + +withdraw/0/14 + + +try/0 + + +enter/0 + + +exit/0 + + +withdraw/1/0 + + +withdraw/1/2 + + +withdraw/1/3 + + +withdraw/1/4 + + +withdraw/1/5 + + +withdraw/1/6 + + +withdraw/1/7 + + +withdraw/1/8 + + +withdraw/1/9 + + +withdraw/1/10 + + +withdraw/1/11 + + +withdraw/1/12 + + +withdraw/1/13 + + +withdraw/1/14 + + +try/1 + + +enter/1 + + +exit/1 + + +withdraw/2/0 + + +withdraw/2/1 + + +withdraw/2/3 + + +withdraw/2/4 + + +withdraw/2/5 + + +withdraw/2/6 + + +withdraw/2/7 + + +withdraw/2/8 + + +withdraw/2/9 + + +withdraw/2/10 + + +withdraw/2/11 + + +withdraw/2/12 + + +withdraw/2/13 + + +withdraw/2/14 + + +try/2 + + +enter/2 + + +exit/2 + + +withdraw/3/0 + + +withdraw/3/1 + + +withdraw/3/2 + + +withdraw/3/4 + + +withdraw/3/5 + + +withdraw/3/6 + + +withdraw/3/7 + + +withdraw/3/8 + + +withdraw/3/9 + + +withdraw/3/10 + + +withdraw/3/11 + + +withdraw/3/12 + + +withdraw/3/13 + + +withdraw/3/14 + + +try/3 + + +enter/3 + + +exit/3 + + +withdraw/4/0 + + +withdraw/4/1 + + +withdraw/4/2 + + +withdraw/4/3 + + +withdraw/4/5 + + +withdraw/4/6 + + +withdraw/4/7 + + +withdraw/4/8 + + +withdraw/4/9 + + +withdraw/4/10 + + +withdraw/4/11 + + +withdraw/4/12 + + +withdraw/4/13 + + +withdraw/4/14 + + +try/4 + + +enter/4 + + +exit/4 + + +withdraw/5/0 + + +withdraw/5/1 + + +withdraw/5/2 + + +withdraw/5/3 + + +withdraw/5/4 + + +withdraw/5/6 + + +withdraw/5/7 + + +withdraw/5/8 + + +withdraw/5/9 + + +withdraw/5/10 + + +withdraw/5/11 + + +withdraw/5/12 + + +withdraw/5/13 + + +withdraw/5/14 + + +try/5 + + +enter/5 + + +exit/5 + + +withdraw/6/0 + + +withdraw/6/1 + + +withdraw/6/2 + + +withdraw/6/3 + + +withdraw/6/4 + + +withdraw/6/5 + + +withdraw/6/7 + + +withdraw/6/8 + + +withdraw/6/9 + + +withdraw/6/10 + + +withdraw/6/11 + + +withdraw/6/12 + + +withdraw/6/13 + + +withdraw/6/14 + + +try/6 + + +enter/6 + + +exit/6 + + +withdraw/7/0 + + +withdraw/7/1 + + +withdraw/7/2 + + +withdraw/7/3 + + +withdraw/7/4 + + +withdraw/7/5 + + +withdraw/7/6 + + +withdraw/7/8 + + +withdraw/7/9 + + +withdraw/7/10 + + +withdraw/7/11 + + +withdraw/7/12 + + +withdraw/7/13 + + +withdraw/7/14 + + +try/7 + + +enter/7 + + +exit/7 + + +withdraw/8/0 + + +withdraw/8/1 + + +withdraw/8/2 + + +withdraw/8/3 + + +withdraw/8/4 + + +withdraw/8/5 + + +withdraw/8/6 + + +withdraw/8/7 + + +withdraw/8/9 + + +withdraw/8/10 + + +withdraw/8/11 + + +withdraw/8/12 + + +withdraw/8/13 + + +withdraw/8/14 + + +try/8 + + +enter/8 + + +exit/8 + + +withdraw/9/0 + + +withdraw/9/1 + + +withdraw/9/2 + + +withdraw/9/3 + + +withdraw/9/4 + + +withdraw/9/5 + + +withdraw/9/6 + + +withdraw/9/7 + + +withdraw/9/8 + + +withdraw/9/10 + + +withdraw/9/11 + + +withdraw/9/12 + + +withdraw/9/13 + + +withdraw/9/14 + + +try/9 + + +enter/9 + + +exit/9 + + +withdraw/10/0 + + +withdraw/10/1 + + +withdraw/10/2 + + +withdraw/10/3 + + +withdraw/10/4 + + +withdraw/10/5 + + +withdraw/10/6 + + +withdraw/10/7 + + +withdraw/10/8 + + +withdraw/10/9 + + +withdraw/10/11 + + +withdraw/10/12 + + +withdraw/10/13 + + +withdraw/10/14 + + +try/10 + + +enter/10 + + +exit/10 + + +withdraw/11/0 + + +withdraw/11/1 + + +withdraw/11/2 + + +withdraw/11/3 + + +withdraw/11/4 + + +withdraw/11/5 + + +withdraw/11/6 + + +withdraw/11/7 + + +withdraw/11/8 + + +withdraw/11/9 + + +withdraw/11/10 + + +withdraw/11/12 + + +withdraw/11/13 + + +withdraw/11/14 + + +try/11 + + +enter/11 + + +exit/11 + + +withdraw/12/0 + + +withdraw/12/1 + + +withdraw/12/2 + + +withdraw/12/3 + + +withdraw/12/4 + + +withdraw/12/5 + + +withdraw/12/6 + + +withdraw/12/7 + + +withdraw/12/8 + + +withdraw/12/9 + + +withdraw/12/10 + + +withdraw/12/11 + + +withdraw/12/13 + + +withdraw/12/14 + + +try/12 + + +enter/12 + + +exit/12 + + +withdraw/13/0 + + +withdraw/13/1 + + +withdraw/13/2 + + +withdraw/13/3 + + +withdraw/13/4 + + +withdraw/13/5 + + +withdraw/13/6 + + +withdraw/13/7 + + +withdraw/13/8 + + +withdraw/13/9 + + +withdraw/13/10 + + +withdraw/13/11 + + +withdraw/13/12 + + +withdraw/13/14 + + +try/13 + + +enter/13 + + +exit/13 + + +withdraw/14/0 + + +withdraw/14/1 + + +withdraw/14/2 + + +withdraw/14/3 + + +withdraw/14/4 + + +withdraw/14/5 + + +withdraw/14/6 + + +withdraw/14/7 + + +withdraw/14/8 + + +withdraw/14/9 + + +withdraw/14/10 + + +withdraw/14/11 + + +withdraw/14/12 + + +withdraw/14/13 + + +try/14 + + +enter/14 + + +exit/14 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/dekker-15.pnml.gsat.order b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/dekker-15.pnml.gsat.order new file mode 100644 index 0000000000..89067515bb --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-analysis/src/test/resources/dekker-15.pnml.gsat.order @@ -0,0 +1,75 @@ +flag_1_9 +p1_9 +p0_9 +flag_0_9 +p3_9 +flag_1_2 +p3_2 +p0_2 +flag_0_2 +p1_2 +flag_1_13 +p1_13 +p0_13 +flag_0_13 +p3_13 +flag_1_7 +p3_7 +p0_7 +flag_0_7 +p1_7 +flag_1_8 +p3_8 +p0_8 +flag_0_8 +p1_8 +flag_1_3 +p3_3 +flag_0_3 +p0_3 +p1_3 +flag_1_12 +p3_12 +flag_0_12 +p0_12 +p1_12 +flag_1_4 +p1_4 +flag_0_4 +p0_4 +p3_4 +flag_1_10 +p3_10 +flag_0_10 +p0_10 +p1_10 +flag_1_6 +p3_6 +flag_0_6 +p0_6 +p1_6 +flag_1_0 +p1_0 +p0_0 +flag_0_0 +p3_0 +flag_1_14 +p1_14 +flag_0_14 +p0_14 +p3_14 +flag_1_1 +p1_1 +flag_0_1 +p0_1 +p3_1 +flag_1_5 +p1_5 +p0_5 +flag_0_5 +p3_5 +flag_1_11 +p1_11 +p0_11 +flag_0_11 +p3_11 diff --git a/subprojects/frontends/petrinet-frontend/petrinet-model/build.gradle.kts b/subprojects/frontends/petrinet-frontend/petrinet-model/build.gradle.kts new file mode 100644 index 0000000000..f1e7bb33f2 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-model/build.gradle.kts @@ -0,0 +1,37 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +plugins { + id("java-common") +} + +dependencies { + implementation(Deps.pnmlCore) + implementation(Deps.pnmlSymmetric) + implementation(Deps.pnmlPtnet) + implementation(Deps.pnmlUtils) + implementation(Deps.pnmlHlpn) + implementation(Deps.pnmlNupn) + implementation(Deps.pnmlPthlpng) + + implementation(Deps.emfEcore) + implementation(Deps.emfCodegenEcore) + implementation(Deps.emfCodegen) + implementation(Deps.emfEcoreXmi) + implementation(Deps.emfCommon) + + implementation(project(":theta-core")) + implementation(project(":theta-common")) +} \ No newline at end of file diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/elements/PnmlArc.java b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/Identified.java similarity index 55% rename from subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/elements/PnmlArc.java rename to subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/Identified.java index 63e6e0ed89..d173a6fe8a 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/elements/PnmlArc.java +++ b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/Identified.java @@ -13,36 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.xsts.pnml.elements; +package hu.bme.mit.theta.frontend.petrinet.model; -public class PnmlArc { - - private final int weight; +public class Identified { private final String id; - private final PnmlNode sourceNode; - private final PnmlNode targetNode; - public PnmlArc(final String id, int weight, final PnmlNode sourceNode, - final PnmlNode targetNode) { + public Identified(final String id) { this.id = id; - this.weight = weight; - this.sourceNode = sourceNode; - this.targetNode = targetNode; } public String getId() { return id; } - - public int getWeight() { - return weight; - } - - public PnmlNode getSourceNode() { - return sourceNode; - } - - public PnmlNode getTargetNode() { - return targetNode; - } } diff --git a/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/PTArc.java b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/PTArc.java new file mode 100644 index 0000000000..1ccc0f58dc --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/PTArc.java @@ -0,0 +1,77 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.frontend.petrinet.model; + +public final class PTArc extends Identified { + private boolean isInhibitor; + private long weight; + + private Place source; + private Transition target; + + public PTArc(final String id) { + super(id); + } + + public boolean isInhibitor() { + return isInhibitor; + } + + public void setInhibitor(final boolean inhibitor) { + isInhibitor = inhibitor; + } + + public long getWeight() { + return weight; + } + + public void setWeight(final long weight) { + this.weight = weight; + } + + public Place getSource() { + return source; + } + + public void setSource(final Place source) { + if (this.source != null) { + this.source.getOutgoingArcs().remove(this); + } + this.source = source; + if (this.source != null) { + this.source.getOutgoingArcs().add(this); + } + } + + public Transition getTarget() { + return target; + } + + public void setTarget(final Transition target) { + if (this.target != null) { + this.target.getIncomingArcs().remove(this); + } + this.target = target; + if (this.target != null) { + this.target.getIncomingArcs().add(this); + } + } + + @Override + public String toString() { + return getId() + " (" + source.toString() + "->" + target.toString() + ")"; + } +} diff --git a/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/PetriNet.java b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/PetriNet.java new file mode 100644 index 0000000000..79a6c68546 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/PetriNet.java @@ -0,0 +1,61 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.frontend.petrinet.model; + +import java.util.ArrayList; +import java.util.List; + +public final class PetriNet extends Identified { + private String name; + + private List places = new ArrayList<>(); + private List transitions = new ArrayList<>(); + private List ptArcs = new ArrayList<>(); + private List tpArcs = new ArrayList<>(); + + public PetriNet(final String id) { + super(id); + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + public List getPlaces() { + return places; + } + + public List getTransitions() { + return transitions; + } + + public List getPtArcs() { + return ptArcs; + } + + public List getTpArcs() { + return tpArcs; + } + + @Override + public String toString() { + return getId() + "(" + places.size() + " places, " + transitions.size() + " transitions, " + (ptArcs.size() + tpArcs.size()) + " arcs)"; + } +} diff --git a/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/Place.java b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/Place.java new file mode 100644 index 0000000000..82ea9dcf73 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/Place.java @@ -0,0 +1,51 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.frontend.petrinet.model; + +import java.util.ArrayList; +import java.util.List; + +public final class Place extends Identified { + private long initialMarking; + + private List outgoingArcs = new ArrayList<>(); + private List incomingArcs = new ArrayList<>(); + + public Place(final String id) { + super(id); + } + + public long getInitialMarking() { + return initialMarking; + } + + public void setInitialMarking(final long initialMarking) { + this.initialMarking = initialMarking; + } + + public List getOutgoingArcs() { + return outgoingArcs; + } + + public List getIncomingArcs() { + return incomingArcs; + } + + @Override + public String toString() { + return getId(); + } +} diff --git a/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/TPArc.java b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/TPArc.java new file mode 100644 index 0000000000..fd6f7a75df --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/TPArc.java @@ -0,0 +1,68 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.frontend.petrinet.model; + +public final class TPArc extends Identified { + private long weight; + + private Transition source; + private Place target; + + public TPArc(final String id) { + super(id); + } + + public long getWeight() { + return weight; + } + + public void setWeight(final long weight) { + this.weight = weight; + } + + public Transition getSource() { + return source; + } + + public void setSource(final Transition source) { + if (this.source != null) { + this.source.getOutgoingArcs().remove(this); + } + this.source = source; + if (this.source != null) { + this.source.getOutgoingArcs().add(this); + } + } + + public Place getTarget() { + return target; + } + + public void setTarget(final Place target) { + if (this.target != null) { + this.target.getIncomingArcs().remove(this); + } + this.target = target; + if (this.target != null) { + this.target.getIncomingArcs().add(this); + } + } + + @Override + public String toString() { + return getId() + " (" + source.toString() + "->" + target.toString() + ")"; + } +} diff --git a/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/Transition.java b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/Transition.java new file mode 100644 index 0000000000..e4a05ae8d0 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/Transition.java @@ -0,0 +1,41 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.frontend.petrinet.model; + +import java.util.ArrayList; +import java.util.List; + +public final class Transition extends Identified { + private List outgoingArcs = new ArrayList<>(); + private List incomingArcs = new ArrayList<>(); + + public Transition(final String id) { + super(id); + } + + public List getOutgoingArcs() { + return outgoingArcs; + } + + public List getIncomingArcs() { + return incomingArcs; + } + + @Override + public String toString() { + return getId(); + } +} diff --git a/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/utils/GraphVizSerializer.java b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/utils/GraphVizSerializer.java new file mode 100644 index 0000000000..831b812cb6 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/model/utils/GraphVizSerializer.java @@ -0,0 +1,53 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.frontend.petrinet.model.utils; + +import hu.bme.mit.theta.frontend.petrinet.model.*; + +public final class GraphVizSerializer { + public static String toDot(PetriNet pn) { + StringBuilder sb = new StringBuilder(); + sb.append("digraph PN {\n"); + + for (Place p : pn.getPlaces()) { + sb.append("\"" + + p.getId() + + "\" [label=\"" + + p.getId() + + (p.getInitialMarking() != 0 ? "\\n(" + p.getInitialMarking() + ")" : "") + + "\"];\n"); + } + for (Transition t : pn.getTransitions()) { + sb.append("\"" + t.getId() + "\" [shape=box,label=\"" + t.getId() + "\"];\n"); + } + for (PTArc pt : pn.getPtArcs()) { + sb.append("\"" + pt.getSource().getId() + "\" -> \"" + pt.getTarget().getId() + "\" [label=\"" + (pt.getWeight() != 1 ? pt.getWeight() : "") + "\""); + + if (pt.isInhibitor()) { + sb.append(",arrowhead=dot"); + } + + sb.append("];\n"); + } + for (TPArc tp : pn.getTpArcs()) { + sb.append("\"" + tp.getSource().getId() + "\" -> \"" + tp.getTarget().getId() + "\" [label=\"" + (tp.getWeight() != 1 ? tp.getWeight() : "") + "\"];\n"); + } + + sb.append("}\n"); + + return sb.toString(); + } +} diff --git a/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/pnml/Lip6PnmlToPetrinet.java b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/pnml/Lip6PnmlToPetrinet.java new file mode 100644 index 0000000000..ee06a2e436 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/pnml/Lip6PnmlToPetrinet.java @@ -0,0 +1,136 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.frontend.petrinet.pnml; + +import fr.lip6.move.pnml.ptnet.*; +import fr.lip6.move.pnml.ptnet.hlapi.PetriNetDocHLAPI; +import hu.bme.mit.theta.frontend.petrinet.model.*; +import hu.bme.mit.theta.frontend.petrinet.model.PetriNet; +import hu.bme.mit.theta.frontend.petrinet.model.Place; +import hu.bme.mit.theta.frontend.petrinet.model.Transition; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +final class Lip6PnmlToPetrinet { + private final PetriNetDocHLAPI root; + + public Lip6PnmlToPetrinet(final PetriNetDocHLAPI root) { + this.root = root; + } + + public List parse() throws PnmlParseException { + fr.lip6.move.pnml.ptnet.PetriNetDoc pnDocDOM = root.getContainedItem(); + List ret = new ArrayList<>(); + for (fr.lip6.move.pnml.ptnet.PetriNet pnDOM : pnDocDOM.getNets()) { + PetriNet pn = new PetriNet(pnDOM.getId()); + if (pnDOM.getName() != null) { + pn.setName(pnDOM.getName().getText()); + } + // TODO parse NUPN + + List places = new ArrayList<>(); + List transitions = new ArrayList<>(); + List arcs = new ArrayList<>(); + for (Page pageDOM : pnDOM.getPages()) { + for (PnObject object : pageDOM.getObjects()) { + if (object instanceof fr.lip6.move.pnml.ptnet.Place) { + places.add((fr.lip6.move.pnml.ptnet.Place) object); + } else if (object instanceof RefPlace) { + //refPlaces.add((RefPlace) object); + } else if (object instanceof fr.lip6.move.pnml.ptnet.Transition) { + transitions.add((fr.lip6.move.pnml.ptnet.Transition) object); + } else if (object instanceof RefTransition) { + //refTransitions.add((RefTransition) object); + } else if (object instanceof Arc) { + arcs.add((Arc) object); + } else { + throw new PnmlParseException("Unknown object: " + object); + } + } + } + + Map placeMap = new HashMap<>(); + Map transitionMap = new HashMap<>(); + + for (fr.lip6.move.pnml.ptnet.Place placeDOM : places) { + Place p = new Place(placeDOM.getId()); + if (placeDOM.getInitialMarking() != null) { + p.setInitialMarking(placeDOM.getInitialMarking().getText()); + } else { + p.setInitialMarking(0); + } + + placeMap.put(p.getId(), p); + pn.getPlaces().add(p); + } + + for (fr.lip6.move.pnml.ptnet.Transition transitionDOM : transitions) { + Transition t = new Transition(transitionDOM.getId()); + + transitionMap.put(t.getId(), t); + pn.getTransitions().add(t); + } + + for (Arc arcDOM : arcs) { + if (arcDOM.getSource() instanceof fr.lip6.move.pnml.ptnet.PlaceNode) { + assert arcDOM.getTarget() instanceof fr.lip6.move.pnml.ptnet.TransitionNode; + + PTArc arc = new PTArc(arcDOM.getId()); + // TODO inhibitor?? + String sourceId = arcDOM.getSource() instanceof RefPlace ? + ((RefPlace) arcDOM.getSource()).getRef().getId() : arcDOM.getSource().getId(); + String targetId = arcDOM.getTarget() instanceof RefTransition ? + ((RefTransition) arcDOM.getTarget()).getRef().getId() : arcDOM.getTarget().getId(); + Place sourcePlace = placeMap.get(sourceId); + Transition targetTransition = transitionMap.get(targetId); + arc.setSource(sourcePlace); + arc.setTarget(targetTransition); + if (arcDOM.getInscription() != null) { + arc.setWeight(arcDOM.getInscription().getText()); + } else { + arc.setWeight(1); + } + pn.getPtArcs().add(arc); + + } else if (arcDOM.getSource() instanceof fr.lip6.move.pnml.ptnet.TransitionNode) { + assert arcDOM.getTarget() instanceof fr.lip6.move.pnml.ptnet.PlaceNode; + + TPArc arc = new TPArc(arcDOM.getId()); + // TODO inhibitor?? + String sourceId = arcDOM.getSource() instanceof RefTransition ? + ((RefTransition) arcDOM.getSource()).getRef().getId() : arcDOM.getSource().getId(); + String targetId = arcDOM.getTarget() instanceof RefPlace ? + ((RefPlace) arcDOM.getTarget()).getRef().getId() : arcDOM.getTarget().getId(); + Transition sourceTransition = transitionMap.get(sourceId); + Place targetPlace = placeMap.get(targetId); + arc.setSource(sourceTransition); + arc.setTarget(targetPlace); + if (arcDOM.getInscription() != null) { + arc.setWeight(arcDOM.getInscription().getText()); + } else { + arc.setWeight(1); + } + pn.getTpArcs().add(arc); + } + } + ret.add(pn); + } + return ret; + } +} diff --git a/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/pnml/PetriNetParser.java b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/pnml/PetriNetParser.java new file mode 100644 index 0000000000..d3c372ba91 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/pnml/PetriNetParser.java @@ -0,0 +1,57 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.frontend.petrinet.pnml; + +import fr.lip6.move.pnml.framework.hlapi.HLAPIRootClass; +import fr.lip6.move.pnml.framework.utils.PNMLUtils; +import fr.lip6.move.pnml.ptnet.hlapi.PetriNetDocHLAPI; +import hu.bme.mit.theta.frontend.petrinet.model.PetriNet; + +import java.io.File; +import java.util.List; +import java.util.Objects; + +public final class PetriNetParser { + public static enum PetriNetType { + PTNet, + Other + } + + private final HLAPIRootClass root; + + public static PetriNetParser loadPnml(File file) throws Exception { + final HLAPIRootClass root = PNMLUtils.importPnmlDocument(file, false); + return new PetriNetParser(root); + } + + private PetriNetParser(final HLAPIRootClass root) { + this.root = Objects.requireNonNull(root); + } + + public PetriNetType getPetriNetType() { + if (root instanceof PetriNetDocHLAPI) { + return PetriNetType.PTNet; + } + return PetriNetType.Other; + } + + public List parsePTNet() throws PnmlParseException { + if (root instanceof PetriNetDocHLAPI) { + return new Lip6PnmlToPetrinet((PetriNetDocHLAPI) root).parse(); + } + throw new PnmlParseException("The file was not a P/T Net."); + } +} diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/elements/PnmlTransition.java b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/pnml/PnmlParseException.java similarity index 78% rename from subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/elements/PnmlTransition.java rename to subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/pnml/PnmlParseException.java index 0a608988a2..a2593ff1bb 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/elements/PnmlTransition.java +++ b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/pnml/PnmlParseException.java @@ -13,11 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.xsts.pnml.elements; +package hu.bme.mit.theta.frontend.petrinet.pnml; -public class PnmlTransition extends PnmlNode { - - public PnmlTransition(final String name, final String id) { - super(name, id); +public final class PnmlParseException extends Exception { + public PnmlParseException(final String s) { + super(s); } } diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/PnmlParser.java b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/pnml/XMLPnmlToPetrinet.java similarity index 67% rename from subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/PnmlParser.java rename to subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/pnml/XMLPnmlToPetrinet.java index c18ccecf9d..adcf8e193b 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/PnmlParser.java +++ b/subprojects/frontends/petrinet-frontend/petrinet-model/src/main/java/hu/bme/mit/theta/frontend/petrinet/pnml/XMLPnmlToPetrinet.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.xsts.pnml; +package hu.bme.mit.theta.frontend.petrinet.pnml; import hu.bme.mit.theta.common.container.Containers; -import hu.bme.mit.theta.xsts.pnml.elements.*; +import hu.bme.mit.theta.frontend.petrinet.model.*; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -34,12 +34,12 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -public class PnmlParser { +public class XMLPnmlToPetrinet { - private PnmlParser() { + private XMLPnmlToPetrinet() { } - public static PnmlNet parse(final String fileName, final String initialMarkingString) + public static PetriNet parse(final String fileName, final String initialMarkingString) throws ParserConfigurationException, IOException, SAXException, XPathExpressionException { final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); @@ -64,9 +64,9 @@ public static PnmlNet parse(final String fileName, final String initialMarkingSt checkArgument(netList.getLength() == 1, "Pnml model contains multiple nets"); final Element netElement = (Element) netList.item(0); - final Map idToNodeMap = Containers.createMap(); - final List places = new ArrayList<>(); - final List transitions = new ArrayList<>(); + final Map idMap = Containers.createMap(); + final List places = new ArrayList<>(); + final List transitions = new ArrayList<>(); // Find all places final XPathExpression childPlacesExpr = xPath.compile("./place"); @@ -76,16 +76,15 @@ public static PnmlNet parse(final String fileName, final String initialMarkingSt final Element placeElement = (Element) placeList.item(i); final String id = placeElement.getAttribute("id"); - final String name; - final XPathExpression nameTextExpr = xPath.compile("./name/text/text()"); - final XPathExpression nameValueExpr = xPath.compile("./name/value/text()"); - final String nameText = (String) nameTextExpr.evaluate(placeElement, - XPathConstants.STRING); - if (nameText.equals("")) { - name = (String) nameValueExpr.evaluate(placeElement, XPathConstants.STRING); - } else { - name = nameText; - } +// final String name; +// final XPathExpression nameTextExpr = xPath.compile("./name/text/text()"); +// final XPathExpression nameValueExpr = xPath.compile("./name/value/text()"); +// final String nameText = (String) nameTextExpr.evaluate(placeElement,XPathConstants.STRING); +// if(nameText.equals("")){ +// name = (String) nameValueExpr.evaluate(placeElement,XPathConstants.STRING); +// } else { +// name = nameText; +// } final int initialMarking; if (overrideInitialMarking) { @@ -97,8 +96,9 @@ public static PnmlNet parse(final String fileName, final String initialMarkingSt XPathConstants.NUMBER)).intValue(); } - final PnmlPlace place = new PnmlPlace(name, id, initialMarking); - idToNodeMap.put(id, place); + final Place place = new Place(id); + place.setInitialMarking(initialMarking); + idMap.put(id, place); places.add(place); } @@ -110,19 +110,18 @@ public static PnmlNet parse(final String fileName, final String initialMarkingSt final Element transitionElement = (Element) transitionList.item(i); final String id = transitionElement.getAttribute("id"); - final String name; - final XPathExpression nameTextExpr = xPath.compile("./name/text/text()"); - final XPathExpression nameValueExpr = xPath.compile("./name/value/text()"); - final String nameText = (String) nameTextExpr.evaluate(transitionElement, - XPathConstants.STRING); - if (nameText.equals("")) { - name = (String) nameValueExpr.evaluate(transitionElement, XPathConstants.STRING); - } else { - name = nameText; - } - - final PnmlTransition transition = new PnmlTransition(name, id); - idToNodeMap.put(id, transition); +// final String name; +// final XPathExpression nameTextExpr = xPath.compile("./name/text/text()"); +// final XPathExpression nameValueExpr = xPath.compile("./name/value/text()"); +// final String nameText = (String) nameTextExpr.evaluate(transitionElement,XPathConstants.STRING); +// if(nameText.equals("")){ +// name = (String) nameValueExpr.evaluate(transitionElement,XPathConstants.STRING); +// } else { +// name = nameText; +// } + + final Transition transition = new Transition(id); + idMap.put(id, transition); transitions.add(transition); } @@ -135,11 +134,11 @@ public static PnmlNet parse(final String fileName, final String initialMarkingSt final String id = arcElement.getAttribute("id"); final String sourceId = arcElement.getAttribute("source"); - final PnmlNode source = idToNodeMap.get(sourceId); + final Identified source = idMap.get(sourceId); checkNotNull(source, "Source node not found of arc " + id); final String targetId = arcElement.getAttribute("target"); - final PnmlNode target = idToNodeMap.get(targetId); + final Identified target = idMap.get(targetId); checkNotNull(source, "Target node not found of arc " + id); final XPathExpression toolspecificWeightExpr = xPath.compile( @@ -148,13 +147,26 @@ public static PnmlNet parse(final String fileName, final String initialMarkingSt XPathConstants.NUMBER)).intValue(); final int weight = toolspecificWeight == 0 ? 1 : toolspecificWeight; - final PnmlArc arc = new PnmlArc(id, weight, source, target); - source.addOutArc(arc); - target.addInArc(arc); + if (source instanceof Place) { + checkArgument(target instanceof Transition); + final PTArc arc = new PTArc(id); + arc.setWeight(weight); + arc.setSource((Place) source); + arc.setTarget((Transition) target); + } else { + checkArgument(source instanceof Transition && target instanceof Place); + final TPArc arc = new TPArc(id); + arc.setWeight(weight); + arc.setSource((Transition) source); + arc.setTarget((Place) target); + } } - return new PnmlNet(places, transitions); + final PetriNet ptNet = new PetriNet("0"); + ptNet.getPlaces().addAll(places); + ptNet.getTransitions().addAll(transitions); + return ptNet; } } diff --git a/subprojects/frontends/petrinet-frontend/petrinet-xsts/build.gradle.kts b/subprojects/frontends/petrinet-frontend/petrinet-xsts/build.gradle.kts new file mode 100644 index 0000000000..1ce9dc4050 --- /dev/null +++ b/subprojects/frontends/petrinet-frontend/petrinet-xsts/build.gradle.kts @@ -0,0 +1,30 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +plugins { + id("java-common") +} + +dependencies { + implementation(project(":theta-core")) + implementation(project(":theta-common")) + implementation(project(":theta-xsts")) + implementation(project(":theta-petrinet-model")) + + testImplementation(project(":theta-xsts-analysis")) + testImplementation(project(":theta-solver-z3-legacy")) + testImplementation(project(":theta-solver")) + testImplementation(project(":theta-analysis")) +} \ No newline at end of file diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/PnmlToXSTS.java b/subprojects/frontends/petrinet-frontend/petrinet-xsts/src/main/java/hu/bme/mit/theta/frontend/petrinet/xsts/PetriNetToXSTS.java similarity index 55% rename from subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/PnmlToXSTS.java rename to subprojects/frontends/petrinet-frontend/petrinet-xsts/src/main/java/hu/bme/mit/theta/frontend/petrinet/xsts/PetriNetToXSTS.java index 51a343ad5c..216111100a 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/PnmlToXSTS.java +++ b/subprojects/frontends/petrinet-frontend/petrinet-xsts/src/main/java/hu/bme/mit/theta/frontend/petrinet/xsts/PetriNetToXSTS.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.xsts.pnml; +package hu.bme.mit.theta.frontend.petrinet.xsts; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -25,11 +25,13 @@ import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.abstracttype.GeqExpr; import hu.bme.mit.theta.core.type.booltype.BoolType; +import hu.bme.mit.theta.core.type.inttype.IntExprs; import hu.bme.mit.theta.core.type.inttype.IntType; +import hu.bme.mit.theta.frontend.petrinet.model.*; import hu.bme.mit.theta.xsts.XSTS; -import hu.bme.mit.theta.xsts.pnml.elements.*; import java.io.InputStream; +import java.math.BigInteger; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -39,63 +41,61 @@ import static hu.bme.mit.theta.core.type.inttype.IntExprs.*; import static hu.bme.mit.theta.core.utils.TypeUtils.cast; -public class PnmlToXSTS { +public class PetriNetToXSTS { - private PnmlToXSTS() { + private PetriNetToXSTS() { } - public static XSTS createXSTS(final PnmlNet net, final InputStream propStream) { + public static XSTS createXSTS(final PetriNet net, final InputStream propStream) { final Map> placeIdToVar = Containers.createMap(); final List> initExprs = new ArrayList<>(); // Create a variable for each place and initialize them - for (PnmlPlace place : net.getPlaces()) { - final VarDecl placeVar = Decls.Var(place.getName(), IntType.getInstance()); + for (Place place : net.getPlaces()) { + final VarDecl placeVar = Decls.Var(place.getId(), IntType.getInstance()); placeIdToVar.put(place.getId(), placeVar); - initExprs.add(Eq(placeVar.getRef(), Int(place.getInitialMarking()))); + initExprs.add(Eq(placeVar.getRef(), IntExprs.Int(BigInteger.valueOf(place.getInitialMarking())))); } final Expr initExpr = And(initExprs); final List tranStmts = new ArrayList<>(); // Create a transition for each variable - for (PnmlTransition transition : net.getTransitions()) { + for (Transition transition : net.getTransitions()) { final List stmts = new ArrayList<>(); + final Map, Long> takesPutsMap = new HashMap<>(); // Check if enough tokens are present and remove input tokens - for (PnmlArc inArc : transition.getInArcs()) { - final PnmlNode sourceNode = inArc.getSourceNode(); - checkArgument(sourceNode instanceof PnmlPlace, - "Transition %s has an illegal source", transition.getId(), sourceNode.getId()); - final PnmlPlace sourcePlace = (PnmlPlace) sourceNode; + for (PTArc inArc : transition.getIncomingArcs()) { + final Place sourcePlace = inArc.getSource(); final VarDecl placeVar = placeIdToVar.get(sourcePlace.getId()); - final int weight = inArc.getWeight(); + final long weight = inArc.getWeight(); final Stmt enoughTokens = AssumeStmt.of( - GeqExpr.create2(placeVar.getRef(), Int(weight))); + GeqExpr.create2(placeVar.getRef(), Int(BigInteger.valueOf(weight)))); stmts.add(enoughTokens); - final Stmt removeTokens = AssignStmt.of(placeVar, - Sub(placeVar.getRef(), Int(weight))); - stmts.add(removeTokens); + takesPutsMap.merge(placeVar, -weight, Long::sum); +// final Stmt removeTokens = AssignStmt.of(placeVar,Sub(placeVar.getRef(),Int(BigInteger.valueOf(weight)))); +// stmts.add(removeTokens); } // Place output tokens - for (PnmlArc outArc : transition.getOutArcs()) { - final PnmlNode targetNode = outArc.getTargetNode(); - checkArgument(targetNode instanceof PnmlPlace, - "Transition %s has an illegal target %s", transition.getId(), - targetNode.getId()); - final PnmlPlace targetPlace = (PnmlPlace) targetNode; + for (TPArc outArc : transition.getOutgoingArcs()) { + final Place targetPlace = outArc.getTarget(); final VarDecl placeVar = placeIdToVar.get(targetPlace.getId()); - final int weight = outArc.getWeight(); + final long weight = outArc.getWeight(); - final Stmt placeTokens = AssignStmt.of(placeVar, - Add(placeVar.getRef(), Int(weight))); - stmts.add(placeTokens); + takesPutsMap.merge(placeVar, weight, Long::sum); +// final Stmt placeTokens = AssignStmt.of(placeVar,Add(placeVar.getRef(),Int(BigInteger.valueOf(weight)))); +// stmts.add(placeTokens); } + takesPutsMap.forEach( + (placeVar, weight) -> stmts.add(AssignStmt.of(placeVar, Add(placeVar.getRef(), Int(BigInteger.valueOf(weight))))) + ); + tranStmts.add(SequenceStmt.of(stmts)); } @@ -104,32 +104,35 @@ public static XSTS createXSTS(final PnmlNet net, final InputStream propStream) { final NonDetStmt env = NonDetStmt.of(ImmutableList.of()); final Set> ctrlVars = ImmutableSet.of(); - final Scanner propScanner = new Scanner(propStream).useDelimiter("\\A"); - final String propertyFile = propScanner.hasNext() ? propScanner.next() : ""; - final String property = stripPropFromPropFile(propertyFile).trim(); + final Expr propExpr; + if (propStream != null) { + final Scanner propScanner = new Scanner(propStream).useDelimiter("\\A"); + final String propertyFile = propScanner.hasNext() ? propScanner.next() : ""; + final String property = stripPropFromPropFile(propertyFile).trim(); + + final Pattern markingPattern = Pattern.compile("([0-9]+\\s)*[0-9]+"); + final Matcher markingMatcher = markingPattern.matcher(property); - final Pattern markingPattern = Pattern.compile("([0-9]+\\s)*[0-9]+"); - final Matcher markingMatcher = markingPattern.matcher(property); - final Expr propExpr; - if (markingMatcher.matches()) { - final String[] valueStrings = property.split("\\s"); - final Integer[] values = Arrays.stream(valueStrings).map(Integer::parseInt) - .toArray(Integer[]::new); - - checkArgument(values.length == net.getPlaces().size()); - final List> exprs = new ArrayList<>(); - for (int i = 0; i < values.length; i++) { - exprs.add( - Eq(placeIdToVar.get(net.getPlaces().get(i).getId()).getRef(), Int(values[i]))); + if (markingMatcher.matches()) { + final String[] valueStrings = property.split("\\s"); + final Integer[] values = Arrays.stream(valueStrings).map(Integer::parseInt).toArray(Integer[]::new); + + checkArgument(values.length == net.getPlaces().size()); + final List> exprs = new ArrayList<>(); + for (int i = 0; i < values.length; i++) { + exprs.add(Eq(placeIdToVar.get(net.getPlaces().get(i).getId()).getRef(), Int(values[i]))); + } + propExpr = Not(And(exprs)); + } else { + final CoreDslManager dslManager = new CoreDslManager(); + for (VarDecl decl : placeIdToVar.values()) { + dslManager.declare(decl); + } + propExpr = cast(dslManager.parseExpr(property), Bool()); } - propExpr = Not(And(exprs)); } else { - final CoreDslManager dslManager = new CoreDslManager(); - for (VarDecl decl : placeIdToVar.values()) { - dslManager.declare(decl); - } - propExpr = cast(dslManager.parseExpr(property), Bool()); + propExpr = True(); } return new XSTS(ctrlVars, init, tran, env, initExpr, propExpr); diff --git a/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/PnmlTest.java b/subprojects/frontends/petrinet-frontend/petrinet-xsts/src/test/java/hu.bme.mit.theta.frontend.petrinet.xsts/PnmlTest.java similarity index 94% rename from subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/PnmlTest.java rename to subprojects/frontends/petrinet-frontend/petrinet-xsts/src/test/java/hu.bme.mit.theta.frontend.petrinet.xsts/PnmlTest.java index a75d56cec7..6b0cb0d5f4 100644 --- a/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/PnmlTest.java +++ b/subprojects/frontends/petrinet-frontend/petrinet-xsts/src/test/java/hu.bme.mit.theta.frontend.petrinet.xsts/PnmlTest.java @@ -13,19 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package hu.bme.mit.theta.xsts.analysis; +package hu.bme.mit.theta.frontend.petrinet.xsts; import hu.bme.mit.theta.analysis.algorithm.SafetyResult; import hu.bme.mit.theta.common.logging.ConsoleLogger; import hu.bme.mit.theta.common.logging.Logger; import hu.bme.mit.theta.common.logging.Logger.Level; +import hu.bme.mit.theta.frontend.petrinet.model.PetriNet; +import hu.bme.mit.theta.frontend.petrinet.pnml.XMLPnmlToPetrinet; import hu.bme.mit.theta.solver.z3legacy.Z3LegacySolverFactory; import hu.bme.mit.theta.xsts.XSTS; import hu.bme.mit.theta.xsts.analysis.config.XstsConfig; import hu.bme.mit.theta.xsts.analysis.config.XstsConfigBuilder; -import hu.bme.mit.theta.xsts.pnml.PnmlParser; -import hu.bme.mit.theta.xsts.pnml.PnmlToXSTS; -import hu.bme.mit.theta.xsts.pnml.elements.PnmlNet; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -76,12 +75,12 @@ public void test() final Logger logger = new ConsoleLogger(Level.SUBSTEP); - final PnmlNet pnmlNet = PnmlParser.parse(filePath, initialMarking); + final PetriNet petriNet = XMLPnmlToPetrinet.parse(filePath, initialMarking); XSTS xsts; try (InputStream propStream = new ByteArrayInputStream( ("prop { " + targetMarking + " }").getBytes())) { - xsts = PnmlToXSTS.createXSTS(pnmlNet, propStream); + xsts = PetriNetToXSTS.createXSTS(petriNet, propStream); } final XstsConfig configuration = new XstsConfigBuilder(domain, diff --git a/subprojects/xsts/xsts-analysis/src/test/resources/model/pnml/DPhil-10.pnml b/subprojects/frontends/petrinet-frontend/petrinet-xsts/src/test/resources/pnml/DPhil-10.pnml similarity index 100% rename from subprojects/xsts/xsts-analysis/src/test/resources/model/pnml/DPhil-10.pnml rename to subprojects/frontends/petrinet-frontend/petrinet-xsts/src/test/resources/pnml/DPhil-10.pnml diff --git a/subprojects/xsts/xsts-analysis/src/test/resources/model/pnml/DPhil-100.pnml b/subprojects/frontends/petrinet-frontend/petrinet-xsts/src/test/resources/pnml/DPhil-100.pnml similarity index 100% rename from subprojects/xsts/xsts-analysis/src/test/resources/model/pnml/DPhil-100.pnml rename to subprojects/frontends/petrinet-frontend/petrinet-xsts/src/test/resources/pnml/DPhil-100.pnml diff --git a/subprojects/xsts/xsts-analysis/src/test/resources/model/pnml/DPhil-20.pnml b/subprojects/frontends/petrinet-frontend/petrinet-xsts/src/test/resources/pnml/DPhil-20.pnml similarity index 100% rename from subprojects/xsts/xsts-analysis/src/test/resources/model/pnml/DPhil-20.pnml rename to subprojects/frontends/petrinet-frontend/petrinet-xsts/src/test/resources/pnml/DPhil-20.pnml diff --git a/subprojects/xsts/xsts-analysis/src/test/resources/model/pnml/DPhil-200.pnml b/subprojects/frontends/petrinet-frontend/petrinet-xsts/src/test/resources/pnml/DPhil-200.pnml similarity index 100% rename from subprojects/xsts/xsts-analysis/src/test/resources/model/pnml/DPhil-200.pnml rename to subprojects/frontends/petrinet-frontend/petrinet-xsts/src/test/resources/pnml/DPhil-200.pnml diff --git a/subprojects/xsts/xsts-analysis/src/test/resources/model/pnml/DPhil-30.pnml b/subprojects/frontends/petrinet-frontend/petrinet-xsts/src/test/resources/pnml/DPhil-30.pnml similarity index 100% rename from subprojects/xsts/xsts-analysis/src/test/resources/model/pnml/DPhil-30.pnml rename to subprojects/frontends/petrinet-frontend/petrinet-xsts/src/test/resources/pnml/DPhil-30.pnml diff --git a/subprojects/xsts/xsts-analysis/src/test/resources/model/pnml/DPhil-50.pnml b/subprojects/frontends/petrinet-frontend/petrinet-xsts/src/test/resources/pnml/DPhil-50.pnml similarity index 100% rename from subprojects/xsts/xsts-analysis/src/test/resources/model/pnml/DPhil-50.pnml rename to subprojects/frontends/petrinet-frontend/petrinet-xsts/src/test/resources/pnml/DPhil-50.pnml diff --git a/subprojects/xsts/xsts-analysis/src/test/resources/model/pnml/FMS_Ciardo.pnml b/subprojects/frontends/petrinet-frontend/petrinet-xsts/src/test/resources/pnml/FMS_Ciardo.pnml similarity index 100% rename from subprojects/xsts/xsts-analysis/src/test/resources/model/pnml/FMS_Ciardo.pnml rename to subprojects/frontends/petrinet-frontend/petrinet-xsts/src/test/resources/pnml/FMS_Ciardo.pnml diff --git a/subprojects/xsts/xsts-analysis/src/test/resources/model/pnml/Kanban.pnml b/subprojects/frontends/petrinet-frontend/petrinet-xsts/src/test/resources/pnml/Kanban.pnml similarity index 100% rename from subprojects/xsts/xsts-analysis/src/test/resources/model/pnml/Kanban.pnml rename to subprojects/frontends/petrinet-frontend/petrinet-xsts/src/test/resources/pnml/Kanban.pnml diff --git a/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTSolver.java b/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTSolver.java index dd1632768e..7e7609a612 100644 --- a/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTSolver.java +++ b/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTSolver.java @@ -315,7 +315,7 @@ private LitExpr extractBvConstLiteral(final Formula formula) { } } - private EnumLitExpr extractEnumLiteral(Formula formula, EnumType enumType) { + private LitExpr extractEnumLiteral(Formula formula, EnumType enumType) { final Formula term = model.eval(formula); if (term == null) { return null; diff --git a/subprojects/solver/solver-smtlib-cli/README.md b/subprojects/solver/solver-smtlib-cli/README.md index a1e53f56d3..d711698eac 100644 --- a/subprojects/solver/solver-smtlib-cli/README.md +++ b/subprojects/solver/solver-smtlib-cli/README.md @@ -2,68 +2,102 @@ **This project is in alpha state. Expect breaking changes in the near future!** -The `solver-smtlib-cli` project is an executable (command line) tool for managing the SMT-LIB compatible solvers. -For more information about the SMT-LIB compatibility in Theta, take a look at the [`solver-smtlib`](../solver-smtlib/README.md) project. +The `solver-smtlib-cli` project is an executable (command line) tool for managing the SMT-LIB +compatible solvers. +For more information about the SMT-LIB compatibility in Theta, take a look at +the [`solver-smtlib`](../solver-smtlib/README.md) project. ### Related projects * [`solver`](../solver/README.md): Contains the generic utilities and solver interface of Theta. -* [`solver-smtlib`](../solver-smtlib/README.md): Implements Theta's solver interface to support SMT-LIB compatible solvers. +* [`solver-smtlib`](../solver-smtlib/README.md): Implements Theta's solver interface to support + SMT-LIB compatible solvers. ## Using the tool 1. First, get the tool. * The easiest way is to download a [pre-built release](https://github.com/ftsrg/theta/releases). - * You can also [build](../../../doc/Build.md) the tool yourself. The runnable jar file will appear under _build/libs/_ with the name _theta-solver-smtlib-cli-\-all.jar_, you can simply rename it to _theta-solver-smtlib-cli.jar_.. + * You can also [build](../../../doc/Build.md) the tool yourself. The runnable jar file will + appear under _build/libs/_ with the name _theta-solver-smtlib-cli-\-all.jar_, you + can simply rename it to _theta-solver-smtlib-cli.jar_.. 2. Running the tool requires Java (JRE) 17. -3. The tool can be executed with `java -jar theta-solver-smtlib-cli.jar [MAIN ARGUMENTS] [COMMAND] [ARGUMENTS]`. - * If no arguments are given, a help screen is displayed about the arguments and their possible values. - More information can also be found below. +3. The tool can be executed + with `java -jar theta-solver-smtlib-cli.jar [MAIN ARGUMENTS] [COMMAND] [ARGUMENTS]`. + * If no arguments are given, a help screen is displayed about the arguments and their possible + values. + More information can also be found below. ## Arguments The tool supports the following main arguments. These are all optional: -* `--home`: Sets the path of the solver registry. It defaults to a folder named _.theta_ in the home folder of the current user. + +* `--home`: Sets the path of the solver registry. It defaults to a folder named _.theta_ in the home + folder of the current user. * `--help`: Prints the help message. The tool supports the following commands and their arguments: -* `install :`: Installs a solver with the given name and version to the current solver registry. The __ identifies the driver (a.k.a. the type) of the solver, while the __ identifies the version of the solver to install. (See the list of supported solvers and their versions with `list-supported`) - * `--name`: Install the solver version under this custom name (:), instead of the default (:) - * `--solver-path`: The path of the solver to install. The solver will not be downloaded, instead the binary on this path will be used. Caveat emptor: the version must be specified correctly, there is no automatic detection. - * `--tempt-murphy`: Enables the installation of unsupported solver versions. If you enable this, you can expect things to break, as these solvers were not tested with Theta at all! -* `install-generic`: Installs an SMT-LIB compatible solver with the generic driver. For more information see the [Generic driver](#Generic-driver) section. +* `install :`: Installs a solver with the given name and version to the + current solver registry. The __ identifies the driver (a.k.a. the type) of the + solver, while the __ identifies the version of the solver to install. (See the + list of supported solvers and their versions with `list-supported`) + * `--name`: Install the solver version under this custom name (:), instead of + the default (:) + * `--solver-path`: The path of the solver to install. The solver will not be downloaded, instead + the binary on this path will be used. Caveat emptor: the version must be specified correctly, + there is no automatic detection. + * `--tempt-murphy`: Enables the installation of unsupported solver versions. If you enable this, + you can expect things to break, as these solvers were not tested with Theta at all! +* `install-generic`: Installs an SMT-LIB compatible solver with the generic driver. For more + information see the [Generic driver](#Generic-driver) section. * `--solver-path` **(required)**: Denotes the path to the binary of the solver. * `--solver-args`: The command line arguments to pass to the generic solver. * `--name` **(required)**: Install the solver under this custom name (generic:) -* `uninstall :`: Uninstalls a solver with the given name and version from the current solver registry. (See the list of installed solvers and their versions with `list-installed`) -* `rename :`: Renames one installed solver version. (See the list of installed solvers and their versions with `list-installed`) - * `--name` **(required)**: Rename the solver version to this custom name (:). -* `get-info :`: Gets the stored information about the solver with the given name and version in the current solver registry. (See the list of installed solvers and their versions with `list-installed`) -* `edit-args :`: Edits the command line arguments of the solver with the given name and version. The command opens a txt file that stores the command line arguments to edit with the default editor, or prints the path of the file to edit if the default editor is not applicable (e.g. CLI). (See the list of installed solvers and their versions with `list-installed`) +* `uninstall :`: Uninstalls a solver with the given name and version + from the current solver registry. (See the list of installed solvers and their versions + with `list-installed`) +* `rename :`: Renames one installed solver version. (See the list of + installed solvers and their versions with `list-installed`) + * `--name` **(required)**: Rename the solver version to this custom name (:). +* `get-info :`: Gets the stored information about the solver with the + given name and version in the current solver registry. (See the list of installed solvers and + their versions with `list-installed`) +* `edit-args :`: Edits the command line arguments of the solver with + the given name and version. The command opens a txt file that stores the command line arguments to + edit with the default editor, or prints the path of the file to edit if the default editor is not + applicable (e.g. CLI). (See the list of installed solvers and their versions + with `list-installed`) * `--print`: If given, the path of the file to edit will be printed instead of opening. -* `list-installed []`: Lists the installed solvers and their versions. If the __ is given, only the versions of that solver will be listed. -* `list-supported []`: Lists the supported solvers and their versions. If the __ is given, only the versions of that solver will be listed. +* `list-installed []`: Lists the installed solvers and their versions. If the _< + solver_name>_ is given, only the versions of that solver will be listed. +* `list-supported []`: Lists the supported solvers and their versions. If the _< + solver_name>_ is given, only the versions of that solver will be listed. ### For developer usage The following main arguments are targeted for developers: -| Flag | Description | -|---|---| -| `--stacktrace` | Print full stack trace for exceptions. | -| `--loglevel` | `--loglevel`: Detailedness of logging. Possible values (from the least to the most detailed): `RESULT`, `MAINSTEP`, `SUBSTEP` (default), `INFO`, `DETAIL`, `VERBOSE` | +| Flag | Description | +|----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `--stacktrace` | Print full stack trace for exceptions. | +| `--loglevel` | `--loglevel`: Detailedness of logging. Possible values (from the least to the most detailed): `RESULT`, `MAINSTEP`, `SUBSTEP` (default), `INFO`, `DETAIL`, `VERBOSE` | ## Generic driver -It is possible to integrate any fully SMT-LIB compatible solvers with Theta using the generic driver. To do this, the following information is needed: +It is possible to integrate any fully SMT-LIB compatible solvers with Theta using the generic +driver. To do this, the following information is needed: -* The path to the binary of the solver. If the solver does not have a binary (e.g. it is Java based), then a bash script should be created that serves as an entry point for the solver. -* The command line arguments to pass to the solver. These arguments should configure the solver for the following behavior: +* The path to the binary of the solver. If the solver does not have a binary (e.g. it is Java + based), then a bash script should be created that serves as an entry point for the solver. +* The command line arguments to pass to the solver. These arguments should configure the solver for + the following behavior: * It must read its input from the standard input. - * It must write its output to the standard output. Moreover, it should flush the standard output after every line. - * It **must not** write anything else to the standard output that is not part of the SMT-LIB standard. The first command the driver issues is the `(set-option :print-success true)`, so the first characters the binary outputs should be the result of this command! - + * It must write its output to the standard output. Moreover, it should flush the standard output + after every line. + * It **must not** write anything else to the standard output that is not part of the SMT-LIB + standard. The first command the driver issues is the `(set-option :print-success true)`, so + the first characters the binary outputs should be the result of this command! + For more information see the default configurations of the supported solvers. ## Supported solvers @@ -79,4 +113,5 @@ Currently, the following solvers are supported. * Z3 * `4.4.0` - `4.6.0`: Supported with interpolation. * `4.7.1` - : Supported without interpolation. Interpolation was removed in `4.7.0`. -* Generic: Any other solver that can communicate with SMT-LIBv2 standard. See section Generic driver for more details. +* Generic: Any other solver that can communicate with SMT-LIBv2 standard. See section Generic driver + for more details. diff --git a/subprojects/solver/solver-smtlib/README.md b/subprojects/solver/solver-smtlib/README.md index dbde95da63..2ed20fb38e 100644 --- a/subprojects/solver/solver-smtlib/README.md +++ b/subprojects/solver/solver-smtlib/README.md @@ -2,60 +2,102 @@ **This project is in alpha state. Expect breaking changes in the near future!** -This project wraps a generic solver that supports the SMT-LIB2 interface into our common interfaces for solvers (located in the [solver](..) project). +This project wraps a generic solver that supports the SMT-LIB2 interface into our common interfaces +for solvers (located in the [solver](..) project). ### Related projects * [`solver`](../solver/README.md): Contains the generic utilities and solver interface of Theta. -* [`solver-smtlib-cli`](../solver-smtlib-cli/README.md): Command line tool for managing the SMT-LIB compatible solvers. +* [`solver-smtlib-cli`](../solver-smtlib-cli/README.md): Command line tool for managing the SMT-LIB + compatible solvers. ## SMT-LIB2 -The [SMT-LIB2 standard](http://smtlib.cs.uiowa.edu/) is an international initiative, whose goal is to partly provide a common input and output language for SMT solvers. The standard is adapted by many SMT solvers, such as Z3, MathSAT, CVC4, etc... +The [SMT-LIB2 standard](http://smtlib.cs.uiowa.edu/) is an international initiative, whose goal is +to partly provide a common input and output language for SMT solvers. The standard is adapted by +many SMT solvers, such as Z3, MathSAT, CVC4, etc... -However, there are some limitation to this standard, both in terms of its content and its practical application by the solvers that support it: +However, there are some limitation to this standard, both in terms of its content and its practical +application by the solvers that support it: -* There are no standard way of denoting an array literal in SMT-LIB. Each solver that support the said theory used to come up with a solution of their own in this matter. This lead to the creation of the `as-array` (Z3), and the `as const` (CVC4, MathSAT) constructs. Nowadays, solvers tend to support the `as const` construct (event the newer versions of Z3). -* There are no standard way of denoting interpolation. Solvers that support interpolation (Z3, SMTInterpol, MathSAT) have their own extension added to SMT-LIB to support this feature. -* The support for the standard tends to be loose in some solvers. For example, MathSAT expects a numeric argument to `push` and `pop`, does not default to 1, like the standard. Moreover, MathSAT uses a custom output language when outputting models, that is not part of the standard. +* There are no standard way of denoting an array literal in SMT-LIB. Each solver that support the + said theory used to come up with a solution of their own in this matter. This lead to the creation + of the `as-array` (Z3), and the `as const` (CVC4, MathSAT) constructs. Nowadays, solvers tend to + support the `as const` construct (event the newer versions of Z3). +* There are no standard way of denoting interpolation. Solvers that support interpolation (Z3, + SMTInterpol, MathSAT) have their own extension added to SMT-LIB to support this feature. +* The support for the standard tends to be loose in some solvers. For example, MathSAT expects a + numeric argument to `push` and `pop`, does not default to 1, like the standard. Moreover, MathSAT + uses a custom output language when outputting models, that is not part of the standard. -This list is unfortunately far from being complete, so one has to be careful when integrating a new solver with SMT-LIB support. +This list is unfortunately far from being complete, so one has to be careful when integrating a new +solver with SMT-LIB support. ## Architecture -The issues of compatibility described in the earlier section warranted to be considered in the architecture. The component is designed to be a composite of subcomponents along well-defined interfaced that make it possible to replace complete subcomponents if for the sake of a solver. +The issues of compatibility described in the earlier section warranted to be considered in the +architecture. The component is designed to be a composite of subcomponents along well-defined +interfaced that make it possible to replace complete subcomponents if for the sake of a solver. ### Generic architecture interface -In general, to have an SMT-LIB supporting solver, components implementing the following interfaces has to be developed: +In general, to have an SMT-LIB supporting solver, components implementing the following interfaces +has to be developed: -* `SmtLibTransformationManager`: Transforms anything in Theta to their SMT-LIB counterpart. It uses further components for this feature: +* `SmtLibTransformationManager`: Transforms anything in Theta to their SMT-LIB counterpart. It uses + further components for this feature: * `SmtLibTypeTransformer`: Transforms a Theta type to and SMT-LIB type. * `SmtLibDeclTransformer`: Transforms a Theta declaration to an SMT-LIB declaration. * `SmtLibExprTransformer`: Transforms a Theta expression to an SMT-LIB expression. * `SmtLibSymbolTable`: Caches the Theta declarations and their SMT-LIB counterpart. -* `SmtLibTermTransformer`: Transforms an SMT-LIB expression to a Theta expression. It provides methods that ensure type-safety. +* `SmtLibTermTransformer`: Transforms an SMT-LIB expression to a Theta expression. It provides + methods that ensure type-safety. * `SmtLibSolverBinary`: Provides an interface to communicate with the binary of the solver. * `SmtLibSolverInstaller`: An interface to support installation scripts and solver management. -The SMT-LIB grammar that the component supports is defined using ANTLR. The ANTLR grammar can be found in the source folder (`SMTLIBv2.g4`). +The SMT-LIB grammar that the component supports is defined using ANTLR. The ANTLR grammar can be +found in the source folder (`SMTLIBv2.g4`). -The components above are integrated into a working solver implementation with Theta's solver interface by the following classes: -* `SmtLibSolver`: Provides a solver implementing Theta's `Solver` and `UCSolver` interface supporting basic satisfiability checks, model querying and unsat core querying. -* `BaseSmtLibItpSolver`: Provides a solver implementing Theta's `ItpSolver` interface supporting interpolating solvers. **Note**: As interpolation is not part of the SMT-LIB standard, this class is abstract. Each solver supporting interpolation has to extend this class and configure it properly. +The components above are integrated into a working solver implementation with Theta's solver +interface by the following classes: + +* `SmtLibSolver`: Provides a solver implementing Theta's `Solver` and `UCSolver` interface + supporting basic satisfiability checks, model querying and unsat core querying. +* `BaseSmtLibItpSolver`: Provides a solver implementing Theta's `ItpSolver` interface supporting + interpolating solvers. **Note**: As interpolation is not part of the SMT-LIB standard, this class + is abstract. Each solver supporting interpolation has to extend this class and configure it + properly. ### Generic interface implementation -The interfaces above have a default, generic implementation that works with solvers that follow the SMT-LIB standard fully. These generic classes can be found in the `hu.bme.mit.theta.solver.smtlib.impl.generic` package. +The interfaces above have a default, generic implementation that works with solvers that follow the +SMT-LIB standard fully. These generic classes can be found in +the `hu.bme.mit.theta.solver.smtlib.impl.generic` package. ### Solver specific implementations -Right now, the solver-smtlib subproject supports the following solvers. Each package contains the specialization of the interfaces above that communicate with the said solver: - -* **Boolector** (`hu.bme.mit.theta.solver.smtlib.impl.boolector`): The solver specializes in bitvector and array theories, but lacks support for others. It cannot interpolate or produce unsat cores, so it can only be used for abstraction. -* **CVC4** (`hu.bme.mit.theta.solver.smtlib.impl.cvc4`): The solver supports basic satisfiability problems for numerous theories (integers, rationals, quantifiers, arrays, bitvectors). -* **Mathsat5** (`hu.bme.mit.theta.solver.smtlib.impl.mathsat`): The solver supports basic satisfiability problems for numerous theories (integers, rationals, quantifiers, arrays, bitvectors, floating points). It also supports interpolation (binary, sequential and tree interpolation) with many of them. -* **Princess** (`hu.bme.mit.theta.solver.smtlib.impl.princess`): The solver supports basic satisfiability problems for numerous theories (integers, rationals, quantifiers, arrays, bitvectors). It also supports interpolation (binary, sequential and tree interpolation) with many of them. -* **SMTInterpol** (`hu.bme.mit.theta.solver.smtlib.impl.smtinterpol`): The solver specializes in integer and rational theories. It also supports interpolation (binary, sequential and tree interpolation) with them. -* **Yices2** (`hu.bme.mit.theta.solver.smtlib.impl.yices2`): The solver supports basic satisfiability problems for numerous theories (integers, rationals, quantifiers, arrays, bitvectors). -* **Z3** (`hu.bme.mit.theta.solver.smtlib.impl.z3`): The solver supports basic satisfiability problems for numerous theories (integers, rationals, quantifiers, arrays, bitvectors, functions), and supports interpolation as well (binary, sequential and tree interpolation) up to version 4.7. \ No newline at end of file +Right now, the solver-smtlib subproject supports the following solvers. Each package contains the +specialization of the interfaces above that communicate with the said solver: + +* **Boolector** (`hu.bme.mit.theta.solver.smtlib.impl.boolector`): The solver specializes in + bitvector and array theories, but lacks support for others. It cannot interpolate or produce unsat + cores, so it can only be used for abstraction. +* **CVC4** (`hu.bme.mit.theta.solver.smtlib.impl.cvc4`): The solver supports basic satisfiability + problems for numerous theories (integers, rationals, quantifiers, arrays, bitvectors). +* **Mathsat5** (`hu.bme.mit.theta.solver.smtlib.impl.mathsat`): The solver supports basic + satisfiability problems for numerous theories (integers, rationals, quantifiers, arrays, + bitvectors, floating points). It also supports interpolation (binary, sequential and tree + interpolation) with many of them. +* **Princess** (`hu.bme.mit.theta.solver.smtlib.impl.princess`): The solver supports basic + satisfiability problems for numerous theories (integers, rationals, quantifiers, arrays, + bitvectors). It also supports interpolation (binary, sequential and tree interpolation) with many + of them. +* **SMTInterpol** (`hu.bme.mit.theta.solver.smtlib.impl.smtinterpol`): The solver specializes in + integer and rational theories. It also supports interpolation (binary, sequential and tree + interpolation) with them. +* **Yices2** (`hu.bme.mit.theta.solver.smtlib.impl.yices2`): The solver supports basic + satisfiability problems for numerous theories (integers, rationals, quantifiers, arrays, + bitvectors). +* **Z3** (`hu.bme.mit.theta.solver.smtlib.impl.z3`): The solver supports basic satisfiability + problems for numerous theories (integers, rationals, quantifiers, arrays, bitvectors, functions), + and supports interpolation as well (binary, sequential and tree interpolation) up to version 4.7. \ No newline at end of file diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibTermTransformer.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibTermTransformer.java index 0a3dbbb376..47bea40577 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibTermTransformer.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibTermTransformer.java @@ -354,7 +354,7 @@ private Expr toLitExpr(final String litImpl, final SmtLibModel model) { return expr; } - private EnumLitExpr toEnumLitExpr(final String litImpl, final EnumType type, final SmtLibModel model) { + private LitExpr toEnumLitExpr(final String litImpl, final EnumType type, final SmtLibModel model) { final var lexer = new SMTLIBv2Lexer(CharStreams.fromString(litImpl)); final var parser = new SMTLIBv2Parser(new CommonTokenStream(lexer)); lexer.removeErrorListeners(); diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/SmtLibEnumStrategy.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/SmtLibEnumStrategy.java index f72ee5939c..bae1132271 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/SmtLibEnumStrategy.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/SmtLibEnumStrategy.java @@ -16,6 +16,7 @@ package hu.bme.mit.theta.solver.smtlib.solver; import hu.bme.mit.theta.core.decl.ConstDecl; +import hu.bme.mit.theta.core.type.LitExpr; import hu.bme.mit.theta.core.type.Type; import hu.bme.mit.theta.core.type.enumtype.EnumLitExpr; import hu.bme.mit.theta.core.type.enumtype.EnumType; @@ -51,7 +52,7 @@ public void declareDatatypes(final Collection allTypes, final St } @Override - public EnumLitExpr transformEnumTerm(Function_defContext funcDef, EnumType type, SmtLibModel model) { + public LitExpr transformEnumTerm(Function_defContext funcDef, EnumType type, SmtLibModel model) { final String longName = funcDef.term().qual_identifier().identifier().symbol().getText(); return type.litFromLongName(longName); } @@ -93,7 +94,7 @@ public String wrapAssertionExpression(String assertion, Map, String } @Override - public EnumLitExpr transformEnumTerm(Function_defContext funcDef, EnumType type, SmtLibModel model) { + public LitExpr transformEnumTerm(Function_defContext funcDef, EnumType type, SmtLibModel model) { final String id = funcDef.term().qual_identifier().identifier().symbol().getText(); for (var lit : type.getLongValues()) { if (model.getTerm(lit).contains(id)) @@ -116,7 +117,7 @@ public String wrapAssertionExpression(final String assertion, final Map transformEnumTerm(final SMTLIBv2Parser.Function_defContext funcDef, final EnumType type, final SmtLibModel model); public static SmtLibEnumStrategy getDefaultStrategy() { return SmtLibEnumStrategy.SORTS; diff --git a/subprojects/solver/solver-z3-legacy/src/main/java/hu/bme/mit/theta/solver/z3legacy/Z3Solver.java b/subprojects/solver/solver-z3-legacy/src/main/java/hu/bme/mit/theta/solver/z3legacy/Z3Solver.java index 3ca336479d..0a06cacc78 100644 --- a/subprojects/solver/solver-z3-legacy/src/main/java/hu/bme/mit/theta/solver/z3legacy/Z3Solver.java +++ b/subprojects/solver/solver-z3-legacy/src/main/java/hu/bme/mit/theta/solver/z3legacy/Z3Solver.java @@ -310,7 +310,12 @@ private LitExpr extractBvConstLiteral(final FuncDecl funcDecl) { } private LitExpr extractEnumLiteral(final ConstDecl constDecl, final FuncDecl funcDecl) { - return EnumLitExpr.of((EnumType) constDecl.getType(), z3Model.getConstInterp(funcDecl).toString()); + final com.microsoft.z3legacy.Expr term = z3Model.getConstInterp(funcDecl); + if (term == null) { + return null; + } else { + return EnumLitExpr.of((EnumType) constDecl.getType(), term.toString()); + } } private LitExpr extractConstLiteral(final FuncDecl funcDecl) { diff --git a/subprojects/solver/solver-z3/README.md b/subprojects/solver/solver-z3/README.md index 47544977d8..786e7cef76 100644 --- a/subprojects/solver/solver-z3/README.md +++ b/subprojects/solver/solver-z3/README.md @@ -1,2 +1,4 @@ -This project wraps the [Z3 solver](https://github.com/Z3Prover/z3) into our common interfaces for solvers (located in the [solver](../solver) project). -Normally, only the factory class should be used from this project to instantiate a new solver and then the common interfaces should be preferred. \ No newline at end of file +This project wraps the [Z3 solver](https://github.com/Z3Prover/z3) into our common interfaces for +solvers (located in the [solver](../solver) project). +Normally, only the factory class should be used from this project to instantiate a new solver and +then the common interfaces should be preferred. \ No newline at end of file diff --git a/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3Solver.java b/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3Solver.java index 1783f9fff6..fb3fb679a5 100644 --- a/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3Solver.java +++ b/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3Solver.java @@ -318,7 +318,12 @@ private LitExpr extractBvConstLiteral(final FuncDecl funcDecl) { } private LitExpr extractEnumLiteral(final ConstDecl constDecl, final FuncDecl funcDecl) { - return EnumLitExpr.of((EnumType) constDecl.getType(), z3Model.getConstInterp(funcDecl).toString()); + final com.microsoft.z3.Expr term = z3Model.getConstInterp(funcDecl); + if (term == null) { + return null; + } else { + return EnumLitExpr.of((EnumType) constDecl.getType(), term.toString()); + } } private LitExpr extractConstLiteral(final FuncDecl funcDecl) { diff --git a/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3SolverFactory.java b/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3SolverFactory.java index 613f1e772c..dcf42464a9 100644 --- a/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3SolverFactory.java +++ b/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3SolverFactory.java @@ -22,6 +22,8 @@ import hu.bme.mit.theta.solver.SolverFactory; import hu.bme.mit.theta.solver.UCSolver; +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.True; + public final class Z3SolverFactory implements SolverFactory { private static final Z3SolverFactory INSTANCE; diff --git a/subprojects/solver/solver/README.md b/subprojects/solver/solver/README.md index a48db4ac18..28f15d6607 100644 --- a/subprojects/solver/solver/README.md +++ b/subprojects/solver/solver/README.md @@ -1,5 +1,8 @@ This project provides common interfaces over different SMT solvers. -SMT solvers can be used to query satisfiability of expressions and to generate interpolants and unsat cores. +SMT solvers can be used to query satisfiability of expressions and to generate interpolants and +unsat cores. There is a separate project for each concrete solver that wraps it to match the common interface. -In order to be able to exchange solvers easily, the common interfaces should be preferred (except when instantiating the concrete solvers). -See [`package-info.java`](src/main/java/hu/bme/mit/theta/solver/package-info.java) in the root package for more information. \ No newline at end of file +In order to be able to exchange solvers easily, the common interfaces should be preferred (except +when instantiating the concrete solvers). +See [`package-info.java`](src/main/java/hu/bme/mit/theta/solver/package-info.java) in the root +package for more information. \ No newline at end of file diff --git a/subprojects/solver/solver/src/main/java/hu/bme/mit/theta/solver/SolverPool.java b/subprojects/solver/solver/src/main/java/hu/bme/mit/theta/solver/SolverPool.java new file mode 100644 index 0000000000..972313a3cb --- /dev/null +++ b/subprojects/solver/solver/src/main/java/hu/bme/mit/theta/solver/SolverPool.java @@ -0,0 +1,101 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.solver; + +import com.google.common.base.Preconditions; +import hu.bme.mit.theta.solver.Solver; +import hu.bme.mit.theta.solver.SolverFactory; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +public class SolverPool implements AutoCloseable { + + private final static int STARTING_SIZE = 10; + private final static int GROWING = 5; + + private int created = 0; + + private final LinkedList available; + private final List all; + + private final SolverFactory solverFactory; + + public enum ClosingMode { + ALL, + RETURNED + } + + private final ClosingMode closingMode; + + public SolverPool(SolverFactory solverFactory) { + this(solverFactory, ClosingMode.ALL); + } + + public SolverPool(SolverFactory solverFactory, ClosingMode closingMode) { + this.solverFactory = solverFactory; + this.available = new LinkedList<>(); + this.all = new ArrayList<>(); + for (int i = 0; i < STARTING_SIZE; i++) { + final var solver = solverFactory.createSolver(); + this.available.add(solver); + this.all.add(solver); + } + this.closingMode = closingMode; + } + + public Solver requestSolver() { + if (this.available.isEmpty()) createNewSolvers(); + return this.available.removeFirst(); + } + + public void returnSolver(Solver solver) { + Preconditions.checkState(solver.getAssertions().isEmpty(), "Only empty solvers can be returned"); +// System.out.println("Returned solver"); + this.available.add(solver); + } + + private void createNewSolvers() { + for (int i = 0; i < GROWING; i++) { + final var solver = solverFactory.createSolver(); + this.available.add(solver); + this.all.add(solver); + } +// System.out.println(created + " solvers created"); +// System.out.println("Free size: " + Runtime.getRuntime().freeMemory()); + this.created = created + GROWING; + } + + public int size() { + return this.created; + } + + @Override + public void close() throws Exception { +// System.out.println(all.size() - available.size() + " solvers not returned"); + if (closingMode == ClosingMode.ALL) { + for (Solver solver : all) solver.close(); +// System.out.println("Closed " + all.size() + " solvers"); + } else { + for (Solver solver : available) solver.close(); +// System.out.println("Closed " + available.size() + " solvers"); + } + this.available.clear(); + this.all.clear(); + this.created = 0; + } +} diff --git a/subprojects/sts/sts-analysis/README.md b/subprojects/sts/sts-analysis/README.md index edaaf61e9f..7f2774eb87 100644 --- a/subprojects/sts/sts-analysis/README.md +++ b/subprojects/sts/sts-analysis/README.md @@ -1,9 +1,11 @@ ## Overview -This project contains analysis modules related to the Symbolic Transition System (STS) formalism. Its main purpose is to enable the algorithms to operate over STS models. +This project contains analysis modules related to the Symbolic Transition System (STS) formalism. +Its main purpose is to enable the algorithms to operate over STS models. ### Related projects * [`analysis`](../../common/analysis/README.md): Common analysis modules. -* [`sts`](../sts/README.md): Classes to represent STSs and a domain specific language (DSL) to parse STSs from a textual representation. +* [`sts`](../sts/README.md): Classes to represent STSs and a domain specific language (DSL) to parse + STSs from a textual representation. * [`sts-cli`](../sts-cli/README.md): An executable tool (command line) for running analyses on STSs. \ No newline at end of file diff --git a/subprojects/sts/sts-analysis/src/main/java/hu/bme/mit/theta/sts/analysis/config/StsConfig.java b/subprojects/sts/sts-analysis/src/main/java/hu/bme/mit/theta/sts/analysis/config/StsConfig.java index 2c8ab89806..43b2a80ecb 100644 --- a/subprojects/sts/sts-analysis/src/main/java/hu/bme/mit/theta/sts/analysis/config/StsConfig.java +++ b/subprojects/sts/sts-analysis/src/main/java/hu/bme/mit/theta/sts/analysis/config/StsConfig.java @@ -18,25 +18,27 @@ import hu.bme.mit.theta.analysis.Action; import hu.bme.mit.theta.analysis.Prec; import hu.bme.mit.theta.analysis.State; +import hu.bme.mit.theta.analysis.Trace; import hu.bme.mit.theta.analysis.algorithm.SafetyChecker; import hu.bme.mit.theta.analysis.algorithm.SafetyResult; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; public final class StsConfig { - private final SafetyChecker checker; + private final SafetyChecker, Trace, P> checker; private final P initPrec; - private StsConfig(final SafetyChecker checker, final P initPrec) { + private StsConfig(final SafetyChecker, Trace, P> checker, final P initPrec) { this.checker = checker; this.initPrec = initPrec; } public static StsConfig create( - final SafetyChecker checker, final P initPrec) { + final SafetyChecker, Trace, P> checker, final P initPrec) { return new StsConfig<>(checker, initPrec); } - public SafetyResult check() { + public SafetyResult, Trace> check() { return checker.check(initPrec); } diff --git a/subprojects/sts/sts-analysis/src/main/java/hu/bme/mit/theta/sts/analysis/config/StsConfigBuilder.java b/subprojects/sts/sts-analysis/src/main/java/hu/bme/mit/theta/sts/analysis/config/StsConfigBuilder.java index 73f643d277..397a4a4ef8 100644 --- a/subprojects/sts/sts-analysis/src/main/java/hu/bme/mit/theta/sts/analysis/config/StsConfigBuilder.java +++ b/subprojects/sts/sts-analysis/src/main/java/hu/bme/mit/theta/sts/analysis/config/StsConfigBuilder.java @@ -15,14 +15,11 @@ */ package hu.bme.mit.theta.sts.analysis.config; -import hu.bme.mit.theta.analysis.Action; -import hu.bme.mit.theta.analysis.Analysis; -import hu.bme.mit.theta.analysis.LTS; -import hu.bme.mit.theta.analysis.Prec; -import hu.bme.mit.theta.analysis.State; -import hu.bme.mit.theta.analysis.algorithm.ArgBuilder; -import hu.bme.mit.theta.analysis.algorithm.ArgNodeComparators; -import hu.bme.mit.theta.analysis.algorithm.ArgNodeComparators.ArgNodeComparator; +import hu.bme.mit.theta.analysis.*; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgBuilder; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNodeComparators; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNodeComparators.ArgNodeComparator; import hu.bme.mit.theta.analysis.algorithm.SafetyChecker; import hu.bme.mit.theta.analysis.algorithm.cegar.Abstractor; import hu.bme.mit.theta.analysis.algorithm.cegar.BasicAbstractor; @@ -221,7 +218,7 @@ public StsConfigBuilder pruneStrategy(final PruneStrategy pruneStrategy) { domain + " domain does not support " + refinement + " refinement."); } - final SafetyChecker checker = CegarChecker.create( + final SafetyChecker, Trace, ExplPrec> checker = CegarChecker.create( abstractor, refiner, logger); final ExplPrec prec = initPrec.builder.createExpl(sts); @@ -291,7 +288,7 @@ public StsConfigBuilder pruneStrategy(final PruneStrategy pruneStrategy) { pruneStrategy, logger); } - final SafetyChecker checker = CegarChecker.create( + final SafetyChecker, Trace, PredPrec> checker = CegarChecker.create( abstractor, refiner, logger); diff --git a/subprojects/sts/sts-analysis/src/test/java/hu/bme/mit/theta/sts/analysis/StsExplTest.java b/subprojects/sts/sts-analysis/src/test/java/hu/bme/mit/theta/sts/analysis/StsExplTest.java index 04ff0d6da4..db171f2718 100644 --- a/subprojects/sts/sts-analysis/src/test/java/hu/bme/mit/theta/sts/analysis/StsExplTest.java +++ b/subprojects/sts/sts-analysis/src/test/java/hu/bme/mit/theta/sts/analysis/StsExplTest.java @@ -18,11 +18,12 @@ import hu.bme.mit.theta.analysis.Analysis; import hu.bme.mit.theta.analysis.LTS; import hu.bme.mit.theta.analysis.State; -import hu.bme.mit.theta.analysis.algorithm.ARG; -import hu.bme.mit.theta.analysis.algorithm.ArgBuilder; -import hu.bme.mit.theta.analysis.algorithm.ArgNodeComparators; -import hu.bme.mit.theta.analysis.algorithm.SafetyChecker; +import hu.bme.mit.theta.analysis.Trace; import hu.bme.mit.theta.analysis.algorithm.SafetyResult; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgBuilder; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgNodeComparators; +import hu.bme.mit.theta.analysis.algorithm.SafetyChecker; import hu.bme.mit.theta.analysis.algorithm.cegar.Abstractor; import hu.bme.mit.theta.analysis.algorithm.cegar.BasicAbstractor; import hu.bme.mit.theta.analysis.algorithm.cegar.CegarChecker; @@ -56,7 +57,7 @@ import java.util.Collections; import java.util.function.Predicate; -import static hu.bme.mit.theta.analysis.algorithm.ArgUtils.isWellLabeled; +import static hu.bme.mit.theta.analysis.algorithm.arg.ArgUtils.isWellLabeled; import static hu.bme.mit.theta.core.decl.Decls.Var; import static hu.bme.mit.theta.core.type.anytype.Exprs.Prime; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.And; @@ -121,12 +122,12 @@ public void test() { .create(exprTraceChecker, JoiningPrecRefiner.create(new VarsRefToExplPrec()), PruneStrategy.LAZY, logger); - final SafetyChecker checker = CegarChecker.create( + final SafetyChecker, Trace, ExplPrec> checker = CegarChecker.create( abstractor, refiner, logger); - final SafetyResult safetyStatus = checker.check(prec); + final SafetyResult, Trace> safetyStatus = checker.check(prec); - final ARG arg = safetyStatus.getArg(); + final ARG arg = safetyStatus.getWitness(); assertTrue(isWellLabeled(arg, abstractionSolver)); // System.out.println(new diff --git a/subprojects/sts/sts-analysis/src/test/java/hu/bme/mit/theta/sts/analysis/StsMddCheckerTest.java b/subprojects/sts/sts-analysis/src/test/java/hu/bme/mit/theta/sts/analysis/StsMddCheckerTest.java new file mode 100644 index 0000000000..e9f88faaad --- /dev/null +++ b/subprojects/sts/sts-analysis/src/test/java/hu/bme/mit/theta/sts/analysis/StsMddCheckerTest.java @@ -0,0 +1,126 @@ +/* + * Copyright 2024 Budapest University of Technology and Economics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package hu.bme.mit.theta.sts.analysis; + +import hu.bme.mit.theta.analysis.algorithm.SafetyResult; +import hu.bme.mit.theta.analysis.algorithm.mdd.MddCex; +import hu.bme.mit.theta.analysis.algorithm.mdd.MddChecker; +import hu.bme.mit.theta.analysis.algorithm.mdd.MddChecker.IterationStrategy; +import hu.bme.mit.theta.analysis.algorithm.mdd.MddWitness; +import hu.bme.mit.theta.analysis.expr.ExprAction; +import hu.bme.mit.theta.common.Utils; +import hu.bme.mit.theta.common.logging.ConsoleLogger; +import hu.bme.mit.theta.common.logging.Logger; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.booltype.BoolType; +import hu.bme.mit.theta.core.utils.indexings.VarIndexing; +import hu.bme.mit.theta.core.utils.indexings.VarIndexingFactory; +import hu.bme.mit.theta.solver.SolverPool; +import hu.bme.mit.theta.solver.z3legacy.Z3LegacySolverFactory; +import hu.bme.mit.theta.sts.STS; +import hu.bme.mit.theta.sts.aiger.AigerParser; +import hu.bme.mit.theta.sts.aiger.AigerToSts; +import hu.bme.mit.theta.sts.dsl.StsDslManager; +import hu.bme.mit.theta.sts.dsl.StsSpec; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; + +import static org.junit.Assert.assertTrue; + +@RunWith(value = Parameterized.class) +public class StsMddCheckerTest { + @Parameterized.Parameter(value = 0) + public String filePath; + + @Parameterized.Parameter(value = 1) + public boolean safe; + + @Parameterized.Parameters(name = "{index}: {0}, {1}") + public static Collection data() { + return Arrays.asList(new Object[][]{ + {"src/test/resources/hw1_false.aag", false}, + + {"src/test/resources/hw2_true.aag", true}, + + {"src/test/resources/boolean1.system", false}, + + {"src/test/resources/boolean2.system", false}, + + {"src/test/resources/counter.system", true}, + + {"src/test/resources/counter_bad.system", false}, + + {"src/test/resources/counter_parametric.system", true}, + + {"src/test/resources/loop.system", true}, + + {"src/test/resources/loop_bad.system", false}, + + {"src/test/resources/multipleinitial.system", false}, + + {"src/test/resources/readerswriters.system", true}, + + {"src/test/resources/simple1.system", false}, + + {"src/test/resources/simple2.system", true}, + + {"src/test/resources/simple3.system", false}, + }); + } + + @Test + public void test() throws Exception { + final Logger logger = new ConsoleLogger(Logger.Level.SUBSTEP); + + final STS sts; + if (filePath.endsWith("aag")) sts = AigerToSts.createSts(AigerParser.parse(filePath)); + else { + final StsSpec spec = StsDslManager.createStsSpec(new FileInputStream(filePath)); + if (spec.getAllSts().size() != 1) + throw new UnsupportedOperationException("STS contains multiple properties."); + sts = Utils.singleElementOf(spec.getAllSts()); + } + + final SafetyResult status; + try (var solverPool = new SolverPool(Z3LegacySolverFactory.getInstance())) { + final MddChecker checker = MddChecker.create(sts.getInit(), VarIndexingFactory.indexing(0), new ExprAction() { + @Override + public Expr toExpr() { + return sts.getTrans(); + } + + @Override + public VarIndexing nextIndexing() { + return VarIndexingFactory.indexing(1); + } + }, sts.getProp(), solverPool, logger, IterationStrategy.GSAT); + status = checker.check(null); + } + + if (safe) { + assertTrue(status.isSafe()); + } else { + assertTrue(status.isUnsafe()); + } + } + +} diff --git a/subprojects/sts/sts-analysis/src/test/java/hu/bme/mit/theta/sts/analysis/StsPredTest.java b/subprojects/sts/sts-analysis/src/test/java/hu/bme/mit/theta/sts/analysis/StsPredTest.java index c0ee26124e..5eea722540 100644 --- a/subprojects/sts/sts-analysis/src/test/java/hu/bme/mit/theta/sts/analysis/StsPredTest.java +++ b/subprojects/sts/sts-analysis/src/test/java/hu/bme/mit/theta/sts/analysis/StsPredTest.java @@ -15,7 +15,7 @@ */ package hu.bme.mit.theta.sts.analysis; -import static hu.bme.mit.theta.analysis.algorithm.ArgUtils.isWellLabeled; +import static hu.bme.mit.theta.analysis.algorithm.arg.ArgUtils.isWellLabeled; import static hu.bme.mit.theta.core.decl.Decls.Var; import static hu.bme.mit.theta.core.type.anytype.Exprs.Prime; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.And; @@ -30,6 +30,8 @@ import java.util.function.Predicate; +import hu.bme.mit.theta.analysis.Trace; +import hu.bme.mit.theta.analysis.algorithm.SafetyResult; import hu.bme.mit.theta.analysis.expr.refinement.*; import hu.bme.mit.theta.solver.ItpSolver; import hu.bme.mit.theta.solver.Solver; @@ -39,10 +41,9 @@ import hu.bme.mit.theta.analysis.Analysis; import hu.bme.mit.theta.analysis.LTS; import hu.bme.mit.theta.analysis.State; -import hu.bme.mit.theta.analysis.algorithm.ARG; -import hu.bme.mit.theta.analysis.algorithm.ArgBuilder; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; +import hu.bme.mit.theta.analysis.algorithm.arg.ArgBuilder; import hu.bme.mit.theta.analysis.algorithm.SafetyChecker; -import hu.bme.mit.theta.analysis.algorithm.SafetyResult; import hu.bme.mit.theta.analysis.algorithm.cegar.Abstractor; import hu.bme.mit.theta.analysis.algorithm.cegar.BasicAbstractor; import hu.bme.mit.theta.analysis.algorithm.cegar.CegarChecker; @@ -116,13 +117,13 @@ public void testPredPrec() { JoiningPrecRefiner.create(new ItpRefToPredPrec(ExprSplitters.atoms())), PruneStrategy.LAZY, logger); - final SafetyChecker checker = CegarChecker.create( + final SafetyChecker, Trace, PredPrec> checker = CegarChecker.create( abstractor, refiner, logger); - final SafetyResult safetyStatus = checker.check(prec); + final SafetyResult, Trace> safetyStatus = checker.check(prec); System.out.println(safetyStatus); - final ARG arg = safetyStatus.getArg(); + final ARG arg = safetyStatus.getWitness(); assertTrue(isWellLabeled(arg, abstractionSolver)); // System.out.println(new diff --git a/subprojects/sts/sts-cli/README.md b/subprojects/sts/sts-cli/README.md index a5e2dbe130..9a6731f2e0 100644 --- a/subprojects/sts/sts-cli/README.md +++ b/subprojects/sts/sts-cli/README.md @@ -1,38 +1,51 @@ ## Overview -The `sts-cli` project is an executable (command line) tool for running CEGAR-based analyses on Symbolic Transition Systems (STS). -For more information about the STS formalism and its supported language elements, take a look at the [`sts`](../sts/README.md) project. +The `sts-cli` project is an executable (command line) tool for running CEGAR-based analyses on +Symbolic Transition Systems (STS). +For more information about the STS formalism and its supported language elements, take a look at +the [`sts`](../sts/README.md) project. ### Related projects -* [`sts`](../sts/README.md): Classes to represent STSs and a domain specific language (DSL) to parse STSs from a textual representation. -* [`sts-analysis`](../sts-analysis/README.md): STS specific analysis modules enabling the algorithms to operate on them. +* [`sts`](../sts/README.md): Classes to represent STSs and a domain specific language (DSL) to parse + STSs from a textual representation. +* [`sts-analysis`](../sts-analysis/README.md): STS specific analysis modules enabling the algorithms + to operate on them. ## Using the tool 1. First, get the tool. * The easiest way is to download a [pre-built release](https://github.com/ftsrg/theta/releases). - * You can also [build](../../../doc/Build.md) the tool yourself. The runnable jar file will appear under _build/libs/_ with the name _theta-sts-cli-\-all.jar_, you can simply rename it to _theta-sts-cli.jar_. + * You can also [build](../../../doc/Build.md) the tool yourself. The runnable jar file will + appear under _build/libs/_ with the name _theta-sts-cli-\-all.jar_, you can simply + rename it to _theta-sts-cli.jar_. * Alternatively, you can use our docker image (see below). 2. Running the tool requires Java (JRE) 17. -3. The tool also requires the [Z3 SMT solver libraries](../../../doc/Build.md) to be available on `PATH`. +3. The tool also requires the [Z3 SMT solver libraries](../../../doc/Build.md) to be available + on `PATH`. 4. The tool can be executed with `java -jar theta-sts-cli.jar [ARGUMENTS]`. - * If no arguments are given, a help screen is displayed about the arguments and their possible values. - More information can also be found below. - * For example `java -jar theta-sts-cli.jar --model counter.system --loglevel INFO` runs the default analysis with logging on the `counter.system` input file. + * If no arguments are given, a help screen is displayed about the arguments and their possible + values. + More information can also be found below. + * For example `java -jar theta-sts-cli.jar --model counter.system --loglevel INFO` runs the + default analysis with logging on the `counter.system` input file. ### Docker A Dockerfile is also available under the _docker_ directory in the root of the repository. The image can be built using the following command (from the root of the repository): + ``` docker build -t theta-sts-cli -f docker/theta-sts-cli.Dockerfile . ``` -The script `run-theta-sts-cli.sh` can be used for running the containerized version on models residing on the host: +The script `run-theta-sts-cli.sh` can be used for running the containerized version on models +residing on the host: + ``` ./docker/run-theta-sts-cli.sh model.sts [OTHER ARGUMENTS] ``` + Note that the model must be given as the first positional argument (without `--model`). ## Arguments @@ -40,17 +53,21 @@ Note that the model must be given as the first positional argument (without `--m All arguments are optional, except `--model`. * `--model`: Path of the input STS model (mandatory). -* `--cex`: Output file where the counterexample is written (if the result is unsafe). If the argument is not given (default) the counterexample is not printed. Use `CON` (Windows) or `/dev/stdout` (Linux) as argument to print to the standard output. +* `--cex`: Output file where the counterexample is written (if the result is unsafe). If the + argument is not given (default) the counterexample is not printed. Use `CON` (Windows) + or `/dev/stdout` (Linux) as argument to print to the standard output. * `--loglevel`: Detailedness of logging. - * Possible values (from the least to the most detailed): `RESULT`, `MAINSTEP`, `SUBSTEP` (default), `INFO`, `DETAIL`, `VERBOSE` + * Possible values (from the least to the most detailed): `RESULT`, `MAINSTEP`, `SUBSTEP` ( + default), `INFO`, `DETAIL`, `VERBOSE` * `--version`: Print version info (in this case `--model` is of course not required). -The arguments related to the algorithm are described in more detail (along with best practices) in [CEGAR-algorithms.md](../../../doc/CEGAR-algorithms.md). +The arguments related to the algorithm are described in more detail (along with best practices) +in [CEGAR-algorithms.md](../../../doc/CEGAR-algorithms.md). ### For developer usage -| Flag | Description | -|--|--| -| `--stacktrace` | Print full stack trace for exceptions. | -| `--benchmark` | Benchmark mode, only print metrics in csv format. | -| `--header` | Print the header for the benchmark mode csv format. | +| Flag | Description | +|----------------|-----------------------------------------------------| +| `--stacktrace` | Print full stack trace for exceptions. | +| `--benchmark` | Benchmark mode, only print metrics in csv format. | +| `--header` | Print the header for the benchmark mode csv format. | diff --git a/subprojects/sts/sts-cli/src/main/java/hu/bme/mit/theta/sts/cli/StsCli.java b/subprojects/sts/sts-cli/src/main/java/hu/bme/mit/theta/sts/cli/StsCli.java index 4c8a605003..dabdb04b79 100644 --- a/subprojects/sts/sts-cli/src/main/java/hu/bme/mit/theta/sts/cli/StsCli.java +++ b/subprojects/sts/sts-cli/src/main/java/hu/bme/mit/theta/sts/cli/StsCli.java @@ -21,6 +21,7 @@ import com.google.common.base.Stopwatch; import hu.bme.mit.theta.analysis.Trace; import hu.bme.mit.theta.analysis.algorithm.SafetyResult; +import hu.bme.mit.theta.analysis.algorithm.arg.ARG; import hu.bme.mit.theta.analysis.algorithm.cegar.CegarStatistics; import hu.bme.mit.theta.analysis.expr.ExprState; import hu.bme.mit.theta.analysis.expr.refinement.PruneStrategy; @@ -158,7 +159,7 @@ private void run() { final Stopwatch sw = Stopwatch.createStarted(); final STS sts = loadModel(); - SafetyResult status = null; + SafetyResult, ? extends Trace> status = null; if (algorithm.equals(Algorithm.CEGAR)) { final StsConfig configuration = buildConfiguration(sts); status = check(configuration); @@ -176,7 +177,7 @@ private void run() { } } - private SafetyResult check(StsConfig configuration) throws Exception { + private SafetyResult, ? extends Trace> check(StsConfig configuration) throws Exception { try { return configuration.check(); } catch (final Exception ex) { @@ -225,7 +226,7 @@ private STS loadModel() throws Exception { } } - private void printResult(final SafetyResult status, final STS sts, + private void printResult(final SafetyResult, ? extends Trace> status, final STS sts, final long totalTimeMs) { final CegarStatistics stats = (CegarStatistics) status.getStats().get(); if (benchmarkMode) { @@ -235,11 +236,11 @@ private void printResult(final SafetyResult status, final STS sts, writer.cell(stats.getAbstractorTimeMs()); writer.cell(stats.getRefinerTimeMs()); writer.cell(stats.getIterations()); - writer.cell(status.getArg().size()); - writer.cell(status.getArg().getDepth()); - writer.cell(status.getArg().getMeanBranchingFactor()); + writer.cell(status.getWitness().size()); + writer.cell(status.getWitness().getDepth()); + writer.cell(status.getWitness().getMeanBranchingFactor()); if (status.isUnsafe()) { - writer.cell(status.asUnsafe().getTrace().length() + ""); + writer.cell(status.asUnsafe().getCex().length() + ""); } else { writer.cell(""); } @@ -267,9 +268,9 @@ private void printError(final Throwable ex) { } } - private void writeCex(final STS sts, final SafetyResult.Unsafe status) + private void writeCex(final STS sts, final SafetyResult.Unsafe> status) throws FileNotFoundException { - @SuppressWarnings("unchecked") final Trace trace = (Trace) status.getTrace(); + @SuppressWarnings("unchecked") final Trace trace = (Trace) status.getCex(); final Trace concrTrace = StsTraceConcretizer.concretize(sts, trace, Z3LegacySolverFactory.getInstance()); final File file = new File(cexfile); diff --git a/subprojects/sts/sts/README.md b/subprojects/sts/sts/README.md index d5ab271e82..1c4805ab5c 100644 --- a/subprojects/sts/sts/README.md +++ b/subprojects/sts/sts/README.md @@ -1,15 +1,19 @@ ## Overview This project contains the Symbolic Transition System (STS) formalism. -It is a generic, low-level formalism that can describe any kind of system using variables and initial/transition expressions. +It is a generic, low-level formalism that can describe any kind of system using variables and +initial/transition expressions. The project includes: + * Classes to represent STSs. * A domain specific language (DSL) to parse STSs from a textual representation. -* A frontend that can parse systems described in the [AIGER](http://fmv.jku.at/aiger/) (And-Inverter Graph) format and represent them using STSs. +* A frontend that can parse systems described in the [AIGER](http://fmv.jku.at/aiger/) (And-Inverter + Graph) format and represent them using STSs. ### Related projects -* [`sts-analysis`](../sts-analysis/README.md): STS specific analysis modules enabling the algorithms to operate on them. +* [`sts-analysis`](../sts-analysis/README.md): STS specific analysis modules enabling the algorithms + to operate on them. * [`sts-cli`](../sts-cli/README.md): An executable tool (command line) for running analyses on STSs. ## STS Formalism @@ -18,18 +22,23 @@ An STS is a tuple `(V, I, T, P)` of * variables `V = {v1, v2, ..., vn}`, * an initial expression `I` over `V` describing the initial states, -* a transition expression `T` (over the variables `V` and their primed version `V'`) describing the transition relation, where the plain variables correspond to the actual state, while the primed variables correspond to the next state, and +* a transition expression `T` (over the variables `V` and their primed version `V'`) describing the + transition relation, where the plain variables correspond to the actual state, while the primed + variables correspond to the next state, and * a property expression `P` over the variables `V`. -Algorithms are usually interested in proving that the property holds for every reachable state (safety property). +Algorithms are usually interested in proving that the property holds for every reachable state ( +safety property). Variables of the STS can have the following types. + * `bool`: Booleans. * `int`: Mathematical, unbounded SMT integers. * `rat`: Rational numbers (implemented as SMT reals). * `[K] -> V`: SMT arrays (associative maps) from a given key type `K` to a value type `V`. Expressions of the STS include the following. + * Identifiers (variables). * Primed expressions (only in transition expression) to represent the next state, e.g., `x'`. * Literals, e.g., `true`, `false` (Bool), `0`, `123` (integer), `4 % 5` (rational). @@ -53,7 +62,8 @@ specification Counter { } ``` -Variables can be defined by `var : `, the initial formula by `initial `, the transition formula by `transition ` and the property by `models G()`. +Variables can be defined by `var : `, the initial formula by `initial `, +the transition formula by `transition ` and the property by `models G()`. See _src/test/resources_ for more examples and _src/main/antlr_ for the full grammar. diff --git a/subprojects/xcfa/llvm2xcfa/src/main/java/hu/bme/mit/theta/llvm2xcfa/Readme.md b/subprojects/xcfa/llvm2xcfa/src/main/java/hu/bme/mit/theta/llvm2xcfa/Readme.md index 0f6977101a..db2cb864fc 100644 --- a/subprojects/xcfa/llvm2xcfa/src/main/java/hu/bme/mit/theta/llvm2xcfa/Readme.md +++ b/subprojects/xcfa/llvm2xcfa/src/main/java/hu/bme/mit/theta/llvm2xcfa/Readme.md @@ -1,113 +1,118 @@ # LLVM Instruction mapping -These tables detail the currently supported LLVM instructions and their corresponding model elements. Note, that a -dash (`-`) denotes an instruction that is recognized but _won't_ cause any alteration to the model (because it is -out-of-scope), while a `TODO` label means that it currently produces an error to use the instruction, but should be +These tables detail the currently supported LLVM instructions and their corresponding model +elements. Note, that a +dash (`-`) denotes an instruction that is recognized but _won't_ cause any alteration to the model ( +because it is +out-of-scope), while a `TODO` label means that it currently produces an error to use the +instruction, but should be handled accordingly. ## Terminator Instructions -| LLVM Instructions | Handled versions | Resulting model element(s)| -| --- | --- | --- | -|`ret` | 1. `ret`
2. `ret ` | 1. Edge to final location
2. Assignment to return variable, edge to final location -|`br` | 1. `br