diff options
Diffstat (limited to 'Solvers')
100 files changed, 7807 insertions, 1869 deletions
diff --git a/Solvers/Alloy-Solver/hu.bme.mit.inf.dlsreasoner.alloy.reasoner/META-INF/MANIFEST.MF b/Solvers/Alloy-Solver/hu.bme.mit.inf.dlsreasoner.alloy.reasoner/META-INF/MANIFEST.MF index 87ff7abc..b944302b 100644 --- a/Solvers/Alloy-Solver/hu.bme.mit.inf.dlsreasoner.alloy.reasoner/META-INF/MANIFEST.MF +++ b/Solvers/Alloy-Solver/hu.bme.mit.inf.dlsreasoner.alloy.reasoner/META-INF/MANIFEST.MF | |||
@@ -4,22 +4,22 @@ Bundle-Name: %pluginName | |||
4 | Bundle-SymbolicName: hu.bme.mit.inf.dlsreasoner.alloy.reasoner;singleton:=true | 4 | Bundle-SymbolicName: hu.bme.mit.inf.dlsreasoner.alloy.reasoner;singleton:=true |
5 | Bundle-Version: 1.0.0.qualifier | 5 | Bundle-Version: 1.0.0.qualifier |
6 | Bundle-ClassPath: lib/alloy4.2_2015-02-22.jar, | 6 | Bundle-ClassPath: lib/alloy4.2_2015-02-22.jar, |
7 | . | 7 | . |
8 | Bundle-Vendor: %providerName | 8 | Bundle-Vendor: %providerName |
9 | Bundle-Localization: plugin | 9 | Bundle-Localization: plugin |
10 | Export-Package: hu.bme.mit.inf.dlsreasoner.alloy.reasoner, | 10 | Export-Package: hu.bme.mit.inf.dlsreasoner.alloy.reasoner, |
11 | hu.bme.mit.inf.dlsreasoner.alloy.reasoner.builder, | 11 | hu.bme.mit.inf.dlsreasoner.alloy.reasoner.builder, |
12 | hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries | 12 | hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries |
13 | Require-Bundle: com.google.guava, | 13 | Require-Bundle: com.google.guava, |
14 | org.eclipse.xtend.lib, | 14 | org.eclipse.xtend.lib, |
15 | org.eclipse.xtext.xbase.lib, | 15 | org.eclipse.xtext.xbase.lib, |
16 | org.eclipse.core.runtime, | 16 | org.eclipse.core.runtime, |
17 | org.eclipse.emf.ecore;visibility:=reexport, | 17 | org.eclipse.emf.ecore;visibility:=reexport, |
18 | hu.bme.mit.inf.dslreasoner.logic.model;bundle-version="1.0.0";visibility:=reexport, | 18 | hu.bme.mit.inf.dslreasoner.logic.model;bundle-version="1.0.0";visibility:=reexport, |
19 | hu.bme.mit.inf.dslreasoner.alloy.language;bundle-version="1.0.0", | 19 | hu.bme.mit.inf.dslreasoner.alloy.language;bundle-version="1.0.0", |
20 | org.eclipse.viatra.query.runtime.base.itc;bundle-version="1.3.0", | 20 | org.eclipse.viatra.query.runtime.base.itc;bundle-version="1.3.0", |
21 | hu.bme.mit.inf.dslreasoner.ecore2logic;bundle-version="1.0.0", | 21 | hu.bme.mit.inf.dslreasoner.ecore2logic;bundle-version="1.0.0", |
22 | org.eclipse.viatra.query.runtime;bundle-version="2.0.0" | 22 | org.eclipse.viatra.query.runtime;bundle-version="2.0.0" |
23 | Import-Package: org.apache.log4j;version="1.2.15" | 23 | Import-Package: org.apache.log4j;version="1.2.15" |
24 | Automatic-Module-Name: hu.bme.mit.inf.dlsreasoner.alloy.reasoner | 24 | Automatic-Module-Name: hu.bme.mit.inf.dlsreasoner.alloy.reasoner |
25 | Bundle-ActivationPolicy: lazy | 25 | Bundle-ActivationPolicy: lazy |
diff --git a/Solvers/Alloy-Solver/hu.bme.mit.inf.dlsreasoner.alloy.reasoner/plugin.xml b/Solvers/Alloy-Solver/hu.bme.mit.inf.dlsreasoner.alloy.reasoner/plugin.xml index 5457d70c..e57b595a 100644 --- a/Solvers/Alloy-Solver/hu.bme.mit.inf.dlsreasoner.alloy.reasoner/plugin.xml +++ b/Solvers/Alloy-Solver/hu.bme.mit.inf.dlsreasoner.alloy.reasoner/plugin.xml | |||
@@ -1,17 +1,17 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?><?eclipse version="3.0"?><!-- | 1 | <?xml version="1.0" encoding="UTF-8"?><?eclipse version="3.0"?><!-- |
2 | --><plugin> | 2 | --><plugin> |
3 | <extension id="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.SignatureQueries" point="org.eclipse.viatra.query.runtime.queryspecification"> | 3 | <extension id="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.SignatureQueries" point="org.eclipse.viatra.query.runtime.queryspecification"> |
4 | <group group="org.eclipse.viatra.query.runtime.extensibility.SingletonExtensionFactory:hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.SignatureQueries" id="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.SignatureQueries"> | 4 | <group group="org.eclipse.viatra.query.runtime.extensibility.SingletonExtensionFactory:hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.SignatureQueries" id="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.SignatureQueries"> |
5 | <query-specification fqn="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.directSubset"/> | 5 | <query-specification fqn="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.directSubset"/> |
6 | <query-specification fqn="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.subset"/> | 6 | <query-specification fqn="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.subset"/> |
7 | </group> | 7 | </group> |
8 | </extension> | 8 | </extension> |
9 | <extension id="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.TypeQueries" point="org.eclipse.viatra.query.runtime.queryspecification"> | 9 | <extension id="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.TypeQueries" point="org.eclipse.viatra.query.runtime.queryspecification"> |
10 | <group group="org.eclipse.viatra.query.runtime.extensibility.SingletonExtensionFactory:hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.TypeQueries" id="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.TypeQueries"> | 10 | <group group="org.eclipse.viatra.query.runtime.extensibility.SingletonExtensionFactory:hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.TypeQueries" id="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.TypeQueries"> |
11 | <query-specification fqn="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.supertype"/> | 11 | <query-specification fqn="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.supertype"/> |
12 | <query-specification fqn="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.topmostCommonSubtypes"/> | 12 | <query-specification fqn="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.topmostCommonSubtypes"/> |
13 | <query-specification fqn="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.lowermostCommonSupertype"/> | 13 | <query-specification fqn="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.lowermostCommonSupertype"/> |
14 | <query-specification fqn="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.lowestCommonSupertypeOfAllOccuranceOfElement"/> | 14 | <query-specification fqn="hu.bme.mit.inf.dlsreasoner.alloy.reasoner.queries.lowestCommonSupertypeOfAllOccuranceOfElement"/> |
15 | </group> | 15 | </group> |
16 | </extension> | 16 | </extension> |
17 | </plugin> | 17 | </plugin> |
diff --git a/Solvers/Alloy-Solver/hu.bme.mit.inf.dlsreasoner.alloy.reasoner/src/hu/bme/mit/inf/dlsreasoner/alloy/reasoner/AlloySolver.xtend b/Solvers/Alloy-Solver/hu.bme.mit.inf.dlsreasoner.alloy.reasoner/src/hu/bme/mit/inf/dlsreasoner/alloy/reasoner/AlloySolver.xtend index 432651af..ceb78e99 100644 --- a/Solvers/Alloy-Solver/hu.bme.mit.inf.dlsreasoner.alloy.reasoner/src/hu/bme/mit/inf/dlsreasoner/alloy/reasoner/AlloySolver.xtend +++ b/Solvers/Alloy-Solver/hu.bme.mit.inf.dlsreasoner.alloy.reasoner/src/hu/bme/mit/inf/dlsreasoner/alloy/reasoner/AlloySolver.xtend | |||
@@ -57,7 +57,7 @@ class AlloySolver extends LogicReasoner{ | |||
57 | val result2 = handler.callSolver(alloyProblem,workspace,alloyConfig,alloyCode) | 57 | val result2 = handler.callSolver(alloyProblem,workspace,alloyConfig,alloyCode) |
58 | alloyConfig.progressMonitor.workedSearchFinished | 58 | alloyConfig.progressMonitor.workedSearchFinished |
59 | 59 | ||
60 | val logicResult = backwardMapper.transformOutput(problem,configuration.solutionScope.numberOfRequiredSolution,result2,forwardTrace,transformationTime) | 60 | val logicResult = backwardMapper.transformOutput(problem,configuration.solutionScope.numberOfRequiredSolutions,result2,forwardTrace,transformationTime) |
61 | alloyConfig.progressMonitor.workedBackwardTransformationFinished | 61 | alloyConfig.progressMonitor.workedBackwardTransformationFinished |
62 | //val solverFinish = System.currentTimeMillis-solverStart | 62 | //val solverFinish = System.currentTimeMillis-solverStart |
63 | // Finish: Solving Alloy problem | 63 | // Finish: Solving Alloy problem |
diff --git a/Solvers/Alloy-Solver/hu.bme.mit.inf.dlsreasoner.alloy.reasoner/src/hu/bme/mit/inf/dlsreasoner/alloy/reasoner/builder/AlloyHandler.xtend b/Solvers/Alloy-Solver/hu.bme.mit.inf.dlsreasoner.alloy.reasoner/src/hu/bme/mit/inf/dlsreasoner/alloy/reasoner/builder/AlloyHandler.xtend index ebbca624..033ced04 100644 --- a/Solvers/Alloy-Solver/hu.bme.mit.inf.dlsreasoner.alloy.reasoner/src/hu/bme/mit/inf/dlsreasoner/alloy/reasoner/builder/AlloyHandler.xtend +++ b/Solvers/Alloy-Solver/hu.bme.mit.inf.dlsreasoner.alloy.reasoner/src/hu/bme/mit/inf/dlsreasoner/alloy/reasoner/builder/AlloyHandler.xtend | |||
@@ -184,7 +184,7 @@ class AlloyCallerWithTimeout implements Callable<List<Pair<A4Solution,Long>>>{ | |||
184 | } else { | 184 | } else { |
185 | lastAnswer = lastAnswer.next | 185 | lastAnswer = lastAnswer.next |
186 | } | 186 | } |
187 | configuration.progressMonitor.workedBackwardTransformation(configuration.solutionScope.numberOfRequiredSolution) | 187 | configuration.progressMonitor.workedBackwardTransformation(configuration.solutionScope.numberOfRequiredSolutions) |
188 | 188 | ||
189 | val runtime = System.currentTimeMillis -startTime | 189 | val runtime = System.currentTimeMillis -startTime |
190 | synchronized(this) { | 190 | synchronized(this) { |
@@ -201,8 +201,8 @@ class AlloyCallerWithTimeout implements Callable<List<Pair<A4Solution,Long>>>{ | |||
201 | } | 201 | } |
202 | 202 | ||
203 | def hasEnoughSolution(List<?> answers) { | 203 | def hasEnoughSolution(List<?> answers) { |
204 | if(configuration.solutionScope.numberOfRequiredSolution < 0) return false | 204 | if(configuration.solutionScope.numberOfRequiredSolutions < 0) return false |
205 | else return answers.size() == configuration.solutionScope.numberOfRequiredSolution | 205 | else return answers.size() == configuration.solutionScope.numberOfRequiredSolutions |
206 | } | 206 | } |
207 | 207 | ||
208 | public def getPartialAnswers() { | 208 | public def getPartialAnswers() { |
diff --git a/Solvers/Alloy-Solver/hu.bme.mit.inf.dslreasoner.alloy.language/.launch/Generate Language Infrastructure (hu.bme.mit.inf.dslreasoner.alloy.language).launch b/Solvers/Alloy-Solver/hu.bme.mit.inf.dslreasoner.alloy.language/.launch/Generate Language Infrastructure (hu.bme.mit.inf.dslreasoner.alloy.language).launch deleted file mode 100644 index 77031bf1..00000000 --- a/Solvers/Alloy-Solver/hu.bme.mit.inf.dslreasoner.alloy.language/.launch/Generate Language Infrastructure (hu.bme.mit.inf.dslreasoner.alloy.language).launch +++ /dev/null | |||
@@ -1,18 +0,0 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||
2 | <launchConfiguration type="org.eclipse.emf.mwe2.launch.Mwe2LaunchConfigurationType"> | ||
3 | <stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <launchConfigurationWorkingSet factoryID="org.eclipse.ui.internal.WorkingSetFactory" id="1299248699643_13" label="working set" name="working set"> <item factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/hu.bme.mit.inf.dslreasoner.alloy.language" type="4"/> <item factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/hu.bme.mit.inf.dslreasoner.alloy.language.generator" type="4"/> <item factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/hu.bme.mit.inf.dslreasoner.alloy.language.tests" type="4"/> <item factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/hu.bme.mit.inf.dslreasoner.alloy.language.ui" type="4"/> </launchConfigurationWorkingSet>}"/> | ||
4 | <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> | ||
5 | <listEntry value="/hu.bme.mit.inf.dslreasoner.alloy.language"/> | ||
6 | </listAttribute> | ||
7 | <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> | ||
8 | <listEntry value="4"/> | ||
9 | </listAttribute> | ||
10 | <listAttribute key="org.eclipse.debug.ui.favoriteGroups"> | ||
11 | <listEntry value="org.eclipse.debug.ui.launchGroup.debug"/> | ||
12 | <listEntry value="org.eclipse.debug.ui.launchGroup.run"/> | ||
13 | </listAttribute> | ||
14 | <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.emf.mwe2.launch.runtime.Mwe2Launcher"/> | ||
15 | <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="src/hu/bme/mit/inf/dslreasoner/GenerateAlloyLanguage.mwe2"/> | ||
16 | <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="hu.bme.mit.inf.dslreasoner.alloy.language"/> | ||
17 | <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx512m"/> | ||
18 | </launchConfiguration> | ||
diff --git a/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/.classpath b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/.classpath new file mode 100644 index 00000000..e19039ae --- /dev/null +++ b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/.classpath | |||
@@ -0,0 +1,15 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | <classpath> | ||
3 | <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"> | ||
4 | <attributes> | ||
5 | <attribute name="module" value="true"/> | ||
6 | </attributes> | ||
7 | </classpathentry> | ||
8 | <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> | ||
9 | <classpathentry kind="src" path="src"> | ||
10 | <attributes> | ||
11 | <attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="hu.bme.mit.inf.dslreasoner.ilp.cbc/lib"/> | ||
12 | </attributes> | ||
13 | </classpathentry> | ||
14 | <classpathentry kind="output" path="bin"/> | ||
15 | </classpath> | ||
diff --git a/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/.gitignore b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/.gitignore new file mode 100644 index 00000000..0cc6a59e --- /dev/null +++ b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/.gitignore | |||
@@ -0,0 +1,2 @@ | |||
1 | /bin/ | ||
2 | /cpp/build/ | ||
diff --git a/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/.project b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/.project new file mode 100644 index 00000000..6c32e464 --- /dev/null +++ b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/.project | |||
@@ -0,0 +1,28 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | <projectDescription> | ||
3 | <name>hu.bme.mit.inf.dslreasoner.ilp.cbc</name> | ||
4 | <comment></comment> | ||
5 | <projects> | ||
6 | </projects> | ||
7 | <buildSpec> | ||
8 | <buildCommand> | ||
9 | <name>org.eclipse.jdt.core.javabuilder</name> | ||
10 | <arguments> | ||
11 | </arguments> | ||
12 | </buildCommand> | ||
13 | <buildCommand> | ||
14 | <name>org.eclipse.pde.ManifestBuilder</name> | ||
15 | <arguments> | ||
16 | </arguments> | ||
17 | </buildCommand> | ||
18 | <buildCommand> | ||
19 | <name>org.eclipse.pde.SchemaBuilder</name> | ||
20 | <arguments> | ||
21 | </arguments> | ||
22 | </buildCommand> | ||
23 | </buildSpec> | ||
24 | <natures> | ||
25 | <nature>org.eclipse.pde.PluginNature</nature> | ||
26 | <nature>org.eclipse.jdt.core.javanature</nature> | ||
27 | </natures> | ||
28 | </projectDescription> | ||
diff --git a/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/META-INF/MANIFEST.MF b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/META-INF/MANIFEST.MF new file mode 100644 index 00000000..04478746 --- /dev/null +++ b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/META-INF/MANIFEST.MF | |||
@@ -0,0 +1,10 @@ | |||
1 | Manifest-Version: 1.0 | ||
2 | Bundle-ManifestVersion: 2 | ||
3 | Bundle-Name: Cbc | ||
4 | Bundle-SymbolicName: hu.bme.mit.inf.dslreasoner.ilp.cbc | ||
5 | Bundle-Version: 1.0.0.qualifier | ||
6 | Automatic-Module-Name: hu.bme.mit.inf.dslreasoner.ilp.cbc | ||
7 | Export-Package: hu.bme.mit.inf.dslreasoner.ilp.cbc | ||
8 | Bundle-NativeCode: libviatracbc.so; | ||
9 | osname=Linux; | ||
10 | processor=x86_64 | ||
diff --git a/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/build.properties b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/build.properties new file mode 100644 index 00000000..34d2e4d2 --- /dev/null +++ b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/build.properties | |||
@@ -0,0 +1,4 @@ | |||
1 | source.. = src/ | ||
2 | output.. = bin/ | ||
3 | bin.includes = META-INF/,\ | ||
4 | . | ||
diff --git a/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/cpp/CMakeLists.txt b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/cpp/CMakeLists.txt new file mode 100644 index 00000000..6169ae8f --- /dev/null +++ b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/cpp/CMakeLists.txt | |||
@@ -0,0 +1,23 @@ | |||
1 | cmake_minimum_required(VERSION 3.10.2) | ||
2 | project(hu.bme.mit.inf.dslreasoner.ilp.cbc) | ||
3 | |||
4 | set(CMAKE_CXX_STANDARD 14) | ||
5 | |||
6 | find_package(JNI REQUIRED) | ||
7 | find_package(PkgConfig REQUIRED) | ||
8 | |||
9 | pkg_check_modules(CBC REQUIRED cbc) | ||
10 | |||
11 | add_library(viatracbc SHARED viatracbc.cpp) | ||
12 | |||
13 | target_link_libraries(viatracbc | ||
14 | ${JAVA_JVM_LIBRARY} | ||
15 | ${CBC_LIBRARIES}) | ||
16 | target_include_directories(viatracbc | ||
17 | PUBLIC ${JNI_INCLUDE_DIRS} | ||
18 | PRIVATE ${CBC_INCLUDE_DIRS}) | ||
19 | |||
20 | set(VIATRACBC_NATIVES_DIR ${CMAKE_SOURCE_DIR}/../lib) | ||
21 | add_custom_command(TARGET viatracbc POST_BUILD | ||
22 | COMMAND ${CMAKE_COMMAND} -E make_directory ${VIATRACBC_NATIVES_DIR} | ||
23 | COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:viatracbc> ${VIATRACBC_NATIVES_DIR}) | ||
diff --git a/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/cpp/viatracbc.cpp b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/cpp/viatracbc.cpp new file mode 100644 index 00000000..34cab1dd --- /dev/null +++ b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/cpp/viatracbc.cpp | |||
@@ -0,0 +1,277 @@ | |||
1 | |||
2 | #include <cmath> | ||
3 | #include <cstdlib> | ||
4 | #include <iostream> | ||
5 | #include <stdexcept> | ||
6 | |||
7 | #include <jni.h> | ||
8 | |||
9 | #include "CbcBranchDefaultDecision.hpp" | ||
10 | #include "CbcCompareDefault.hpp" | ||
11 | #include "CbcHeuristic.hpp" | ||
12 | #include "CbcHeuristicLocal.hpp" | ||
13 | #include "CbcModel.hpp" | ||
14 | #include "CglClique.hpp" | ||
15 | #include "CglFlowCover.hpp" | ||
16 | #include "CglGomory.hpp" | ||
17 | #include "CglKnapsackCover.hpp" | ||
18 | #include "CglMixedIntegerRounding.hpp" | ||
19 | #include "CglOddHole.hpp" | ||
20 | #include "CglProbing.hpp" | ||
21 | #include "CoinModel.hpp" | ||
22 | #include "OsiClpSolverInterface.hpp" | ||
23 | |||
24 | #include "viatracbc.hpp" | ||
25 | |||
26 | static const char *const kCbcExceptionClassName = "hu/bme/mit/inf/dslreasoner/ilp/cbc/CbcException"; | ||
27 | static const char *const kRuntimeExceptionClassName = "java/lang/RuntimeException"; | ||
28 | |||
29 | static const jint kCbcSolutionBounded = 0; | ||
30 | static const jint kCbcSolutionUnbounded = 1; | ||
31 | static const jint kCbcUnsat = 2; | ||
32 | static const jint kCbcAbandoned = 3; | ||
33 | static const jint kCbcTimeout = 4; | ||
34 | static const jint kCbcError = 5; | ||
35 | |||
36 | static CoinModel CreateModel(JNIEnv *env, jdoubleArray columnLowerBoundsArray, | ||
37 | jdoubleArray columnUpperBoundsArray, jintArray rowStartsArray, jintArray columnIndicesArray, | ||
38 | jdoubleArray entriedArray, jdoubleArray rowLowerBoundsArray, jdoubleArray rowUpperBoundsArray, | ||
39 | jdoubleArray objectiveArray, jboolean lpRelaxation); | ||
40 | static void CreateModelColumns(JNIEnv *env, jdoubleArray columnLowerBoundsArray, | ||
41 | jdoubleArray columnUpperBoundsArray, jdoubleArray objectiveArray, jboolean lpRelaxation, | ||
42 | CoinModel &build); | ||
43 | static void CreateModelRows(JNIEnv *env, jintArray rowStartsArray, jintArray columnIndicesArray, | ||
44 | jdoubleArray entriesArray, jdoubleArray rowLowerBoundsArray, jdoubleArray rowUpperBoundsArray, | ||
45 | CoinModel &build); | ||
46 | static jint SolveModel(CoinModel &build, jdouble timeoutSeconds, jboolean silent, jdouble &value); | ||
47 | static void ThrowException(JNIEnv *env, const char *message); | ||
48 | |||
49 | template < | ||
50 | typename Array, | ||
51 | typename Element, | ||
52 | Element *(JNIEnv::*GetElementsPtr)(Array, jboolean *), | ||
53 | void (JNIEnv::*ReleaseElementsPtr)(Array, Element *, jint) | ||
54 | > | ||
55 | class PinnedArray { | ||
56 | public: | ||
57 | PinnedArray(JNIEnv *env, Array array) | ||
58 | : env_{env}, array_{array}, elements_{(env->*GetElementsPtr)(array, nullptr)} { | ||
59 | if (elements_ == nullptr) { | ||
60 | throw std::runtime_error("Failed to pin array elements"); | ||
61 | } | ||
62 | } | ||
63 | PinnedArray(const PinnedArray &) = delete; | ||
64 | PinnedArray(PinnedArray &&) = delete; | ||
65 | PinnedArray &operator=(const PinnedArray &) = delete; | ||
66 | PinnedArray &operator=(PinnedArray &&) = delete; | ||
67 | ~PinnedArray() { | ||
68 | (env_->*ReleaseElementsPtr)(array_, elements_, 0); | ||
69 | } | ||
70 | |||
71 | operator Element *() { return elements_; } | ||
72 | operator const Element *() const { return elements_; } | ||
73 | |||
74 | private: | ||
75 | JNIEnv *env_; | ||
76 | Array array_; | ||
77 | Element *elements_; | ||
78 | }; | ||
79 | |||
80 | using PinnedIntArray = PinnedArray<jintArray, jint, &JNIEnv::GetIntArrayElements, &JNIEnv::ReleaseIntArrayElements>; | ||
81 | using PinnedDoubleArray = PinnedArray<jdoubleArray, jdouble, &JNIEnv::GetDoubleArrayElements, &JNIEnv::ReleaseDoubleArrayElements>; | ||
82 | |||
83 | jint Java_hu_bme_mit_inf_dslreasoner_ilp_cbc_CbcSolver_solveIlpProblem( | ||
84 | JNIEnv *env, jclass klazz, jdoubleArray columnLowerBoundsArray, jdoubleArray columnUpperBoundsArray, | ||
85 | jintArray rowStartsArray, jintArray columnIndicesArray, jdoubleArray entriesArray, | ||
86 | jdoubleArray rowLowerBoundsArray, jdoubleArray rowUpperBoundsArray, jdoubleArray objectiveArray, | ||
87 | jdoubleArray outputArray, jboolean lpRelaxation, jdouble timeoutSeconds, jboolean silent) { | ||
88 | try { | ||
89 | auto build = CreateModel(env, columnLowerBoundsArray, columnUpperBoundsArray, | ||
90 | rowStartsArray, columnIndicesArray, entriesArray, rowLowerBoundsArray, rowUpperBoundsArray, | ||
91 | objectiveArray, lpRelaxation); | ||
92 | double value; | ||
93 | jint result = SolveModel(build, timeoutSeconds, silent, value); | ||
94 | if (result == kCbcSolutionBounded) { | ||
95 | PinnedDoubleArray output{env, outputArray}; | ||
96 | *output = value; | ||
97 | } | ||
98 | return result; | ||
99 | } catch (const std::exception &e) { | ||
100 | ThrowException(env, e.what()); | ||
101 | } catch (...) { | ||
102 | ThrowException(env, "Unknown solver error"); | ||
103 | } | ||
104 | return kCbcError; | ||
105 | } | ||
106 | |||
107 | CoinModel CreateModel(JNIEnv *env, jdoubleArray columnLowerBoundsArray, | ||
108 | jdoubleArray columnUpperBoundsArray, jintArray rowStartsArray, jintArray columnIndicesArray, | ||
109 | jdoubleArray entriesArray, jdoubleArray rowLowerBoundsArray, jdoubleArray rowUpperBoundsArray, | ||
110 | jdoubleArray objectiveArray, jboolean lpRelaxation) { | ||
111 | CoinModel build; | ||
112 | CreateModelColumns(env, columnLowerBoundsArray, columnUpperBoundsArray, objectiveArray, | ||
113 | lpRelaxation, build); | ||
114 | CreateModelRows(env, rowStartsArray, columnIndicesArray, entriesArray, rowLowerBoundsArray, | ||
115 | rowUpperBoundsArray, build); | ||
116 | return build; | ||
117 | } | ||
118 | |||
119 | void CreateModelColumns(JNIEnv *env, jdoubleArray columnLowerBoundsArray, | ||
120 | jdoubleArray columnUpperBoundsArray, jdoubleArray objectiveArray, jboolean lpRelaxation, | ||
121 | CoinModel &build) { | ||
122 | int numColumns = env->GetArrayLength(columnLowerBoundsArray); | ||
123 | PinnedDoubleArray columnLowerBounds{env, columnLowerBoundsArray}; | ||
124 | PinnedDoubleArray columnUpperBounds{env, columnUpperBoundsArray}; | ||
125 | PinnedDoubleArray objective{env, objectiveArray}; | ||
126 | for (int i = 0; i < numColumns; i++) { | ||
127 | build.setColumnBounds(i, columnLowerBounds[i], columnUpperBounds[i]); | ||
128 | build.setObjective(i, objective[i]); | ||
129 | if (!lpRelaxation) { | ||
130 | build.setInteger(i); | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
135 | void CreateModelRows(JNIEnv *env, jintArray rowStartsArray, jintArray columnIndicesArray, | ||
136 | jdoubleArray entriesArray, jdoubleArray rowLowerBoundsArray, jdoubleArray rowUpperBoundsArray, | ||
137 | CoinModel &build) { | ||
138 | int numRows = env->GetArrayLength(rowLowerBoundsArray); | ||
139 | PinnedIntArray rowStarts{env, rowStartsArray}; | ||
140 | PinnedIntArray columnIndices{env, columnIndicesArray}; | ||
141 | PinnedDoubleArray entries{env, entriesArray}; | ||
142 | PinnedDoubleArray rowLowerBounds{env, rowLowerBoundsArray}; | ||
143 | PinnedDoubleArray rowUpperBounds{env, rowUpperBoundsArray}; | ||
144 | for (int i = 0; i < numRows; i++) { | ||
145 | int rowStart = rowStarts[i]; | ||
146 | int numbersInRow = rowStarts[i + 1] - rowStart; | ||
147 | build.addRow(numbersInRow, &columnIndices[rowStart], &entries[rowStart], | ||
148 | rowLowerBounds[i], rowUpperBounds[i]); | ||
149 | } | ||
150 | } | ||
151 | |||
152 | jint SolveModel(CoinModel &build, jdouble timeoutSeconds, jboolean silent, jdouble &value) { | ||
153 | OsiClpSolverInterface solver; | ||
154 | solver.loadFromCoinModel(build); | ||
155 | CbcModel model{solver}; | ||
156 | |||
157 | if (timeoutSeconds >= 0) { | ||
158 | model.setDblParam(CbcModel::CbcMaximumSeconds, timeoutSeconds); | ||
159 | } | ||
160 | if (silent == JNI_FALSE) { | ||
161 | model.messageHandler()->setLogLevel(2); | ||
162 | model.solver()->messageHandler()->setLogLevel(1); | ||
163 | } else { | ||
164 | model.solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry); | ||
165 | model.messageHandler()->setLogLevel(0); | ||
166 | model.solver()->messageHandler()->setLogLevel(0); | ||
167 | } | ||
168 | |||
169 | // Cut generators and heuristics are used according to | ||
170 | // https://github.com/coin-or/Cbc/blob/6b977b6707f1755520c64fea57b95891c1f3ddc0/Cbc/examples/sample2.cpp | ||
171 | |||
172 | CglProbing probing; | ||
173 | probing.setUsingObjective(true); | ||
174 | probing.setMaxPass(1); | ||
175 | probing.setMaxPassRoot(5); | ||
176 | probing.setMaxProbe(10); | ||
177 | probing.setMaxProbeRoot(1000); | ||
178 | probing.setMaxLook(50); | ||
179 | probing.setMaxLookRoot(500); | ||
180 | probing.setMaxElements(200); | ||
181 | probing.setRowCuts(3); | ||
182 | model.addCutGenerator(&probing, -1, "Probing"); | ||
183 | |||
184 | CglGomory gomory; | ||
185 | gomory.setLimit(300); | ||
186 | model.addCutGenerator(&gomory, -1, "Gomory"); | ||
187 | |||
188 | CglKnapsackCover knapsackCover; | ||
189 | model.addCutGenerator(&knapsackCover, -1, "KnapsackCover"); | ||
190 | |||
191 | CglClique clique; | ||
192 | clique.setStarCliqueReport(false); | ||
193 | clique.setRowCliqueReport(false); | ||
194 | model.addCutGenerator(&clique, -1, "Clique"); | ||
195 | |||
196 | CglFlowCover flowCover; | ||
197 | model.addCutGenerator(&flowCover, -1, "FlowCover"); | ||
198 | |||
199 | CglMixedIntegerRounding mixedIntegerRounding; | ||
200 | model.addCutGenerator(&mixedIntegerRounding, -1, "MixedIntegerRounding"); | ||
201 | |||
202 | OsiClpSolverInterface *osiClp = dynamic_cast<OsiClpSolverInterface *>(model.solver()); | ||
203 | if (osiClp != nullptr) { | ||
204 | osiClp->setSpecialOptions(128); | ||
205 | osiClp->setupForRepeatedUse(0, 0); | ||
206 | } | ||
207 | |||
208 | CbcRounding rounding; | ||
209 | model.addHeuristic(&rounding); | ||
210 | |||
211 | CbcHeuristicLocal localHeuristic; | ||
212 | model.addHeuristic(&localHeuristic); | ||
213 | |||
214 | CbcBranchDefaultDecision branchDecision; | ||
215 | model.setBranchingMethod(&branchDecision); | ||
216 | |||
217 | CbcCompareDefault nodeComparison; | ||
218 | model.setNodeComparison(nodeComparison); | ||
219 | |||
220 | model.initialSolve(); | ||
221 | |||
222 | if (model.isInitialSolveProvenPrimalInfeasible()) { | ||
223 | return kCbcUnsat; | ||
224 | } | ||
225 | if (model.isInitialSolveProvenDualInfeasible()) { | ||
226 | return kCbcSolutionUnbounded; | ||
227 | } | ||
228 | if (model.isInitialSolveAbandoned()) { | ||
229 | return kCbcTimeout; | ||
230 | } | ||
231 | |||
232 | model.setMinimumDrop(CoinMin(1.0, fabs(model.getMinimizationObjValue()) * 1.0e-3 + 1.0e-4)); | ||
233 | model.setMaximumCutPassesAtRoot(-100); | ||
234 | model.setNumberStrong(10); | ||
235 | model.solver()->setIntParam(OsiMaxNumIterationHotStart, 100); | ||
236 | |||
237 | model.branchAndBound(); | ||
238 | |||
239 | switch (model.status()) { | ||
240 | case 0: | ||
241 | if (model.isProvenInfeasible()) { | ||
242 | return kCbcUnsat; | ||
243 | } | ||
244 | if (model.isProvenDualInfeasible()) { | ||
245 | return kCbcSolutionUnbounded; | ||
246 | } | ||
247 | if (model.isProvenOptimal()) { | ||
248 | value = model.getMinimizationObjValue(); | ||
249 | return kCbcSolutionBounded; | ||
250 | } | ||
251 | throw std::runtime_error("CBC status is 0, but no solution is found"); | ||
252 | case 1: | ||
253 | return kCbcTimeout; | ||
254 | case 2: | ||
255 | return kCbcAbandoned; | ||
256 | default: | ||
257 | throw std::runtime_error("Unknown CBC status"); | ||
258 | } | ||
259 | } | ||
260 | |||
261 | void ThrowException(JNIEnv *env, const char *message) { | ||
262 | jclass exceptionClass = env->FindClass(kCbcExceptionClassName); | ||
263 | if (exceptionClass == nullptr) { | ||
264 | std::cerr << "WARNING: " << kCbcExceptionClassName << " class was not found" << std::endl; | ||
265 | exceptionClass = env->FindClass(kRuntimeExceptionClassName); | ||
266 | if (exceptionClass == nullptr) { | ||
267 | std::cerr << "FATAL: " << kRuntimeExceptionClassName << " class was not found" << std::endl; | ||
268 | std::cerr << "FATAL: " << message << std::endl; | ||
269 | std::exit(EXIT_FAILURE); | ||
270 | } | ||
271 | } | ||
272 | if (env->ThrowNew(exceptionClass, message) < 0) { | ||
273 | std::cerr << "FATAL: Could not throw java exception" << std::endl; | ||
274 | std::cerr << "FATAL: " << message << std::endl; | ||
275 | std::exit(EXIT_FAILURE); | ||
276 | } | ||
277 | } | ||
diff --git a/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/cpp/viatracbc.hpp b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/cpp/viatracbc.hpp new file mode 100644 index 00000000..12198c8b --- /dev/null +++ b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/cpp/viatracbc.hpp | |||
@@ -0,0 +1,16 @@ | |||
1 | #ifndef HU_BME_MIT_INF_DSLREASONER_ILP_CBC_ | ||
2 | #define HU_BME_MIT_INF_DSLREASONER_ILP_CBC_ | ||
3 | |||
4 | #include <jni.h> | ||
5 | |||
6 | extern "C" { | ||
7 | |||
8 | JNIEXPORT jint JNICALL Java_hu_bme_mit_inf_dslreasoner_ilp_cbc_CbcSolver_solveIlpProblem( | ||
9 | JNIEnv *env, jclass klazz, jdoubleArray columnLowerBoundsArray, jdoubleArray columnUpperBoundsArray, | ||
10 | jintArray rowStartsArray, jintArray columnIndicesArray, jdoubleArray entriesArray, | ||
11 | jdoubleArray rowLowerBoundsArray, jdoubleArray rowUpperBoundsArray, jdoubleArray objectiveArray, | ||
12 | jdoubleArray outputArray, jboolean lpRelaxation, jdouble timeoutSeconds, jboolean silent); | ||
13 | |||
14 | } | ||
15 | |||
16 | #endif // HU_BME_MIT_INF_DSLREASONER_ILP_CBC_ | ||
diff --git a/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/lib/libviatracbc.so b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/lib/libviatracbc.so new file mode 100755 index 00000000..96289216 --- /dev/null +++ b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/lib/libviatracbc.so | |||
Binary files differ | |||
diff --git a/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/src/hu/bme/mit/inf/dslreasoner/ilp/cbc/CbcException.java b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/src/hu/bme/mit/inf/dslreasoner/ilp/cbc/CbcException.java new file mode 100644 index 00000000..26846958 --- /dev/null +++ b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/src/hu/bme/mit/inf/dslreasoner/ilp/cbc/CbcException.java | |||
@@ -0,0 +1,30 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.ilp.cbc; | ||
2 | |||
3 | public class CbcException extends RuntimeException { | ||
4 | |||
5 | /** | ||
6 | * | ||
7 | */ | ||
8 | private static final long serialVersionUID = 2691773509078511887L; | ||
9 | |||
10 | public CbcException() { | ||
11 | super(); | ||
12 | } | ||
13 | |||
14 | public CbcException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { | ||
15 | super(message, cause, enableSuppression, writableStackTrace); | ||
16 | } | ||
17 | |||
18 | public CbcException(String message, Throwable cause) { | ||
19 | super(message, cause); | ||
20 | } | ||
21 | |||
22 | public CbcException(String message) { | ||
23 | super(message); | ||
24 | } | ||
25 | |||
26 | public CbcException(Throwable cause) { | ||
27 | super(cause); | ||
28 | } | ||
29 | |||
30 | } | ||
diff --git a/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/src/hu/bme/mit/inf/dslreasoner/ilp/cbc/CbcResult.java b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/src/hu/bme/mit/inf/dslreasoner/ilp/cbc/CbcResult.java new file mode 100644 index 00000000..dae3a447 --- /dev/null +++ b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/src/hu/bme/mit/inf/dslreasoner/ilp/cbc/CbcResult.java | |||
@@ -0,0 +1,54 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.ilp.cbc; | ||
2 | |||
3 | public abstract class CbcResult { | ||
4 | public static final CbcResult SOLUTION_UNBOUNDED = new CbcResult() { | ||
5 | }; | ||
6 | |||
7 | public static final CbcResult UNSAT = new CbcResult() { | ||
8 | }; | ||
9 | |||
10 | public static final CbcResult ABANDONED = new CbcResult() { | ||
11 | }; | ||
12 | |||
13 | public static final CbcResult TIMEOUT = new CbcResult() { | ||
14 | }; | ||
15 | |||
16 | private CbcResult() { | ||
17 | } | ||
18 | |||
19 | public static class SolutionBounded extends CbcResult { | ||
20 | public final double value; | ||
21 | |||
22 | public SolutionBounded(double value) { | ||
23 | this.value = value; | ||
24 | } | ||
25 | |||
26 | public double getValue() { | ||
27 | return value; | ||
28 | } | ||
29 | |||
30 | @Override | ||
31 | public int hashCode() { | ||
32 | final int prime = 31; | ||
33 | int result = 1; | ||
34 | long temp; | ||
35 | temp = Double.doubleToLongBits(value); | ||
36 | result = prime * result + (int) (temp ^ (temp >>> 32)); | ||
37 | return result; | ||
38 | } | ||
39 | |||
40 | @Override | ||
41 | public boolean equals(Object obj) { | ||
42 | if (this == obj) | ||
43 | return true; | ||
44 | if (obj == null) | ||
45 | return false; | ||
46 | if (getClass() != obj.getClass()) | ||
47 | return false; | ||
48 | SolutionBounded other = (SolutionBounded) obj; | ||
49 | if (Double.doubleToLongBits(value) != Double.doubleToLongBits(other.value)) | ||
50 | return false; | ||
51 | return true; | ||
52 | } | ||
53 | } | ||
54 | } | ||
diff --git a/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/src/hu/bme/mit/inf/dslreasoner/ilp/cbc/CbcSolver.java b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/src/hu/bme/mit/inf/dslreasoner/ilp/cbc/CbcSolver.java new file mode 100644 index 00000000..085d4448 --- /dev/null +++ b/Solvers/ILP-Solver/hu.bme.mit.inf.dslreasoner.ilp.cbc/src/hu/bme/mit/inf/dslreasoner/ilp/cbc/CbcSolver.java | |||
@@ -0,0 +1,71 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.ilp.cbc; | ||
2 | |||
3 | public class CbcSolver { | ||
4 | private static int CBC_SOLUTION_BOUNDED = 0; | ||
5 | private static int CBC_SOLUTION_UNBOUNDED = 1; | ||
6 | private static int CBC_UNSAT = 2; | ||
7 | private static int CBC_ABANDONED = 3; | ||
8 | private static int CBC_TIMEOUT = 4; | ||
9 | private static int CBC_ERROR = 5; | ||
10 | |||
11 | private static boolean nativesLoaded = false; | ||
12 | |||
13 | private CbcSolver() { | ||
14 | throw new IllegalStateException("This is a static utility class and should not be instantiated directly."); | ||
15 | } | ||
16 | |||
17 | public static CbcResult solve(double[] columnLowerBounds, double[] columnUpperBounds, int[] rowStarts, | ||
18 | int[] columnIndices, double[] entries, double[] rowLowerBounds, double[] rowUpperBounds, double[] objective, | ||
19 | boolean lpRelaxation, double timeoutSeconds, boolean silent) { | ||
20 | loadNatives(); | ||
21 | validate(columnLowerBounds, columnUpperBounds, rowStarts, columnIndices, entries, rowLowerBounds, | ||
22 | rowUpperBounds, objective); | ||
23 | double[] output = new double[1]; | ||
24 | int result = solveIlpProblem(columnLowerBounds, columnUpperBounds, rowStarts, columnIndices, entries, | ||
25 | rowLowerBounds, rowUpperBounds, objective, output, lpRelaxation, timeoutSeconds, silent); | ||
26 | if (result == CBC_SOLUTION_BOUNDED) { | ||
27 | return new CbcResult.SolutionBounded(output[0]); | ||
28 | } else if (result == CBC_SOLUTION_UNBOUNDED) { | ||
29 | return CbcResult.SOLUTION_UNBOUNDED; | ||
30 | } else if (result == CBC_UNSAT) { | ||
31 | return CbcResult.UNSAT; | ||
32 | } else if (result == CBC_ABANDONED) { | ||
33 | return CbcResult.ABANDONED; | ||
34 | } else if (result == CBC_TIMEOUT) { | ||
35 | return CbcResult.TIMEOUT; | ||
36 | } else if (result == CBC_ERROR) { | ||
37 | throw new CbcException("Solver signalled error, but no exception was thrown"); | ||
38 | } else { | ||
39 | throw new CbcException("Unknown return value: " + result); | ||
40 | } | ||
41 | } | ||
42 | |||
43 | private static void loadNatives() { | ||
44 | if (!nativesLoaded) { | ||
45 | synchronized (CbcSolver.class) { | ||
46 | System.loadLibrary("viatracbc"); | ||
47 | nativesLoaded = true; | ||
48 | } | ||
49 | } | ||
50 | } | ||
51 | |||
52 | private static void validate(double[] columnLowerBounds, double[] columnUpperBounds, int[] rowStarts, | ||
53 | int[] columnIndices, double[] entries, double[] rowLowerBounds, double[] rowUpperBounds, | ||
54 | double[] objective) { | ||
55 | int numColumns = columnLowerBounds.length; | ||
56 | if (columnUpperBounds.length != numColumns) { | ||
57 | throw new CbcException("Lengths of columnLowerBounds and columnUpperBounds must match"); | ||
58 | } | ||
59 | if (objective.length != numColumns) { | ||
60 | throw new CbcException("Lengths of columnLowerBounds and objective must match"); | ||
61 | } | ||
62 | int numRows = rowLowerBounds.length; | ||
63 | if (rowUpperBounds.length != numRows) { | ||
64 | throw new CbcException("Lengths of rowLowerBounds and rowUpperBounds must match"); | ||
65 | } | ||
66 | } | ||
67 | |||
68 | private static native int solveIlpProblem(double[] columnLowerBounds, double[] columnUpperBounds, int[] rowStarts, | ||
69 | int[] columnIndices, double[] entries, double[] rowLowerBounds, double[] rowUpperBounds, double[] objective, | ||
70 | double[] output, boolean lpRelaxation, double timeoutSeconds, boolean silent); | ||
71 | } | ||
diff --git a/Solvers/SMT-Solver/com.microsoft.z3/.classpath b/Solvers/SMT-Solver/com.microsoft.z3/.classpath new file mode 100644 index 00000000..ffdc022a --- /dev/null +++ b/Solvers/SMT-Solver/com.microsoft.z3/.classpath | |||
@@ -0,0 +1,15 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | <classpath> | ||
3 | <classpathentry exported="true" kind="lib" path="com.microsoft.z3.jar"> | ||
4 | <attributes> | ||
5 | <attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="com.microsoft.z3/lib"/> | ||
6 | </attributes> | ||
7 | </classpathentry> | ||
8 | <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"> | ||
9 | <attributes> | ||
10 | <attribute name="module" value="true"/> | ||
11 | </attributes> | ||
12 | </classpathentry> | ||
13 | <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> | ||
14 | <classpathentry kind="output" path="bin"/> | ||
15 | </classpath> | ||
diff --git a/Solvers/SMT-Solver/com.microsoft.z3/.gitignore b/Solvers/SMT-Solver/com.microsoft.z3/.gitignore new file mode 100644 index 00000000..ae3c1726 --- /dev/null +++ b/Solvers/SMT-Solver/com.microsoft.z3/.gitignore | |||
@@ -0,0 +1 @@ | |||
/bin/ | |||
diff --git a/Solvers/SMT-Solver/com.microsoft.z3/.project b/Solvers/SMT-Solver/com.microsoft.z3/.project new file mode 100644 index 00000000..ec5bbc58 --- /dev/null +++ b/Solvers/SMT-Solver/com.microsoft.z3/.project | |||
@@ -0,0 +1,28 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | <projectDescription> | ||
3 | <name>com.microsoft.z3</name> | ||
4 | <comment></comment> | ||
5 | <projects> | ||
6 | </projects> | ||
7 | <buildSpec> | ||
8 | <buildCommand> | ||
9 | <name>org.eclipse.jdt.core.javabuilder</name> | ||
10 | <arguments> | ||
11 | </arguments> | ||
12 | </buildCommand> | ||
13 | <buildCommand> | ||
14 | <name>org.eclipse.pde.ManifestBuilder</name> | ||
15 | <arguments> | ||
16 | </arguments> | ||
17 | </buildCommand> | ||
18 | <buildCommand> | ||
19 | <name>org.eclipse.pde.SchemaBuilder</name> | ||
20 | <arguments> | ||
21 | </arguments> | ||
22 | </buildCommand> | ||
23 | </buildSpec> | ||
24 | <natures> | ||
25 | <nature>org.eclipse.pde.PluginNature</nature> | ||
26 | <nature>org.eclipse.jdt.core.javanature</nature> | ||
27 | </natures> | ||
28 | </projectDescription> | ||
diff --git a/Solvers/SMT-Solver/com.microsoft.z3/META-INF/MANIFEST.MF b/Solvers/SMT-Solver/com.microsoft.z3/META-INF/MANIFEST.MF new file mode 100644 index 00000000..401fa6cf --- /dev/null +++ b/Solvers/SMT-Solver/com.microsoft.z3/META-INF/MANIFEST.MF | |||
@@ -0,0 +1,22 @@ | |||
1 | Manifest-Version: 1.0 | ||
2 | Bundle-ManifestVersion: 2 | ||
3 | Bundle-Name: Z3 | ||
4 | Bundle-SymbolicName: com.microsoft.z3 | ||
5 | Bundle-Version: 4.8.5.qualifier | ||
6 | Bundle-Vendor: Microsoft | ||
7 | Automatic-Module-Name: com.microsoft.z3 | ||
8 | Bundle-ClassPath: com.microsoft.z3.jar | ||
9 | Bundle-NativeCode: lib/libz3.so; | ||
10 | lib/libz3java.so; | ||
11 | osname=Linux; | ||
12 | processor=x86_64, | ||
13 | lib/libz3.dylib; | ||
14 | lib/libz3java.dylib; | ||
15 | osname=MacOSX; | ||
16 | processor=x86_64, | ||
17 | lib/libz3.dll; | ||
18 | lib/libz3java.dll; | ||
19 | osname=win32; | ||
20 | processor=x86_64 | ||
21 | Export-Package: com.microsoft.z3, | ||
22 | com.microsoft.z3.enumerations | ||
diff --git a/Solvers/SMT-Solver/com.microsoft.z3/build.properties b/Solvers/SMT-Solver/com.microsoft.z3/build.properties new file mode 100644 index 00000000..87f4e73f --- /dev/null +++ b/Solvers/SMT-Solver/com.microsoft.z3/build.properties | |||
@@ -0,0 +1,3 @@ | |||
1 | bin.includes = META-INF/,\ | ||
2 | lib/,\ | ||
3 | com.microsoft.z3.jar | ||
diff --git a/Solvers/SMT-Solver/com.microsoft.z3/lib/libz3.dll b/Solvers/SMT-Solver/com.microsoft.z3/lib/libz3.dll new file mode 100644 index 00000000..0b518988 --- /dev/null +++ b/Solvers/SMT-Solver/com.microsoft.z3/lib/libz3.dll | |||
Binary files differ | |||
diff --git a/Solvers/SMT-Solver/com.microsoft.z3/lib/libz3.dylib b/Solvers/SMT-Solver/com.microsoft.z3/lib/libz3.dylib new file mode 100755 index 00000000..7884a0e7 --- /dev/null +++ b/Solvers/SMT-Solver/com.microsoft.z3/lib/libz3.dylib | |||
Binary files differ | |||
diff --git a/Solvers/SMT-Solver/com.microsoft.z3/lib/libz3.so b/Solvers/SMT-Solver/com.microsoft.z3/lib/libz3.so new file mode 100755 index 00000000..5beffe36 --- /dev/null +++ b/Solvers/SMT-Solver/com.microsoft.z3/lib/libz3.so | |||
Binary files differ | |||
diff --git a/Solvers/SMT-Solver/com.microsoft.z3/lib/libz3java.dll b/Solvers/SMT-Solver/com.microsoft.z3/lib/libz3java.dll new file mode 100644 index 00000000..5e8dbc9b --- /dev/null +++ b/Solvers/SMT-Solver/com.microsoft.z3/lib/libz3java.dll | |||
Binary files differ | |||
diff --git a/Solvers/SMT-Solver/com.microsoft.z3/lib/libz3java.dylib b/Solvers/SMT-Solver/com.microsoft.z3/lib/libz3java.dylib new file mode 100755 index 00000000..2d9116ac --- /dev/null +++ b/Solvers/SMT-Solver/com.microsoft.z3/lib/libz3java.dylib | |||
Binary files differ | |||
diff --git a/Solvers/SMT-Solver/com.microsoft.z3/lib/libz3java.so b/Solvers/SMT-Solver/com.microsoft.z3/lib/libz3java.so new file mode 100755 index 00000000..e2d2618d --- /dev/null +++ b/Solvers/SMT-Solver/com.microsoft.z3/lib/libz3java.so | |||
Binary files differ | |||
diff --git a/Solvers/SMT-Solver/hu.bme.mit.inf.dslreasoner.smt.language/.launch/Generate Language Infrastructure (hu.bme.mit.inf.dslreasoner.smt.language).launch b/Solvers/SMT-Solver/hu.bme.mit.inf.dslreasoner.smt.language/.launch/Generate Language Infrastructure (hu.bme.mit.inf.dslreasoner.smt.language).launch deleted file mode 100644 index e448edbe..00000000 --- a/Solvers/SMT-Solver/hu.bme.mit.inf.dslreasoner.smt.language/.launch/Generate Language Infrastructure (hu.bme.mit.inf.dslreasoner.smt.language).launch +++ /dev/null | |||
@@ -1,17 +0,0 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||
2 | <launchConfiguration type="org.eclipse.emf.mwe2.launch.Mwe2LaunchConfigurationType"> | ||
3 | <stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <launchConfigurationWorkingSet factoryID="org.eclipse.ui.internal.WorkingSetFactory" id="1299248699643_13" label="working set" name="working set"> <item factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/hu.bme.mit.inf.dslreasoner.smt.language" type="4"/> <item factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/hu.bme.mit.inf.dslreasoner.smt.language.generator" type="4"/> <item factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/hu.bme.mit.inf.dslreasoner.smt.language.tests" type="4"/> <item factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/hu.bme.mit.inf.dslreasoner.smt.language.ui" type="4"/> </launchConfigurationWorkingSet>}"/> | ||
4 | <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> | ||
5 | <listEntry value="/hu.bme.mit.inf.dslreasoner.smt.language"/> | ||
6 | </listAttribute> | ||
7 | <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> | ||
8 | <listEntry value="4"/> | ||
9 | </listAttribute> | ||
10 | <listAttribute key="org.eclipse.debug.ui.favoriteGroups"> | ||
11 | <listEntry value="org.eclipse.debug.ui.launchGroup.run"/> | ||
12 | </listAttribute> | ||
13 | <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.emf.mwe2.launch.runtime.Mwe2Launcher"/> | ||
14 | <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="src/hu/bme/mit/inf/dslreasoner/GenerateSmtLanguage.mwe2"/> | ||
15 | <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="hu.bme.mit.inf.dslreasoner.smt.language"/> | ||
16 | <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx512m"/> | ||
17 | </launchConfiguration> | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/META-INF/MANIFEST.MF b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/META-INF/MANIFEST.MF index 23e3ad13..f9090901 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/META-INF/MANIFEST.MF +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/META-INF/MANIFEST.MF | |||
@@ -4,6 +4,9 @@ Bundle-Name: Logic2viatra | |||
4 | Bundle-SymbolicName: hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatraquery;singleton:=true | 4 | Bundle-SymbolicName: hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatraquery;singleton:=true |
5 | Bundle-Version: 1.0.0.qualifier | 5 | Bundle-Version: 1.0.0.qualifier |
6 | Export-Package: hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra, | 6 | Export-Package: hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra, |
7 | hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality, | ||
8 | hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.interval, | ||
9 | hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.interval.aggregators, | ||
7 | hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns, | 10 | hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns, |
8 | hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries | 11 | hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries |
9 | Require-Bundle: hu.bme.mit.inf.dslreasoner.logic.model;bundle-version="1.0.0", | 12 | Require-Bundle: hu.bme.mit.inf.dslreasoner.logic.model;bundle-version="1.0.0", |
@@ -20,7 +23,9 @@ Require-Bundle: hu.bme.mit.inf.dslreasoner.logic.model;bundle-version="1.0.0", | |||
20 | com.google.inject;bundle-version="3.0.0", | 23 | com.google.inject;bundle-version="3.0.0", |
21 | org.eclipse.xtext;bundle-version="2.10.0", | 24 | org.eclipse.xtext;bundle-version="2.10.0", |
22 | org.eclipse.viatra.transformation.runtime.emf;bundle-version="1.5.0", | 25 | org.eclipse.viatra.transformation.runtime.emf;bundle-version="1.5.0", |
23 | org.eclipse.xtext.xbase;bundle-version="2.10.0" | 26 | org.eclipse.xtext.xbase;bundle-version="2.10.0", |
27 | com.microsoft.z3;bundle-version="4.8.5", | ||
28 | hu.bme.mit.inf.dslreasoner.ilp.cbc;bundle-version="1.0.0" | ||
24 | Bundle-RequiredExecutionEnvironment: JavaSE-1.8 | 29 | Bundle-RequiredExecutionEnvironment: JavaSE-1.8 |
25 | Import-Package: org.apache.log4j | 30 | Import-Package: org.apache.log4j |
26 | Automatic-Module-Name: hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatraquery | 31 | Automatic-Module-Name: hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatraquery |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/build.properties b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/build.properties index 585df5ce..9ffc994a 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/build.properties +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/build.properties | |||
@@ -4,6 +4,5 @@ bin.includes = META-INF/,\ | |||
4 | source.. = src/,\ | 4 | source.. = src/,\ |
5 | patterns/,\ | 5 | patterns/,\ |
6 | vql-gen/,\ | 6 | vql-gen/,\ |
7 | xtend-gen/,\ | 7 | xtend-gen/ |
8 | src-gen/ | ||
9 | output.. = bin/ | 8 | output.. = bin/ |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/plugin.xml b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/plugin.xml index 05e00983..6e4d96ca 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/plugin.xml +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/plugin.xml | |||
@@ -1,14 +1,14 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?><plugin> | 1 | <?xml version="1.0" encoding="UTF-8"?><plugin> |
2 | <extension id="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.TypeAnalysis" point="org.eclipse.viatra.query.runtime.queryspecification"> | 2 | <extension id="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.TypeAnalysis" point="org.eclipse.viatra.query.runtime.queryspecification"> |
3 | <group group="org.eclipse.viatra.query.runtime.extensibility.SingletonExtensionFactory:hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.TypeAnalysis" id="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.TypeAnalysis"> | 3 | <group group="org.eclipse.viatra.query.runtime.extensibility.SingletonExtensionFactory:hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.TypeAnalysis" id="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.TypeAnalysis"> |
4 | <query-specification fqn="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.hasDefinedSupertype"/> | 4 | <query-specification fqn="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.hasDefinedSupertype"/> |
5 | <query-specification fqn="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.dontHaveDefinedSupertype"/> | 5 | <query-specification fqn="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.dontHaveDefinedSupertype"/> |
6 | <query-specification fqn="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.newElementTypeConstructor"/> | 6 | <query-specification fqn="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.newElementTypeConstructor"/> |
7 | <query-specification fqn="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.newElementTypeRefinementTarget"/> | 7 | <query-specification fqn="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.newElementTypeRefinementTarget"/> |
8 | <query-specification fqn="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.incompatibleSuperType"/> | 8 | <query-specification fqn="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.incompatibleSuperType"/> |
9 | <query-specification fqn="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.incompatibleTopType"/> | 9 | <query-specification fqn="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.incompatibleTopType"/> |
10 | <query-specification fqn="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.newElementTypeRefinementNegativeConstraint"/> | 10 | <query-specification fqn="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.newElementTypeRefinementNegativeConstraint"/> |
11 | <query-specification fqn="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.newElementMayTypeNegativeConstraint"/> | 11 | <query-specification fqn="hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.queries.newElementMayTypeNegativeConstraint"/> |
12 | </group> | 12 | </group> |
13 | </extension> | 13 | </extension> |
14 | </plugin> | 14 | </plugin> |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/Modality.java b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/Modality.java index d2132cea..f3a6ec32 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/Modality.java +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/Modality.java | |||
@@ -2,21 +2,46 @@ package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra; | |||
2 | 2 | ||
3 | public enum Modality { | 3 | public enum Modality { |
4 | MUST, MAY, CURRENT; | 4 | MUST, MAY, CURRENT; |
5 | |||
5 | public boolean isMust() { | 6 | public boolean isMust() { |
6 | return this == MUST; | 7 | return this == MUST; |
7 | } | 8 | } |
9 | |||
8 | public boolean isMay() { | 10 | public boolean isMay() { |
9 | return this == MAY; | 11 | return this == MAY; |
10 | } | 12 | } |
13 | |||
11 | public boolean isCurrent() { | 14 | public boolean isCurrent() { |
12 | return this == CURRENT; | 15 | return this == CURRENT; |
13 | } | 16 | } |
17 | |||
14 | public boolean isMustOrCurrent() { | 18 | public boolean isMustOrCurrent() { |
15 | return isMust() || isCurrent(); | 19 | return isMust() || isCurrent(); |
16 | } | 20 | } |
21 | |||
17 | public Modality getDual() { | 22 | public Modality getDual() { |
18 | if(this.isCurrent()) return CURRENT; | 23 | switch (this) { |
19 | else if(this.isMust())return MAY; | 24 | case CURRENT: |
20 | else return MUST; | 25 | return CURRENT; |
26 | case MUST: | ||
27 | return MAY; | ||
28 | case MAY: | ||
29 | return MUST; | ||
30 | default: | ||
31 | throw new UnsupportedOperationException("Unknown Modality: " + this); | ||
32 | } | ||
33 | } | ||
34 | |||
35 | public Modality toBase() { | ||
36 | if (this.isCurrent()) { | ||
37 | return MUST; | ||
38 | } else { | ||
39 | return this; | ||
40 | } | ||
41 | } | ||
42 | |||
43 | @Override | ||
44 | public String toString() { | ||
45 | return super.toString().toLowerCase(); | ||
21 | } | 46 | } |
22 | } | 47 | } |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/ModelGenerationMethodProvider.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/ModelGenerationMethodProvider.xtend index f43ab96d..23632d4d 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/ModelGenerationMethodProvider.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/ModelGenerationMethodProvider.xtend | |||
@@ -1,8 +1,19 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra | 1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra |
2 | 2 | ||
3 | import com.google.common.collect.ImmutableMap | ||
3 | import hu.bme.mit.inf.dslreasoner.logic.model.builder.DocumentationLevel | 4 | import hu.bme.mit.inf.dslreasoner.logic.model.builder.DocumentationLevel |
4 | import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem | 5 | import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem |
5 | import hu.bme.mit.inf.dslreasoner.viatra2logic.viatra2logicannotations.TransfomedViatraQuery | 6 | import hu.bme.mit.inf.dslreasoner.viatra2logic.viatra2logicannotations.TransfomedViatraQuery |
7 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.CbcPolyhedronSolver | ||
8 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.MultiplicityGoalConstraintCalculator | ||
9 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.PolyhedronScopePropagator | ||
10 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.RelationConstraintCalculator | ||
11 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.ScopePropagator | ||
12 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.ScopePropagatorStrategy | ||
13 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.TypeHierarchyScopePropagator | ||
14 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.Z3PolyhedronSolver | ||
15 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns.GeneratedPatterns | ||
16 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns.ModalPatternQueries | ||
6 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns.PatternProvider | 17 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns.PatternProvider |
7 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.rules.GoalConstraintProvider | 18 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.rules.GoalConstraintProvider |
8 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.rules.RefinementRuleProvider | 19 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.rules.RefinementRuleProvider |
@@ -10,6 +21,7 @@ import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.par | |||
10 | import hu.bme.mit.inf.dslreasoner.workspace.ReasonerWorkspace | 21 | import hu.bme.mit.inf.dslreasoner.workspace.ReasonerWorkspace |
11 | import java.util.Collection | 22 | import java.util.Collection |
12 | import java.util.List | 23 | import java.util.List |
24 | import java.util.Map | ||
13 | import java.util.Set | 25 | import java.util.Set |
14 | import org.eclipse.viatra.query.runtime.api.IPatternMatch | 26 | import org.eclipse.viatra.query.runtime.api.IPatternMatch |
15 | import org.eclipse.viatra.query.runtime.api.IQuerySpecification | 27 | import org.eclipse.viatra.query.runtime.api.IQuerySpecification |
@@ -20,63 +32,99 @@ import org.eclipse.xtend.lib.annotations.Data | |||
20 | 32 | ||
21 | class ModelGenerationStatistics { | 33 | class ModelGenerationStatistics { |
22 | public var long transformationExecutionTime = 0 | 34 | public var long transformationExecutionTime = 0 |
35 | |||
23 | synchronized def addExecutionTime(long amount) { | 36 | synchronized def addExecutionTime(long amount) { |
24 | transformationExecutionTime+=amount | 37 | transformationExecutionTime += amount |
38 | } | ||
39 | |||
40 | public var long scopePropagationTime = 0 | ||
41 | |||
42 | synchronized def addScopePropagationTime(long amount) { | ||
43 | scopePropagationTime += amount | ||
44 | } | ||
45 | |||
46 | public var long preliminaryTypeAnalisisTime = 0 | ||
47 | |||
48 | public var int decisionsTried = 0 | ||
49 | |||
50 | synchronized def incrementDecisionCount() { | ||
51 | decisionsTried++ | ||
52 | } | ||
53 | |||
54 | public var int scopePropagatorInvocations | ||
55 | |||
56 | synchronized def incrementScopePropagationCount() { | ||
57 | scopePropagatorInvocations++ | ||
25 | } | 58 | } |
26 | public var long PreliminaryTypeAnalisisTime = 0 | ||
27 | } | 59 | } |
60 | |||
28 | @Data class ModelGenerationMethod { | 61 | @Data class ModelGenerationMethod { |
29 | ModelGenerationStatistics statistics | 62 | ModelGenerationStatistics statistics |
30 | 63 | ||
31 | Collection<? extends BatchTransformationRule<?,?>> objectRefinementRules | 64 | Collection<? extends BatchTransformationRule<?, ?>> objectRefinementRules |
32 | Collection<? extends BatchTransformationRule<?,?>> relationRefinementRules | 65 | Collection<? extends BatchTransformationRule<?, ?>> relationRefinementRules |
33 | 66 | ||
34 | List<MultiplicityGoalConstraintCalculator> unfinishedMultiplicities | 67 | List<MultiplicityGoalConstraintCalculator> unfinishedMultiplicities |
35 | Collection<? extends IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> unfinishedWF | 68 | |
36 | 69 | Collection<? extends IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> unfinishedWF | |
37 | Collection<? extends IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> invalidWF | 70 | |
38 | 71 | Collection<? extends IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> invalidWF | |
39 | Collection<? extends IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> allPatterns | 72 | |
73 | Map<String, ModalPatternQueries> modalRelationQueries | ||
74 | |||
75 | Collection<? extends IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> allPatterns | ||
40 | } | 76 | } |
77 | |||
41 | enum TypeInferenceMethod { | 78 | enum TypeInferenceMethod { |
42 | Generic, PreliminaryAnalysis | 79 | Generic, |
80 | PreliminaryAnalysis | ||
43 | } | 81 | } |
44 | 82 | ||
45 | class ModelGenerationMethodProvider { | 83 | class ModelGenerationMethodProvider { |
46 | private val PatternProvider patternProvider = new PatternProvider | 84 | val PatternProvider patternProvider = new PatternProvider |
47 | private val RefinementRuleProvider refinementRuleProvider = new RefinementRuleProvider | 85 | val RefinementRuleProvider refinementRuleProvider = new RefinementRuleProvider |
48 | private val GoalConstraintProvider goalConstraintProvider = new GoalConstraintProvider | 86 | val GoalConstraintProvider goalConstraintProvider = new GoalConstraintProvider |
49 | 87 | val relationConstraintCalculator = new RelationConstraintCalculator | |
50 | public def ModelGenerationMethod createModelGenerationMethod( | 88 | |
89 | def ModelGenerationMethod createModelGenerationMethod( | ||
51 | LogicProblem logicProblem, | 90 | LogicProblem logicProblem, |
52 | PartialInterpretation emptySolution, | 91 | PartialInterpretation emptySolution, |
53 | ReasonerWorkspace workspace, | 92 | ReasonerWorkspace workspace, |
54 | boolean nameNewElements, | 93 | boolean nameNewElements, |
55 | TypeInferenceMethod typeInferenceMethod, | 94 | TypeInferenceMethod typeInferenceMethod, |
56 | ScopePropagator scopePropagator, | 95 | ScopePropagatorStrategy scopePropagatorStrategy, |
57 | DocumentationLevel debugLevel | 96 | DocumentationLevel debugLevel |
58 | ) { | 97 | ) { |
59 | val statistics = new ModelGenerationStatistics | 98 | val statistics = new ModelGenerationStatistics |
60 | val writeFiles = (debugLevel === DocumentationLevel.NORMAL || debugLevel === DocumentationLevel.FULL) | 99 | val writeFiles = (debugLevel === DocumentationLevel.NORMAL || debugLevel === DocumentationLevel.FULL) |
61 | 100 | ||
62 | val Set<PQuery> existingQueries = logicProblem | 101 | val Set<PQuery> existingQueries = logicProblem.relations.map[annotations].flatten.filter(TransfomedViatraQuery). |
63 | .relations | 102 | map[it.patternPQuery as PQuery].toSet |
64 | .map[annotations] | 103 | |
65 | .flatten | 104 | val relationConstraints = relationConstraintCalculator.calculateRelationConstraints(logicProblem) |
66 | .filter(TransfomedViatraQuery) | 105 | val queries = patternProvider.generateQueries(logicProblem, emptySolution, statistics, existingQueries, |
67 | .map[it.patternPQuery as PQuery] | 106 | workspace, typeInferenceMethod, scopePropagatorStrategy, relationConstraints, writeFiles) |
68 | .toSet | 107 | val scopePropagator = createScopePropagator(scopePropagatorStrategy, emptySolution, queries, statistics) |
69 | 108 | scopePropagator.propagateAllScopeConstraints | |
70 | val queries = patternProvider.generateQueries(logicProblem,emptySolution,statistics,existingQueries,workspace,typeInferenceMethod,writeFiles) | 109 | val objectRefinementRules = refinementRuleProvider.createObjectRefinementRules(queries, scopePropagator, |
71 | val //LinkedHashMap<Pair<Relation, ? extends Type>, BatchTransformationRule<GenericPatternMatch, ViatraQueryMatcher<GenericPatternMatch>>> | 110 | nameNewElements, statistics) |
72 | objectRefinementRules = refinementRuleProvider.createObjectRefinementRules(queries,scopePropagator,nameNewElements,statistics) | 111 | val relationRefinementRules = refinementRuleProvider.createRelationRefinementRules(queries, scopePropagator, |
73 | val relationRefinementRules = refinementRuleProvider.createRelationRefinementRules(queries,statistics) | 112 | statistics) |
74 | 113 | ||
75 | val unfinishedMultiplicities = goalConstraintProvider.getUnfinishedMultiplicityQueries(queries) | 114 | val unfinishedMultiplicities = goalConstraintProvider.getUnfinishedMultiplicityQueries(queries) |
76 | val unfinishedWF = queries.getUnfinishedWFQueries.values | 115 | val unfinishedWF = queries.getUnfinishedWFQueries.values |
77 | 116 | ||
117 | val modalRelationQueriesBuilder = ImmutableMap.builder | ||
118 | for (entry : queries.modalRelationQueries.entrySet) { | ||
119 | val annotation = entry.key.annotations.filter(TransfomedViatraQuery).head | ||
120 | if (annotation !== null) { | ||
121 | modalRelationQueriesBuilder.put(annotation.patternFullyQualifiedName, entry.value) | ||
122 | } | ||
123 | } | ||
124 | val modalRelationQueries = modalRelationQueriesBuilder.build | ||
125 | |||
78 | val invalidWF = queries.getInvalidWFQueries.values | 126 | val invalidWF = queries.getInvalidWFQueries.values |
79 | 127 | ||
80 | return new ModelGenerationMethod( | 128 | return new ModelGenerationMethod( |
81 | statistics, | 129 | statistics, |
82 | objectRefinementRules.values, | 130 | objectRefinementRules.values, |
@@ -84,7 +132,38 @@ class ModelGenerationMethodProvider { | |||
84 | unfinishedMultiplicities, | 132 | unfinishedMultiplicities, |
85 | unfinishedWF, | 133 | unfinishedWF, |
86 | invalidWF, | 134 | invalidWF, |
135 | modalRelationQueries, | ||
87 | queries.allQueries | 136 | queries.allQueries |
88 | ) | 137 | ) |
89 | } | 138 | } |
139 | |||
140 | private def createScopePropagator(ScopePropagatorStrategy scopePropagatorStrategy, | ||
141 | PartialInterpretation emptySolution, GeneratedPatterns queries, ModelGenerationStatistics statistics) { | ||
142 | switch (scopePropagatorStrategy) { | ||
143 | case ScopePropagatorStrategy.Count: | ||
144 | new ScopePropagator(emptySolution, statistics) | ||
145 | case ScopePropagatorStrategy.BasicTypeHierarchy: | ||
146 | new TypeHierarchyScopePropagator(emptySolution, statistics) | ||
147 | ScopePropagatorStrategy.Polyhedral: { | ||
148 | val types = queries.refineObjectQueries.keySet.map[newType].toSet | ||
149 | val solver = switch (scopePropagatorStrategy.solver) { | ||
150 | case Z3Integer: | ||
151 | new Z3PolyhedronSolver(false, scopePropagatorStrategy.timeoutSeconds) | ||
152 | case Z3Real: | ||
153 | new Z3PolyhedronSolver(true, scopePropagatorStrategy.timeoutSeconds) | ||
154 | case Cbc: | ||
155 | new CbcPolyhedronSolver(false, scopePropagatorStrategy.timeoutSeconds, true) | ||
156 | case Clp: | ||
157 | new CbcPolyhedronSolver(true, scopePropagatorStrategy.timeoutSeconds, true) | ||
158 | default: | ||
159 | throw new IllegalArgumentException("Unknown polyhedron solver: " + | ||
160 | scopePropagatorStrategy.solver) | ||
161 | } | ||
162 | new PolyhedronScopePropagator(emptySolution, statistics, types, queries.multiplicityConstraintQueries, | ||
163 | queries.hasElementInContainmentQuery, solver, scopePropagatorStrategy.requiresUpperBoundIndexing) | ||
164 | } | ||
165 | default: | ||
166 | throw new IllegalArgumentException("Unknown scope propagator strategy: " + scopePropagatorStrategy) | ||
167 | } | ||
168 | } | ||
90 | } | 169 | } |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/ScopePropagator.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/ScopePropagator.xtend deleted file mode 100644 index 38633c07..00000000 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/ScopePropagator.xtend +++ /dev/null | |||
@@ -1,156 +0,0 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra | ||
2 | |||
3 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | ||
4 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialTypeInterpratation | ||
5 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.Scope | ||
6 | import java.util.HashMap | ||
7 | import java.util.Map | ||
8 | import java.util.Set | ||
9 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialComplexTypeInterpretation | ||
10 | import java.util.HashSet | ||
11 | |||
12 | class ScopePropagator { | ||
13 | PartialInterpretation partialInterpretation | ||
14 | Map<PartialTypeInterpratation,Scope> type2Scope | ||
15 | |||
16 | val Map<Scope, Set<Scope>> superScopes | ||
17 | val Map<Scope, Set<Scope>> subScopes | ||
18 | |||
19 | public new(PartialInterpretation p) { | ||
20 | partialInterpretation = p | ||
21 | type2Scope = new HashMap | ||
22 | for(scope : p.scopes) { | ||
23 | type2Scope.put(scope.targetTypeInterpretation,scope) | ||
24 | } | ||
25 | |||
26 | superScopes = new HashMap | ||
27 | subScopes = new HashMap | ||
28 | for(scope : p.scopes) { | ||
29 | superScopes.put(scope,new HashSet) | ||
30 | subScopes.put(scope,new HashSet) | ||
31 | } | ||
32 | |||
33 | for(scope : p.scopes) { | ||
34 | val target = scope.targetTypeInterpretation | ||
35 | if(target instanceof PartialComplexTypeInterpretation) { | ||
36 | val supertypeInterpretations = target.supertypeInterpretation | ||
37 | for(supertypeInterpretation : supertypeInterpretations) { | ||
38 | val supertypeScope = type2Scope.get(supertypeInterpretation) | ||
39 | superScopes.get(scope).add(supertypeScope) | ||
40 | subScopes.get(supertypeScope).add(scope) | ||
41 | } | ||
42 | } | ||
43 | } | ||
44 | } | ||
45 | |||
46 | def public propagateAllScopeConstraints() { | ||
47 | var boolean hadChanged | ||
48 | do{ | ||
49 | hadChanged = false | ||
50 | for(superScopeEntry : superScopes.entrySet) { | ||
51 | val sub = superScopeEntry.key | ||
52 | hadChanged = propagateLowerLimitUp(sub,partialInterpretation) || hadChanged | ||
53 | hadChanged = propagateUpperLimitDown(sub,partialInterpretation) || hadChanged | ||
54 | for(sup: superScopeEntry.value) { | ||
55 | hadChanged = propagateLowerLimitUp(sub,sup) || hadChanged | ||
56 | hadChanged = propagateUpperLimitDown(sub,sup) || hadChanged | ||
57 | } | ||
58 | } | ||
59 | } while(hadChanged) | ||
60 | // println('''All constraints are propagated.''') | ||
61 | } | ||
62 | |||
63 | def public propagateAdditionToType(PartialTypeInterpratation t) { | ||
64 | // println('''Adding to «(t as PartialComplexTypeInterpretation).interpretationOf.name»''') | ||
65 | val targetScope = type2Scope.get(t) | ||
66 | targetScope.removeOne | ||
67 | val sups = superScopes.get(targetScope) | ||
68 | sups.forEach[removeOne] | ||
69 | if(this.partialInterpretation.minNewElements > 0) { | ||
70 | this.partialInterpretation.minNewElements = this.partialInterpretation.minNewElements-1 | ||
71 | } | ||
72 | if(this.partialInterpretation.maxNewElements > 0) { | ||
73 | this.partialInterpretation.maxNewElements = this.partialInterpretation.maxNewElements-1 | ||
74 | } else if(this.partialInterpretation.maxNewElements === 0) { | ||
75 | throw new IllegalArgumentException('''Inconsistent object creation: lower node limit is 0!''') | ||
76 | } | ||
77 | |||
78 | // subScopes.get(targetScope).forEach[propagateUpperLimitDown(it,targetScope)] | ||
79 | // for(sup: sups) { | ||
80 | // subScopes.get(sup).forEach[propagateUpperLimitDown(it,sup)] | ||
81 | // } | ||
82 | // for(scope : type2Scope.values) { | ||
83 | // propagateUpperLimitDown(scope,partialInterpretation) | ||
84 | // } | ||
85 | |||
86 | propagateAllScopeConstraints | ||
87 | |||
88 | // println('''Target Scope: «targetScope.minNewElements» - «targetScope.maxNewElements»''') | ||
89 | // println(''' «this.partialInterpretation.minNewElements» - «this.partialInterpretation.maxNewElements»''') | ||
90 | // this.partialInterpretation.scopes.forEach[println(''' «(it.targetTypeInterpretation as PartialComplexTypeInterpretation).interpretationOf.name»: «it.minNewElements»-«it.maxNewElements»''')] | ||
91 | // println('''All constraints are propagated upon increasing «(t as PartialComplexTypeInterpretation).interpretationOf.name»''') | ||
92 | } | ||
93 | |||
94 | private def propagateLowerLimitUp(Scope subScope, Scope superScope) { | ||
95 | if(subScope.minNewElements>superScope.minNewElements) { | ||
96 | // println(''' | ||
97 | // «(subScope.targetTypeInterpretation as PartialComplexTypeInterpretation).interpretationOf.name» -> «(superScope.targetTypeInterpretation as PartialComplexTypeInterpretation).interpretationOf.name» | ||
98 | // superScope.minNewElements «superScope.minNewElements» = subScope.minNewElements «subScope.minNewElements» | ||
99 | // ''') | ||
100 | superScope.minNewElements = subScope.minNewElements | ||
101 | return true | ||
102 | } else { | ||
103 | return false | ||
104 | } | ||
105 | } | ||
106 | |||
107 | private def propagateUpperLimitDown(Scope subScope, Scope superScope) { | ||
108 | if(superScope.maxNewElements>=0 && (superScope.maxNewElements<subScope.maxNewElements || subScope.maxNewElements<0)) { | ||
109 | // println(''' | ||
110 | // «(subScope.targetTypeInterpretation as PartialComplexTypeInterpretation).interpretationOf.name» -> «(superScope.targetTypeInterpretation as PartialComplexTypeInterpretation).interpretationOf.name» | ||
111 | // subScope.maxNewElements «subScope.maxNewElements» = superScope.maxNewElements «superScope.maxNewElements» | ||
112 | // ''') | ||
113 | subScope.maxNewElements = superScope.maxNewElements | ||
114 | return true | ||
115 | } else { | ||
116 | return false | ||
117 | } | ||
118 | } | ||
119 | |||
120 | private def propagateLowerLimitUp(Scope subScope, PartialInterpretation p) { | ||
121 | if(subScope.minNewElements>p.minNewElements) { | ||
122 | // println(''' | ||
123 | // «(subScope.targetTypeInterpretation as PartialComplexTypeInterpretation).interpretationOf.name» -> nodes | ||
124 | // p.minNewElements «p.minNewElements» = subScope.minNewElements «subScope.minNewElements» | ||
125 | // ''') | ||
126 | p.minNewElements = subScope.minNewElements | ||
127 | return true | ||
128 | } else { | ||
129 | return false | ||
130 | } | ||
131 | } | ||
132 | |||
133 | private def propagateUpperLimitDown(Scope subScope, PartialInterpretation p) { | ||
134 | if(p.maxNewElements>=0 && (p.maxNewElements<subScope.maxNewElements || subScope.maxNewElements<0)) { | ||
135 | // println(''' | ||
136 | // «(subScope.targetTypeInterpretation as PartialComplexTypeInterpretation).interpretationOf.name» -> nodes | ||
137 | // subScope.maxNewElements «subScope.maxNewElements» = p.maxNewElements «p.maxNewElements» | ||
138 | // ''') | ||
139 | subScope.maxNewElements = p.maxNewElements | ||
140 | return true | ||
141 | } else { | ||
142 | return false | ||
143 | } | ||
144 | } | ||
145 | private def removeOne(Scope scope) { | ||
146 | if(scope.maxNewElements===0) { | ||
147 | throw new IllegalArgumentException('''Inconsistent object creation: «scope.targetTypeInterpretation»''') | ||
148 | } else if(scope.maxNewElements>0) { | ||
149 | scope.maxNewElements= scope.maxNewElements-1 | ||
150 | } | ||
151 | if(scope.minNewElements>0) { | ||
152 | scope.minNewElements= scope.minNewElements-1 | ||
153 | } | ||
154 | } | ||
155 | } | ||
156 | \ No newline at end of file | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/AbstractPolyhedronSaturationOperator.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/AbstractPolyhedronSaturationOperator.xtend new file mode 100644 index 00000000..94f97e94 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/AbstractPolyhedronSaturationOperator.xtend | |||
@@ -0,0 +1,53 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality | ||
2 | |||
3 | import com.google.common.collect.ImmutableList | ||
4 | import org.eclipse.xtend.lib.annotations.Accessors | ||
5 | |||
6 | abstract class AbstractPolyhedronSaturationOperator implements PolyhedronSaturationOperator { | ||
7 | @Accessors val Polyhedron polyhedron | ||
8 | |||
9 | new(Polyhedron polyhedron) { | ||
10 | if (polyhedron.dimensions.empty) { | ||
11 | throw new IllegalArgumentException("Polyhedron must have at least one dimension.") | ||
12 | } | ||
13 | this.polyhedron = polyhedron | ||
14 | } | ||
15 | |||
16 | override saturate() { | ||
17 | if (polyhedron.expressionsToSaturate.empty) { | ||
18 | return PolyhedronSaturationResult.SATURATED | ||
19 | } | ||
20 | for (constraint : polyhedron.constraints) { | ||
21 | if (constraint.zero) { | ||
22 | if (constraint.lowerBound !== null && constraint.lowerBound > 0) { | ||
23 | return PolyhedronSaturationResult.EMPTY | ||
24 | } | ||
25 | if (constraint.upperBound !== null && constraint.upperBound < 0) { | ||
26 | return PolyhedronSaturationResult.EMPTY | ||
27 | } | ||
28 | } else { | ||
29 | if (constraint.lowerBound !== null && constraint.upperBound !== null && | ||
30 | constraint.upperBound < constraint.lowerBound) { | ||
31 | return PolyhedronSaturationResult.EMPTY | ||
32 | } | ||
33 | } | ||
34 | } | ||
35 | doSaturate() | ||
36 | } | ||
37 | |||
38 | protected def PolyhedronSaturationResult doSaturate() | ||
39 | |||
40 | protected def getNonTrivialConstraints() { | ||
41 | ImmutableList.copyOf(polyhedron.constraints.filter [ constraint | | ||
42 | (constraint.lowerBound !== null || constraint.upperBound !== null) && !constraint.zero | ||
43 | ]) | ||
44 | } | ||
45 | |||
46 | private static def isZero(LinearConstraint constraint) { | ||
47 | constraint.coefficients.values.forall[it == 0] | ||
48 | } | ||
49 | |||
50 | override close() throws Exception { | ||
51 | // Nothing to close by default. | ||
52 | } | ||
53 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/CbcPolyhedronSolver.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/CbcPolyhedronSolver.xtend new file mode 100644 index 00000000..4bd46fbf --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/CbcPolyhedronSolver.xtend | |||
@@ -0,0 +1,216 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality | ||
2 | |||
3 | import com.google.common.collect.ImmutableList | ||
4 | import com.google.common.collect.ImmutableMap | ||
5 | import hu.bme.mit.inf.dslreasoner.ilp.cbc.CbcResult | ||
6 | import hu.bme.mit.inf.dslreasoner.ilp.cbc.CbcSolver | ||
7 | import java.util.HashSet | ||
8 | import java.util.List | ||
9 | import java.util.Map | ||
10 | import java.util.Set | ||
11 | import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor | ||
12 | |||
13 | @FinalFieldsConstructor | ||
14 | class CbcPolyhedronSolver implements PolyhedronSolver { | ||
15 | val boolean lpRelaxation | ||
16 | val double timeoutSeconds | ||
17 | val boolean silent | ||
18 | |||
19 | new() { | ||
20 | this(false, -1, true) | ||
21 | } | ||
22 | |||
23 | override createSaturationOperator(Polyhedron polyhedron) { | ||
24 | new CbcSaturationOperator(polyhedron, lpRelaxation, timeoutSeconds, silent) | ||
25 | } | ||
26 | } | ||
27 | |||
28 | class CbcSaturationOperator extends AbstractPolyhedronSaturationOperator { | ||
29 | val boolean lpRelaxation | ||
30 | val double timeoutSeconds | ||
31 | val boolean silent | ||
32 | val double[] columnLowerBounds | ||
33 | val double[] columnUpperBounds | ||
34 | val double[] objective | ||
35 | val Map<Dimension, Integer> dimensionsToIndicesMap | ||
36 | |||
37 | new(Polyhedron polyhedron, boolean lpRelaxation, double timeoutSeconds, boolean silent) { | ||
38 | super(polyhedron) | ||
39 | this.lpRelaxation = lpRelaxation | ||
40 | this.timeoutSeconds = timeoutSeconds | ||
41 | this.silent = silent | ||
42 | val numDimensions = polyhedron.dimensions.size | ||
43 | columnLowerBounds = newDoubleArrayOfSize(numDimensions) | ||
44 | columnUpperBounds = newDoubleArrayOfSize(numDimensions) | ||
45 | objective = newDoubleArrayOfSize(numDimensions) | ||
46 | dimensionsToIndicesMap = ImmutableMap.copyOf(polyhedron.dimensions.indexed.toMap([value], [key])) | ||
47 | } | ||
48 | |||
49 | override doSaturate() { | ||
50 | val numDimensions = polyhedron.dimensions.size | ||
51 | for (var int j = 0; j < numDimensions; j++) { | ||
52 | val dimension = polyhedron.dimensions.get(j) | ||
53 | columnLowerBounds.set(j, dimension.lowerBound.toDouble(Double.NEGATIVE_INFINITY)) | ||
54 | columnUpperBounds.set(j, dimension.upperBound.toDouble(Double.POSITIVE_INFINITY)) | ||
55 | } | ||
56 | val constraints = nonTrivialConstraints | ||
57 | val numConstraints = constraints.size | ||
58 | val rowStarts = newIntArrayOfSize(numConstraints + 1) | ||
59 | val rowLowerBounds = newDoubleArrayOfSize(numConstraints) | ||
60 | val rowUpperBounds = newDoubleArrayOfSize(numConstraints) | ||
61 | val numEntries = constraints.map[coefficients.size].reduce[a, b|a + b] ?: 0 | ||
62 | rowStarts.set(numConstraints, numEntries) | ||
63 | val columnIndices = newIntArrayOfSize(numEntries) | ||
64 | val entries = newDoubleArrayOfSize(numEntries) | ||
65 | val unconstrainedDimensions = new HashSet | ||
66 | for (dimension : polyhedron.dimensions) { | ||
67 | if (dimension.lowerBound === null && dimension.upperBound === null) { | ||
68 | unconstrainedDimensions += dimension | ||
69 | } | ||
70 | } | ||
71 | var int index = 0 | ||
72 | for (var int i = 0; i < numConstraints; i++) { | ||
73 | rowStarts.set(i, index) | ||
74 | val constraint = constraints.get(i) | ||
75 | rowLowerBounds.set(i, constraint.lowerBound.toDouble(Double.NEGATIVE_INFINITY)) | ||
76 | rowUpperBounds.set(i, constraint.upperBound.toDouble(Double.POSITIVE_INFINITY)) | ||
77 | if (!dimensionsToIndicesMap.keySet.containsAll(constraint.coefficients.keySet)) { | ||
78 | throw new IllegalArgumentException("Constrains has unknown dimensions") | ||
79 | } | ||
80 | for (var int j = 0; j < numDimensions; j++) { | ||
81 | val dimension = polyhedron.dimensions.get(j) | ||
82 | val coefficient = constraint.coefficients.get(dimension) | ||
83 | if (coefficient !== null && coefficient != 0) { | ||
84 | unconstrainedDimensions -= dimension | ||
85 | columnIndices.set(index, j) | ||
86 | entries.set(index, coefficient) | ||
87 | index++ | ||
88 | } | ||
89 | } | ||
90 | } | ||
91 | if (index != numEntries) { | ||
92 | throw new AssertionError("Last entry does not equal the number of entries in the constraint matrix") | ||
93 | } | ||
94 | for (expressionToSaturate : polyhedron.expressionsToSaturate) { | ||
95 | val result = saturate(expressionToSaturate, rowStarts, columnIndices, entries, rowLowerBounds, | ||
96 | rowUpperBounds, unconstrainedDimensions, constraints) | ||
97 | if (result != PolyhedronSaturationResult.SATURATED) { | ||
98 | return result | ||
99 | } | ||
100 | } | ||
101 | PolyhedronSaturationResult.SATURATED | ||
102 | } | ||
103 | |||
104 | protected def saturate(LinearBoundedExpression expressionToSaturate, int[] rowStarts, int[] columnIndices, | ||
105 | double[] entries, double[] rowLowerBounds, double[] rowUpperBounds, Set<Dimension> unconstrainedDimensions, | ||
106 | ImmutableList<LinearConstraint> constraints) { | ||
107 | val numDimensions = objective.size | ||
108 | for (var int j = 0; j < numDimensions; j++) { | ||
109 | objective.set(j, 0) | ||
110 | } | ||
111 | switch (expressionToSaturate) { | ||
112 | Dimension: { | ||
113 | // CBC will return nonsensical results or call free() with invalid arguments if | ||
114 | // it is passed a fully unconstrained (-Inf lower and +Int upper bound, no inequalities) variable | ||
115 | // in the objective function. | ||
116 | if (unconstrainedDimensions.contains(expressionToSaturate)) { | ||
117 | return PolyhedronSaturationResult.SATURATED | ||
118 | } | ||
119 | val j = getIndex(expressionToSaturate) | ||
120 | objective.set(j, 1) | ||
121 | } | ||
122 | LinearConstraint: { | ||
123 | for (pair : expressionToSaturate.coefficients.entrySet) { | ||
124 | val dimension = pair.key | ||
125 | // We also have to check for unconstrained dimensions here to avoid crashing. | ||
126 | if (unconstrainedDimensions.contains(dimension)) { | ||
127 | expressionToSaturate.lowerBound = null | ||
128 | expressionToSaturate.upperBound = null | ||
129 | return PolyhedronSaturationResult.SATURATED | ||
130 | } | ||
131 | val j = getIndex(dimension) | ||
132 | objective.set(j, pair.value) | ||
133 | } | ||
134 | } | ||
135 | default: | ||
136 | throw new IllegalArgumentException("Unknown expression: " + expressionToSaturate) | ||
137 | } | ||
138 | val minimizationResult = CbcSolver.solve(columnLowerBounds, columnUpperBounds, rowStarts, columnIndices, | ||
139 | entries, rowLowerBounds, rowUpperBounds, objective, lpRelaxation, timeoutSeconds, silent) | ||
140 | switch (minimizationResult) { | ||
141 | CbcResult.SolutionBounded: { | ||
142 | val value = Math.floor(minimizationResult.value) | ||
143 | expressionToSaturate.lowerBound = value as int | ||
144 | setBound(expressionToSaturate, constraints, value, columnLowerBounds, rowLowerBounds) | ||
145 | } | ||
146 | case CbcResult.SOLUTION_UNBOUNDED: { | ||
147 | expressionToSaturate.lowerBound = null | ||
148 | setBound(expressionToSaturate, constraints, Double.NEGATIVE_INFINITY, columnLowerBounds, rowLowerBounds) | ||
149 | } | ||
150 | case CbcResult.UNSAT: | ||
151 | return PolyhedronSaturationResult.EMPTY | ||
152 | case CbcResult.ABANDONED, | ||
153 | case CbcResult.TIMEOUT: | ||
154 | return PolyhedronSaturationResult.UNKNOWN | ||
155 | default: | ||
156 | throw new RuntimeException("Unknown CbcResult: " + minimizationResult) | ||
157 | } | ||
158 | for (var int j = 0; j < numDimensions; j++) { | ||
159 | val objectiveCoefficient = objective.get(j) | ||
160 | objective.set(j, -objectiveCoefficient) | ||
161 | } | ||
162 | val maximizationResult = CbcSolver.solve(columnLowerBounds, columnUpperBounds, rowStarts, columnIndices, | ||
163 | entries, rowLowerBounds, rowUpperBounds, objective, lpRelaxation, timeoutSeconds, silent) | ||
164 | switch (maximizationResult) { | ||
165 | CbcResult.SolutionBounded: { | ||
166 | val value = Math.ceil(-maximizationResult.value) | ||
167 | expressionToSaturate.upperBound = value as int | ||
168 | setBound(expressionToSaturate, constraints, value, columnUpperBounds, rowUpperBounds) | ||
169 | } | ||
170 | case CbcResult.SOLUTION_UNBOUNDED: { | ||
171 | expressionToSaturate.upperBound = null | ||
172 | setBound(expressionToSaturate, constraints, Double.POSITIVE_INFINITY, columnUpperBounds, rowUpperBounds) | ||
173 | } | ||
174 | case CbcResult.UNSAT: | ||
175 | throw new RuntimeException("Minimization was SAT, but maximization is UNSAT") | ||
176 | case CbcResult.ABANDONED, | ||
177 | case CbcResult.TIMEOUT: | ||
178 | return PolyhedronSaturationResult.UNKNOWN | ||
179 | default: | ||
180 | throw new RuntimeException("Unknown CbcResult: " + maximizationResult) | ||
181 | } | ||
182 | return PolyhedronSaturationResult.SATURATED | ||
183 | } | ||
184 | |||
185 | private def toDouble(Integer nullableInt, double defaultValue) { | ||
186 | if (nullableInt === null) { | ||
187 | defaultValue | ||
188 | } else { | ||
189 | nullableInt.doubleValue | ||
190 | } | ||
191 | } | ||
192 | |||
193 | private def int getIndex(Dimension dimension) { | ||
194 | val index = dimensionsToIndicesMap.get(dimension) | ||
195 | if (index === null) { | ||
196 | throw new IllegalArgumentException("Unknown dimension: " + dimension) | ||
197 | } | ||
198 | index | ||
199 | } | ||
200 | |||
201 | private def void setBound(LinearBoundedExpression expression, List<LinearConstraint> constraints, double bound, | ||
202 | double[] columnBounds, double[] rowBounds) { | ||
203 | switch (expression) { | ||
204 | Dimension: { | ||
205 | val j = getIndex(expression) | ||
206 | columnBounds.set(j, bound) | ||
207 | } | ||
208 | LinearConstraint: { | ||
209 | val i = constraints.indexOf(expression) | ||
210 | if (i >= 0) { | ||
211 | rowBounds.set(i, bound) | ||
212 | } | ||
213 | } | ||
214 | } | ||
215 | } | ||
216 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/MultiplicityGoalConstraintCalculator.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/MultiplicityGoalConstraintCalculator.xtend index e05160d0..86a59aa1 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/MultiplicityGoalConstraintCalculator.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/MultiplicityGoalConstraintCalculator.xtend | |||
@@ -1,4 +1,4 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra | 1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality |
2 | 2 | ||
3 | import org.eclipse.emf.common.notify.Notifier | 3 | import org.eclipse.emf.common.notify.Notifier |
4 | import org.eclipse.viatra.query.runtime.api.IQuerySpecification | 4 | import org.eclipse.viatra.query.runtime.api.IQuerySpecification |
@@ -11,36 +11,36 @@ class MultiplicityGoalConstraintCalculator { | |||
11 | val IQuerySpecification<?> querySpecification; | 11 | val IQuerySpecification<?> querySpecification; |
12 | var ViatraQueryMatcher<?> matcher; | 12 | var ViatraQueryMatcher<?> matcher; |
13 | 13 | ||
14 | public new(String targetRelationName, IQuerySpecification<?> querySpecification) { | 14 | new(String targetRelationName, IQuerySpecification<?> querySpecification) { |
15 | this.targetRelationName = targetRelationName | 15 | this.targetRelationName = targetRelationName |
16 | this.querySpecification = querySpecification | 16 | this.querySpecification = querySpecification |
17 | this.matcher = null | 17 | this.matcher = null |
18 | } | 18 | } |
19 | 19 | ||
20 | public new(MultiplicityGoalConstraintCalculator other) { | 20 | new(MultiplicityGoalConstraintCalculator other) { |
21 | this.targetRelationName = other.targetRelationName | 21 | this.targetRelationName = other.targetRelationName |
22 | this.querySpecification = other.querySpecification | 22 | this.querySpecification = other.querySpecification |
23 | this.matcher = null | 23 | this.matcher = null |
24 | } | 24 | } |
25 | 25 | ||
26 | def public getName() { | 26 | def getName() { |
27 | targetRelationName | 27 | targetRelationName |
28 | } | 28 | } |
29 | 29 | ||
30 | def public init(Notifier notifier) { | 30 | def init(Notifier notifier) { |
31 | val engine = ViatraQueryEngine.on(new EMFScope(notifier)) | 31 | val engine = ViatraQueryEngine.on(new EMFScope(notifier)) |
32 | matcher = querySpecification.getMatcher(engine) | 32 | matcher = querySpecification.getMatcher(engine) |
33 | } | 33 | } |
34 | 34 | ||
35 | def public calculateValue() { | 35 | def calculateValue() { |
36 | var res = 0 | 36 | var res = 0 |
37 | val allMatches = this.matcher.allMatches | 37 | val allMatches = this.matcher.allMatches |
38 | for(match : allMatches) { | 38 | for(match : allMatches) { |
39 | //println(targetRelationName+ " missing multiplicity: "+match.get(3)) | 39 | //println(targetRelationName+ " missing multiplicity: "+match.get(3)) |
40 | val missingMultiplicity = match.get(4) as Integer | 40 | val missingMultiplicity = match.get(2) as Integer |
41 | res += missingMultiplicity | 41 | res += missingMultiplicity |
42 | } | 42 | } |
43 | //println(targetRelationName+ " all missing multiplicities: "+res) | 43 | //println(targetRelationName+ " all missing multiplicities: "+res) |
44 | return res | 44 | return res |
45 | } | 45 | } |
46 | } \ No newline at end of file | 46 | } |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/PolyhedronScopePropagator.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/PolyhedronScopePropagator.xtend new file mode 100644 index 00000000..7c05e818 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/PolyhedronScopePropagator.xtend | |||
@@ -0,0 +1,516 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality | ||
2 | |||
3 | import com.google.common.collect.ImmutableList | ||
4 | import com.google.common.collect.ImmutableMap | ||
5 | import com.google.common.collect.ImmutableSet | ||
6 | import com.google.common.collect.Maps | ||
7 | import com.google.common.collect.Sets | ||
8 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Relation | ||
9 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Type | ||
10 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.ModelGenerationStatistics | ||
11 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns.UnifinishedMultiplicityQueries | ||
12 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialComplexTypeInterpretation | ||
13 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | ||
14 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialPrimitiveInterpretation | ||
15 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.Scope | ||
16 | import java.util.ArrayDeque | ||
17 | import java.util.ArrayList | ||
18 | import java.util.HashMap | ||
19 | import java.util.HashSet | ||
20 | import java.util.List | ||
21 | import java.util.Map | ||
22 | import java.util.Set | ||
23 | import javax.naming.OperationNotSupportedException | ||
24 | import org.eclipse.viatra.query.runtime.api.IPatternMatch | ||
25 | import org.eclipse.viatra.query.runtime.api.IQuerySpecification | ||
26 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine | ||
27 | import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher | ||
28 | import org.eclipse.viatra.query.runtime.emf.EMFScope | ||
29 | import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor | ||
30 | |||
31 | class PolyhedronScopePropagator extends TypeHierarchyScopePropagator { | ||
32 | val Map<Scope, LinearBoundedExpression> scopeBounds | ||
33 | val LinearBoundedExpression topLevelBounds | ||
34 | val Polyhedron polyhedron | ||
35 | val PolyhedronSaturationOperator operator | ||
36 | val Set<Relation> relevantRelations | ||
37 | List<RelationConstraintUpdater> updaters = emptyList | ||
38 | |||
39 | new(PartialInterpretation p, ModelGenerationStatistics statistics, Set<? extends Type> possibleNewDynamicTypes, | ||
40 | Map<RelationMultiplicityConstraint, UnifinishedMultiplicityQueries> unfinishedMultiplicityQueries, | ||
41 | IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> hasElementInContainmentQuery, | ||
42 | PolyhedronSolver solver, boolean propagateRelations) { | ||
43 | super(p, statistics) | ||
44 | val builder = new PolyhedronBuilder(p) | ||
45 | builder.buildPolyhedron(possibleNewDynamicTypes) | ||
46 | scopeBounds = builder.scopeBounds | ||
47 | topLevelBounds = builder.topLevelBounds | ||
48 | polyhedron = builder.polyhedron | ||
49 | operator = solver.createSaturationOperator(polyhedron) | ||
50 | if (propagateRelations) { | ||
51 | propagateAllScopeConstraints() | ||
52 | val maximumNumberOfNewNodes = topLevelBounds.upperBound | ||
53 | if (maximumNumberOfNewNodes === null) { | ||
54 | throw new IllegalStateException("Could not determine maximum number of new nodes, it may be unbounded") | ||
55 | } | ||
56 | if (maximumNumberOfNewNodes <= 0) { | ||
57 | throw new IllegalStateException("Maximum number of new nodes is not positive") | ||
58 | } | ||
59 | builder.buildMultiplicityConstraints(unfinishedMultiplicityQueries, hasElementInContainmentQuery, | ||
60 | maximumNumberOfNewNodes) | ||
61 | relevantRelations = builder.relevantRelations | ||
62 | updaters = builder.updaters | ||
63 | } else { | ||
64 | relevantRelations = emptySet | ||
65 | } | ||
66 | } | ||
67 | |||
68 | override void doPropagateAllScopeConstraints() { | ||
69 | resetBounds() | ||
70 | populatePolyhedronFromScope() | ||
71 | // println(polyhedron) | ||
72 | val result = operator.saturate() | ||
73 | // println(polyhedron) | ||
74 | if (result == PolyhedronSaturationResult.EMPTY) { | ||
75 | setScopesInvalid() | ||
76 | } else { | ||
77 | populateScopesFromPolyhedron() | ||
78 | if (result != PolyhedronSaturationResult.SATURATED) { | ||
79 | super.propagateAllScopeConstraints() | ||
80 | } | ||
81 | } | ||
82 | } | ||
83 | |||
84 | override propagateAdditionToRelation(Relation r) { | ||
85 | super.propagateAdditionToRelation(r) | ||
86 | if (relevantRelations.contains(r)) { | ||
87 | propagateAllScopeConstraints() | ||
88 | } | ||
89 | } | ||
90 | |||
91 | def resetBounds() { | ||
92 | for (dimension : polyhedron.dimensions) { | ||
93 | dimension.lowerBound = 0 | ||
94 | dimension.upperBound = null | ||
95 | } | ||
96 | for (constraint : polyhedron.constraints) { | ||
97 | constraint.lowerBound = null | ||
98 | constraint.upperBound = null | ||
99 | } | ||
100 | } | ||
101 | |||
102 | private def populatePolyhedronFromScope() { | ||
103 | topLevelBounds.tightenLowerBound(partialInterpretation.minNewElements) | ||
104 | if (partialInterpretation.maxNewElements >= 0) { | ||
105 | topLevelBounds.tightenUpperBound(partialInterpretation.maxNewElements) | ||
106 | } | ||
107 | for (pair : scopeBounds.entrySet) { | ||
108 | val scope = pair.key | ||
109 | val bounds = pair.value | ||
110 | bounds.tightenLowerBound(scope.minNewElements) | ||
111 | if (scope.maxNewElements >= 0) { | ||
112 | bounds.tightenUpperBound(scope.maxNewElements) | ||
113 | } | ||
114 | } | ||
115 | for (updater : updaters) { | ||
116 | updater.update(partialInterpretation) | ||
117 | } | ||
118 | } | ||
119 | |||
120 | private def populateScopesFromPolyhedron() { | ||
121 | checkBounds(topLevelBounds) | ||
122 | if (partialInterpretation.minNewElements > topLevelBounds.lowerBound) { | ||
123 | throw new IllegalArgumentException('''Lower bound of «topLevelBounds» smaller than top-level scope: «partialInterpretation.minNewElements»''') | ||
124 | } else if (partialInterpretation.minNewElements != topLevelBounds.lowerBound) { | ||
125 | partialInterpretation.minNewElements = topLevelBounds.lowerBound | ||
126 | } | ||
127 | val topLevelUpperBound = topLevelBounds.upperBound ?: -1 | ||
128 | if (partialInterpretation.maxNewElements >= 0 && topLevelUpperBound >= 0 && | ||
129 | partialInterpretation.maxNewElements < topLevelUpperBound) { | ||
130 | throw new IllegalArgumentException('''Upper bound of «topLevelBounds» larger than top-level scope: «partialInterpretation.maxNewElements»''') | ||
131 | } else if (partialInterpretation.maxNewElements != topLevelUpperBound) { | ||
132 | partialInterpretation.maxNewElements = topLevelUpperBound | ||
133 | } | ||
134 | for (pair : scopeBounds.entrySet) { | ||
135 | val scope = pair.key | ||
136 | val bounds = pair.value | ||
137 | checkBounds(bounds) | ||
138 | if (scope.minNewElements > bounds.lowerBound) { | ||
139 | throw new IllegalArgumentException('''Lower bound of «bounds» smaller than «scope.targetTypeInterpretation» scope: «scope.minNewElements»''') | ||
140 | } else if (scope.minNewElements != bounds.lowerBound) { | ||
141 | scope.minNewElements = bounds.lowerBound | ||
142 | } | ||
143 | val upperBound = bounds.upperBound ?: -1 | ||
144 | if (scope.maxNewElements >= 0 && upperBound >= 0 && scope.maxNewElements < upperBound) { | ||
145 | throw new IllegalArgumentException('''Upper bound of «bounds» larger than «scope.targetTypeInterpretation» scope: «scope.maxNewElements»''') | ||
146 | } else if (scope.maxNewElements != upperBound) { | ||
147 | scope.maxNewElements = upperBound | ||
148 | } | ||
149 | } | ||
150 | } | ||
151 | |||
152 | private def checkBounds(LinearBoundedExpression bounds) { | ||
153 | if (bounds.lowerBound === null) { | ||
154 | throw new IllegalArgumentException("Infinite lower bound: " + bounds) | ||
155 | } else if (bounds.lowerBound < 0) { | ||
156 | throw new IllegalArgumentException("Negative lower bound: " + bounds) | ||
157 | } | ||
158 | if (bounds.upperBound !== null && bounds.upperBound < 0) { | ||
159 | throw new IllegalArgumentException("Negative upper bound: " + bounds) | ||
160 | } | ||
161 | } | ||
162 | |||
163 | private def setScopesInvalid() { | ||
164 | partialInterpretation.minNewElements = Integer.MAX_VALUE | ||
165 | partialInterpretation.maxNewElements = 0 | ||
166 | for (scope : partialInterpretation.scopes) { | ||
167 | scope.minNewElements = Integer.MAX_VALUE | ||
168 | scope.maxNewElements = 0 | ||
169 | } | ||
170 | } | ||
171 | |||
172 | private static def <T extends IPatternMatch> getCalculatedMultiplicity(ViatraQueryMatcher<T> matcher, | ||
173 | PartialInterpretation p) { | ||
174 | val match = matcher.newEmptyMatch | ||
175 | match.set(0, p.problem) | ||
176 | match.set(1, p) | ||
177 | val iterator = matcher.streamAllMatches(match).iterator | ||
178 | if (!iterator.hasNext) { | ||
179 | return null | ||
180 | } | ||
181 | val value = iterator.next.get(2) as Integer | ||
182 | if (iterator.hasNext) { | ||
183 | throw new IllegalArgumentException("Multiplicity calculation query has more than one match") | ||
184 | } | ||
185 | value | ||
186 | } | ||
187 | |||
188 | @FinalFieldsConstructor | ||
189 | private static class PolyhedronBuilder { | ||
190 | static val INFINITY_SCALE = 10 | ||
191 | |||
192 | val PartialInterpretation p | ||
193 | |||
194 | Map<Type, Dimension> instanceCounts | ||
195 | Map<Type, Map<Dimension, Integer>> subtypeDimensions | ||
196 | Map<Map<Dimension, Integer>, LinearBoundedExpression> expressionsCache | ||
197 | Map<Type, LinearBoundedExpression> typeBounds | ||
198 | int infinity | ||
199 | ViatraQueryEngine queryEngine | ||
200 | ImmutableList.Builder<RelationConstraintUpdater> updatersBuilder | ||
201 | |||
202 | Map<Scope, LinearBoundedExpression> scopeBounds | ||
203 | LinearBoundedExpression topLevelBounds | ||
204 | Polyhedron polyhedron | ||
205 | Set<Relation> relevantRelations | ||
206 | List<RelationConstraintUpdater> updaters | ||
207 | |||
208 | def buildPolyhedron(Set<? extends Type> possibleNewDynamicTypes) { | ||
209 | instanceCounts = possibleNewDynamicTypes.toInvertedMap[new Dimension(name, 0, null)] | ||
210 | val types = p.problem.types | ||
211 | expressionsCache = Maps.newHashMapWithExpectedSize(types.size) | ||
212 | subtypeDimensions = types.toInvertedMap[findSubtypeDimensions.toInvertedMap[1]] | ||
213 | typeBounds = ImmutableMap.copyOf(subtypeDimensions.mapValues[toExpression]) | ||
214 | scopeBounds = buildScopeBounds | ||
215 | topLevelBounds = instanceCounts.values.toInvertedMap[1].toExpression | ||
216 | val dimensions = ImmutableList.copyOf(instanceCounts.values) | ||
217 | val expressionsToSaturate = ImmutableList.copyOf(scopeBounds.values) | ||
218 | polyhedron = new Polyhedron(dimensions, new ArrayList, expressionsToSaturate) | ||
219 | addCachedConstraintsToPolyhedron() | ||
220 | } | ||
221 | |||
222 | def buildMultiplicityConstraints( | ||
223 | Map<RelationMultiplicityConstraint, UnifinishedMultiplicityQueries> constraints, | ||
224 | IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> hasElementInContainmentQuery, | ||
225 | int maximumNuberOfNewNodes) { | ||
226 | infinity = maximumNuberOfNewNodes * INFINITY_SCALE | ||
227 | queryEngine = ViatraQueryEngine.on(new EMFScope(p)) | ||
228 | updatersBuilder = ImmutableList.builder | ||
229 | val containmentConstraints = constraints.entrySet.filter[key.containment].groupBy[key.targetType] | ||
230 | for (pair : containmentConstraints.entrySet) { | ||
231 | buildContainmentConstraints(pair.key, pair.value) | ||
232 | } | ||
233 | buildConstainmentRootConstraints(containmentConstraints.keySet, hasElementInContainmentQuery) | ||
234 | for (pair : constraints.entrySet) { | ||
235 | val constraint = pair.key | ||
236 | if (!constraint.containment) { | ||
237 | buildNonContainmentConstraints(constraint, pair.value) | ||
238 | } | ||
239 | } | ||
240 | buildRelevantRelations(constraints.keySet) | ||
241 | updaters = updatersBuilder.build | ||
242 | addCachedConstraintsToPolyhedron() | ||
243 | } | ||
244 | |||
245 | private def buildRelevantRelations(Set<RelationMultiplicityConstraint> constraints) { | ||
246 | val builder = ImmutableSet.builder | ||
247 | for (constraint : constraints) { | ||
248 | builder.add(constraint.relation) | ||
249 | if (constraint.inverseRelation !== null) { | ||
250 | builder.add(constraint.inverseRelation) | ||
251 | } | ||
252 | } | ||
253 | relevantRelations = builder.build | ||
254 | } | ||
255 | |||
256 | private def addCachedConstraintsToPolyhedron() { | ||
257 | val constraints = new HashSet | ||
258 | constraints.addAll(expressionsCache.values.filter(LinearConstraint)) | ||
259 | constraints.removeAll(polyhedron.constraints) | ||
260 | polyhedron.constraints.addAll(constraints) | ||
261 | } | ||
262 | |||
263 | private def buildContainmentConstraints(Type containedType, | ||
264 | List<Map.Entry<RelationMultiplicityConstraint, UnifinishedMultiplicityQueries>> constraints) { | ||
265 | val typeCoefficients = subtypeDimensions.get(containedType) | ||
266 | val orphansLowerBoundCoefficients = new HashMap(typeCoefficients) | ||
267 | val orphansUpperBoundCoefficients = new HashMap(typeCoefficients) | ||
268 | val unfinishedMultiplicitiesMatchersBuilder = ImmutableList.builder | ||
269 | val remainingContentsQueriesBuilder = ImmutableList.builder | ||
270 | for (pair : constraints) { | ||
271 | val constraint = pair.key | ||
272 | val containerCoefficients = subtypeDimensions.get(constraint.sourceType) | ||
273 | if (constraint.isUpperBoundFinite) { | ||
274 | orphansLowerBoundCoefficients.addCoefficients(-constraint.upperBound, containerCoefficients) | ||
275 | } else { | ||
276 | orphansLowerBoundCoefficients.addCoefficients(-infinity, containerCoefficients) | ||
277 | } | ||
278 | orphansUpperBoundCoefficients.addCoefficients(-constraint.lowerBound, containerCoefficients) | ||
279 | val queries = pair.value | ||
280 | if (constraint.constrainsUnfinished) { | ||
281 | if (queries.unfinishedMultiplicityQuery === null) { | ||
282 | throw new IllegalArgumentException( | ||
283 | "Containment constraints need unfinished multiplicity queries") | ||
284 | } | ||
285 | unfinishedMultiplicitiesMatchersBuilder.add( | ||
286 | queries.unfinishedMultiplicityQuery.getMatcher(queryEngine)) | ||
287 | } | ||
288 | if (queries.remainingContentsQuery === null) { | ||
289 | throw new IllegalArgumentException("Containment constraints need remaining contents queries") | ||
290 | } | ||
291 | remainingContentsQueriesBuilder.add(queries.remainingContentsQuery.getMatcher(queryEngine)) | ||
292 | } | ||
293 | val orphanLowerBound = orphansLowerBoundCoefficients.toExpression | ||
294 | val orphanUpperBound = orphansUpperBoundCoefficients.toExpression | ||
295 | val updater = new ContainmentConstraintUpdater(containedType.name, orphanLowerBound, orphanUpperBound, | ||
296 | unfinishedMultiplicitiesMatchersBuilder.build, remainingContentsQueriesBuilder.build) | ||
297 | updatersBuilder.add(updater) | ||
298 | } | ||
299 | |||
300 | private def buildConstainmentRootConstraints(Set<Type> containedTypes, | ||
301 | IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> hasElementInContainmentQuery) { | ||
302 | val matcher = hasElementInContainmentQuery.getMatcher(queryEngine) | ||
303 | val rootDimensions = Sets.newHashSet(instanceCounts.values) | ||
304 | for (type : containedTypes) { | ||
305 | val containedDimensions = subtypeDimensions.get(type).keySet | ||
306 | rootDimensions.removeAll(containedDimensions) | ||
307 | } | ||
308 | for (dimension : rootDimensions) { | ||
309 | updatersBuilder.add(new ContainmentRootConstraintUpdater(dimension, matcher)) | ||
310 | } | ||
311 | } | ||
312 | |||
313 | private def buildNonContainmentConstraints(RelationMultiplicityConstraint constraint, | ||
314 | UnifinishedMultiplicityQueries queries) { | ||
315 | if (constraint.constrainsRemainingInverse) { | ||
316 | if (queries.unfinishedMultiplicityQuery === null) { | ||
317 | throw new IllegalArgumentException("Reference constraints need unfinished multiplicity queries") | ||
318 | } | ||
319 | val unfinishedMultiplicityMatcher = queries.unfinishedMultiplicityQuery.getMatcher(queryEngine) | ||
320 | if (queries.remainingInverseMultiplicityQuery === null) { | ||
321 | throw new IllegalArgumentException( | ||
322 | "Reference constraints need remaining inverse multiplicity queries") | ||
323 | } | ||
324 | val remainingInverseMultiplicityMatcher = queries.remainingInverseMultiplicityQuery.getMatcher( | ||
325 | queryEngine) | ||
326 | val availableMultiplicityCoefficients = new HashMap | ||
327 | availableMultiplicityCoefficients.addCoefficients(constraint.inverseUpperBound, | ||
328 | subtypeDimensions.get(constraint.targetType)) | ||
329 | availableMultiplicityCoefficients.addCoefficients(-constraint.lowerBound, | ||
330 | subtypeDimensions.get(constraint.targetType)) | ||
331 | val availableMultiplicity = availableMultiplicityCoefficients.toExpression | ||
332 | updatersBuilder.add( | ||
333 | new UnfinishedMultiplicityConstraintUpdater(constraint.relation.name, availableMultiplicity, | ||
334 | unfinishedMultiplicityMatcher, remainingInverseMultiplicityMatcher)) | ||
335 | } | ||
336 | if (constraint.constrainsUnrepairable) { | ||
337 | if (queries.unrepairableMultiplicityQuery === null) { | ||
338 | throw new IllegalArgumentException("Reference constraints need unrepairable multiplicity queries") | ||
339 | } | ||
340 | val unrepairableMultiplicityMatcher = queries.unrepairableMultiplicityQuery.getMatcher(queryEngine) | ||
341 | val targetTypeCardinality = typeBounds.get(constraint.targetType) | ||
342 | updatersBuilder.add( | ||
343 | new UnrepairableMultiplicityConstraintUpdater(constraint.relation.name, targetTypeCardinality, | ||
344 | unrepairableMultiplicityMatcher)) | ||
345 | } | ||
346 | } | ||
347 | |||
348 | private def addCoefficients(Map<Dimension, Integer> accumulator, int scale, Map<Dimension, Integer> a) { | ||
349 | for (pair : a.entrySet) { | ||
350 | val dimension = pair.key | ||
351 | val currentValue = accumulator.get(pair.key) ?: 0 | ||
352 | val newValue = currentValue + scale * pair.value | ||
353 | if (newValue == 0) { | ||
354 | accumulator.remove(dimension) | ||
355 | } else { | ||
356 | accumulator.put(dimension, newValue) | ||
357 | } | ||
358 | } | ||
359 | } | ||
360 | |||
361 | private def findSubtypeDimensions(Type type) { | ||
362 | val subtypes = new HashSet | ||
363 | val dimensions = new HashSet | ||
364 | val stack = new ArrayDeque | ||
365 | stack.addLast(type) | ||
366 | while (!stack.empty) { | ||
367 | val subtype = stack.removeLast | ||
368 | if (subtypes.add(subtype)) { | ||
369 | val dimension = instanceCounts.get(subtype) | ||
370 | if (dimension !== null) { | ||
371 | dimensions.add(dimension) | ||
372 | } | ||
373 | stack.addAll(subtype.subtypes) | ||
374 | } | ||
375 | } | ||
376 | dimensions | ||
377 | } | ||
378 | |||
379 | private def toExpression(Map<Dimension, Integer> coefficients) { | ||
380 | expressionsCache.computeIfAbsent(coefficients) [ c | | ||
381 | if (c.size == 1 && c.entrySet.head.value == 1) { | ||
382 | c.entrySet.head.key | ||
383 | } else { | ||
384 | new LinearConstraint(c, null, null) | ||
385 | } | ||
386 | ] | ||
387 | } | ||
388 | |||
389 | private def buildScopeBounds() { | ||
390 | val scopeBoundsBuilder = ImmutableMap.builder | ||
391 | for (scope : p.scopes) { | ||
392 | switch (targetTypeInterpretation : scope.targetTypeInterpretation) { | ||
393 | PartialPrimitiveInterpretation: | ||
394 | throw new OperationNotSupportedException("Primitive type scopes are not yet implemented") | ||
395 | PartialComplexTypeInterpretation: { | ||
396 | val complexType = targetTypeInterpretation.interpretationOf | ||
397 | val typeBound = typeBounds.get(complexType) | ||
398 | if (typeBound === null) { | ||
399 | if (scope.minNewElements > 0) { | ||
400 | throw new IllegalArgumentException("Found scope for " + complexType.name + | ||
401 | ", but the type cannot be instantiated") | ||
402 | } | ||
403 | } else { | ||
404 | scopeBoundsBuilder.put(scope, typeBound) | ||
405 | } | ||
406 | } | ||
407 | default: | ||
408 | throw new IllegalArgumentException("Unknown PartialTypeInterpretation: " + | ||
409 | targetTypeInterpretation) | ||
410 | } | ||
411 | } | ||
412 | scopeBoundsBuilder.build | ||
413 | } | ||
414 | } | ||
415 | |||
416 | private static interface RelationConstraintUpdater { | ||
417 | def void update(PartialInterpretation p) | ||
418 | } | ||
419 | |||
420 | @FinalFieldsConstructor | ||
421 | static class ContainmentConstraintUpdater implements RelationConstraintUpdater { | ||
422 | val String name | ||
423 | val LinearBoundedExpression orphansLowerBound | ||
424 | val LinearBoundedExpression orphansUpperBound | ||
425 | val List<ViatraQueryMatcher<? extends IPatternMatch>> unfinishedMultiplicitiesMatchers | ||
426 | val List<ViatraQueryMatcher<? extends IPatternMatch>> remainingContentsQueries | ||
427 | |||
428 | override update(PartialInterpretation p) { | ||
429 | tightenLowerBound(p) | ||
430 | tightenUpperBound(p) | ||
431 | } | ||
432 | |||
433 | private def tightenLowerBound(PartialInterpretation p) { | ||
434 | var int sum = 0 | ||
435 | for (matcher : remainingContentsQueries) { | ||
436 | val value = matcher.getCalculatedMultiplicity(p) | ||
437 | if (value === null) { | ||
438 | throw new IllegalArgumentException("Remaining contents count is missing for " + name) | ||
439 | } | ||
440 | if (value == -1) { | ||
441 | // Infinite upper bound, no need to tighten. | ||
442 | return | ||
443 | } | ||
444 | sum += value | ||
445 | } | ||
446 | orphansLowerBound.tightenUpperBound(sum) | ||
447 | } | ||
448 | |||
449 | private def tightenUpperBound(PartialInterpretation p) { | ||
450 | var int sum = 0 | ||
451 | for (matcher : unfinishedMultiplicitiesMatchers) { | ||
452 | val value = matcher.getCalculatedMultiplicity(p) | ||
453 | if (value === null) { | ||
454 | throw new IllegalArgumentException("Unfinished multiplicity is missing for " + name) | ||
455 | } | ||
456 | sum += value | ||
457 | } | ||
458 | orphansUpperBound.tightenLowerBound(sum) | ||
459 | } | ||
460 | } | ||
461 | |||
462 | @FinalFieldsConstructor | ||
463 | static class ContainmentRootConstraintUpdater implements RelationConstraintUpdater { | ||
464 | val LinearBoundedExpression typeCardinality | ||
465 | val ViatraQueryMatcher<? extends IPatternMatch> hasElementInContainmentMatcher | ||
466 | |||
467 | override update(PartialInterpretation p) { | ||
468 | if (hasElementInContainmentMatcher.hasMatch(p)) { | ||
469 | typeCardinality.tightenUpperBound(0) | ||
470 | } else { | ||
471 | typeCardinality.tightenUpperBound(1) | ||
472 | } | ||
473 | } | ||
474 | |||
475 | private static def <T extends IPatternMatch> hasMatch(ViatraQueryMatcher<T> matcher, PartialInterpretation p) { | ||
476 | val match = matcher.newMatch(p.problem, p) | ||
477 | matcher.countMatches(match) != 0 | ||
478 | } | ||
479 | } | ||
480 | |||
481 | @FinalFieldsConstructor | ||
482 | static class UnfinishedMultiplicityConstraintUpdater implements RelationConstraintUpdater { | ||
483 | val String name | ||
484 | val LinearBoundedExpression availableMultiplicityExpression | ||
485 | val ViatraQueryMatcher<? extends IPatternMatch> unfinishedMultiplicityMatcher | ||
486 | val ViatraQueryMatcher<? extends IPatternMatch> remainingInverseMultiplicityMatcher | ||
487 | |||
488 | override update(PartialInterpretation p) { | ||
489 | val unfinishedMultiplicity = unfinishedMultiplicityMatcher.getCalculatedMultiplicity(p) | ||
490 | if (unfinishedMultiplicity === null) { | ||
491 | throw new IllegalArgumentException("Unfinished multiplicity is missing for " + name) | ||
492 | } | ||
493 | val remainingInverseMultiplicity = remainingInverseMultiplicityMatcher.getCalculatedMultiplicity(p) | ||
494 | if (remainingInverseMultiplicity === null) { | ||
495 | throw new IllegalArgumentException("Remaining inverse multiplicity is missing for " + name) | ||
496 | } | ||
497 | val int requiredMultiplicity = unfinishedMultiplicity - remainingInverseMultiplicity | ||
498 | availableMultiplicityExpression.tightenLowerBound(requiredMultiplicity) | ||
499 | } | ||
500 | } | ||
501 | |||
502 | @FinalFieldsConstructor | ||
503 | static class UnrepairableMultiplicityConstraintUpdater implements RelationConstraintUpdater { | ||
504 | val String name | ||
505 | val LinearBoundedExpression targetCardinalityExpression | ||
506 | val ViatraQueryMatcher<? extends IPatternMatch> unrepairableMultiplicityMatcher | ||
507 | |||
508 | override update(PartialInterpretation p) { | ||
509 | val value = unrepairableMultiplicityMatcher.getCalculatedMultiplicity(p) | ||
510 | if (value === null) { | ||
511 | throw new IllegalArgumentException("Unrepairable multiplicity is missing for " + name) | ||
512 | } | ||
513 | targetCardinalityExpression.tightenLowerBound(value) | ||
514 | } | ||
515 | } | ||
516 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/PolyhedronSolver.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/PolyhedronSolver.xtend new file mode 100644 index 00000000..9c6cb82e --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/PolyhedronSolver.xtend | |||
@@ -0,0 +1,123 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality | ||
2 | |||
3 | import java.util.List | ||
4 | import java.util.Map | ||
5 | import org.eclipse.xtend.lib.annotations.Accessors | ||
6 | import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor | ||
7 | |||
8 | interface PolyhedronSolver { | ||
9 | def PolyhedronSaturationOperator createSaturationOperator(Polyhedron polyhedron) | ||
10 | } | ||
11 | |||
12 | enum PolyhedronSaturationResult { | ||
13 | SATURATED, | ||
14 | EMPTY, | ||
15 | UNKNOWN | ||
16 | } | ||
17 | |||
18 | interface PolyhedronSaturationOperator extends AutoCloseable { | ||
19 | def Polyhedron getPolyhedron() | ||
20 | |||
21 | def PolyhedronSaturationResult saturate() | ||
22 | } | ||
23 | |||
24 | @FinalFieldsConstructor | ||
25 | @Accessors | ||
26 | class Polyhedron { | ||
27 | /** | ||
28 | * The list of dimensions (variables) for this polyhedron. | ||
29 | * | ||
30 | * This list must not be modified after the polyhedron was created. | ||
31 | * However, lower and upper bounds of the dimensions may be changed. | ||
32 | * | ||
33 | * Names of dimensions in this list are assumed to be unique. | ||
34 | */ | ||
35 | val List<Dimension> dimensions | ||
36 | |||
37 | /** | ||
38 | * The list of constraints defining this polyhedron. | ||
39 | * | ||
40 | * The list and its elements may be freely modified. | ||
41 | */ | ||
42 | val List<LinearConstraint> constraints | ||
43 | |||
44 | /** | ||
45 | * The list of constraints that should be saturated (tightened) | ||
46 | * when a {@link PolyhedronSaturationOperator} is invoked. | ||
47 | * | ||
48 | * This list may be freely modified. | ||
49 | * | ||
50 | * Place all dimensions and constraints here to saturate all the bounds. | ||
51 | */ | ||
52 | val List<LinearBoundedExpression> expressionsToSaturate | ||
53 | |||
54 | override toString() ''' | ||
55 | Dimensions: | ||
56 | «FOR dimension : dimensions» | ||
57 | «dimension» | ||
58 | «ENDFOR» | ||
59 | Constraints: | ||
60 | «FOR constraint : constraints» | ||
61 | «constraint» | ||
62 | «ENDFOR» | ||
63 | ''' | ||
64 | |||
65 | } | ||
66 | |||
67 | @Accessors | ||
68 | abstract class LinearBoundedExpression { | ||
69 | var Integer lowerBound | ||
70 | var Integer upperBound | ||
71 | |||
72 | def void tightenLowerBound(Integer tighterBound) { | ||
73 | if (lowerBound === null || (tighterBound !== null && lowerBound < tighterBound)) { | ||
74 | lowerBound = tighterBound | ||
75 | } | ||
76 | } | ||
77 | |||
78 | def void tightenUpperBound(Integer tighterBound) { | ||
79 | if (upperBound === null || (tighterBound !== null && upperBound > tighterBound)) { | ||
80 | upperBound = tighterBound | ||
81 | } | ||
82 | } | ||
83 | } | ||
84 | |||
85 | @Accessors | ||
86 | class Dimension extends LinearBoundedExpression { | ||
87 | val String name | ||
88 | |||
89 | @FinalFieldsConstructor | ||
90 | new() { | ||
91 | } | ||
92 | |||
93 | new(String name, Integer lowerBound, Integer upperBound) { | ||
94 | this(name) | ||
95 | this.lowerBound = lowerBound | ||
96 | this.upperBound = upperBound | ||
97 | } | ||
98 | |||
99 | override toString() { | ||
100 | '''«IF lowerBound !== null»«lowerBound» <= «ENDIF»«name»«IF upperBound !== null» <= «upperBound»«ENDIF»''' | ||
101 | } | ||
102 | |||
103 | } | ||
104 | |||
105 | @Accessors | ||
106 | class LinearConstraint extends LinearBoundedExpression { | ||
107 | val Map<Dimension, Integer> coefficients | ||
108 | |||
109 | @FinalFieldsConstructor | ||
110 | new() { | ||
111 | } | ||
112 | |||
113 | new(Map<Dimension, Integer> coefficients, Integer lowerBound, Integer upperBound) { | ||
114 | this(coefficients) | ||
115 | this.lowerBound = lowerBound | ||
116 | this.upperBound = upperBound | ||
117 | } | ||
118 | |||
119 | override toString() { | ||
120 | '''«IF lowerBound !== null»«lowerBound» <= «ENDIF»«FOR pair : coefficients.entrySet SEPARATOR " + "»«IF pair.value != 1»«pair.value» * «ENDIF»«pair.key.name»«ENDFOR»«IF upperBound !== null» <= «upperBound»«ENDIF»''' | ||
121 | } | ||
122 | |||
123 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/RelationConstraintCalculator.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/RelationConstraintCalculator.xtend new file mode 100644 index 00000000..52a390a8 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/RelationConstraintCalculator.xtend | |||
@@ -0,0 +1,134 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality | ||
2 | |||
3 | import com.google.common.collect.ImmutableList | ||
4 | import com.google.common.collect.ImmutableSet | ||
5 | import hu.bme.mit.inf.dslreasoner.ecore2logic.ecore2logicannotations.InverseRelationAssertion | ||
6 | import hu.bme.mit.inf.dslreasoner.ecore2logic.ecore2logicannotations.LowerMultiplicityAssertion | ||
7 | import hu.bme.mit.inf.dslreasoner.ecore2logic.ecore2logicannotations.UpperMultiplicityAssertion | ||
8 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.ComplexTypeReference | ||
9 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Relation | ||
10 | import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem | ||
11 | import java.util.HashMap | ||
12 | import java.util.List | ||
13 | import org.eclipse.xtend.lib.annotations.Data | ||
14 | |||
15 | @Data | ||
16 | class RelationConstraints { | ||
17 | val List<RelationMultiplicityConstraint> multiplicityConstraints | ||
18 | } | ||
19 | |||
20 | @Data | ||
21 | class RelationMultiplicityConstraint { | ||
22 | Relation relation | ||
23 | Relation inverseRelation | ||
24 | boolean containment | ||
25 | boolean container | ||
26 | int lowerBound | ||
27 | int upperBound | ||
28 | int inverseUpperBound | ||
29 | |||
30 | def isUpperBoundFinite() { | ||
31 | upperBound >= 0 | ||
32 | } | ||
33 | |||
34 | private def isInverseUpperBoundFinite() { | ||
35 | inverseUpperBound >= 0 | ||
36 | } | ||
37 | |||
38 | private def canHaveMultipleSourcesPerTarget() { | ||
39 | inverseUpperBound != 1 | ||
40 | } | ||
41 | |||
42 | def constrainsUnfinished() { | ||
43 | lowerBound >= 1 && (!container || lowerBound >= 2) | ||
44 | } | ||
45 | |||
46 | def constrainsUnrepairable() { | ||
47 | constrainsUnfinished && canHaveMultipleSourcesPerTarget | ||
48 | } | ||
49 | |||
50 | def constrainsRemainingInverse() { | ||
51 | lowerBound >= 1 && !containment && inverseUpperBoundFinite | ||
52 | } | ||
53 | |||
54 | def constrainsRemainingContents() { | ||
55 | containment | ||
56 | } | ||
57 | |||
58 | def isActive() { | ||
59 | constrainsUnfinished || constrainsUnrepairable || constrainsRemainingInverse || constrainsRemainingContents | ||
60 | } | ||
61 | |||
62 | def getSourceType() { | ||
63 | getParamType(0) | ||
64 | } | ||
65 | |||
66 | def getTargetType() { | ||
67 | getParamType(1) | ||
68 | } | ||
69 | |||
70 | private def getParamType(int i) { | ||
71 | val parameters = relation.parameters | ||
72 | if (i < parameters.size) { | ||
73 | val firstParam = parameters.get(i) | ||
74 | if (firstParam instanceof ComplexTypeReference) { | ||
75 | return firstParam.referred | ||
76 | } | ||
77 | } | ||
78 | throw new IllegalArgumentException("Constraint with unknown source type") | ||
79 | } | ||
80 | } | ||
81 | |||
82 | class RelationConstraintCalculator { | ||
83 | def calculateRelationConstraints(LogicProblem problem) { | ||
84 | val containmentRelations = switch (problem.containmentHierarchies.size) { | ||
85 | case 0: | ||
86 | <Relation>emptySet | ||
87 | case 1: | ||
88 | ImmutableSet.copyOf(problem.containmentHierarchies.head.containmentRelations) | ||
89 | default: | ||
90 | throw new IllegalArgumentException("Only a single containment hierarchy is supported") | ||
91 | } | ||
92 | val inverseRelations = new HashMap<Relation, Relation> | ||
93 | val lowerMultiplicities = new HashMap<Relation, Integer> | ||
94 | val upperMultiplicities = new HashMap<Relation, Integer> | ||
95 | for (relation : problem.relations) { | ||
96 | lowerMultiplicities.put(relation, 0) | ||
97 | upperMultiplicities.put(relation, -1) | ||
98 | } | ||
99 | for (annotation : problem.annotations) { | ||
100 | switch (annotation) { | ||
101 | InverseRelationAssertion: { | ||
102 | inverseRelations.put(annotation.inverseA, annotation.inverseB) | ||
103 | inverseRelations.put(annotation.inverseB, annotation.inverseA) | ||
104 | } | ||
105 | LowerMultiplicityAssertion: | ||
106 | lowerMultiplicities.put(annotation.relation, annotation.lower) | ||
107 | UpperMultiplicityAssertion: | ||
108 | upperMultiplicities.put(annotation.relation, annotation.upper) | ||
109 | } | ||
110 | } | ||
111 | val multiplicityConstraintsBuilder = ImmutableList.builder() | ||
112 | for (relation : problem.relations) { | ||
113 | val containment = containmentRelations.contains(relation) | ||
114 | val lowerMultiplicity = lowerMultiplicities.get(relation) | ||
115 | val upperMultiplicity = upperMultiplicities.get(relation) | ||
116 | var container = false | ||
117 | var inverseUpperMultiplicity = -1 | ||
118 | val inverseRelation = inverseRelations.get(relation) | ||
119 | if (inverseRelation !== null) { | ||
120 | inverseUpperMultiplicity = upperMultiplicities.get(relation) | ||
121 | container = containmentRelations.contains(inverseRelation) | ||
122 | } | ||
123 | val constraint = new RelationMultiplicityConstraint(relation, inverseRelation, containment, container, | ||
124 | lowerMultiplicity, upperMultiplicity, inverseUpperMultiplicity) | ||
125 | if (constraint.isActive) { | ||
126 | if (relation.parameters.size != 2) { | ||
127 | throw new IllegalArgumentException('''Relation «relation.name» has multiplicity or containment constraints, but it is not binary''') | ||
128 | } | ||
129 | multiplicityConstraintsBuilder.add(constraint) | ||
130 | } | ||
131 | } | ||
132 | new RelationConstraints(multiplicityConstraintsBuilder.build) | ||
133 | } | ||
134 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/ScopePropagator.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/ScopePropagator.xtend new file mode 100644 index 00000000..0bdb202e --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/ScopePropagator.xtend | |||
@@ -0,0 +1,109 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality | ||
2 | |||
3 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Relation | ||
4 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.ModelGenerationStatistics | ||
5 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialComplexTypeInterpretation | ||
6 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | ||
7 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialTypeInterpratation | ||
8 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.Scope | ||
9 | import java.util.HashMap | ||
10 | import java.util.HashSet | ||
11 | import java.util.Map | ||
12 | import java.util.Set | ||
13 | import org.eclipse.xtend.lib.annotations.Accessors | ||
14 | |||
15 | class ScopePropagator { | ||
16 | @Accessors(PROTECTED_GETTER) val PartialInterpretation partialInterpretation | ||
17 | val ModelGenerationStatistics statistics | ||
18 | val Map<PartialTypeInterpratation, Scope> type2Scope | ||
19 | @Accessors(PROTECTED_GETTER) val Map<Scope, Set<Scope>> superScopes | ||
20 | @Accessors(PROTECTED_GETTER) val Map<Scope, Set<Scope>> subScopes | ||
21 | |||
22 | new(PartialInterpretation p, ModelGenerationStatistics statistics) { | ||
23 | partialInterpretation = p | ||
24 | this.statistics = statistics | ||
25 | type2Scope = new HashMap | ||
26 | for (scope : p.scopes) { | ||
27 | type2Scope.put(scope.targetTypeInterpretation, scope) | ||
28 | } | ||
29 | |||
30 | superScopes = new HashMap | ||
31 | subScopes = new HashMap | ||
32 | for (scope : p.scopes) { | ||
33 | superScopes.put(scope, new HashSet) | ||
34 | subScopes.put(scope, new HashSet) | ||
35 | } | ||
36 | |||
37 | for (scope : p.scopes) { | ||
38 | val target = scope.targetTypeInterpretation | ||
39 | if (target instanceof PartialComplexTypeInterpretation) { | ||
40 | val supertypeInterpretations = target.supertypeInterpretation | ||
41 | for (supertypeInterpretation : supertypeInterpretations) { | ||
42 | val supertypeScope = type2Scope.get(supertypeInterpretation) | ||
43 | superScopes.get(scope).add(supertypeScope) | ||
44 | subScopes.get(supertypeScope).add(scope) | ||
45 | } | ||
46 | } | ||
47 | } | ||
48 | var boolean changed | ||
49 | do { | ||
50 | changed = false | ||
51 | for (scope : p.scopes) { | ||
52 | val subScopeSet = subScopes.get(scope) | ||
53 | val superScopeSet = superScopes.get(scope) | ||
54 | for (subScope : subScopeSet) { | ||
55 | changed = changed || superScopes.get(subScope).addAll(superScopeSet) | ||
56 | } | ||
57 | for (superScope : superScopeSet) { | ||
58 | changed = changed || subScopes.get(superScope).addAll(subScopeSet) | ||
59 | } | ||
60 | } | ||
61 | } while (changed) | ||
62 | } | ||
63 | |||
64 | def propagateAllScopeConstraints() { | ||
65 | statistics.incrementScopePropagationCount() | ||
66 | doPropagateAllScopeConstraints() | ||
67 | } | ||
68 | |||
69 | protected def void doPropagateAllScopeConstraints() { | ||
70 | // Nothing to propagate. | ||
71 | } | ||
72 | |||
73 | def propagateAdditionToType(PartialTypeInterpratation t) { | ||
74 | // println('''Adding to «(t as PartialComplexTypeInterpretation).interpretationOf.name»''') | ||
75 | val targetScope = type2Scope.get(t) | ||
76 | targetScope.removeOne | ||
77 | val sups = superScopes.get(targetScope) | ||
78 | sups.forEach[removeOne] | ||
79 | if (this.partialInterpretation.minNewElements > 0) { | ||
80 | this.partialInterpretation.minNewElements = this.partialInterpretation.minNewElements - 1 | ||
81 | } | ||
82 | if (this.partialInterpretation.maxNewElements > 0) { | ||
83 | this.partialInterpretation.maxNewElements = this.partialInterpretation.maxNewElements - 1 | ||
84 | } else if (this.partialInterpretation.maxNewElements === 0) { | ||
85 | throw new IllegalArgumentException('''Inconsistent object creation: lower node limit is 0!''') | ||
86 | } | ||
87 | propagateAllScopeConstraints | ||
88 | |||
89 | // println('''Target Scope: «targetScope.minNewElements» - «targetScope.maxNewElements»''') | ||
90 | // println(''' «this.partialInterpretation.minNewElements» - «this.partialInterpretation.maxNewElements»''') | ||
91 | // this.partialInterpretation.scopes.forEach[println(''' «(it.targetTypeInterpretation as PartialComplexTypeInterpretation).interpretationOf.name»: «it.minNewElements»-«it.maxNewElements»''')] | ||
92 | // println('''All constraints are propagated upon increasing «(t as PartialComplexTypeInterpretation).interpretationOf.name»''') | ||
93 | } | ||
94 | |||
95 | def void propagateAdditionToRelation(Relation r) { | ||
96 | // Nothing to propagate. | ||
97 | } | ||
98 | |||
99 | private def removeOne(Scope scope) { | ||
100 | if (scope.maxNewElements === 0) { | ||
101 | throw new IllegalArgumentException('''Inconsistent object creation: «scope.targetTypeInterpretation»''') | ||
102 | } else if (scope.maxNewElements > 0) { | ||
103 | scope.maxNewElements = scope.maxNewElements - 1 | ||
104 | } | ||
105 | if (scope.minNewElements > 0) { | ||
106 | scope.minNewElements = scope.minNewElements - 1 | ||
107 | } | ||
108 | } | ||
109 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/ScopePropagatorStrategy.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/ScopePropagatorStrategy.xtend new file mode 100644 index 00000000..b0ed75cb --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/ScopePropagatorStrategy.xtend | |||
@@ -0,0 +1,64 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality | ||
2 | |||
3 | import org.eclipse.xtend.lib.annotations.Data | ||
4 | import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor | ||
5 | |||
6 | enum PolyhedralScopePropagatorConstraints { | ||
7 | TypeHierarchy, | ||
8 | Relational | ||
9 | } | ||
10 | |||
11 | enum PolyhedralScopePropagatorSolver { | ||
12 | Z3Real, | ||
13 | Z3Integer, | ||
14 | Cbc, | ||
15 | Clp | ||
16 | } | ||
17 | |||
18 | abstract class ScopePropagatorStrategy { | ||
19 | public static val Count = new Simple("Count") | ||
20 | |||
21 | public static val BasicTypeHierarchy = new Simple("BasicTypeHierarchy") | ||
22 | |||
23 | private new() { | ||
24 | } | ||
25 | |||
26 | def boolean requiresUpperBoundIndexing() | ||
27 | |||
28 | static class Simple extends ScopePropagatorStrategy { | ||
29 | val String name | ||
30 | |||
31 | @FinalFieldsConstructor | ||
32 | private new() { | ||
33 | } | ||
34 | |||
35 | override requiresUpperBoundIndexing() { | ||
36 | false | ||
37 | } | ||
38 | |||
39 | override toString() { | ||
40 | name | ||
41 | } | ||
42 | } | ||
43 | |||
44 | @Data | ||
45 | static class Polyhedral extends ScopePropagatorStrategy { | ||
46 | public static val UNLIMITED_TIME = -1 | ||
47 | |||
48 | val PolyhedralScopePropagatorConstraints constraints | ||
49 | val PolyhedralScopePropagatorSolver solver | ||
50 | val double timeoutSeconds | ||
51 | |||
52 | @FinalFieldsConstructor | ||
53 | new() { | ||
54 | } | ||
55 | |||
56 | new(PolyhedralScopePropagatorConstraints constraints, PolyhedralScopePropagatorSolver solver) { | ||
57 | this(constraints, solver, UNLIMITED_TIME) | ||
58 | } | ||
59 | |||
60 | override requiresUpperBoundIndexing() { | ||
61 | constraints == PolyhedralScopePropagatorConstraints.Relational | ||
62 | } | ||
63 | } | ||
64 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/TypeHierarchyScopePropagator.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/TypeHierarchyScopePropagator.xtend new file mode 100644 index 00000000..be8ef00a --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/TypeHierarchyScopePropagator.xtend | |||
@@ -0,0 +1,77 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality | ||
2 | |||
3 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.ModelGenerationStatistics | ||
4 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | ||
5 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.Scope | ||
6 | |||
7 | class TypeHierarchyScopePropagator extends ScopePropagator { | ||
8 | |||
9 | new(PartialInterpretation p, ModelGenerationStatistics statistics) { | ||
10 | super(p, statistics) | ||
11 | } | ||
12 | |||
13 | protected override doPropagateAllScopeConstraints() { | ||
14 | var boolean hadChanged | ||
15 | do { | ||
16 | hadChanged = false | ||
17 | for (superScopeEntry : superScopes.entrySet) { | ||
18 | val sub = superScopeEntry.key | ||
19 | hadChanged = propagateLowerLimitUp(sub, partialInterpretation) || hadChanged | ||
20 | hadChanged = propagateUpperLimitDown(sub, partialInterpretation) || hadChanged | ||
21 | for (sup : superScopeEntry.value) { | ||
22 | hadChanged = propagateLowerLimitUp(sub, sup) || hadChanged | ||
23 | hadChanged = propagateUpperLimitDown(sub, sup) || hadChanged | ||
24 | } | ||
25 | } | ||
26 | } while (hadChanged) | ||
27 | } | ||
28 | |||
29 | private def propagateLowerLimitUp(Scope subScope, Scope superScope) { | ||
30 | if (subScope.minNewElements > superScope.minNewElements) { | ||
31 | superScope.minNewElements = subScope.minNewElements | ||
32 | return true | ||
33 | } else { | ||
34 | return false | ||
35 | } | ||
36 | } | ||
37 | |||
38 | private def propagateUpperLimitDown(Scope subScope, Scope superScope) { | ||
39 | if (superScope.maxNewElements >= 0 && | ||
40 | (superScope.maxNewElements < subScope.maxNewElements || subScope.maxNewElements < 0)) { | ||
41 | // println(''' | ||
42 | // «(subScope.targetTypeInterpretation as PartialComplexTypeInterpretation).interpretationOf.name» -> «(superScope.targetTypeInterpretation as PartialComplexTypeInterpretation).interpretationOf.name» | ||
43 | // subScope.maxNewElements «subScope.maxNewElements» = superScope.maxNewElements «superScope.maxNewElements» | ||
44 | // ''') | ||
45 | subScope.maxNewElements = superScope.maxNewElements | ||
46 | return true | ||
47 | } else { | ||
48 | return false | ||
49 | } | ||
50 | } | ||
51 | |||
52 | private def propagateLowerLimitUp(Scope subScope, PartialInterpretation p) { | ||
53 | if (subScope.minNewElements > p.minNewElements) { | ||
54 | // println(''' | ||
55 | // «(subScope.targetTypeInterpretation as PartialComplexTypeInterpretation).interpretationOf.name» -> nodes | ||
56 | // p.minNewElements «p.minNewElements» = subScope.minNewElements «subScope.minNewElements» | ||
57 | // ''') | ||
58 | p.minNewElements = subScope.minNewElements | ||
59 | return true | ||
60 | } else { | ||
61 | return false | ||
62 | } | ||
63 | } | ||
64 | |||
65 | private def propagateUpperLimitDown(Scope subScope, PartialInterpretation p) { | ||
66 | if (p.maxNewElements >= 0 && (p.maxNewElements < subScope.maxNewElements || subScope.maxNewElements < 0)) { | ||
67 | // println(''' | ||
68 | // «(subScope.targetTypeInterpretation as PartialComplexTypeInterpretation).interpretationOf.name» -> nodes | ||
69 | // subScope.maxNewElements «subScope.maxNewElements» = p.maxNewElements «p.maxNewElements» | ||
70 | // ''') | ||
71 | subScope.maxNewElements = p.maxNewElements | ||
72 | return true | ||
73 | } else { | ||
74 | return false | ||
75 | } | ||
76 | } | ||
77 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/Z3PolyhedronSolver.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/Z3PolyhedronSolver.xtend new file mode 100644 index 00000000..23444956 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/Z3PolyhedronSolver.xtend | |||
@@ -0,0 +1,248 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality | ||
2 | |||
3 | import com.microsoft.z3.AlgebraicNum | ||
4 | import com.microsoft.z3.ArithExpr | ||
5 | import com.microsoft.z3.Context | ||
6 | import com.microsoft.z3.Expr | ||
7 | import com.microsoft.z3.IntNum | ||
8 | import com.microsoft.z3.Optimize | ||
9 | import com.microsoft.z3.RatNum | ||
10 | import com.microsoft.z3.Status | ||
11 | import com.microsoft.z3.Symbol | ||
12 | import java.math.BigDecimal | ||
13 | import java.math.MathContext | ||
14 | import java.math.RoundingMode | ||
15 | import java.util.Map | ||
16 | import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor | ||
17 | |||
18 | class Z3PolyhedronSolver implements PolyhedronSolver { | ||
19 | val boolean lpRelaxation | ||
20 | val double timeoutSeconds | ||
21 | |||
22 | @FinalFieldsConstructor | ||
23 | new() { | ||
24 | } | ||
25 | |||
26 | new() { | ||
27 | this(false, -1) | ||
28 | } | ||
29 | |||
30 | override createSaturationOperator(Polyhedron polyhedron) { | ||
31 | new Z3SaturationOperator(polyhedron, lpRelaxation, timeoutSeconds) | ||
32 | } | ||
33 | } | ||
34 | |||
35 | class Z3SaturationOperator extends AbstractPolyhedronSaturationOperator { | ||
36 | static val INFINITY_SYMBOL_NAME = "oo" | ||
37 | static val MULT_SYMBOL_NAME = "*" | ||
38 | static val TIMEOUT_SYMBOL_NAME = "timeout" | ||
39 | static val INTEGER_PRECISION = new BigDecimal(Integer.MAX_VALUE).precision | ||
40 | static val ROUND_DOWN = new MathContext(INTEGER_PRECISION, RoundingMode.FLOOR) | ||
41 | static val ROUND_UP = new MathContext(INTEGER_PRECISION, RoundingMode.CEILING) | ||
42 | // The interval isolating the number is smaller than 1/10^precision. | ||
43 | static val ALGEBRAIC_NUMBER_ROUNDING = 0 | ||
44 | |||
45 | extension val Context context | ||
46 | val Symbol infinitySymbol | ||
47 | val Symbol multSymbol | ||
48 | val Map<Dimension, ArithExpr> variables | ||
49 | val int timeoutMilliseconds | ||
50 | |||
51 | new(Polyhedron polyhedron, boolean lpRelaxation, double timeoutSeconds) { | ||
52 | super(polyhedron) | ||
53 | context = new Context | ||
54 | infinitySymbol = context.mkSymbol(INFINITY_SYMBOL_NAME) | ||
55 | multSymbol = context.mkSymbol(MULT_SYMBOL_NAME) | ||
56 | variables = polyhedron.dimensions.toInvertedMap [ dimension | | ||
57 | val name = dimension.name | ||
58 | if (lpRelaxation) { | ||
59 | mkRealConst(name) | ||
60 | } else { | ||
61 | mkIntConst(name) | ||
62 | } | ||
63 | ] | ||
64 | timeoutMilliseconds = Math.ceil(timeoutSeconds * 1000) as int | ||
65 | } | ||
66 | |||
67 | override doSaturate() { | ||
68 | val status = executeSolver() | ||
69 | convertStatusToSaturationResult(status) | ||
70 | } | ||
71 | |||
72 | private def convertStatusToSaturationResult(Status status) { | ||
73 | switch (status) { | ||
74 | case SATISFIABLE: | ||
75 | PolyhedronSaturationResult.SATURATED | ||
76 | case UNSATISFIABLE: | ||
77 | PolyhedronSaturationResult.EMPTY | ||
78 | case UNKNOWN: | ||
79 | PolyhedronSaturationResult.UNKNOWN | ||
80 | default: | ||
81 | throw new IllegalArgumentException("Unknown Status: " + status) | ||
82 | } | ||
83 | } | ||
84 | |||
85 | private def executeSolver() { | ||
86 | for (expressionToSaturate : polyhedron.expressionsToSaturate) { | ||
87 | val expr = expressionToSaturate.toExpr | ||
88 | val lowerResult = saturateLowerBound(expr, expressionToSaturate) | ||
89 | if (lowerResult != Status.SATISFIABLE) { | ||
90 | return lowerResult | ||
91 | } | ||
92 | val upperResult = saturateUpperBound(expr, expressionToSaturate) | ||
93 | if (upperResult != Status.SATISFIABLE) { | ||
94 | return upperResult | ||
95 | } | ||
96 | } | ||
97 | Status.SATISFIABLE | ||
98 | } | ||
99 | |||
100 | private def saturateLowerBound(ArithExpr expr, LinearBoundedExpression expressionToSaturate) { | ||
101 | val optimize = prepareOptimize | ||
102 | val handle = optimize.MkMinimize(expr) | ||
103 | val status = optimize.Check() | ||
104 | if (status == Status.SATISFIABLE) { | ||
105 | val value = switch (resultExpr : handle.lower) { | ||
106 | IntNum: | ||
107 | resultExpr.getInt() | ||
108 | RatNum: | ||
109 | floor(resultExpr) | ||
110 | AlgebraicNum: | ||
111 | floor(resultExpr.toLower(ALGEBRAIC_NUMBER_ROUNDING)) | ||
112 | default: | ||
113 | if (isNegativeInfinity(resultExpr)) { | ||
114 | null | ||
115 | } else { | ||
116 | throw new IllegalArgumentException("Integer result expected, got: " + resultExpr) | ||
117 | } | ||
118 | } | ||
119 | expressionToSaturate.lowerBound = value | ||
120 | } | ||
121 | status | ||
122 | } | ||
123 | |||
124 | private def floor(RatNum ratNum) { | ||
125 | val numerator = new BigDecimal(ratNum.numerator.bigInteger) | ||
126 | val denominator = new BigDecimal(ratNum.denominator.bigInteger) | ||
127 | numerator.divide(denominator, ROUND_DOWN).setScale(0, RoundingMode.FLOOR).intValue | ||
128 | } | ||
129 | |||
130 | private def saturateUpperBound(ArithExpr expr, LinearBoundedExpression expressionToSaturate) { | ||
131 | val optimize = prepareOptimize | ||
132 | val handle = optimize.MkMaximize(expr) | ||
133 | val status = optimize.Check() | ||
134 | if (status == Status.SATISFIABLE) { | ||
135 | val value = switch (resultExpr : handle.upper) { | ||
136 | IntNum: | ||
137 | resultExpr.getInt() | ||
138 | RatNum: | ||
139 | ceil(resultExpr) | ||
140 | AlgebraicNum: | ||
141 | ceil(resultExpr.toUpper(ALGEBRAIC_NUMBER_ROUNDING)) | ||
142 | default: | ||
143 | if (isPositiveInfinity(resultExpr)) { | ||
144 | null | ||
145 | } else { | ||
146 | throw new IllegalArgumentException("Integer result expected, got: " + resultExpr) | ||
147 | } | ||
148 | } | ||
149 | expressionToSaturate.upperBound = value | ||
150 | } | ||
151 | status | ||
152 | } | ||
153 | |||
154 | private def ceil(RatNum ratNum) { | ||
155 | val numerator = new BigDecimal(ratNum.numerator.bigInteger) | ||
156 | val denominator = new BigDecimal(ratNum.denominator.bigInteger) | ||
157 | numerator.divide(denominator, ROUND_UP).setScale(0, RoundingMode.CEILING).intValue | ||
158 | } | ||
159 | |||
160 | private def isPositiveInfinity(Expr expr) { | ||
161 | expr.app && expr.getFuncDecl.name == infinitySymbol | ||
162 | } | ||
163 | |||
164 | private def isNegativeInfinity(Expr expr) { | ||
165 | // Negative infinity is represented as (* (- 1) oo) | ||
166 | if (!expr.app || expr.getFuncDecl.name != multSymbol || expr.numArgs != 2) { | ||
167 | return false | ||
168 | } | ||
169 | isPositiveInfinity(expr.args.get(1)) | ||
170 | } | ||
171 | |||
172 | private def prepareOptimize() { | ||
173 | val optimize = mkOptimize() | ||
174 | if (timeoutMilliseconds >= 0) { | ||
175 | val params = mkParams() | ||
176 | // We cannot turn TIMEOUT_SYMBOL_NAME into a Symbol in the constructor, | ||
177 | // because there is no add(Symbol, int) overload. | ||
178 | params.add(TIMEOUT_SYMBOL_NAME, timeoutMilliseconds) | ||
179 | optimize.parameters = params | ||
180 | } | ||
181 | assertConstraints(optimize) | ||
182 | optimize | ||
183 | } | ||
184 | |||
185 | private def assertConstraints(Optimize it) { | ||
186 | for (pair : variables.entrySet) { | ||
187 | assertBounds(pair.value, pair.key) | ||
188 | } | ||
189 | for (constraint : nonTrivialConstraints) { | ||
190 | val expr = createLinearCombination(constraint.coefficients) | ||
191 | assertBounds(expr, constraint) | ||
192 | } | ||
193 | } | ||
194 | |||
195 | private def assertBounds(Optimize it, ArithExpr expression, LinearBoundedExpression bounds) { | ||
196 | val lowerBound = bounds.lowerBound | ||
197 | val upperBound = bounds.upperBound | ||
198 | if (lowerBound == upperBound) { | ||
199 | if (lowerBound === null) { | ||
200 | return | ||
201 | } | ||
202 | Assert(mkEq(expression, mkInt(lowerBound))) | ||
203 | } else { | ||
204 | if (lowerBound !== null) { | ||
205 | Assert(mkGe(expression, mkInt(lowerBound))) | ||
206 | } | ||
207 | if (upperBound !== null) { | ||
208 | Assert(mkLe(expression, mkInt(upperBound))) | ||
209 | } | ||
210 | } | ||
211 | } | ||
212 | |||
213 | private def toExpr(LinearBoundedExpression linearBoundedExpression) { | ||
214 | switch (linearBoundedExpression) { | ||
215 | Dimension: variables.get(linearBoundedExpression) | ||
216 | LinearConstraint: createLinearCombination(linearBoundedExpression.coefficients) | ||
217 | default: throw new IllegalArgumentException("Unknown linear bounded expression:" + linearBoundedExpression) | ||
218 | } | ||
219 | } | ||
220 | |||
221 | private def createLinearCombination(Map<Dimension, Integer> coefficients) { | ||
222 | val size = coefficients.size | ||
223 | if (size == 0) { | ||
224 | return mkInt(0) | ||
225 | } | ||
226 | val array = newArrayOfSize(size) | ||
227 | var int i = 0 | ||
228 | for (pair : coefficients.entrySet) { | ||
229 | val variable = variables.get(pair.key) | ||
230 | if (variable === null) { | ||
231 | throw new IllegalArgumentException("Unknown dimension: " + pair.key.name) | ||
232 | } | ||
233 | val coefficient = pair.value | ||
234 | val term = if (coefficient == 1) { | ||
235 | variable | ||
236 | } else { | ||
237 | mkMul(mkInt(coefficient), variable) | ||
238 | } | ||
239 | array.set(i, term) | ||
240 | i++ | ||
241 | } | ||
242 | mkAdd(array) | ||
243 | } | ||
244 | |||
245 | override close() throws Exception { | ||
246 | context.close() | ||
247 | } | ||
248 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/Interval.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/Interval.xtend new file mode 100644 index 00000000..691c8783 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/Interval.xtend | |||
@@ -0,0 +1,584 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.interval | ||
2 | |||
3 | import java.math.BigDecimal | ||
4 | import java.math.MathContext | ||
5 | import java.math.RoundingMode | ||
6 | import org.eclipse.xtend.lib.annotations.Data | ||
7 | |||
8 | abstract class Interval implements Comparable<Interval> { | ||
9 | static val PRECISION = 32 | ||
10 | package static val ROUND_DOWN = new MathContext(PRECISION, RoundingMode.FLOOR) | ||
11 | package static val ROUND_UP = new MathContext(PRECISION, RoundingMode.CEILING) | ||
12 | |||
13 | private new() { | ||
14 | } | ||
15 | |||
16 | abstract def boolean mustEqual(Interval other) | ||
17 | |||
18 | abstract def boolean mayEqual(Interval other) | ||
19 | |||
20 | def mustNotEqual(Interval other) { | ||
21 | !mayEqual(other) | ||
22 | } | ||
23 | |||
24 | def mayNotEqual(Interval other) { | ||
25 | !mustEqual(other) | ||
26 | } | ||
27 | |||
28 | abstract def boolean mustBeLessThan(Interval other) | ||
29 | |||
30 | abstract def boolean mayBeLessThan(Interval other) | ||
31 | |||
32 | def mustBeLessThanOrEqual(Interval other) { | ||
33 | !mayBeGreaterThan(other) | ||
34 | } | ||
35 | |||
36 | def mayBeLessThanOrEqual(Interval other) { | ||
37 | !mustBeGreaterThan(other) | ||
38 | } | ||
39 | |||
40 | def mustBeGreaterThan(Interval other) { | ||
41 | other.mustBeLessThan(this) | ||
42 | } | ||
43 | |||
44 | def mayBeGreaterThan(Interval other) { | ||
45 | other.mayBeLessThan(this) | ||
46 | } | ||
47 | |||
48 | def mustBeGreaterThanOrEqual(Interval other) { | ||
49 | other.mustBeLessThanOrEqual(this) | ||
50 | } | ||
51 | |||
52 | def mayBeGreaterThanOrEqual(Interval other) { | ||
53 | other.mayBeLessThanOrEqual(this) | ||
54 | } | ||
55 | |||
56 | abstract def Interval min(Interval other) | ||
57 | |||
58 | abstract def Interval max(Interval other) | ||
59 | |||
60 | abstract def Interval join(Interval other) | ||
61 | |||
62 | def +() { | ||
63 | this | ||
64 | } | ||
65 | |||
66 | abstract def Interval -() | ||
67 | |||
68 | abstract def Interval +(Interval other) | ||
69 | |||
70 | abstract def Interval -(Interval other) | ||
71 | |||
72 | abstract def Interval *(int count) | ||
73 | |||
74 | abstract def Interval *(Interval other) | ||
75 | |||
76 | abstract def Interval /(Interval other) | ||
77 | |||
78 | abstract def Interval **(Interval other) | ||
79 | |||
80 | public static val EMPTY = new Interval { | ||
81 | override mustEqual(Interval other) { | ||
82 | true | ||
83 | } | ||
84 | |||
85 | override mayEqual(Interval other) { | ||
86 | false | ||
87 | } | ||
88 | |||
89 | override mustBeLessThan(Interval other) { | ||
90 | true | ||
91 | } | ||
92 | |||
93 | override mayBeLessThan(Interval other) { | ||
94 | false | ||
95 | } | ||
96 | |||
97 | override min(Interval other) { | ||
98 | EMPTY | ||
99 | } | ||
100 | |||
101 | override max(Interval other) { | ||
102 | EMPTY | ||
103 | } | ||
104 | |||
105 | override join(Interval other) { | ||
106 | other | ||
107 | } | ||
108 | |||
109 | override -() { | ||
110 | EMPTY | ||
111 | } | ||
112 | |||
113 | override +(Interval other) { | ||
114 | EMPTY | ||
115 | } | ||
116 | |||
117 | override -(Interval other) { | ||
118 | EMPTY | ||
119 | } | ||
120 | |||
121 | override *(int count) { | ||
122 | EMPTY | ||
123 | } | ||
124 | |||
125 | override *(Interval other) { | ||
126 | EMPTY | ||
127 | } | ||
128 | |||
129 | override /(Interval other) { | ||
130 | EMPTY | ||
131 | } | ||
132 | |||
133 | override **(Interval other) { | ||
134 | EMPTY | ||
135 | } | ||
136 | |||
137 | override toString() { | ||
138 | "∅" | ||
139 | } | ||
140 | |||
141 | override compareTo(Interval o) { | ||
142 | if (o == EMPTY) { | ||
143 | 0 | ||
144 | } else { | ||
145 | -1 | ||
146 | } | ||
147 | } | ||
148 | |||
149 | } | ||
150 | |||
151 | public static val Interval ZERO = new NonEmpty(BigDecimal.ZERO, BigDecimal.ZERO) | ||
152 | |||
153 | public static val Interval UNBOUNDED = new NonEmpty(null, null) | ||
154 | |||
155 | static def Interval of(BigDecimal lower, BigDecimal upper) { | ||
156 | new NonEmpty(lower, upper) | ||
157 | } | ||
158 | |||
159 | static def between(double lower, double upper) { | ||
160 | of(new BigDecimal(lower, ROUND_DOWN), new BigDecimal(upper, ROUND_UP)) | ||
161 | } | ||
162 | |||
163 | static def upTo(double upper) { | ||
164 | of(null, new BigDecimal(upper, ROUND_UP)) | ||
165 | } | ||
166 | |||
167 | static def above(double lower) { | ||
168 | of(new BigDecimal(lower, ROUND_DOWN), null) | ||
169 | } | ||
170 | |||
171 | @Data | ||
172 | private static class NonEmpty extends Interval { | ||
173 | val BigDecimal lower | ||
174 | val BigDecimal upper | ||
175 | |||
176 | /** | ||
177 | * Construct a new non-empty interval. | ||
178 | * | ||
179 | * @param lower The lower bound of the interval. Use <code>null</code> for negative infinity. | ||
180 | * @param upper The upper bound of the interval. Use <code>null</code> for positive infinity. | ||
181 | */ | ||
182 | new(BigDecimal lower, BigDecimal upper) { | ||
183 | if (lower !== null && upper !== null && lower > upper) { | ||
184 | throw new IllegalArgumentException("Lower bound of interval must not be larger than upper bound") | ||
185 | } | ||
186 | this.lower = lower | ||
187 | this.upper = upper | ||
188 | } | ||
189 | |||
190 | override mustEqual(Interval other) { | ||
191 | switch (other) { | ||
192 | case EMPTY: true | ||
193 | NonEmpty: lower == upper && lower == other.lower && lower == other.upper | ||
194 | default: throw new IllegalArgumentException("Unknown interval: " + other) | ||
195 | } | ||
196 | } | ||
197 | |||
198 | override mayEqual(Interval other) { | ||
199 | if (other instanceof NonEmpty) { | ||
200 | (lower === null || other.upper === null || lower <= other.upper) && | ||
201 | (other.lower === null || upper === null || other.lower <= upper) | ||
202 | } else { | ||
203 | false | ||
204 | } | ||
205 | } | ||
206 | |||
207 | override mustBeLessThan(Interval other) { | ||
208 | switch (other) { | ||
209 | case EMPTY: true | ||
210 | NonEmpty: upper !== null && other.lower !== null && upper < other.lower | ||
211 | default: throw new IllegalArgumentException("Unknown interval: " + other) | ||
212 | } | ||
213 | } | ||
214 | |||
215 | override mayBeLessThan(Interval other) { | ||
216 | if (other instanceof NonEmpty) { | ||
217 | lower === null || other.upper === null || lower < other.upper | ||
218 | } else { | ||
219 | false | ||
220 | } | ||
221 | } | ||
222 | |||
223 | override min(Interval other) { | ||
224 | switch (other) { | ||
225 | case EMPTY: this | ||
226 | NonEmpty: min(other) | ||
227 | default: throw new IllegalArgumentException("Unknown interval: " + other) | ||
228 | } | ||
229 | } | ||
230 | |||
231 | def min(NonEmpty other) { | ||
232 | new NonEmpty( | ||
233 | lower.tryMin(other.lower), | ||
234 | if(other.upper === null) upper else if(upper === null) other.upper else upper.min(other.upper) | ||
235 | ) | ||
236 | } | ||
237 | |||
238 | override max(Interval other) { | ||
239 | switch (other) { | ||
240 | case EMPTY: this | ||
241 | NonEmpty: max(other) | ||
242 | default: throw new IllegalArgumentException("Unknown interval: " + other) | ||
243 | } | ||
244 | } | ||
245 | |||
246 | def max(NonEmpty other) { | ||
247 | new NonEmpty( | ||
248 | if(other.lower === null) lower else if(lower === null) other.lower else lower.max(other.lower), | ||
249 | upper.tryMax(other.upper) | ||
250 | ) | ||
251 | } | ||
252 | |||
253 | override join(Interval other) { | ||
254 | switch (other) { | ||
255 | case EMPTY: this | ||
256 | NonEmpty: new NonEmpty(lower.tryMin(other.lower), upper.tryMax(other.upper)) | ||
257 | default: throw new IllegalArgumentException("Unknown interval: " + other) | ||
258 | } | ||
259 | } | ||
260 | |||
261 | override -() { | ||
262 | new NonEmpty(upper?.negate(ROUND_DOWN), lower?.negate(ROUND_UP)) | ||
263 | } | ||
264 | |||
265 | override +(Interval other) { | ||
266 | switch (other) { | ||
267 | case EMPTY: EMPTY | ||
268 | NonEmpty: this + other | ||
269 | default: throw new IllegalArgumentException("Unknown interval: " + other) | ||
270 | } | ||
271 | } | ||
272 | |||
273 | def +(NonEmpty other) { | ||
274 | new NonEmpty( | ||
275 | lower.tryAdd(other.lower, ROUND_DOWN), | ||
276 | upper.tryAdd(other.upper, ROUND_UP) | ||
277 | ) | ||
278 | } | ||
279 | |||
280 | private static def tryAdd(BigDecimal a, BigDecimal b, MathContext mc) { | ||
281 | if (b === null) { | ||
282 | null | ||
283 | } else { | ||
284 | a?.add(b, mc) | ||
285 | } | ||
286 | } | ||
287 | |||
288 | override -(Interval other) { | ||
289 | switch (other) { | ||
290 | case EMPTY: EMPTY | ||
291 | NonEmpty: this - other | ||
292 | default: throw new IllegalArgumentException("Unknown interval: " + other) | ||
293 | } | ||
294 | } | ||
295 | |||
296 | def -(NonEmpty other) { | ||
297 | new NonEmpty( | ||
298 | lower.trySubtract(other.upper, ROUND_DOWN), | ||
299 | upper.trySubtract(other.lower, ROUND_UP) | ||
300 | ) | ||
301 | } | ||
302 | |||
303 | private static def trySubtract(BigDecimal a, BigDecimal b, MathContext mc) { | ||
304 | if (b === null) { | ||
305 | null | ||
306 | } else { | ||
307 | a?.subtract(b, mc) | ||
308 | } | ||
309 | } | ||
310 | |||
311 | override *(int count) { | ||
312 | val bigCount = new BigDecimal(count) | ||
313 | new NonEmpty( | ||
314 | lower.tryMultiply(bigCount, ROUND_DOWN), | ||
315 | upper.tryMultiply(bigCount, ROUND_UP) | ||
316 | ) | ||
317 | } | ||
318 | |||
319 | override *(Interval other) { | ||
320 | switch (other) { | ||
321 | case EMPTY: EMPTY | ||
322 | NonEmpty: this * other | ||
323 | default: throw new IllegalArgumentException("Unknown interval: " + other) | ||
324 | } | ||
325 | } | ||
326 | |||
327 | def *(NonEmpty other) { | ||
328 | if (this == ZERO || other == ZERO) { | ||
329 | ZERO | ||
330 | } else if (nonpositive) { | ||
331 | if (other.nonpositive) { | ||
332 | new NonEmpty( | ||
333 | upper.multiply(other.upper, ROUND_DOWN), | ||
334 | lower.tryMultiply(other.lower, ROUND_UP) | ||
335 | ) | ||
336 | } else if (other.nonnegative) { | ||
337 | new NonEmpty( | ||
338 | lower.tryMultiply(other.upper, ROUND_DOWN), | ||
339 | upper.multiply(other.lower, ROUND_UP) | ||
340 | ) | ||
341 | } else { | ||
342 | new NonEmpty( | ||
343 | lower.tryMultiply(other.upper, ROUND_DOWN), | ||
344 | lower.tryMultiply(other.lower, ROUND_UP) | ||
345 | ) | ||
346 | } | ||
347 | } else if (nonnegative) { | ||
348 | if (other.nonpositive) { | ||
349 | new NonEmpty( | ||
350 | upper.tryMultiply(other.lower, ROUND_DOWN), | ||
351 | lower.multiply(other.upper, ROUND_UP) | ||
352 | ) | ||
353 | } else if (other.nonnegative) { | ||
354 | new NonEmpty( | ||
355 | lower.multiply(other.lower, ROUND_DOWN), | ||
356 | upper.tryMultiply(other.upper, ROUND_UP) | ||
357 | ) | ||
358 | } else { | ||
359 | new NonEmpty( | ||
360 | upper.tryMultiply(other.lower, ROUND_DOWN), | ||
361 | upper.tryMultiply(other.upper, ROUND_UP) | ||
362 | ) | ||
363 | } | ||
364 | } else { | ||
365 | if (other.nonpositive) { | ||
366 | new NonEmpty( | ||
367 | upper.tryMultiply(other.lower, ROUND_DOWN), | ||
368 | lower.tryMultiply(other.lower, ROUND_UP) | ||
369 | ) | ||
370 | } else if (other.nonnegative) { | ||
371 | new NonEmpty( | ||
372 | lower.tryMultiply(other.upper, ROUND_DOWN), | ||
373 | upper.tryMultiply(other.upper, ROUND_UP) | ||
374 | ) | ||
375 | } else { | ||
376 | new NonEmpty( | ||
377 | lower.tryMultiply(other.upper, ROUND_DOWN).tryMin(upper.tryMultiply(other.lower, ROUND_DOWN)), | ||
378 | lower.tryMultiply(other.lower, ROUND_UP).tryMax(upper.tryMultiply(other.upper, ROUND_UP)) | ||
379 | ) | ||
380 | } | ||
381 | } | ||
382 | } | ||
383 | |||
384 | private def isNonpositive() { | ||
385 | upper !== null && upper <= BigDecimal.ZERO | ||
386 | } | ||
387 | |||
388 | private def isNonnegative() { | ||
389 | lower !== null && lower >= BigDecimal.ZERO | ||
390 | } | ||
391 | |||
392 | private static def tryMultiply(BigDecimal a, BigDecimal b, MathContext mc) { | ||
393 | if (b === null) { | ||
394 | null | ||
395 | } else { | ||
396 | a?.multiply(b, mc) | ||
397 | } | ||
398 | } | ||
399 | |||
400 | private static def tryMin(BigDecimal a, BigDecimal b) { | ||
401 | if (b === null) { | ||
402 | null | ||
403 | } else { | ||
404 | a?.min(b) | ||
405 | } | ||
406 | } | ||
407 | |||
408 | private static def tryMax(BigDecimal a, BigDecimal b) { | ||
409 | if (b === null) { | ||
410 | null | ||
411 | } else { | ||
412 | a?.max(b) | ||
413 | } | ||
414 | } | ||
415 | |||
416 | override /(Interval other) { | ||
417 | switch (other) { | ||
418 | case EMPTY: EMPTY | ||
419 | NonEmpty: this / other | ||
420 | default: throw new IllegalArgumentException("Unknown interval: " + other) | ||
421 | } | ||
422 | } | ||
423 | |||
424 | def /(NonEmpty other) { | ||
425 | if (other == ZERO) { | ||
426 | EMPTY | ||
427 | } else if (this == ZERO) { | ||
428 | ZERO | ||
429 | } else if (other.strictlyNegative) { | ||
430 | if (nonpositive) { | ||
431 | new NonEmpty( | ||
432 | upper.tryDivide(other.lower, ROUND_DOWN), | ||
433 | lower.tryDivide(other.upper, ROUND_UP) | ||
434 | ) | ||
435 | } else if (nonnegative) { | ||
436 | new NonEmpty( | ||
437 | upper.tryDivide(other.upper, ROUND_DOWN), | ||
438 | lower.tryDivide(other.lower, ROUND_UP) | ||
439 | ) | ||
440 | } else { // lower < 0 < upper | ||
441 | new NonEmpty( | ||
442 | upper.tryDivide(other.upper, ROUND_DOWN), | ||
443 | lower.tryDivide(other.upper, ROUND_UP) | ||
444 | ) | ||
445 | } | ||
446 | } else if (other.strictlyPositive) { | ||
447 | if (nonpositive) { | ||
448 | new NonEmpty( | ||
449 | lower.tryDivide(other.lower, ROUND_DOWN), | ||
450 | upper.tryDivide(other.upper, ROUND_UP) | ||
451 | ) | ||
452 | } else if (nonnegative) { | ||
453 | new NonEmpty( | ||
454 | lower.tryDivide(other.upper, ROUND_DOWN), | ||
455 | upper.tryDivide(other.lower, ROUND_UP) | ||
456 | ) | ||
457 | } else { // lower < 0 < upper | ||
458 | new NonEmpty( | ||
459 | lower.tryDivide(other.lower, ROUND_DOWN), | ||
460 | upper.tryDivide(other.lower, ROUND_UP) | ||
461 | ) | ||
462 | } | ||
463 | } else { // other contains 0 | ||
464 | if (other.lower == BigDecimal.ZERO) { // 0 == other.lower < other.upper, because [0, 0] was exluded earlier | ||
465 | if (nonpositive) { | ||
466 | new NonEmpty(null, upper.tryDivide(other.upper, ROUND_UP)) | ||
467 | } else if (nonnegative) { | ||
468 | new NonEmpty(lower.tryDivide(other.upper, ROUND_DOWN), null) | ||
469 | } else { // lower < 0 < upper | ||
470 | UNBOUNDED | ||
471 | } | ||
472 | } else if (other.upper == BigDecimal.ZERO) { // other.lower < other.upper == 0 | ||
473 | if (nonpositive) { | ||
474 | new NonEmpty(upper.tryDivide(other.lower, ROUND_DOWN), null) | ||
475 | } else if (nonnegative) { | ||
476 | new NonEmpty(null, lower.tryDivide(other.lower, ROUND_UP)) | ||
477 | } else { // lower < 0 < upper | ||
478 | UNBOUNDED | ||
479 | } | ||
480 | } else { // other.lower < 0 < other.upper | ||
481 | UNBOUNDED | ||
482 | } | ||
483 | } | ||
484 | } | ||
485 | |||
486 | private def isStrictlyNegative() { | ||
487 | upper !== null && upper < BigDecimal.ZERO | ||
488 | } | ||
489 | |||
490 | private def isStrictlyPositive() { | ||
491 | lower !== null && lower > BigDecimal.ZERO | ||
492 | } | ||
493 | |||
494 | private static def tryDivide(BigDecimal a, BigDecimal b, MathContext mc) { | ||
495 | if (b === null) { | ||
496 | BigDecimal.ZERO | ||
497 | } else { | ||
498 | a?.divide(b, mc) | ||
499 | } | ||
500 | } | ||
501 | |||
502 | override **(Interval other) { | ||
503 | switch (other) { | ||
504 | case EMPTY: EMPTY | ||
505 | NonEmpty: this ** other | ||
506 | default: throw new IllegalArgumentException("Unknown interval: " + other) | ||
507 | } | ||
508 | } | ||
509 | |||
510 | def **(NonEmpty other) { | ||
511 | // XXX This should use proper rounding for log and exp instead of | ||
512 | // converting to double. | ||
513 | // XXX We should not ignore (integer) powers of negative numbers. | ||
514 | val lowerLog = if (lower === null || lower <= BigDecimal.ZERO) { | ||
515 | null | ||
516 | } else { | ||
517 | new BigDecimal(Math.log(lower.doubleValue), ROUND_DOWN) | ||
518 | } | ||
519 | val upperLog = if (upper === null) { | ||
520 | null | ||
521 | } else if (upper == BigDecimal.ZERO) { | ||
522 | return ZERO | ||
523 | } else if (upper < BigDecimal.ZERO) { | ||
524 | return EMPTY | ||
525 | } else { | ||
526 | new BigDecimal(Math.log(upper.doubleValue), ROUND_UP) | ||
527 | } | ||
528 | val log = new NonEmpty(lowerLog, upperLog) | ||
529 | val product = log * other | ||
530 | if (product instanceof NonEmpty) { | ||
531 | val lowerResult = if (product.lower === null) { | ||
532 | BigDecimal.ZERO | ||
533 | } else { | ||
534 | new BigDecimal(Math.exp(product.lower.doubleValue), ROUND_DOWN) | ||
535 | } | ||
536 | val upperResult = if (product.upper === null) { | ||
537 | null | ||
538 | } else { | ||
539 | new BigDecimal(Math.exp(product.upper.doubleValue), ROUND_UP) | ||
540 | } | ||
541 | new NonEmpty(lowerResult, upperResult) | ||
542 | } else { | ||
543 | throw new IllegalArgumentException("Unknown interval: " + product) | ||
544 | } | ||
545 | } | ||
546 | |||
547 | override toString() { | ||
548 | '''«IF lower === null»(-∞«ELSE»[«lower»«ENDIF», «IF upper === null»∞)«ELSE»«upper»]«ENDIF»''' | ||
549 | } | ||
550 | |||
551 | override compareTo(Interval o) { | ||
552 | switch (o) { | ||
553 | case EMPTY: 1 | ||
554 | NonEmpty: compareTo(o) | ||
555 | default: throw new IllegalArgumentException("Unknown interval: " + o) | ||
556 | } | ||
557 | } | ||
558 | |||
559 | def compareTo(NonEmpty o) { | ||
560 | if (lower === null) { | ||
561 | if (o.lower !== null) { | ||
562 | return -1 | ||
563 | } | ||
564 | } else if (o.lower === null) { // lower !== null | ||
565 | return 1 | ||
566 | } else { // both lower and o.lower are finite | ||
567 | val lowerDifference = lower.compareTo(o.lower) | ||
568 | if (lowerDifference != 0) { | ||
569 | return lowerDifference | ||
570 | } | ||
571 | } | ||
572 | if (upper === null) { | ||
573 | if (o.upper === null) { | ||
574 | return 0 | ||
575 | } else { | ||
576 | return 1 | ||
577 | } | ||
578 | } else if (o.upper === null) { // upper !== null | ||
579 | return -1 | ||
580 | } | ||
581 | upper.compareTo(o.upper) | ||
582 | } | ||
583 | } | ||
584 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/IntervalAggregationMode.java b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/IntervalAggregationMode.java new file mode 100644 index 00000000..f106e305 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/IntervalAggregationMode.java | |||
@@ -0,0 +1,99 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.interval; | ||
2 | |||
3 | import java.util.function.BinaryOperator; | ||
4 | |||
5 | public enum IntervalAggregationMode implements BinaryOperator<Interval> { | ||
6 | SUM("intervalSum", "Sum a set of intervals") { | ||
7 | @Override | ||
8 | public IntervalRedBlackNode createNode(Interval interval) { | ||
9 | return new IntervalRedBlackNode(interval) { | ||
10 | public boolean isMultiplicitySensitive() { | ||
11 | return true; | ||
12 | } | ||
13 | |||
14 | public Interval multiply(Interval interval, int count) { | ||
15 | return interval.operator_multiply(count); | ||
16 | }; | ||
17 | |||
18 | @Override | ||
19 | public Interval op(Interval left, Interval right) { | ||
20 | return left.operator_plus(right); | ||
21 | } | ||
22 | }; | ||
23 | } | ||
24 | |||
25 | @Override | ||
26 | public Interval getNeutral() { | ||
27 | return Interval.ZERO; | ||
28 | } | ||
29 | }, | ||
30 | |||
31 | MIN("intervalMin", "Find the minimum a set of intervals") { | ||
32 | @Override | ||
33 | public IntervalRedBlackNode createNode(Interval interval) { | ||
34 | return new IntervalRedBlackNode(interval) { | ||
35 | @Override | ||
36 | public Interval op(Interval left, Interval right) { | ||
37 | return left.min(right); | ||
38 | } | ||
39 | }; | ||
40 | } | ||
41 | }, | ||
42 | |||
43 | MAX("intervalMax", "Find the maximum a set of intervals") { | ||
44 | @Override | ||
45 | public IntervalRedBlackNode createNode(Interval interval) { | ||
46 | return new IntervalRedBlackNode(interval) { | ||
47 | @Override | ||
48 | public Interval op(Interval left, Interval right) { | ||
49 | return left.max(right); | ||
50 | } | ||
51 | }; | ||
52 | } | ||
53 | }, | ||
54 | |||
55 | JOIN("intervalJoin", "Calculate the smallest interval containing all the intervals in a set") { | ||
56 | @Override | ||
57 | public IntervalRedBlackNode createNode(Interval interval) { | ||
58 | return new IntervalRedBlackNode(interval) { | ||
59 | @Override | ||
60 | public Interval op(Interval left, Interval right) { | ||
61 | return left.join(right); | ||
62 | } | ||
63 | }; | ||
64 | } | ||
65 | }; | ||
66 | |||
67 | private final String modeName; | ||
68 | private final String description; | ||
69 | private final IntervalRedBlackNode empty; | ||
70 | |||
71 | IntervalAggregationMode(String modeName, String description) { | ||
72 | this.modeName = modeName; | ||
73 | this.description = description; | ||
74 | empty = createNode(null); | ||
75 | } | ||
76 | |||
77 | public String getModeName() { | ||
78 | return modeName; | ||
79 | } | ||
80 | |||
81 | public String getDescription() { | ||
82 | return description; | ||
83 | } | ||
84 | |||
85 | public IntervalRedBlackNode getEmpty() { | ||
86 | return empty; | ||
87 | } | ||
88 | |||
89 | @Override | ||
90 | public Interval apply(Interval left, Interval right) { | ||
91 | return empty.op(left, right); | ||
92 | } | ||
93 | |||
94 | public abstract IntervalRedBlackNode createNode(Interval interval); | ||
95 | |||
96 | public Interval getNeutral() { | ||
97 | return Interval.EMPTY; | ||
98 | } | ||
99 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/IntervalAggregationOperator.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/IntervalAggregationOperator.xtend new file mode 100644 index 00000000..21d3d73b --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/IntervalAggregationOperator.xtend | |||
@@ -0,0 +1,48 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.interval | ||
2 | |||
3 | import java.util.stream.Stream | ||
4 | import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator | ||
5 | import org.eclipse.xtend.lib.annotations.Accessors | ||
6 | import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor | ||
7 | |||
8 | @FinalFieldsConstructor | ||
9 | class IntervalAggregationOperator implements IMultisetAggregationOperator<Interval, IntervalRedBlackNode, Interval> { | ||
10 | @Accessors val IntervalAggregationMode mode | ||
11 | |||
12 | override getName() { | ||
13 | mode.modeName | ||
14 | } | ||
15 | |||
16 | override getShortDescription() { | ||
17 | mode.description | ||
18 | } | ||
19 | |||
20 | override createNeutral() { | ||
21 | mode.empty | ||
22 | } | ||
23 | |||
24 | override isNeutral(IntervalRedBlackNode result) { | ||
25 | result.leaf | ||
26 | } | ||
27 | |||
28 | override update(IntervalRedBlackNode oldResult, Interval updateValue, boolean isInsertion) { | ||
29 | if (isInsertion) { | ||
30 | val newNode = mode.createNode(updateValue) | ||
31 | oldResult.add(newNode) | ||
32 | } else { | ||
33 | oldResult.remove(updateValue) | ||
34 | } | ||
35 | } | ||
36 | |||
37 | override getAggregate(IntervalRedBlackNode result) { | ||
38 | if (result.leaf) { | ||
39 | mode.neutral | ||
40 | } else { | ||
41 | result.result | ||
42 | } | ||
43 | } | ||
44 | |||
45 | override aggregateStream(Stream<Interval> stream) { | ||
46 | stream.reduce(mode).orElse(mode.neutral) | ||
47 | } | ||
48 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/IntervalHullAggregatorOperator.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/IntervalHullAggregatorOperator.xtend new file mode 100644 index 00000000..ce48eca1 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/IntervalHullAggregatorOperator.xtend | |||
@@ -0,0 +1,87 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.interval | ||
2 | |||
3 | import java.math.BigDecimal | ||
4 | import java.math.MathContext | ||
5 | import java.util.SortedMap | ||
6 | import java.util.TreeMap | ||
7 | import java.util.stream.Stream | ||
8 | import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator | ||
9 | |||
10 | abstract class IntervalHullAggregatorOperator<T extends Comparable<T>> implements IMultisetAggregationOperator<T, SortedMap<T, Integer>, Interval> { | ||
11 | protected new() { | ||
12 | } | ||
13 | |||
14 | override getName() { | ||
15 | "intervalHull" | ||
16 | } | ||
17 | |||
18 | override getShortDescription() { | ||
19 | "Calculates the interval hull of a set of numbers" | ||
20 | } | ||
21 | |||
22 | override createNeutral() { | ||
23 | new TreeMap | ||
24 | } | ||
25 | |||
26 | override getAggregate(SortedMap<T, Integer> result) { | ||
27 | if (result.neutral) { | ||
28 | Interval.EMPTY | ||
29 | } else { | ||
30 | toInterval(result.firstKey, result.lastKey) | ||
31 | } | ||
32 | } | ||
33 | |||
34 | protected abstract def BigDecimal toBigDecimal(T value, MathContext mc) | ||
35 | |||
36 | private def toInterval(T min, T max) { | ||
37 | Interval.of(min.toBigDecimal(Interval.ROUND_DOWN), max.toBigDecimal(Interval.ROUND_UP)) | ||
38 | } | ||
39 | |||
40 | override isNeutral(SortedMap<T, Integer> result) { | ||
41 | result.empty | ||
42 | } | ||
43 | |||
44 | override update(SortedMap<T, Integer> oldResult, T updateValue, boolean isInsertion) { | ||
45 | if (isInsertion) { | ||
46 | oldResult.compute(updateValue) [ key, value | | ||
47 | if (value === null) { | ||
48 | 1 | ||
49 | } else if (value > 0) { | ||
50 | value + 1 | ||
51 | } else { | ||
52 | throw new IllegalStateException("Invalid count: " + value) | ||
53 | } | ||
54 | ] | ||
55 | } else { | ||
56 | oldResult.compute(updateValue) [ key, value | | ||
57 | if (value === 1) { | ||
58 | null | ||
59 | } else if (value > 1) { | ||
60 | value - 1 | ||
61 | } else { | ||
62 | throw new IllegalStateException("Invalid count: " + value) | ||
63 | } | ||
64 | ] | ||
65 | } | ||
66 | oldResult | ||
67 | } | ||
68 | |||
69 | override aggregateStream(Stream<T> stream) { | ||
70 | val iterator = stream.iterator | ||
71 | if (!iterator.hasNext) { | ||
72 | return Interval.EMPTY | ||
73 | } | ||
74 | var min = iterator.next | ||
75 | var max = min | ||
76 | while (iterator.hasNext) { | ||
77 | val element = iterator.next | ||
78 | if (element.compareTo(min) < 0) { | ||
79 | min = element | ||
80 | } | ||
81 | if (element.compareTo(max) > 0) { | ||
82 | max = element | ||
83 | } | ||
84 | } | ||
85 | toInterval(min, max) | ||
86 | } | ||
87 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/IntervalRedBlackNode.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/IntervalRedBlackNode.xtend new file mode 100644 index 00000000..3aa575bc --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/IntervalRedBlackNode.xtend | |||
@@ -0,0 +1,177 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.interval | ||
2 | |||
3 | abstract class IntervalRedBlackNode extends RedBlackNode<IntervalRedBlackNode> { | ||
4 | public val Interval interval | ||
5 | public var int count = 1 | ||
6 | public var Interval result | ||
7 | |||
8 | new(Interval interval) { | ||
9 | this.interval = interval | ||
10 | } | ||
11 | |||
12 | def boolean isMultiplicitySensitive() { | ||
13 | false | ||
14 | } | ||
15 | |||
16 | def Interval multiply(Interval interval, int count) { | ||
17 | interval | ||
18 | } | ||
19 | |||
20 | abstract def Interval op(Interval left, Interval right) | ||
21 | |||
22 | override augment() { | ||
23 | val value = calcualteAugmentation() | ||
24 | if (result == value) { | ||
25 | false | ||
26 | } else { | ||
27 | result = value | ||
28 | true | ||
29 | } | ||
30 | } | ||
31 | |||
32 | private def calcualteAugmentation() { | ||
33 | var value = multiply(interval, count) | ||
34 | if (!left.leaf) { | ||
35 | value = op(value, left.result) | ||
36 | } | ||
37 | if (!right.leaf) { | ||
38 | value = op(value, right.result) | ||
39 | } | ||
40 | value | ||
41 | } | ||
42 | |||
43 | override assertNodeIsValid() { | ||
44 | super.assertNodeIsValid() | ||
45 | if (leaf) { | ||
46 | return | ||
47 | } | ||
48 | if (count <= 0) { | ||
49 | throw new IllegalStateException("Node with nonpositive count") | ||
50 | } | ||
51 | val value = calcualteAugmentation() | ||
52 | if (result != value) { | ||
53 | throw new IllegalStateException("Node with invalid augmentation: " + result + " != " + value) | ||
54 | } | ||
55 | } | ||
56 | |||
57 | override assertSubtreeIsValid() { | ||
58 | super.assertSubtreeIsValid() | ||
59 | assertNodeIsValid() | ||
60 | } | ||
61 | |||
62 | override compareTo(IntervalRedBlackNode other) { | ||
63 | if (leaf || other.leaf) { | ||
64 | throw new IllegalArgumentException("One of the nodes is a leaf node") | ||
65 | } | ||
66 | interval.compareTo(other.interval) | ||
67 | } | ||
68 | |||
69 | def add(IntervalRedBlackNode newNode) { | ||
70 | if (parent !== null) { | ||
71 | throw new IllegalArgumentException("This is not the root of a tree") | ||
72 | } | ||
73 | if (leaf) { | ||
74 | newNode.isRed = false | ||
75 | newNode.left = this | ||
76 | newNode.right = this | ||
77 | newNode.parent = null | ||
78 | newNode.augment | ||
79 | return newNode | ||
80 | } | ||
81 | val modifiedNode = addWithoutFixup(newNode) | ||
82 | if (modifiedNode === newNode) { | ||
83 | // Must augment here, because fixInsertion() might call augment() | ||
84 | // on a node repeatedly, which might lose the change notification the | ||
85 | // second time it is called, and the augmentation will fail to | ||
86 | // reach the root. | ||
87 | modifiedNode.augmentRecursively | ||
88 | modifiedNode.isRed = true | ||
89 | return modifiedNode.fixInsertion | ||
90 | } | ||
91 | if (multiplicitySensitive) { | ||
92 | modifiedNode.augmentRecursively | ||
93 | } | ||
94 | this | ||
95 | } | ||
96 | |||
97 | private def addWithoutFixup(IntervalRedBlackNode newNode) { | ||
98 | var node = this | ||
99 | while (!node.leaf) { | ||
100 | val comparison = node.interval.compareTo(newNode.interval) | ||
101 | if (comparison < 0) { | ||
102 | if (node.left.leaf) { | ||
103 | newNode.left = node.left | ||
104 | newNode.right = node.left | ||
105 | node.left = newNode | ||
106 | newNode.parent = node | ||
107 | return newNode | ||
108 | } else { | ||
109 | node = node.left | ||
110 | } | ||
111 | } else if (comparison > 0) { | ||
112 | if (node.right.leaf) { | ||
113 | newNode.left = node.right | ||
114 | newNode.right = node.right | ||
115 | node.right = newNode | ||
116 | newNode.parent = node | ||
117 | return newNode | ||
118 | } else { | ||
119 | node = node.right | ||
120 | } | ||
121 | } else { // comparison == 0 | ||
122 | newNode.parent = null | ||
123 | node.count++ | ||
124 | return node | ||
125 | } | ||
126 | } | ||
127 | throw new IllegalStateException("Reached leaf node while searching for insertion point") | ||
128 | } | ||
129 | |||
130 | private def augmentRecursively() { | ||
131 | for (var node = this; node !== null; node = node.parent) { | ||
132 | if (!node.augment) { | ||
133 | return | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
138 | def remove(Interval interval) { | ||
139 | val node = find(interval) | ||
140 | node.count-- | ||
141 | if (node.count == 0) { | ||
142 | return node.remove | ||
143 | } | ||
144 | if (multiplicitySensitive) { | ||
145 | node.augmentRecursively | ||
146 | } | ||
147 | this | ||
148 | } | ||
149 | |||
150 | private def find(Interval interval) { | ||
151 | var node = this | ||
152 | while (!node.leaf) { | ||
153 | val comparison = node.interval.compareTo(interval) | ||
154 | if (comparison < 0) { | ||
155 | node = node.left | ||
156 | } else if (comparison > 0) { | ||
157 | node = node.right | ||
158 | } else { // comparison == 0 | ||
159 | return node | ||
160 | } | ||
161 | } | ||
162 | throw new IllegalStateException("Reached leaf node while searching for interval to remove") | ||
163 | } | ||
164 | |||
165 | override toString() { | ||
166 | if (leaf) { | ||
167 | "L" | ||
168 | } else { | ||
169 | ''' | ||
170 | «IF isRed»R«ELSE»B«ENDIF» «count»«interval» : «result» | ||
171 | «left» | ||
172 | «right» | ||
173 | ''' | ||
174 | } | ||
175 | } | ||
176 | |||
177 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/RedBlackNode.java b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/RedBlackNode.java new file mode 100644 index 00000000..8c40816b --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/RedBlackNode.java | |||
@@ -0,0 +1,1392 @@ | |||
1 | /* | ||
2 | * The MIT License (MIT) | ||
3 | * | ||
4 | * Copyright (c) 2016 btrekkie | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in all | ||
14 | * copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | * SOFTWARE. | ||
23 | */ | ||
24 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.interval; | ||
25 | |||
26 | import java.lang.reflect.Array; | ||
27 | import java.util.Collection; | ||
28 | import java.util.Comparator; | ||
29 | import java.util.HashSet; | ||
30 | import java.util.Iterator; | ||
31 | import java.util.Set; | ||
32 | |||
33 | /** | ||
34 | * A node in a red-black tree ( https://en.wikipedia.org/wiki/Red%E2%80%93black_tree ). Compared to a class like Java's | ||
35 | * TreeMap, RedBlackNode is a low-level data structure. The internals of a node are exposed as public fields, allowing | ||
36 | * clients to directly observe and manipulate the structure of the tree. This gives clients flexibility, although it | ||
37 | * also enables them to violate the red-black or BST properties. The RedBlackNode class provides methods for performing | ||
38 | * various standard operations, such as insertion and removal. | ||
39 | * | ||
40 | * Unlike most implementations of binary search trees, RedBlackNode supports arbitrary augmentation. By subclassing | ||
41 | * RedBlackNode, clients can add arbitrary data and augmentation information to each node. For example, if we were to | ||
42 | * use a RedBlackNode subclass to implement a sorted set, the subclass would have a field storing an element in the set. | ||
43 | * If we wanted to keep track of the number of non-leaf nodes in each subtree, we would store this as a "size" field and | ||
44 | * override augment() to update this field. All RedBlackNode methods (such as "insert" and remove()) call augment() as | ||
45 | * necessary to correctly maintain the augmentation information, unless otherwise indicated. | ||
46 | * | ||
47 | * The values of the tree are stored in the non-leaf nodes. RedBlackNode does not support use cases where values must be | ||
48 | * stored in the leaf nodes. It is recommended that all of the leaf nodes in a given tree be the same (black) | ||
49 | * RedBlackNode instance, to save space. The root of an empty tree is a leaf node, as opposed to null. | ||
50 | * | ||
51 | * For reference, a red-black tree is a binary search tree satisfying the following properties: | ||
52 | * | ||
53 | * - Every node is colored red or black. | ||
54 | * - The leaf nodes, which are dummy nodes that do not store any values, are colored black. | ||
55 | * - The root is black. | ||
56 | * - Both children of each red node are black. | ||
57 | * - Every path from the root to a leaf contains the same number of black nodes. | ||
58 | * | ||
59 | * @param <N> The type of node in the tree. For example, we might have | ||
60 | * "class FooNode<T> extends RedBlackNode<FooNode<T>>". | ||
61 | * @author Bill Jacobs | ||
62 | */ | ||
63 | public abstract class RedBlackNode<N extends RedBlackNode<N>> implements Comparable<N> { | ||
64 | /** A Comparator that compares Comparable elements using their natural order. */ | ||
65 | private static final Comparator<Comparable<Object>> NATURAL_ORDER = new Comparator<Comparable<Object>>() { | ||
66 | @Override | ||
67 | public int compare(Comparable<Object> value1, Comparable<Object> value2) { | ||
68 | return value1.compareTo(value2); | ||
69 | } | ||
70 | }; | ||
71 | |||
72 | /** The parent of this node, if any. "parent" is null if this is a leaf node. */ | ||
73 | public N parent; | ||
74 | |||
75 | /** The left child of this node. "left" is null if this is a leaf node. */ | ||
76 | public N left; | ||
77 | |||
78 | /** The right child of this node. "right" is null if this is a leaf node. */ | ||
79 | public N right; | ||
80 | |||
81 | /** Whether the node is colored red, as opposed to black. */ | ||
82 | public boolean isRed; | ||
83 | |||
84 | /** | ||
85 | * Sets any augmentation information about the subtree rooted at this node that is stored in this node. For | ||
86 | * example, if we augment each node by subtree size (the number of non-leaf nodes in the subtree), this method would | ||
87 | * set the size field of this node to be equal to the size field of the left child plus the size field of the right | ||
88 | * child plus one. | ||
89 | * | ||
90 | * "Augmentation information" is information that we can compute about a subtree rooted at some node, preferably | ||
91 | * based only on the augmentation information in the node's two children and the information in the node. Examples | ||
92 | * of augmentation information are the sum of the values in a subtree and the number of non-leaf nodes in a subtree. | ||
93 | * Augmentation information may not depend on the colors of the nodes. | ||
94 | * | ||
95 | * This method returns whether the augmentation information in any of the ancestors of this node might have been | ||
96 | * affected by changes in this subtree since the last call to augment(). In the usual case, where the augmentation | ||
97 | * information depends only on the information in this node and the augmentation information in its immediate | ||
98 | * children, this is equivalent to whether the augmentation information changed as a result of this call to | ||
99 | * augment(). For example, in the case of subtree size, this returns whether the value of the size field prior to | ||
100 | * calling augment() differed from the size field of the left child plus the size field of the right child plus one. | ||
101 | * False positives are permitted. The return value is unspecified if we have not called augment() on this node | ||
102 | * before. | ||
103 | * | ||
104 | * This method may assume that this is not a leaf node. It may not assume that the augmentation information stored | ||
105 | * in any of the tree's nodes is correct. However, if the augmentation information stored in all of the node's | ||
106 | * descendants is correct, then the augmentation information stored in this node must be correct after calling | ||
107 | * augment(). | ||
108 | */ | ||
109 | public boolean augment() { | ||
110 | return false; | ||
111 | } | ||
112 | |||
113 | /** | ||
114 | * Throws a RuntimeException if we detect that this node locally violates any invariants specific to this subclass | ||
115 | * of RedBlackNode. For example, if this stores the size of the subtree rooted at this node, this should throw a | ||
116 | * RuntimeException if the size field of this is not equal to the size field of the left child plus the size field | ||
117 | * of the right child plus one. Note that we may call this on a leaf node. | ||
118 | * | ||
119 | * assertSubtreeIsValid() calls assertNodeIsValid() on each node, or at least starts to do so until it detects a | ||
120 | * problem. assertNodeIsValid() should assume the node is in a tree that satisfies all properties common to all | ||
121 | * red-black trees, as assertSubtreeIsValid() is responsible for such checks. assertNodeIsValid() should be | ||
122 | * "downward-looking", i.e. it should ignore any information in "parent", and it should be "local", i.e. it should | ||
123 | * only check a constant number of descendants. To include "global" checks, such as verifying the BST property | ||
124 | * concerning ordering, override assertSubtreeIsValid(). assertOrderIsValid is useful for checking the BST | ||
125 | * property. | ||
126 | */ | ||
127 | public void assertNodeIsValid() { | ||
128 | |||
129 | } | ||
130 | |||
131 | /** Returns whether this is a leaf node. */ | ||
132 | public boolean isLeaf() { | ||
133 | return left == null; | ||
134 | } | ||
135 | |||
136 | /** Returns the root of the tree that contains this node. */ | ||
137 | public N root() { | ||
138 | @SuppressWarnings("unchecked") | ||
139 | N node = (N)this; | ||
140 | while (node.parent != null) { | ||
141 | node = node.parent; | ||
142 | } | ||
143 | return node; | ||
144 | } | ||
145 | |||
146 | /** Returns the first node in the subtree rooted at this node, if any. */ | ||
147 | public N min() { | ||
148 | if (isLeaf()) { | ||
149 | return null; | ||
150 | } | ||
151 | @SuppressWarnings("unchecked") | ||
152 | N node = (N)this; | ||
153 | while (!node.left.isLeaf()) { | ||
154 | node = node.left; | ||
155 | } | ||
156 | return node; | ||
157 | } | ||
158 | |||
159 | /** Returns the last node in the subtree rooted at this node, if any. */ | ||
160 | public N max() { | ||
161 | if (isLeaf()) { | ||
162 | return null; | ||
163 | } | ||
164 | @SuppressWarnings("unchecked") | ||
165 | N node = (N)this; | ||
166 | while (!node.right.isLeaf()) { | ||
167 | node = node.right; | ||
168 | } | ||
169 | return node; | ||
170 | } | ||
171 | |||
172 | /** Returns the node immediately before this in the tree that contains this node, if any. */ | ||
173 | public N predecessor() { | ||
174 | if (!left.isLeaf()) { | ||
175 | N node; | ||
176 | for (node = left; !node.right.isLeaf(); node = node.right); | ||
177 | return node; | ||
178 | } else if (parent == null) { | ||
179 | return null; | ||
180 | } else { | ||
181 | @SuppressWarnings("unchecked") | ||
182 | N node = (N)this; | ||
183 | while (node.parent != null && node.parent.left == node) { | ||
184 | node = node.parent; | ||
185 | } | ||
186 | return node.parent; | ||
187 | } | ||
188 | } | ||
189 | |||
190 | /** Returns the node immediately after this in the tree that contains this node, if any. */ | ||
191 | public N successor() { | ||
192 | if (!right.isLeaf()) { | ||
193 | N node; | ||
194 | for (node = right; !node.left.isLeaf(); node = node.left); | ||
195 | return node; | ||
196 | } else if (parent == null) { | ||
197 | return null; | ||
198 | } else { | ||
199 | @SuppressWarnings("unchecked") | ||
200 | N node = (N)this; | ||
201 | while (node.parent != null && node.parent.right == node) { | ||
202 | node = node.parent; | ||
203 | } | ||
204 | return node.parent; | ||
205 | } | ||
206 | } | ||
207 | |||
208 | /** | ||
209 | * Performs a left rotation about this node. This method assumes that !isLeaf() && !right.isLeaf(). It calls | ||
210 | * augment() on this node and on its resulting parent. However, it does not call augment() on any of the resulting | ||
211 | * parent's ancestors, because that is normally the responsibility of the caller. | ||
212 | * @return The return value from calling augment() on the resulting parent. | ||
213 | */ | ||
214 | public boolean rotateLeft() { | ||
215 | if (isLeaf() || right.isLeaf()) { | ||
216 | throw new IllegalArgumentException("The node or its right child is a leaf"); | ||
217 | } | ||
218 | N newParent = right; | ||
219 | right = newParent.left; | ||
220 | @SuppressWarnings("unchecked") | ||
221 | N nThis = (N)this; | ||
222 | if (!right.isLeaf()) { | ||
223 | right.parent = nThis; | ||
224 | } | ||
225 | newParent.parent = parent; | ||
226 | parent = newParent; | ||
227 | newParent.left = nThis; | ||
228 | if (newParent.parent != null) { | ||
229 | if (newParent.parent.left == this) { | ||
230 | newParent.parent.left = newParent; | ||
231 | } else { | ||
232 | newParent.parent.right = newParent; | ||
233 | } | ||
234 | } | ||
235 | augment(); | ||
236 | return newParent.augment(); | ||
237 | } | ||
238 | |||
239 | /** | ||
240 | * Performs a right rotation about this node. This method assumes that !isLeaf() && !left.isLeaf(). It calls | ||
241 | * augment() on this node and on its resulting parent. However, it does not call augment() on any of the resulting | ||
242 | * parent's ancestors, because that is normally the responsibility of the caller. | ||
243 | * @return The return value from calling augment() on the resulting parent. | ||
244 | */ | ||
245 | public boolean rotateRight() { | ||
246 | if (isLeaf() || left.isLeaf()) { | ||
247 | throw new IllegalArgumentException("The node or its left child is a leaf"); | ||
248 | } | ||
249 | N newParent = left; | ||
250 | left = newParent.right; | ||
251 | @SuppressWarnings("unchecked") | ||
252 | N nThis = (N)this; | ||
253 | if (!left.isLeaf()) { | ||
254 | left.parent = nThis; | ||
255 | } | ||
256 | newParent.parent = parent; | ||
257 | parent = newParent; | ||
258 | newParent.right = nThis; | ||
259 | if (newParent.parent != null) { | ||
260 | if (newParent.parent.left == this) { | ||
261 | newParent.parent.left = newParent; | ||
262 | } else { | ||
263 | newParent.parent.right = newParent; | ||
264 | } | ||
265 | } | ||
266 | augment(); | ||
267 | return newParent.augment(); | ||
268 | } | ||
269 | |||
270 | /** | ||
271 | * Performs red-black insertion fixup. To be more precise, this fixes a tree that satisfies all of the requirements | ||
272 | * of red-black trees, except that this may be a red child of a red node, and if this is the root, the root may be | ||
273 | * red. node.isRed must initially be true. This method assumes that this is not a leaf node. The method performs | ||
274 | * any rotations by calling rotateLeft() and rotateRight(). This method is more efficient than fixInsertion if | ||
275 | * "augment" is false or augment() might return false. | ||
276 | * @param augment Whether to set the augmentation information for "node" and its ancestors, by calling augment(). | ||
277 | */ | ||
278 | public void fixInsertionWithoutGettingRoot(boolean augment) { | ||
279 | if (!isRed) { | ||
280 | throw new IllegalArgumentException("The node must be red"); | ||
281 | } | ||
282 | boolean changed = augment; | ||
283 | if (augment) { | ||
284 | augment(); | ||
285 | } | ||
286 | |||
287 | RedBlackNode<N> node = this; | ||
288 | while (node.parent != null && node.parent.isRed) { | ||
289 | N parent = node.parent; | ||
290 | N grandparent = parent.parent; | ||
291 | if (grandparent.left.isRed && grandparent.right.isRed) { | ||
292 | grandparent.left.isRed = false; | ||
293 | grandparent.right.isRed = false; | ||
294 | grandparent.isRed = true; | ||
295 | |||
296 | if (changed) { | ||
297 | changed = parent.augment(); | ||
298 | if (changed) { | ||
299 | changed = grandparent.augment(); | ||
300 | } | ||
301 | } | ||
302 | node = grandparent; | ||
303 | } else { | ||
304 | if (parent.left == node) { | ||
305 | if (grandparent.right == parent) { | ||
306 | parent.rotateRight(); | ||
307 | node = parent; | ||
308 | parent = node.parent; | ||
309 | } | ||
310 | } else if (grandparent.left == parent) { | ||
311 | parent.rotateLeft(); | ||
312 | node = parent; | ||
313 | parent = node.parent; | ||
314 | } | ||
315 | |||
316 | if (parent.left == node) { | ||
317 | boolean grandparentChanged = grandparent.rotateRight(); | ||
318 | if (augment) { | ||
319 | changed = grandparentChanged; | ||
320 | } | ||
321 | } else { | ||
322 | boolean grandparentChanged = grandparent.rotateLeft(); | ||
323 | if (augment) { | ||
324 | changed = grandparentChanged; | ||
325 | } | ||
326 | } | ||
327 | |||
328 | parent.isRed = false; | ||
329 | grandparent.isRed = true; | ||
330 | node = parent; | ||
331 | break; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | if (node.parent == null) { | ||
336 | node.isRed = false; | ||
337 | } | ||
338 | if (changed) { | ||
339 | for (node = node.parent; node != null; node = node.parent) { | ||
340 | if (!node.augment()) { | ||
341 | break; | ||
342 | } | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | |||
347 | /** | ||
348 | * Performs red-black insertion fixup. To be more precise, this fixes a tree that satisfies all of the requirements | ||
349 | * of red-black trees, except that this may be a red child of a red node, and if this is the root, the root may be | ||
350 | * red. node.isRed must initially be true. This method assumes that this is not a leaf node. The method performs | ||
351 | * any rotations by calling rotateLeft() and rotateRight(). This method is more efficient than fixInsertion() if | ||
352 | * augment() might return false. | ||
353 | */ | ||
354 | public void fixInsertionWithoutGettingRoot() { | ||
355 | fixInsertionWithoutGettingRoot(true); | ||
356 | } | ||
357 | |||
358 | /** | ||
359 | * Performs red-black insertion fixup. To be more precise, this fixes a tree that satisfies all of the requirements | ||
360 | * of red-black trees, except that this may be a red child of a red node, and if this is the root, the root may be | ||
361 | * red. node.isRed must initially be true. This method assumes that this is not a leaf node. The method performs | ||
362 | * any rotations by calling rotateLeft() and rotateRight(). | ||
363 | * @param augment Whether to set the augmentation information for "node" and its ancestors, by calling augment(). | ||
364 | * @return The root of the resulting tree. | ||
365 | */ | ||
366 | public N fixInsertion(boolean augment) { | ||
367 | fixInsertionWithoutGettingRoot(augment); | ||
368 | return root(); | ||
369 | } | ||
370 | |||
371 | /** | ||
372 | * Performs red-black insertion fixup. To be more precise, this fixes a tree that satisfies all of the requirements | ||
373 | * of red-black trees, except that this may be a red child of a red node, and if this is the root, the root may be | ||
374 | * red. node.isRed must initially be true. This method assumes that this is not a leaf node. The method performs | ||
375 | * any rotations by calling rotateLeft() and rotateRight(). | ||
376 | * @return The root of the resulting tree. | ||
377 | */ | ||
378 | public N fixInsertion() { | ||
379 | fixInsertionWithoutGettingRoot(true); | ||
380 | return root(); | ||
381 | } | ||
382 | |||
383 | /** Returns a Comparator that compares instances of N using their natural order, as in N.compareTo. */ | ||
384 | @SuppressWarnings({"rawtypes", "unchecked"}) | ||
385 | private Comparator<N> naturalOrder() { | ||
386 | Comparator comparator = (Comparator)NATURAL_ORDER; | ||
387 | return (Comparator<N>)comparator; | ||
388 | } | ||
389 | |||
390 | /** | ||
391 | * Inserts the specified node into the tree rooted at this node. Assumes this is the root. We treat newNode as a | ||
392 | * solitary node that does not belong to any tree, and we ignore its initial "parent", "left", "right", and isRed | ||
393 | * fields. | ||
394 | * | ||
395 | * If it is not efficient or convenient to find the location for a node using a Comparator, then you should manually | ||
396 | * add the node to the appropriate location, color it red, and call fixInsertion(). | ||
397 | * | ||
398 | * @param newNode The node to insert. | ||
399 | * @param allowDuplicates Whether to insert newNode if there is an equal node in the tree. To check whether we | ||
400 | * inserted newNode, check whether newNode.parent is null and the return value differs from newNode. | ||
401 | * @param comparator A comparator indicating where to put the node. If this is null, we use the nodes' natural | ||
402 | * order, as in N.compareTo. If you are passing null, then you must override the compareTo method, because the | ||
403 | * default implementation requires the nodes to already be in the same tree. | ||
404 | * @return The root of the resulting tree. | ||
405 | */ | ||
406 | public N insert(N newNode, boolean allowDuplicates, Comparator<? super N> comparator) { | ||
407 | if (parent != null) { | ||
408 | throw new IllegalArgumentException("This is not the root of a tree"); | ||
409 | } | ||
410 | @SuppressWarnings("unchecked") | ||
411 | N nThis = (N)this; | ||
412 | if (isLeaf()) { | ||
413 | newNode.isRed = false; | ||
414 | newNode.left = nThis; | ||
415 | newNode.right = nThis; | ||
416 | newNode.parent = null; | ||
417 | newNode.augment(); | ||
418 | return newNode; | ||
419 | } | ||
420 | if (comparator == null) { | ||
421 | comparator = naturalOrder(); | ||
422 | } | ||
423 | |||
424 | N node = nThis; | ||
425 | int comparison; | ||
426 | while (true) { | ||
427 | comparison = comparator.compare(newNode, node); | ||
428 | if (comparison < 0) { | ||
429 | if (!node.left.isLeaf()) { | ||
430 | node = node.left; | ||
431 | } else { | ||
432 | newNode.left = node.left; | ||
433 | newNode.right = node.left; | ||
434 | node.left = newNode; | ||
435 | newNode.parent = node; | ||
436 | break; | ||
437 | } | ||
438 | } else if (comparison > 0 || allowDuplicates) { | ||
439 | if (!node.right.isLeaf()) { | ||
440 | node = node.right; | ||
441 | } else { | ||
442 | newNode.left = node.right; | ||
443 | newNode.right = node.right; | ||
444 | node.right = newNode; | ||
445 | newNode.parent = node; | ||
446 | break; | ||
447 | } | ||
448 | } else { | ||
449 | newNode.parent = null; | ||
450 | return nThis; | ||
451 | } | ||
452 | } | ||
453 | newNode.isRed = true; | ||
454 | return newNode.fixInsertion(); | ||
455 | } | ||
456 | |||
457 | /** | ||
458 | * Moves this node to its successor's former position in the tree and vice versa, i.e. sets the "left", "right", | ||
459 | * "parent", and isRed fields of each. This method assumes that this is not a leaf node. | ||
460 | * @return The node with which we swapped. | ||
461 | */ | ||
462 | private N swapWithSuccessor() { | ||
463 | N replacement = successor(); | ||
464 | boolean oldReplacementIsRed = replacement.isRed; | ||
465 | N oldReplacementLeft = replacement.left; | ||
466 | N oldReplacementRight = replacement.right; | ||
467 | N oldReplacementParent = replacement.parent; | ||
468 | |||
469 | replacement.isRed = isRed; | ||
470 | replacement.left = left; | ||
471 | replacement.right = right; | ||
472 | replacement.parent = parent; | ||
473 | if (parent != null) { | ||
474 | if (parent.left == this) { | ||
475 | parent.left = replacement; | ||
476 | } else { | ||
477 | parent.right = replacement; | ||
478 | } | ||
479 | } | ||
480 | |||
481 | @SuppressWarnings("unchecked") | ||
482 | N nThis = (N)this; | ||
483 | isRed = oldReplacementIsRed; | ||
484 | left = oldReplacementLeft; | ||
485 | right = oldReplacementRight; | ||
486 | if (oldReplacementParent == this) { | ||
487 | parent = replacement; | ||
488 | parent.right = nThis; | ||
489 | } else { | ||
490 | parent = oldReplacementParent; | ||
491 | parent.left = nThis; | ||
492 | } | ||
493 | |||
494 | replacement.right.parent = replacement; | ||
495 | if (!replacement.left.isLeaf()) { | ||
496 | replacement.left.parent = replacement; | ||
497 | } | ||
498 | if (!right.isLeaf()) { | ||
499 | right.parent = nThis; | ||
500 | } | ||
501 | return replacement; | ||
502 | } | ||
503 | |||
504 | /** | ||
505 | * Performs red-black deletion fixup. To be more precise, this fixes a tree that satisfies all of the requirements | ||
506 | * of red-black trees, except that all paths from the root to a leaf that pass through the sibling of this node have | ||
507 | * one fewer black node than all other root-to-leaf paths. This method assumes that this is not a leaf node. | ||
508 | */ | ||
509 | private void fixSiblingDeletion() { | ||
510 | RedBlackNode<N> sibling = this; | ||
511 | boolean changed = true; | ||
512 | boolean haveAugmentedParent = false; | ||
513 | boolean haveAugmentedGrandparent = false; | ||
514 | while (true) { | ||
515 | N parent = sibling.parent; | ||
516 | if (sibling.isRed) { | ||
517 | parent.isRed = true; | ||
518 | sibling.isRed = false; | ||
519 | if (parent.left == sibling) { | ||
520 | changed = parent.rotateRight(); | ||
521 | sibling = parent.left; | ||
522 | } else { | ||
523 | changed = parent.rotateLeft(); | ||
524 | sibling = parent.right; | ||
525 | } | ||
526 | haveAugmentedParent = true; | ||
527 | haveAugmentedGrandparent = true; | ||
528 | } else if (!sibling.left.isRed && !sibling.right.isRed) { | ||
529 | sibling.isRed = true; | ||
530 | if (parent.isRed) { | ||
531 | parent.isRed = false; | ||
532 | break; | ||
533 | } else { | ||
534 | if (changed && !haveAugmentedParent) { | ||
535 | changed = parent.augment(); | ||
536 | } | ||
537 | N grandparent = parent.parent; | ||
538 | if (grandparent == null) { | ||
539 | break; | ||
540 | } else if (grandparent.left == parent) { | ||
541 | sibling = grandparent.right; | ||
542 | } else { | ||
543 | sibling = grandparent.left; | ||
544 | } | ||
545 | haveAugmentedParent = haveAugmentedGrandparent; | ||
546 | haveAugmentedGrandparent = false; | ||
547 | } | ||
548 | } else { | ||
549 | if (sibling == parent.left) { | ||
550 | if (!sibling.left.isRed) { | ||
551 | sibling.rotateLeft(); | ||
552 | sibling = sibling.parent; | ||
553 | } | ||
554 | } else if (!sibling.right.isRed) { | ||
555 | sibling.rotateRight(); | ||
556 | sibling = sibling.parent; | ||
557 | } | ||
558 | sibling.isRed = parent.isRed; | ||
559 | parent.isRed = false; | ||
560 | if (sibling == parent.left) { | ||
561 | sibling.left.isRed = false; | ||
562 | changed = parent.rotateRight(); | ||
563 | } else { | ||
564 | sibling.right.isRed = false; | ||
565 | changed = parent.rotateLeft(); | ||
566 | } | ||
567 | haveAugmentedParent = haveAugmentedGrandparent; | ||
568 | haveAugmentedGrandparent = false; | ||
569 | break; | ||
570 | } | ||
571 | } | ||
572 | |||
573 | // Update augmentation info | ||
574 | N parent = sibling.parent; | ||
575 | if (changed && parent != null) { | ||
576 | if (!haveAugmentedParent) { | ||
577 | changed = parent.augment(); | ||
578 | } | ||
579 | if (changed && parent.parent != null) { | ||
580 | parent = parent.parent; | ||
581 | if (!haveAugmentedGrandparent) { | ||
582 | changed = parent.augment(); | ||
583 | } | ||
584 | if (changed) { | ||
585 | for (parent = parent.parent; parent != null; parent = parent.parent) { | ||
586 | if (!parent.augment()) { | ||
587 | break; | ||
588 | } | ||
589 | } | ||
590 | } | ||
591 | } | ||
592 | } | ||
593 | } | ||
594 | |||
595 | /** | ||
596 | * Removes this node from the tree that contains it. The effect of this method on the fields of this node is | ||
597 | * unspecified. This method assumes that this is not a leaf node. This method is more efficient than remove() if | ||
598 | * augment() might return false. | ||
599 | * | ||
600 | * If the node has two children, we begin by moving the node's successor to its former position, by changing the | ||
601 | * successor's "left", "right", "parent", and isRed fields. | ||
602 | */ | ||
603 | public void removeWithoutGettingRoot() { | ||
604 | if (isLeaf()) { | ||
605 | throw new IllegalArgumentException("Attempted to remove a leaf node"); | ||
606 | } | ||
607 | N replacement; | ||
608 | if (left.isLeaf() || right.isLeaf()) { | ||
609 | replacement = null; | ||
610 | } else { | ||
611 | replacement = swapWithSuccessor(); | ||
612 | } | ||
613 | |||
614 | N child; | ||
615 | if (!left.isLeaf()) { | ||
616 | child = left; | ||
617 | } else if (!right.isLeaf()) { | ||
618 | child = right; | ||
619 | } else { | ||
620 | child = null; | ||
621 | } | ||
622 | |||
623 | if (child != null) { | ||
624 | // Replace this node with its child | ||
625 | child.parent = parent; | ||
626 | if (parent != null) { | ||
627 | if (parent.left == this) { | ||
628 | parent.left = child; | ||
629 | } else { | ||
630 | parent.right = child; | ||
631 | } | ||
632 | } | ||
633 | child.isRed = false; | ||
634 | |||
635 | if (child.parent != null) { | ||
636 | N parent; | ||
637 | for (parent = child.parent; parent != null; parent = parent.parent) { | ||
638 | if (!parent.augment()) { | ||
639 | break; | ||
640 | } | ||
641 | } | ||
642 | } | ||
643 | } else if (parent != null) { | ||
644 | // Replace this node with a leaf node | ||
645 | N leaf = left; | ||
646 | N parent = this.parent; | ||
647 | N sibling; | ||
648 | if (parent.left == this) { | ||
649 | parent.left = leaf; | ||
650 | sibling = parent.right; | ||
651 | } else { | ||
652 | parent.right = leaf; | ||
653 | sibling = parent.left; | ||
654 | } | ||
655 | |||
656 | if (!isRed) { | ||
657 | RedBlackNode<N> siblingNode = sibling; | ||
658 | siblingNode.fixSiblingDeletion(); | ||
659 | } else { | ||
660 | while (parent != null) { | ||
661 | if (!parent.augment()) { | ||
662 | break; | ||
663 | } | ||
664 | parent = parent.parent; | ||
665 | } | ||
666 | } | ||
667 | } | ||
668 | |||
669 | if (replacement != null) { | ||
670 | replacement.augment(); | ||
671 | for (N parent = replacement.parent; parent != null; parent = parent.parent) { | ||
672 | if (!parent.augment()) { | ||
673 | break; | ||
674 | } | ||
675 | } | ||
676 | } | ||
677 | |||
678 | // Clear any previously existing links, so that we're more likely to encounter an exception if we attempt to | ||
679 | // access the removed node | ||
680 | parent = null; | ||
681 | left = null; | ||
682 | right = null; | ||
683 | isRed = true; | ||
684 | } | ||
685 | |||
686 | /** | ||
687 | * Removes this node from the tree that contains it. The effect of this method on the fields of this node is | ||
688 | * unspecified. This method assumes that this is not a leaf node. | ||
689 | * | ||
690 | * If the node has two children, we begin by moving the node's successor to its former position, by changing the | ||
691 | * successor's "left", "right", "parent", and isRed fields. | ||
692 | * | ||
693 | * @return The root of the resulting tree. | ||
694 | */ | ||
695 | public N remove() { | ||
696 | if (isLeaf()) { | ||
697 | throw new IllegalArgumentException("Attempted to remove a leaf node"); | ||
698 | } | ||
699 | |||
700 | // Find an arbitrary non-leaf node in the tree other than this node | ||
701 | N node; | ||
702 | if (parent != null) { | ||
703 | node = parent; | ||
704 | } else if (!left.isLeaf()) { | ||
705 | node = left; | ||
706 | } else if (!right.isLeaf()) { | ||
707 | node = right; | ||
708 | } else { | ||
709 | return left; | ||
710 | } | ||
711 | |||
712 | removeWithoutGettingRoot(); | ||
713 | return node.root(); | ||
714 | } | ||
715 | |||
716 | /** | ||
717 | * Returns the root of a perfectly height-balanced subtree containing the next "size" (non-leaf) nodes from | ||
718 | * "iterator", in iteration order. This method is responsible for setting the "left", "right", "parent", and isRed | ||
719 | * fields of the nodes, and calling augment() as appropriate. It ignores the initial values of the "left", "right", | ||
720 | * "parent", and isRed fields. | ||
721 | * @param iterator The nodes. | ||
722 | * @param size The number of nodes. | ||
723 | * @param height The "height" of the subtree's root node above the deepest leaf in the tree that contains it. Since | ||
724 | * insertion fixup is slow if there are too many red nodes and deleteion fixup is slow if there are too few red | ||
725 | * nodes, we compromise and have red nodes at every fourth level. We color a node red iff its "height" is equal | ||
726 | * to 1 mod 4. | ||
727 | * @param leaf The leaf node. | ||
728 | * @return The root of the subtree. | ||
729 | */ | ||
730 | private static <N extends RedBlackNode<N>> N createTree( | ||
731 | Iterator<? extends N> iterator, int size, int height, N leaf) { | ||
732 | if (size == 0) { | ||
733 | return leaf; | ||
734 | } else { | ||
735 | N left = createTree(iterator, (size - 1) / 2, height - 1, leaf); | ||
736 | N node = iterator.next(); | ||
737 | N right = createTree(iterator, size / 2, height - 1, leaf); | ||
738 | |||
739 | node.isRed = height % 4 == 1; | ||
740 | node.left = left; | ||
741 | node.right = right; | ||
742 | if (!left.isLeaf()) { | ||
743 | left.parent = node; | ||
744 | } | ||
745 | if (!right.isLeaf()) { | ||
746 | right.parent = node; | ||
747 | } | ||
748 | |||
749 | node.augment(); | ||
750 | return node; | ||
751 | } | ||
752 | } | ||
753 | |||
754 | /** | ||
755 | * Returns the root of a perfectly height-balanced tree containing the specified nodes, in iteration order. This | ||
756 | * method is responsible for setting the "left", "right", "parent", and isRed fields of the nodes (excluding | ||
757 | * "leaf"), and calling augment() as appropriate. It ignores the initial values of the "left", "right", "parent", | ||
758 | * and isRed fields. | ||
759 | * @param nodes The nodes. | ||
760 | * @param leaf The leaf node. | ||
761 | * @return The root of the tree. | ||
762 | */ | ||
763 | public static <N extends RedBlackNode<N>> N createTree(Collection<? extends N> nodes, N leaf) { | ||
764 | int size = nodes.size(); | ||
765 | if (size == 0) { | ||
766 | return leaf; | ||
767 | } | ||
768 | |||
769 | int height = 0; | ||
770 | for (int subtreeSize = size; subtreeSize > 0; subtreeSize /= 2) { | ||
771 | height++; | ||
772 | } | ||
773 | |||
774 | N node = createTree(nodes.iterator(), size, height, leaf); | ||
775 | node.parent = null; | ||
776 | node.isRed = false; | ||
777 | return node; | ||
778 | } | ||
779 | |||
780 | /** | ||
781 | * Concatenates to the end of the tree rooted at this node. To be precise, given that all of the nodes in this | ||
782 | * precede the node "pivot", which precedes all of the nodes in "last", this returns the root of a tree containing | ||
783 | * all of these nodes. This method destroys the trees rooted at "this" and "last". We treat "pivot" as a solitary | ||
784 | * node that does not belong to any tree, and we ignore its initial "parent", "left", "right", and isRed fields. | ||
785 | * This method assumes that this node and "last" are the roots of their respective trees. | ||
786 | * | ||
787 | * This method takes O(log N) time. It is more efficient than inserting "pivot" and then calling concatenate(last). | ||
788 | * It is considerably more efficient than inserting "pivot" and all of the nodes in "last". | ||
789 | */ | ||
790 | public N concatenate(N last, N pivot) { | ||
791 | // If the black height of "first", where first = this, is less than or equal to that of "last", starting at the | ||
792 | // root of "last", we keep going left until we reach a black node whose black height is equal to that of | ||
793 | // "first". Then, we make "pivot" the parent of that node and of "first", coloring it red, and perform | ||
794 | // insertion fixup on the pivot. If the black height of "first" is greater than that of "last", we do the | ||
795 | // mirror image of the above. | ||
796 | |||
797 | if (parent != null) { | ||
798 | throw new IllegalArgumentException("This is not the root of a tree"); | ||
799 | } | ||
800 | if (last.parent != null) { | ||
801 | throw new IllegalArgumentException("\"last\" is not the root of a tree"); | ||
802 | } | ||
803 | |||
804 | // Compute the black height of the trees | ||
805 | int firstBlackHeight = 0; | ||
806 | @SuppressWarnings("unchecked") | ||
807 | N first = (N)this; | ||
808 | for (N node = first; node != null; node = node.right) { | ||
809 | if (!node.isRed) { | ||
810 | firstBlackHeight++; | ||
811 | } | ||
812 | } | ||
813 | int lastBlackHeight = 0; | ||
814 | for (N node = last; node != null; node = node.right) { | ||
815 | if (!node.isRed) { | ||
816 | lastBlackHeight++; | ||
817 | } | ||
818 | } | ||
819 | |||
820 | // Identify the children and parent of pivot | ||
821 | N firstChild = first; | ||
822 | N lastChild = last; | ||
823 | N parent; | ||
824 | if (firstBlackHeight <= lastBlackHeight) { | ||
825 | parent = null; | ||
826 | int blackHeight = lastBlackHeight; | ||
827 | while (blackHeight > firstBlackHeight) { | ||
828 | if (!lastChild.isRed) { | ||
829 | blackHeight--; | ||
830 | } | ||
831 | parent = lastChild; | ||
832 | lastChild = lastChild.left; | ||
833 | } | ||
834 | if (lastChild.isRed) { | ||
835 | parent = lastChild; | ||
836 | lastChild = lastChild.left; | ||
837 | } | ||
838 | } else { | ||
839 | parent = null; | ||
840 | int blackHeight = firstBlackHeight; | ||
841 | while (blackHeight > lastBlackHeight) { | ||
842 | if (!firstChild.isRed) { | ||
843 | blackHeight--; | ||
844 | } | ||
845 | parent = firstChild; | ||
846 | firstChild = firstChild.right; | ||
847 | } | ||
848 | if (firstChild.isRed) { | ||
849 | parent = firstChild; | ||
850 | firstChild = firstChild.right; | ||
851 | } | ||
852 | } | ||
853 | |||
854 | // Add "pivot" to the tree | ||
855 | pivot.isRed = true; | ||
856 | pivot.parent = parent; | ||
857 | if (parent != null) { | ||
858 | if (firstBlackHeight < lastBlackHeight) { | ||
859 | parent.left = pivot; | ||
860 | } else { | ||
861 | parent.right = pivot; | ||
862 | } | ||
863 | } | ||
864 | pivot.left = firstChild; | ||
865 | if (!firstChild.isLeaf()) { | ||
866 | firstChild.parent = pivot; | ||
867 | } | ||
868 | pivot.right = lastChild; | ||
869 | if (!lastChild.isLeaf()) { | ||
870 | lastChild.parent = pivot; | ||
871 | } | ||
872 | |||
873 | // Perform insertion fixup | ||
874 | return pivot.fixInsertion(); | ||
875 | } | ||
876 | |||
877 | /** | ||
878 | * Concatenates the tree rooted at "last" to the end of the tree rooted at this node. To be precise, given that all | ||
879 | * of the nodes in this precede all of the nodes in "last", this returns the root of a tree containing all of these | ||
880 | * nodes. This method destroys the trees rooted at "this" and "last". It assumes that this node and "last" are the | ||
881 | * roots of their respective trees. This method takes O(log N) time. It is considerably more efficient than | ||
882 | * inserting all of the nodes in "last". | ||
883 | */ | ||
884 | public N concatenate(N last) { | ||
885 | if (parent != null || last.parent != null) { | ||
886 | throw new IllegalArgumentException("The node is not the root of a tree"); | ||
887 | } | ||
888 | if (isLeaf()) { | ||
889 | return last; | ||
890 | } else if (last.isLeaf()) { | ||
891 | @SuppressWarnings("unchecked") | ||
892 | N nThis = (N)this; | ||
893 | return nThis; | ||
894 | } else { | ||
895 | N node = last.min(); | ||
896 | last = node.remove(); | ||
897 | return concatenate(last, node); | ||
898 | } | ||
899 | } | ||
900 | |||
901 | /** | ||
902 | * Splits the tree rooted at this node into two trees, so that the first element of the return value is the root of | ||
903 | * a tree consisting of the nodes that were before the specified node, and the second element of the return value is | ||
904 | * the root of a tree consisting of the nodes that were equal to or after the specified node. This method is | ||
905 | * destructive, meaning it does not preserve the original tree. It assumes that this node is the root and is in the | ||
906 | * same tree as splitNode. It takes O(log N) time. It is considerably more efficient than removing all of the | ||
907 | * nodes at or after splitNode and then creating a new tree from those nodes. | ||
908 | * @param The node at which to split the tree. | ||
909 | * @return An array consisting of the resulting trees. | ||
910 | */ | ||
911 | public N[] split(N splitNode) { | ||
912 | // To split the tree, we accumulate a pre-split tree and a post-split tree. We walk down the tree toward the | ||
913 | // position where we are splitting. Whenever we go left, we concatenate the right subtree with the post-split | ||
914 | // tree, and whenever we go right, we concatenate the pre-split tree with the left subtree. We use the | ||
915 | // concatenation algorithm described in concatenate(Object, Object). For the pivot, we use the last node where | ||
916 | // we went left in the case of a left move, and the last node where we went right in the case of a right move. | ||
917 | // | ||
918 | // The method uses the following variables: | ||
919 | // | ||
920 | // node: The current node in our walk down the tree. | ||
921 | // first: A node on the right spine of the pre-split tree. At the beginning of each iteration, it is the black | ||
922 | // node with the same black height as "node". If the pre-split tree is empty, this is null instead. | ||
923 | // firstParent: The parent of "first". If the pre-split tree is empty, this is null. Otherwise, this is the | ||
924 | // same as first.parent, unless first.isLeaf(). | ||
925 | // firstPivot: The node where we last went right, i.e. the next node to use as a pivot when concatenating with | ||
926 | // the pre-split tree. | ||
927 | // advanceFirst: Whether to set "first" to be its next black descendant at the end of the loop. | ||
928 | // last, lastParent, lastPivot, advanceLast: Analogous to "first", firstParent, firstPivot, and advanceFirst, | ||
929 | // but for the post-split tree. | ||
930 | if (parent != null) { | ||
931 | throw new IllegalArgumentException("This is not the root of a tree"); | ||
932 | } | ||
933 | if (isLeaf() || splitNode.isLeaf()) { | ||
934 | throw new IllegalArgumentException("The root or the split node is a leaf"); | ||
935 | } | ||
936 | |||
937 | // Create an array containing the path from the root to splitNode | ||
938 | int depth = 1; | ||
939 | N parent; | ||
940 | for (parent = splitNode; parent.parent != null; parent = parent.parent) { | ||
941 | depth++; | ||
942 | } | ||
943 | if (parent != this) { | ||
944 | throw new IllegalArgumentException("The split node does not belong to this tree"); | ||
945 | } | ||
946 | RedBlackNode<?>[] path = new RedBlackNode<?>[depth]; | ||
947 | for (parent = splitNode; parent != null; parent = parent.parent) { | ||
948 | depth--; | ||
949 | path[depth] = parent; | ||
950 | } | ||
951 | |||
952 | @SuppressWarnings("unchecked") | ||
953 | N node = (N)this; | ||
954 | N first = null; | ||
955 | N firstParent = null; | ||
956 | N last = null; | ||
957 | N lastParent = null; | ||
958 | N firstPivot = null; | ||
959 | N lastPivot = null; | ||
960 | while (!node.isLeaf()) { | ||
961 | boolean advanceFirst = !node.isRed && firstPivot != null; | ||
962 | boolean advanceLast = !node.isRed && lastPivot != null; | ||
963 | if ((depth + 1 < path.length && path[depth + 1] == node.left) || depth + 1 == path.length) { | ||
964 | // Left move | ||
965 | if (lastPivot == null) { | ||
966 | // The post-split tree is empty | ||
967 | last = node.right; | ||
968 | last.parent = null; | ||
969 | if (last.isRed) { | ||
970 | last.isRed = false; | ||
971 | lastParent = last; | ||
972 | last = last.left; | ||
973 | } | ||
974 | } else { | ||
975 | // Concatenate node.right and the post-split tree | ||
976 | if (node.right.isRed) { | ||
977 | node.right.isRed = false; | ||
978 | } else if (!node.isRed) { | ||
979 | lastParent = last; | ||
980 | last = last.left; | ||
981 | if (last.isRed) { | ||
982 | lastParent = last; | ||
983 | last = last.left; | ||
984 | } | ||
985 | advanceLast = false; | ||
986 | } | ||
987 | lastPivot.isRed = true; | ||
988 | lastPivot.parent = lastParent; | ||
989 | if (lastParent != null) { | ||
990 | lastParent.left = lastPivot; | ||
991 | } | ||
992 | lastPivot.left = node.right; | ||
993 | if (!lastPivot.left.isLeaf()) { | ||
994 | lastPivot.left.parent = lastPivot; | ||
995 | } | ||
996 | lastPivot.right = last; | ||
997 | if (!last.isLeaf()) { | ||
998 | last.parent = lastPivot; | ||
999 | } | ||
1000 | last = lastPivot.left; | ||
1001 | lastParent = lastPivot; | ||
1002 | lastPivot.fixInsertionWithoutGettingRoot(false); | ||
1003 | } | ||
1004 | lastPivot = node; | ||
1005 | node = node.left; | ||
1006 | } else { | ||
1007 | // Right move | ||
1008 | if (firstPivot == null) { | ||
1009 | // The pre-split tree is empty | ||
1010 | first = node.left; | ||
1011 | first.parent = null; | ||
1012 | if (first.isRed) { | ||
1013 | first.isRed = false; | ||
1014 | firstParent = first; | ||
1015 | first = first.right; | ||
1016 | } | ||
1017 | } else { | ||
1018 | // Concatenate the post-split tree and node.left | ||
1019 | if (node.left.isRed) { | ||
1020 | node.left.isRed = false; | ||
1021 | } else if (!node.isRed) { | ||
1022 | firstParent = first; | ||
1023 | first = first.right; | ||
1024 | if (first.isRed) { | ||
1025 | firstParent = first; | ||
1026 | first = first.right; | ||
1027 | } | ||
1028 | advanceFirst = false; | ||
1029 | } | ||
1030 | firstPivot.isRed = true; | ||
1031 | firstPivot.parent = firstParent; | ||
1032 | if (firstParent != null) { | ||
1033 | firstParent.right = firstPivot; | ||
1034 | } | ||
1035 | firstPivot.right = node.left; | ||
1036 | if (!firstPivot.right.isLeaf()) { | ||
1037 | firstPivot.right.parent = firstPivot; | ||
1038 | } | ||
1039 | firstPivot.left = first; | ||
1040 | if (!first.isLeaf()) { | ||
1041 | first.parent = firstPivot; | ||
1042 | } | ||
1043 | first = firstPivot.right; | ||
1044 | firstParent = firstPivot; | ||
1045 | firstPivot.fixInsertionWithoutGettingRoot(false); | ||
1046 | } | ||
1047 | firstPivot = node; | ||
1048 | node = node.right; | ||
1049 | } | ||
1050 | |||
1051 | depth++; | ||
1052 | |||
1053 | // Update "first" and "last" to be the nodes at the proper black height | ||
1054 | if (advanceFirst) { | ||
1055 | firstParent = first; | ||
1056 | first = first.right; | ||
1057 | if (first.isRed) { | ||
1058 | firstParent = first; | ||
1059 | first = first.right; | ||
1060 | } | ||
1061 | } | ||
1062 | if (advanceLast) { | ||
1063 | lastParent = last; | ||
1064 | last = last.left; | ||
1065 | if (last.isRed) { | ||
1066 | lastParent = last; | ||
1067 | last = last.left; | ||
1068 | } | ||
1069 | } | ||
1070 | } | ||
1071 | |||
1072 | // Add firstPivot to the pre-split tree | ||
1073 | N leaf = node; | ||
1074 | if (first == null) { | ||
1075 | first = leaf; | ||
1076 | } else { | ||
1077 | firstPivot.isRed = true; | ||
1078 | firstPivot.parent = firstParent; | ||
1079 | if (firstParent != null) { | ||
1080 | firstParent.right = firstPivot; | ||
1081 | } | ||
1082 | firstPivot.left = leaf; | ||
1083 | firstPivot.right = leaf; | ||
1084 | firstPivot.fixInsertionWithoutGettingRoot(false); | ||
1085 | for (first = firstPivot; first.parent != null; first = first.parent) { | ||
1086 | first.augment(); | ||
1087 | } | ||
1088 | first.augment(); | ||
1089 | } | ||
1090 | |||
1091 | // Add lastPivot to the post-split tree | ||
1092 | lastPivot.isRed = true; | ||
1093 | lastPivot.parent = lastParent; | ||
1094 | if (lastParent != null) { | ||
1095 | lastParent.left = lastPivot; | ||
1096 | } | ||
1097 | lastPivot.left = leaf; | ||
1098 | lastPivot.right = leaf; | ||
1099 | lastPivot.fixInsertionWithoutGettingRoot(false); | ||
1100 | for (last = lastPivot; last.parent != null; last = last.parent) { | ||
1101 | last.augment(); | ||
1102 | } | ||
1103 | last.augment(); | ||
1104 | |||
1105 | @SuppressWarnings("unchecked") | ||
1106 | N[] result = (N[])Array.newInstance(getClass(), 2); | ||
1107 | result[0] = first; | ||
1108 | result[1] = last; | ||
1109 | return result; | ||
1110 | } | ||
1111 | |||
1112 | /** | ||
1113 | * Returns the lowest common ancestor of this node and "other" - the node that is an ancestor of both and is not the | ||
1114 | * parent of a node that is an ancestor of both. Assumes that this is in the same tree as "other". Assumes that | ||
1115 | * neither "this" nor "other" is a leaf node. This method may return "this" or "other". | ||
1116 | * | ||
1117 | * Note that while it is possible to compute the lowest common ancestor in O(P) time, where P is the length of the | ||
1118 | * path from this node to "other", the "lca" method is not guaranteed to take O(P) time. If your application | ||
1119 | * requires this, then you should write your own lowest common ancestor method. | ||
1120 | */ | ||
1121 | public N lca(N other) { | ||
1122 | if (isLeaf() || other.isLeaf()) { | ||
1123 | throw new IllegalArgumentException("One of the nodes is a leaf node"); | ||
1124 | } | ||
1125 | |||
1126 | // Compute the depth of each node | ||
1127 | int depth = 0; | ||
1128 | for (N parent = this.parent; parent != null; parent = parent.parent) { | ||
1129 | depth++; | ||
1130 | } | ||
1131 | int otherDepth = 0; | ||
1132 | for (N parent = other.parent; parent != null; parent = parent.parent) { | ||
1133 | otherDepth++; | ||
1134 | } | ||
1135 | |||
1136 | // Go up to nodes of the same depth | ||
1137 | @SuppressWarnings("unchecked") | ||
1138 | N parent = (N)this; | ||
1139 | N otherParent = other; | ||
1140 | if (depth <= otherDepth) { | ||
1141 | for (int i = otherDepth; i > depth; i--) { | ||
1142 | otherParent = otherParent.parent; | ||
1143 | } | ||
1144 | } else { | ||
1145 | for (int i = depth; i > otherDepth; i--) { | ||
1146 | parent = parent.parent; | ||
1147 | } | ||
1148 | } | ||
1149 | |||
1150 | // Find the LCA | ||
1151 | while (parent != otherParent) { | ||
1152 | parent = parent.parent; | ||
1153 | otherParent = otherParent.parent; | ||
1154 | } | ||
1155 | if (parent != null) { | ||
1156 | return parent; | ||
1157 | } else { | ||
1158 | throw new IllegalArgumentException("The nodes do not belong to the same tree"); | ||
1159 | } | ||
1160 | } | ||
1161 | |||
1162 | /** | ||
1163 | * Returns an integer comparing the position of this node in the tree that contains it with that of "other". Returns | ||
1164 | * a negative number if this is earlier, a positive number if this is later, and 0 if this is at the same position. | ||
1165 | * Assumes that this is in the same tree as "other". Assumes that neither "this" nor "other" is a leaf node. | ||
1166 | * | ||
1167 | * The base class's implementation takes O(log N) time. If a RedBlackNode subclass stores a value used to order the | ||
1168 | * nodes, then it could override compareTo to compare the nodes' values, which would take O(1) time. | ||
1169 | * | ||
1170 | * Note that while it is possible to compare the positions of two nodes in O(P) time, where P is the length of the | ||
1171 | * path from this node to "other", the default implementation of compareTo is not guaranteed to take O(P) time. If | ||
1172 | * your application requires this, then you should write your own comparison method. | ||
1173 | */ | ||
1174 | @Override | ||
1175 | public int compareTo(N other) { | ||
1176 | if (isLeaf() || other.isLeaf()) { | ||
1177 | throw new IllegalArgumentException("One of the nodes is a leaf node"); | ||
1178 | } | ||
1179 | |||
1180 | // The algorithm operates as follows: compare the depth of this node to that of "other". If the depth of | ||
1181 | // "other" is greater, keep moving up from "other" until we find the ancestor at the same depth. Then, keep | ||
1182 | // moving up from "this" and from that node until we reach the lowest common ancestor. The node that arrived | ||
1183 | // from the left child of the common ancestor is earlier. The algorithm is analogous if the depth of "other" is | ||
1184 | // not greater. | ||
1185 | if (this == other) { | ||
1186 | return 0; | ||
1187 | } | ||
1188 | |||
1189 | // Compute the depth of each node | ||
1190 | int depth = 0; | ||
1191 | RedBlackNode<N> parent; | ||
1192 | for (parent = this; parent.parent != null; parent = parent.parent) { | ||
1193 | depth++; | ||
1194 | } | ||
1195 | int otherDepth = 0; | ||
1196 | N otherParent; | ||
1197 | for (otherParent = other; otherParent.parent != null; otherParent = otherParent.parent) { | ||
1198 | otherDepth++; | ||
1199 | } | ||
1200 | |||
1201 | // Go up to nodes of the same depth | ||
1202 | if (depth < otherDepth) { | ||
1203 | otherParent = other; | ||
1204 | for (int i = otherDepth - 1; i > depth; i--) { | ||
1205 | otherParent = otherParent.parent; | ||
1206 | } | ||
1207 | if (otherParent.parent != this) { | ||
1208 | otherParent = otherParent.parent; | ||
1209 | } else if (left == otherParent) { | ||
1210 | return 1; | ||
1211 | } else { | ||
1212 | return -1; | ||
1213 | } | ||
1214 | parent = this; | ||
1215 | } else if (depth > otherDepth) { | ||
1216 | parent = this; | ||
1217 | for (int i = depth - 1; i > otherDepth; i--) { | ||
1218 | parent = parent.parent; | ||
1219 | } | ||
1220 | if (parent.parent != other) { | ||
1221 | parent = parent.parent; | ||
1222 | } else if (other.left == parent) { | ||
1223 | return -1; | ||
1224 | } else { | ||
1225 | return 1; | ||
1226 | } | ||
1227 | otherParent = other; | ||
1228 | } else { | ||
1229 | parent = this; | ||
1230 | otherParent = other; | ||
1231 | } | ||
1232 | |||
1233 | // Keep going up until we reach the lowest common ancestor | ||
1234 | while (parent.parent != otherParent.parent) { | ||
1235 | parent = parent.parent; | ||
1236 | otherParent = otherParent.parent; | ||
1237 | } | ||
1238 | if (parent.parent == null) { | ||
1239 | throw new IllegalArgumentException("The nodes do not belong to the same tree"); | ||
1240 | } | ||
1241 | if (parent.parent.left == parent) { | ||
1242 | return -1; | ||
1243 | } else { | ||
1244 | return 1; | ||
1245 | } | ||
1246 | } | ||
1247 | |||
1248 | /** Throws a RuntimeException if the RedBlackNode fields of this are not correct for a leaf node. */ | ||
1249 | private void assertIsValidLeaf() { | ||
1250 | if (left != null || right != null || parent != null || isRed) { | ||
1251 | throw new RuntimeException("A leaf node's \"left\", \"right\", \"parent\", or isRed field is incorrect"); | ||
1252 | } | ||
1253 | } | ||
1254 | |||
1255 | /** | ||
1256 | * Throws a RuntimeException if the subtree rooted at this node does not satisfy the red-black properties, excluding | ||
1257 | * the requirement that the root be black, or it contains a repeated node other than a leaf node. | ||
1258 | * @param blackHeight The required number of black nodes in each path from this to a leaf node, including this and | ||
1259 | * the leaf node. | ||
1260 | * @param visited The nodes we have reached thus far, other than leaf nodes. This method adds the non-leaf nodes in | ||
1261 | * the subtree rooted at this node to "visited". | ||
1262 | */ | ||
1263 | private void assertSubtreeIsValidRedBlack(int blackHeight, Set<Reference<N>> visited) { | ||
1264 | @SuppressWarnings("unchecked") | ||
1265 | N nThis = (N)this; | ||
1266 | if (left == null || right == null) { | ||
1267 | assertIsValidLeaf(); | ||
1268 | if (blackHeight != 1) { | ||
1269 | throw new RuntimeException("Not all root-to-leaf paths have the same number of black nodes"); | ||
1270 | } | ||
1271 | return; | ||
1272 | } else if (!visited.add(new Reference<N>(nThis))) { | ||
1273 | throw new RuntimeException("The tree contains a repeated non-leaf node"); | ||
1274 | } else { | ||
1275 | int childBlackHeight; | ||
1276 | if (isRed) { | ||
1277 | if ((!left.isLeaf() && left.isRed) || (!right.isLeaf() && right.isRed)) { | ||
1278 | throw new RuntimeException("A red node has a red child"); | ||
1279 | } | ||
1280 | childBlackHeight = blackHeight; | ||
1281 | } else if (blackHeight == 0) { | ||
1282 | throw new RuntimeException("Not all root-to-leaf paths have the same number of black nodes"); | ||
1283 | } else { | ||
1284 | childBlackHeight = blackHeight - 1; | ||
1285 | } | ||
1286 | |||
1287 | if (!left.isLeaf() && left.parent != this) { | ||
1288 | throw new RuntimeException("left.parent != this"); | ||
1289 | } | ||
1290 | if (!right.isLeaf() && right.parent != this) { | ||
1291 | throw new RuntimeException("right.parent != this"); | ||
1292 | } | ||
1293 | RedBlackNode<N> leftNode = left; | ||
1294 | RedBlackNode<N> rightNode = right; | ||
1295 | leftNode.assertSubtreeIsValidRedBlack(childBlackHeight, visited); | ||
1296 | rightNode.assertSubtreeIsValidRedBlack(childBlackHeight, visited); | ||
1297 | } | ||
1298 | } | ||
1299 | |||
1300 | /** Calls assertNodeIsValid() on every node in the subtree rooted at this node. */ | ||
1301 | private void assertNodesAreValid() { | ||
1302 | assertNodeIsValid(); | ||
1303 | if (left != null) { | ||
1304 | RedBlackNode<N> leftNode = left; | ||
1305 | RedBlackNode<N> rightNode = right; | ||
1306 | leftNode.assertNodesAreValid(); | ||
1307 | rightNode.assertNodesAreValid(); | ||
1308 | } | ||
1309 | } | ||
1310 | |||
1311 | /** | ||
1312 | * Throws a RuntimeException if the subtree rooted at this node is not a valid red-black tree, e.g. if a red node | ||
1313 | * has a red child or it contains a non-leaf node "node" for which node.left.parent != node. (If parent != null, | ||
1314 | * it's okay if isRed is true.) This method is useful for debugging. See also assertSubtreeIsValid(). | ||
1315 | */ | ||
1316 | public void assertSubtreeIsValidRedBlack() { | ||
1317 | if (isLeaf()) { | ||
1318 | assertIsValidLeaf(); | ||
1319 | } else { | ||
1320 | if (parent == null && isRed) { | ||
1321 | throw new RuntimeException("The root is red"); | ||
1322 | } | ||
1323 | |||
1324 | // Compute the black height of the tree | ||
1325 | Set<Reference<N>> nodes = new HashSet<Reference<N>>(); | ||
1326 | int blackHeight = 0; | ||
1327 | @SuppressWarnings("unchecked") | ||
1328 | N node = (N)this; | ||
1329 | while (node != null) { | ||
1330 | if (!nodes.add(new Reference<N>(node))) { | ||
1331 | throw new RuntimeException("The tree contains a repeated non-leaf node"); | ||
1332 | } | ||
1333 | if (!node.isRed) { | ||
1334 | blackHeight++; | ||
1335 | } | ||
1336 | node = node.left; | ||
1337 | } | ||
1338 | |||
1339 | assertSubtreeIsValidRedBlack(blackHeight, new HashSet<Reference<N>>()); | ||
1340 | } | ||
1341 | } | ||
1342 | |||
1343 | /** | ||
1344 | * Throws a RuntimeException if we detect a problem with the subtree rooted at this node, such as a red child of a | ||
1345 | * red node or a non-leaf descendant "node" for which node.left.parent != node. This method is useful for | ||
1346 | * debugging. RedBlackNode subclasses may want to override assertSubtreeIsValid() to call assertOrderIsValid. | ||
1347 | */ | ||
1348 | public void assertSubtreeIsValid() { | ||
1349 | assertSubtreeIsValidRedBlack(); | ||
1350 | assertNodesAreValid(); | ||
1351 | } | ||
1352 | |||
1353 | /** | ||
1354 | * Throws a RuntimeException if the nodes in the subtree rooted at this node are not in the specified order or they | ||
1355 | * do not lie in the specified range. Assumes that the subtree rooted at this node is a valid binary tree, i.e. it | ||
1356 | * has no repeated nodes other than leaf nodes. | ||
1357 | * @param comparator A comparator indicating how the nodes should be ordered. | ||
1358 | * @param start The lower limit for nodes in the subtree, if any. | ||
1359 | * @param end The upper limit for nodes in the subtree, if any. | ||
1360 | */ | ||
1361 | private void assertOrderIsValid(Comparator<? super N> comparator, N start, N end) { | ||
1362 | if (!isLeaf()) { | ||
1363 | @SuppressWarnings("unchecked") | ||
1364 | N nThis = (N)this; | ||
1365 | if (start != null && comparator.compare(nThis, start) < 0) { | ||
1366 | throw new RuntimeException("The nodes are not ordered correctly"); | ||
1367 | } | ||
1368 | if (end != null && comparator.compare(nThis, end) > 0) { | ||
1369 | throw new RuntimeException("The nodes are not ordered correctly"); | ||
1370 | } | ||
1371 | RedBlackNode<N> leftNode = left; | ||
1372 | RedBlackNode<N> rightNode = right; | ||
1373 | leftNode.assertOrderIsValid(comparator, start, nThis); | ||
1374 | rightNode.assertOrderIsValid(comparator, nThis, end); | ||
1375 | } | ||
1376 | } | ||
1377 | |||
1378 | /** | ||
1379 | * Throws a RuntimeException if the nodes in the subtree rooted at this node are not in the specified order. | ||
1380 | * Assumes that this is a valid binary tree, i.e. there are no repeated nodes other than leaf nodes. This method is | ||
1381 | * useful for debugging. RedBlackNode subclasses may want to override assertSubtreeIsValid() to call | ||
1382 | * assertOrderIsValid. | ||
1383 | * @param comparator A comparator indicating how the nodes should be ordered. If this is null, we use the nodes' | ||
1384 | * natural order, as in N.compareTo. | ||
1385 | */ | ||
1386 | public void assertOrderIsValid(Comparator<? super N> comparator) { | ||
1387 | if (comparator == null) { | ||
1388 | comparator = naturalOrder(); | ||
1389 | } | ||
1390 | assertOrderIsValid(comparator, null, null); | ||
1391 | } | ||
1392 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/Reference.java b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/Reference.java new file mode 100644 index 00000000..a25c167d --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/Reference.java | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * The MIT License (MIT) | ||
3 | * | ||
4 | * Copyright (c) 2016 btrekkie | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in all | ||
14 | * copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | * SOFTWARE. | ||
23 | */ | ||
24 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.interval; | ||
25 | |||
26 | /** | ||
27 | * Wraps a value using reference equality. In other words, two references are equal only if their values are the same | ||
28 | * object instance, as in ==. | ||
29 | * @param <T> The type of value. | ||
30 | */ | ||
31 | class Reference<T> { | ||
32 | /** The value this wraps. */ | ||
33 | private final T value; | ||
34 | |||
35 | public Reference(T value) { | ||
36 | this.value = value; | ||
37 | } | ||
38 | |||
39 | public boolean equals(Object obj) { | ||
40 | if (!(obj instanceof Reference)) { | ||
41 | return false; | ||
42 | } | ||
43 | Reference<?> reference = (Reference<?>)obj; | ||
44 | return value == reference.value; | ||
45 | } | ||
46 | |||
47 | @Override | ||
48 | public int hashCode() { | ||
49 | return System.identityHashCode(value); | ||
50 | } | ||
51 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/aggregators/IntervalAggregatorFactory.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/aggregators/IntervalAggregatorFactory.xtend new file mode 100644 index 00000000..dee31f67 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/aggregators/IntervalAggregatorFactory.xtend | |||
@@ -0,0 +1,50 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.interval.aggregators | ||
2 | |||
3 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.interval.Interval | ||
4 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.interval.IntervalAggregationMode | ||
5 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.interval.IntervalAggregationOperator | ||
6 | import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.AggregatorType | ||
7 | import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.BoundAggregator | ||
8 | import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IAggregatorFactory | ||
9 | import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor | ||
10 | |||
11 | @AggregatorType(parameterTypes=#[Interval], returnTypes=#[Interval]) | ||
12 | abstract class IntervalAggregatorFactory implements IAggregatorFactory { | ||
13 | val IntervalAggregationMode mode | ||
14 | |||
15 | @FinalFieldsConstructor | ||
16 | protected new() { | ||
17 | } | ||
18 | |||
19 | override getAggregatorLogic(Class<?> domainClass) { | ||
20 | if (domainClass == Interval) { | ||
21 | new BoundAggregator(new IntervalAggregationOperator(mode), Interval, Interval) | ||
22 | } else { | ||
23 | throw new IllegalArgumentException("Unknown domain class: " + domainClass) | ||
24 | } | ||
25 | } | ||
26 | } | ||
27 | |||
28 | class intervalSum extends IntervalAggregatorFactory { | ||
29 | new() { | ||
30 | super(IntervalAggregationMode.SUM) | ||
31 | } | ||
32 | } | ||
33 | |||
34 | class intervalMin extends IntervalAggregatorFactory { | ||
35 | new() { | ||
36 | super(IntervalAggregationMode.MIN) | ||
37 | } | ||
38 | } | ||
39 | |||
40 | class intervalMax extends IntervalAggregatorFactory { | ||
41 | new() { | ||
42 | super(IntervalAggregationMode.MAX) | ||
43 | } | ||
44 | } | ||
45 | |||
46 | class intervalJoin extends IntervalAggregatorFactory { | ||
47 | new() { | ||
48 | super(IntervalAggregationMode.JOIN) | ||
49 | } | ||
50 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/aggregators/intervalHull.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/aggregators/intervalHull.xtend new file mode 100644 index 00000000..72605f57 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/interval/aggregators/intervalHull.xtend | |||
@@ -0,0 +1,74 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.interval.aggregators | ||
2 | |||
3 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.interval.Interval | ||
4 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.interval.IntervalHullAggregatorOperator | ||
5 | import java.math.BigDecimal | ||
6 | import java.math.BigInteger | ||
7 | import java.math.MathContext | ||
8 | import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.AggregatorType | ||
9 | import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.BoundAggregator | ||
10 | import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IAggregatorFactory | ||
11 | |||
12 | @AggregatorType(parameterTypes=#[BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, Short], returnTypes=#[ | ||
13 | Interval, Interval, Interval, Interval, Interval, Interval, Interval, Interval]) | ||
14 | class intervalHull implements IAggregatorFactory { | ||
15 | |||
16 | override getAggregatorLogic(Class<?> domainClass) { | ||
17 | new BoundAggregator(getAggregationOperator(domainClass), domainClass, Interval) | ||
18 | } | ||
19 | |||
20 | private def getAggregationOperator(Class<?> domainClass) { | ||
21 | switch (domainClass) { | ||
22 | case BigDecimal: | ||
23 | new IntervalHullAggregatorOperator<BigDecimal>() { | ||
24 | override protected toBigDecimal(BigDecimal value, MathContext mc) { | ||
25 | value.round(mc) | ||
26 | } | ||
27 | } | ||
28 | case BigInteger: | ||
29 | new IntervalHullAggregatorOperator<BigInteger>() { | ||
30 | override protected toBigDecimal(BigInteger value, MathContext mc) { | ||
31 | new BigDecimal(value, mc) | ||
32 | } | ||
33 | } | ||
34 | case Byte: | ||
35 | new IntervalHullAggregatorOperator<Byte>() { | ||
36 | override protected toBigDecimal(Byte value, MathContext mc) { | ||
37 | new BigDecimal(value, mc) | ||
38 | } | ||
39 | } | ||
40 | case Double: | ||
41 | new IntervalHullAggregatorOperator<Double>() { | ||
42 | override protected toBigDecimal(Double value, MathContext mc) { | ||
43 | new BigDecimal(value, mc) | ||
44 | } | ||
45 | } | ||
46 | case Float: | ||
47 | new IntervalHullAggregatorOperator<Float>() { | ||
48 | override protected toBigDecimal(Float value, MathContext mc) { | ||
49 | new BigDecimal(value, mc) | ||
50 | } | ||
51 | } | ||
52 | case Integer: | ||
53 | new IntervalHullAggregatorOperator<Integer>() { | ||
54 | override protected toBigDecimal(Integer value, MathContext mc) { | ||
55 | new BigDecimal(value, mc) | ||
56 | } | ||
57 | } | ||
58 | case Long: | ||
59 | new IntervalHullAggregatorOperator<Long>() { | ||
60 | override protected toBigDecimal(Long value, MathContext mc) { | ||
61 | new BigDecimal(value, mc) | ||
62 | } | ||
63 | } | ||
64 | case Short: | ||
65 | new IntervalHullAggregatorOperator<Short>() { | ||
66 | override protected toBigDecimal(Short value, MathContext mc) { | ||
67 | new BigDecimal(value, mc) | ||
68 | } | ||
69 | } | ||
70 | default: | ||
71 | throw new IllegalArgumentException("Unknown domain class: " + domainClass) | ||
72 | } | ||
73 | } | ||
74 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/GenericTypeIndexer.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/GenericTypeIndexer.xtend index d6a15c1a..0e0f1f02 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/GenericTypeIndexer.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/GenericTypeIndexer.xtend | |||
@@ -1,209 +1,150 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns | 1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns |
2 | 2 | ||
3 | import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem | ||
4 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Type | 3 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Type |
5 | import org.eclipse.emf.ecore.EClass | 4 | import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem |
6 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.Modality | 5 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.Modality |
7 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | ||
8 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.TypeAnalysisResult | 6 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.TypeAnalysisResult |
9 | 7 | ||
10 | class GenericTypeIndexer extends TypeIndexer { | 8 | class GenericTypeIndexer extends TypeIndexer { |
11 | val PatternGenerator base; | ||
12 | |||
13 | new(PatternGenerator base) { | 9 | new(PatternGenerator base) { |
14 | this.base = base | 10 | super(base) |
15 | } | 11 | } |
12 | |||
16 | override requiresTypeAnalysis() { false } | 13 | override requiresTypeAnalysis() { false } |
17 | 14 | ||
18 | public override getRequiredQueries() ''' | 15 | override getRequiredQueries() ''' |
19 | private pattern newELement(interpretation: PartialInterpretation, element: DefinedElement) { | 16 | «super.requiredQueries» |
20 | PartialInterpretation.newElements(interpretation,element); | 17 | |
21 | } | 18 | /** |
22 | 19 | * Direct supertypes of a type. | |
23 | private pattern typeInterpretation(problem:LogicProblem, interpetation:PartialInterpretation, type:TypeDeclaration, typeInterpretation:PartialComplexTypeInterpretation) { | 20 | */ |
24 | find interpretation(problem,interpetation); | 21 | private pattern supertypeDirect(subtype : Type, supertype : Type) { |
25 | LogicProblem.types(problem,type); | 22 | Type.supertypes(subtype, supertype); |
26 | PartialInterpretation.partialtypeinterpratation(interpetation,typeInterpretation); | 23 | } |
27 | PartialComplexTypeInterpretation.interpretationOf(typeInterpretation,type); | 24 | |
28 | } | 25 | /** |
29 | 26 | * All supertypes of a type. | |
30 | private pattern directInstanceOf(problem:LogicProblem, interpetation:PartialInterpretation, element:DefinedElement, type:Type) { | 27 | */ |
31 | find interpretation(problem,interpetation); | 28 | private pattern supertypeStar(subtype: Type, supertype: Type) { |
32 | find mustExist(problem,interpetation,element); | 29 | subtype == supertype; |
33 | LogicProblem.types(problem,type); | 30 | } or { |
34 | TypeDefinition.elements(type,element); | 31 | find supertypeDirect+(subtype,supertype); |
35 | } or { | 32 | } |
36 | find mustExist(problem,interpetation,element); | 33 | |
37 | find typeInterpretation(problem,interpetation,type,typeInterpretation); | 34 | /// Complex type reasoning patterns /// |
38 | PartialComplexTypeInterpretation.elements(typeInterpretation,element); | 35 | // |
39 | } | 36 | // In a valid type system, for each element e there is exactly one type T where |
40 | 37 | // 1: T(e) - but we dont know this for type declaration | |
41 | /** | 38 | // 2: For the dynamic type D and another type T, where D(e) && D-->T, T(e) is true. |
42 | * Direct supertypes of a type. | 39 | // 2e: A type hierarchy is invalid, if there is a supertype T for a dynamic type D which does no contains e: |
43 | */ | 40 | // D(e) && D-->T && !T(e) |
44 | private pattern supertypeDirect(subtype : Type, supertype : Type) { | 41 | // 3: There is no T' that T'->T and T'(e) |
45 | Type.supertypes(subtype, supertype); | 42 | // 3e: A type hierarcy is invalid, if there is a type T for a dynamic type D, which contains e, but not subtype of T: |
46 | } | 43 | // D(e) && ![T--->D] && T(e) |
47 | |||
48 | /** | ||
49 | * All supertypes of a type. | ||
50 | */ | ||
51 | private pattern supertypeStar(subtype: Type, supertype: Type) { | ||
52 | subtype == supertype; | ||
53 | } or { | ||
54 | find supertypeDirect+(subtype,supertype); | ||
55 | } | ||
56 | |||
57 | /// Complex type reasoning patterns /// | ||
58 | // | ||
59 | // In a valid type system, for each element e there is exactly one type T where | ||
60 | // 1: T(e) - but we dont know this for type declaration | ||
61 | // 2: For the dynamic type D and another type T, where D(e) && D-->T, T(e) is true. | ||
62 | // 2e: A type hierarchy is invalid, if there is a supertype T for a dynamic type D which does no contains e: | ||
63 | // D(e) && D-->T && !T(e) | ||
64 | // 3: There is no T' that T'->T and T'(e) | ||
65 | // 3e: A type hierarcy is invalid, if there is a type T for a dynamic type D, which contains e, but not subtype of T: | ||
66 | // D(e) && ![T--->D] && T(e) | ||
67 | // 4: T is not abstract | ||
68 | // Such type T is called Dynamic type of e, while other types are called static types. | ||
69 | // | ||
70 | // The following patterns checks the possible dynamic types for an element | ||
71 | |||
72 | private pattern wellformedType(problem: LogicProblem, interpretation:PartialInterpretation, dynamic:Type, element:DefinedElement) { | ||
73 | // 1: T(e) | ||
74 | find directInstanceOf(problem,interpretation,element,dynamic); | ||
75 | // 2e is not true: D(e) && D-->T && !T(e) | ||
76 | neg find dynamicTypeNotSubtypeOfADefinition(problem,interpretation,element,dynamic); | ||
77 | // 3e is not true: D(e) && ![T--->D] && T(e) | ||
78 | neg find dynamicTypeIsSubtypeOfANonDefinition(problem,interpretation,element,dynamic); | ||
79 | // 4: T is not abstract | ||
80 | Type.isAbstract(dynamic,false); | ||
81 | } | ||
82 | |||
83 | |||
84 | private pattern isPrimitive(element: PrimitiveElement) { | ||
85 | PrimitiveElement(element); | ||
86 | } | ||
87 | |||
88 | private pattern possibleDynamicType(problem: LogicProblem, interpretation:PartialInterpretation, dynamic:Type, element:DefinedElement) | ||
89 | // case 1: element is defined at least once | ||
90 | { | ||
91 | LogicProblem.types(problem,dynamic); | ||
92 | // select a random definition 'randomType' | ||
93 | find directInstanceOf(problem,interpretation,element,randomType); | ||
94 | // dynamic is a subtype of 'randomType' | ||
95 | find supertypeStar(dynamic,randomType); | ||
96 | // 2e is not true: D(e) && D-->T && !T(e) | ||
97 | neg find dynamicTypeNotSubtypeOfADefinition(problem,interpretation,element,dynamic); | ||
98 | // 3e is not true: D(e) && ![T--->D] && T(e) | ||
99 | neg find dynamicTypeIsSubtypeOfANonDefinition(problem,interpretation,element,dynamic); | ||
100 | // 4: T is not abstract | ||
101 | Type.isAbstract(dynamic,false); | ||
102 | // 5. element is not primitive datatype | ||
103 | neg find isPrimitive(element); | ||
104 | } or | ||
105 | // case 2: element is not defined anywhere | ||
106 | { | ||
107 | find mayExist(problem,interpretation,element); | ||
108 | // there is no definition | ||
109 | neg find directInstanceOf(problem,interpretation,element,_); | ||
110 | // 2e is not true: D(e) && D-->T && !T(e) | ||
111 | // because non of the definition contains element, the type cannot have defined supertype | ||
112 | LogicProblem.types(problem,dynamic); | ||
113 | PartialInterpretation.problem(interpretation,problem); | ||
114 | neg find typeWithDefinedSupertype(dynamic); | ||
115 | // 3e is not true: D(e) && ![T--->D] && T(e) | ||
116 | // because there is no definition, dynamic covers all definition | ||
117 | // 4: T is not abstract | 44 | // 4: T is not abstract |
118 | Type.isAbstract(dynamic,false); | 45 | // Such type T is called Dynamic type of e, while other types are called static types. |
119 | // 5. element is not primitive datatype | 46 | // |
120 | neg find isPrimitive(element); | 47 | // The following patterns checks the possible dynamic types for an element |
121 | } | 48 | |
122 | 49 | private pattern wellformedType(problem: LogicProblem, interpretation:PartialInterpretation, dynamic:Type, element:DefinedElement) { | |
123 | /** | 50 | // 1: T(e) |
124 | * supertype -------> element <------- otherSupertype | 51 | find directInstanceOf(problem,interpretation,element,dynamic); |
125 | * A A | 52 | // 2e is not true: D(e) && D-->T && !T(e) |
126 | * | | | 53 | neg find dynamicTypeNotSubtypeOfADefinition(problem,interpretation,element,dynamic); |
127 | * wrongDynamic -----------------------------X | 54 | // 3e is not true: D(e) && ![T--->D] && T(e) |
128 | */ | 55 | neg find dynamicTypeIsSubtypeOfANonDefinition(problem,interpretation,element,dynamic); |
129 | private pattern dynamicTypeNotSubtypeOfADefinition(problem:LogicProblem, interpretation:PartialInterpretation, element:DefinedElement, wrongDynamic : Type) { | 56 | // 4: T is not abstract |
130 | find directInstanceOf(problem,interpretation,element,supertype); | 57 | Type.isAbstract(dynamic,false); |
131 | find directInstanceOf(problem,interpretation,element,otherSupertype); | 58 | } |
132 | find supertypeStar(wrongDynamic,supertype); | 59 | |
133 | neg find supertypeStar(wrongDynamic,otherSupertype); | 60 | private pattern possibleDynamicType(problem: LogicProblem, interpretation:PartialInterpretation, dynamic:Type, element:DefinedElement) |
134 | } | 61 | // case 1: element is defined at least once |
135 | 62 | { | |
136 | /** | 63 | LogicProblem.types(problem,dynamic); |
137 | * supertype -------> element <---X--- otherSupertype | 64 | // select a random definition 'randomType' |
138 | * A A | 65 | find directInstanceOf(problem,interpretation,element,randomType); |
139 | * | | | 66 | // dynamic is a subtype of 'randomType' |
140 | * wrongDynamic -----------------------------+ | 67 | find supertypeStar(dynamic,randomType); |
141 | */ | 68 | // 2e is not true: D(e) && D-->T && !T(e) |
142 | private pattern dynamicTypeIsSubtypeOfANonDefinition(problem: LogicProblem, interpretation:PartialInterpretation, element:DefinedElement, wrongDynamic:Type) { | 69 | neg find dynamicTypeNotSubtypeOfADefinition(problem,interpretation,element,dynamic); |
143 | find directInstanceOf(problem,interpretation,element,supertype); | 70 | // 3e is not true: D(e) && ![T--->D] && T(e) |
144 | neg find elementInTypeDefinition(element,otherSupertype); | 71 | neg find dynamicTypeIsSubtypeOfANonDefinition(problem,interpretation,element,dynamic); |
145 | TypeDefinition(otherSupertype); | 72 | // 4: T is not abstract |
146 | find supertypeStar(wrongDynamic, supertype); | 73 | Type.isAbstract(dynamic,false); |
147 | find supertypeStar(wrongDynamic, otherSupertype); | 74 | // 5. element is not primitive datatype |
148 | } | 75 | neg find isPrimitive(element); |
149 | 76 | } or | |
150 | private pattern elementInTypeDefinition(element:DefinedElement, definition:TypeDefinition) { | 77 | // case 2: element is not defined anywhere |
151 | TypeDefinition.elements(definition,element); | 78 | { |
152 | } | 79 | find mayExist(problem,interpretation,element); |
153 | 80 | // there is no definition | |
154 | private pattern typeWithDefinedSupertype(type:Type) { | 81 | neg find directInstanceOf(problem,interpretation,element,_); |
155 | find supertypeStar(type,definedSupertype); | 82 | // 2e is not true: D(e) && D-->T && !T(e) |
156 | TypeDefinition(definedSupertype); | 83 | // because non of the definition contains element, the type cannot have defined supertype |
157 | } | 84 | LogicProblem.types(problem,dynamic); |
158 | 85 | PartialInterpretation.problem(interpretation,problem); | |
159 | private pattern scopeDisallowsNewElementsFromType(typeInterpretation:PartialComplexTypeInterpretation) { | 86 | neg find typeWithDefinedSupertype(dynamic); |
160 | Scope.targetTypeInterpretation(scope,typeInterpretation); | 87 | // 3e is not true: D(e) && ![T--->D] && T(e) |
161 | Scope.maxNewElements(scope,0); | 88 | // because there is no definition, dynamic covers all definition |
162 | } | 89 | // 4: T is not abstract |
163 | ''' | 90 | Type.isAbstract(dynamic,false); |
164 | 91 | // 5. element is not primitive datatype | |
165 | public override generateInstanceOfQueries(LogicProblem problem, PartialInterpretation emptySolution,TypeAnalysisResult typeAnalysisResult) { | 92 | neg find isPrimitive(element); |
166 | ''' | 93 | } |
167 | «FOR type:problem.types» | 94 | |
168 | «problem.generateMustInstenceOf(type)» | ||
169 | «problem.generateMayInstanceOf(type)» | ||
170 | «ENDFOR» | ||
171 | ''' | ||
172 | } | ||
173 | |||
174 | private def patternName(Type type, Modality modality) | ||
175 | '''«modality.toString.toLowerCase»InstanceOf«base.canonizeName(type.name)»''' | ||
176 | |||
177 | private def generateMustInstenceOf(LogicProblem problem, Type type) { | ||
178 | ''' | ||
179 | /** | 95 | /** |
180 | * An element must be an instance of type "«type.name»". | 96 | * supertype -------> element <------- otherSupertype |
97 | * A A | ||
98 | * | | | ||
99 | * wrongDynamic -----------------------------X | ||
181 | */ | 100 | */ |
182 | private pattern «patternName(type,Modality.MUST)»(problem:LogicProblem, interpretation:PartialInterpretation, element:DefinedElement) { | 101 | private pattern dynamicTypeNotSubtypeOfADefinition(problem:LogicProblem, interpretation:PartialInterpretation, element:DefinedElement, wrongDynamic : Type) { |
183 | Type.name(type,"«type.name»"); | 102 | find directInstanceOf(problem,interpretation,element,supertype); |
184 | find directInstanceOf(problem,interpretation,element,type); | 103 | find directInstanceOf(problem,interpretation,element,otherSupertype); |
104 | find supertypeStar(wrongDynamic,supertype); | ||
105 | neg find supertypeStar(wrongDynamic,otherSupertype); | ||
185 | } | 106 | } |
186 | ''' | 107 | |
187 | } | ||
188 | |||
189 | private def generateMayInstanceOf(LogicProblem problem, Type type) { | ||
190 | ''' | ||
191 | /** | 108 | /** |
192 | * An element may be an instance of type "«type.name»". | 109 | * supertype -------> element <---X--- otherSupertype |
110 | * A A | ||
111 | * | | | ||
112 | * wrongDynamic -----------------------------+ | ||
193 | */ | 113 | */ |
194 | private pattern «patternName(type,Modality.MAY)»(problem:LogicProblem, interpretation:PartialInterpretation, element:DefinedElement) { | 114 | private pattern dynamicTypeIsSubtypeOfANonDefinition(problem: LogicProblem, interpretation:PartialInterpretation, element:DefinedElement, wrongDynamic:Type) { |
195 | Type.name(type,"«type.name»"); | 115 | find directInstanceOf(problem,interpretation,element,supertype); |
196 | find possibleDynamicType(problem,interpretation,dynamic,element); | 116 | neg find elementInTypeDefinition(element,otherSupertype); |
197 | find supertypeStar(dynamic,type); | 117 | TypeDefinition(otherSupertype); |
198 | neg find scopeDisallowsNewElementsFromType(dynamic); | 118 | find supertypeStar(wrongDynamic, supertype); |
119 | find supertypeStar(wrongDynamic, otherSupertype); | ||
120 | } | ||
121 | |||
122 | private pattern elementInTypeDefinition(element:DefinedElement, definition:TypeDefinition) { | ||
123 | TypeDefinition.elements(definition,element); | ||
124 | } | ||
125 | |||
126 | private pattern typeWithDefinedSupertype(type:Type) { | ||
127 | find supertypeStar(type,definedSupertype); | ||
128 | TypeDefinition(definedSupertype); | ||
129 | } | ||
130 | |||
131 | private pattern scopeDisallowsNewElementsFromType(typeInterpretation:PartialComplexTypeInterpretation) { | ||
132 | Scope.targetTypeInterpretation(scope,typeInterpretation); | ||
133 | Scope.maxNewElements(scope,0); | ||
199 | } | 134 | } |
135 | ''' | ||
136 | |||
137 | protected override generateMayInstanceOf(LogicProblem problem, Type type, TypeAnalysisResult typeAnalysisResult) { | ||
138 | ''' | ||
139 | /** | ||
140 | * An element may be an instance of type "«type.name»". | ||
141 | */ | ||
142 | private pattern «patternName(type,Modality.MAY)»(problem:LogicProblem, interpretation:PartialInterpretation, element:DefinedElement) { | ||
143 | Type.name(type,"«type.name»"); | ||
144 | find possibleDynamicType(problem,interpretation,dynamic,element); | ||
145 | find supertypeStar(dynamic,type); | ||
146 | neg find scopeDisallowsNewElementsFromType(dynamic); | ||
147 | } | ||
200 | ''' | 148 | ''' |
201 | } | 149 | } |
202 | 150 | } | |
203 | public override referInstanceOf(Type type, Modality modality, String variableName) { | ||
204 | '''find «patternName(type,modality)»(problem,interpretation,«variableName»);''' | ||
205 | } | ||
206 | public override referInstanceOf(EClass type, Modality modality, String variableName) { | ||
207 | '''find «modality.toString.toLowerCase»InstanceOf«base.canonizeName('''«type.name» class''')»(problem,interpretation,«variableName»);''' | ||
208 | } | ||
209 | } \ No newline at end of file | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/GenericTypeRefinementGenerator.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/GenericTypeRefinementGenerator.xtend index 2e03d6ed..52f0cbea 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/GenericTypeRefinementGenerator.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/GenericTypeRefinementGenerator.xtend | |||
@@ -11,110 +11,114 @@ import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.par | |||
11 | import java.util.HashMap | 11 | import java.util.HashMap |
12 | 12 | ||
13 | class GenericTypeRefinementGenerator extends TypeRefinementGenerator { | 13 | class GenericTypeRefinementGenerator extends TypeRefinementGenerator { |
14 | public new(PatternGenerator base) { | 14 | new(PatternGenerator base) { |
15 | super(base) | 15 | super(base) |
16 | } | 16 | } |
17 | |||
17 | override requiresTypeAnalysis() { false } | 18 | override requiresTypeAnalysis() { false } |
18 | 19 | ||
19 | override generateRefineObjectQueries(LogicProblem p, PartialInterpretation emptySolution, TypeAnalysisResult typeAnalysisResult) { | 20 | override generateRefineObjectQueries(LogicProblem p, PartialInterpretation emptySolution, |
21 | TypeAnalysisResult typeAnalysisResult) { | ||
20 | val containment = p.containmentHierarchies.head | 22 | val containment = p.containmentHierarchies.head |
21 | val newObjectTypes = p.types.filter(TypeDeclaration).filter[!isAbstract] | 23 | val newObjectTypes = p.types.filter(TypeDeclaration).filter[!isAbstract] |
22 | val inverseRelations = new HashMap | 24 | val inverseRelations = new HashMap |
23 | p.annotations.filter(InverseRelationAssertion).forEach[ | 25 | p.annotations.filter(InverseRelationAssertion).forEach [ |
24 | inverseRelations.put(it.inverseA,it.inverseB) | 26 | inverseRelations.put(it.inverseA, it.inverseB) |
25 | inverseRelations.put(it.inverseB,it.inverseA) | 27 | inverseRelations.put(it.inverseB, it.inverseA) |
26 | ] | 28 | ] |
27 | return ''' | 29 | return ''' |
28 | private pattern hasElementInContainment(problem:LogicProblem, interpretation:PartialInterpretation) | 30 | pattern «hasElementInContainmentName»(problem:LogicProblem, interpretation:PartialInterpretation) |
29 | «FOR type :containment.typesOrderedInHierarchy SEPARATOR "or"»{ | 31 | «FOR type : containment.typesOrderedInHierarchy SEPARATOR "or"»{ |
30 | find interpretation(problem,interpretation); | ||
31 | «base.typeIndexer.referInstanceOf(type,Modality.MUST,"root")» | ||
32 | find mustExist(problem, interpretation, root); | ||
33 | }«ENDFOR» | ||
34 | «FOR type:newObjectTypes» | ||
35 | «IF(containment.typesOrderedInHierarchy.contains(type))» | ||
36 | «FOR containmentRelation : containment.containmentRelations.filter[canBeContainedByRelation(it,type)]» | ||
37 | «IF inverseRelations.containsKey(containmentRelation)» | ||
38 | pattern «this.patternName(containmentRelation,inverseRelations.get(containmentRelation),type)»( | ||
39 | problem:LogicProblem, interpretation:PartialInterpretation, | ||
40 | relationInterpretation:PartialRelationInterpretation, inverseInterpretation:PartialRelationInterpretation ,typeInterpretation:PartialComplexTypeInterpretation, | ||
41 | container:DefinedElement) | ||
42 | { | ||
43 | find interpretation(problem,interpretation); | ||
44 | PartialInterpretation.partialtypeinterpratation(interpretation,typeInterpretation); | ||
45 | PartialComplexTypeInterpretation.interpretationOf.name(typeInterpretation,"«type.name»"); | ||
46 | PartialInterpretation.partialrelationinterpretation(interpretation,relationInterpretation); | ||
47 | PartialRelationInterpretation.interpretationOf.name(relationInterpretation,"«containmentRelation.name»"); | ||
48 | PartialInterpretation.partialrelationinterpretation(interpretation,inverseInterpretation); | ||
49 | PartialRelationInterpretation.interpretationOf.name(inverseInterpretation,"«inverseRelations.get(containmentRelation).name»"); | ||
50 | «base.typeIndexer.referInstanceOf((containmentRelation.parameters.get(0) as ComplexTypeReference).referred,Modality.MUST,"container")» | ||
51 | «base.typeIndexer.referInstanceOf(type,Modality.MAY,"newObject")» | ||
52 | «base.relationDeclarationIndexer.referRelation(containmentRelation as RelationDeclaration,"container","newObject",Modality.MAY)» | ||
53 | find mustExist(problem, interpretation, container); | ||
54 | neg find mustExist(problem, interpretation, newObject); | ||
55 | } | ||
56 | «ELSE» | ||
57 | pattern «this.patternName(containmentRelation,null,type)»( | ||
58 | problem:LogicProblem, interpretation:PartialInterpretation, | ||
59 | relationInterpretation:PartialRelationInterpretation, typeInterpretation:PartialComplexTypeInterpretation, | ||
60 | container:DefinedElement) | ||
61 | { | ||
62 | find interpretation(problem,interpretation); | ||
63 | PartialInterpretation.partialtypeinterpratation(interpretation,typeInterpretation); | ||
64 | PartialComplexTypeInterpretation.interpretationOf.name(typeInterpretation,"«type.name»"); | ||
65 | PartialInterpretation.partialrelationinterpretation(interpretation,relationInterpretation); | ||
66 | PartialRelationInterpretation.interpretationOf.name(relationInterpretation,"«containmentRelation.name»"); | ||
67 | «base.typeIndexer.referInstanceOf((containmentRelation.parameters.get(0) as ComplexTypeReference).referred,Modality.MUST,"container")» | ||
68 | «base.typeIndexer.referInstanceOf(type,Modality.MAY,"newObject")» | ||
69 | «base.relationDeclarationIndexer.referRelation(containmentRelation as RelationDeclaration,"container","newObject",Modality.MAY)» | ||
70 | find mustExist(problem, interpretation, container); | ||
71 | neg find mustExist(problem, interpretation, newObject); | ||
72 | } | ||
73 | «ENDIF» | ||
74 | «ENDFOR» | ||
75 | pattern «patternName(null,null,type)»( | ||
76 | problem:LogicProblem, interpretation:PartialInterpretation, | ||
77 | typeInterpretation:PartialComplexTypeInterpretation) | ||
78 | { | ||
79 | find interpretation(problem,interpretation); | 32 | find interpretation(problem,interpretation); |
80 | neg find hasElementInContainment(problem,interpretation); | 33 | «base.typeIndexer.referInstanceOf(type,Modality.MUST,"root")» |
81 | PartialInterpretation.partialtypeinterpratation(interpretation,typeInterpretation); | 34 | find mustExist(problem, interpretation, root); |
82 | PartialComplexTypeInterpretation.interpretationOf.name(type,"«type.name»"); | 35 | }«ENDFOR» |
83 | «base.typeIndexer.referInstanceOf(type,Modality.MAY,"newObject")» | 36 | «FOR type : newObjectTypes» |
84 | find mayExist(problem, interpretation, newObject); | 37 | «IF(containment.typesOrderedInHierarchy.contains(type))» |
85 | neg find mustExist(problem, interpretation, newObject); | 38 | «FOR containmentRelation : containment.containmentRelations.filter[canBeContainedByRelation(it,type)]» |
86 | } | 39 | «IF inverseRelations.containsKey(containmentRelation)» |
87 | «ELSE» | 40 | pattern «this.patternName(containmentRelation,inverseRelations.get(containmentRelation),type)»( |
88 | pattern createObject_«this.patternName(null,null,type)»( | 41 | problem:LogicProblem, interpretation:PartialInterpretation, |
89 | problem:LogicProblem, interpretation:PartialInterpretation, | 42 | relationInterpretation:PartialRelationInterpretation, inverseInterpretation:PartialRelationInterpretation ,typeInterpretation:PartialComplexTypeInterpretation, |
90 | typeInterpretation:PartialComplexTypeInterpretation) | 43 | container:DefinedElement) |
91 | { | 44 | { |
92 | find interpretation(problem,interpretation); | 45 | find interpretation(problem,interpretation); |
93 | PartialInterpretation.partialtypeinterpratation(interpretation,typeInterpretation); | 46 | PartialInterpretation.partialtypeinterpratation(interpretation,typeInterpretation); |
94 | PartialComplexTypeInterpretation.interpretationOf.name(typeInterpretation,"«type.name»"); | 47 | PartialComplexTypeInterpretation.interpretationOf.name(typeInterpretation,"«type.name»"); |
95 | «base.typeIndexer.referInstanceOf(type,Modality.MAY,"newObject")» | 48 | PartialInterpretation.partialrelationinterpretation(interpretation,relationInterpretation); |
96 | find mayExist(problem, interpretation, newObject); | 49 | PartialRelationInterpretation.interpretationOf.name(relationInterpretation,"«containmentRelation.name»"); |
97 | neg find mustExist(problem, interpretation, newObject); | 50 | PartialInterpretation.partialrelationinterpretation(interpretation,inverseInterpretation); |
98 | } | 51 | PartialRelationInterpretation.interpretationOf.name(inverseInterpretation,"«inverseRelations.get(containmentRelation).name»"); |
99 | «ENDIF» | 52 | «base.typeIndexer.referInstanceOf((containmentRelation.parameters.get(0) as ComplexTypeReference).referred,Modality.MUST,"container")» |
100 | «ENDFOR» | 53 | «base.typeIndexer.referInstanceOf(type,Modality.MAY,"newObject")» |
54 | «base.relationDeclarationIndexer.referRelation(containmentRelation as RelationDeclaration,"container","newObject",Modality.MAY)» | ||
55 | find mustExist(problem, interpretation, container); | ||
56 | neg find mustExist(problem, interpretation, newObject); | ||
57 | } | ||
58 | «ELSE» | ||
59 | pattern «this.patternName(containmentRelation,null,type)»( | ||
60 | problem:LogicProblem, interpretation:PartialInterpretation, | ||
61 | relationInterpretation:PartialRelationInterpretation, typeInterpretation:PartialComplexTypeInterpretation, | ||
62 | container:DefinedElement) | ||
63 | { | ||
64 | find interpretation(problem,interpretation); | ||
65 | PartialInterpretation.partialtypeinterpratation(interpretation,typeInterpretation); | ||
66 | PartialComplexTypeInterpretation.interpretationOf.name(typeInterpretation,"«type.name»"); | ||
67 | PartialInterpretation.partialrelationinterpretation(interpretation,relationInterpretation); | ||
68 | PartialRelationInterpretation.interpretationOf.name(relationInterpretation,"«containmentRelation.name»"); | ||
69 | «base.typeIndexer.referInstanceOf((containmentRelation.parameters.get(0) as ComplexTypeReference).referred,Modality.MUST,"container")» | ||
70 | «base.typeIndexer.referInstanceOf(type,Modality.MAY,"newObject")» | ||
71 | «base.relationDeclarationIndexer.referRelation(containmentRelation as RelationDeclaration,"container","newObject",Modality.MAY)» | ||
72 | find mustExist(problem, interpretation, container); | ||
73 | neg find mustExist(problem, interpretation, newObject); | ||
74 | } | ||
75 | «ENDIF» | ||
76 | «ENDFOR» | ||
77 | pattern «patternName(null,null,type)»( | ||
78 | problem:LogicProblem, interpretation:PartialInterpretation, | ||
79 | typeInterpretation:PartialComplexTypeInterpretation) | ||
80 | { | ||
81 | find interpretation(problem,interpretation); | ||
82 | neg find «hasElementInContainmentName»(problem,interpretation); | ||
83 | PartialInterpretation.partialtypeinterpratation(interpretation,typeInterpretation); | ||
84 | PartialComplexTypeInterpretation.interpretationOf.name(type,"«type.name»"); | ||
85 | «base.typeIndexer.referInstanceOf(type,Modality.MAY,"newObject")» | ||
86 | find mayExist(problem, interpretation, newObject); | ||
87 | neg find mustExist(problem, interpretation, newObject); | ||
88 | } | ||
89 | «ELSE» | ||
90 | pattern createObject_«this.patternName(null,null,type)»( | ||
91 | problem:LogicProblem, interpretation:PartialInterpretation, | ||
92 | typeInterpretation:PartialComplexTypeInterpretation) | ||
93 | { | ||
94 | find interpretation(problem,interpretation); | ||
95 | PartialInterpretation.partialtypeinterpratation(interpretation,typeInterpretation); | ||
96 | PartialComplexTypeInterpretation.interpretationOf.name(typeInterpretation,"«type.name»"); | ||
97 | «base.typeIndexer.referInstanceOf(type,Modality.MAY,"newObject")» | ||
98 | find mayExist(problem, interpretation, newObject); | ||
99 | neg find mustExist(problem, interpretation, newObject); | ||
100 | } | ||
101 | «ENDIF» | ||
102 | «ENDFOR» | ||
101 | ''' | 103 | ''' |
102 | } | 104 | } |
103 | 105 | ||
104 | override generateRefineTypeQueries(LogicProblem p, PartialInterpretation emptySolution, TypeAnalysisResult typeAnalysisResult) { | 106 | override generateRefineTypeQueries(LogicProblem p, PartialInterpretation emptySolution, |
107 | TypeAnalysisResult typeAnalysisResult) { | ||
105 | return ''' | 108 | return ''' |
106 | «FOR type : p.types.filter(TypeDeclaration).filter[!it.isAbstract]» | 109 | «FOR type : p.types.filter(TypeDeclaration).filter[!it.isAbstract]» |
107 | pattern refineTypeTo_«base.canonizeName(type.name)»(problem:LogicProblem, interpretation:PartialInterpretation, object: DefinedElement) { | 110 | pattern refineTypeTo_«base.canonizeName(type.name)»(problem:LogicProblem, interpretation:PartialInterpretation, object: DefinedElement) { |
108 | find interpretation(problem,interpretation); | 111 | find interpretation(problem,interpretation); |
109 | find mustExist(problem, interpretation, object); | 112 | find mustExist(problem, interpretation, object); |
110 | «base.typeIndexer.referInstanceOf(type,Modality.MAY,"object")» | 113 | «base.typeIndexer.referInstanceOf(type,Modality.MAY,"object")» |
111 | neg «base.typeIndexer.referInstanceOf(type,Modality.MUST,"object")» | 114 | neg «base.typeIndexer.referInstanceOf(type,Modality.MUST,"object")» |
112 | } | 115 | } |
113 | «ENDFOR» | 116 | «ENDFOR» |
114 | ''' | 117 | ''' |
115 | } | 118 | } |
116 | 119 | ||
117 | override getRefineTypeQueryNames(LogicProblem p, PartialInterpretation emptySolution, TypeAnalysisResult typeAnalysisResult) { | 120 | override getRefineTypeQueryNames(LogicProblem p, PartialInterpretation emptySolution, |
121 | TypeAnalysisResult typeAnalysisResult) { | ||
118 | p.types.filter(TypeDeclaration).toInvertedMap['''refineTypeTo_«base.canonizeName(it.name)»'''] | 122 | p.types.filter(TypeDeclaration).toInvertedMap['''refineTypeTo_«base.canonizeName(it.name)»'''] |
119 | } | 123 | } |
120 | } \ No newline at end of file | 124 | } |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/PatternGenerator.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/PatternGenerator.xtend index d4c76bb4..1b0db90e 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/PatternGenerator.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/PatternGenerator.xtend | |||
@@ -1,7 +1,6 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns | 1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns |
2 | 2 | ||
3 | import hu.bme.mit.inf.dslreasoner.ecore2logic.ecore2logicannotations.InverseRelationAssertion | 3 | import hu.bme.mit.inf.dslreasoner.ecore2logic.ecore2logicannotations.InverseRelationAssertion |
4 | import hu.bme.mit.inf.dslreasoner.ecore2logic.ecore2logicannotations.LowerMultiplicityAssertion | ||
5 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.BoolTypeReference | 4 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.BoolTypeReference |
6 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.IntTypeReference | 5 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.IntTypeReference |
7 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RealTypeReference | 6 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RealTypeReference |
@@ -17,6 +16,7 @@ import hu.bme.mit.inf.dslreasoner.viatra2logic.viatra2logicannotations.Transform | |||
17 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.Modality | 16 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.Modality |
18 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.TypeAnalysisResult | 17 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.TypeAnalysisResult |
19 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.TypeInferenceMethod | 18 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.TypeInferenceMethod |
19 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.RelationConstraints | ||
20 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | 20 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation |
21 | import java.util.HashMap | 21 | import java.util.HashMap |
22 | import java.util.Map | 22 | import java.util.Map |
@@ -26,22 +26,26 @@ import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery | |||
26 | import org.eclipse.xtend.lib.annotations.Accessors | 26 | import org.eclipse.xtend.lib.annotations.Accessors |
27 | 27 | ||
28 | import static extension hu.bme.mit.inf.dslreasoner.util.CollectionsUtil.* | 28 | import static extension hu.bme.mit.inf.dslreasoner.util.CollectionsUtil.* |
29 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.ScopePropagatorStrategy | ||
29 | 30 | ||
30 | class PatternGenerator { | 31 | class PatternGenerator { |
31 | @Accessors(PUBLIC_GETTER) val TypeIndexer typeIndexer //= new TypeIndexer(this) | 32 | @Accessors(PUBLIC_GETTER) val TypeIndexer typeIndexer // = new TypeIndexer(this) |
32 | @Accessors(PUBLIC_GETTER) val RelationDeclarationIndexer relationDeclarationIndexer = new RelationDeclarationIndexer(this) | 33 | @Accessors(PUBLIC_GETTER) val RelationDeclarationIndexer relationDeclarationIndexer = new RelationDeclarationIndexer( |
33 | @Accessors(PUBLIC_GETTER) val RelationDefinitionIndexer relationDefinitionIndexer = new RelationDefinitionIndexer(this) | 34 | this) |
35 | @Accessors(PUBLIC_GETTER) val RelationDefinitionIndexer relationDefinitionIndexer = new RelationDefinitionIndexer( | ||
36 | this) | ||
34 | @Accessors(PUBLIC_GETTER) val ContainmentIndexer containmentIndexer = new ContainmentIndexer(this) | 37 | @Accessors(PUBLIC_GETTER) val ContainmentIndexer containmentIndexer = new ContainmentIndexer(this) |
35 | @Accessors(PUBLIC_GETTER) val InvalidIndexer invalidIndexer = new InvalidIndexer(this) | 38 | @Accessors(PUBLIC_GETTER) val InvalidIndexer invalidIndexer = new InvalidIndexer(this) |
36 | @Accessors(PUBLIC_GETTER) val UnfinishedIndexer unfinishedIndexer = new UnfinishedIndexer(this) | 39 | @Accessors(PUBLIC_GETTER) val UnfinishedIndexer unfinishedIndexer |
37 | @Accessors(PUBLIC_GETTER) val TypeRefinementGenerator typeRefinementGenerator //= new RefinementGenerator(this) | 40 | @Accessors(PUBLIC_GETTER) val TypeRefinementGenerator typeRefinementGenerator // = new RefinementGenerator(this) |
38 | @Accessors(PUBLIC_GETTER) val RelationRefinementGenerator relationRefinementGenerator = new RelationRefinementGenerator(this) | 41 | @Accessors(PUBLIC_GETTER) val RelationRefinementGenerator relationRefinementGenerator = new RelationRefinementGenerator( |
39 | 42 | this) | |
40 | public new(TypeInferenceMethod typeInferenceMethod) { | 43 | |
41 | if(typeInferenceMethod == TypeInferenceMethod.Generic) { | 44 | new(TypeInferenceMethod typeInferenceMethod, ScopePropagatorStrategy scopePropagatorStrategy) { |
45 | if (typeInferenceMethod == TypeInferenceMethod.Generic) { | ||
42 | this.typeIndexer = new GenericTypeIndexer(this) | 46 | this.typeIndexer = new GenericTypeIndexer(this) |
43 | this.typeRefinementGenerator = new GenericTypeRefinementGenerator(this) | 47 | this.typeRefinementGenerator = new GenericTypeRefinementGenerator(this) |
44 | } else if(typeInferenceMethod == TypeInferenceMethod.PreliminaryAnalysis) { | 48 | } else if (typeInferenceMethod == TypeInferenceMethod.PreliminaryAnalysis) { |
45 | this.typeIndexer = new TypeIndexerWithPreliminaryTypeAnalysis(this) | 49 | this.typeIndexer = new TypeIndexerWithPreliminaryTypeAnalysis(this) |
46 | this.typeRefinementGenerator = new TypeRefinementWithPreliminaryTypeAnalysis(this) | 50 | this.typeRefinementGenerator = new TypeRefinementWithPreliminaryTypeAnalysis(this) |
47 | } else { | 51 | } else { |
@@ -49,112 +53,100 @@ class PatternGenerator { | |||
49 | this.typeRefinementGenerator = null | 53 | this.typeRefinementGenerator = null |
50 | throw new IllegalArgumentException('''Unknown type indexing technique : «typeInferenceMethod.name»''') | 54 | throw new IllegalArgumentException('''Unknown type indexing technique : «typeInferenceMethod.name»''') |
51 | } | 55 | } |
56 | this.unfinishedIndexer = new UnfinishedIndexer(this, scopePropagatorStrategy.requiresUpperBoundIndexing) | ||
52 | } | 57 | } |
53 | 58 | ||
54 | public def requiresTypeAnalysis() { | 59 | def requiresTypeAnalysis() { |
55 | typeIndexer.requiresTypeAnalysis || typeRefinementGenerator.requiresTypeAnalysis | 60 | typeIndexer.requiresTypeAnalysis || typeRefinementGenerator.requiresTypeAnalysis |
56 | } | 61 | } |
57 | 62 | ||
58 | public dispatch def referRelation( | 63 | dispatch def CharSequence referRelation(RelationDeclaration referred, String sourceVariable, String targetVariable, |
59 | RelationDeclaration referred, | 64 | Modality modality, Map<String, PQuery> fqn2PQuery) { |
60 | String sourceVariable, | 65 | return this.relationDeclarationIndexer.referRelation(referred, sourceVariable, targetVariable, modality) |
61 | String targetVariable, | ||
62 | Modality modality, | ||
63 | Map<String,PQuery> fqn2PQuery) | ||
64 | { | ||
65 | return this.relationDeclarationIndexer.referRelation(referred,sourceVariable,targetVariable,modality) | ||
66 | } | 66 | } |
67 | public dispatch def referRelation( | 67 | |
68 | RelationDefinition referred, | 68 | dispatch def CharSequence referRelation(RelationDefinition referred, String sourceVariable, String targetVariable, |
69 | String sourceVariable, | 69 | Modality modality, Map<String, PQuery> fqn2PQuery) { |
70 | String targetVariable, | 70 | val pattern = referred.annotations.filter(TransfomedViatraQuery).head.patternFullyQualifiedName.lookup( |
71 | Modality modality, | 71 | fqn2PQuery) |
72 | Map<String,PQuery> fqn2PQuery) | 72 | return this.relationDefinitionIndexer.referPattern(pattern, #[sourceVariable, targetVariable], modality, true, |
73 | { | 73 | false) |
74 | val pattern = referred.annotations.filter(TransfomedViatraQuery).head.patternFullyQualifiedName.lookup(fqn2PQuery) | ||
75 | return this.relationDefinitionIndexer.referPattern(pattern,#[sourceVariable,targetVariable],modality,true,false) | ||
76 | } | 74 | } |
77 | 75 | ||
78 | def public referRelationByName(EReference reference, | 76 | def referRelationByName(EReference reference, String sourceVariable, String targetVariable, Modality modality) { |
79 | String sourceVariable, | 77 | '''find «modality.name.toLowerCase»InRelation«canonizeName('''«reference.name» reference «reference.EContainingClass.name»''')»(problem,interpretation,«sourceVariable»,«targetVariable»);''' |
80 | String targetVariable, | ||
81 | Modality modality) | ||
82 | { | ||
83 | '''find «modality.name.toLowerCase»InRelation«canonizeName('''«reference.name» reference «reference.EContainingClass.name»''') | ||
84 | »(problem,interpretation,«sourceVariable»,«targetVariable»);''' | ||
85 | } | 78 | } |
86 | 79 | ||
87 | def public CharSequence referAttributeByName(EAttribute attribute, | 80 | def CharSequence referAttributeByName(EAttribute attribute, String sourceVariable, String targetVariable, |
88 | String sourceVariable, | 81 | Modality modality) { |
89 | String targetVariable, | 82 | '''find «modality.name.toLowerCase»InRelation«canonizeName('''«attribute.name» attribute «attribute.EContainingClass.name»''')»(problem,interpretation,«sourceVariable»,«targetVariable»);''' |
90 | Modality modality) | ||
91 | { | ||
92 | '''find «modality.name.toLowerCase»InRelation«canonizeName('''«attribute.name» attribute «attribute.EContainingClass.name»''') | ||
93 | »(problem,interpretation,«sourceVariable»,«targetVariable»);''' | ||
94 | } | 83 | } |
95 | 84 | ||
96 | public def canonizeName(String name) { | 85 | def canonizeName(String name) { |
97 | name.split(' ').join('_') | 86 | name.split(' ').join('_') |
98 | } | 87 | } |
99 | 88 | ||
100 | public def lowerMultiplicities(LogicProblem problem) { | 89 | def wfQueries(LogicProblem problem) { |
101 | problem.assertions.map[annotations].flatten.filter(LowerMultiplicityAssertion).filter[!it.relation.isDerived] | 90 | problem.assertions.map[it.annotations].flatten.filter(TransformedViatraWellformednessConstraint).map[it.query] |
102 | } | ||
103 | public def wfQueries(LogicProblem problem) { | ||
104 | problem.assertions.map[it.annotations] | ||
105 | .flatten | ||
106 | .filter(TransformedViatraWellformednessConstraint) | ||
107 | .map[it.query] | ||
108 | } | 91 | } |
109 | public def getContainments(LogicProblem p) { | 92 | |
93 | def getContainments(LogicProblem p) { | ||
110 | return p.containmentHierarchies.head.containmentRelations | 94 | return p.containmentHierarchies.head.containmentRelations |
111 | } | 95 | } |
112 | public def getInverseRelations(LogicProblem p) { | 96 | |
97 | def getInverseRelations(LogicProblem p) { | ||
113 | val inverseRelations = new HashMap | 98 | val inverseRelations = new HashMap |
114 | p.annotations.filter(InverseRelationAssertion).forEach[ | 99 | p.annotations.filter(InverseRelationAssertion).forEach [ |
115 | inverseRelations.put(it.inverseA,it.inverseB) | 100 | inverseRelations.put(it.inverseA, it.inverseB) |
116 | inverseRelations.put(it.inverseB,it.inverseA) | 101 | inverseRelations.put(it.inverseB, it.inverseA) |
117 | ] | 102 | ] |
118 | return inverseRelations | 103 | return inverseRelations |
119 | } | 104 | } |
120 | public def isRepresentative(Relation relation, Relation inverse) { | 105 | |
121 | if(inverse == null) { | 106 | def isRepresentative(Relation relation, Relation inverse) { |
107 | if (inverse === null) { | ||
122 | return true | 108 | return true |
123 | } else { | 109 | } else { |
124 | relation.name.compareTo(inverse.name)<1 | 110 | relation.name.compareTo(inverse.name) < 1 |
125 | } | 111 | } |
126 | } | 112 | } |
127 | 113 | ||
128 | public def isDerived(Relation relation) { | 114 | def isDerived(Relation relation) { |
129 | relation.annotations.exists[it instanceof DefinedByDerivedFeature] | 115 | relation.annotations.exists[it instanceof DefinedByDerivedFeature] |
130 | } | 116 | } |
131 | public def getDerivedDefinition(RelationDeclaration relation) { | 117 | |
118 | def getDerivedDefinition(RelationDeclaration relation) { | ||
132 | relation.annotations.filter(DefinedByDerivedFeature).head.query | 119 | relation.annotations.filter(DefinedByDerivedFeature).head.query |
133 | } | 120 | } |
134 | 121 | ||
135 | private def allTypeReferences(LogicProblem problem) { | 122 | private def allTypeReferences(LogicProblem problem) { |
136 | problem.eAllContents.filter(TypeReference).toIterable | 123 | problem.eAllContents.filter(TypeReference).toIterable |
137 | } | 124 | } |
125 | |||
138 | protected def hasBoolean(LogicProblem problem) { | 126 | protected def hasBoolean(LogicProblem problem) { |
139 | problem.allTypeReferences.exists[it instanceof BoolTypeReference] | 127 | problem.allTypeReferences.exists[it instanceof BoolTypeReference] |
140 | } | 128 | } |
129 | |||
141 | protected def hasInteger(LogicProblem problem) { | 130 | protected def hasInteger(LogicProblem problem) { |
142 | problem.allTypeReferences.exists[it instanceof IntTypeReference] | 131 | problem.allTypeReferences.exists[it instanceof IntTypeReference] |
143 | } | 132 | } |
133 | |||
144 | protected def hasReal(LogicProblem problem) { | 134 | protected def hasReal(LogicProblem problem) { |
145 | problem.allTypeReferences.exists[it instanceof RealTypeReference] | 135 | problem.allTypeReferences.exists[it instanceof RealTypeReference] |
146 | } | 136 | } |
137 | |||
147 | protected def hasString(LogicProblem problem) { | 138 | protected def hasString(LogicProblem problem) { |
148 | problem.allTypeReferences.exists[it instanceof StringTypeReference] | 139 | problem.allTypeReferences.exists[it instanceof StringTypeReference] |
149 | } | 140 | } |
150 | 141 | ||
151 | public def transformBaseProperties( | 142 | def transformBaseProperties( |
152 | LogicProblem problem, | 143 | LogicProblem problem, |
153 | PartialInterpretation emptySolution, | 144 | PartialInterpretation emptySolution, |
154 | Map<String,PQuery> fqn2PQuery, | 145 | Map<String, PQuery> fqn2PQuery, |
155 | TypeAnalysisResult typeAnalysisResult | 146 | TypeAnalysisResult typeAnalysisResult, |
147 | RelationConstraints constraints | ||
156 | ) { | 148 | ) { |
157 | 149 | ||
158 | return ''' | 150 | return ''' |
159 | import epackage "http://www.bme.hu/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage" | 151 | import epackage "http://www.bme.hu/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage" |
160 | import epackage "http://www.bme.hu/mit/inf/dslreasoner/logic/model/problem" | 152 | import epackage "http://www.bme.hu/mit/inf/dslreasoner/logic/model/problem" |
@@ -188,7 +180,7 @@ class PatternGenerator { | |||
188 | 180 | ||
189 | private pattern elementCloseWorld(element:DefinedElement) { | 181 | private pattern elementCloseWorld(element:DefinedElement) { |
190 | PartialInterpretation.openWorldElements(i,element); | 182 | PartialInterpretation.openWorldElements(i,element); |
191 | PartialInterpretation.maxNewElements(i,0); | 183 | PartialInterpretation.maxNewElements(i,0); |
192 | } or { | 184 | } or { |
193 | Scope.targetTypeInterpretation(scope,interpretation); | 185 | Scope.targetTypeInterpretation(scope,interpretation); |
194 | PartialTypeInterpratation.elements(interpretation,element); | 186 | PartialTypeInterpratation.elements(interpretation,element); |
@@ -221,7 +213,7 @@ class PatternGenerator { | |||
221 | ////////// | 213 | ////////// |
222 | // 1.1.1 primitive Type Indexers | 214 | // 1.1.1 primitive Type Indexers |
223 | ////////// | 215 | ////////// |
224 | ««« pattern instanceofBoolean(problem:LogicProblem, interpretation:PartialInterpretation, element:DefinedElement) { | 216 | ««« pattern instanceofBoolean(problem:LogicProblem, interpretation:PartialInterpretation, element:DefinedElement) { |
225 | ««« find interpretation(problem,interpretation); | 217 | ««« find interpretation(problem,interpretation); |
226 | ««« PartialInterpretation.booleanelements(interpretation,element); | 218 | ««« PartialInterpretation.booleanelements(interpretation,element); |
227 | ««« } | 219 | ««« } |
@@ -279,7 +271,7 @@ class PatternGenerator { | |||
279 | ////////// | 271 | ////////// |
280 | // 3.1 Unfinishedness Measured by Multiplicity | 272 | // 3.1 Unfinishedness Measured by Multiplicity |
281 | ////////// | 273 | ////////// |
282 | «unfinishedIndexer.generateUnfinishedMultiplicityQueries(problem,fqn2PQuery)» | 274 | «unfinishedIndexer.generateUnfinishedMultiplicityQueries(constraints.multiplicityConstraints,fqn2PQuery)» |
283 | 275 | ||
284 | ////////// | 276 | ////////// |
285 | // 3.2 Unfinishedness Measured by WF Queries | 277 | // 3.2 Unfinishedness Measured by WF Queries |
@@ -302,6 +294,6 @@ class PatternGenerator { | |||
302 | // 4.3 Relation refinement | 294 | // 4.3 Relation refinement |
303 | ////////// | 295 | ////////// |
304 | «relationRefinementGenerator.generateRefineReference(problem)» | 296 | «relationRefinementGenerator.generateRefineReference(problem)» |
305 | ''' | 297 | ''' |
306 | } | 298 | } |
307 | } | 299 | } |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/PatternProvider.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/PatternProvider.xtend index 0e13a5e1..eadf0ae0 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/PatternProvider.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/PatternProvider.xtend | |||
@@ -2,16 +2,23 @@ package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns | |||
2 | 2 | ||
3 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Relation | 3 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Relation |
4 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RelationDeclaration | 4 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RelationDeclaration |
5 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RelationDefinition | ||
5 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Type | 6 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Type |
6 | import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem | 7 | import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem |
8 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.Modality | ||
7 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.ModelGenerationStatistics | 9 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.ModelGenerationStatistics |
8 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.TypeAnalysis | 10 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.TypeAnalysis |
9 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.TypeAnalysisResult | 11 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.TypeAnalysisResult |
10 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.TypeInferenceMethod | 12 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.TypeInferenceMethod |
13 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.RelationConstraints | ||
14 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.RelationMultiplicityConstraint | ||
15 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.ScopePropagatorStrategy | ||
11 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.util.ParseUtil | 16 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.util.ParseUtil |
12 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | 17 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation |
13 | import hu.bme.mit.inf.dslreasoner.workspace.ReasonerWorkspace | 18 | import hu.bme.mit.inf.dslreasoner.workspace.ReasonerWorkspace |
19 | import java.util.Collection | ||
14 | import java.util.Map | 20 | import java.util.Map |
21 | import java.util.Set | ||
15 | import org.eclipse.viatra.query.runtime.api.IPatternMatch | 22 | import org.eclipse.viatra.query.runtime.api.IPatternMatch |
16 | import org.eclipse.viatra.query.runtime.api.IQuerySpecification | 23 | import org.eclipse.viatra.query.runtime.api.IQuerySpecification |
17 | import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher | 24 | import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher |
@@ -19,79 +26,115 @@ import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery | |||
19 | import org.eclipse.xtend.lib.annotations.Data | 26 | import org.eclipse.xtend.lib.annotations.Data |
20 | 27 | ||
21 | import static extension hu.bme.mit.inf.dslreasoner.util.CollectionsUtil.* | 28 | import static extension hu.bme.mit.inf.dslreasoner.util.CollectionsUtil.* |
22 | import java.util.Collection | ||
23 | import java.util.Set | ||
24 | 29 | ||
25 | @Data class GeneratedPatterns { | 30 | @Data |
26 | public Map<Relation, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> invalidWFQueries | 31 | class GeneratedPatterns { |
27 | public Map<Relation, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> unfinishedWFQueries | 32 | public Map<Relation, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> invalidWFQueries |
28 | public Map<Relation, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> unfinishedMulticiplicityQueries | 33 | public Map<Relation, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> unfinishedWFQueries |
29 | public Map<ObjectCreationPrecondition, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> refineObjectQueries | 34 | public Map<RelationMultiplicityConstraint, UnifinishedMultiplicityQueries> multiplicityConstraintQueries |
30 | public Map<? extends Type, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> refineTypeQueries | 35 | public IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> hasElementInContainmentQuery |
31 | public Map<Pair<RelationDeclaration, Relation>, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> refinerelationQueries | 36 | public Map<Relation, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> unfinishedMulticiplicityQueries |
37 | public Map<ObjectCreationPrecondition, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> refineObjectQueries | ||
38 | public Map<? extends Type, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> refineTypeQueries | ||
39 | public Map<Pair<RelationDeclaration, Relation>, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> refinerelationQueries | ||
40 | public Map<RelationDefinition, ModalPatternQueries> modalRelationQueries | ||
32 | public Collection<IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> allQueries | 41 | public Collection<IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> allQueries |
33 | } | 42 | } |
34 | 43 | ||
44 | @Data | ||
45 | class ModalPatternQueries { | ||
46 | val IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> mayQuery | ||
47 | val IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> mustQuery | ||
48 | val IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> currentQuery | ||
49 | } | ||
50 | |||
51 | @Data | ||
52 | class UnifinishedMultiplicityQueries { | ||
53 | val IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> unfinishedMultiplicityQuery | ||
54 | val IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> unrepairableMultiplicityQuery | ||
55 | val IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> remainingInverseMultiplicityQuery | ||
56 | val IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> remainingContentsQuery | ||
57 | } | ||
58 | |||
35 | class PatternProvider { | 59 | class PatternProvider { |
36 | 60 | ||
37 | val TypeAnalysis typeAnalysis = new TypeAnalysis | 61 | val TypeAnalysis typeAnalysis = new TypeAnalysis |
38 | 62 | ||
39 | public def generateQueries( | 63 | def generateQueries(LogicProblem problem, PartialInterpretation emptySolution, ModelGenerationStatistics statistics, |
40 | LogicProblem problem, | 64 | Set<PQuery> existingQueries, ReasonerWorkspace workspace, TypeInferenceMethod typeInferenceMethod, |
41 | PartialInterpretation emptySolution, | 65 | ScopePropagatorStrategy scopePropagatorStrategy, RelationConstraints relationConstraints, boolean writeToFile) { |
42 | ModelGenerationStatistics statistics, | ||
43 | Set<PQuery> existingQueries, | ||
44 | ReasonerWorkspace workspace, | ||
45 | TypeInferenceMethod typeInferenceMethod, | ||
46 | boolean writeToFile) | ||
47 | { | ||
48 | val fqn2Query = existingQueries.toMap[it.fullyQualifiedName] | 66 | val fqn2Query = existingQueries.toMap[it.fullyQualifiedName] |
49 | val PatternGenerator patternGenerator = new PatternGenerator(typeInferenceMethod) | 67 | val PatternGenerator patternGenerator = new PatternGenerator(typeInferenceMethod, scopePropagatorStrategy) |
50 | val typeAnalysisResult = if(patternGenerator.requiresTypeAnalysis) { | 68 | val typeAnalysisResult = if (patternGenerator.requiresTypeAnalysis) { |
51 | val startTime = System.nanoTime | 69 | val startTime = System.nanoTime |
52 | val result = typeAnalysis.performTypeAnalysis(problem,emptySolution) | 70 | val result = typeAnalysis.performTypeAnalysis(problem, emptySolution) |
53 | val typeAnalysisTime = System.nanoTime - startTime | 71 | val typeAnalysisTime = System.nanoTime - startTime |
54 | statistics.PreliminaryTypeAnalisisTime = typeAnalysisTime | 72 | statistics.preliminaryTypeAnalisisTime = typeAnalysisTime |
55 | result | 73 | result |
56 | } else { | 74 | } else { |
57 | null | 75 | null |
58 | } | 76 | } |
59 | val baseIndexerFile = patternGenerator.transformBaseProperties(problem,emptySolution,fqn2Query,typeAnalysisResult) | 77 | val baseIndexerFile = patternGenerator.transformBaseProperties(problem, emptySolution, fqn2Query, |
60 | if(writeToFile) { | 78 | typeAnalysisResult, relationConstraints) |
61 | workspace.writeText('''generated3valued.vql_deactivated''',baseIndexerFile) | 79 | if (writeToFile) { |
80 | workspace.writeText('''generated3valued.vql_deactivated''', baseIndexerFile) | ||
62 | } | 81 | } |
63 | val ParseUtil parseUtil = new ParseUtil | 82 | val ParseUtil parseUtil = new ParseUtil |
64 | val generatedQueries = parseUtil.parse(baseIndexerFile) | 83 | val generatedQueries = parseUtil.parse(baseIndexerFile) |
65 | val runtimeQueries = calclulateRuntimeQueries(patternGenerator,problem,emptySolution,typeAnalysisResult,generatedQueries); | 84 | val runtimeQueries = calclulateRuntimeQueries(patternGenerator, problem, emptySolution, typeAnalysisResult, |
85 | relationConstraints, generatedQueries) | ||
66 | return runtimeQueries | 86 | return runtimeQueries |
67 | } | 87 | } |
68 | 88 | ||
69 | private def GeneratedPatterns calclulateRuntimeQueries( | 89 | private def GeneratedPatterns calclulateRuntimeQueries( |
70 | PatternGenerator patternGenerator, | 90 | PatternGenerator patternGenerator, |
71 | LogicProblem problem, | 91 | LogicProblem problem, |
72 | PartialInterpretation emptySolution, | 92 | PartialInterpretation emptySolution, |
73 | TypeAnalysisResult typeAnalysisResult, | 93 | TypeAnalysisResult typeAnalysisResult, |
74 | Map<String, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> queries | 94 | RelationConstraints relationConstraints, |
95 | Map<String, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> queries | ||
75 | ) { | 96 | ) { |
76 | val Map<Relation, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> | 97 | val invalidWFQueries = patternGenerator.invalidIndexer.getInvalidateByWfQueryNames(problem).mapValues [ |
77 | invalidWFQueries = patternGenerator.invalidIndexer.getInvalidateByWfQueryNames(problem).mapValues[it.lookup(queries)] | 98 | it.lookup(queries) |
78 | val Map<Relation, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> | 99 | ] |
79 | unfinishedWFQueries = patternGenerator.unfinishedIndexer.getUnfinishedWFQueryNames(problem).mapValues[it.lookup(queries)] | 100 | val unfinishedWFQueries = patternGenerator.unfinishedIndexer.getUnfinishedWFQueryNames(problem).mapValues [ |
80 | val Map<Relation, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> | 101 | it.lookup(queries) |
81 | unfinishedMultiplicityQueries = patternGenerator.unfinishedIndexer.getUnfinishedMultiplicityQueries(problem).mapValues[it.lookup(queries)] | 102 | ] |
82 | val Map<ObjectCreationPrecondition, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> | 103 | val multiplicityConstraintQueries = patternGenerator.unfinishedIndexer.getUnfinishedMultiplicityQueries( |
83 | refineObjectsQueries = patternGenerator.typeRefinementGenerator.getRefineObjectQueryNames(problem,emptySolution,typeAnalysisResult).mapValues[it.lookup(queries)] | 104 | relationConstraints.multiplicityConstraints).mapValues [ |
84 | val Map<? extends Type, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> | 105 | new UnifinishedMultiplicityQueries(unfinishedMultiplicityQueryName?.lookup(queries), |
85 | refineTypeQueries = patternGenerator.typeRefinementGenerator.getRefineTypeQueryNames(problem,emptySolution,typeAnalysisResult).mapValues[it.lookup(queries)] | 106 | unrepairableMultiplicityQueryName?.lookup(queries), |
86 | val Map<Pair<RelationDeclaration, Relation>, IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> | 107 | remainingInverseMultiplicityQueryName?.lookup(queries), remainingContentsQueryName?.lookup(queries)) |
87 | refineRelationQueries = patternGenerator.relationRefinementGenerator.getRefineRelationQueries(problem).mapValues[it.lookup(queries)] | 108 | ] |
109 | val hasElementInContainmentQuery = patternGenerator.typeRefinementGenerator.hasElementInContainmentName.lookup( | ||
110 | queries) | ||
111 | val unfinishedMultiplicityQueries = multiplicityConstraintQueries.entrySet.filter [ | ||
112 | value.unfinishedMultiplicityQuery !== null | ||
113 | ].toMap([key.relation], [value.unfinishedMultiplicityQuery]) | ||
114 | val refineObjectsQueries = patternGenerator.typeRefinementGenerator. | ||
115 | getRefineObjectQueryNames(problem, emptySolution, typeAnalysisResult).mapValues[it.lookup(queries)] | ||
116 | val refineTypeQueries = patternGenerator.typeRefinementGenerator.getRefineTypeQueryNames(problem, emptySolution, | ||
117 | typeAnalysisResult).mapValues[it.lookup(queries)] | ||
118 | val refineRelationQueries = patternGenerator.relationRefinementGenerator.getRefineRelationQueries(problem). | ||
119 | mapValues[it.lookup(queries)] | ||
120 | val modalRelationQueries = problem.relations.filter(RelationDefinition).toMap([it], [ relationDefinition | | ||
121 | val indexer = patternGenerator.relationDefinitionIndexer | ||
122 | new ModalPatternQueries( | ||
123 | indexer.relationDefinitionName(relationDefinition, Modality.MAY).lookup(queries), | ||
124 | indexer.relationDefinitionName(relationDefinition, Modality.MUST).lookup(queries), | ||
125 | indexer.relationDefinitionName(relationDefinition, Modality.CURRENT).lookup(queries) | ||
126 | ) | ||
127 | ]) | ||
88 | return new GeneratedPatterns( | 128 | return new GeneratedPatterns( |
89 | invalidWFQueries, | 129 | invalidWFQueries, |
90 | unfinishedWFQueries, | 130 | unfinishedWFQueries, |
131 | multiplicityConstraintQueries, | ||
132 | hasElementInContainmentQuery, | ||
91 | unfinishedMultiplicityQueries, | 133 | unfinishedMultiplicityQueries, |
92 | refineObjectsQueries, | 134 | refineObjectsQueries, |
93 | refineTypeQueries, | 135 | refineTypeQueries, |
94 | refineRelationQueries, | 136 | refineRelationQueries, |
137 | modalRelationQueries, | ||
95 | queries.values | 138 | queries.values |
96 | ) | 139 | ) |
97 | } | 140 | } |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/RelationDefinitionIndexer.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/RelationDefinitionIndexer.xtend index 9723373f..cedcec5a 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/RelationDefinitionIndexer.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/RelationDefinitionIndexer.xtend | |||
@@ -71,7 +71,7 @@ class RelationDefinitionIndexer { | |||
71 | ] | 71 | ] |
72 | } | 72 | } |
73 | 73 | ||
74 | private def relationDefinitionName(RelationDefinition relation, Modality modality) | 74 | def String relationDefinitionName(RelationDefinition relation, Modality modality) |
75 | '''«modality.name.toLowerCase»InRelation_«base.canonizeName(relation.name)»''' | 75 | '''«modality.name.toLowerCase»InRelation_«base.canonizeName(relation.name)»''' |
76 | 76 | ||
77 | private def canonizeName(PVariable v) { | 77 | private def canonizeName(PVariable v) { |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/RelationRefinementGenerator.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/RelationRefinementGenerator.xtend index f9e9baea..fa73c861 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/RelationRefinementGenerator.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/RelationRefinementGenerator.xtend | |||
@@ -9,77 +9,71 @@ import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.ComplexTypeReference | |||
9 | 9 | ||
10 | class RelationRefinementGenerator { | 10 | class RelationRefinementGenerator { |
11 | PatternGenerator base; | 11 | PatternGenerator base; |
12 | |||
12 | public new(PatternGenerator base) { | 13 | public new(PatternGenerator base) { |
13 | this.base = base | 14 | this.base = base |
14 | } | 15 | } |
15 | 16 | ||
16 | def CharSequence generateRefineReference(LogicProblem p) { | 17 | def CharSequence generateRefineReference(LogicProblem p) ''' |
17 | return ''' | 18 | «FOR relationRefinement : this.getRelationRefinements(p)» |
18 | «FOR relationRefinement: this.getRelationRefinements(p)» | 19 | pattern «relationRefinementQueryName(relationRefinement.key,relationRefinement.value)»( |
19 | pattern «relationRefinementQueryName(relationRefinement.key,relationRefinement.value)»( | 20 | problem:LogicProblem, interpretation:PartialInterpretation, |
20 | problem:LogicProblem, interpretation:PartialInterpretation, | 21 | relationIterpretation:PartialRelationInterpretation«IF relationRefinement.value !== null», oppositeInterpretation:PartialRelationInterpretation«ENDIF», |
21 | relationIterpretation:PartialRelationInterpretation«IF relationRefinement.value != null», oppositeInterpretation:PartialRelationInterpretation«ENDIF», | 22 | from: DefinedElement, to: DefinedElement) |
22 | from: DefinedElement, to: DefinedElement) | 23 | { |
23 | { | 24 | find interpretation(problem,interpretation); |
24 | find interpretation(problem,interpretation); | 25 | PartialInterpretation.partialrelationinterpretation(interpretation,relationIterpretation); |
25 | PartialInterpretation.partialrelationinterpretation(interpretation,relationIterpretation); | 26 | PartialRelationInterpretation.interpretationOf.name(relationIterpretation,"«relationRefinement.key.name»"); |
26 | PartialRelationInterpretation.interpretationOf.name(relationIterpretation,"«relationRefinement.key.name»"); | 27 | «IF relationRefinement.value !== null» |
27 | «IF relationRefinement.value != null» | 28 | PartialInterpretation.partialrelationinterpretation(interpretation,oppositeInterpretation); |
28 | PartialInterpretation.partialrelationinterpretation(interpretation,oppositeInterpretation); | 29 | PartialRelationInterpretation.interpretationOf.name(oppositeInterpretation,"«relationRefinement.value.name»"); |
29 | PartialRelationInterpretation.interpretationOf.name(oppositeInterpretation,"«relationRefinement.value.name»"); | 30 | «ENDIF» |
30 | «ENDIF» | 31 | find mustExist(problem, interpretation, from); |
31 | find mustExist(problem, interpretation, from); | 32 | find mustExist(problem, interpretation, to); |
32 | find mustExist(problem, interpretation, to); | 33 | «base.typeIndexer.referInstanceOfByReference(relationRefinement.key.parameters.get(0), Modality::MUST,"from")» |
33 | «base.typeIndexer.referInstanceOfByReference(relationRefinement.key.parameters.get(0), Modality::MUST,"from")» | 34 | «base.typeIndexer.referInstanceOfByReference(relationRefinement.key.parameters.get(1), Modality::MUST,"to")» |
34 | «base.typeIndexer.referInstanceOfByReference(relationRefinement.key.parameters.get(1), Modality::MUST,"to")» | 35 | «base.relationDeclarationIndexer.referRelation(relationRefinement.key,"from","to",Modality.MAY)» |
35 | «base.relationDeclarationIndexer.referRelation(relationRefinement.key,"from","to",Modality.MAY)» | 36 | neg «base.relationDeclarationIndexer.referRelation(relationRefinement.key,"from","to",Modality.MUST)» |
36 | neg «base.relationDeclarationIndexer.referRelation(relationRefinement.key,"from","to",Modality.MUST)» | 37 | } |
37 | } | ||
38 | «ENDFOR» | 38 | «ENDFOR» |
39 | ''' | 39 | ''' |
40 | } | 40 | |
41 | |||
42 | def String relationRefinementQueryName(RelationDeclaration relation, Relation inverseRelation) { | 41 | def String relationRefinementQueryName(RelationDeclaration relation, Relation inverseRelation) { |
43 | '''«IF inverseRelation != null | 42 | '''«IF inverseRelation !== null»refineRelation_«base.canonizeName(relation.name)»_and_«base.canonizeName(inverseRelation.name)»«ELSE»refineRelation_«base.canonizeName(relation.name)»«ENDIF»''' |
44 | »refineRelation_«base.canonizeName(relation.name)»_and_«base.canonizeName(inverseRelation.name)»« | ||
45 | ELSE | ||
46 | »refineRelation_«base.canonizeName(relation.name)»«ENDIF»''' | ||
47 | } | 43 | } |
48 | 44 | ||
49 | def referRefinementQuery(RelationDeclaration relation, Relation inverseRelation, String relInterpretationName, | 45 | def referRefinementQuery(RelationDeclaration relation, Relation inverseRelation, String relInterpretationName, |
50 | String inverseInterpretationName, String sourceName, String targetName) | 46 | String inverseInterpretationName, String sourceName, |
51 | '''find «this.relationRefinementQueryName(relation,inverseRelation)»(problem, interpretation, «relInterpretationName», «IF inverseRelation != null»inverseInterpretationName, «ENDIF»«sourceName», «targetName»);''' | 47 | String targetName) '''find «this.relationRefinementQueryName(relation,inverseRelation)»(problem, interpretation, «relInterpretationName», «IF inverseRelation !== null»inverseInterpretationName, «ENDIF»«sourceName», «targetName»);''' |
52 | 48 | ||
53 | def getRefineRelationQueries(LogicProblem p) { | 49 | def getRefineRelationQueries(LogicProblem p) { |
54 | // val containmentRelations = p.containmentHierarchies.map[containmentRelations].flatten.toSet | 50 | // val containmentRelations = p.containmentHierarchies.map[containmentRelations].flatten.toSet |
55 | // p.relations.filter(RelationDeclaration).filter[!containmentRelations.contains(it)].toInvertedMap['''refineRelation_«base.canonizeName(it.name)»'''] | 51 | // p.relations.filter(RelationDeclaration).filter[!containmentRelations.contains(it)].toInvertedMap['''refineRelation_«base.canonizeName(it.name)»'''] |
56 | /* | 52 | /* |
57 | val res = new LinkedHashMap | 53 | * val res = new LinkedHashMap |
58 | for(relation: getRelationRefinements(p)) { | 54 | * for(relation: getRelationRefinements(p)) { |
59 | if(inverseRelations.containsKey(relation)) { | 55 | * if(inverseRelations.containsKey(relation)) { |
60 | val name = '''refineRelation_«base.canonizeName(relation.name)»_and_«base.canonizeName(inverseRelations.get(relation).name)»''' | 56 | * val name = '''refineRelation_«base.canonizeName(relation.name)»_and_«base.canonizeName(inverseRelations.get(relation).name)»''' |
61 | res.put(relation -> inverseRelations.get(relation),name) | 57 | * res.put(relation -> inverseRelations.get(relation),name) |
62 | } else { | 58 | * } else { |
63 | val name = '''refineRelation_«base.canonizeName(relation.name)»''' | 59 | * val name = '''refineRelation_«base.canonizeName(relation.name)»''' |
64 | res.put(relation -> null,name) | 60 | * res.put(relation -> null,name) |
65 | } | 61 | * } |
66 | } | 62 | * } |
67 | return res*/ | 63 | return res*/ |
68 | 64 | getRelationRefinements(p).toInvertedMap[relationRefinementQueryName(it.key, it.value)] | |
69 | getRelationRefinements(p).toInvertedMap[relationRefinementQueryName(it.key,it.value)] | ||
70 | } | 65 | } |
71 | |||
72 | 66 | ||
73 | def getRelationRefinements(LogicProblem p) { | 67 | def getRelationRefinements(LogicProblem p) { |
74 | val inverses = base.getInverseRelations(p) | 68 | val inverses = base.getInverseRelations(p) |
75 | val containments = base.getContainments(p) | 69 | val containments = base.getContainments(p) |
76 | val list = new LinkedList | 70 | val list = new LinkedList |
77 | for(relation : p.relations.filter(RelationDeclaration)) { | 71 | for (relation : p.relations.filter(RelationDeclaration)) { |
78 | if(!containments.contains(relation)) { | 72 | if (!containments.contains(relation)) { |
79 | if(inverses.containsKey(relation)) { | 73 | if (inverses.containsKey(relation)) { |
80 | val inverse = inverses.get(relation) | 74 | val inverse = inverses.get(relation) |
81 | if(!containments.contains(inverse)) { | 75 | if (!containments.contains(inverse)) { |
82 | if(base.isRepresentative(relation,inverse)) { | 76 | if (base.isRepresentative(relation, inverse)) { |
83 | list += (relation -> inverse) | 77 | list += (relation -> inverse) |
84 | } | 78 | } |
85 | } | 79 | } |
@@ -90,4 +84,4 @@ class RelationRefinementGenerator { | |||
90 | } | 84 | } |
91 | return list | 85 | return list |
92 | } | 86 | } |
93 | } \ No newline at end of file | 87 | } |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/TypeIndexer.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/TypeIndexer.xtend index d1d57189..7d687e99 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/TypeIndexer.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/TypeIndexer.xtend | |||
@@ -1,52 +1,122 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns | 1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns |
2 | 2 | ||
3 | import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem | ||
4 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Type | ||
5 | import org.eclipse.emf.ecore.EClass | ||
6 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.Modality | ||
7 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | ||
8 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.TypeAnalysisResult | ||
9 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.ComplexTypeReference | ||
10 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.BoolTypeReference | 3 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.BoolTypeReference |
4 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.ComplexTypeReference | ||
11 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.IntTypeReference | 5 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.IntTypeReference |
12 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RealTypeReference | 6 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RealTypeReference |
13 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.StringTypeReference | 7 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.StringTypeReference |
8 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Type | ||
9 | import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem | ||
10 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.Modality | ||
11 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.TypeAnalysisResult | ||
12 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | ||
14 | import java.math.BigDecimal | 13 | import java.math.BigDecimal |
14 | import org.eclipse.emf.ecore.EClass | ||
15 | import org.eclipse.xtend.lib.annotations.Accessors | ||
16 | import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor | ||
15 | 17 | ||
18 | @FinalFieldsConstructor | ||
16 | abstract class TypeIndexer { | 19 | abstract class TypeIndexer { |
17 | public def CharSequence getRequiredQueries() | 20 | @Accessors(PROTECTED_GETTER) val PatternGenerator base |
18 | public def boolean requiresTypeAnalysis() | 21 | |
19 | public def CharSequence generateInstanceOfQueries(LogicProblem problem,PartialInterpretation emptySolution,TypeAnalysisResult typeAnalysisResult) | 22 | def CharSequence getRequiredQueries() ''' |
20 | public def CharSequence referInstanceOf(Type type, Modality modality, String variableName) | 23 | private pattern typeInterpretation(problem:LogicProblem, interpretation:PartialInterpretation, type:TypeDeclaration, typeInterpretation:PartialComplexTypeInterpretation) { |
21 | public def CharSequence referInstanceOf(EClass type, Modality modality, String variableName) | 24 | find interpretation(problem,interpretation); |
22 | 25 | LogicProblem.types(problem,type); | |
23 | public def dispatch CharSequence referInstanceOfByReference(ComplexTypeReference reference, Modality modality, String variableName) { | 26 | PartialInterpretation.partialtypeinterpratation(interpretation,typeInterpretation); |
24 | reference.referred.referInstanceOf(modality,variableName) | 27 | PartialComplexTypeInterpretation.interpretationOf(typeInterpretation,type); |
25 | } | 28 | } |
26 | public def dispatch CharSequence referInstanceOfByReference(BoolTypeReference reference, Modality modality, String variableName) { | 29 | |
30 | private pattern directInstanceOf(problem:LogicProblem, interpretation:PartialInterpretation, element:DefinedElement, type:Type) { | ||
31 | find interpretation(problem,interpretation); | ||
32 | LogicProblem.types(problem,type); | ||
33 | TypeDefinition.elements(type,element); | ||
34 | } or { | ||
35 | find interpretation(problem,interpretation); | ||
36 | find typeInterpretation(problem,interpretation,type,typeInterpretation); | ||
37 | PartialComplexTypeInterpretation.elements(typeInterpretation,element); | ||
38 | } | ||
39 | |||
40 | private pattern isPrimitive(element: PrimitiveElement) { | ||
41 | PrimitiveElement(element); | ||
42 | } | ||
43 | ''' | ||
44 | |||
45 | def boolean requiresTypeAnalysis() | ||
46 | |||
47 | def CharSequence generateInstanceOfQueries(LogicProblem problem, PartialInterpretation emptySolution, | ||
48 | TypeAnalysisResult typeAnalysisResult) ''' | ||
49 | «FOR type : problem.types» | ||
50 | «problem.generateMustInstenceOf(type, typeAnalysisResult)» | ||
51 | «problem.generateMayInstanceOf(type, typeAnalysisResult)» | ||
52 | «ENDFOR» | ||
53 | ''' | ||
54 | |||
55 | protected def CharSequence generateMustInstenceOf(LogicProblem problem, Type type, | ||
56 | TypeAnalysisResult typeAnalysisResult) ''' | ||
57 | /** | ||
58 | * An element must be an instance of type "«type.name»". | ||
59 | */ | ||
60 | private pattern «patternName(type,Modality.MUST)»(problem:LogicProblem, interpretation:PartialInterpretation, element:DefinedElement) { | ||
61 | Type.name(type,"«type.name»"); | ||
62 | find directInstanceOf(problem,interpretation,element,type); | ||
63 | } | ||
64 | ''' | ||
65 | |||
66 | protected def CharSequence generateMayInstanceOf(LogicProblem problem, Type type, | ||
67 | TypeAnalysisResult typeAnalysisResult) | ||
68 | |||
69 | protected def patternName(Type type, | ||
70 | Modality modality) '''«modality.toBase»InstanceOf«base.canonizeName(type.name)»''' | ||
71 | |||
72 | def referInstanceOf(Type type, Modality modality, String variableName) { | ||
73 | '''find «patternName(type,modality)»(problem,interpretation,«variableName»);''' | ||
74 | } | ||
75 | |||
76 | def referInstanceOf(EClass type, Modality modality, String variableName) { | ||
77 | '''find «modality.toBase»InstanceOf«base.canonizeName('''«type.name» class''')»(problem,interpretation,«variableName»);''' | ||
78 | } | ||
79 | |||
80 | def dispatch CharSequence referInstanceOfByReference(ComplexTypeReference reference, Modality modality, | ||
81 | String variableName) { | ||
82 | reference.referred.referInstanceOf(modality, variableName) | ||
83 | } | ||
84 | |||
85 | def dispatch CharSequence referInstanceOfByReference(BoolTypeReference reference, Modality modality, | ||
86 | String variableName) { | ||
27 | '''BooleanElement(«variableName»);''' | 87 | '''BooleanElement(«variableName»);''' |
28 | } | 88 | } |
29 | public def dispatch CharSequence referInstanceOfByReference(IntTypeReference reference, Modality modality, String variableName) { | 89 | |
90 | def dispatch CharSequence referInstanceOfByReference(IntTypeReference reference, Modality modality, | ||
91 | String variableName) { | ||
30 | '''IntegerElement(«variableName»);''' | 92 | '''IntegerElement(«variableName»);''' |
31 | } | 93 | } |
32 | public def dispatch CharSequence referInstanceOfByReference(RealTypeReference reference, Modality modality, String variableName) { | 94 | |
95 | def dispatch CharSequence referInstanceOfByReference(RealTypeReference reference, Modality modality, | ||
96 | String variableName) { | ||
33 | '''RealElement(«variableName»);''' | 97 | '''RealElement(«variableName»);''' |
34 | } | 98 | } |
35 | public def dispatch CharSequence referInstanceOfByReference(StringTypeReference reference, Modality modality, String variableName) { | 99 | |
100 | def dispatch CharSequence referInstanceOfByReference(StringTypeReference reference, Modality modality, | ||
101 | String variableName) { | ||
36 | '''StringElement(«variableName»);''' | 102 | '''StringElement(«variableName»);''' |
37 | } | 103 | } |
38 | public def dispatch CharSequence referPrimitiveValue(String variableName, Boolean value) { | 104 | |
105 | def dispatch CharSequence referPrimitiveValue(String variableName, Boolean value) { | ||
39 | '''BooleanElement.value(«variableName»,«value»);''' | 106 | '''BooleanElement.value(«variableName»,«value»);''' |
40 | } | 107 | } |
41 | public def dispatch CharSequence referPrimitiveValue(String variableName, Integer value) { | 108 | |
109 | def dispatch CharSequence referPrimitiveValue(String variableName, Integer value) { | ||
42 | '''IntegerElement.value(«variableName»,«value»);''' | 110 | '''IntegerElement.value(«variableName»,«value»);''' |
43 | } | 111 | } |
44 | public def dispatch CharSequence referPrimitiveValue(String variableName, BigDecimal value) { | 112 | |
113 | def dispatch CharSequence referPrimitiveValue(String variableName, BigDecimal value) { | ||
45 | '''RealElement.value(«variableName»,«value»);''' | 114 | '''RealElement.value(«variableName»,«value»);''' |
46 | } | 115 | } |
47 | ///TODO: de-escaping string literals | 116 | |
48 | public def dispatch CharSequence referPrimitiveValue(String variableName, String value) { | 117 | def dispatch CharSequence referPrimitiveValue(String variableName, String value) { |
118 | // /TODO: de-escaping string literals | ||
49 | '''StringElement.value(«variableName»,"«value»");''' | 119 | '''StringElement.value(«variableName»,"«value»");''' |
50 | } | 120 | } |
51 | 121 | ||
52 | } \ No newline at end of file | 122 | } |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/TypeIndexerWithPreliminaryTypeAnalysis.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/TypeIndexerWithPreliminaryTypeAnalysis.xtend index d3af0426..0393b803 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/TypeIndexerWithPreliminaryTypeAnalysis.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/TypeIndexerWithPreliminaryTypeAnalysis.xtend | |||
@@ -4,113 +4,51 @@ import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Type | |||
4 | import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem | 4 | import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem |
5 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.Modality | 5 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.Modality |
6 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.TypeAnalysisResult | 6 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.TypeAnalysisResult |
7 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.TypeRefinementPrecondition | ||
8 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | ||
9 | import org.eclipse.emf.ecore.EClass | ||
10 | 7 | ||
11 | class TypeIndexerWithPreliminaryTypeAnalysis extends TypeIndexer{ | 8 | class TypeIndexerWithPreliminaryTypeAnalysis extends TypeIndexer { |
12 | val PatternGenerator base; | ||
13 | |||
14 | new(PatternGenerator base) { | 9 | new(PatternGenerator base) { |
15 | this.base = base | 10 | super(base) |
16 | } | 11 | } |
12 | |||
17 | override requiresTypeAnalysis() { true } | 13 | override requiresTypeAnalysis() { true } |
18 | 14 | ||
19 | override getRequiredQueries() ''' | 15 | protected override generateMayInstanceOf(LogicProblem problem, Type type, TypeAnalysisResult typeAnalysisResult) { |
20 | private pattern typeInterpretation(problem:LogicProblem, interpretation:PartialInterpretation, type:TypeDeclaration, typeInterpretation:PartialComplexTypeInterpretation) { | 16 | val precondition = typeAnalysisResult?.mayNewTypePreconditions?.get(type) |
21 | find interpretation(problem,interpretation); | 17 | val inhibitorTypes = precondition?.inhibitorTypes |
22 | LogicProblem.types(problem,type); | ||
23 | PartialInterpretation.partialtypeinterpratation(interpretation,typeInterpretation); | ||
24 | PartialComplexTypeInterpretation.interpretationOf(typeInterpretation,type); | ||
25 | } | ||
26 | |||
27 | private pattern directInstanceOf(problem:LogicProblem, interpretation:PartialInterpretation, element:DefinedElement, type:Type) { | ||
28 | find interpretation(problem,interpretation); | ||
29 | LogicProblem.types(problem,type); | ||
30 | TypeDefinition.elements(type,element); | ||
31 | } or { | ||
32 | find interpretation(problem,interpretation); | ||
33 | find typeInterpretation(problem,interpretation,type,typeInterpretation); | ||
34 | PartialComplexTypeInterpretation.elements(typeInterpretation,element); | ||
35 | } | ||
36 | |||
37 | private pattern isPrimitive(element: PrimitiveElement) { | ||
38 | PrimitiveElement(element); | ||
39 | } | ||
40 | ''' | ||
41 | |||
42 | override generateInstanceOfQueries(LogicProblem problem, PartialInterpretation emptySolution, TypeAnalysisResult typeAnalysisResult) { | ||
43 | val mayNewTypePreconditions = typeAnalysisResult.mayNewTypePreconditions | ||
44 | |||
45 | return ''' | ||
46 | «FOR type:problem.types» | ||
47 | «problem.generateMustInstenceOf(type)» | ||
48 | «problem.generateMayInstanceOf(type,mayNewTypePreconditions.get(type))» | ||
49 | «ENDFOR» | ||
50 | ''' | ||
51 | } | ||
52 | |||
53 | private def patternName(Type type, Modality modality) | ||
54 | '''«modality.toString.toLowerCase»InstanceOf«base.canonizeName(type.name)»''' | ||
55 | |||
56 | private def generateMustInstenceOf(LogicProblem problem, Type type) { | ||
57 | ''' | ||
58 | /** | ||
59 | * An element must be an instance of type "«type.name»". | ||
60 | */ | ||
61 | private pattern «patternName(type,Modality.MUST)»(problem:LogicProblem, interpretation:PartialInterpretation, element:DefinedElement) { | ||
62 | Type.name(type,"«type.name»"); | ||
63 | find directInstanceOf(problem,interpretation,element,type); | ||
64 | } | ||
65 | ''' | ||
66 | } | ||
67 | |||
68 | private def generateMayInstanceOf(LogicProblem problem, Type type, TypeRefinementPrecondition precondition) { | ||
69 | val inhibitorTypes = if(precondition!=null) { | ||
70 | precondition.inhibitorTypes | ||
71 | } else { | ||
72 | null | ||
73 | } | ||
74 | ''' | 18 | ''' |
75 | private pattern scopeDisallowsNew«base.canonizeName(type.name)»(problem:LogicProblem, interpretation:PartialInterpretation) { | 19 | private pattern scopeDisallowsNew«base.canonizeName(type.name)»(problem:LogicProblem, interpretation:PartialInterpretation) { |
76 | find interpretation(problem,interpretation); | 20 | find interpretation(problem,interpretation); |
77 | PartialInterpretation.scopes(interpretation,scope); | 21 | PartialInterpretation.scopes(interpretation,scope); |
78 | Scope.targetTypeInterpretation(scope,typeInterpretation); | 22 | Scope.targetTypeInterpretation(scope,typeInterpretation); |
79 | Scope.maxNewElements(scope,0); | 23 | Scope.maxNewElements(scope,0); |
80 | PartialComplexTypeInterpretation.interpretationOf(typeInterpretation,type); | 24 | PartialComplexTypeInterpretation.interpretationOf(typeInterpretation,type); |
81 | Type.name(type,"«type.name»"); | 25 | Type.name(type,"«type.name»"); |
82 | } | 26 | } |
83 | 27 | ||
84 | /** | 28 | /** |
85 | * An element may be an instance of type "«type.name»". | 29 | * An element may be an instance of type "«type.name»". |
86 | */ | 30 | */ |
87 | private pattern «patternName(type,Modality.MAY)»(problem:LogicProblem, interpretation:PartialInterpretation, element:DefinedElement) | 31 | private pattern «patternName(type,Modality.MAY)»(problem:LogicProblem, interpretation:PartialInterpretation, element:DefinedElement) |
88 | «IF inhibitorTypes !== null»{ | 32 | «IF inhibitorTypes !== null» |
89 | find interpretation(problem,interpretation); | 33 | { |
90 | PartialInterpretation.newElements(interpretation,element); | 34 | find interpretation(problem,interpretation); |
91 | «FOR inhibitorType : inhibitorTypes» | 35 | PartialInterpretation.newElements(interpretation,element); |
92 | neg «referInstanceOf(inhibitorType,Modality.MUST,"element")» | 36 | «FOR inhibitorType : inhibitorTypes» |
93 | «ENDFOR» | 37 | neg «referInstanceOf(inhibitorType,Modality.MUST,"element")» |
94 | neg find scopeDisallowsNew«base.canonizeName(type.name)»(problem, interpretation); | 38 | «ENDFOR» |
95 | neg find isPrimitive(element); | 39 | neg find scopeDisallowsNew«base.canonizeName(type.name)»(problem, interpretation); |
96 | } or { | 40 | neg find isPrimitive(element); |
97 | find interpretation(problem,interpretation); | 41 | } or { |
98 | PartialInterpretation.openWorldElements(interpretation,element); | 42 | find interpretation(problem,interpretation); |
99 | «FOR inhibitorType : inhibitorTypes» | 43 | PartialInterpretation.openWorldElements(interpretation,element); |
100 | neg «referInstanceOf(inhibitorType,Modality.MUST,"element")» | 44 | «FOR inhibitorType : inhibitorTypes» |
101 | «ENDFOR» | 45 | neg «referInstanceOf(inhibitorType,Modality.MUST,"element")» |
102 | neg find scopeDisallowsNew«base.canonizeName(type.name)»(problem, interpretation); | 46 | «ENDFOR» |
103 | neg find isPrimitive(element); | 47 | neg find scopeDisallowsNew«base.canonizeName(type.name)»(problem, interpretation); |
104 | } or | 48 | neg find isPrimitive(element); |
105 | «ENDIF» | 49 | } or |
106 | { «referInstanceOf(type,Modality.MUST,"element")» } | 50 | «ENDIF» |
51 | { «referInstanceOf(type,Modality.MUST,"element")» } | ||
107 | ''' | 52 | ''' |
108 | } | 53 | } |
109 | 54 | } | |
110 | public override referInstanceOf(Type type, Modality modality, String variableName) { | ||
111 | '''find «patternName(type,modality)»(problem,interpretation,«variableName»);''' | ||
112 | } | ||
113 | public override referInstanceOf(EClass type, Modality modality, String variableName) { | ||
114 | '''find «modality.toString.toLowerCase»InstanceOf«base.canonizeName('''«type.name» class''')»(problem,interpretation,«variableName»);''' | ||
115 | } | ||
116 | } \ No newline at end of file | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/TypeRefinementGenerator.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/TypeRefinementGenerator.xtend index 7e3fad91..4ef336ae 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/TypeRefinementGenerator.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/TypeRefinementGenerator.xtend | |||
@@ -25,69 +25,76 @@ class ObjectCreationPrecondition { | |||
25 | 25 | ||
26 | abstract class TypeRefinementGenerator { | 26 | abstract class TypeRefinementGenerator { |
27 | val protected PatternGenerator base; | 27 | val protected PatternGenerator base; |
28 | public new(PatternGenerator base) { | 28 | |
29 | new(PatternGenerator base) { | ||
29 | this.base = base | 30 | this.base = base |
30 | } | 31 | } |
31 | 32 | ||
32 | public def boolean requiresTypeAnalysis() | 33 | def boolean requiresTypeAnalysis() |
33 | public def CharSequence generateRefineObjectQueries(LogicProblem p, PartialInterpretation emptySolution, TypeAnalysisResult typeAnalysisResult) | 34 | |
34 | public def CharSequence generateRefineTypeQueries(LogicProblem p, PartialInterpretation emptySolution, TypeAnalysisResult typeAnalysisResult) | 35 | def CharSequence generateRefineObjectQueries(LogicProblem p, PartialInterpretation emptySolution, |
35 | public def Map<? extends Type, String> getRefineTypeQueryNames(LogicProblem p, PartialInterpretation emptySolution, TypeAnalysisResult typeAnalysisResult) | 36 | TypeAnalysisResult typeAnalysisResult) |
36 | 37 | ||
37 | public def getRefineObjectQueryNames(LogicProblem p, PartialInterpretation emptySolution, TypeAnalysisResult typeAnalysisResult) { | 38 | def CharSequence generateRefineTypeQueries(LogicProblem p, PartialInterpretation emptySolution, |
38 | val Map<ObjectCreationPrecondition,String> objectCreationQueries = new LinkedHashMap | 39 | TypeAnalysisResult typeAnalysisResult) |
40 | |||
41 | def Map<? extends Type, String> getRefineTypeQueryNames(LogicProblem p, PartialInterpretation emptySolution, | ||
42 | TypeAnalysisResult typeAnalysisResult) | ||
43 | |||
44 | def getRefineObjectQueryNames(LogicProblem p, PartialInterpretation emptySolution, | ||
45 | TypeAnalysisResult typeAnalysisResult) { | ||
46 | val Map<ObjectCreationPrecondition, String> objectCreationQueries = new LinkedHashMap | ||
39 | val containment = p.containmentHierarchies.head | 47 | val containment = p.containmentHierarchies.head |
40 | val inverseRelations = new HashMap | 48 | val inverseRelations = new HashMap |
41 | p.annotations.filter(InverseRelationAssertion).forEach[ | 49 | p.annotations.filter(InverseRelationAssertion).forEach [ |
42 | inverseRelations.put(it.inverseA,it.inverseB) | 50 | inverseRelations.put(it.inverseA, it.inverseB) |
43 | inverseRelations.put(it.inverseB,it.inverseA) | 51 | inverseRelations.put(it.inverseB, it.inverseA) |
44 | ] | 52 | ] |
45 | for(type: p.types.filter(TypeDeclaration).filter[!it.isAbstract]) { | 53 | for (type : p.types.filter(TypeDeclaration).filter[!it.isAbstract]) { |
46 | if(containment.typeInContainment(type)) { | 54 | if (containment.typeInContainment(type)) { |
47 | for(containmentRelation : containment.containmentRelations.filter[canBeContainedByRelation(it,type)]) { | 55 | for (containmentRelation : containment.containmentRelations. |
48 | if(inverseRelations.containsKey(containmentRelation)) { | 56 | filter[canBeContainedByRelation(it, type)]) { |
57 | if (inverseRelations.containsKey(containmentRelation)) { | ||
49 | objectCreationQueries.put( | 58 | objectCreationQueries.put( |
50 | new ObjectCreationPrecondition(containmentRelation,inverseRelations.get(containmentRelation),type), | 59 | new ObjectCreationPrecondition(containmentRelation, |
51 | this.patternName(containmentRelation,inverseRelations.get(containmentRelation),type)) | 60 | inverseRelations.get(containmentRelation), type), |
61 | this.patternName(containmentRelation, inverseRelations.get(containmentRelation), type)) | ||
52 | } else { | 62 | } else { |
53 | objectCreationQueries.put( | 63 | objectCreationQueries.put(new ObjectCreationPrecondition(containmentRelation, null, type), |
54 | new ObjectCreationPrecondition(containmentRelation,null,type), | 64 | patternName(containmentRelation, null, type)) |
55 | patternName(containmentRelation,null,type)) | ||
56 | } | 65 | } |
57 | } | 66 | } |
58 | objectCreationQueries.put( | 67 | objectCreationQueries.put(new ObjectCreationPrecondition(null, null, type), |
59 | new ObjectCreationPrecondition(null,null,type), | 68 | patternName(null, null, type)) |
60 | patternName(null,null,type)) | ||
61 | } else { | 69 | } else { |
62 | objectCreationQueries.put( | 70 | objectCreationQueries.put(new ObjectCreationPrecondition(null, null, type), |
63 | new ObjectCreationPrecondition(null,null,type), | 71 | this.patternName(null, null, type)) |
64 | this.patternName(null,null,type)) | ||
65 | } | 72 | } |
66 | } | 73 | } |
67 | return objectCreationQueries | 74 | return objectCreationQueries |
68 | } | 75 | } |
69 | 76 | ||
70 | protected def canBeContainedByRelation(Relation r, Type t) { | 77 | protected def canBeContainedByRelation(Relation r, Type t) { |
71 | if(r.parameters.size==2) { | 78 | if (r.parameters.size == 2) { |
72 | val param = r.parameters.get(1) | 79 | val param = r.parameters.get(1) |
73 | if(param instanceof ComplexTypeReference) { | 80 | if (param instanceof ComplexTypeReference) { |
74 | val allSuperTypes = t.transitiveClosureStar[it.supertypes] | 81 | val allSuperTypes = t.transitiveClosureStar[it.supertypes] |
75 | for(superType : allSuperTypes) { | 82 | for (superType : allSuperTypes) { |
76 | if(param.referred == superType) return true | 83 | if(param.referred == superType) return true |
77 | } | 84 | } |
78 | } | 85 | } |
79 | } | 86 | } |
80 | return false | 87 | return false |
81 | } | 88 | } |
82 | 89 | ||
83 | private def typeInContainment(ContainmentHierarchy hierarchy, Type type) { | 90 | private def typeInContainment(ContainmentHierarchy hierarchy, Type type) { |
84 | val allSuperTypes = type.transitiveClosureStar[it.supertypes] | 91 | val allSuperTypes = type.transitiveClosureStar[it.supertypes] |
85 | return allSuperTypes.exists[hierarchy.typesOrderedInHierarchy.contains(it)] | 92 | return allSuperTypes.exists[hierarchy.typesOrderedInHierarchy.contains(it)] |
86 | } | 93 | } |
87 | 94 | ||
88 | protected def String patternName(Relation containmentRelation, Relation inverseContainment, Type newType) { | 95 | protected def String patternName(Relation containmentRelation, Relation inverseContainment, Type newType) { |
89 | if(containmentRelation != null) { | 96 | if (containmentRelation !== null) { |
90 | if(inverseContainment != null) { | 97 | if (inverseContainment !== null) { |
91 | '''createObject_«base.canonizeName(newType.name)»_by_«base.canonizeName(containmentRelation.name)»_with_«base.canonizeName(inverseContainment.name)»''' | 98 | '''createObject_«base.canonizeName(newType.name)»_by_«base.canonizeName(containmentRelation.name)»_with_«base.canonizeName(inverseContainment.name)»''' |
92 | } else { | 99 | } else { |
93 | '''createObject_«base.canonizeName(newType.name)»_by_«base.canonizeName(containmentRelation.name)»''' | 100 | '''createObject_«base.canonizeName(newType.name)»_by_«base.canonizeName(containmentRelation.name)»''' |
@@ -96,4 +103,8 @@ abstract class TypeRefinementGenerator { | |||
96 | '''createObject_«base.canonizeName(newType.name)»''' | 103 | '''createObject_«base.canonizeName(newType.name)»''' |
97 | } | 104 | } |
98 | } | 105 | } |
99 | } \ No newline at end of file | 106 | |
107 | def hasElementInContainmentName() { | ||
108 | "hasElementInContainment" | ||
109 | } | ||
110 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/TypeRefinementWithPreliminaryTypeAnalysis.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/TypeRefinementWithPreliminaryTypeAnalysis.xtend index cbbbcb08..1a81695e 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/TypeRefinementWithPreliminaryTypeAnalysis.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/TypeRefinementWithPreliminaryTypeAnalysis.xtend | |||
@@ -10,7 +10,7 @@ import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.par | |||
10 | import java.util.HashMap | 10 | import java.util.HashMap |
11 | 11 | ||
12 | class TypeRefinementWithPreliminaryTypeAnalysis extends TypeRefinementGenerator{ | 12 | class TypeRefinementWithPreliminaryTypeAnalysis extends TypeRefinementGenerator{ |
13 | public new(PatternGenerator base) { | 13 | new(PatternGenerator base) { |
14 | super(base) | 14 | super(base) |
15 | } | 15 | } |
16 | override requiresTypeAnalysis() { true } | 16 | override requiresTypeAnalysis() { true } |
@@ -24,7 +24,7 @@ class TypeRefinementWithPreliminaryTypeAnalysis extends TypeRefinementGenerator{ | |||
24 | inverseRelations.put(it.inverseB,it.inverseA) | 24 | inverseRelations.put(it.inverseB,it.inverseA) |
25 | ] | 25 | ] |
26 | return ''' | 26 | return ''' |
27 | private pattern hasElementInContainment(problem:LogicProblem, interpretation:PartialInterpretation) | 27 | pattern «hasElementInContainmentName»(problem:LogicProblem, interpretation:PartialInterpretation) |
28 | «FOR type :containment.typesOrderedInHierarchy SEPARATOR "or"»{ | 28 | «FOR type :containment.typesOrderedInHierarchy SEPARATOR "or"»{ |
29 | find interpretation(problem,interpretation); | 29 | find interpretation(problem,interpretation); |
30 | «base.typeIndexer.referInstanceOf(type,Modality.MUST,"root")» | 30 | «base.typeIndexer.referInstanceOf(type,Modality.MUST,"root")» |
@@ -76,7 +76,7 @@ class TypeRefinementWithPreliminaryTypeAnalysis extends TypeRefinementGenerator{ | |||
76 | typeInterpretation:PartialComplexTypeInterpretation) | 76 | typeInterpretation:PartialComplexTypeInterpretation) |
77 | { | 77 | { |
78 | find interpretation(problem,interpretation); | 78 | find interpretation(problem,interpretation); |
79 | neg find hasElementInContainment(problem,interpretation); | 79 | neg find «hasElementInContainmentName»(problem,interpretation); |
80 | PartialInterpretation.partialtypeinterpratation(interpretation,typeInterpretation); | 80 | PartialInterpretation.partialtypeinterpratation(interpretation,typeInterpretation); |
81 | PartialComplexTypeInterpretation.interpretationOf.name(typeInterpretation,"«type.name»"); | 81 | PartialComplexTypeInterpretation.interpretationOf.name(typeInterpretation,"«type.name»"); |
82 | «base.typeIndexer.referInstanceOf(type,Modality.MAY,"newObject")» | 82 | «base.typeIndexer.referInstanceOf(type,Modality.MAY,"newObject")» |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/UnfinishedIndexer.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/UnfinishedIndexer.xtend index ad1c9033..15b5a047 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/UnfinishedIndexer.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/UnfinishedIndexer.xtend | |||
@@ -1,85 +1,198 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns | 1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns |
2 | 2 | ||
3 | import hu.bme.mit.inf.dslreasoner.ecore2logic.ecore2logicannotations.LowerMultiplicityAssertion | ||
4 | import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem | 3 | import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem |
5 | import hu.bme.mit.inf.dslreasoner.viatra2logic.viatra2logicannotations.TransformedViatraWellformednessConstraint | 4 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.Modality |
5 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.RelationMultiplicityConstraint | ||
6 | import java.util.LinkedHashMap | ||
7 | import java.util.List | ||
6 | import java.util.Map | 8 | import java.util.Map |
7 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery | 9 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery |
10 | import org.eclipse.xtend.lib.annotations.Data | ||
8 | 11 | ||
9 | import static extension hu.bme.mit.inf.dslreasoner.util.CollectionsUtil.* | 12 | import static extension hu.bme.mit.inf.dslreasoner.util.CollectionsUtil.* |
10 | import java.util.LinkedHashMap | 13 | |
11 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.Modality | 14 | @Data |
12 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.ComplexTypeReference | 15 | class UnifinishedMultiplicityQueryNames { |
16 | val String unfinishedMultiplicityQueryName | ||
17 | val String unrepairableMultiplicityQueryName | ||
18 | val String remainingInverseMultiplicityQueryName | ||
19 | val String remainingContentsQueryName | ||
20 | } | ||
13 | 21 | ||
14 | class UnfinishedIndexer { | 22 | class UnfinishedIndexer { |
15 | val PatternGenerator base | 23 | val PatternGenerator base |
16 | 24 | val boolean indexUpperMultiplicities | |
17 | new(PatternGenerator patternGenerator) { | 25 | |
26 | new(PatternGenerator patternGenerator, boolean indexUpperMultiplicities) { | ||
18 | this.base = patternGenerator | 27 | this.base = patternGenerator |
28 | this.indexUpperMultiplicities = indexUpperMultiplicities | ||
19 | } | 29 | } |
20 | 30 | ||
21 | def generateUnfinishedWfQueries(LogicProblem problem, Map<String,PQuery> fqn2PQuery) { | 31 | def generateUnfinishedWfQueries(LogicProblem problem, Map<String, PQuery> fqn2PQuery) { |
22 | val wfQueries = base.wfQueries(problem) | 32 | val wfQueries = base.wfQueries(problem) |
23 | ''' | 33 | ''' |
24 | «FOR wfQuery: wfQueries» | 34 | «FOR wfQuery : wfQueries» |
25 | pattern unfinishedBy_«base.canonizeName(wfQuery.target.name)»(problem:LogicProblem, interpretation:PartialInterpretation, | 35 | pattern unfinishedBy_«base.canonizeName(wfQuery.target.name)»(problem:LogicProblem, interpretation:PartialInterpretation, |
26 | «FOR param : wfQuery.patternFullyQualifiedName.lookup(fqn2PQuery).parameters SEPARATOR ', '»var_«param.name»«ENDFOR») | 36 | «FOR param : wfQuery.patternFullyQualifiedName.lookup(fqn2PQuery).parameters SEPARATOR ', '»var_«param.name»«ENDFOR») |
27 | { | 37 | { |
28 | «base.relationDefinitionIndexer.referPattern( | 38 | «base.relationDefinitionIndexer.referPattern( |
29 | wfQuery.patternFullyQualifiedName.lookup(fqn2PQuery), | 39 | wfQuery.patternFullyQualifiedName.lookup(fqn2PQuery), |
30 | wfQuery.patternFullyQualifiedName.lookup(fqn2PQuery).parameters.map['''var_«it.name»'''], | 40 | wfQuery.patternFullyQualifiedName.lookup(fqn2PQuery).parameters.map['''var_«it.name»'''], |
31 | Modality.CURRENT, | 41 | Modality.CURRENT, |
32 | true,false)» | 42 | true,false)» |
33 | } | 43 | } |
34 | «ENDFOR» | 44 | «ENDFOR» |
35 | ''' | 45 | ''' |
36 | } | 46 | } |
47 | |||
37 | def getUnfinishedWFQueryNames(LogicProblem problem) { | 48 | def getUnfinishedWFQueryNames(LogicProblem problem) { |
38 | val wfQueries = base.wfQueries(problem) | 49 | val wfQueries = base.wfQueries(problem) |
39 | val map = new LinkedHashMap | 50 | val map = new LinkedHashMap |
40 | for(wfQuery : wfQueries) { | 51 | for (wfQuery : wfQueries) { |
41 | map.put(wfQuery.target,'''unfinishedBy_«base.canonizeName(wfQuery.target.name)»''') | 52 | map.put(wfQuery.target, '''unfinishedBy_«base.canonizeName(wfQuery.target.name)»''') |
42 | } | 53 | } |
43 | return map | 54 | return map |
44 | } | 55 | } |
45 | def generateUnfinishedMultiplicityQueries(LogicProblem problem, Map<String,PQuery> fqn2PQuery) { | 56 | |
46 | val lowerMultiplicities = base.lowerMultiplicities(problem) | 57 | def generateUnfinishedMultiplicityQueries(List<RelationMultiplicityConstraint> constraints, |
47 | return ''' | 58 | Map<String, PQuery> fqn2PQuery) ''' |
48 | «FOR lowerMultiplicity : lowerMultiplicities» | 59 | «FOR constraint : constraints» |
49 | pattern «unfinishedMultiplicityName(lowerMultiplicity)»(problem:LogicProblem, interpretation:PartialInterpretation, relationIterpretation:PartialRelationInterpretation, object:DefinedElement,missingMultiplicity) { | 60 | «IF constraint.constrainsUnfinished» |
50 | find interpretation(problem,interpretation); | 61 | private pattern «unfinishedMultiplicityName(constraint)»_helper(problem:LogicProblem, interpretation:PartialInterpretation, object:DefinedElement, missingMultiplicity:java Integer) { |
51 | PartialInterpretation.partialrelationinterpretation(interpretation,relationIterpretation); | 62 | find interpretation(problem,interpretation); |
52 | PartialRelationInterpretation.interpretationOf.name(relationIterpretation,"«lowerMultiplicity.relation.name»"); | 63 | find mustExist(problem,interpretation,object); |
53 | «base.typeIndexer.referInstanceOf(lowerMultiplicity.firstParamTypeOfRelation,Modality::MUST,"object")» | 64 | «base.typeIndexer.referInstanceOf(constraint.sourceType,Modality::MUST,"object")» |
54 | numberOfExistingReferences == count «base.referRelation(lowerMultiplicity.relation,"object","_",Modality.MUST,fqn2PQuery)» | 65 | numberOfExistingReferences == count «base.referRelation(constraint.relation,"object","_",Modality.MUST,fqn2PQuery)» |
55 | check(numberOfExistingReferences < «lowerMultiplicity.lower»); | 66 | check(numberOfExistingReferences < «constraint.lowerBound»); |
56 | missingMultiplicity == eval(«lowerMultiplicity.lower»-numberOfExistingReferences); | 67 | missingMultiplicity == eval(«constraint.lowerBound»-numberOfExistingReferences); |
57 | } | 68 | } |
69 | |||
70 | pattern «unfinishedMultiplicityName(constraint)»(problem:LogicProblem, interpretation:PartialInterpretation, missingMultiplicity:java Integer) { | ||
71 | find interpretation(problem,interpretation); | ||
72 | missingMultiplicity == sum find «unfinishedMultiplicityName(constraint)»_helper(problem, interpretation, _, #_); | ||
73 | } | ||
74 | «ENDIF» | ||
75 | |||
76 | «IF indexUpperMultiplicities» | ||
77 | «IF constraint.constrainsUnrepairable || constraint.constrainsRemainingInverse» | ||
78 | private pattern «repairMatchName(constraint)»(problem:LogicProblem, interpretation:PartialInterpretation, source:DefinedElement, target:DefinedElement) { | ||
79 | find interpretation(problem,interpretation); | ||
80 | find mustExist(problem,interpretation,source); | ||
81 | «base.typeIndexer.referInstanceOf(constraint.sourceType,Modality::MUST,"source")» | ||
82 | find mustExist(problem,interpretation,target); | ||
83 | «base.typeIndexer.referInstanceOf(constraint.targetType,Modality::MUST,"target")» | ||
84 | neg «base.referRelation(constraint.relation,"source","target",Modality.MUST,fqn2PQuery)» | ||
85 | «base.referRelation(constraint.relation,"source","target",Modality.MAY,fqn2PQuery)» | ||
86 | } | ||
87 | «ENDIF» | ||
88 | |||
89 | «IF constraint.constrainsUnrepairable» | ||
90 | private pattern «unrepairableMultiplicityName(constraint)»_helper(problem:LogicProblem, interpretation:PartialInterpretation, object:DefinedElement, unrepairableMultiplicity:java Integer) { | ||
91 | find interpretation(problem,interpretation); | ||
92 | find mustExist(problem,interpretation,object); | ||
93 | «base.typeIndexer.referInstanceOf(constraint.sourceType,Modality::MUST,"object")» | ||
94 | find «unfinishedMultiplicityName(constraint)»_helper(problem, interpretation, object, missingMultiplicity); | ||
95 | numberOfRepairMatches == count find «repairMatchName(constraint)»(problem, interpretation, object, _); | ||
96 | check(numberOfRepairMatches < missingMultiplicity); | ||
97 | unrepairableMultiplicity == eval(missingMultiplicity-numberOfRepairMatches); | ||
98 | } | ||
99 | |||
100 | private pattern «unrepairableMultiplicityName(constraint)»(problem:LogicProblem, interpretation:PartialInterpretation, unrepairableMultiplicity:java Integer) { | ||
101 | find interpretation(problem,interpretation); | ||
102 | unrepairableMultiplicity == max find «unrepairableMultiplicityName(constraint)»_helper(problem, interpretation, _, #_); | ||
103 | } or { | ||
104 | find interpretation(problem,interpretation); | ||
105 | neg find «unrepairableMultiplicityName(constraint)»_helper(problem, interpretation, _, _); | ||
106 | unrepairableMultiplicity == 0; | ||
107 | } | ||
108 | «ENDIF» | ||
109 | |||
110 | «IF constraint.constrainsRemainingInverse» | ||
111 | private pattern «remainingMultiplicityName(constraint)»_helper(problem:LogicProblem, interpretation:PartialInterpretation, object:DefinedElement, remainingMultiplicity:java Integer) { | ||
112 | find interpretation(problem,interpretation); | ||
113 | find mustExist(problem,interpretation,object); | ||
114 | «base.typeIndexer.referInstanceOf(constraint.targetType,Modality::MUST,"object")» | ||
115 | numberOfExistingReferences == count «base.referRelation(constraint.relation,"_","object",Modality.MUST,fqn2PQuery)» | ||
116 | check(numberOfExistingReferences < «constraint.inverseUpperBound»); | ||
117 | numberOfRepairMatches == count find «repairMatchName(constraint)»(problem, interpretation, _, object); | ||
118 | remainingMultiplicity == eval(Math.min(«constraint.inverseUpperBound»-numberOfExistingReferences, numberOfRepairMatches)); | ||
119 | } | ||
120 | |||
121 | pattern «remainingMultiplicityName(constraint)»(problem:LogicProblem, interpretation:PartialInterpretation, remainingMultiplicity:java Integer) { | ||
122 | find interpretation(problem,interpretation); | ||
123 | remainingMultiplicity == sum find «remainingMultiplicityName(constraint)»_helper(problem, interpretation, _, #_); | ||
124 | } | ||
125 | «ENDIF» | ||
126 | |||
127 | «IF constraint.constrainsRemainingContents» | ||
128 | «IF constraint.upperBoundFinite» | ||
129 | private pattern «remainingContentsName(constraint)»_helper(problem:LogicProblem, interpretation:PartialInterpretation, object:DefinedElement, remainingMultiplicity:java Integer) { | ||
130 | find interpretation(problem,interpretation); | ||
131 | find mustExist(problem,interpretation,object); | ||
132 | «base.typeIndexer.referInstanceOf(constraint.sourceType,Modality::MUST,"object")» | ||
133 | numberOfExistingReferences == count «base.referRelation(constraint.relation,"object","_",Modality.MUST,fqn2PQuery)» | ||
134 | check(numberOfExistingReferences < «constraint.upperBound»); | ||
135 | remainingMultiplicity == eval(«constraint.upperBound»-numberOfExistingReferences); | ||
136 | } | ||
137 | |||
138 | pattern «remainingContentsName(constraint)»(problem:LogicProblem, interpretation:PartialInterpretation, remainingMultiplicity:java Integer) { | ||
139 | find interpretation(problem,interpretation); | ||
140 | remainingMultiplicity == sum find «remainingContentsName(constraint)»_helper(problem, interpretation, _, #_); | ||
141 | } | ||
142 | «ELSE» | ||
143 | pattern «remainingContentsName(constraint)»_helper(problem:LogicProblem, interpretation:PartialInterpretation) { | ||
144 | find interpretation(problem,interpretation); | ||
145 | find mustExist(problem,interpretation,object); | ||
146 | «base.typeIndexer.referInstanceOf(constraint.sourceType,Modality::MUST,"object")» | ||
147 | } | ||
148 | |||
149 | pattern «remainingContentsName(constraint)»(problem:LogicProblem, interpretation:PartialInterpretation, remainingMultiplicity:java Integer) { | ||
150 | find interpretation(problem,interpretation); | ||
151 | find «remainingContentsName(constraint)»_helper(problem, interpretation); | ||
152 | remainingMultiplicity == -1; | ||
153 | } or { | ||
154 | find interpretation(problem,interpretation); | ||
155 | neg find «remainingContentsName(constraint)»_helper(problem, interpretation); | ||
156 | remainingMultiplicity == 0; | ||
157 | } | ||
158 | «ENDIF» | ||
159 | «ENDIF» | ||
160 | «ENDIF» | ||
58 | «ENDFOR» | 161 | «ENDFOR» |
59 | ''' | 162 | ''' |
60 | } | 163 | |
61 | def String unfinishedMultiplicityName(LowerMultiplicityAssertion lowerMultiplicityAssertion) | 164 | def String unfinishedMultiplicityName( |
62 | '''unfinishedLowerMultiplicity_«base.canonizeName(lowerMultiplicityAssertion.relation.name)»''' | 165 | RelationMultiplicityConstraint constraint) '''unfinishedLowerMultiplicity_«base.canonizeName(constraint.relation.name)»''' |
63 | 166 | ||
64 | def public referUnfinishedMultiplicityQuery(LowerMultiplicityAssertion lowerMultiplicityAssertion) | 167 | def String unrepairableMultiplicityName( |
65 | '''find «unfinishedMultiplicityName(lowerMultiplicityAssertion)»(problem, interpretation ,object, missingMultiplicity);''' | 168 | RelationMultiplicityConstraint constraint) '''unrepairableLowerMultiplicity_«base.canonizeName(constraint.relation.name)»''' |
66 | 169 | ||
67 | def getFirstParamTypeOfRelation(LowerMultiplicityAssertion lowerMultiplicityAssertion) { | 170 | private def String repairMatchName( |
68 | val parameters = lowerMultiplicityAssertion.relation.parameters | 171 | RelationMultiplicityConstraint constraint) '''repair_«base.canonizeName(constraint.relation.name)»''' |
69 | if(parameters.size == 2) { | 172 | |
70 | val firstParam = parameters.get(0) | 173 | def String remainingMultiplicityName( |
71 | if(firstParam instanceof ComplexTypeReference) { | 174 | RelationMultiplicityConstraint constraint) '''remainingInverseUpperMultiplicity_«base.canonizeName(constraint.relation.name)»''' |
72 | return firstParam.referred | 175 | |
73 | } | 176 | def String remainingContentsName( |
74 | } | 177 | RelationMultiplicityConstraint constraint) '''remainingContents_«base.canonizeName(constraint.relation.name)»''' |
75 | } | 178 | |
76 | 179 | def getUnfinishedMultiplicityQueries(List<RelationMultiplicityConstraint> constraints) { | |
77 | def getUnfinishedMultiplicityQueries(LogicProblem problem) { | 180 | constraints.toInvertedMap [ constraint | |
78 | val lowerMultiplicities = base.lowerMultiplicities(problem) | 181 | new UnifinishedMultiplicityQueryNames( |
79 | val map = new LinkedHashMap | 182 | if(constraint.constrainsUnfinished) unfinishedMultiplicityName(constraint) else null, |
80 | for(lowerMultiplicity : lowerMultiplicities) { | 183 | if (indexUpperMultiplicities && constraint.constrainsUnrepairable) |
81 | map.put(lowerMultiplicity.relation,unfinishedMultiplicityName(lowerMultiplicity)) | 184 | unrepairableMultiplicityName(constraint) |
82 | } | 185 | else |
83 | return map | 186 | null, |
187 | if (indexUpperMultiplicities && constraint.constrainsRemainingInverse) | ||
188 | remainingMultiplicityName(constraint) | ||
189 | else | ||
190 | null, | ||
191 | if (indexUpperMultiplicities && constraint.constrainsRemainingContents) | ||
192 | remainingContentsName(constraint) | ||
193 | else | ||
194 | null | ||
195 | ) | ||
196 | ] | ||
84 | } | 197 | } |
85 | } | 198 | } |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/rules/GoalConstraintProvider.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/rules/GoalConstraintProvider.xtend index e1be2742..b6fdbe06 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/rules/GoalConstraintProvider.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/rules/GoalConstraintProvider.xtend | |||
@@ -1,6 +1,6 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.rules | 1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.rules |
2 | 2 | ||
3 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.MultiplicityGoalConstraintCalculator | 3 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.MultiplicityGoalConstraintCalculator |
4 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns.GeneratedPatterns | 4 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns.GeneratedPatterns |
5 | import java.util.ArrayList | 5 | import java.util.ArrayList |
6 | 6 | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/rules/RefinementRuleProvider.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/rules/RefinementRuleProvider.xtend index 20d24b77..bf816de9 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/rules/RefinementRuleProvider.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/rules/RefinementRuleProvider.xtend | |||
@@ -6,7 +6,7 @@ import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Relation | |||
6 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RelationDeclaration | 6 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RelationDeclaration |
7 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Type | 7 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Type |
8 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.ModelGenerationStatistics | 8 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.ModelGenerationStatistics |
9 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.ScopePropagator | 9 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.ScopePropagator |
10 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns.GeneratedPatterns | 10 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns.GeneratedPatterns |
11 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns.ObjectCreationPrecondition | 11 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns.ObjectCreationPrecondition |
12 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialComplexTypeInterpretation | 12 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialComplexTypeInterpretation |
@@ -98,10 +98,12 @@ class RefinementRuleProvider { | |||
98 | val newLink2 = factory2.createBinaryElementRelationLink => [it.param1 = newElement it.param2 = container] | 98 | val newLink2 = factory2.createBinaryElementRelationLink => [it.param1 = newElement it.param2 = container] |
99 | inverseRelationInterpretation.relationlinks+=newLink2 | 99 | inverseRelationInterpretation.relationlinks+=newLink2 |
100 | 100 | ||
101 | val propagatorStartTime = System.nanoTime | ||
102 | statistics.addExecutionTime(propagatorStartTime-startTime) | ||
103 | |||
101 | // Scope propagation | 104 | // Scope propagation |
102 | scopePropagator.propagateAdditionToType(typeInterpretation) | 105 | scopePropagator.propagateAdditionToType(typeInterpretation) |
103 | 106 | statistics.addScopePropagationTime(System.nanoTime-propagatorStartTime) | |
104 | statistics.addExecutionTime(System.nanoTime-startTime) | ||
105 | ] | 107 | ] |
106 | } else { | 108 | } else { |
107 | ruleBuilder.action[match | | 109 | ruleBuilder.action[match | |
@@ -132,10 +134,12 @@ class RefinementRuleProvider { | |||
132 | val newLink = factory2.createBinaryElementRelationLink => [it.param1 = container it.param2 = newElement] | 134 | val newLink = factory2.createBinaryElementRelationLink => [it.param1 = container it.param2 = newElement] |
133 | relationInterpretation.relationlinks+=newLink | 135 | relationInterpretation.relationlinks+=newLink |
134 | 136 | ||
137 | val propagatorStartTime = System.nanoTime | ||
138 | statistics.addExecutionTime(propagatorStartTime-startTime) | ||
139 | |||
135 | // Scope propagation | 140 | // Scope propagation |
136 | scopePropagator.propagateAdditionToType(typeInterpretation) | 141 | scopePropagator.propagateAdditionToType(typeInterpretation) |
137 | 142 | statistics.addScopePropagationTime(System.nanoTime-propagatorStartTime) | |
138 | statistics.addExecutionTime(System.nanoTime-startTime) | ||
139 | ] | 143 | ] |
140 | } | 144 | } |
141 | } else { | 145 | } else { |
@@ -162,29 +166,31 @@ class RefinementRuleProvider { | |||
162 | typeInterpretation.elements += newElement | 166 | typeInterpretation.elements += newElement |
163 | typeInterpretation.supertypeInterpretation.forEach[it.elements += newElement] | 167 | typeInterpretation.supertypeInterpretation.forEach[it.elements += newElement] |
164 | 168 | ||
169 | val propagatorStartTime = System.nanoTime | ||
170 | statistics.addExecutionTime(propagatorStartTime-startTime) | ||
171 | |||
165 | // Scope propagation | 172 | // Scope propagation |
166 | scopePropagator.propagateAdditionToType(typeInterpretation) | 173 | scopePropagator.propagateAdditionToType(typeInterpretation) |
167 | 174 | statistics.addScopePropagationTime(System.nanoTime-propagatorStartTime) | |
168 | statistics.addExecutionTime(System.nanoTime-startTime) | ||
169 | ] | 175 | ] |
170 | } | 176 | } |
171 | return ruleBuilder.build | 177 | return ruleBuilder.build |
172 | } | 178 | } |
173 | 179 | ||
174 | def createRelationRefinementRules(GeneratedPatterns patterns, ModelGenerationStatistics statistics) { | 180 | def createRelationRefinementRules(GeneratedPatterns patterns, ScopePropagator scopePropagator, ModelGenerationStatistics statistics) { |
175 | val res = new LinkedHashMap | 181 | val res = new LinkedHashMap |
176 | for(LHSEntry: patterns.refinerelationQueries.entrySet) { | 182 | for(LHSEntry: patterns.refinerelationQueries.entrySet) { |
177 | val declaration = LHSEntry.key.key | 183 | val declaration = LHSEntry.key.key |
178 | val inverseReference = LHSEntry.key.value | 184 | val inverseReference = LHSEntry.key.value |
179 | val lhs = LHSEntry.value as IQuerySpecification<ViatraQueryMatcher<GenericPatternMatch>> | 185 | val lhs = LHSEntry.value as IQuerySpecification<ViatraQueryMatcher<GenericPatternMatch>> |
180 | val rule = createRelationRefinementRule(declaration,inverseReference,lhs,statistics) | 186 | val rule = createRelationRefinementRule(declaration,inverseReference,lhs,scopePropagator,statistics) |
181 | res.put(LHSEntry.key,rule) | 187 | res.put(LHSEntry.key,rule) |
182 | } | 188 | } |
183 | return res | 189 | return res |
184 | } | 190 | } |
185 | 191 | ||
186 | def private BatchTransformationRule<GenericPatternMatch, ViatraQueryMatcher<GenericPatternMatch>> | 192 | def private BatchTransformationRule<GenericPatternMatch, ViatraQueryMatcher<GenericPatternMatch>> |
187 | createRelationRefinementRule(RelationDeclaration declaration, Relation inverseRelation, IQuerySpecification<ViatraQueryMatcher<GenericPatternMatch>> lhs, ModelGenerationStatistics statistics) | 193 | createRelationRefinementRule(RelationDeclaration declaration, Relation inverseRelation, IQuerySpecification<ViatraQueryMatcher<GenericPatternMatch>> lhs, ScopePropagator scopePropagator, ModelGenerationStatistics statistics) |
188 | { | 194 | { |
189 | val name = '''addRelation_«declaration.name.canonizeName»«IF inverseRelation != null»_and_«inverseRelation.name.canonizeName»«ENDIF»''' | 195 | val name = '''addRelation_«declaration.name.canonizeName»«IF inverseRelation != null»_and_«inverseRelation.name.canonizeName»«ENDIF»''' |
190 | val ruleBuilder = factory.createRule | 196 | val ruleBuilder = factory.createRule |
@@ -201,7 +207,13 @@ class RefinementRuleProvider { | |||
201 | val trg = match.get(4) as DefinedElement | 207 | val trg = match.get(4) as DefinedElement |
202 | val link = createBinaryElementRelationLink => [it.param1 = src it.param2 = trg] | 208 | val link = createBinaryElementRelationLink => [it.param1 = src it.param2 = trg] |
203 | relationInterpretation.relationlinks += link | 209 | relationInterpretation.relationlinks += link |
204 | statistics.addExecutionTime(System.nanoTime-startTime) | 210 | |
211 | val propagatorStartTime = System.nanoTime | ||
212 | statistics.addExecutionTime(propagatorStartTime-startTime) | ||
213 | |||
214 | // Scope propagation | ||
215 | scopePropagator.propagateAdditionToRelation(declaration) | ||
216 | statistics.addScopePropagationTime(System.nanoTime-propagatorStartTime) | ||
205 | ] | 217 | ] |
206 | } else { | 218 | } else { |
207 | ruleBuilder.action [ match | | 219 | ruleBuilder.action [ match | |
@@ -217,7 +229,13 @@ class RefinementRuleProvider { | |||
217 | relationInterpretation.relationlinks += link | 229 | relationInterpretation.relationlinks += link |
218 | val inverseLink = createBinaryElementRelationLink => [it.param1 = trg it.param2 = src] | 230 | val inverseLink = createBinaryElementRelationLink => [it.param1 = trg it.param2 = src] |
219 | inverseInterpretation.relationlinks += inverseLink | 231 | inverseInterpretation.relationlinks += inverseLink |
220 | statistics.addExecutionTime(System.nanoTime-startTime) | 232 | |
233 | val propagatorStartTime = System.nanoTime | ||
234 | statistics.addExecutionTime(propagatorStartTime-startTime) | ||
235 | |||
236 | // Scope propagation | ||
237 | scopePropagator.propagateAdditionToRelation(declaration) | ||
238 | statistics.addScopePropagationTime(System.nanoTime-propagatorStartTime) | ||
221 | ] | 239 | ] |
222 | } | 240 | } |
223 | 241 | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/neighbourhood/Descriptor.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/neighbourhood/Descriptor.xtend index 41482b28..c7c1ad77 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/neighbourhood/Descriptor.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/neighbourhood/Descriptor.xtend | |||
@@ -4,10 +4,21 @@ import java.util.HashMap | |||
4 | import java.util.Map | 4 | import java.util.Map |
5 | import java.util.Set | 5 | import java.util.Set |
6 | import org.eclipse.xtend.lib.annotations.Data | 6 | import org.eclipse.xtend.lib.annotations.Data |
7 | import org.eclipse.xtend2.lib.StringConcatenationClient | ||
7 | 8 | ||
8 | @Data abstract class AbstractNodeDescriptor { | 9 | @Data abstract class AbstractNodeDescriptor { |
9 | long dataHash | 10 | long dataHash |
10 | 11 | ||
12 | protected def StringConcatenationClient prettyPrint() { | ||
13 | '''(«dataHash»)[«class.simpleName»]''' | ||
14 | } | ||
15 | |||
16 | override toString() { | ||
17 | ''' | ||
18 | «prettyPrint» | ||
19 | ''' | ||
20 | } | ||
21 | |||
11 | // @Pure | 22 | // @Pure |
12 | // @Override | 23 | // @Override |
13 | // override public boolean equals(Object obj) { | 24 | // override public boolean equals(Object obj) { |
@@ -24,34 +35,41 @@ import org.eclipse.xtend.lib.annotations.Data | |||
24 | // } | 35 | // } |
25 | } | 36 | } |
26 | 37 | ||
27 | @Data class LocalNodeDescriptor extends AbstractNodeDescriptor{ | 38 | @Data class LocalNodeDescriptor extends AbstractNodeDescriptor { |
28 | Set<String> types | 39 | Set<String> types |
29 | String id; | 40 | String id; |
41 | |||
30 | new(String id, Set<String> types) { | 42 | new(String id, Set<String> types) { |
31 | super(calcualteDataHash(id,types)) | 43 | super(calcualteDataHash(id, types)) |
32 | this.types = types | 44 | this.types = types |
33 | this.id = id | 45 | this.id = id |
34 | } | 46 | } |
35 | 47 | ||
36 | def private static calcualteDataHash(String id, Set<String> types) { | 48 | def private static calcualteDataHash(String id, Set<String> types) { |
37 | val int prime = 31; | 49 | val int prime = 31; |
38 | var result = 0 | 50 | var result = 0 |
39 | if(id !== null) | 51 | if (id !== null) |
40 | result = id.hashCode(); | 52 | result = id.hashCode(); |
41 | if(types !== null) { | 53 | if (types !== null) { |
42 | result = prime * result + types.hashCode | 54 | result = prime * result + types.hashCode |
43 | } | 55 | } |
44 | return result | 56 | return result |
45 | } | 57 | } |
46 | 58 | ||
47 | override hashCode() { | 59 | override hashCode() { |
48 | return this.dataHash.hashCode | 60 | return this.dataHash.hashCode |
49 | } | 61 | } |
50 | 62 | ||
63 | override protected prettyPrint() { | ||
64 | '''(«dataHash»)[«IF id !== null»id = "«id»"«IF types === null || !types.empty», «ENDIF»«ENDIF»«IF types === null»TYPES = null«ELSE»«FOR type : types SEPARATOR ", "»«type»«ENDFOR»«ENDIF»]''' | ||
65 | } | ||
66 | |||
51 | override toString() { | 67 | override toString() { |
52 | return class.name + this.dataHash | 68 | ''' |
69 | «prettyPrint» | ||
70 | ''' | ||
53 | } | 71 | } |
54 | 72 | ||
55 | // @Pure | 73 | // @Pure |
56 | // @Override | 74 | // @Override |
57 | // override public boolean equals(Object obj) { | 75 | // override public boolean equals(Object obj) { |
@@ -66,7 +84,6 @@ import org.eclipse.xtend.lib.annotations.Data | |||
66 | // return false; | 84 | // return false; |
67 | // return true; | 85 | // return true; |
68 | // } | 86 | // } |
69 | |||
70 | // @Pure | 87 | // @Pure |
71 | // override public boolean equals(Object obj) { | 88 | // override public boolean equals(Object obj) { |
72 | // if (this === obj) | 89 | // if (this === obj) |
@@ -97,49 +114,70 @@ import org.eclipse.xtend.lib.annotations.Data | |||
97 | String type | 114 | String type |
98 | } | 115 | } |
99 | 116 | ||
100 | @Data class FurtherNodeDescriptor<NodeRep> extends AbstractNodeDescriptor{ | 117 | @Data class FurtherNodeDescriptor<NodeRep> extends AbstractNodeDescriptor { |
101 | 118 | ||
102 | NodeRep previousRepresentation | 119 | NodeRep previousRepresentation |
103 | Map<IncomingRelation<NodeRep>,Integer> incomingEdges | 120 | Map<IncomingRelation<NodeRep>, Integer> incomingEdges |
104 | Map<OutgoingRelation<NodeRep>,Integer> outgoingEdges | 121 | Map<OutgoingRelation<NodeRep>, Integer> outgoingEdges |
105 | 122 | ||
106 | new( | 123 | new(NodeRep previousRepresentation, Map<IncomingRelation<NodeRep>, Integer> incomingEdges, |
107 | NodeRep previousRepresentation, | 124 | Map<OutgoingRelation<NodeRep>, Integer> outgoingEdges) { |
108 | Map<IncomingRelation<NodeRep>,Integer> incomingEdges, | 125 | super(calculateDataHash(previousRepresentation, incomingEdges, outgoingEdges)) |
109 | Map<OutgoingRelation<NodeRep>,Integer> outgoingEdges) | 126 | this.previousRepresentation = previousRepresentation |
110 | { | 127 | this.incomingEdges = new HashMap(incomingEdges) |
111 | super(calculateDataHash(previousRepresentation,incomingEdges,outgoingEdges)) | 128 | this.outgoingEdges = new HashMap(outgoingEdges) |
112 | this.previousRepresentation = previousRepresentation | ||
113 | this.incomingEdges = new HashMap(incomingEdges) | ||
114 | this.outgoingEdges = new HashMap(outgoingEdges) | ||
115 | } | ||
116 | |||
117 | static def private <NodeRep> int calculateDataHash( | ||
118 | NodeRep previousRepresentation, | ||
119 | Map<IncomingRelation<NodeRep>,Integer> incomingEdges, | ||
120 | Map<OutgoingRelation<NodeRep>,Integer> outgoingEdges) | ||
121 | { | ||
122 | val int prime = 31; | ||
123 | var int result = previousRepresentation.hashCode; | ||
124 | if(incomingEdges !== null) | ||
125 | result = prime * result + incomingEdges.hashCode(); | ||
126 | if(outgoingEdges !== null) | ||
127 | result = prime * result + outgoingEdges.hashCode(); | ||
128 | return result; | ||
129 | } | ||
130 | |||
131 | override hashCode() { | ||
132 | return this.dataHash.hashCode | ||
133 | } | 129 | } |
134 | 130 | ||
131 | static def private <NodeRep> int calculateDataHash(NodeRep previousRepresentation, | ||
132 | Map<IncomingRelation<NodeRep>, Integer> incomingEdges, Map<OutgoingRelation<NodeRep>, Integer> outgoingEdges) { | ||
133 | val int prime = 31; | ||
134 | var int result = previousRepresentation.hashCode; | ||
135 | if (incomingEdges !== null) | ||
136 | result = prime * result + incomingEdges.hashCode(); | ||
137 | if (outgoingEdges !== null) | ||
138 | result = prime * result + outgoingEdges.hashCode(); | ||
139 | return result; | ||
140 | } | ||
141 | |||
142 | override hashCode() { | ||
143 | return this.dataHash.hashCode | ||
144 | } | ||
145 | |||
146 | override prettyPrint() { | ||
147 | ''' | ||
148 | («dataHash»)[ | ||
149 | PREV = «previousRepresentation?.prettyPrint» | ||
150 | «IF incomingEdges === null» | ||
151 | IN null | ||
152 | «ELSE» | ||
153 | «FOR edge : incomingEdges.entrySet» | ||
154 | IN «edge.value» «edge.key.type» = «edge.key.from.prettyPrint» | ||
155 | «ENDFOR» | ||
156 | «ENDIF» | ||
157 | «IF outgoingEdges === null» | ||
158 | OUT null | ||
159 | «ELSE» | ||
160 | «FOR edge : outgoingEdges.entrySet» | ||
161 | OUT «edge.value» «edge.key.type» = «edge.key.to.prettyPrint» | ||
162 | «ENDFOR» | ||
163 | «ENDIF» | ||
164 | ]''' | ||
165 | } | ||
166 | |||
167 | private def StringConcatenationClient prettyPrint(NodeRep rep) { | ||
168 | if (rep instanceof AbstractNodeDescriptor) { | ||
169 | rep.prettyPrint | ||
170 | } else { | ||
171 | '''«rep»''' | ||
172 | } | ||
173 | } | ||
174 | |||
135 | override toString() { | 175 | override toString() { |
136 | return class.name + dataHash | 176 | ''' |
137 | // return '''[«previousRepresentation»,(«FOR | 177 | «prettyPrint» |
138 | // in: incomingEdges.entrySet»(«in.key.type.name»=«in.key.from»,«in.value»)«ENDFOR»),(«FOR | 178 | ''' |
139 | // out: outgoingEdges.entrySet»(«out.key.type.name»=«out.key.to»,«out.value»)«ENDFOR»),«FOR | ||
140 | // att: attributeValues»(«att.type.name»=«att.value»)«ENDFOR»]''' | ||
141 | } | 179 | } |
142 | 180 | ||
143 | // @Pure | 181 | // @Pure |
144 | // @Override | 182 | // @Override |
145 | // override public boolean equals(Object obj) { | 183 | // override public boolean equals(Object obj) { |
@@ -154,7 +192,6 @@ import org.eclipse.xtend.lib.annotations.Data | |||
154 | // return false; | 192 | // return false; |
155 | // return true; | 193 | // return true; |
156 | // } | 194 | // } |
157 | |||
158 | // @Pure | 195 | // @Pure |
159 | // override public boolean equals(Object obj) { | 196 | // override public boolean equals(Object obj) { |
160 | // if (this === obj) | 197 | // if (this === obj) |
@@ -191,24 +228,23 @@ import org.eclipse.xtend.lib.annotations.Data | |||
191 | // return true; | 228 | // return true; |
192 | // } | 229 | // } |
193 | } | 230 | } |
194 | |||
195 | /* | 231 | /* |
196 | @Data | 232 | * @Data |
197 | class ModelDescriptor { | 233 | * class ModelDescriptor { |
198 | int dataHash | 234 | * int dataHash |
199 | int unknownElements | 235 | * int unknownElements |
200 | Map<? extends AbstractNodeDescriptor,Integer> knownElements | 236 | * Map<? extends AbstractNodeDescriptor,Integer> knownElements |
201 | 237 | * | |
202 | public new(Map<? extends AbstractNodeDescriptor,Integer> knownElements, int unknownElements) { | 238 | * public new(Map<? extends AbstractNodeDescriptor,Integer> knownElements, int unknownElements) { |
203 | this.dataHash = calculateDataHash(knownElements,unknownElements) | 239 | * this.dataHash = calculateDataHash(knownElements,unknownElements) |
204 | this.unknownElements = unknownElements | 240 | * this.unknownElements = unknownElements |
205 | this.knownElements = knownElements | 241 | * this.knownElements = knownElements |
206 | } | 242 | * } |
207 | 243 | * | |
208 | def private static calculateDataHash(Map<? extends AbstractNodeDescriptor,Integer> knownElements, int unknownElements) | 244 | * def private static calculateDataHash(Map<? extends AbstractNodeDescriptor,Integer> knownElements, int unknownElements) |
209 | { | 245 | * { |
210 | val int prime = 31; | 246 | * val int prime = 31; |
211 | return knownElements.hashCode * prime + unknownElements.hashCode | 247 | * return knownElements.hashCode * prime + unknownElements.hashCode |
212 | } | 248 | * } |
213 | } | 249 | * } |
214 | */ \ No newline at end of file | 250 | */ |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/neighbourhood/NeighbourhoodOptions.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/neighbourhood/NeighbourhoodOptions.xtend new file mode 100644 index 00000000..efc89803 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/neighbourhood/NeighbourhoodOptions.xtend | |||
@@ -0,0 +1,22 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.neighbourhood | ||
2 | |||
3 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RelationDeclaration | ||
4 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.TypeDeclaration | ||
5 | import java.util.Set | ||
6 | import org.eclipse.xtend.lib.annotations.Data | ||
7 | |||
8 | @Data | ||
9 | class NeighbourhoodOptions { | ||
10 | public static val FixPointRage = -1 | ||
11 | public static val GraphWidthRange = -2 | ||
12 | public static val FullParallels = Integer.MAX_VALUE | ||
13 | public static val MaxNumbers = Integer.MAX_VALUE | ||
14 | |||
15 | public static val DEFAULT = new NeighbourhoodOptions(GraphWidthRange, FullParallels, MaxNumbers, null, null) | ||
16 | |||
17 | val int range | ||
18 | val int parallels | ||
19 | val int maxNumber | ||
20 | val Set<TypeDeclaration> relevantTypes | ||
21 | val Set<RelationDeclaration> relevantRelations | ||
22 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/neighbourhood/PartialInterpretation2NeighbourhoodRepresentation.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/neighbourhood/PartialInterpretation2NeighbourhoodRepresentation.xtend index d1bf0348..a0382e8e 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/neighbourhood/PartialInterpretation2NeighbourhoodRepresentation.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/neighbourhood/PartialInterpretation2NeighbourhoodRepresentation.xtend | |||
@@ -4,32 +4,34 @@ import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.DefinedElement | |||
4 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RelationDeclaration | 4 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RelationDeclaration |
5 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.TypeDeclaration | 5 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.TypeDeclaration |
6 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.BinaryElementRelationLink | 6 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.BinaryElementRelationLink |
7 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialComplexTypeInterpretation | ||
7 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | 8 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation |
9 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialPrimitiveInterpretation | ||
10 | import java.util.ArrayList | ||
8 | import java.util.HashMap | 11 | import java.util.HashMap |
9 | import java.util.HashSet | 12 | import java.util.HashSet |
10 | import java.util.LinkedList | ||
11 | import java.util.List | 13 | import java.util.List |
12 | import java.util.Map | 14 | import java.util.Map |
13 | import java.util.Set | 15 | import java.util.Set |
14 | 16 | ||
15 | import static extension hu.bme.mit.inf.dslreasoner.util.CollectionsUtil.* | 17 | import static extension hu.bme.mit.inf.dslreasoner.util.CollectionsUtil.* |
16 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialPrimitiveInterpretation | ||
17 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialComplexTypeInterpretation | ||
18 | 18 | ||
19 | abstract class PartialInterpretation2NeighbourhoodRepresentation<ModelRepresentation,NodeRepresentation> { | 19 | abstract class PartialInterpretation2NeighbourhoodRepresentation<ModelRepresentation, NodeRepresentation> { |
20 | private val boolean deepRepresentation | 20 | val boolean deepRepresentation |
21 | private val boolean mergeSimilarNeighbourhood | 21 | val boolean mergeSimilarNeighbourhood |
22 | 22 | ||
23 | protected new(boolean deeprepresentation, boolean mergeSimilarNeighbourhood) { | 23 | protected new(boolean deeprepresentation, boolean mergeSimilarNeighbourhood) { |
24 | this.deepRepresentation = deeprepresentation | 24 | this.deepRepresentation = deeprepresentation |
25 | this.mergeSimilarNeighbourhood = mergeSimilarNeighbourhood | 25 | this.mergeSimilarNeighbourhood = mergeSimilarNeighbourhood |
26 | } | 26 | } |
27 | 27 | ||
28 | public static val FixPointRage = -1 | 28 | public static val FixPointRage = NeighbourhoodOptions.FixPointRage |
29 | public static val GraphWidthRange = -2 | 29 | public static val GraphWidthRange = NeighbourhoodOptions.GraphWidthRange |
30 | public static val FullParallels = Integer.MAX_VALUE | 30 | public static val FullParallels = NeighbourhoodOptions.FullParallels |
31 | public static val MaxNumbers = Integer.MAX_VALUE | 31 | public static val MaxNumbers = NeighbourhoodOptions.MaxNumbers |
32 | 32 | ||
33 | static val FOCUSED_ELEMENT_NAME = "<<THIS>>" | ||
34 | |||
33 | /** | 35 | /** |
34 | * Creates a neighbourhood representation with traces | 36 | * Creates a neighbourhood representation with traces |
35 | * @param model The model to be represented. | 37 | * @param model The model to be represented. |
@@ -37,10 +39,15 @@ abstract class PartialInterpretation2NeighbourhoodRepresentation<ModelRepresenta | |||
37 | * @param parallels The maximal number of parallel references to be differentiated. | 39 | * @param parallels The maximal number of parallel references to be differentiated. |
38 | * @param maxNumber The maximal number of elements in a equivalence class that chan be differentiated. | 40 | * @param maxNumber The maximal number of elements in a equivalence class that chan be differentiated. |
39 | */ | 41 | */ |
40 | def public createRepresentation(PartialInterpretation model, int range, int parallels, int maxNumber) { | 42 | def createRepresentation(PartialInterpretation model, int range, int parallels, int maxNumber) { |
41 | return createRepresentation(model,range,parallels,maxNumber,null,null) | 43 | return createRepresentation(model, range, parallels, maxNumber, null, null) |
44 | } | ||
45 | |||
46 | def createRepresentation(PartialInterpretation model, NeighbourhoodOptions options) { | ||
47 | createRepresentation(model, options.range, options.parallels, options.maxNumber, options.relevantTypes, | ||
48 | options.relevantRelations) | ||
42 | } | 49 | } |
43 | 50 | ||
44 | /** | 51 | /** |
45 | * Creates a neighbourhood representation with traces | 52 | * Creates a neighbourhood representation with traces |
46 | * @param model The model to be represented. | 53 | * @param model The model to be represented. |
@@ -48,45 +55,50 @@ abstract class PartialInterpretation2NeighbourhoodRepresentation<ModelRepresenta | |||
48 | * @param parallels The maximal number of parallel references to be differentiated. | 55 | * @param parallels The maximal number of parallel references to be differentiated. |
49 | * @param maxNumber The maximal number of elements in a equivalence class that chan be differentiated. | 56 | * @param maxNumber The maximal number of elements in a equivalence class that chan be differentiated. |
50 | */ | 57 | */ |
51 | def public createRepresentation( | 58 | def createRepresentation(PartialInterpretation model, int range, int parallels, int maxNumber, |
52 | PartialInterpretation model, | 59 | Set<TypeDeclaration> relevantTypes, Set<RelationDeclaration> relevantRelations) { |
53 | int range, int parallels, int maxNumber, | 60 | createRepresentationWithFocus(model, range, parallels, maxNumber, relevantTypes, relevantRelations, null) |
54 | Set<TypeDeclaration> relevantTypes, Set<RelationDeclaration> relevantRelations) | 61 | } |
55 | { | 62 | |
63 | def createRepresentationWithFocus(PartialInterpretation model, NeighbourhoodOptions options, | ||
64 | DefinedElement focusedElement) { | ||
65 | createRepresentationWithFocus(model, options.range, options.parallels, options.maxNumber, options.relevantTypes, | ||
66 | options.relevantRelations, focusedElement) | ||
67 | } | ||
68 | |||
69 | def createRepresentationWithFocus(PartialInterpretation model, int range, int parallels, int maxNumber, | ||
70 | Set<TypeDeclaration> relevantTypes, Set<RelationDeclaration> relevantRelations, DefinedElement focusedElement) { | ||
56 | val Map<DefinedElement, Set<String>> types = new HashMap | 71 | val Map<DefinedElement, Set<String>> types = new HashMap |
57 | fillTypes(model,types,relevantTypes) | 72 | fillTypes(model, types, relevantTypes) |
58 | val Map<DefinedElement, List<IncomingRelation<DefinedElement>>> IncomingRelations = new HashMap; | 73 | val Map<DefinedElement, List<IncomingRelation<DefinedElement>>> IncomingRelations = new HashMap; |
59 | val Map<DefinedElement, List<OutgoingRelation<DefinedElement>>> OutgoingRelations = new HashMap; | 74 | val Map<DefinedElement, List<OutgoingRelation<DefinedElement>>> OutgoingRelations = new HashMap; |
60 | fillReferences(model,IncomingRelations,OutgoingRelations,relevantRelations) | 75 | fillReferences(model, IncomingRelations, OutgoingRelations, relevantRelations) |
61 | 76 | ||
62 | val res = doRecursiveNeighbourCalculation(model,types,IncomingRelations,OutgoingRelations,range,parallels,maxNumber); | 77 | val res = doRecursiveNeighbourCalculation(model, types, IncomingRelations, OutgoingRelations, range, parallels, |
63 | 78 | maxNumber, focusedElement); | |
79 | |||
64 | return res; | 80 | return res; |
65 | } | 81 | } |
66 | 82 | ||
67 | def private isRelevant(TypeDeclaration t, Set<TypeDeclaration> relevantTypes) { | 83 | def private isRelevant(TypeDeclaration t, Set<TypeDeclaration> relevantTypes) { |
68 | if(relevantTypes === null) { | 84 | if (relevantTypes === null) { |
69 | return true | 85 | return true |
70 | } else { | 86 | } else { |
71 | return relevantTypes.contains(t) | 87 | return relevantTypes.contains(t) |
72 | } | 88 | } |
73 | } | 89 | } |
90 | |||
74 | def private isRelevant(RelationDeclaration r, Set<RelationDeclaration> relevantRelations) { | 91 | def private isRelevant(RelationDeclaration r, Set<RelationDeclaration> relevantRelations) { |
75 | if(relevantRelations === null) { | 92 | if (relevantRelations === null) { |
76 | return true | 93 | return true |
77 | } else { | 94 | } else { |
78 | return relevantRelations.contains(r) | 95 | return relevantRelations.contains(r) |
79 | } | 96 | } |
80 | } | 97 | } |
81 | /** | ||
82 | * Gets the largest | ||
83 | */ | ||
84 | /** | ||
85 | 98 | ||
99 | /** | ||
86 | * Gets the minimal neighbourhood size such that every reachable node appears in the shape of every other at least once. | 100 | * Gets the minimal neighbourhood size such that every reachable node appears in the shape of every other at least once. |
87 | |||
88 | */ | 101 | */ |
89 | |||
90 | def private getWidth(Map<DefinedElement, Set<String>> types, | 102 | def private getWidth(Map<DefinedElement, Set<String>> types, |
91 | Map<DefinedElement, List<IncomingRelation<DefinedElement>>> IncomingRelations, | 103 | Map<DefinedElement, List<IncomingRelation<DefinedElement>>> IncomingRelations, |
92 | Map<DefinedElement, List<OutgoingRelation<DefinedElement>>> OutgoingRelations) { | 104 | Map<DefinedElement, List<OutgoingRelation<DefinedElement>>> OutgoingRelations) { |
@@ -99,6 +111,7 @@ abstract class PartialInterpretation2NeighbourhoodRepresentation<ModelRepresenta | |||
99 | reachable.put(element, new HashSet) | 111 | reachable.put(element, new HashSet) |
100 | newReachable.put(element, set) | 112 | newReachable.put(element, set) |
101 | } | 113 | } |
114 | |||
102 | var int width = 0 | 115 | var int width = 0 |
103 | var boolean newAdded | 116 | var boolean newAdded |
104 | do { | 117 | do { |
@@ -122,7 +135,6 @@ abstract class PartialInterpretation2NeighbourhoodRepresentation<ModelRepresenta | |||
122 | } while (newAdded) | 135 | } while (newAdded) |
123 | return width | 136 | return width |
124 | } | 137 | } |
125 | |||
126 | /** | 138 | /** |
127 | * Creates a neighbourhood representation with traces | 139 | * Creates a neighbourhood representation with traces |
128 | * @param model The model to be represented. | 140 | * @param model The model to be represented. |
@@ -131,68 +143,71 @@ abstract class PartialInterpretation2NeighbourhoodRepresentation<ModelRepresenta | |||
131 | * @param range The range of the neighbourhood. | 143 | * @param range The range of the neighbourhood. |
132 | * @param parallels The maximal number of parallel references to be differentiated. | 144 | * @param parallels The maximal number of parallel references to be differentiated. |
133 | */ | 145 | */ |
134 | def private NeighbourhoodWithTraces<ModelRepresentation,NodeRepresentation> doRecursiveNeighbourCalculation( | 146 | def private NeighbourhoodWithTraces<ModelRepresentation, NodeRepresentation> doRecursiveNeighbourCalculation( |
135 | PartialInterpretation model, | 147 | PartialInterpretation model, Map<DefinedElement, Set<String>> types, |
136 | Map<DefinedElement, Set<String>> types, | ||
137 | Map<DefinedElement, List<IncomingRelation<DefinedElement>>> IncomingRelations, | 148 | Map<DefinedElement, List<IncomingRelation<DefinedElement>>> IncomingRelations, |
138 | Map<DefinedElement, List<OutgoingRelation<DefinedElement>>> OutgoingRelations, | 149 | Map<DefinedElement, List<OutgoingRelation<DefinedElement>>> OutgoingRelations, int range, int parallels, |
139 | int range, int parallels, int maxNumber) | 150 | int maxNumber, DefinedElement focusedElement) { |
140 | { | 151 | if (range == 0) { |
141 | if(range == 0){ | 152 | val r = calculateLocalNodeDescriptors(model, types, maxNumber, focusedElement) |
142 | val r = calculateLocalNodeDescriptors(model,types,maxNumber) | 153 | val res = this.createLocalRepresentation(r.value, r.key) |
143 | val res = this.createLocalRepresentation(r.value,r.key) | 154 | if (res.modelRepresentation === null) { |
144 | if(res.modelRepresentation === null) { | ||
145 | throw new IllegalArgumentException('''Model representation is null''') | 155 | throw new IllegalArgumentException('''Model representation is null''') |
146 | } else if(res.nodeRepresentations === null || res.nodeRepresentations.empty) { | 156 | } else if (res.nodeRepresentations === null || res.nodeRepresentations.empty) { |
147 | throw new IllegalArgumentException('''No node representation''') | 157 | throw new IllegalArgumentException('''No node representation''') |
148 | } else if(res.previousRepresentation !== null) { | 158 | } else if (res.previousRepresentation !== null) { |
149 | throw new IllegalArgumentException('''The previous representation of the first neighbourhood have to be null''') | 159 | throw new IllegalArgumentException('''The previous representation of the first neighbourhood have to be null''') |
150 | } else return res | 160 | } else |
151 | } else if(range > 0) { | 161 | return res |
152 | val previous = doRecursiveNeighbourCalculation(model,types,IncomingRelations,OutgoingRelations,range-1,parallels,maxNumber) | 162 | } else if (range > 0) { |
153 | val r = calculateFurtherNodeDescriptors(model,previous,IncomingRelations,OutgoingRelations,parallels,maxNumber) | 163 | val previous = doRecursiveNeighbourCalculation(model, types, IncomingRelations, OutgoingRelations, |
154 | //println('''Level «range» finished.''') | 164 | range - 1, parallels, maxNumber, focusedElement) |
155 | val res = createFurtherRepresentation(r.key,r.value,previous,deepRepresentation) | 165 | val r = calculateFurtherNodeDescriptors(model, previous, IncomingRelations, OutgoingRelations, parallels, |
156 | if(res.modelRepresentation === null) { | 166 | maxNumber) |
167 | // println('''Level «range» finished.''') | ||
168 | val res = createFurtherRepresentation(r.key, r.value, previous, deepRepresentation) | ||
169 | if (res.modelRepresentation === null) { | ||
157 | throw new IllegalArgumentException('''Model representation is null''') | 170 | throw new IllegalArgumentException('''Model representation is null''') |
158 | } else if(res.nodeRepresentations === null || res.nodeRepresentations.empty) { | 171 | } else if (res.nodeRepresentations === null || res.nodeRepresentations.empty) { |
159 | throw new IllegalArgumentException('''No node representation''') | 172 | throw new IllegalArgumentException('''No node representation''') |
160 | } else if(res.previousRepresentation === null && deepRepresentation) { | 173 | } else if (res.previousRepresentation === null && deepRepresentation) { |
161 | throw new IllegalArgumentException('''Need previous representations''') | 174 | throw new IllegalArgumentException('''Need previous representations''') |
162 | } else return res | 175 | } else |
176 | return res | ||
163 | } else if (range == FixPointRage) { | 177 | } else if (range == FixPointRage) { |
164 | return refineUntilFixpoint(model,types,IncomingRelations,OutgoingRelations,parallels,maxNumber) | 178 | return refineUntilFixpoint(model, types, IncomingRelations, OutgoingRelations, parallels, maxNumber, |
179 | focusedElement) | ||
165 | } else if (range == GraphWidthRange) { | 180 | } else if (range == GraphWidthRange) { |
166 | val width = this.getWidth(types,IncomingRelations,OutgoingRelations) | 181 | val width = this.getWidth(types, IncomingRelations, OutgoingRelations) |
167 | //println(width) | 182 | // println(width) |
168 | return doRecursiveNeighbourCalculation(model,types,IncomingRelations,OutgoingRelations,width,parallels,maxNumber) | 183 | return doRecursiveNeighbourCalculation(model, types, IncomingRelations, OutgoingRelations, width, parallels, |
184 | maxNumber, focusedElement) | ||
169 | } | 185 | } |
170 | } | 186 | } |
171 | 187 | ||
172 | def private refineUntilFixpoint( | 188 | def private refineUntilFixpoint(PartialInterpretation model, Map<DefinedElement, Set<String>> types, |
173 | PartialInterpretation model, | ||
174 | Map<DefinedElement, Set<String>> types, | ||
175 | Map<DefinedElement, List<IncomingRelation<DefinedElement>>> IncomingRelations, | 189 | Map<DefinedElement, List<IncomingRelation<DefinedElement>>> IncomingRelations, |
176 | Map<DefinedElement, List<OutgoingRelation<DefinedElement>>> OutgoingRelations, | 190 | Map<DefinedElement, List<OutgoingRelation<DefinedElement>>> OutgoingRelations, int parallels, int maxNumbers, |
177 | int parallels, int maxNumbers) | 191 | DefinedElement focusedElement) { |
178 | { | ||
179 | var lastRange = 0 | 192 | var lastRange = 0 |
180 | val last = calculateLocalNodeDescriptors(model,types,maxNumbers) | 193 | val last = calculateLocalNodeDescriptors(model, types, maxNumbers, focusedElement) |
181 | var lastRepresentation = this.createLocalRepresentation(last.value,last.key) | 194 | var lastRepresentation = this.createLocalRepresentation(last.value, last.key) |
182 | //println('''Level 0 finished.''') | 195 | // println('''Level 0 finished.''') |
183 | var boolean hasRefined | 196 | var boolean hasRefined |
184 | do { | 197 | do { |
185 | val nextRange = lastRange+1 | 198 | val nextRange = lastRange + 1 |
186 | val next = calculateFurtherNodeDescriptors(model,lastRepresentation,IncomingRelations,OutgoingRelations,parallels,maxNumbers) | 199 | val next = calculateFurtherNodeDescriptors(model, lastRepresentation, IncomingRelations, OutgoingRelations, |
187 | val nextRepresentation = createFurtherRepresentation(next.key,next.value,lastRepresentation,deepRepresentation) | 200 | parallels, maxNumbers) |
188 | 201 | val nextRepresentation = createFurtherRepresentation(next.key, next.value, lastRepresentation, | |
189 | val previousNumberOfTypes =lastRepresentation.nodeRepresentations.values.toSet.size | 202 | deepRepresentation) |
203 | |||
204 | val previousNumberOfTypes = lastRepresentation.nodeRepresentations.values.toSet.size | ||
190 | val nextNumberOfTypes = nextRepresentation.nodeRepresentations.values.toSet.size | 205 | val nextNumberOfTypes = nextRepresentation.nodeRepresentations.values.toSet.size |
191 | hasRefined = nextNumberOfTypes > previousNumberOfTypes | 206 | hasRefined = nextNumberOfTypes > previousNumberOfTypes |
192 | 207 | ||
193 | lastRange = nextRange | 208 | lastRange = nextRange |
194 | lastRepresentation = nextRepresentation | 209 | lastRepresentation = nextRepresentation |
195 | 210 | ||
196 | // if(hasRefined) { | 211 | // if(hasRefined) { |
197 | // println('''Level «nextRange» is calculated, number of types is refined: «previousNumberOfTypes» -> «nextNumberOfTypes»''') | 212 | // println('''Level «nextRange» is calculated, number of types is refined: «previousNumberOfTypes» -> «nextNumberOfTypes»''') |
198 | // } else { | 213 | // } else { |
@@ -201,211 +216,219 @@ abstract class PartialInterpretation2NeighbourhoodRepresentation<ModelRepresenta | |||
201 | } while (hasRefined) | 216 | } while (hasRefined) |
202 | return lastRepresentation | 217 | return lastRepresentation |
203 | } | 218 | } |
204 | 219 | ||
205 | def private getElements(PartialInterpretation model) { | 220 | def private getElements(PartialInterpretation model) { |
206 | return | 221 | return model.problem.elements + model.newElements + model.openWorldElements |
207 | model.problem.elements + | ||
208 | model.newElements + | ||
209 | model.openWorldElements | ||
210 | } | 222 | } |
211 | 223 | ||
212 | def private fillTypes(PartialInterpretation model, Map<DefinedElement, Set<String>> node2Type, Set<TypeDeclaration> relevantTypes) { | 224 | def private fillTypes(PartialInterpretation model, Map<DefinedElement, Set<String>> node2Type, |
213 | for(element : model.elements) { | 225 | Set<TypeDeclaration> relevantTypes) { |
226 | for (element : model.elements) { | ||
214 | node2Type.put(element, new HashSet) | 227 | node2Type.put(element, new HashSet) |
215 | } | 228 | } |
216 | 229 | ||
217 | // for(typeDefinition : model.problem.types.filter(TypeDefinition)) { | 230 | // for(typeDefinition : model.problem.types.filter(TypeDefinition)) { |
218 | // // Dont need | 231 | // // Dont need |
219 | // } | 232 | // } |
220 | for(typeInterpretation : model.partialtypeinterpratation) { | 233 | for (typeInterpretation : model.partialtypeinterpratation) { |
221 | if(typeInterpretation instanceof PartialPrimitiveInterpretation) { | 234 | if (typeInterpretation instanceof PartialPrimitiveInterpretation) { |
222 | 235 | } else if (typeInterpretation instanceof PartialComplexTypeInterpretation) { | |
223 | } else if(typeInterpretation instanceof PartialComplexTypeInterpretation) { | ||
224 | val type = typeInterpretation.interpretationOf | 236 | val type = typeInterpretation.interpretationOf |
225 | if(type.isRelevant(relevantTypes)) { | 237 | if (type.isRelevant(relevantTypes)) { |
226 | for(element : typeInterpretation.elements) { | 238 | for (element : typeInterpretation.elements) { |
227 | element.lookup(node2Type).add(type.name) | 239 | element.lookup(node2Type).add(type.name) |
228 | } | 240 | } |
229 | } | 241 | } |
230 | } | 242 | } |
231 | } | 243 | } |
232 | } | 244 | } |
233 | 245 | ||
234 | /** | 246 | /** |
235 | * Indexes the references | 247 | * Indexes the references |
236 | */ | 248 | */ |
237 | def private fillReferences(PartialInterpretation model, | 249 | def private fillReferences(PartialInterpretation model, |
238 | Map<DefinedElement, List<IncomingRelation<DefinedElement>>> IncomingRelations, | 250 | Map<DefinedElement, List<IncomingRelation<DefinedElement>>> IncomingRelations, |
239 | Map<DefinedElement, List<OutgoingRelation<DefinedElement>>> OutgoingRelations, | 251 | Map<DefinedElement, List<OutgoingRelation<DefinedElement>>> OutgoingRelations, |
240 | Set<RelationDeclaration> relevantRelations) | 252 | Set<RelationDeclaration> relevantRelations) { |
241 | { | 253 | for (object : model.elements) { |
242 | for(object : model.elements) { | 254 | IncomingRelations.put(object, new ArrayList) |
243 | IncomingRelations.put(object,new LinkedList) | 255 | OutgoingRelations.put(object, new ArrayList) |
244 | OutgoingRelations.put(object,new LinkedList) | ||
245 | } | 256 | } |
246 | for(relationInterpretation : model.partialrelationinterpretation) { | 257 | for (relationInterpretation : model.partialrelationinterpretation) { |
247 | val type = relationInterpretation.interpretationOf | 258 | val type = relationInterpretation.interpretationOf |
248 | if(type.isRelevant(relevantRelations)) { | 259 | if (type.isRelevant(relevantRelations)) { |
249 | for(link : relationInterpretation.relationlinks) { | 260 | for (link : relationInterpretation.relationlinks) { |
250 | if(link instanceof BinaryElementRelationLink) { | 261 | if (link instanceof BinaryElementRelationLink) { |
251 | OutgoingRelations.get(link.param1) += new OutgoingRelation(link.param2,type.name) | 262 | OutgoingRelations.get(link.param1) += new OutgoingRelation(link.param2, type.name) |
252 | IncomingRelations.get(link.param2) += new IncomingRelation(link.param1,type.name) | 263 | IncomingRelations.get(link.param2) += new IncomingRelation(link.param1, type.name) |
253 | } else throw new UnsupportedOperationException | 264 | } else |
265 | throw new UnsupportedOperationException | ||
254 | } | 266 | } |
255 | } | 267 | } |
256 | } | 268 | } |
257 | } | 269 | } |
258 | 270 | ||
259 | /** | 271 | /** |
260 | * Creates a local representation of the objects (aka zero range neighbourhood) | 272 | * Creates a local representation of the objects (aka zero range neighbourhood) |
261 | */ | 273 | */ |
262 | def abstract protected NeighbourhoodWithTraces<ModelRepresentation,NodeRepresentation> createLocalRepresentation( | 274 | def abstract protected NeighbourhoodWithTraces<ModelRepresentation, NodeRepresentation> createLocalRepresentation( |
263 | Map<DefinedElement, LocalNodeDescriptor> node2Representation, | 275 | Map<DefinedElement, LocalNodeDescriptor> node2Representation, |
264 | Map<LocalNodeDescriptor, Integer> representation2Amount | 276 | Map<LocalNodeDescriptor, Integer> representation2Amount |
265 | ) | 277 | ) |
266 | 278 | ||
267 | /** | 279 | /** |
268 | * Creates a | 280 | * Creates a |
269 | */ | 281 | */ |
270 | def abstract protected NeighbourhoodWithTraces<ModelRepresentation,NodeRepresentation> createFurtherRepresentation( | 282 | def abstract protected NeighbourhoodWithTraces<ModelRepresentation, NodeRepresentation> createFurtherRepresentation( |
271 | Map<FurtherNodeDescriptor<NodeRepresentation>, Integer> nodeDescriptors, | 283 | Map<FurtherNodeDescriptor<NodeRepresentation>, Integer> nodeDescriptors, |
272 | Map<DefinedElement, FurtherNodeDescriptor<NodeRepresentation>> node2Representation, | 284 | Map<DefinedElement, FurtherNodeDescriptor<NodeRepresentation>> node2Representation, |
273 | NeighbourhoodWithTraces<ModelRepresentation,NodeRepresentation> previous, | 285 | NeighbourhoodWithTraces<ModelRepresentation, NodeRepresentation> previous, |
274 | boolean deepRepresentation | 286 | boolean deepRepresentation |
275 | ) | 287 | ) |
276 | 288 | ||
277 | def private addOne(int original, int max) { | 289 | def private addOne(int original, int max) { |
278 | if(original == Integer.MAX_VALUE) return Integer.MAX_VALUE | 290 | if(original == Integer.MAX_VALUE) return Integer.MAX_VALUE |
279 | if(original +1 > max) return Integer.MAX_VALUE | 291 | if(original + 1 > max) return Integer.MAX_VALUE else return original + 1 |
280 | else return original+1 | ||
281 | } | 292 | } |
282 | 293 | ||
283 | private def calculateIncomingEdges(Map<DefinedElement, List<IncomingRelation<DefinedElement>>> IncomingRelations, | 294 | private def calculateIncomingEdges(Map<DefinedElement, List<IncomingRelation<DefinedElement>>> IncomingRelations, |
284 | DefinedElement object, Map<DefinedElement, ? extends NodeRepresentation> previousNodeRepresentations, int parallel) | 295 | DefinedElement object, Map<DefinedElement, ? extends NodeRepresentation> previousNodeRepresentations, |
285 | { | 296 | int parallel) { |
286 | val Map<IncomingRelation<NodeRepresentation>, Integer> res = new HashMap | 297 | val Map<IncomingRelation<NodeRepresentation>, Integer> res = new HashMap |
287 | for (incomingConcreteEdge : IncomingRelations.get(object)) { | 298 | for (incomingConcreteEdge : IncomingRelations.get(object)) { |
288 | val IncomingRelation<NodeRepresentation> e = new IncomingRelation( | 299 | val IncomingRelation<NodeRepresentation> e = new IncomingRelation( |
289 | previousNodeRepresentations.get(incomingConcreteEdge.from), incomingConcreteEdge.type) | 300 | previousNodeRepresentations.get(incomingConcreteEdge.from), incomingConcreteEdge.type) |
290 | if (res.containsKey(e)) { | 301 | if (res.containsKey(e)) { |
291 | res.put(e, addOne(res.get(e),parallel)) | 302 | res.put(e, addOne(res.get(e), parallel)) |
292 | } else { | 303 | } else { |
293 | res.put(e, 1) | 304 | res.put(e, 1) |
294 | } | 305 | } |
295 | } | 306 | } |
296 | return res | 307 | return res |
297 | } | 308 | } |
298 | 309 | ||
299 | private def calcuateOutgoingEdges(Map<DefinedElement,List<OutgoingRelation<DefinedElement>>> OutgoingRelations, | 310 | private def calcuateOutgoingEdges(Map<DefinedElement, List<OutgoingRelation<DefinedElement>>> OutgoingRelations, |
300 | DefinedElement object, Map<DefinedElement, ? extends NodeRepresentation> previousNodeRepresentations, int parallel) | 311 | DefinedElement object, Map<DefinedElement, ? extends NodeRepresentation> previousNodeRepresentations, |
301 | { | 312 | int parallel) { |
302 | val Map<OutgoingRelation<NodeRepresentation>,Integer> res= new HashMap | 313 | val Map<OutgoingRelation<NodeRepresentation>, Integer> res = new HashMap |
303 | for(outgoingConcreteEdge : OutgoingRelations.get(object)) { | 314 | for (outgoingConcreteEdge : OutgoingRelations.get(object)) { |
304 | val OutgoingRelation<NodeRepresentation> e = | 315 | val OutgoingRelation<NodeRepresentation> e = new OutgoingRelation( |
305 | new OutgoingRelation( | 316 | previousNodeRepresentations.get(outgoingConcreteEdge.to), outgoingConcreteEdge.type) |
306 | previousNodeRepresentations.get(outgoingConcreteEdge.to), | 317 | if (res.containsKey(e)) { |
307 | outgoingConcreteEdge.type) | 318 | res.put(e, addOne(res.get(e), parallel)) |
308 | if(res.containsKey(e)) { | ||
309 | res.put(e,addOne(res.get(e),parallel)) | ||
310 | } else { | 319 | } else { |
311 | res.put(e,1) | 320 | res.put(e, 1) |
312 | } | 321 | } |
313 | } | 322 | } |
314 | return res; | 323 | return res; |
315 | } | 324 | } |
316 | 325 | ||
317 | /*def private <KEY,VALUE> void addOrCreate_Set(Map<KEY,Set<VALUE>> map, KEY key, VALUE value) { | 326 | /*def private <KEY,VALUE> void addOrCreate_Set(Map<KEY,Set<VALUE>> map, KEY key, VALUE value) { |
318 | var Set<VALUE> s; | 327 | * var Set<VALUE> s; |
319 | if(map.containsKey(key)) { | 328 | * if(map.containsKey(key)) { |
320 | s = map.get(key); | 329 | * s = map.get(key); |
321 | } else { | 330 | * } else { |
322 | s = new HashSet | 331 | * s = new HashSet |
323 | map.put(key,s) | 332 | * map.put(key,s) |
324 | } | 333 | * } |
325 | s.add(value) | 334 | * s.add(value) |
326 | }*/ | 335 | }*/ |
327 | 336 | private def calculateFurtherNodeDescriptors(PartialInterpretation model, | |
328 | |||
329 | private def calculateFurtherNodeDescriptors( | ||
330 | PartialInterpretation model, | ||
331 | NeighbourhoodWithTraces<ModelRepresentation, NodeRepresentation> previous, | 337 | NeighbourhoodWithTraces<ModelRepresentation, NodeRepresentation> previous, |
332 | Map<DefinedElement, List<IncomingRelation<DefinedElement>>> IncomingRelations, | 338 | Map<DefinedElement, List<IncomingRelation<DefinedElement>>> IncomingRelations, |
333 | Map<DefinedElement, List<OutgoingRelation<DefinedElement>>> OutgoingRelations, | 339 | Map<DefinedElement, List<OutgoingRelation<DefinedElement>>> OutgoingRelations, int parallels, int maxNumber) { |
334 | int parallels, int maxNumber) | ||
335 | { | ||
336 | val previousNodeRepresentations = previous.nodeRepresentations | 340 | val previousNodeRepresentations = previous.nodeRepresentations |
337 | val node2Representation = new HashMap<DefinedElement,FurtherNodeDescriptor<NodeRepresentation>> | 341 | val node2Representation = new HashMap<DefinedElement, FurtherNodeDescriptor<NodeRepresentation>> |
338 | val Map<FurtherNodeDescriptor<NodeRepresentation>,Integer> descriptor2Number = | 342 | val Map<FurtherNodeDescriptor<NodeRepresentation>, Integer> descriptor2Number = if (this. |
339 | if(this.mergeSimilarNeighbourhood){ new HashMap } else { null } | 343 | mergeSimilarNeighbourhood) { |
340 | val Map<FurtherNodeDescriptor<NodeRepresentation>,FurtherNodeDescriptor<NodeRepresentation>> uniqueDescription = | 344 | new HashMap |
341 | if(this.mergeSimilarNeighbourhood){ new HashMap } else { null } | 345 | } else { |
342 | 346 | null | |
343 | for(object: model.elements) { | 347 | } |
344 | val incomingEdges = this.calculateIncomingEdges(IncomingRelations, object, previousNodeRepresentations,parallels) | 348 | val Map<FurtherNodeDescriptor<NodeRepresentation>, FurtherNodeDescriptor<NodeRepresentation>> uniqueDescription = if (this. |
345 | val outgoingEdges = this.calcuateOutgoingEdges(OutgoingRelations,object, previousNodeRepresentations,parallels) | 349 | mergeSimilarNeighbourhood) { |
346 | 350 | new HashMap | |
351 | } else { | ||
352 | null | ||
353 | } | ||
354 | |||
355 | for (object : model.elements) { | ||
356 | val incomingEdges = this.calculateIncomingEdges(IncomingRelations, object, previousNodeRepresentations, | ||
357 | parallels) | ||
358 | val outgoingEdges = this.calcuateOutgoingEdges(OutgoingRelations, object, previousNodeRepresentations, | ||
359 | parallels) | ||
360 | |||
347 | val previousType = previousNodeRepresentations.get(object) | 361 | val previousType = previousNodeRepresentations.get(object) |
348 | 362 | ||
349 | if(previousType === null) { | 363 | if (previousType === null) { |
350 | println("Error in state coder") | 364 | println("Error in state coder") |
351 | } | 365 | } |
352 | 366 | ||
353 | val nodeDescriptor = new FurtherNodeDescriptor( | 367 | val nodeDescriptor = new FurtherNodeDescriptor(previousType, incomingEdges, outgoingEdges) |
354 | previousType, | 368 | |
355 | incomingEdges, | 369 | if (this.mergeSimilarNeighbourhood) { |
356 | outgoingEdges) | 370 | if (descriptor2Number.containsKey(nodeDescriptor)) { |
357 | |||
358 | if(this.mergeSimilarNeighbourhood) { | ||
359 | if(descriptor2Number.containsKey(nodeDescriptor)) { | ||
360 | descriptor2Number.put( | 371 | descriptor2Number.put( |
361 | nodeDescriptor, | 372 | nodeDescriptor, |
362 | addOne(descriptor2Number.get(nodeDescriptor),maxNumber) | 373 | addOne(descriptor2Number.get(nodeDescriptor), maxNumber) |
363 | ) | 374 | ) |
364 | node2Representation.put(object,uniqueDescription.get(nodeDescriptor)) | 375 | node2Representation.put(object, uniqueDescription.get(nodeDescriptor)) |
365 | } else { | 376 | } else { |
366 | descriptor2Number.put(nodeDescriptor,if(1>maxNumber){Integer.MAX_VALUE}else{1}) | 377 | descriptor2Number.put(nodeDescriptor, if (1 > maxNumber) { |
367 | uniqueDescription.put(nodeDescriptor,nodeDescriptor) | 378 | Integer.MAX_VALUE |
368 | node2Representation.put(object,nodeDescriptor) | 379 | } else { |
380 | 1 | ||
381 | }) | ||
382 | uniqueDescription.put(nodeDescriptor, nodeDescriptor) | ||
383 | node2Representation.put(object, nodeDescriptor) | ||
369 | } | 384 | } |
370 | } else { | 385 | } else { |
371 | node2Representation.put(object,nodeDescriptor) | 386 | node2Representation.put(object, nodeDescriptor) |
372 | } | 387 | } |
373 | } | 388 | } |
374 | 389 | ||
375 | return descriptor2Number -> node2Representation | 390 | return descriptor2Number -> node2Representation |
376 | } | 391 | } |
377 | 392 | ||
378 | private def calculateLocalNodeDescriptors( | 393 | private def calculateLocalNodeDescriptors(PartialInterpretation model, Map<DefinedElement, Set<String>> types, |
379 | PartialInterpretation model, | 394 | int maxNumber, DefinedElement focusedElement) { |
380 | Map<DefinedElement, Set<String>> types, | ||
381 | int maxNumber) | ||
382 | { | ||
383 | val Map<DefinedElement, LocalNodeDescriptor> node2Representation = new HashMap | 395 | val Map<DefinedElement, LocalNodeDescriptor> node2Representation = new HashMap |
384 | val Map<LocalNodeDescriptor, Integer> representation2Amount = | 396 | val Map<LocalNodeDescriptor, Integer> representation2Amount = if (mergeSimilarNeighbourhood) { |
385 | if(mergeSimilarNeighbourhood){ new HashMap } else { null } | 397 | new HashMap |
386 | val Map<LocalNodeDescriptor, LocalNodeDescriptor> uniqueRepresentation = | 398 | } else { |
387 | if(this.mergeSimilarNeighbourhood){ new HashMap } else { null } | 399 | null |
388 | 400 | } | |
389 | for(element : model.elements) { | 401 | val Map<LocalNodeDescriptor, LocalNodeDescriptor> uniqueRepresentation = if (this.mergeSimilarNeighbourhood) { |
390 | var newDescriptor = new LocalNodeDescriptor(element.name,element.lookup(types)) | 402 | new HashMap |
391 | if(this.mergeSimilarNeighbourhood){ | 403 | } else { |
392 | if(uniqueRepresentation.containsKey(newDescriptor)) { | 404 | null |
405 | } | ||
406 | |||
407 | for (element : model.elements) { | ||
408 | val name = if(element == focusedElement) FOCUSED_ELEMENT_NAME else element.name | ||
409 | var newDescriptor = new LocalNodeDescriptor(name, element.lookup(types)) | ||
410 | if (this.mergeSimilarNeighbourhood) { | ||
411 | if (uniqueRepresentation.containsKey(newDescriptor)) { | ||
393 | newDescriptor = newDescriptor.lookup(uniqueRepresentation) | 412 | newDescriptor = newDescriptor.lookup(uniqueRepresentation) |
394 | node2Representation.put(element,newDescriptor) | 413 | node2Representation.put(element, newDescriptor) |
395 | representation2Amount.put( | 414 | representation2Amount.put( |
396 | newDescriptor, | 415 | newDescriptor, |
397 | addOne(newDescriptor.lookup(representation2Amount),maxNumber) | 416 | addOne(newDescriptor.lookup(representation2Amount), maxNumber) |
398 | ) | 417 | ) |
399 | } else { | 418 | } else { |
400 | uniqueRepresentation.put(newDescriptor,newDescriptor) | 419 | uniqueRepresentation.put(newDescriptor, newDescriptor) |
401 | node2Representation.put(element,newDescriptor) | 420 | node2Representation.put(element, newDescriptor) |
402 | representation2Amount.put(newDescriptor, if(1>maxNumber){Integer.MAX_VALUE}else{1}) | 421 | representation2Amount.put(newDescriptor, if (1 > maxNumber) { |
422 | Integer.MAX_VALUE | ||
423 | } else { | ||
424 | 1 | ||
425 | }) | ||
403 | } | 426 | } |
404 | } else { | 427 | } else { |
405 | node2Representation.put(element,newDescriptor) | 428 | node2Representation.put(element, newDescriptor) |
406 | } | 429 | } |
407 | } | 430 | } |
408 | 431 | ||
409 | return representation2Amount -> node2Representation | 432 | return representation2Amount -> node2Representation |
410 | } | 433 | } |
411 | } \ No newline at end of file | 434 | } |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/neighbourhood/PartialInterpretation2PairwiseNeighbourhoodRepresentation.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/neighbourhood/PartialInterpretation2PairwiseNeighbourhoodRepresentation.xtend new file mode 100644 index 00000000..c10457b0 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/neighbourhood/PartialInterpretation2PairwiseNeighbourhoodRepresentation.xtend | |||
@@ -0,0 +1,68 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.neighbourhood | ||
2 | |||
3 | import com.google.common.collect.Maps | ||
4 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.DefinedElement | ||
5 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | ||
6 | import java.util.HashMap | ||
7 | import java.util.Map | ||
8 | import org.eclipse.xtend.lib.annotations.Data | ||
9 | import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor | ||
10 | |||
11 | @Data | ||
12 | class PairwiseNeighbourhoodRepresentation<BasicNodeRepresentation> { | ||
13 | val Map<?, Integer> modelRepresentation | ||
14 | val Map<DefinedElement, BasicNodeRepresentation> basicNodeRepresentations | ||
15 | val Map<DefinedElement, ? extends Map<DefinedElement, ? extends BasicNodeRepresentation>> pairwiseNodeRepresentations | ||
16 | |||
17 | def getBasicRepresentation(DefinedElement a) { | ||
18 | basicNodeRepresentations.get(a) | ||
19 | } | ||
20 | |||
21 | def getPairwiseRepresentation(DefinedElement a, DefinedElement b) { | ||
22 | pairwiseNodeRepresentations.get(a).get(b) | ||
23 | } | ||
24 | } | ||
25 | |||
26 | @FinalFieldsConstructor | ||
27 | class PartialInterpretation2PairwiseNeighbourhoodRepresentation<BasicNodeRepresentation> { | ||
28 | val PartialInterpretation2NeighbourhoodRepresentation<? extends Map<? extends BasicNodeRepresentation, Integer>, BasicNodeRepresentation> basicNeighbourhoodRepresenter | ||
29 | |||
30 | def createRepresentation(PartialInterpretation model, NeighbourhoodOptions options) { | ||
31 | val basicRepresentation = basicNeighbourhoodRepresenter.createRepresentation(model, options) | ||
32 | val basicModelRepresentation = basicRepresentation.modelRepresentation | ||
33 | val basicNodeRepresentations = basicRepresentation.nodeRepresentations | ||
34 | val pairwiseNodeRepresentations = Maps.newHashMapWithExpectedSize(basicNodeRepresentations.size) | ||
35 | val modelRepresentation = new HashMap<Object, Integer> | ||
36 | for (nodeWithBasicRepresentation : basicNodeRepresentations.entrySet) { | ||
37 | val node = nodeWithBasicRepresentation.key | ||
38 | val basicNodeRepresentation = nodeWithBasicRepresentation.value | ||
39 | val count = basicModelRepresentation.get(basicNodeRepresentation) | ||
40 | if (count == 1) { | ||
41 | pairwiseNodeRepresentations.put(node, basicNodeRepresentations) | ||
42 | modelRepresentation.put(basicNodeRepresentation, count) | ||
43 | } else { | ||
44 | val neighbourhoodRepresentation = basicNeighbourhoodRepresenter. | ||
45 | createRepresentationWithFocus(model, options, node) | ||
46 | pairwiseNodeRepresentations.put(node, neighbourhoodRepresentation.nodeRepresentations) | ||
47 | modelRepresentation.compute(neighbourhoodRepresentation.modelRepresentation) [ key, value | | ||
48 | if (value === null) { | ||
49 | if (1 > options.maxNumber) { | ||
50 | Integer.MAX_VALUE | ||
51 | } else { | ||
52 | 1 | ||
53 | } | ||
54 | } else { | ||
55 | addOne(value, options.maxNumber) | ||
56 | } | ||
57 | ] | ||
58 | } | ||
59 | } | ||
60 | new PairwiseNeighbourhoodRepresentation(modelRepresentation, basicNodeRepresentations, | ||
61 | pairwiseNodeRepresentations) | ||
62 | } | ||
63 | |||
64 | def private addOne(int original, int max) { | ||
65 | if(original == Integer.MAX_VALUE) return Integer.MAX_VALUE | ||
66 | if(original + 1 > max) return Integer.MAX_VALUE else return original + 1 | ||
67 | } | ||
68 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/statecoder/AbstractNeighborhoodBasedStateCoderFactory.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/statecoder/AbstractNeighborhoodBasedStateCoderFactory.xtend new file mode 100644 index 00000000..089880b1 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/statecoder/AbstractNeighborhoodBasedStateCoderFactory.xtend | |||
@@ -0,0 +1,137 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.statecoder | ||
2 | |||
3 | import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem | ||
4 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.neighbourhood.NeighbourhoodOptions | ||
5 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialComplexTypeInterpretation | ||
6 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | ||
7 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialPrimitiveInterpretation | ||
8 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialRelationInterpretation | ||
9 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialinterpretationPackage | ||
10 | import java.util.LinkedList | ||
11 | import java.util.List | ||
12 | import org.eclipse.emf.common.notify.Notifier | ||
13 | import org.eclipse.emf.ecore.EClass | ||
14 | import org.eclipse.emf.ecore.EObject | ||
15 | import org.eclipse.emf.ecore.EStructuralFeature | ||
16 | import org.eclipse.viatra.dse.statecode.IStateCoder | ||
17 | import org.eclipse.viatra.dse.statecode.IStateCoderFactory | ||
18 | import org.eclipse.viatra.query.runtime.api.IPatternMatch | ||
19 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine | ||
20 | import org.eclipse.viatra.query.runtime.base.api.FeatureListener | ||
21 | import org.eclipse.viatra.query.runtime.base.api.IndexingLevel | ||
22 | import org.eclipse.viatra.query.runtime.base.api.InstanceListener | ||
23 | import org.eclipse.viatra.query.runtime.emf.EMFBaseIndexWrapper | ||
24 | import org.eclipse.viatra.query.runtime.emf.EMFScope | ||
25 | import org.eclipse.xtend.lib.annotations.Accessors | ||
26 | |||
27 | abstract class AbstractNeighbourhoodBasedStateCoderFactory implements IStateCoderFactory { | ||
28 | val List<AbstractNeighbourhoodBasedPartialInterpretationStateCoder> statecoders = new LinkedList | ||
29 | |||
30 | val NeighbourhoodOptions options | ||
31 | |||
32 | protected new() { | ||
33 | this(NeighbourhoodOptions.DEFAULT) | ||
34 | } | ||
35 | |||
36 | protected new(NeighbourhoodOptions options) { | ||
37 | this.options = options | ||
38 | } | ||
39 | |||
40 | synchronized override createStateCoder() { | ||
41 | val res = doCreateStateCoder(options) | ||
42 | statecoders += res | ||
43 | return res | ||
44 | } | ||
45 | |||
46 | protected def AbstractNeighbourhoodBasedPartialInterpretationStateCoder doCreateStateCoder( | ||
47 | NeighbourhoodOptions options) | ||
48 | |||
49 | def getSumStatecoderRuntime() { | ||
50 | statecoders.map[statecoderRuntime].reduce[p1, p2|p1 + p2] | ||
51 | } | ||
52 | } | ||
53 | |||
54 | abstract class AbstractNeighbourhoodBasedPartialInterpretationStateCoder implements IStateCoder { | ||
55 | val NeighbourhoodOptions options | ||
56 | |||
57 | var PartialInterpretation target | ||
58 | |||
59 | protected new(NeighbourhoodOptions options) { | ||
60 | this.options = options | ||
61 | } | ||
62 | |||
63 | @Accessors(PUBLIC_GETTER) var long statecoderRuntime = 0 | ||
64 | |||
65 | synchronized private def refreshStateCodes() { | ||
66 | if (refreshNeeded) { | ||
67 | val startTime = System.nanoTime | ||
68 | doRefreshStateCodes(target, options) | ||
69 | statecoderRuntime += (System.nanoTime - startTime) | ||
70 | } | ||
71 | } | ||
72 | |||
73 | protected def boolean isRefreshNeeded() | ||
74 | |||
75 | protected def void doRefreshStateCodes(PartialInterpretation target, NeighbourhoodOptions options) | ||
76 | |||
77 | synchronized override createActivationCode(IPatternMatch match) { | ||
78 | refreshStateCodes | ||
79 | val startTime = System.nanoTime | ||
80 | val code = doCreateActivationCode(match) | ||
81 | statecoderRuntime += (System.nanoTime - startTime) | ||
82 | code | ||
83 | } | ||
84 | |||
85 | protected def Object doCreateActivationCode(IPatternMatch match) | ||
86 | |||
87 | synchronized override createStateCode() { | ||
88 | refreshStateCodes | ||
89 | doCreateStateCode | ||
90 | } | ||
91 | |||
92 | protected def Object doCreateStateCode() | ||
93 | |||
94 | override init(Notifier notifier) { | ||
95 | this.target = notifier as PartialInterpretation | ||
96 | val queryEngine = ViatraQueryEngine.on(new EMFScope(notifier)) | ||
97 | val baseIndex = queryEngine.getBaseIndex() as EMFBaseIndexWrapper | ||
98 | val navigationHelper = baseIndex.getNavigationHelper(); | ||
99 | |||
100 | val classes = PartialinterpretationPackage.eINSTANCE.EClassifiers.filter(EClass).toSet | ||
101 | val features = classes.map[it.EAllStructuralFeatures].flatten.toSet | ||
102 | navigationHelper.registerObservedTypes(classes, null, features, IndexingLevel.FULL); | ||
103 | |||
104 | navigationHelper.addFeatureListener(features, new FeatureListener() { | ||
105 | override void featureInserted(EObject host, EStructuralFeature feature, Object value) { invalidate } | ||
106 | |||
107 | override void featureDeleted(EObject host, EStructuralFeature feature, Object value) { invalidate } | ||
108 | }) | ||
109 | navigationHelper.addInstanceListener(classes, new InstanceListener() { | ||
110 | override void instanceInserted(EClass clazz, EObject instance) { invalidate } | ||
111 | |||
112 | override void instanceDeleted(EClass clazz, EObject instance) { invalidate } | ||
113 | }) | ||
114 | } | ||
115 | |||
116 | synchronized def invalidate() { | ||
117 | doInvalidate | ||
118 | } | ||
119 | |||
120 | protected def void doInvalidate() | ||
121 | |||
122 | def protected getFallbackCode(Object o) { | ||
123 | switch (o) { | ||
124 | PartialInterpretation, | ||
125 | LogicProblem: | ||
126 | null | ||
127 | PartialRelationInterpretation: | ||
128 | o.interpretationOf.name | ||
129 | PartialPrimitiveInterpretation: | ||
130 | o.class.simpleName.hashCode | ||
131 | PartialComplexTypeInterpretation: | ||
132 | o.interpretationOf.name.hashCode | ||
133 | default: | ||
134 | throw new UnsupportedOperationException('''Unsupported type: «o.class.simpleName»''') | ||
135 | } | ||
136 | } | ||
137 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/statecoder/IdentifierBasedStateCoderFactory.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/statecoder/IdentifierBasedStateCoderFactory.xtend index f55a501a..c7b8ee37 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/statecoder/IdentifierBasedStateCoderFactory.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/statecoder/IdentifierBasedStateCoderFactory.xtend | |||
@@ -62,13 +62,13 @@ class IdentifierBasedStateCode { | |||
62 | int numberOfNewElement | 62 | int numberOfNewElement |
63 | SortedSet<RelationStatecoder> relationStatecoders | 63 | SortedSet<RelationStatecoder> relationStatecoders |
64 | 64 | ||
65 | private static val comparator = new Comparator<RelationStatecoder>() { | 65 | static val comparator = new Comparator<RelationStatecoder>() { |
66 | override compare(RelationStatecoder o1, RelationStatecoder o2) { | 66 | override compare(RelationStatecoder o1, RelationStatecoder o2) { |
67 | o1.relationName.compareTo(o2.relationName) | 67 | o1.relationName.compareTo(o2.relationName) |
68 | } | 68 | } |
69 | } | 69 | } |
70 | 70 | ||
71 | public new(int numberOfNewElements) { | 71 | new(int numberOfNewElements) { |
72 | this.numberOfNewElement = numberOfNewElements | 72 | this.numberOfNewElement = numberOfNewElements |
73 | this.relationStatecoders = new TreeSet(comparator) | 73 | this.relationStatecoders = new TreeSet(comparator) |
74 | } | 74 | } |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/statecoder/NeighbourhoodBasedStateCoderFactory.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/statecoder/NeighbourhoodBasedStateCoderFactory.xtend index a86bcd1f..4ff39999 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/statecoder/NeighbourhoodBasedStateCoderFactory.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/statecoder/NeighbourhoodBasedStateCoderFactory.xtend | |||
@@ -1,223 +1,86 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.statecoder | 1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.statecoder |
2 | 2 | ||
3 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.DefinedElement | ||
3 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.neighbourhood.AbstractNodeDescriptor | 4 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.neighbourhood.AbstractNodeDescriptor |
5 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.neighbourhood.NeighbourhoodOptions | ||
4 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.neighbourhood.PartialInterpretation2ImmutableTypeLattice | 6 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.neighbourhood.PartialInterpretation2ImmutableTypeLattice |
5 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | 7 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation |
6 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialinterpretationPackage | ||
7 | import java.util.ArrayList | 8 | import java.util.ArrayList |
8 | import java.util.LinkedList | ||
9 | import java.util.List | ||
10 | import java.util.Map | 9 | import java.util.Map |
11 | import org.eclipse.emf.common.notify.Notifier | ||
12 | import org.eclipse.emf.ecore.EClass | ||
13 | import org.eclipse.emf.ecore.EObject | ||
14 | import org.eclipse.emf.ecore.EStructuralFeature | ||
15 | import org.eclipse.viatra.dse.statecode.IStateCoder | ||
16 | import org.eclipse.viatra.dse.statecode.IStateCoderFactory | ||
17 | import org.eclipse.viatra.query.runtime.api.IPatternMatch | 10 | import org.eclipse.viatra.query.runtime.api.IPatternMatch |
18 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine | 11 | |
19 | import org.eclipse.viatra.query.runtime.base.api.FeatureListener | 12 | class NeighbourhoodBasedStateCoderFactory extends AbstractNeighbourhoodBasedStateCoderFactory { |
20 | import org.eclipse.viatra.query.runtime.base.api.IndexingLevel | 13 | new() { |
21 | import org.eclipse.viatra.query.runtime.base.api.InstanceListener | ||
22 | import org.eclipse.viatra.query.runtime.emf.EMFBaseIndexWrapper | ||
23 | import org.eclipse.viatra.query.runtime.emf.EMFScope | ||
24 | import org.eclipse.xtend.lib.annotations.Accessors | ||
25 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.DefinedElement | ||
26 | import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem | ||
27 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialTypeInterpratation | ||
28 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialRelationInterpretation | ||
29 | import java.util.Set | ||
30 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.TypeDeclaration | ||
31 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RelationDeclaration | ||
32 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.neighbourhood.PartialInterpretation2NeighbourhoodRepresentation | ||
33 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialComplexTypeInterpretation | ||
34 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialPrimitiveInterpretation | ||
35 | |||
36 | class NeighbourhoodBasedStateCoderFactory implements IStateCoderFactory { | ||
37 | val List<NeighbourhoodBasedPartialInterpretationStateCoder> statecoders = new LinkedList | ||
38 | |||
39 | val int range | ||
40 | val int parallels | ||
41 | val int maxNumber | ||
42 | val Set<TypeDeclaration> relevantTypes | ||
43 | val Set<RelationDeclaration> relevantRelations | ||
44 | |||
45 | public new() { | ||
46 | this.range = PartialInterpretation2NeighbourhoodRepresentation::GraphWidthRange | ||
47 | this.parallels = PartialInterpretation2NeighbourhoodRepresentation::FullParallels | ||
48 | this.maxNumber = PartialInterpretation2NeighbourhoodRepresentation::MaxNumbers | ||
49 | this.relevantTypes = null | ||
50 | this.relevantRelations = null | ||
51 | } | 14 | } |
52 | 15 | ||
53 | public new(int range, int parallels, int maxNumber, Set<TypeDeclaration> relevantTypes, Set<RelationDeclaration> relevantRelations) { | 16 | new(NeighbourhoodOptions options) { |
54 | this.range = range | 17 | super(options) |
55 | this.parallels = parallels | 18 | } |
56 | this.maxNumber = maxNumber | 19 | |
57 | this.relevantTypes = relevantTypes | 20 | override protected doCreateStateCoder(NeighbourhoodOptions options) { |
58 | this.relevantRelations = relevantRelations | 21 | new NeighbourhoodBasedPartialInterpretationStateCoder(options) |
59 | } | 22 | } |
60 | 23 | ||
61 | synchronized override createStateCoder() { | ||
62 | val res = new NeighbourhoodBasedPartialInterpretationStateCoder(statecoders.size, | ||
63 | range,parallels,maxNumber,relevantTypes,relevantRelations) | ||
64 | statecoders += res | ||
65 | return res | ||
66 | } | ||
67 | def getSumStatecoderRuntime() { | ||
68 | statecoders.map[statecoderRuntime].reduce[p1, p2|p1+p2] | ||
69 | } | ||
70 | } | 24 | } |
71 | 25 | ||
72 | class NeighbourhoodBasedPartialInterpretationStateCoder implements IStateCoder{ | 26 | class NeighbourhoodBasedPartialInterpretationStateCoder extends AbstractNeighbourhoodBasedPartialInterpretationStateCoder { |
73 | val int id; | 27 | val calculator = new PartialInterpretation2ImmutableTypeLattice |
74 | val int range | 28 | |
75 | val int parallels | 29 | var Map<DefinedElement, ? extends AbstractNodeDescriptor> nodeRepresentations = null |
76 | val int maxNumber | 30 | var Map<? extends AbstractNodeDescriptor, Integer> modelRepresentation = null |
77 | val Set<TypeDeclaration> relevantTypes | 31 | |
78 | val Set<RelationDeclaration> relevantRelations | 32 | new(NeighbourhoodOptions options) { |
79 | 33 | super(options) | |
80 | val calculator = | ||
81 | new PartialInterpretation2ImmutableTypeLattice | ||
82 | var PartialInterpretation target | ||
83 | |||
84 | private var Map<DefinedElement, ? extends AbstractNodeDescriptor> nodeRepresentations = null | ||
85 | private var Map<? extends AbstractNodeDescriptor, Integer> modelRepresentation = null | ||
86 | |||
87 | /*public new(int id) { | ||
88 | this.id = id | ||
89 | this.range = PartialInterpretation2NeighbourhoodRepresentation::FixPointRage | ||
90 | this.parallels = PartialInterpretation2NeighbourhoodRepresentation::FullParallels | ||
91 | this.maxNumber = maxNumber = PartialInterpretation2NeighbourhoodRepresentation::MaxNumbers | ||
92 | this.relevantTypes = relevantTypes | ||
93 | this.relevantRelations = relevantRelations | ||
94 | }*/ | ||
95 | |||
96 | public new(int id, int range, int parallels, int maxNumber, Set<TypeDeclaration> relevantTypes, Set<RelationDeclaration> relevantRelations) { | ||
97 | this.id = id | ||
98 | this.range = range | ||
99 | this.parallels = parallels | ||
100 | this.maxNumber = maxNumber | ||
101 | this.relevantTypes = relevantTypes | ||
102 | this.relevantRelations = relevantRelations | ||
103 | } | 34 | } |
104 | 35 | ||
105 | @Accessors(PUBLIC_GETTER) var long statecoderRuntime = 0 | 36 | override protected isRefreshNeeded() { |
106 | 37 | nodeRepresentations === null || modelRepresentation === null | |
107 | // val range = -1 | 38 | } |
108 | // val par = Integer.MAX_VALUE | 39 | |
109 | //val deeprepresentation = false | 40 | override doRefreshStateCodes(PartialInterpretation target, NeighbourhoodOptions options) { |
110 | 41 | val code = calculator.createRepresentation(target, options) | |
111 | ///////// | 42 | modelRepresentation = code.modelRepresentation |
112 | // Caching version | 43 | nodeRepresentations = code.nodeRepresentations |
113 | ///////// | 44 | } |
114 | synchronized private def refreshStateCodes() { | 45 | |
115 | if(this.nodeRepresentations === null || this.modelRepresentation === null) { | 46 | override doCreateActivationCode(IPatternMatch match) { |
116 | val startTime = System.nanoTime | 47 | val size = match.specification.parameters.size |
117 | //relevantObjects.forEach[println(it)] | 48 | val res = new ArrayList(size) |
118 | val code = calculator.createRepresentation(target,range,parallels,maxNumber,relevantTypes,relevantRelations) | 49 | var int index = 0 |
119 | this.modelRepresentation = code.modelRepresentation | 50 | var int equivalenceHash = 0 |
120 | this.nodeRepresentations = code.nodeRepresentations | 51 | val prime = 31 |
121 | statecoderRuntime += (System.nanoTime - startTime) | 52 | |
122 | } | 53 | while (index < size) { |
123 | } | 54 | res.add(getCode(match.get(index))) |
124 | synchronized override createActivationCode(IPatternMatch match) { | 55 | index++ |
125 | refreshStateCodes | 56 | for (var i = 0; i < index; i++) { |
126 | 57 | val number = if (match.get(index) === match.get(i)) { | |
127 | val startTime = System.nanoTime | 58 | 1 |
128 | val size = match.specification.parameters.size | 59 | } else { |
129 | val res = new ArrayList(size) | 60 | 0 |
130 | var int index = 0 | 61 | } |
131 | var int equivalenceHash = 0 | 62 | equivalenceHash = prime * equivalenceHash + number |
132 | val prime = 31 | ||
133 | |||
134 | while(index < size) { | ||
135 | res.add(getCode(match.get(index))) | ||
136 | index++ | ||
137 | for(var i = 0; i<index; i++) { | ||
138 | val number = if(match.get(index) === match.get(i)){1}else{0} | ||
139 | equivalenceHash = prime * equivalenceHash + number | ||
140 | } | ||
141 | } | ||
142 | |||
143 | statecoderRuntime += (System.nanoTime - startTime) | ||
144 | return match.specification.fullyQualifiedName->(res->equivalenceHash).hashCode | ||
145 | } | ||
146 | |||
147 | |||
148 | def private getCode(Object o) { | ||
149 | if(o instanceof DefinedElement) { | ||
150 | this.nodeRepresentations.get(o) | ||
151 | } else if(o instanceof PartialInterpretation || o instanceof LogicProblem) { | ||
152 | return null | ||
153 | } else if(o instanceof PartialRelationInterpretation) { | ||
154 | return o.interpretationOf.name | ||
155 | } else if(o instanceof PartialTypeInterpratation) { | ||
156 | if(o instanceof PartialPrimitiveInterpretation) { | ||
157 | o.class.simpleName.hashCode | ||
158 | } else if (o instanceof PartialComplexTypeInterpretation){ | ||
159 | return o.interpretationOf.name.hashCode | ||
160 | } else { | ||
161 | throw new UnsupportedOperationException('''Unsupported type: «o.class.simpleName»''') | ||
162 | } | 63 | } |
163 | } else { | ||
164 | throw new UnsupportedOperationException('''Unsupported type: «o.class.simpleName»''') | ||
165 | } | 64 | } |
166 | } | 65 | |
167 | 66 | match.specification.fullyQualifiedName -> (res -> equivalenceHash).hashCode | |
168 | synchronized override createStateCode() { | 67 | } |
169 | refreshStateCodes | 68 | |
170 | return this.modelRepresentation.hashCode | 69 | def private getCode(Object o) { |
171 | } | 70 | switch (o) { |
172 | ///////// | 71 | DefinedElement: |
173 | // Caching version | 72 | nodeRepresentations.get(o) |
174 | ///////// | 73 | default: |
175 | 74 | getFallbackCode(o) | |
176 | ///////// | 75 | } |
177 | // Recalculating version | 76 | } |
178 | ///////// | 77 | |
179 | // synchronized override createActivationCode(IPatternMatch match) { | 78 | override doCreateStateCode() { |
180 | // val nodes = calculator.createRepresentation(getRelevantObjects().toList,range,par).nodeRepresentations | 79 | modelRepresentation.hashCode |
181 | // val res = match.toArray.map[objectInMatch | | 80 | } |
182 | // nodes.get(objectInMatch) | 81 | |
183 | // ] | 82 | override doInvalidate() { |
184 | // return res | 83 | nodeRepresentations = null |
185 | // } | 84 | modelRepresentation = null |
186 | // | ||
187 | // override createStateCode() { | ||
188 | // return this.calculator.createRepresentation(getRelevantObjects().toList,range,par).modelRepresentation | ||
189 | // } | ||
190 | ///////// | ||
191 | // Recalculating version | ||
192 | ///////// | ||
193 | |||
194 | override init(Notifier notifier) { | ||
195 | this.target = notifier as PartialInterpretation | ||
196 | val queryEngine = ViatraQueryEngine.on(new EMFScope(notifier)) | ||
197 | val baseIndex = queryEngine.getBaseIndex() as EMFBaseIndexWrapper | ||
198 | val navigationHelper = baseIndex.getNavigationHelper(); | ||
199 | |||
200 | val classes = PartialinterpretationPackage.eINSTANCE.EClassifiers.filter(EClass).toSet | ||
201 | val features = classes.map[it.EAllStructuralFeatures].flatten.toSet | ||
202 | navigationHelper.registerObservedTypes( | ||
203 | classes, | ||
204 | null, | ||
205 | features, | ||
206 | IndexingLevel.FULL); | ||
207 | |||
208 | |||
209 | navigationHelper.addFeatureListener(features, new FeatureListener() { | ||
210 | override public void featureInserted(EObject host, EStructuralFeature feature, Object value) { invalidate } | ||
211 | override public void featureDeleted(EObject host, EStructuralFeature feature, Object value) { invalidate } | ||
212 | }); | ||
213 | navigationHelper.addInstanceListener(classes, new InstanceListener() { | ||
214 | override public void instanceInserted(EClass clazz, EObject instance) { invalidate } | ||
215 | override public void instanceDeleted(EClass clazz, EObject instance) { invalidate } | ||
216 | }); | ||
217 | } | ||
218 | |||
219 | synchronized def public invalidate() { | ||
220 | this.nodeRepresentations = null | ||
221 | this.modelRepresentation = null | ||
222 | } | 85 | } |
223 | } | 86 | } |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/statecoder/PairwiseNeighbourhoodBasedStateCoderFactory.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/statecoder/PairwiseNeighbourhoodBasedStateCoderFactory.xtend new file mode 100644 index 00000000..84e798f2 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage/src/hu/bme/mit/inf/dslreasoner/viatrasolver/partialinterpretationlanguage/statecoder/PairwiseNeighbourhoodBasedStateCoderFactory.xtend | |||
@@ -0,0 +1,75 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.statecoder | ||
2 | |||
3 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.DefinedElement | ||
4 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.neighbourhood.AbstractNodeDescriptor | ||
5 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.neighbourhood.NeighbourhoodOptions | ||
6 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.neighbourhood.PairwiseNeighbourhoodRepresentation | ||
7 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.neighbourhood.PartialInterpretation2ImmutableTypeLattice | ||
8 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.neighbourhood.PartialInterpretation2PairwiseNeighbourhoodRepresentation | ||
9 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | ||
10 | import java.util.ArrayList | ||
11 | import org.eclipse.viatra.query.runtime.api.IPatternMatch | ||
12 | |||
13 | class PairwiseNeighbourhoodBasedStateCoderFactory extends AbstractNeighbourhoodBasedStateCoderFactory { | ||
14 | new() { | ||
15 | } | ||
16 | |||
17 | new(NeighbourhoodOptions options) { | ||
18 | super(options) | ||
19 | } | ||
20 | |||
21 | override protected doCreateStateCoder(NeighbourhoodOptions options) { | ||
22 | new PairwiseNeighbourhoodBasedPartialInterpretationStateCoder(options) | ||
23 | } | ||
24 | } | ||
25 | |||
26 | class PairwiseNeighbourhoodBasedPartialInterpretationStateCoder extends AbstractNeighbourhoodBasedPartialInterpretationStateCoder { | ||
27 | val calculator = new PartialInterpretation2PairwiseNeighbourhoodRepresentation( | ||
28 | new PartialInterpretation2ImmutableTypeLattice) | ||
29 | var PairwiseNeighbourhoodRepresentation<? extends AbstractNodeDescriptor> representation | ||
30 | |||
31 | new(NeighbourhoodOptions options) { | ||
32 | super(options) | ||
33 | } | ||
34 | |||
35 | override protected isRefreshNeeded() { | ||
36 | representation === null | ||
37 | } | ||
38 | |||
39 | override protected doRefreshStateCodes(PartialInterpretation target, NeighbourhoodOptions options) { | ||
40 | representation = calculator.createRepresentation(target, options) | ||
41 | } | ||
42 | |||
43 | override protected doCreateActivationCode(IPatternMatch match) { | ||
44 | val size = match.specification.parameters.size | ||
45 | val res = new ArrayList(size * size) | ||
46 | for (var int i = 0; i < size; i++) { | ||
47 | val a = match.get(i) | ||
48 | for (var int j = 0; j < size; j++) { | ||
49 | val b = match.get(j) | ||
50 | res.add(getPairwiseRepresentation(a, b)) | ||
51 | } | ||
52 | } | ||
53 | match.specification.fullyQualifiedName -> res.hashCode | ||
54 | } | ||
55 | |||
56 | private def getPairwiseRepresentation(Object a, Object b) { | ||
57 | if (b instanceof DefinedElement) { | ||
58 | if (a instanceof DefinedElement) { | ||
59 | representation.getPairwiseRepresentation(a, b) | ||
60 | } else { | ||
61 | representation.getBasicRepresentation(b) | ||
62 | } | ||
63 | } else { | ||
64 | getFallbackCode(b) | ||
65 | } | ||
66 | } | ||
67 | |||
68 | override protected doCreateStateCode() { | ||
69 | representation.modelRepresentation.hashCode | ||
70 | } | ||
71 | |||
72 | override protected doInvalidate() { | ||
73 | representation = null | ||
74 | } | ||
75 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/META-INF/MANIFEST.MF b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/META-INF/MANIFEST.MF index 2a271acf..4ad61ccb 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/META-INF/MANIFEST.MF +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/META-INF/MANIFEST.MF | |||
@@ -3,7 +3,8 @@ Bundle-ManifestVersion: 2 | |||
3 | Bundle-Name: Reasoner | 3 | Bundle-Name: Reasoner |
4 | Bundle-SymbolicName: hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner | 4 | Bundle-SymbolicName: hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner |
5 | Bundle-Version: 1.0.0.qualifier | 5 | Bundle-Version: 1.0.0.qualifier |
6 | Export-Package: hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner | 6 | Export-Package: hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner, |
7 | hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization | ||
7 | Require-Bundle: hu.bme.mit.inf.dslreasoner.ecore2logic;bundle-version="1.0.0", | 8 | Require-Bundle: hu.bme.mit.inf.dslreasoner.ecore2logic;bundle-version="1.0.0", |
8 | hu.bme.mit.inf.dslreasoner.logic.model;bundle-version="1.0.0", | 9 | hu.bme.mit.inf.dslreasoner.logic.model;bundle-version="1.0.0", |
9 | hu.bme.mit.inf.dslreasoner.viatra2logic;bundle-version="1.0.0", | 10 | hu.bme.mit.inf.dslreasoner.viatra2logic;bundle-version="1.0.0", |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/ViatraReasoner.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/ViatraReasoner.xtend index 6639e5f3..1abde0a8 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/ViatraReasoner.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/ViatraReasoner.xtend | |||
@@ -1,5 +1,7 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner | 1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner |
2 | 2 | ||
3 | import com.google.common.collect.ImmutableList | ||
4 | import com.google.common.collect.Lists | ||
3 | import hu.bme.mit.inf.dslreasoner.logic.model.builder.DocumentationLevel | 5 | import hu.bme.mit.inf.dslreasoner.logic.model.builder.DocumentationLevel |
4 | import hu.bme.mit.inf.dslreasoner.logic.model.builder.LogicReasoner | 6 | import hu.bme.mit.inf.dslreasoner.logic.model.builder.LogicReasoner |
5 | import hu.bme.mit.inf.dslreasoner.logic.model.builder.LogicReasonerException | 7 | import hu.bme.mit.inf.dslreasoner.logic.model.builder.LogicReasonerException |
@@ -10,19 +12,25 @@ import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicproblemPackage | |||
10 | import hu.bme.mit.inf.dslreasoner.logic.model.logicresult.LogicresultFactory | 12 | import hu.bme.mit.inf.dslreasoner.logic.model.logicresult.LogicresultFactory |
11 | import hu.bme.mit.inf.dslreasoner.logic.model.logicresult.ModelResult | 13 | import hu.bme.mit.inf.dslreasoner.logic.model.logicresult.ModelResult |
12 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.ModelGenerationMethodProvider | 14 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.ModelGenerationMethodProvider |
13 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.ScopePropagator | ||
14 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.PartialInterpretationInitialiser | 15 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.PartialInterpretationInitialiser |
15 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | 16 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation |
16 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialinterpretationPackage | 17 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialinterpretationPackage |
18 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.statecoder.AbstractNeighbourhoodBasedStateCoderFactory | ||
17 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.statecoder.IdentifierBasedStateCoderFactory | 19 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.statecoder.IdentifierBasedStateCoderFactory |
18 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.statecoder.NeighbourhoodBasedStateCoderFactory | 20 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.statecoder.PairwiseNeighbourhoodBasedStateCoderFactory |
19 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.BestFirstStrategyForModelGeneration | 21 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.BestFirstStrategyForModelGeneration |
22 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.DiversityChecker | ||
23 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.InconsistentScopeGlobalConstraint | ||
24 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.LoggerSolutionFoundHandler | ||
20 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.ModelGenerationCompositeObjective | 25 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.ModelGenerationCompositeObjective |
21 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.PartialModelAsLogicInterpretation | 26 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.PartialModelAsLogicInterpretation |
22 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.ScopeObjective | 27 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.ScopeObjective |
28 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.SurelyViolatedObjectiveGlobalConstraint | ||
23 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.UnfinishedMultiplicityObjective | 29 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.UnfinishedMultiplicityObjective |
24 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.UnfinishedWFObjective | 30 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.ViatraReasonerSolutionSaver |
25 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.WF2ObjectiveConverter | 31 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.WF2ObjectiveConverter |
32 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization.ThreeValuedCostElement | ||
33 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization.ThreeValuedCostObjective | ||
26 | import hu.bme.mit.inf.dslreasoner.workspace.ReasonerWorkspace | 34 | import hu.bme.mit.inf.dslreasoner.workspace.ReasonerWorkspace |
27 | import java.util.List | 35 | import java.util.List |
28 | import java.util.Map | 36 | import java.util.Map |
@@ -31,185 +39,247 @@ import org.eclipse.viatra.dse.api.DesignSpaceExplorer | |||
31 | import org.eclipse.viatra.dse.api.DesignSpaceExplorer.DseLoggingLevel | 39 | import org.eclipse.viatra.dse.api.DesignSpaceExplorer.DseLoggingLevel |
32 | import org.eclipse.viatra.dse.solutionstore.SolutionStore | 40 | import org.eclipse.viatra.dse.solutionstore.SolutionStore |
33 | import org.eclipse.viatra.dse.statecode.IStateCoderFactory | 41 | import org.eclipse.viatra.dse.statecode.IStateCoderFactory |
34 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.SolutionStoreWithDiversityDescriptor | 42 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.statecoder.NeighbourhoodBasedStateCoderFactory |
35 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse.DiversityGranularity | ||
36 | 43 | ||
37 | class ViatraReasoner extends LogicReasoner{ | 44 | class ViatraReasoner extends LogicReasoner { |
38 | val PartialInterpretationInitialiser initialiser = new PartialInterpretationInitialiser() | 45 | val PartialInterpretationInitialiser initialiser = new PartialInterpretationInitialiser() |
39 | val ModelGenerationMethodProvider modelGenerationMethodProvider = new ModelGenerationMethodProvider | 46 | val ModelGenerationMethodProvider modelGenerationMethodProvider = new ModelGenerationMethodProvider |
40 | val extension LogicresultFactory factory = LogicresultFactory.eINSTANCE | 47 | val extension LogicresultFactory factory = LogicresultFactory.eINSTANCE |
41 | val WF2ObjectiveConverter wf2ObjectiveConverter = new WF2ObjectiveConverter | 48 | val WF2ObjectiveConverter wf2ObjectiveConverter = new WF2ObjectiveConverter |
42 | 49 | ||
43 | 50 | override solve(LogicProblem problem, LogicSolverConfiguration configuration, | |
44 | override solve(LogicProblem problem, LogicSolverConfiguration configuration, ReasonerWorkspace workspace) throws LogicReasonerException { | 51 | ReasonerWorkspace workspace) throws LogicReasonerException { |
45 | val viatraConfig = configuration.asConfig | 52 | val viatraConfig = configuration.asConfig |
46 | 53 | ||
47 | if(viatraConfig.debugCongiguration.logging) { | 54 | if (viatraConfig.documentationLevel == DocumentationLevel.FULL) { |
48 | DesignSpaceExplorer.turnOnLogging(DseLoggingLevel.VERBOSE_FULL) | 55 | DesignSpaceExplorer.turnOnLogging(DseLoggingLevel.VERBOSE_FULL) |
49 | } else { | 56 | } else { |
50 | DesignSpaceExplorer.turnOnLogging(DseLoggingLevel.WARN) | 57 | DesignSpaceExplorer.turnOnLogging(DseLoggingLevel.WARN) |
51 | } | 58 | } |
52 | 59 | ||
53 | val DesignSpaceExplorer dse = new DesignSpaceExplorer(); | 60 | val DesignSpaceExplorer dse = new DesignSpaceExplorer(); |
54 | 61 | ||
55 | dse.addMetaModelPackage(LogiclanguagePackage.eINSTANCE) | 62 | dse.addMetaModelPackage(LogiclanguagePackage.eINSTANCE) |
56 | dse.addMetaModelPackage(LogicproblemPackage.eINSTANCE) | 63 | dse.addMetaModelPackage(LogicproblemPackage.eINSTANCE) |
57 | dse.addMetaModelPackage(PartialinterpretationPackage.eINSTANCE) | 64 | dse.addMetaModelPackage(PartialinterpretationPackage.eINSTANCE) |
58 | 65 | ||
59 | val transformationStartTime = System.nanoTime | 66 | val transformationStartTime = System.nanoTime |
60 | 67 | ||
61 | 68 | val emptySolution = initialiser.initialisePartialInterpretation(problem, viatraConfig.typeScopes).output | |
62 | 69 | if ((viatraConfig.documentationLevel == DocumentationLevel::FULL || | |
63 | val emptySolution = initialiser.initialisePartialInterpretation(problem,viatraConfig.typeScopes).output | 70 | viatraConfig.documentationLevel == DocumentationLevel::NORMAL) && workspace !== null) { |
64 | if((viatraConfig.documentationLevel == DocumentationLevel::FULL || viatraConfig.documentationLevel == DocumentationLevel::NORMAL) && workspace !== null) { | 71 | workspace.writeModel(emptySolution, "init.partialmodel") |
65 | workspace.writeModel(emptySolution,"init.partialmodel") | 72 | } |
66 | } | ||
67 | emptySolution.problemConainer = problem | 73 | emptySolution.problemConainer = problem |
68 | 74 | ||
69 | val ScopePropagator scopePropagator = new ScopePropagator(emptySolution) | ||
70 | scopePropagator.propagateAllScopeConstraints | ||
71 | |||
72 | val method = modelGenerationMethodProvider.createModelGenerationMethod( | 75 | val method = modelGenerationMethodProvider.createModelGenerationMethod( |
73 | problem, | 76 | problem, |
74 | emptySolution, | 77 | emptySolution, |
75 | workspace, | 78 | workspace, |
76 | viatraConfig.nameNewElements, | 79 | viatraConfig.nameNewElements, |
77 | viatraConfig.typeInferenceMethod, | 80 | viatraConfig.typeInferenceMethod, |
78 | scopePropagator, | 81 | viatraConfig.scopePropagatorStrategy, |
79 | viatraConfig.documentationLevel | 82 | viatraConfig.documentationLevel |
80 | ) | 83 | ) |
81 | 84 | ||
82 | dse.addObjective(new ModelGenerationCompositeObjective( | 85 | dse.addObjective(new ModelGenerationCompositeObjective( |
83 | new ScopeObjective, | 86 | new ScopeObjective, |
84 | method.unfinishedMultiplicities.map[new UnfinishedMultiplicityObjective(it)], | 87 | method.unfinishedMultiplicities.map[new UnfinishedMultiplicityObjective(it)], |
85 | new UnfinishedWFObjective(method.unfinishedWF) | 88 | wf2ObjectiveConverter.createCompletenessObjective(method.unfinishedWF) |
86 | )) | 89 | )) |
87 | 90 | ||
88 | dse.addGlobalConstraint(wf2ObjectiveConverter.createInvalidationObjective(method.invalidWF)) | 91 | val extremalObjectives = Lists.newArrayListWithExpectedSize(viatraConfig.costObjectives.size) |
89 | for(additionalConstraint : viatraConfig.searchSpaceConstraints.additionalGlobalConstraints) { | 92 | for (entry : viatraConfig.costObjectives.indexed) { |
93 | val objectiveName = '''costObjective«entry.key»''' | ||
94 | val objectiveConfig = entry.value | ||
95 | val elementsBuilder = ImmutableList.builder | ||
96 | for (elementConfig : objectiveConfig.elements) { | ||
97 | val relationName = elementConfig.patternQualifiedName | ||
98 | val modalQueries = method.modalRelationQueries.get(relationName) | ||
99 | if (modalQueries === null) { | ||
100 | throw new IllegalArgumentException("Unknown relation: " + relationName) | ||
101 | } | ||
102 | elementsBuilder.add(new ThreeValuedCostElement( | ||
103 | modalQueries.currentQuery, | ||
104 | modalQueries.mayQuery, | ||
105 | modalQueries.mustQuery, | ||
106 | elementConfig.weight | ||
107 | )) | ||
108 | } | ||
109 | val costElements = elementsBuilder.build | ||
110 | val costObjective = new ThreeValuedCostObjective(objectiveName, costElements, objectiveConfig.kind, | ||
111 | objectiveConfig.threshold, 3) | ||
112 | dse.addObjective(costObjective) | ||
113 | if (objectiveConfig.findExtremum) { | ||
114 | extremalObjectives += costObjective | ||
115 | } | ||
116 | } | ||
117 | |||
118 | val numberOfRequiredSolutions = configuration.solutionScope.numberOfRequiredSolutions | ||
119 | val solutionStore = if (extremalObjectives.empty) { | ||
120 | new SolutionStore(numberOfRequiredSolutions) | ||
121 | } else { | ||
122 | new SolutionStore() | ||
123 | } | ||
124 | solutionStore.registerSolutionFoundHandler(new LoggerSolutionFoundHandler(viatraConfig)) | ||
125 | val diversityChecker = DiversityChecker.of(viatraConfig.diversityRequirement) | ||
126 | val solutionSaver = new ViatraReasonerSolutionSaver(newArrayList(extremalObjectives), numberOfRequiredSolutions, | ||
127 | diversityChecker) | ||
128 | val solutionCopier = solutionSaver.solutionCopier | ||
129 | solutionStore.withSolutionSaver(solutionSaver) | ||
130 | dse.solutionStore = solutionStore | ||
131 | |||
132 | dse.addGlobalConstraint(wf2ObjectiveConverter.createInvalidationGlobalConstraint(method.invalidWF)) | ||
133 | dse.addGlobalConstraint(new SurelyViolatedObjectiveGlobalConstraint(solutionSaver)) | ||
134 | dse.addGlobalConstraint(new InconsistentScopeGlobalConstraint) | ||
135 | for (additionalConstraint : viatraConfig.searchSpaceConstraints.additionalGlobalConstraints) { | ||
90 | dse.addGlobalConstraint(additionalConstraint.apply(method)) | 136 | dse.addGlobalConstraint(additionalConstraint.apply(method)) |
91 | } | 137 | } |
92 | 138 | ||
93 | dse.setInitialModel(emptySolution,false) | 139 | dse.setInitialModel(emptySolution, false) |
94 | 140 | ||
95 | val IStateCoderFactory statecoder = if(viatraConfig.stateCoderStrategy == StateCoderStrategy.Neighbourhood) { | 141 | val IStateCoderFactory statecoder = switch (viatraConfig.stateCoderStrategy) { |
96 | new NeighbourhoodBasedStateCoderFactory | 142 | case Neighbourhood: |
97 | } else { | 143 | new NeighbourhoodBasedStateCoderFactory |
98 | new IdentifierBasedStateCoderFactory | 144 | case PairwiseNeighbourhood: |
145 | new PairwiseNeighbourhoodBasedStateCoderFactory | ||
146 | default: | ||
147 | new IdentifierBasedStateCoderFactory | ||
99 | } | 148 | } |
100 | dse.stateCoderFactory = statecoder | 149 | dse.stateCoderFactory = statecoder |
101 | 150 | ||
102 | dse.maxNumberOfThreads = 1 | 151 | dse.maxNumberOfThreads = 1 |
103 | 152 | ||
104 | val solutionStore = new SolutionStore(configuration.solutionScope.numberOfRequiredSolution) | 153 | for (rule : method.relationRefinementRules) { |
105 | dse.solutionStore = solutionStore | ||
106 | |||
107 | for(rule : method.relationRefinementRules) { | ||
108 | dse.addTransformationRule(rule) | 154 | dse.addTransformationRule(rule) |
109 | } | 155 | } |
110 | for(rule : method.objectRefinementRules) { | 156 | for (rule : method.objectRefinementRules) { |
111 | dse.addTransformationRule(rule) | 157 | dse.addTransformationRule(rule) |
112 | } | 158 | } |
113 | 159 | ||
114 | val strategy = new BestFirstStrategyForModelGeneration(workspace,viatraConfig,method) | 160 | val strategy = new BestFirstStrategyForModelGeneration(workspace, viatraConfig, method) |
115 | viatraConfig.progressMonitor.workedForwardTransformation | 161 | viatraConfig.progressMonitor.workedForwardTransformation |
116 | 162 | ||
117 | val transformationTime = System.nanoTime - transformationStartTime | 163 | val transformationTime = System.nanoTime - transformationStartTime |
118 | val solverStartTime = System.nanoTime | 164 | val solverStartTime = System.nanoTime |
119 | 165 | ||
120 | var boolean stoppedByTimeout | 166 | var boolean stoppedByTimeout |
121 | var boolean stoppedByException | 167 | try { |
122 | try{ | 168 | stoppedByTimeout = dse.startExplorationWithTimeout(strategy, configuration.runtimeLimit * 1000); |
123 | stoppedByTimeout = dse.startExplorationWithTimeout(strategy,configuration.runtimeLimit*1000); | ||
124 | stoppedByException = false | ||
125 | } catch (NullPointerException npe) { | 169 | } catch (NullPointerException npe) { |
126 | stoppedByTimeout = false | 170 | stoppedByTimeout = false |
127 | stoppedByException = true | ||
128 | } | 171 | } |
129 | val solverTime = System.nanoTime - solverStartTime | 172 | val solverTime = System.nanoTime - solverStartTime |
130 | viatraConfig.progressMonitor.workedSearchFinished | 173 | viatraConfig.progressMonitor.workedSearchFinished |
131 | 174 | ||
132 | //additionalMatches = strategy.solutionStoreWithCopy.additionalMatches | 175 | // additionalMatches = strategy.solutionStoreWithCopy.additionalMatches |
133 | val statistics = createStatistics => [ | 176 | val statistics = createStatistics => [ |
134 | //it.solverTime = viatraConfig.runtimeLimit | 177 | // it.solverTime = viatraConfig.runtimeLimit |
135 | it.solverTime = (solverTime/1000000) as int | 178 | it.solverTime = (solverTime / 1000000) as int |
136 | it.transformationTime = (transformationTime/1000000) as int | 179 | it.transformationTime = (transformationTime / 1000000) as int |
137 | for(x : 0..<strategy.solutionStoreWithCopy.allRuntimes.size) { | 180 | for (pair : solutionCopier.getAllCopierRuntimes(true).indexed) { |
138 | it.entries += createIntStatisticEntry => [ | 181 | it.entries += createIntStatisticEntry => [ |
139 | it.name = '''_Solution«x»FoundAt''' | 182 | it.name = '''_Solution«pair.key»FoundAt''' |
140 | it.value = (strategy.solutionStoreWithCopy.allRuntimes.get(x)/1000000) as int | 183 | it.value = (pair.value / 1000000) as int |
141 | ] | 184 | ] |
142 | } | 185 | } |
143 | it.entries += createIntStatisticEntry => [ | 186 | it.entries += createIntStatisticEntry => [ |
144 | it.name = "TransformationExecutionTime" it.value = (method.statistics.transformationExecutionTime/1000000) as int | 187 | it.name = "TransformationExecutionTime" |
188 | it.value = (method.statistics.transformationExecutionTime / 1000000) as int | ||
145 | ] | 189 | ] |
146 | it.entries += createIntStatisticEntry => [ | 190 | it.entries += createIntStatisticEntry => [ |
147 | it.name = "TypeAnalysisTime" it.value = (method.statistics.PreliminaryTypeAnalisisTime/1000000) as int | 191 | it.name = "ScopePropagationTime" |
192 | it.value = (method.statistics.scopePropagationTime / 1000000) as int | ||
148 | ] | 193 | ] |
149 | it.entries += createIntStatisticEntry => [ | 194 | it.entries += createIntStatisticEntry => [ |
150 | it.name = "StateCoderTime" it.value = (statecoder.runtime/1000000) as int | 195 | it.name = "TypeAnalysisTime" |
196 | it.value = (method.statistics.preliminaryTypeAnalisisTime / 1000000) as int | ||
151 | ] | 197 | ] |
152 | it.entries += createIntStatisticEntry => [ | 198 | it.entries += createIntStatisticEntry => [ |
153 | it.name = "StateCoderFailCount" it.value = strategy.numberOfStatecoderFail | 199 | it.name = "StateCoderTime" |
200 | it.value = (statecoder.runtime / 1000000) as int | ||
154 | ] | 201 | ] |
155 | it.entries += createIntStatisticEntry => [ | 202 | it.entries += createIntStatisticEntry => [ |
156 | it.name = "SolutionCopyTime" it.value = (strategy.solutionStoreWithCopy.sumRuntime/1000000) as int | 203 | it.name = "StateCoderFailCount" |
204 | it.value = strategy.numberOfStatecoderFail | ||
157 | ] | 205 | ] |
158 | if(strategy.solutionStoreWithDiversityDescriptor.isActive) { | 206 | it.entries += createIntStatisticEntry => [ |
207 | it.name = "SolutionCopyTime" | ||
208 | it.value = (solutionCopier.getTotalCopierRuntime / 1000000) as int | ||
209 | ] | ||
210 | it.entries += createIntStatisticEntry => [ | ||
211 | it.name = "States" | ||
212 | it.value = dse.numberOfStates as int | ||
213 | ] | ||
214 | it.entries += createIntStatisticEntry => [ | ||
215 | it.name = "Decisions" | ||
216 | it.value = method.statistics.decisionsTried | ||
217 | ] | ||
218 | it.entries += createIntStatisticEntry => [ | ||
219 | it.name = "ScopePropagations" | ||
220 | it.value = method.statistics.scopePropagatorInvocations | ||
221 | ] | ||
222 | if (diversityChecker.isActive) { | ||
159 | it.entries += createIntStatisticEntry => [ | 223 | it.entries += createIntStatisticEntry => [ |
160 | it.name = "SolutionDiversityCheckTime" it.value = (strategy.solutionStoreWithDiversityDescriptor.sumRuntime/1000000) as int | 224 | it.name = "SolutionDiversityCheckTime" |
225 | it.value = (diversityChecker.totalRuntime / 1000000) as int | ||
161 | ] | 226 | ] |
162 | it.entries += createRealStatisticEntry => [ | 227 | it.entries += createRealStatisticEntry => [ |
163 | it.name = "SolutionDiversitySuccessRate" it.value = strategy.solutionStoreWithDiversityDescriptor.successRate | 228 | it.name = "SolutionDiversitySuccessRate" |
229 | it.value = diversityChecker.successRate | ||
164 | ] | 230 | ] |
165 | } | 231 | } |
166 | ] | 232 | ] |
167 | 233 | ||
168 | viatraConfig.progressMonitor.workedBackwardTransformationFinished | 234 | viatraConfig.progressMonitor.workedBackwardTransformationFinished |
169 | 235 | ||
170 | if(stoppedByTimeout) { | 236 | if (stoppedByTimeout) { |
171 | return createInsuficientResourcesResult=>[ | 237 | return createInsuficientResourcesResult => [ |
172 | it.problem = problem | 238 | it.problem = problem |
173 | it.resourceName="time" | 239 | it.resourceName = "time" |
174 | it.representation += strategy.solutionStoreWithCopy.solutions | 240 | it.representation += solutionCopier.getPartialInterpretations(true) |
175 | it.statistics = statistics | 241 | it.statistics = statistics |
176 | ] | 242 | ] |
177 | } else { | 243 | } else { |
178 | if(solutionStore.solutions.empty) { | 244 | if (solutionStore.solutions.empty) { |
179 | return createInconsistencyResult => [ | 245 | return createInconsistencyResult => [ |
180 | it.problem = problem | 246 | it.problem = problem |
181 | it.representation += strategy.solutionStoreWithCopy.solutions | 247 | it.representation += solutionCopier.getPartialInterpretations(true) |
182 | it.statistics = statistics | 248 | it.statistics = statistics |
183 | ] | 249 | ] |
184 | } else { | 250 | } else { |
185 | return createModelResult => [ | 251 | return createModelResult => [ |
186 | it.problem = problem | 252 | it.problem = problem |
187 | it.trace = strategy.solutionStoreWithCopy.copyTraces | 253 | it.trace = solutionCopier.getTraces(true) |
188 | it.representation += strategy.solutionStoreWithCopy.solutions | 254 | it.representation += solutionCopier.getPartialInterpretations(true) |
189 | it.statistics = statistics | 255 | it.statistics = statistics |
190 | ] | 256 | ] |
191 | } | 257 | } |
192 | } | 258 | } |
193 | } | 259 | } |
194 | 260 | ||
195 | private def dispatch long runtime(NeighbourhoodBasedStateCoderFactory sc) { | 261 | private def dispatch long runtime(AbstractNeighbourhoodBasedStateCoderFactory sc) { |
196 | sc.sumStatecoderRuntime | 262 | sc.sumStatecoderRuntime |
197 | } | 263 | } |
198 | 264 | ||
199 | private def dispatch long runtime(IdentifierBasedStateCoderFactory sc) { | 265 | private def dispatch long runtime(IdentifierBasedStateCoderFactory sc) { |
200 | sc.sumStatecoderRuntime | 266 | sc.sumStatecoderRuntime |
201 | } | 267 | } |
202 | 268 | ||
203 | override getInterpretations(ModelResult modelResult) { | 269 | override getInterpretations(ModelResult modelResult) { |
204 | val indexes = 0..<modelResult.representation.size | 270 | val indexes = 0 ..< modelResult.representation.size |
205 | val traces = modelResult.trace as List<Map<EObject, EObject>>; | 271 | val traces = modelResult.trace as List<Map<EObject, EObject>>; |
206 | val res = indexes.map[i | new PartialModelAsLogicInterpretation(modelResult.representation.get(i) as PartialInterpretation,traces.get(i))].toList | 272 | val res = indexes.map [ i | |
273 | new PartialModelAsLogicInterpretation(modelResult.representation.get(i) as PartialInterpretation, | ||
274 | traces.get(i)) | ||
275 | ].toList | ||
207 | return res | 276 | return res |
208 | } | 277 | } |
209 | 278 | ||
210 | private def ViatraReasonerConfiguration asConfig(LogicSolverConfiguration configuration) { | 279 | private def ViatraReasonerConfiguration asConfig(LogicSolverConfiguration configuration) { |
211 | if(configuration instanceof ViatraReasonerConfiguration) { | 280 | if (configuration instanceof ViatraReasonerConfiguration) { |
212 | return configuration | 281 | return configuration |
213 | } else throw new IllegalArgumentException('''Wrong configuration. Expected: «ViatraReasonerConfiguration.name», but got: «configuration.class.name»"''') | 282 | } else |
283 | throw new IllegalArgumentException('''Wrong configuration. Expected: «ViatraReasonerConfiguration.name», but got: «configuration.class.name»"''') | ||
214 | } | 284 | } |
215 | } | 285 | } |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/ViatraReasonerConfiguration.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/ViatraReasonerConfiguration.xtend index c4d7e231..a5f42a5f 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/ViatraReasonerConfiguration.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/ViatraReasonerConfiguration.xtend | |||
@@ -6,19 +6,27 @@ import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RelationDeclaration | |||
6 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.TypeDeclaration | 6 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.TypeDeclaration |
7 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.ModelGenerationMethod | 7 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.ModelGenerationMethod |
8 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.TypeInferenceMethod | 8 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.TypeInferenceMethod |
9 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.PolyhedralScopePropagatorConstraints | ||
10 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.PolyhedralScopePropagatorSolver | ||
11 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.ScopePropagatorStrategy | ||
9 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.visualisation.PartialInterpretationVisualiser | 12 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.visualisation.PartialInterpretationVisualiser |
13 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization.ObjectiveKind | ||
14 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization.ObjectiveThreshold | ||
10 | import java.util.LinkedList | 15 | import java.util.LinkedList |
11 | import java.util.List | 16 | import java.util.List |
12 | import java.util.Set | 17 | import java.util.Set |
13 | import org.eclipse.xtext.xbase.lib.Functions.Function1 | 18 | import org.eclipse.xtext.xbase.lib.Functions.Function1 |
14 | 19 | ||
15 | public enum StateCoderStrategy { | 20 | enum StateCoderStrategy { |
16 | Neighbourhood, NeighbourhoodWithEquivalence, IDBased, DefinedByDiversity | 21 | Neighbourhood, |
22 | PairwiseNeighbourhood, | ||
23 | NeighbourhoodWithEquivalence, | ||
24 | IDBased, | ||
25 | DefinedByDiversity | ||
17 | } | 26 | } |
18 | 27 | ||
19 | class ViatraReasonerConfiguration extends LogicSolverConfiguration{ | 28 | class ViatraReasonerConfiguration extends LogicSolverConfiguration { |
20 | //public var Iterable<PQuery> existingQueries | 29 | // public var Iterable<PQuery> existingQueries |
21 | |||
22 | public var nameNewElements = false | 30 | public var nameNewElements = false |
23 | public var StateCoderStrategy stateCoderStrategy = StateCoderStrategy.Neighbourhood | 31 | public var StateCoderStrategy stateCoderStrategy = StateCoderStrategy.Neighbourhood |
24 | public var TypeInferenceMethod typeInferenceMethod = TypeInferenceMethod.PreliminaryAnalysis | 32 | public var TypeInferenceMethod typeInferenceMethod = TypeInferenceMethod.PreliminaryAnalysis |
@@ -26,7 +34,7 @@ class ViatraReasonerConfiguration extends LogicSolverConfiguration{ | |||
26 | * Once per 1/randomBacktrackChance the search selects a random state. | 34 | * Once per 1/randomBacktrackChance the search selects a random state. |
27 | */ | 35 | */ |
28 | public var int randomBacktrackChance = 20; | 36 | public var int randomBacktrackChance = 20; |
29 | 37 | ||
30 | /** | 38 | /** |
31 | * Describes the required diversity between the solutions. | 39 | * Describes the required diversity between the solutions. |
32 | * Null means that the solutions have to have different state codes only. | 40 | * Null means that the solutions have to have different state codes only. |
@@ -40,14 +48,19 @@ class ViatraReasonerConfiguration extends LogicSolverConfiguration{ | |||
40 | /** | 48 | /** |
41 | * Configuration for debugging support. | 49 | * Configuration for debugging support. |
42 | */ | 50 | */ |
43 | public var DebugConfiguration debugCongiguration = new DebugConfiguration | 51 | public var DebugConfiguration debugConfiguration = new DebugConfiguration |
44 | /** | 52 | /** |
45 | * Configuration for cutting search space. | 53 | * Configuration for cutting search space. |
46 | */ | 54 | */ |
47 | public var SearchSpaceConstraint searchSpaceConstraints = new SearchSpaceConstraint | 55 | public var SearchSpaceConstraint searchSpaceConstraints = new SearchSpaceConstraint |
56 | |||
57 | public var ScopePropagatorStrategy scopePropagatorStrategy = new ScopePropagatorStrategy.Polyhedral( | ||
58 | PolyhedralScopePropagatorConstraints.Relational, PolyhedralScopePropagatorSolver.Clp) | ||
59 | |||
60 | public var List<CostObjectiveConfiguration> costObjectives = newArrayList | ||
48 | } | 61 | } |
49 | 62 | ||
50 | public class DiversityDescriptor { | 63 | class DiversityDescriptor { |
51 | public var ensureDiversity = false | 64 | public var ensureDiversity = false |
52 | public static val FixPointRange = -1 | 65 | public static val FixPointRange = -1 |
53 | public var int range = FixPointRange | 66 | public var int range = FixPointRange |
@@ -57,20 +70,31 @@ public class DiversityDescriptor { | |||
57 | public var Set<RelationDeclaration> relevantRelations = null | 70 | public var Set<RelationDeclaration> relevantRelations = null |
58 | } | 71 | } |
59 | 72 | ||
60 | public class DebugConfiguration { | 73 | class DebugConfiguration { |
61 | public var logging = false | 74 | public var PartialInterpretationVisualiser partialInterpretatioVisualiser = null |
62 | public var PartialInterpretationVisualiser partialInterpretatioVisualiser = null; | ||
63 | public var partalInterpretationVisualisationFrequency = 1 | 75 | public var partalInterpretationVisualisationFrequency = 1 |
64 | } | 76 | } |
65 | 77 | ||
66 | public class InternalConsistencyCheckerConfiguration { | 78 | class InternalConsistencyCheckerConfiguration { |
67 | public var LogicReasoner internalIncosnsitencyDetector = null | 79 | public var LogicReasoner internalIncosnsitencyDetector = null |
68 | public var LogicSolverConfiguration internalInconsistencDetectorConfiguration = null | 80 | public var LogicSolverConfiguration internalInconsistencDetectorConfiguration = null |
69 | public var incternalConsistencyCheckingFrequency = 1 | 81 | public var incternalConsistencyCheckingFrequency = 1 |
70 | } | 82 | } |
71 | 83 | ||
72 | public class SearchSpaceConstraint { | 84 | class SearchSpaceConstraint { |
73 | public static val UNLIMITED_MAXDEPTH = Integer.MAX_VALUE | 85 | public static val UNLIMITED_MAXDEPTH = Integer.MAX_VALUE |
74 | public var int maxDepth = UNLIMITED_MAXDEPTH | 86 | public var int maxDepth = UNLIMITED_MAXDEPTH |
75 | public var List<Function1<ModelGenerationMethod, ModelGenerationMethodBasedGlobalConstraint>> additionalGlobalConstraints = new LinkedList | 87 | public var List<Function1<ModelGenerationMethod, ModelGenerationMethodBasedGlobalConstraint>> additionalGlobalConstraints = new LinkedList |
76 | } \ No newline at end of file | 88 | } |
89 | |||
90 | class CostObjectiveConfiguration { | ||
91 | public var List<CostObjectiveElementConfiguration> elements = newArrayList | ||
92 | public var ObjectiveKind kind | ||
93 | public var ObjectiveThreshold threshold | ||
94 | public var boolean findExtremum | ||
95 | } | ||
96 | |||
97 | class CostObjectiveElementConfiguration { | ||
98 | public var String patternQualifiedName | ||
99 | public var int weight | ||
100 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/BestFirstStrategyForModelGeneration.java b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/BestFirstStrategyForModelGeneration.java index 60f46033..5af7fc69 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/BestFirstStrategyForModelGeneration.java +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/BestFirstStrategyForModelGeneration.java | |||
@@ -21,6 +21,7 @@ import java.util.PriorityQueue; | |||
21 | import java.util.Random; | 21 | import java.util.Random; |
22 | 22 | ||
23 | import org.apache.log4j.Logger; | 23 | import org.apache.log4j.Logger; |
24 | import org.eclipse.emf.ecore.EObject; | ||
24 | import org.eclipse.emf.ecore.util.EcoreUtil; | 25 | import org.eclipse.emf.ecore.util.EcoreUtil; |
25 | import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy; | 26 | import org.eclipse.viatra.dse.api.strategy.interfaces.IStrategy; |
26 | import org.eclipse.viatra.dse.base.ThreadContext; | 27 | import org.eclipse.viatra.dse.base.ThreadContext; |
@@ -75,8 +76,6 @@ public class BestFirstStrategyForModelGeneration implements IStrategy { | |||
75 | // Running | 76 | // Running |
76 | private PriorityQueue<TrajectoryWithFitness> trajectoiresToExplore; | 77 | private PriorityQueue<TrajectoryWithFitness> trajectoiresToExplore; |
77 | private SolutionStore solutionStore; | 78 | private SolutionStore solutionStore; |
78 | private SolutionStoreWithCopy solutionStoreWithCopy; | ||
79 | private SolutionStoreWithDiversityDescriptor solutionStoreWithDiversityDescriptor; | ||
80 | private volatile boolean isInterrupted = false; | 79 | private volatile boolean isInterrupted = false; |
81 | private ModelResult modelResultByInternalSolver = null; | 80 | private ModelResult modelResultByInternalSolver = null; |
82 | private Random random = new Random(); | 81 | private Random random = new Random(); |
@@ -95,14 +94,9 @@ public class BestFirstStrategyForModelGeneration implements IStrategy { | |||
95 | this.workspace = workspace; | 94 | this.workspace = workspace; |
96 | this.configuration = configuration; | 95 | this.configuration = configuration; |
97 | this.method = method; | 96 | this.method = method; |
97 | //logger.setLevel(Level.DEBUG); | ||
98 | } | 98 | } |
99 | 99 | ||
100 | public SolutionStoreWithCopy getSolutionStoreWithCopy() { | ||
101 | return solutionStoreWithCopy; | ||
102 | } | ||
103 | public SolutionStoreWithDiversityDescriptor getSolutionStoreWithDiversityDescriptor() { | ||
104 | return solutionStoreWithDiversityDescriptor; | ||
105 | } | ||
106 | public int getNumberOfStatecoderFail() { | 100 | public int getNumberOfStatecoderFail() { |
107 | return numberOfStatecoderFail; | 101 | return numberOfStatecoderFail; |
108 | } | 102 | } |
@@ -121,9 +115,6 @@ public class BestFirstStrategyForModelGeneration implements IStrategy { | |||
121 | matchers.add(matcher); | 115 | matchers.add(matcher); |
122 | } | 116 | } |
123 | 117 | ||
124 | this.solutionStoreWithCopy = new SolutionStoreWithCopy(); | ||
125 | this.solutionStoreWithDiversityDescriptor = new SolutionStoreWithDiversityDescriptor(configuration.diversityRequirement); | ||
126 | |||
127 | final ObjectiveComparatorHelper objectiveComparatorHelper = context.getObjectiveComparatorHelper(); | 118 | final ObjectiveComparatorHelper objectiveComparatorHelper = context.getObjectiveComparatorHelper(); |
128 | this.comparator = new Comparator<TrajectoryWithFitness>() { | 119 | this.comparator = new Comparator<TrajectoryWithFitness>() { |
129 | @Override | 120 | @Override |
@@ -146,13 +137,13 @@ public class BestFirstStrategyForModelGeneration implements IStrategy { | |||
146 | return; | 137 | return; |
147 | } | 138 | } |
148 | 139 | ||
149 | final Fitness firstFittness = context.calculateFitness(); | 140 | final Fitness firstfitness = context.calculateFitness(); |
150 | checkForSolution(firstFittness); | 141 | solutionStore.newSolution(context); |
151 | 142 | ||
152 | final ObjectiveComparatorHelper objectiveComparatorHelper = context.getObjectiveComparatorHelper(); | 143 | final ObjectiveComparatorHelper objectiveComparatorHelper = context.getObjectiveComparatorHelper(); |
153 | final Object[] firstTrajectory = context.getTrajectory().toArray(new Object[0]); | 144 | final Object[] firstTrajectory = context.getTrajectory().toArray(new Object[0]); |
154 | TrajectoryWithFitness currentTrajectoryWithFittness = new TrajectoryWithFitness(firstTrajectory, firstFittness); | 145 | TrajectoryWithFitness currentTrajectoryWithfitness = new TrajectoryWithFitness(firstTrajectory, firstfitness); |
155 | trajectoiresToExplore.add(currentTrajectoryWithFittness); | 146 | trajectoiresToExplore.add(currentTrajectoryWithfitness); |
156 | 147 | ||
157 | //if(configuration) | 148 | //if(configuration) |
158 | visualiseCurrentState(); | 149 | visualiseCurrentState(); |
@@ -167,22 +158,22 @@ public class BestFirstStrategyForModelGeneration implements IStrategy { | |||
167 | 158 | ||
168 | mainLoop: while (!isInterrupted && !configuration.progressMonitor.isCancelled()) { | 159 | mainLoop: while (!isInterrupted && !configuration.progressMonitor.isCancelled()) { |
169 | 160 | ||
170 | if (currentTrajectoryWithFittness == null) { | 161 | if (currentTrajectoryWithfitness == null) { |
171 | if (trajectoiresToExplore.isEmpty()) { | 162 | if (trajectoiresToExplore.isEmpty()) { |
172 | logger.debug("State space is fully traversed."); | 163 | logger.debug("State space is fully traversed."); |
173 | return; | 164 | return; |
174 | } else { | 165 | } else { |
175 | currentTrajectoryWithFittness = selectState(); | 166 | currentTrajectoryWithfitness = selectState(); |
176 | if (logger.isDebugEnabled()) { | 167 | if (logger.isDebugEnabled()) { |
177 | logger.debug("Current trajectory: " + Arrays.toString(context.getTrajectory().toArray())); | 168 | logger.debug("Current trajectory: " + Arrays.toString(context.getTrajectory().toArray())); |
178 | logger.debug("New trajectory is chosen: " + currentTrajectoryWithFittness); | 169 | logger.debug("New trajectory is chosen: " + currentTrajectoryWithfitness); |
179 | } | 170 | } |
180 | context.getDesignSpaceManager().executeTrajectoryWithMinimalBacktrackWithoutStateCoding(currentTrajectoryWithFittness.trajectory); | 171 | context.getDesignSpaceManager().executeTrajectoryWithMinimalBacktrackWithoutStateCoding(currentTrajectoryWithfitness.trajectory); |
181 | } | 172 | } |
182 | } | 173 | } |
183 | 174 | ||
184 | // visualiseCurrentState(); | 175 | // visualiseCurrentState(); |
185 | // boolean consistencyCheckResult = checkConsistency(currentTrajectoryWithFittness); | 176 | // boolean consistencyCheckResult = checkConsistency(currentTrajectoryWithfitness); |
186 | // if(consistencyCheckResult == true) { | 177 | // if(consistencyCheckResult == true) { |
187 | // continue mainLoop; | 178 | // continue mainLoop; |
188 | // } | 179 | // } |
@@ -194,10 +185,11 @@ public class BestFirstStrategyForModelGeneration implements IStrategy { | |||
194 | final Object nextActivation = iterator.next(); | 185 | final Object nextActivation = iterator.next(); |
195 | // if (!iterator.hasNext()) { | 186 | // if (!iterator.hasNext()) { |
196 | // logger.debug("Last untraversed activation of the state."); | 187 | // logger.debug("Last untraversed activation of the state."); |
197 | // trajectoiresToExplore.remove(currentTrajectoryWithFittness); | 188 | // trajectoiresToExplore.remove(currentTrajectoryWithfitness); |
198 | // } | 189 | // } |
199 | logger.debug("Executing new activation: " + nextActivation); | 190 | logger.debug("Executing new activation: " + nextActivation); |
200 | context.executeAcitvationId(nextActivation); | 191 | context.executeAcitvationId(nextActivation); |
192 | method.getStatistics().incrementDecisionCount(); | ||
201 | 193 | ||
202 | visualiseCurrentState(); | 194 | visualiseCurrentState(); |
203 | // for(ViatraQueryMatcher<? extends IPatternMatch> matcher : matchers) { | 195 | // for(ViatraQueryMatcher<? extends IPatternMatch> matcher : matchers) { |
@@ -209,7 +201,7 @@ public class BestFirstStrategyForModelGeneration implements IStrategy { | |||
209 | // System.out.println("---------"); | 201 | // System.out.println("---------"); |
210 | // } | 202 | // } |
211 | 203 | ||
212 | boolean consistencyCheckResult = checkConsistency(currentTrajectoryWithFittness); | 204 | boolean consistencyCheckResult = checkConsistency(currentTrajectoryWithfitness); |
213 | if(consistencyCheckResult == true) { continue mainLoop; } | 205 | if(consistencyCheckResult == true) { continue mainLoop; } |
214 | 206 | ||
215 | if (context.isCurrentStateAlreadyTraversed()) { | 207 | if (context.isCurrentStateAlreadyTraversed()) { |
@@ -220,38 +212,38 @@ public class BestFirstStrategyForModelGeneration implements IStrategy { | |||
220 | context.backtrack(); | 212 | context.backtrack(); |
221 | } else { | 213 | } else { |
222 | final Fitness nextFitness = context.calculateFitness(); | 214 | final Fitness nextFitness = context.calculateFitness(); |
223 | checkForSolution(nextFitness); | 215 | solutionStore.newSolution(context); |
224 | if (context.getDepth() > configuration.searchSpaceConstraints.maxDepth) { | 216 | if (context.getDepth() > configuration.searchSpaceConstraints.maxDepth) { |
225 | logger.debug("Reached max depth."); | 217 | logger.debug("Reached max depth."); |
226 | context.backtrack(); | 218 | context.backtrack(); |
227 | continue; | 219 | continue; |
228 | } | 220 | } |
229 | 221 | ||
230 | TrajectoryWithFitness nextTrajectoryWithFittness = new TrajectoryWithFitness( | 222 | TrajectoryWithFitness nextTrajectoryWithfitness = new TrajectoryWithFitness( |
231 | context.getTrajectory().toArray(), nextFitness); | 223 | context.getTrajectory().toArray(), nextFitness); |
232 | trajectoiresToExplore.add(nextTrajectoryWithFittness); | 224 | trajectoiresToExplore.add(nextTrajectoryWithfitness); |
233 | 225 | ||
234 | int compare = objectiveComparatorHelper.compare(currentTrajectoryWithFittness.fitness, | 226 | int compare = objectiveComparatorHelper.compare(currentTrajectoryWithfitness.fitness, |
235 | nextTrajectoryWithFittness.fitness); | 227 | nextTrajectoryWithfitness.fitness); |
236 | if (compare < 0) { | 228 | if (compare < 0) { |
237 | logger.debug("Better fitness, moving on: " + nextFitness); | 229 | logger.debug("Better fitness, moving on: " + nextFitness); |
238 | currentTrajectoryWithFittness = nextTrajectoryWithFittness; | 230 | currentTrajectoryWithfitness = nextTrajectoryWithfitness; |
239 | continue mainLoop; | 231 | continue mainLoop; |
240 | } else if (compare == 0) { | 232 | } else if (compare == 0) { |
241 | logger.debug("Equally good fitness, moving on: " + nextFitness); | 233 | logger.debug("Equally good fitness, moving on: " + nextFitness); |
242 | currentTrajectoryWithFittness = nextTrajectoryWithFittness; | 234 | currentTrajectoryWithfitness = nextTrajectoryWithfitness; |
243 | continue mainLoop; | 235 | continue mainLoop; |
244 | } else { | 236 | } else { |
245 | logger.debug("Worse fitness."); | 237 | logger.debug("Worse fitness."); |
246 | currentTrajectoryWithFittness = null; | 238 | currentTrajectoryWithfitness = null; |
247 | continue mainLoop; | 239 | continue mainLoop; |
248 | } | 240 | } |
249 | } | 241 | } |
250 | } | 242 | } |
251 | 243 | ||
252 | logger.debug("State is fully traversed."); | 244 | logger.debug("State is fully traversed."); |
253 | trajectoiresToExplore.remove(currentTrajectoryWithFittness); | 245 | trajectoiresToExplore.remove(currentTrajectoryWithfitness); |
254 | currentTrajectoryWithFittness = null; | 246 | currentTrajectoryWithfitness = null; |
255 | 247 | ||
256 | } | 248 | } |
257 | logger.info("Interrupted."); | 249 | logger.info("Interrupted."); |
@@ -263,25 +255,13 @@ public class BestFirstStrategyForModelGeneration implements IStrategy { | |||
263 | activationIds = new ArrayList<Object>(context.getUntraversedActivationIds()); | 255 | activationIds = new ArrayList<Object>(context.getUntraversedActivationIds()); |
264 | Collections.shuffle(activationIds); | 256 | Collections.shuffle(activationIds); |
265 | } catch (NullPointerException e) { | 257 | } catch (NullPointerException e) { |
258 | logger.warn("Unexpected state code: " + context.getDesignSpaceManager().getCurrentState()); | ||
266 | numberOfStatecoderFail++; | 259 | numberOfStatecoderFail++; |
267 | activationIds = Collections.emptyList(); | 260 | activationIds = Collections.emptyList(); |
268 | } | 261 | } |
269 | return activationIds; | 262 | return activationIds; |
270 | } | 263 | } |
271 | 264 | ||
272 | private void checkForSolution(final Fitness fittness) { | ||
273 | if (fittness.isSatisifiesHardObjectives()) { | ||
274 | if (solutionStoreWithDiversityDescriptor.isDifferent(context)) { | ||
275 | solutionStoreWithCopy.newSolution(context); | ||
276 | solutionStoreWithDiversityDescriptor.newSolution(context); | ||
277 | solutionStore.newSolution(context); | ||
278 | configuration.progressMonitor.workedModelFound(configuration.solutionScope.numberOfRequiredSolution); | ||
279 | |||
280 | logger.debug("Found a solution."); | ||
281 | } | ||
282 | } | ||
283 | } | ||
284 | |||
285 | @Override | 265 | @Override |
286 | public void interruptStrategy() { | 266 | public void interruptStrategy() { |
287 | isInterrupted = true; | 267 | isInterrupted = true; |
@@ -311,13 +291,16 @@ public class BestFirstStrategyForModelGeneration implements IStrategy { | |||
311 | } | 291 | } |
312 | 292 | ||
313 | public void visualiseCurrentState() { | 293 | public void visualiseCurrentState() { |
314 | PartialInterpretationVisualiser partialInterpretatioVisualiser = configuration.debugCongiguration.partialInterpretatioVisualiser; | 294 | PartialInterpretationVisualiser partialInterpretatioVisualiser = configuration.debugConfiguration.partialInterpretatioVisualiser; |
315 | if(partialInterpretatioVisualiser != null && this.configuration.documentationLevel == DocumentationLevel.FULL && workspace != null) { | 295 | if(partialInterpretatioVisualiser != null && this.configuration.documentationLevel == DocumentationLevel.FULL && workspace != null) { |
316 | PartialInterpretation p = (PartialInterpretation) (context.getModel()); | 296 | PartialInterpretation p = (PartialInterpretation) (context.getModel()); |
317 | int id = ++numberOfPrintedModel; | 297 | int id = ++numberOfPrintedModel; |
318 | if (id % configuration.debugCongiguration.partalInterpretationVisualisationFrequency == 0) { | 298 | if (id % configuration.debugConfiguration.partalInterpretationVisualisationFrequency == 0) { |
319 | PartialInterpretationVisualisation visualisation = partialInterpretatioVisualiser.visualiseConcretization(p); | 299 | PartialInterpretationVisualisation visualisation = partialInterpretatioVisualiser.visualiseConcretization(p); |
320 | visualisation.writeToFile(workspace, String.format("state%09d.png", id)); | 300 | logger.debug("Visualizing state: " + id + " (" + context.getDesignSpaceManager().getCurrentState() + ")"); |
301 | String name = String.format("state%09d", id); | ||
302 | visualisation.writeToFile(workspace, name + ".png"); | ||
303 | workspace.writeModel((EObject) context.getModel(), name + ".xmi"); | ||
321 | } | 304 | } |
322 | } | 305 | } |
323 | } | 306 | } |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/DiversityChecker.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/DiversityChecker.xtend new file mode 100644 index 00000000..fb1b2066 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/DiversityChecker.xtend | |||
@@ -0,0 +1,184 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse | ||
2 | |||
3 | import com.google.common.collect.HashMultiset | ||
4 | import com.google.common.collect.ImmutableSet | ||
5 | import com.google.common.collect.Multiset | ||
6 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.neighbourhood.AbstractNodeDescriptor | ||
7 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.neighbourhood.NeighbourhoodWithTraces | ||
8 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.neighbourhood.PartialInterpretation2ImmutableTypeLattice | ||
9 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | ||
10 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.DiversityDescriptor | ||
11 | import java.util.Collection | ||
12 | import java.util.HashSet | ||
13 | import java.util.Map | ||
14 | import java.util.Set | ||
15 | import org.eclipse.viatra.dse.base.ThreadContext | ||
16 | import org.eclipse.xtend.lib.annotations.Accessors | ||
17 | |||
18 | interface DiversityChecker { | ||
19 | public static val NO_DIVERSITY_CHECKER = new DiversityChecker { | ||
20 | override isActive() { | ||
21 | false | ||
22 | } | ||
23 | |||
24 | override getTotalRuntime() { | ||
25 | 0 | ||
26 | } | ||
27 | |||
28 | override getSuccessRate() { | ||
29 | 1.0 | ||
30 | } | ||
31 | |||
32 | override newSolution(ThreadContext threadContext, Object solutionId, Collection<Object> dominatedSolutionIds) { | ||
33 | true | ||
34 | } | ||
35 | } | ||
36 | |||
37 | def boolean isActive() | ||
38 | |||
39 | def long getTotalRuntime() | ||
40 | |||
41 | def double getSuccessRate() | ||
42 | |||
43 | def boolean newSolution(ThreadContext threadContext, Object solutionId, Collection<Object> dominatedSolutionIds) | ||
44 | |||
45 | static def of(DiversityDescriptor descriptor) { | ||
46 | if (descriptor.ensureDiversity) { | ||
47 | new NodewiseDiversityChecker(descriptor) | ||
48 | } else { | ||
49 | NO_DIVERSITY_CHECKER | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | |||
54 | abstract class AbstractDiversityChecker implements DiversityChecker { | ||
55 | val DiversityDescriptor descriptor | ||
56 | val PartialInterpretation2ImmutableTypeLattice solutionCoder = new PartialInterpretation2ImmutableTypeLattice | ||
57 | |||
58 | @Accessors(PUBLIC_GETTER) var long totalRuntime = 0 | ||
59 | var int allCheckCount = 0 | ||
60 | var int successfulCheckCount = 0 | ||
61 | |||
62 | protected new(DiversityDescriptor descriptor) { | ||
63 | if (!descriptor.ensureDiversity) { | ||
64 | throw new IllegalArgumentException( | ||
65 | "Diversity description should enforce diversity or NO_DIVERSITY_CHECKER should be used instead.") | ||
66 | } | ||
67 | this.descriptor = descriptor | ||
68 | } | ||
69 | |||
70 | override isActive() { | ||
71 | true | ||
72 | } | ||
73 | |||
74 | override getTotalRuntime() { | ||
75 | throw new UnsupportedOperationException("TODO: auto-generated method stub") | ||
76 | } | ||
77 | |||
78 | override getSuccessRate() { | ||
79 | (allCheckCount as double) / (successfulCheckCount as double) | ||
80 | } | ||
81 | |||
82 | override newSolution(ThreadContext threadContext, Object solutionId, Collection<Object> dominatedSolutionIds) { | ||
83 | val start = System.nanoTime | ||
84 | val model = threadContext.model as PartialInterpretation | ||
85 | val representation = solutionCoder.createRepresentation(model, descriptor.range, descriptor.parallels, | ||
86 | descriptor.maxNumber, descriptor.relevantTypes, descriptor.relevantRelations) | ||
87 | val isDifferent = internalNewSolution(representation, solutionId, dominatedSolutionIds) | ||
88 | totalRuntime += System.nanoTime - start | ||
89 | allCheckCount++ | ||
90 | if (isDifferent) { | ||
91 | successfulCheckCount++ | ||
92 | } | ||
93 | isDifferent | ||
94 | } | ||
95 | |||
96 | protected abstract def boolean internalNewSolution( | ||
97 | NeighbourhoodWithTraces<Map<? extends AbstractNodeDescriptor, Integer>, AbstractNodeDescriptor> representation, | ||
98 | Object solutionId, Collection<Object> dominatedSolutionIds) | ||
99 | } | ||
100 | |||
101 | class NodewiseDiversityChecker extends AbstractDiversityChecker { | ||
102 | var Multiset<Integer> nodeCodes = HashMultiset.create | ||
103 | val Map<Object, Set<Integer>> tracedNodeCodes = newHashMap | ||
104 | |||
105 | new(DiversityDescriptor descriptor) { | ||
106 | super(descriptor) | ||
107 | } | ||
108 | |||
109 | override protected internalNewSolution( | ||
110 | NeighbourhoodWithTraces<Map<? extends AbstractNodeDescriptor, Integer>, AbstractNodeDescriptor> representation, | ||
111 | Object solutionId, Collection<Object> dominatedSolutionIds) { | ||
112 | val nodeCodesInSolution = ImmutableSet.copyOf(representation.modelRepresentation.keySet.map[hashCode]) | ||
113 | val remainingNodeCodes = if (dominatedSolutionIds.empty) { | ||
114 | nodeCodes | ||
115 | } else { | ||
116 | getRemainingNodeCodes(dominatedSolutionIds) | ||
117 | } | ||
118 | val hasNewCode = nodeCodesInSolution.exists[!remainingNodeCodes.contains(it)] | ||
119 | if (hasNewCode) { | ||
120 | nodeCodes = remainingNodeCodes | ||
121 | nodeCodes.addAll(nodeCodesInSolution) | ||
122 | for (dominatedSolutionId : dominatedSolutionIds) { | ||
123 | tracedNodeCodes.remove(dominatedSolutionId) | ||
124 | } | ||
125 | tracedNodeCodes.put(solutionId, nodeCodesInSolution) | ||
126 | } | ||
127 | hasNewCode | ||
128 | } | ||
129 | |||
130 | private def getRemainingNodeCodes(Collection<Object> dominatedSolutionIds) { | ||
131 | // TODO Optimize multiset operations. | ||
132 | val copyOfNodeCodes = HashMultiset.create(nodeCodes) | ||
133 | for (dominatedSolutionId : dominatedSolutionIds) { | ||
134 | val dominatedModelCode = tracedNodeCodes.get(dominatedSolutionId) | ||
135 | if (dominatedModelCode === null) { | ||
136 | throw new IllegalArgumentException("Unknown dominated solution: " + dominatedSolutionId) | ||
137 | } | ||
138 | copyOfNodeCodes.removeAll(dominatedModelCode) | ||
139 | } | ||
140 | copyOfNodeCodes | ||
141 | } | ||
142 | } | ||
143 | |||
144 | class GraphwiseDiversityChecker extends AbstractDiversityChecker { | ||
145 | var Set<Integer> modelCodes = newHashSet | ||
146 | val Map<Object, Integer> tracedModelCodes = newHashMap | ||
147 | |||
148 | new(DiversityDescriptor descriptor) { | ||
149 | super(descriptor) | ||
150 | } | ||
151 | |||
152 | override protected internalNewSolution( | ||
153 | NeighbourhoodWithTraces<Map<? extends AbstractNodeDescriptor, Integer>, AbstractNodeDescriptor> representation, | ||
154 | Object solutionId, Collection<Object> dominatedSolutionIds) { | ||
155 | val modelCodeOfSolution = representation.modelRepresentation.hashCode | ||
156 | val remainingModelCodes = if (dominatedSolutionIds.empty) { | ||
157 | modelCodes | ||
158 | } else { | ||
159 | getRemainingModelCodes(dominatedSolutionIds) | ||
160 | } | ||
161 | val isNewCode = !remainingModelCodes.contains(modelCodeOfSolution) | ||
162 | if (isNewCode) { | ||
163 | modelCodes = remainingModelCodes | ||
164 | modelCodes += modelCodeOfSolution | ||
165 | for (dominatedSolutionId : dominatedSolutionIds) { | ||
166 | tracedModelCodes.remove(dominatedSolutionId) | ||
167 | } | ||
168 | tracedModelCodes.put(solutionId, modelCodeOfSolution) | ||
169 | } | ||
170 | isNewCode | ||
171 | } | ||
172 | |||
173 | private def getRemainingModelCodes(Collection<Object> dominatedSolutionIds) { | ||
174 | val copyOfModelCodes = new HashSet(modelCodes) | ||
175 | for (dominatedSolutionId : dominatedSolutionIds) { | ||
176 | val dominatedModelCode = tracedModelCodes.get(dominatedSolutionId) | ||
177 | if (dominatedModelCode === null) { | ||
178 | throw new IllegalArgumentException("Unknown dominated solution: " + dominatedSolutionId) | ||
179 | } | ||
180 | copyOfModelCodes -= dominatedModelCode | ||
181 | } | ||
182 | copyOfModelCodes | ||
183 | } | ||
184 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/DseUtils.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/DseUtils.xtend new file mode 100644 index 00000000..3c2e3319 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/DseUtils.xtend | |||
@@ -0,0 +1,66 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse | ||
2 | |||
3 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization.IThreeValuedObjective | ||
4 | import org.eclipse.viatra.dse.base.ThreadContext | ||
5 | import org.eclipse.viatra.dse.objectives.Comparators | ||
6 | import org.eclipse.viatra.dse.objectives.Fitness | ||
7 | import org.eclipse.viatra.dse.objectives.IObjective | ||
8 | |||
9 | final class DseUtils { | ||
10 | private new() { | ||
11 | throw new IllegalStateException("This is a static utility class and should not be instantiated directly.") | ||
12 | } | ||
13 | |||
14 | static def calculateFitness(ThreadContext it, (IObjective)=>Double getFitness) { | ||
15 | val result = new Fitness | ||
16 | var boolean satisifiesHardObjectives = true | ||
17 | for (objective : objectives) { | ||
18 | val fitness = getFitness.apply(objective) | ||
19 | result.put(objective.name, fitness) | ||
20 | if (objective.isHardObjective() && !objective.satisifiesHardObjective(fitness)) { | ||
21 | satisifiesHardObjectives = false | ||
22 | } | ||
23 | } | ||
24 | result.satisifiesHardObjectives = satisifiesHardObjectives | ||
25 | result | ||
26 | } | ||
27 | |||
28 | static def caclulateBestPossibleFitness(ThreadContext threadContext) { | ||
29 | threadContext.calculateFitness [ objective | | ||
30 | if (objective instanceof IThreeValuedObjective) { | ||
31 | objective.getBestPossibleFitness(threadContext) | ||
32 | } else { | ||
33 | switch (objective.comparator) { | ||
34 | case Comparators.LOWER_IS_BETTER: | ||
35 | Double.NEGATIVE_INFINITY | ||
36 | case Comparators.HIGHER_IS_BETTER: | ||
37 | Double.POSITIVE_INFINITY | ||
38 | case Comparators.DIFFERENCE_TO_ZERO_IS_BETTER: | ||
39 | 0.0 | ||
40 | default: | ||
41 | throw new IllegalArgumentException("Unknown comparator for non-three-valued objective: " + | ||
42 | objective.name) | ||
43 | } | ||
44 | } | ||
45 | ] | ||
46 | } | ||
47 | |||
48 | static def caclulateWorstPossibleFitness(ThreadContext threadContext) { | ||
49 | threadContext.calculateFitness [ objective | | ||
50 | if (objective instanceof IThreeValuedObjective) { | ||
51 | objective.getWorstPossibleFitness(threadContext) | ||
52 | } else { | ||
53 | switch (objective.comparator) { | ||
54 | case Comparators.LOWER_IS_BETTER, | ||
55 | case Comparators.DIFFERENCE_TO_ZERO_IS_BETTER: | ||
56 | Double.POSITIVE_INFINITY | ||
57 | case Comparators.HIGHER_IS_BETTER: | ||
58 | Double.NEGATIVE_INFINITY | ||
59 | default: | ||
60 | throw new IllegalArgumentException("Unknown comparator for non-three-valued objective: " + | ||
61 | objective.name) | ||
62 | } | ||
63 | } | ||
64 | ] | ||
65 | } | ||
66 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/InconsistentScopeGlobalConstraint.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/InconsistentScopeGlobalConstraint.xtend new file mode 100644 index 00000000..2e039ca2 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/InconsistentScopeGlobalConstraint.xtend | |||
@@ -0,0 +1,25 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse | ||
2 | |||
3 | import org.eclipse.viatra.dse.objectives.IGlobalConstraint | ||
4 | import org.eclipse.viatra.dse.base.ThreadContext | ||
5 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | ||
6 | |||
7 | class InconsistentScopeGlobalConstraint implements IGlobalConstraint { | ||
8 | |||
9 | override init(ThreadContext context) { | ||
10 | // Nothing to initialize. | ||
11 | } | ||
12 | |||
13 | override createNew() { | ||
14 | this | ||
15 | } | ||
16 | |||
17 | override getName() { | ||
18 | class.name | ||
19 | } | ||
20 | |||
21 | override checkGlobalConstraint(ThreadContext context) { | ||
22 | val partialModel = context.model as PartialInterpretation | ||
23 | partialModel.minNewElements <= partialModel.maxNewElements || partialModel.maxNewElements < 0 | ||
24 | } | ||
25 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/LoggerSolutionFoundHandler.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/LoggerSolutionFoundHandler.xtend new file mode 100644 index 00000000..39ef5f9a --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/LoggerSolutionFoundHandler.xtend | |||
@@ -0,0 +1,24 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse | ||
2 | |||
3 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.ViatraReasonerConfiguration | ||
4 | import org.apache.log4j.Logger | ||
5 | import org.eclipse.viatra.dse.api.SolutionTrajectory | ||
6 | import org.eclipse.viatra.dse.base.ThreadContext | ||
7 | import org.eclipse.viatra.dse.solutionstore.ISolutionFoundHandler | ||
8 | import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor | ||
9 | |||
10 | @FinalFieldsConstructor | ||
11 | class LoggerSolutionFoundHandler implements ISolutionFoundHandler { | ||
12 | val ViatraReasonerConfiguration configuration | ||
13 | |||
14 | val logger = Logger.getLogger(SolutionCopier) | ||
15 | |||
16 | override solutionFound(ThreadContext context, SolutionTrajectory trajectory) { | ||
17 | configuration.progressMonitor.workedModelFound(configuration.solutionScope.numberOfRequiredSolutions) | ||
18 | logger.debug("Found a solution.") | ||
19 | } | ||
20 | |||
21 | override solutionTriedToSave(ThreadContext context, SolutionTrajectory trajectory) { | ||
22 | // We are not interested in invalid solutions, ignore. | ||
23 | } | ||
24 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/ModelGenerationCompositeObjective.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/ModelGenerationCompositeObjective.xtend index 2489c751..9a33753c 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/ModelGenerationCompositeObjective.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/ModelGenerationCompositeObjective.xtend | |||
@@ -1,11 +1,13 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse | 1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse |
2 | 2 | ||
3 | import com.google.common.collect.ImmutableList | ||
4 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization.IThreeValuedObjective | ||
3 | import java.util.Comparator | 5 | import java.util.Comparator |
4 | import java.util.List | 6 | import java.util.List |
5 | import org.eclipse.viatra.dse.base.ThreadContext | 7 | import org.eclipse.viatra.dse.base.ThreadContext |
6 | import org.eclipse.viatra.dse.objectives.Comparators | 8 | import org.eclipse.viatra.dse.objectives.Comparators |
7 | import org.eclipse.viatra.dse.objectives.IObjective | 9 | import org.eclipse.viatra.dse.objectives.IObjective |
8 | import org.eclipse.viatra.dse.objectives.impl.BaseObjective | 10 | import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor |
9 | 11 | ||
10 | //class ViatraReasonerNumbers { | 12 | //class ViatraReasonerNumbers { |
11 | // public static val scopePriority = 2 | 13 | // public static val scopePriority = 2 |
@@ -22,64 +24,66 @@ import org.eclipse.viatra.dse.objectives.impl.BaseObjective | |||
22 | // public static val compositePriority = 2 | 24 | // public static val compositePriority = 2 |
23 | //} | 25 | //} |
24 | 26 | ||
25 | class ModelGenerationCompositeObjective implements IObjective{ | 27 | @FinalFieldsConstructor |
26 | val ScopeObjective scopeObjective | 28 | class ModelGenerationCompositeObjective implements IThreeValuedObjective { |
27 | val List<UnfinishedMultiplicityObjective> unfinishedMultiplicityObjectives | 29 | val IObjective scopeObjective |
28 | val UnfinishedWFObjective unfinishedWFObjective | 30 | val List<IObjective> unfinishedMultiplicityObjectives |
29 | 31 | val IObjective unfinishedWFObjective | |
30 | public new( | 32 | |
31 | ScopeObjective scopeObjective, | ||
32 | List<UnfinishedMultiplicityObjective> unfinishedMultiplicityObjectives, | ||
33 | UnfinishedWFObjective unfinishedWFObjective) | ||
34 | { | ||
35 | this.scopeObjective = scopeObjective | ||
36 | this.unfinishedMultiplicityObjectives = unfinishedMultiplicityObjectives | ||
37 | this.unfinishedWFObjective = unfinishedWFObjective | ||
38 | } | ||
39 | |||
40 | override init(ThreadContext context) { | 33 | override init(ThreadContext context) { |
41 | this.scopeObjective.init(context) | 34 | this.scopeObjective.init(context) |
42 | this.unfinishedMultiplicityObjectives.forEach[it.init(context)] | 35 | this.unfinishedMultiplicityObjectives.forEach[it.init(context)] |
43 | this.unfinishedWFObjective.init(context) | 36 | this.unfinishedWFObjective.init(context) |
44 | } | 37 | } |
45 | 38 | ||
46 | override createNew() { | 39 | override createNew() { |
47 | return new ModelGenerationCompositeObjective( | 40 | return new ModelGenerationCompositeObjective( |
48 | this.scopeObjective, this.unfinishedMultiplicityObjectives, this.unfinishedWFObjective) | 41 | scopeObjective.createNew, |
42 | ImmutableList.copyOf(unfinishedMultiplicityObjectives.map[createNew]), | ||
43 | unfinishedWFObjective.createNew | ||
44 | ) | ||
49 | } | 45 | } |
50 | 46 | ||
51 | override getComparator() { Comparators.LOWER_IS_BETTER } | 47 | override getComparator() { Comparators.LOWER_IS_BETTER } |
48 | |||
52 | override getFitness(ThreadContext context) { | 49 | override getFitness(ThreadContext context) { |
53 | var sum = 0.0 | 50 | var sum = 0.0 |
54 | val scopeFitnes = scopeObjective.getFitness(context) | 51 | val scopeFitnes = scopeObjective.getFitness(context) |
55 | //val unfinishedMultiplicitiesFitneses = unfinishedMultiplicityObjectives.map[x|x.getFitness(context)] | 52 | // val unfinishedMultiplicitiesFitneses = unfinishedMultiplicityObjectives.map[x|x.getFitness(context)] |
56 | val unfinishedWFsFitness = unfinishedWFObjective.getFitness(context) | 53 | val unfinishedWFsFitness = unfinishedWFObjective.getFitness(context) |
57 | 54 | ||
58 | sum+=scopeFitnes | 55 | sum += scopeFitnes |
59 | var multiplicity = 0.0 | 56 | var multiplicity = 0.0 |
60 | for(multiplicityObjective : unfinishedMultiplicityObjectives) { | 57 | for (multiplicityObjective : unfinishedMultiplicityObjectives) { |
61 | multiplicity+=multiplicityObjective.getFitness(context)//*0.5 | 58 | multiplicity += multiplicityObjective.getFitness(context) // *0.5 |
62 | } | 59 | } |
63 | sum+=multiplicity | 60 | sum += multiplicity |
64 | sum += unfinishedWFsFitness//*0.5 | 61 | sum += unfinishedWFsFitness // *0.5 |
65 | 62 | // println('''Sum=«sum»|Scope=«scopeFitnes»|Multiplicity=«multiplicity»|WFs=«unfinishedWFsFitness»''') | |
66 | //println('''Sum=«sum»|Scope=«scopeFitnes»|Multiplicity=«multiplicity»|WFs=«unfinishedWFsFitness»''') | ||
67 | |||
68 | return sum | 63 | return sum |
69 | } | 64 | } |
70 | 65 | ||
71 | override getLevel() { 2 } | 66 | override getWorstPossibleFitness(ThreadContext threadContext) { |
72 | override getName() { "CompositeUnfinishednessObjective"} | 67 | Double.POSITIVE_INFINITY |
68 | } | ||
73 | 69 | ||
70 | override getBestPossibleFitness(ThreadContext threadContext) { | ||
71 | 0.0 | ||
72 | } | ||
73 | |||
74 | override getLevel() { 2 } | ||
75 | |||
76 | override getName() { "CompositeUnfinishednessObjective" } | ||
77 | |||
74 | override isHardObjective() { true } | 78 | override isHardObjective() { true } |
79 | |||
75 | override satisifiesHardObjective(Double fitness) { fitness <= 0.001 } | 80 | override satisifiesHardObjective(Double fitness) { fitness <= 0.001 } |
76 | 81 | ||
77 | |||
78 | override setComparator(Comparator<Double> comparator) { | 82 | override setComparator(Comparator<Double> comparator) { |
79 | throw new UnsupportedOperationException("TODO: auto-generated method stub") | 83 | throw new UnsupportedOperationException("Model generation objective comparator cannot be set.") |
80 | } | 84 | } |
85 | |||
81 | override setLevel(int level) { | 86 | override setLevel(int level) { |
82 | throw new UnsupportedOperationException("TODO: auto-generated method stub") | 87 | throw new UnsupportedOperationException("Model generation objective level cannot be set.") |
83 | } | 88 | } |
84 | 89 | } | |
85 | } \ No newline at end of file | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/SolutionCopier.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/SolutionCopier.xtend new file mode 100644 index 00000000..d036257d --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/SolutionCopier.xtend | |||
@@ -0,0 +1,74 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse | ||
2 | |||
3 | import com.google.common.collect.ImmutableList | ||
4 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | ||
5 | import java.util.LinkedHashMap | ||
6 | import java.util.List | ||
7 | import java.util.Map | ||
8 | import org.eclipse.emf.ecore.EObject | ||
9 | import org.eclipse.emf.ecore.util.EcoreUtil | ||
10 | import org.eclipse.viatra.dse.base.ThreadContext | ||
11 | import org.eclipse.xtend.lib.annotations.Accessors | ||
12 | import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor | ||
13 | |||
14 | @FinalFieldsConstructor | ||
15 | class CopiedSolution { | ||
16 | @Accessors val PartialInterpretation partialInterpretations | ||
17 | @Accessors val Map<EObject, EObject> trace | ||
18 | @Accessors val long copierRuntime | ||
19 | @Accessors var boolean current = true | ||
20 | } | ||
21 | |||
22 | class SolutionCopier { | ||
23 | val copiedSolutions = new LinkedHashMap<Object, CopiedSolution> | ||
24 | |||
25 | long startTime = System.nanoTime | ||
26 | @Accessors(PUBLIC_GETTER) long totalCopierRuntime = 0 | ||
27 | |||
28 | def void copySolution(ThreadContext context, Object solutionId) { | ||
29 | val existingCopy = copiedSolutions.get(solutionId) | ||
30 | if (existingCopy === null) { | ||
31 | val copyStart = System.nanoTime | ||
32 | val solution = context.model as PartialInterpretation | ||
33 | val copier = new EcoreUtil.Copier | ||
34 | val copiedPartialInterpretation = copier.copy(solution) as PartialInterpretation | ||
35 | copier.copyReferences | ||
36 | totalCopierRuntime += System.nanoTime - copyStart | ||
37 | val copierRuntime = System.nanoTime - startTime | ||
38 | val copiedSolution = new CopiedSolution(copiedPartialInterpretation, copier, copierRuntime) | ||
39 | copiedSolutions.put(solutionId, copiedSolution) | ||
40 | } else { | ||
41 | existingCopy.current = true | ||
42 | } | ||
43 | } | ||
44 | |||
45 | def void markAsObsolete(Object solutionId) { | ||
46 | val copiedSolution = copiedSolutions.get(solutionId) | ||
47 | if (copiedSolution === null) { | ||
48 | throw new IllegalStateException("No solution to mark as obsolete for state code: " + solutionId) | ||
49 | } | ||
50 | copiedSolution.current = false | ||
51 | } | ||
52 | |||
53 | def List<PartialInterpretation> getPartialInterpretations(boolean currentOnly) { | ||
54 | getListOfCopiedSolutions(currentOnly).map[partialInterpretations] | ||
55 | } | ||
56 | |||
57 | def List<Map<EObject, EObject>> getTraces(boolean currentOnly) { | ||
58 | getListOfCopiedSolutions(currentOnly).map[trace] | ||
59 | } | ||
60 | |||
61 | def List<Long> getAllCopierRuntimes(boolean currentOnly) { | ||
62 | getListOfCopiedSolutions(currentOnly).map[copierRuntime] | ||
63 | } | ||
64 | |||
65 | def List<CopiedSolution> getListOfCopiedSolutions(boolean currentOnly) { | ||
66 | val values = copiedSolutions.values | ||
67 | val filteredSolutions = if (currentOnly) { | ||
68 | values.filter[current] | ||
69 | } else { | ||
70 | values | ||
71 | } | ||
72 | ImmutableList.copyOf(filteredSolutions) | ||
73 | } | ||
74 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/SolutionStoreWithCopy.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/SolutionStoreWithCopy.xtend deleted file mode 100644 index a8b7301e..00000000 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/SolutionStoreWithCopy.xtend +++ /dev/null | |||
@@ -1,52 +0,0 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse | ||
2 | |||
3 | import java.util.List | ||
4 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | ||
5 | import java.util.LinkedList | ||
6 | import org.eclipse.emf.ecore.EObject | ||
7 | import java.util.Map | ||
8 | import org.eclipse.emf.ecore.util.EcoreUtil | ||
9 | import org.eclipse.viatra.dse.base.ThreadContext | ||
10 | import java.util.TreeMap | ||
11 | import java.util.SortedMap | ||
12 | |||
13 | class SolutionStoreWithCopy { | ||
14 | |||
15 | long runtime = 0 | ||
16 | List<PartialInterpretation> solutions = new LinkedList | ||
17 | //public List<SortedMap<String,Integer>> additionalMatches = new LinkedList | ||
18 | List<Map<EObject,EObject>> copyTraces = new LinkedList | ||
19 | |||
20 | long sartTime = System.nanoTime | ||
21 | List<Long> solutionTimes = new LinkedList | ||
22 | |||
23 | /*def newSolution(ThreadContext context, SortedMap<String,Integer> additonalMatch) { | ||
24 | additionalMatches+= additonalMatch | ||
25 | newSolution(context) | ||
26 | }*/ | ||
27 | |||
28 | def newSolution(ThreadContext context) { | ||
29 | //print(System.nanoTime-initTime + ";") | ||
30 | val copyStart = System.nanoTime | ||
31 | val solution = context.model as PartialInterpretation | ||
32 | val copier = new EcoreUtil.Copier | ||
33 | val solutionCopy = copier.copy(solution) as PartialInterpretation | ||
34 | copier.copyReferences | ||
35 | solutions.add(solutionCopy) | ||
36 | copyTraces.add(copier) | ||
37 | runtime += System.nanoTime - copyStart | ||
38 | solutionTimes.add(System.nanoTime-sartTime) | ||
39 | } | ||
40 | def getSumRuntime() { | ||
41 | return runtime | ||
42 | } | ||
43 | def getAllRuntimes() { | ||
44 | return solutionTimes | ||
45 | } | ||
46 | def getSolutions() { | ||
47 | solutions | ||
48 | } | ||
49 | def getCopyTraces() { | ||
50 | return copyTraces | ||
51 | } | ||
52 | } \ No newline at end of file | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/SolutionStoreWithDiversityDescriptor.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/SolutionStoreWithDiversityDescriptor.xtend deleted file mode 100644 index 1e7f18a8..00000000 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/SolutionStoreWithDiversityDescriptor.xtend +++ /dev/null | |||
@@ -1,120 +0,0 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse | ||
2 | |||
3 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.neighbourhood.PartialInterpretation2ImmutableTypeLattice | ||
4 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | ||
5 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.DiversityDescriptor | ||
6 | import java.util.LinkedList | ||
7 | import java.util.List | ||
8 | import org.eclipse.viatra.dse.base.ThreadContext | ||
9 | import java.util.HashSet | ||
10 | import java.util.Set | ||
11 | |||
12 | enum DiversityGranularity { | ||
13 | Nodewise, Graphwise | ||
14 | } | ||
15 | |||
16 | class SolutionStoreWithDiversityDescriptor { | ||
17 | val DiversityDescriptor descriptor | ||
18 | DiversityGranularity granularity | ||
19 | val PartialInterpretation2ImmutableTypeLattice solutionCoder = new PartialInterpretation2ImmutableTypeLattice | ||
20 | val Set<Integer> solutionCodeList = new HashSet | ||
21 | |||
22 | var long runtime | ||
23 | var int allCheck | ||
24 | var int successfulCheck | ||
25 | |||
26 | new(DiversityDescriptor descriptor) { | ||
27 | if(descriptor.ensureDiversity) { | ||
28 | this.descriptor = descriptor | ||
29 | this.granularity = DiversityGranularity::Nodewise | ||
30 | } else { | ||
31 | this.descriptor = null | ||
32 | this.granularity = DiversityGranularity::Nodewise | ||
33 | } | ||
34 | } | ||
35 | |||
36 | def public isActive() { | ||
37 | descriptor!==null | ||
38 | } | ||
39 | |||
40 | def getSumRuntime() { | ||
41 | return runtime | ||
42 | } | ||
43 | def getSuccessRate() { | ||
44 | return successfulCheck as double / allCheck | ||
45 | } | ||
46 | |||
47 | def isDifferent(ThreadContext context) { | ||
48 | if(active) { | ||
49 | val start = System.nanoTime | ||
50 | val model = context.model as PartialInterpretation | ||
51 | var boolean isDifferent | ||
52 | if(this.granularity == DiversityGranularity::Graphwise) { | ||
53 | val code = solutionCoder.createRepresentation(model, | ||
54 | descriptor.range, | ||
55 | descriptor.parallels, | ||
56 | descriptor.maxNumber, | ||
57 | descriptor.relevantTypes, | ||
58 | descriptor.relevantRelations).modelRepresentation.hashCode | ||
59 | |||
60 | isDifferent = !solutionCodeList.contains(code) | ||
61 | } else if(this.granularity == DiversityGranularity::Nodewise){ | ||
62 | val codes = solutionCoder.createRepresentation(model, | ||
63 | descriptor.range, | ||
64 | descriptor.parallels, | ||
65 | descriptor.maxNumber, | ||
66 | descriptor.relevantTypes, | ||
67 | descriptor.relevantRelations).modelRepresentation.keySet.map[hashCode].toList | ||
68 | val differentCodes = codes.filter[!solutionCodeList.contains(it)] | ||
69 | //println(differentCodes.size) | ||
70 | |||
71 | isDifferent = differentCodes.size>=1 | ||
72 | } else { | ||
73 | throw new UnsupportedOperationException('''Unsupported diversity type: «this.granularity»''') | ||
74 | } | ||
75 | |||
76 | runtime += System.nanoTime - start | ||
77 | allCheck++ | ||
78 | if(isDifferent) { successfulCheck++ } | ||
79 | return isDifferent | ||
80 | } else { | ||
81 | allCheck++ | ||
82 | successfulCheck++ | ||
83 | return true | ||
84 | } | ||
85 | } | ||
86 | |||
87 | def canBeDifferent(ThreadContext context) { | ||
88 | return true | ||
89 | } | ||
90 | |||
91 | def newSolution(ThreadContext context) { | ||
92 | if(active) { | ||
93 | val start = System.nanoTime | ||
94 | val model = context.model as PartialInterpretation | ||
95 | if(this.granularity == DiversityGranularity::Graphwise) { | ||
96 | val code = solutionCoder.createRepresentation(model, | ||
97 | descriptor.range, | ||
98 | descriptor.parallels, | ||
99 | descriptor.maxNumber, | ||
100 | descriptor.relevantTypes, | ||
101 | descriptor.relevantRelations).modelRepresentation.hashCode | ||
102 | |||
103 | solutionCodeList += code.hashCode | ||
104 | } else if(this.granularity == DiversityGranularity::Nodewise){ | ||
105 | val codes = solutionCoder.createRepresentation(model, | ||
106 | descriptor.range, | ||
107 | descriptor.parallels, | ||
108 | descriptor.maxNumber, | ||
109 | descriptor.relevantTypes, | ||
110 | descriptor.relevantRelations).modelRepresentation.keySet.map[hashCode].toList | ||
111 | |||
112 | solutionCodeList += codes.map[it.hashCode] | ||
113 | } else { | ||
114 | throw new UnsupportedOperationException('''Unsupported diversity type: «this.granularity»''') | ||
115 | } | ||
116 | |||
117 | runtime += System.nanoTime - start | ||
118 | } | ||
119 | } | ||
120 | } \ No newline at end of file | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/SurelyViolatedObjectiveGlobalConstraint.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/SurelyViolatedObjectiveGlobalConstraint.xtend new file mode 100644 index 00000000..8ed3e912 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/SurelyViolatedObjectiveGlobalConstraint.xtend | |||
@@ -0,0 +1,27 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse | ||
2 | |||
3 | import org.eclipse.viatra.dse.base.ThreadContext | ||
4 | import org.eclipse.viatra.dse.objectives.IGlobalConstraint | ||
5 | import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor | ||
6 | |||
7 | @FinalFieldsConstructor | ||
8 | class SurelyViolatedObjectiveGlobalConstraint implements IGlobalConstraint { | ||
9 | val ViatraReasonerSolutionSaver solutionSaver | ||
10 | |||
11 | override init(ThreadContext context) { | ||
12 | // Nothing to initialize. | ||
13 | } | ||
14 | |||
15 | override createNew() { | ||
16 | this | ||
17 | } | ||
18 | |||
19 | override getName() { | ||
20 | class.name | ||
21 | } | ||
22 | |||
23 | override checkGlobalConstraint(ThreadContext context) { | ||
24 | val bestFitness = DseUtils.caclulateBestPossibleFitness(context) | ||
25 | bestFitness.satisifiesHardObjectives && solutionSaver.fitnessMayBeSaved(bestFitness) | ||
26 | } | ||
27 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/UnfinishedMultiplicityObjective.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/UnfinishedMultiplicityObjective.xtend index aad9a448..9f0c642f 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/UnfinishedMultiplicityObjective.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/UnfinishedMultiplicityObjective.xtend | |||
@@ -1,15 +1,15 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse | 1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse |
2 | 2 | ||
3 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.MultiplicityGoalConstraintCalculator | 3 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.MultiplicityGoalConstraintCalculator |
4 | import java.util.Comparator | 4 | import java.util.Comparator |
5 | import org.eclipse.viatra.dse.base.ThreadContext | 5 | import org.eclipse.viatra.dse.base.ThreadContext |
6 | import org.eclipse.viatra.dse.objectives.IObjective | ||
7 | import org.eclipse.viatra.dse.objectives.Comparators | 6 | import org.eclipse.viatra.dse.objectives.Comparators |
7 | import org.eclipse.viatra.dse.objectives.IObjective | ||
8 | 8 | ||
9 | class UnfinishedMultiplicityObjective implements IObjective { | 9 | class UnfinishedMultiplicityObjective implements IObjective { |
10 | val MultiplicityGoalConstraintCalculator unfinishedMultiplicity; | 10 | val MultiplicityGoalConstraintCalculator unfinishedMultiplicity; |
11 | 11 | ||
12 | public new(MultiplicityGoalConstraintCalculator unfinishedMultiplicity) { | 12 | new(MultiplicityGoalConstraintCalculator unfinishedMultiplicity) { |
13 | this.unfinishedMultiplicity = unfinishedMultiplicity | 13 | this.unfinishedMultiplicity = unfinishedMultiplicity |
14 | } | 14 | } |
15 | 15 | ||
@@ -29,9 +29,9 @@ class UnfinishedMultiplicityObjective implements IObjective { | |||
29 | override satisifiesHardObjective(Double fitness) { return fitness <=0.01 } | 29 | override satisifiesHardObjective(Double fitness) { return fitness <=0.01 } |
30 | 30 | ||
31 | override setComparator(Comparator<Double> comparator) { | 31 | override setComparator(Comparator<Double> comparator) { |
32 | throw new UnsupportedOperationException("TODO: auto-generated method stub") | 32 | throw new UnsupportedOperationException |
33 | } | 33 | } |
34 | override setLevel(int level) { | 34 | override setLevel(int level) { |
35 | throw new UnsupportedOperationException("TODO: auto-generated method stub") | 35 | throw new UnsupportedOperationException |
36 | } | 36 | } |
37 | } \ No newline at end of file | 37 | } |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/UnfinishedWFObjective.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/UnfinishedWFObjective.xtend index e0111cf6..bf34aeeb 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/UnfinishedWFObjective.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/UnfinishedWFObjective.xtend | |||
@@ -1,23 +1,21 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse | 1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse |
2 | 2 | ||
3 | import org.eclipse.viatra.dse.objectives.IObjective | 3 | import java.util.ArrayList |
4 | import org.eclipse.viatra.query.runtime.api.IPatternMatch | ||
5 | import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher | ||
6 | import org.eclipse.viatra.query.runtime.api.IQuerySpecification | ||
7 | import java.util.Collection | 4 | import java.util.Collection |
8 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine | 5 | import java.util.Comparator |
9 | import org.eclipse.viatra.query.runtime.emf.EMFScope | ||
10 | import org.eclipse.viatra.dse.base.ThreadContext | ||
11 | import java.util.List | 6 | import java.util.List |
7 | import org.eclipse.viatra.dse.base.ThreadContext | ||
12 | import org.eclipse.viatra.dse.objectives.Comparators | 8 | import org.eclipse.viatra.dse.objectives.Comparators |
13 | import java.util.ArrayList | 9 | import org.eclipse.viatra.dse.objectives.IObjective |
14 | import java.util.Comparator | 10 | import org.eclipse.viatra.query.runtime.api.IPatternMatch |
11 | import org.eclipse.viatra.query.runtime.api.IQuerySpecification | ||
12 | import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher | ||
15 | 13 | ||
16 | class UnfinishedWFObjective implements IObjective { | 14 | class UnfinishedWFObjective implements IObjective { |
17 | Collection<? extends IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> unfinishedWFs | 15 | Collection<? extends IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> unfinishedWFs |
18 | val List<ViatraQueryMatcher<?>> matchers | 16 | val List<ViatraQueryMatcher<?>> matchers |
19 | 17 | ||
20 | public new(Collection<? extends IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> unfinishedWFs) { | 18 | new(Collection<? extends IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> unfinishedWFs) { |
21 | this.unfinishedWFs = unfinishedWFs | 19 | this.unfinishedWFs = unfinishedWFs |
22 | matchers = new ArrayList(unfinishedWFs.size) | 20 | matchers = new ArrayList(unfinishedWFs.size) |
23 | } | 21 | } |
@@ -48,9 +46,9 @@ class UnfinishedWFObjective implements IObjective { | |||
48 | override satisifiesHardObjective(Double fitness) { return fitness <=0.01 } | 46 | override satisifiesHardObjective(Double fitness) { return fitness <=0.01 } |
49 | 47 | ||
50 | override setComparator(Comparator<Double> comparator) { | 48 | override setComparator(Comparator<Double> comparator) { |
51 | throw new UnsupportedOperationException("TODO: auto-generated method stub") | 49 | throw new UnsupportedOperationException() |
52 | } | 50 | } |
53 | override setLevel(int level) { | 51 | override setLevel(int level) { |
54 | throw new UnsupportedOperationException("TODO: auto-generated method stub") | 52 | throw new UnsupportedOperationException() |
55 | } | 53 | } |
56 | } \ No newline at end of file | 54 | } \ No newline at end of file |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/ViatraReasonerSolutionSaver.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/ViatraReasonerSolutionSaver.xtend new file mode 100644 index 00000000..6bffeb59 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/ViatraReasonerSolutionSaver.xtend | |||
@@ -0,0 +1,137 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse | ||
2 | |||
3 | import java.util.HashMap | ||
4 | import java.util.Map | ||
5 | import org.eclipse.viatra.dse.api.DSEException | ||
6 | import org.eclipse.viatra.dse.api.Solution | ||
7 | import org.eclipse.viatra.dse.api.SolutionTrajectory | ||
8 | import org.eclipse.viatra.dse.base.ThreadContext | ||
9 | import org.eclipse.viatra.dse.objectives.Fitness | ||
10 | import org.eclipse.viatra.dse.objectives.IObjective | ||
11 | import org.eclipse.viatra.dse.objectives.ObjectiveComparatorHelper | ||
12 | import org.eclipse.viatra.dse.solutionstore.SolutionStore.ISolutionSaver | ||
13 | import org.eclipse.xtend.lib.annotations.Accessors | ||
14 | |||
15 | /** | ||
16 | * Based on {@link SolutionStore.BestSolutionSaver}. | ||
17 | */ | ||
18 | class ViatraReasonerSolutionSaver implements ISolutionSaver { | ||
19 | @Accessors val solutionCopier = new SolutionCopier | ||
20 | @Accessors val DiversityChecker diversityChecker | ||
21 | val boolean hasExtremalObjectives | ||
22 | val int numberOfRequiredSolutions | ||
23 | val ObjectiveComparatorHelper comparatorHelper | ||
24 | val Map<SolutionTrajectory, Fitness> trajectories = new HashMap | ||
25 | |||
26 | @Accessors(PUBLIC_SETTER) var Map<Object, Solution> solutionsCollection | ||
27 | |||
28 | new(IObjective[][] leveledExtremalObjectives, int numberOfRequiredSolutions, DiversityChecker diversityChecker) { | ||
29 | this.diversityChecker = diversityChecker | ||
30 | comparatorHelper = new ObjectiveComparatorHelper(leveledExtremalObjectives) | ||
31 | hasExtremalObjectives = leveledExtremalObjectives.exists[!empty] | ||
32 | this.numberOfRequiredSolutions = numberOfRequiredSolutions | ||
33 | } | ||
34 | |||
35 | override saveSolution(ThreadContext context, Object id, SolutionTrajectory solutionTrajectory) { | ||
36 | if (hasExtremalObjectives) { | ||
37 | saveBestSolutionOnly(context, id, solutionTrajectory) | ||
38 | } else { | ||
39 | saveAnyDiverseSolution(context, id, solutionTrajectory) | ||
40 | } | ||
41 | } | ||
42 | |||
43 | private def saveBestSolutionOnly(ThreadContext context, Object id, SolutionTrajectory solutionTrajectory) { | ||
44 | val fitness = context.lastFitness | ||
45 | if (!fitness.satisifiesHardObjectives) { | ||
46 | return false | ||
47 | } | ||
48 | val dominatedTrajectories = newArrayList | ||
49 | for (entry : trajectories.entrySet) { | ||
50 | val isLastFitnessBetter = comparatorHelper.compare(fitness, entry.value) | ||
51 | if (isLastFitnessBetter < 0) { | ||
52 | // Found a trajectory that dominates the current one, no need to save | ||
53 | return false | ||
54 | } | ||
55 | if (isLastFitnessBetter > 0) { | ||
56 | dominatedTrajectories += entry.key | ||
57 | } | ||
58 | } | ||
59 | if (dominatedTrajectories.size == 0 && !needsMoreSolutionsWithSameFitness) { | ||
60 | return false | ||
61 | } | ||
62 | if (!diversityChecker.newSolution(context, id, dominatedTrajectories.map[solution.stateCode])) { | ||
63 | return false | ||
64 | } | ||
65 | // We must save the new trajectory before removing dominated trajectories | ||
66 | // to avoid removing the current solution when it is reachable only via dominated trajectories. | ||
67 | val solutionSaved = basicSaveSolution(context, id, solutionTrajectory, fitness) | ||
68 | for (dominatedTrajectory : dominatedTrajectories) { | ||
69 | trajectories -= dominatedTrajectory | ||
70 | val dominatedSolution = dominatedTrajectory.solution | ||
71 | if (!dominatedSolution.trajectories.remove(dominatedTrajectory)) { | ||
72 | throw new DSEException( | ||
73 | "Dominated solution is not reachable from dominated trajectory. This should never happen!") | ||
74 | } | ||
75 | if (dominatedSolution.trajectories.empty) { | ||
76 | val dominatedSolutionId = dominatedSolution.stateCode | ||
77 | solutionCopier.markAsObsolete(dominatedSolutionId) | ||
78 | solutionsCollection -= dominatedSolutionId | ||
79 | } | ||
80 | } | ||
81 | solutionSaved | ||
82 | } | ||
83 | |||
84 | private def saveAnyDiverseSolution(ThreadContext context, Object id, SolutionTrajectory solutionTrajectory) { | ||
85 | val fitness = context.lastFitness | ||
86 | if (!fitness.satisifiesHardObjectives) { | ||
87 | return false | ||
88 | } | ||
89 | if (!diversityChecker.newSolution(context, id, emptyList)) { | ||
90 | return false | ||
91 | } | ||
92 | basicSaveSolution(context, id, solutionTrajectory, fitness) | ||
93 | } | ||
94 | |||
95 | private def basicSaveSolution(ThreadContext context, Object id, SolutionTrajectory solutionTrajectory, Fitness fitness) { | ||
96 | var boolean solutionSaved = false | ||
97 | var dseSolution = solutionsCollection.get(id) | ||
98 | if (dseSolution === null) { | ||
99 | solutionCopier.copySolution(context, id) | ||
100 | dseSolution = new Solution(id, solutionTrajectory) | ||
101 | solutionsCollection.put(id, dseSolution) | ||
102 | solutionSaved = true | ||
103 | } else { | ||
104 | solutionSaved = dseSolution.trajectories.add(solutionTrajectory) | ||
105 | } | ||
106 | if (solutionSaved) { | ||
107 | solutionTrajectory.solution = dseSolution | ||
108 | trajectories.put(solutionTrajectory, fitness) | ||
109 | } | ||
110 | solutionSaved | ||
111 | } | ||
112 | |||
113 | def fitnessMayBeSaved(Fitness fitness) { | ||
114 | if (!hasExtremalObjectives) { | ||
115 | return true | ||
116 | } | ||
117 | var boolean mayDominate | ||
118 | for (existingFitness : trajectories.values) { | ||
119 | val isNewFitnessBetter = comparatorHelper.compare(fitness, existingFitness) | ||
120 | if (isNewFitnessBetter < 0) { | ||
121 | return false | ||
122 | } | ||
123 | if (isNewFitnessBetter > 0) { | ||
124 | mayDominate = true | ||
125 | } | ||
126 | } | ||
127 | mayDominate || needsMoreSolutionsWithSameFitness | ||
128 | } | ||
129 | |||
130 | private def boolean needsMoreSolutionsWithSameFitness() { | ||
131 | if (solutionsCollection === null) { | ||
132 | // The solutions collection will only be initialized upon saving the first solution. | ||
133 | return true | ||
134 | } | ||
135 | solutionsCollection.size < numberOfRequiredSolutions | ||
136 | } | ||
137 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/WF2ObjectiveConverter.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/WF2ObjectiveConverter.xtend index 5a528a9e..63d78220 100644 --- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/WF2ObjectiveConverter.xtend +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/dse/WF2ObjectiveConverter.xtend | |||
@@ -1,5 +1,6 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse | 1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.dse |
2 | 2 | ||
3 | import com.google.common.collect.ImmutableList | ||
3 | import java.util.ArrayList | 4 | import java.util.ArrayList |
4 | import java.util.Collection | 5 | import java.util.Collection |
5 | import org.eclipse.viatra.dse.objectives.Comparators | 6 | import org.eclipse.viatra.dse.objectives.Comparators |
@@ -12,25 +13,35 @@ import org.eclipse.viatra.query.runtime.api.IQuerySpecification | |||
12 | import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher | 13 | import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher |
13 | 14 | ||
14 | class WF2ObjectiveConverter { | 15 | class WF2ObjectiveConverter { |
15 | 16 | static val UNFINISHED_WFS_NAME = "unfinishedWFs" | |
17 | static val INVALIDATED_WFS_NAME = "invalidatedWFs" | ||
18 | |||
16 | def createCompletenessObjective( | 19 | def createCompletenessObjective( |
17 | Collection<? extends IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> unfinishedWF) | 20 | Collection<? extends IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> unfinishedWF) { |
18 | { | 21 | // createConstraintObjective(UNFINISHED_WFS_NAME, unfinishedWF) |
19 | val res = new ConstraintsObjective('''unfinishedWFs''', | 22 | new UnfinishedWFObjective(unfinishedWF) |
20 | unfinishedWF.map[ | 23 | } |
21 | new QueryConstraint(it.fullyQualifiedName,it,2.0) | 24 | |
22 | ].toList | 25 | def createInvalidationObjective( |
26 | Collection<? extends IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> invalidatedByWF) { | ||
27 | createConstraintObjective(INVALIDATED_WFS_NAME, invalidatedByWF) | ||
28 | } | ||
29 | |||
30 | def IGlobalConstraint createInvalidationGlobalConstraint( | ||
31 | Collection<? extends IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> invalidatedByWF) { | ||
32 | new ModelQueriesGlobalConstraint(INVALIDATED_WFS_NAME, new ArrayList(invalidatedByWF)) | ||
33 | } | ||
34 | |||
35 | private def createConstraintObjective(String name, | ||
36 | Collection<? extends IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> queries) { | ||
37 | val res = new ConstraintsObjective( | ||
38 | name, | ||
39 | ImmutableList.copyOf(queries.map [ | ||
40 | new QueryConstraint(it.fullyQualifiedName, it, 1.0) | ||
41 | ]) | ||
23 | ) | 42 | ) |
24 | res.withComparator(Comparators.LOWER_IS_BETTER) | 43 | res.withComparator(Comparators.LOWER_IS_BETTER) |
25 | res.level = 2 | 44 | res.level = 2 |
26 | return res | 45 | res |
27 | } | ||
28 | |||
29 | def IGlobalConstraint createInvalidationObjective( | ||
30 | Collection<? extends IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> invalidatedByWF) | ||
31 | { | ||
32 | return new ModelQueriesGlobalConstraint('''invalidatedWFs''', | ||
33 | new ArrayList(invalidatedByWF) | ||
34 | ) | ||
35 | } | 46 | } |
36 | } \ No newline at end of file | 47 | } |
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/AbstractThreeValuedObjective.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/AbstractThreeValuedObjective.xtend new file mode 100644 index 00000000..cd911ab5 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/AbstractThreeValuedObjective.xtend | |||
@@ -0,0 +1,35 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization | ||
2 | |||
3 | import org.eclipse.viatra.dse.base.ThreadContext | ||
4 | |||
5 | abstract class AbstractThreeValuedObjective extends DirectionalThresholdObjective implements IThreeValuedObjective { | ||
6 | protected new(String name, ObjectiveKind kind, ObjectiveThreshold threshold, int level) { | ||
7 | super(name, kind, threshold, level) | ||
8 | } | ||
9 | |||
10 | abstract def double getLowestPossibleFitness(ThreadContext threadContext) | ||
11 | |||
12 | abstract def double getHighestPossibleFitness(ThreadContext threadContext) | ||
13 | |||
14 | override getWorstPossibleFitness(ThreadContext threadContext) { | ||
15 | switch (kind) { | ||
16 | case LOWER_IS_BETTER: | ||
17 | getHighestPossibleFitness(threadContext) | ||
18 | case HIGHER_IS_BETTER: | ||
19 | getLowestPossibleFitness(threadContext) | ||
20 | default: | ||
21 | throw new IllegalStateException("Unknown three valued objective kind: " + kind) | ||
22 | } | ||
23 | } | ||
24 | |||
25 | override getBestPossibleFitness(ThreadContext threadContext) { | ||
26 | switch (kind) { | ||
27 | case LOWER_IS_BETTER: | ||
28 | getLowestPossibleFitness(threadContext) | ||
29 | case HIGHER_IS_BETTER: | ||
30 | getHighestPossibleFitness(threadContext) | ||
31 | default: | ||
32 | throw new IllegalStateException("Unknown three valued objective kind: " + kind) | ||
33 | } | ||
34 | } | ||
35 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/CompositeDirectionalThresholdObjective.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/CompositeDirectionalThresholdObjective.xtend new file mode 100644 index 00000000..0aa442f5 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/CompositeDirectionalThresholdObjective.xtend | |||
@@ -0,0 +1,62 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization | ||
2 | |||
3 | import com.google.common.collect.ImmutableList | ||
4 | import java.util.Collection | ||
5 | import org.eclipse.viatra.dse.base.ThreadContext | ||
6 | |||
7 | class CompositeDirectionalThresholdObjective extends DirectionalThresholdObjective { | ||
8 | val Collection<DirectionalThresholdObjective> objectives | ||
9 | |||
10 | new(String name, Collection<DirectionalThresholdObjective> objectives) { | ||
11 | this(name, objectives, getKind(objectives), getThreshold(objectives), getLevel(objectives)) | ||
12 | } | ||
13 | |||
14 | new(String name, DirectionalThresholdObjective... objectives) { | ||
15 | this(name, objectives as Collection<DirectionalThresholdObjective>) | ||
16 | } | ||
17 | |||
18 | protected new(String name, Iterable<DirectionalThresholdObjective> objectives, ObjectiveKind kind, | ||
19 | ObjectiveThreshold threshold, int level) { | ||
20 | super(name, kind, threshold, level) | ||
21 | this.objectives = ImmutableList.copyOf(objectives) | ||
22 | } | ||
23 | |||
24 | override createNew() { | ||
25 | new CompositeDirectionalThresholdObjective(name, objectives.map[createNew as DirectionalThresholdObjective], | ||
26 | kind, threshold, level) | ||
27 | } | ||
28 | |||
29 | override init(ThreadContext context) { | ||
30 | for (objective : objectives) { | ||
31 | objective.init(context) | ||
32 | } | ||
33 | } | ||
34 | |||
35 | override protected getRawFitness(ThreadContext context) { | ||
36 | var double fitness = 0 | ||
37 | for (objective : objectives) { | ||
38 | fitness += objective.getFitness(context) | ||
39 | } | ||
40 | fitness | ||
41 | } | ||
42 | |||
43 | private static def getKind(Collection<DirectionalThresholdObjective> objectives) { | ||
44 | val kinds = objectives.map[kind].toSet | ||
45 | if (kinds.size != 1) { | ||
46 | throw new IllegalArgumentException("Passed objectives must have the same kind") | ||
47 | } | ||
48 | kinds.head | ||
49 | } | ||
50 | |||
51 | private static def getThreshold(Collection<DirectionalThresholdObjective> objectives) { | ||
52 | objectives.map[threshold].reduce[a, b|a.merge(b)] | ||
53 | } | ||
54 | |||
55 | private static def int getLevel(Collection<DirectionalThresholdObjective> objectives) { | ||
56 | val levels = objectives.map[level].toSet | ||
57 | if (levels.size != 1) { | ||
58 | throw new IllegalArgumentException("Passed objectives must have the same level") | ||
59 | } | ||
60 | levels.head | ||
61 | } | ||
62 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/DirectionalThresholdObjective.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/DirectionalThresholdObjective.xtend new file mode 100644 index 00000000..376e3d1a --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/DirectionalThresholdObjective.xtend | |||
@@ -0,0 +1,164 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization | ||
2 | |||
3 | import java.util.Comparator | ||
4 | import org.eclipse.viatra.dse.base.ThreadContext | ||
5 | import org.eclipse.viatra.dse.objectives.IObjective | ||
6 | import org.eclipse.xtend.lib.annotations.Accessors | ||
7 | import org.eclipse.xtend.lib.annotations.Data | ||
8 | import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor | ||
9 | |||
10 | abstract class ObjectiveThreshold { | ||
11 | public static val NO_THRESHOLD = new ObjectiveThreshold { | ||
12 | override isHard() { | ||
13 | false | ||
14 | } | ||
15 | |||
16 | override satisfiesThreshold(double cost, Comparator<Double> comparator) { | ||
17 | true | ||
18 | } | ||
19 | |||
20 | override protected postProcessSatisfactoryCost(double cost, ObjectiveKind kind) { | ||
21 | cost | ||
22 | } | ||
23 | |||
24 | override ObjectiveThreshold merge(ObjectiveThreshold other) { | ||
25 | if (other == NO_THRESHOLD) { | ||
26 | NO_THRESHOLD | ||
27 | } else { | ||
28 | throw new IllegalArgumentException("Merged thresholds must have the same type") | ||
29 | } | ||
30 | } | ||
31 | } | ||
32 | |||
33 | private new() { | ||
34 | } | ||
35 | |||
36 | def boolean isHard() { | ||
37 | true | ||
38 | } | ||
39 | |||
40 | def boolean satisfiesThreshold(double cost, ObjectiveKind kind) { | ||
41 | satisfiesThreshold(cost, kind.comparator) | ||
42 | } | ||
43 | |||
44 | def boolean satisfiesThreshold(double cost, Comparator<Double> comparator) | ||
45 | |||
46 | def double postProcessCost(double cost, ObjectiveKind kind) { | ||
47 | if (satisfiesThreshold(cost, kind)) { | ||
48 | postProcessSatisfactoryCost(cost, kind) | ||
49 | } else { | ||
50 | cost | ||
51 | } | ||
52 | } | ||
53 | |||
54 | protected def double postProcessSatisfactoryCost(double cost, ObjectiveKind kind) | ||
55 | |||
56 | def ObjectiveThreshold merge(ObjectiveThreshold other) | ||
57 | |||
58 | @Data | ||
59 | static class Exclusive extends ObjectiveThreshold { | ||
60 | static val EPSILON = 0.1 | ||
61 | |||
62 | val double threshold | ||
63 | val boolean clampToThreshold | ||
64 | |||
65 | @FinalFieldsConstructor | ||
66 | new() { | ||
67 | } | ||
68 | |||
69 | new(double threshold) { | ||
70 | this(threshold, true) | ||
71 | } | ||
72 | |||
73 | override satisfiesThreshold(double cost, Comparator<Double> comparator) { | ||
74 | comparator.compare(threshold, cost) < 0 | ||
75 | } | ||
76 | |||
77 | override protected postProcessSatisfactoryCost(double cost, ObjectiveKind kind) { | ||
78 | if (clampToThreshold) { | ||
79 | threshold + Math.signum(kind.satisfiedValue) * EPSILON | ||
80 | } else { | ||
81 | cost | ||
82 | } | ||
83 | } | ||
84 | |||
85 | override ObjectiveThreshold merge(ObjectiveThreshold other) { | ||
86 | if (other instanceof Exclusive) { | ||
87 | new Exclusive(threshold + other.threshold) | ||
88 | } else { | ||
89 | throw new IllegalArgumentException("Merged thresholds must have the same type") | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | |||
94 | @Data | ||
95 | static class Inclusive extends ObjectiveThreshold { | ||
96 | val double threshold | ||
97 | val boolean clampToThreshold | ||
98 | |||
99 | @FinalFieldsConstructor | ||
100 | new() { | ||
101 | } | ||
102 | |||
103 | new(double threshold) { | ||
104 | this(threshold, true) | ||
105 | } | ||
106 | |||
107 | override satisfiesThreshold(double cost, Comparator<Double> comparator) { | ||
108 | comparator.compare(threshold, cost) <= 0 | ||
109 | } | ||
110 | |||
111 | override protected postProcessSatisfactoryCost(double cost, ObjectiveKind kind) { | ||
112 | if (clampToThreshold) { | ||
113 | threshold | ||
114 | } else { | ||
115 | cost | ||
116 | } | ||
117 | } | ||
118 | |||
119 | override ObjectiveThreshold merge(ObjectiveThreshold other) { | ||
120 | if (other instanceof Inclusive) { | ||
121 | new Inclusive(threshold + other.threshold) | ||
122 | } else { | ||
123 | throw new IllegalArgumentException("Merged thresholds must have the same type") | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | |||
129 | abstract class DirectionalThresholdObjective implements IObjective { | ||
130 | @Accessors val String name | ||
131 | @Accessors ObjectiveKind kind | ||
132 | @Accessors ObjectiveThreshold threshold | ||
133 | @Accessors int level | ||
134 | |||
135 | protected new(String name, ObjectiveKind kind, ObjectiveThreshold threshold, int level) { | ||
136 | this.name = name | ||
137 | this.kind = kind | ||
138 | this.threshold = threshold | ||
139 | this.level = level | ||
140 | } | ||
141 | |||
142 | override isHardObjective() { | ||
143 | threshold.hard | ||
144 | } | ||
145 | |||
146 | override satisifiesHardObjective(Double fitness) { | ||
147 | threshold.satisfiesThreshold(fitness, comparator) | ||
148 | } | ||
149 | |||
150 | override getComparator() { | ||
151 | kind.comparator | ||
152 | } | ||
153 | |||
154 | override setComparator(Comparator<Double> comparator) { | ||
155 | kind = ObjectiveKind.fromComparator(comparator) | ||
156 | } | ||
157 | |||
158 | override getFitness(ThreadContext context) { | ||
159 | val fitness = getRawFitness(context) | ||
160 | threshold.postProcessCost(fitness, kind) | ||
161 | } | ||
162 | |||
163 | protected def double getRawFitness(ThreadContext context) | ||
164 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/IThreeValuedObjective.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/IThreeValuedObjective.xtend new file mode 100644 index 00000000..4a870a3e --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/IThreeValuedObjective.xtend | |||
@@ -0,0 +1,10 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization | ||
2 | |||
3 | import org.eclipse.viatra.dse.base.ThreadContext | ||
4 | import org.eclipse.viatra.dse.objectives.IObjective | ||
5 | |||
6 | interface IThreeValuedObjective extends IObjective { | ||
7 | def Double getWorstPossibleFitness(ThreadContext threadContext) | ||
8 | |||
9 | def Double getBestPossibleFitness(ThreadContext threadContext) | ||
10 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/MatchCostObjective.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/MatchCostObjective.xtend new file mode 100644 index 00000000..a0c6a2c1 --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/MatchCostObjective.xtend | |||
@@ -0,0 +1,52 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization | ||
2 | |||
3 | import com.google.common.collect.ImmutableList | ||
4 | import java.util.Collection | ||
5 | import org.eclipse.viatra.dse.base.ThreadContext | ||
6 | import org.eclipse.viatra.query.runtime.api.IPatternMatch | ||
7 | import org.eclipse.viatra.query.runtime.api.IQuerySpecification | ||
8 | import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher | ||
9 | import org.eclipse.xtend.lib.annotations.Data | ||
10 | |||
11 | @Data | ||
12 | class MatchCostElement { | ||
13 | val IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> querySpecification | ||
14 | val double weight | ||
15 | } | ||
16 | |||
17 | class MatchCostObjective extends DirectionalThresholdObjective { | ||
18 | val Collection<MatchCostElement> costElements | ||
19 | Collection<CostElementMatcher> matchers | ||
20 | |||
21 | new(String name, Collection<MatchCostElement> costElements, ObjectiveKind kind, ObjectiveThreshold threshold, | ||
22 | int level) { | ||
23 | super(name, kind, threshold, level) | ||
24 | this.costElements = costElements | ||
25 | } | ||
26 | |||
27 | override createNew() { | ||
28 | new MatchCostObjective(name, costElements, kind, threshold, level) | ||
29 | } | ||
30 | |||
31 | override init(ThreadContext context) { | ||
32 | val queryEngine = context.queryEngine | ||
33 | matchers = ImmutableList.copyOf(costElements.map [ | ||
34 | val matcher = querySpecification.getMatcher(queryEngine) | ||
35 | new CostElementMatcher(matcher, weight) | ||
36 | ]) | ||
37 | } | ||
38 | |||
39 | override protected getRawFitness(ThreadContext context) { | ||
40 | var double cost = 0 | ||
41 | for (it : matchers) { | ||
42 | cost += weight * matcher.countMatches | ||
43 | } | ||
44 | cost | ||
45 | } | ||
46 | |||
47 | @Data | ||
48 | private static class CostElementMatcher { | ||
49 | val ViatraQueryMatcher<? extends IPatternMatch> matcher | ||
50 | val double weight | ||
51 | } | ||
52 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/ObjectiveKind.java b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/ObjectiveKind.java new file mode 100644 index 00000000..cbbaaafd --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/ObjectiveKind.java | |||
@@ -0,0 +1,60 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization; | ||
2 | |||
3 | import java.util.Comparator; | ||
4 | |||
5 | import org.eclipse.viatra.dse.objectives.Comparators; | ||
6 | |||
7 | public enum ObjectiveKind { | ||
8 | LOWER_IS_BETTER { | ||
9 | |||
10 | @Override | ||
11 | public Comparator<Double> getComparator() { | ||
12 | return Comparators.LOWER_IS_BETTER; | ||
13 | } | ||
14 | |||
15 | @Override | ||
16 | public double getInvalidValue() { | ||
17 | return Double.POSITIVE_INFINITY; | ||
18 | } | ||
19 | |||
20 | @Override | ||
21 | public double getSatisfiedValue() { | ||
22 | return Double.NEGATIVE_INFINITY; | ||
23 | } | ||
24 | |||
25 | }, | ||
26 | HIGHER_IS_BETTER { | ||
27 | |||
28 | @Override | ||
29 | public Comparator<Double> getComparator() { | ||
30 | return Comparators.HIGHER_IS_BETTER; | ||
31 | } | ||
32 | |||
33 | @Override | ||
34 | public double getInvalidValue() { | ||
35 | return Double.NEGATIVE_INFINITY; | ||
36 | } | ||
37 | |||
38 | @Override | ||
39 | public double getSatisfiedValue() { | ||
40 | return Double.POSITIVE_INFINITY; | ||
41 | } | ||
42 | |||
43 | }; | ||
44 | |||
45 | public abstract Comparator<Double> getComparator(); | ||
46 | |||
47 | public abstract double getInvalidValue(); | ||
48 | |||
49 | public abstract double getSatisfiedValue(); | ||
50 | |||
51 | public static ObjectiveKind fromComparator(Comparator<Double> comparator) { | ||
52 | if (Comparators.LOWER_IS_BETTER.equals(comparator)) { | ||
53 | return ObjectiveKind.LOWER_IS_BETTER; | ||
54 | } else if (Comparators.HIGHER_IS_BETTER.equals(comparator)) { | ||
55 | return ObjectiveKind.HIGHER_IS_BETTER; | ||
56 | } else { | ||
57 | throw new IllegalStateException("Only LOWER_IS_BETTER and HIGHER_IS_BETTER comparators are supported."); | ||
58 | } | ||
59 | } | ||
60 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/QueryBasedObjective.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/QueryBasedObjective.xtend new file mode 100644 index 00000000..d355f5be --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/QueryBasedObjective.xtend | |||
@@ -0,0 +1,48 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization | ||
2 | |||
3 | import org.eclipse.viatra.dse.base.ThreadContext | ||
4 | import org.eclipse.viatra.query.runtime.api.IPatternMatch | ||
5 | import org.eclipse.viatra.query.runtime.api.IQuerySpecification | ||
6 | import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher | ||
7 | |||
8 | class QueryBasedObjective extends DirectionalThresholdObjective { | ||
9 | val IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> querySpecification | ||
10 | ViatraQueryMatcher<? extends IPatternMatch> matcher | ||
11 | |||
12 | new(IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> querySpecification, | ||
13 | ObjectiveKind kind, ObjectiveThreshold threshold, int level) { | ||
14 | super(querySpecification.simpleName + " objective", kind, threshold, level) | ||
15 | if (querySpecification.parameters.size != 1) { | ||
16 | throw new IllegalArgumentException("Objective query must have a single parameter") | ||
17 | } | ||
18 | this.querySpecification = querySpecification | ||
19 | } | ||
20 | |||
21 | override createNew() { | ||
22 | new QueryBasedObjective(querySpecification, kind, threshold, level) | ||
23 | } | ||
24 | |||
25 | override init(ThreadContext context) { | ||
26 | matcher = querySpecification.getMatcher(context.queryEngine) | ||
27 | } | ||
28 | |||
29 | override protected getRawFitness(ThreadContext context) { | ||
30 | val iterator = matcher.allMatches.iterator | ||
31 | if (!iterator.hasNext) { | ||
32 | return invalidValue | ||
33 | } | ||
34 | val value = iterator.next.get(0) | ||
35 | if (iterator.hasNext) { | ||
36 | throw new IllegalStateException("Multiple matches for objective query") | ||
37 | } | ||
38 | if (value instanceof Number) { | ||
39 | value.doubleValue | ||
40 | } else { | ||
41 | throw new IllegalStateException("Objective value is not an instance of Number") | ||
42 | } | ||
43 | } | ||
44 | |||
45 | private def getInvalidValue() { | ||
46 | kind.invalidValue | ||
47 | } | ||
48 | } | ||
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/ThreeValuedCostObjective.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/ThreeValuedCostObjective.xtend new file mode 100644 index 00000000..0a6fd55b --- /dev/null +++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/ThreeValuedCostObjective.xtend | |||
@@ -0,0 +1,85 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization | ||
2 | |||
3 | import com.google.common.collect.ImmutableList | ||
4 | import java.util.Collection | ||
5 | import org.eclipse.viatra.dse.base.ThreadContext | ||
6 | import org.eclipse.viatra.query.runtime.api.IPatternMatch | ||
7 | import org.eclipse.viatra.query.runtime.api.IQuerySpecification | ||
8 | import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher | ||
9 | import org.eclipse.xtend.lib.annotations.Data | ||
10 | |||
11 | @Data | ||
12 | class ThreeValuedCostElement { | ||
13 | val IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> currentMatchQuery | ||
14 | val IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> mayMatchQuery | ||
15 | val IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> mustMatchQuery | ||
16 | val int weight | ||
17 | } | ||
18 | |||
19 | class ThreeValuedCostObjective extends AbstractThreeValuedObjective { | ||
20 | val Collection<ThreeValuedCostElement> costElements | ||
21 | Collection<CostElementMatchers> matchers | ||
22 | |||
23 | new(String name, Collection<ThreeValuedCostElement> costElements, ObjectiveKind kind, ObjectiveThreshold threshold, | ||
24 | int level) { | ||
25 | super(name, kind, threshold, level) | ||
26 | this.costElements = costElements | ||
27 | } | ||
28 | |||
29 | override createNew() { | ||
30 | new ThreeValuedCostObjective(name, costElements, kind, threshold, level) | ||
31 | } | ||
32 | |||
33 | override init(ThreadContext context) { | ||
34 | val queryEngine = context.queryEngine | ||
35 | matchers = ImmutableList.copyOf(costElements.map [ element | | ||
36 | new CostElementMatchers( | ||
37 | queryEngine.getMatcher(element.currentMatchQuery), | ||
38 | queryEngine.getMatcher(element.mayMatchQuery), | ||
39 | queryEngine.getMatcher(element.mustMatchQuery), | ||
40 | element.weight | ||
41 | ) | ||
42 | ]) | ||
43 | } | ||
44 | |||
45 | override getRawFitness(ThreadContext context) { | ||
46 | var int cost = 0 | ||
47 | for (matcher : matchers) { | ||
48 | cost += matcher.weight * matcher.currentMatcher.countMatches | ||
49 | } | ||
50 | cost as double | ||
51 | } | ||
52 | |||
53 | override getLowestPossibleFitness(ThreadContext threadContext) { | ||
54 | var int cost = 0 | ||
55 | for (matcher : matchers) { | ||
56 | if (matcher.weight >= 0) { | ||
57 | cost += matcher.weight * matcher.mustMatcher.countMatches | ||
58 | } else if (matcher.mayMatcher.countMatches > 0) { | ||
59 | // TODO Count may matches. | ||
60 | return Double.NEGATIVE_INFINITY | ||
61 | } | ||
62 | } | ||
63 | cost as double | ||
64 | } | ||
65 | |||
66 | override getHighestPossibleFitness(ThreadContext threadContext) { | ||
67 | var int cost = 0 | ||
68 | for (matcher : matchers) { | ||
69 | if (matcher.weight <= 0) { | ||
70 | cost += matcher.weight * matcher.mustMatcher.countMatches | ||
71 | } else if (matcher.mayMatcher.countMatches > 0) { | ||
72 | return Double.POSITIVE_INFINITY | ||
73 | } | ||
74 | } | ||
75 | cost as double | ||
76 | } | ||
77 | |||
78 | @Data | ||
79 | private static class CostElementMatchers { | ||
80 | val ViatraQueryMatcher<? extends IPatternMatch> currentMatcher | ||
81 | val ViatraQueryMatcher<? extends IPatternMatch> mayMatcher | ||
82 | val ViatraQueryMatcher<? extends IPatternMatch> mustMatcher | ||
83 | val int weight | ||
84 | } | ||
85 | } | ||