aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime/src/main/java/tools
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-08-19 03:14:50 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-08-19 03:14:50 +0200
commitd48a3d35bdcc6dcb15730e8daddfeec737df38b9 (patch)
tree56c1a6fe443767892b9508285ad66f73ec0dd91a /subprojects/viatra-runtime/src/main/java/tools
parentrefactor: remove unused VIATRA code (diff)
downloadrefinery-d48a3d35bdcc6dcb15730e8daddfeec737df38b9.tar.gz
refinery-d48a3d35bdcc6dcb15730e8daddfeec737df38b9.tar.zst
refinery-d48a3d35bdcc6dcb15730e8daddfeec737df38b9.zip
refactor: merge VIATRA subprojects
Since we remove EMF dependencies, there is no point to maintaining a base index separate from the rest of the runtime.
Diffstat (limited to 'subprojects/viatra-runtime/src/main/java/tools')
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngine.java1
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/counting/CountingAlg.java226
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/counting/CountingTcRelation.java259
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/dred/DRedAlg.java308
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/dred/DRedTcRelation.java223
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/fw/FloydWarshallAlg.java110
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/incscc/CountingListener.java36
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/incscc/IncSCCAlg.java645
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/DFSPathFinder.java146
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/Edge.java38
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/GraphHelper.java173
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/IGraphPathFinder.java67
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/ITcRelation.java31
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/Tuple.java60
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/bfs/BFS.java151
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/dfs/DFSAlg.java93
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/PKAlg.java179
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCC.java146
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCCProperty.java37
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCCResult.java81
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/topsort/TopologicalSorting.java77
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/representative/RepresentativeElectionAlgorithm.java140
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/representative/RepresentativeObserver.java12
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/representative/StronglyConnectedComponentAlgorithm.java66
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/representative/WeaklyConnectedComponentAlgorithm.java85
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/util/CollectionHelper.java64
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/graphimpl/DotGenerator.java160
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/graphimpl/Graph.java185
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/IBiDirectionalGraphDataSource.java37
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/IBiDirectionalWrapper.java110
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/IGraphDataSource.java70
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/IGraphObserver.java55
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/ITcDataSource.java82
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/ITcObserver.java39
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/ViatraQueryRuntimeException.java42
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/AverageAccumulator.java24
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleAverageOperator.java82
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleSumOperator.java62
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/ExtremumOperator.java135
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerAverageOperator.java82
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerSumOperator.java61
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongAverageOperator.java82
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongSumOperator.java61
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/avg.java39
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/count.java33
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/max.java44
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/min.java44
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/sum.java39
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/OrderedIterableMerge.java83
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFind.java214
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFindNodeProperty.java32
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/CommonQueryHintOptions.java36
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ICallDelegationStrategy.java89
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IMatcherCapability.java26
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackend.java68
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactory.java52
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactoryProvider.java46
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendHintProvider.java32
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryResultProvider.java202
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IUpdateable.java27
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryEvaluationHint.java241
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryHintOption.java122
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ResultProviderRequestor.java74
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryMetaContext.java69
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryRuntimeContext.java21
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IInputKey.java45
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IPosetComparator.java35
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryBackendContext.java49
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryCacheContext.java39
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryMetaContext.java98
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryResultProviderAccess.java31
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContext.java281
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContextListener.java27
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IndexingService.java36
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/InputKeyImplication.java103
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/BaseInputKeyWrapper.java55
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/JavaTransitiveInstancesKey.java165
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/surrogate/SurrogateQueryRegistry.java153
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/AbstractTrivialMaskedMemory.java58
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/DefaultMaskedTupleMemory.java127
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/IdentityMaskedTupleMemory.java77
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/MaskedTupleMemory.java385
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/NullaryMaskedTupleMemory.java85
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/UnaryMaskedTupleMemory.java143
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyMaskedMemory.java228
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyTrivialMaskedMemory.java100
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyDefaultMaskedTupleMemory.java98
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyIdentityMaskedTupleMemory.java106
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyNullaryMaskedTupleMemory.java108
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyUnaryMaskedTupleMemory.java133
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IOperationCompiler.java108
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IQueryPlannerStrategy.java29
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/QueryProcessingException.java102
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlan.java240
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlanFactory.java33
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/BuildHelper.java165
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/FunctionalDependencyHelper.java143
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/StatisticsHelper.java62
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/TypeHelper.java217
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PApply.java94
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PEnumerate.java76
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PJoin.java64
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/POperation.java52
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PProject.java109
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PStart.java90
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/BasePConstraint.java108
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/DeferredPConstraint.java31
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/EnumerablePConstraint.java59
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IExpressionEvaluator.java42
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IMultiQueryReference.java26
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IQueryReference.java33
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IRelationEvaluator.java47
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeConstraint.java65
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeInfoProviderConstraint.java28
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IValueProvider.java27
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/InitializablePQuery.java56
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/KeyedEnumerablePConstraint.java39
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PBody.java289
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PConstraint.java70
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PTraceable.java16
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PVariable.java203
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/TypeJudgement.java153
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/VariableDeferredPConstraint.java40
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AbstractMemorylessAggregationOperator.java31
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AggregatorType.java49
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/BoundAggregator.java61
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IAggregatorFactory.java40
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IMultisetAggregationOperator.java106
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/analysis/QueryAnalyzer.java194
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/PAnnotation.java94
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/ParameterReference.java30
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/AggregatorConstraint.java98
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/BaseTypeSafeConstraint.java99
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Equality.java96
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExportedParameter.java108
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExpressionEvaluation.java80
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Inequality.java151
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/NegativePatternCall.java52
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternCallBasedDeferred.java118
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternMatchCounter.java70
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/RelationEvaluation.java57
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/TypeFilterConstraint.java105
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/AbstractTransitiveClosure.java44
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryReflexiveTransitiveClosure.java57
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryTransitiveClosure.java33
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/Connectivity.java11
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/ConstantValue.java57
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/PositivePatternCall.java76
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/RepresentativeElectionConstraint.java43
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/TypeConstraint.java79
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/BasePQuery.java231
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PDisjunction.java104
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameter.java105
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameterDirection.java35
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PProblem.java68
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueries.java110
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQuery.java154
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueryHeader.java101
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PVisibility.java37
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/QueryInitializationException.java35
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/AbstractRewriterTraceSource.java53
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/ConstraintRemovalReason.java23
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/DefaultFlattenCallPredicate.java23
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/FlattenerCopier.java129
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IConstraintFilter.java48
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IDerivativeModificationReason.java19
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IFlattenCallPredicate.java50
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IPTraceableTraceProvider.java55
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IRewriterTraceCollector.java33
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IVariableRenamer.java59
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/MappingTraceCollector.java135
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NeverFlattenCallPredicate.java26
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NopTraceCollector.java68
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyCopier.java306
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyNormalizer.java310
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriter.java27
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriterCacher.java64
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PQueryFlattener.java253
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/RewriterException.java31
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/SurrogateQueryRewriter.java63
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/VariableMappingExpressionEvaluatorWrapper.java88
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/AbstractTuple.java136
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseFlatTuple.java20
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseLeftInheritanceTuple.java65
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple.java60
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple0.java46
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple1.java44
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple2.java51
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple3.java55
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple4.java59
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/IModifiableTuple.java27
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/ITuple.java64
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple.java172
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple1.java83
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple2.java73
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple3.java81
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple4.java88
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/MaskedTuple.java48
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuple.java69
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask.java560
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask0.java56
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMaskIdentity.java51
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleValueProvider.java48
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuples.java157
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileMaskedTuple.java50
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileModifiableMaskedTuple.java47
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileTuple.java47
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Accuracy.java48
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Clearable.java23
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/CollectionsFactory.java188
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Direction.java61
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsBagMemory.java86
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsDeltaBag.java41
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsFactory.java159
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongMultiset.java150
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongSetMemory.java212
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiLookup.java226
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiset.java93
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsSetMemory.java94
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EmptyMemory.java93
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/ICache.java32
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IDeltaBag.java26
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemory.java81
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemoryView.java205
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookup.java216
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookupAbstract.java485
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiset.java30
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IProvider.java30
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/ISetMemory.java37
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MapBackedMemoryView.java102
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MarkedMemory.java21
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MemoryViewBackedMapView.java117
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Preconditions.java208
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/PurgableCache.java44
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Sets.java90
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Signed.java60
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonInstanceProvider.java29
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonMemoryView.java105
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/TimelyMemory.java517
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/MaskedResumable.java36
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/Resumable.java27
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/UnmaskedResumable.java36
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/CompactTimeline.java111
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Diff.java55
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/SingletonTimeline.java73
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timeline.java146
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timelines.java46
247 files changed, 23714 insertions, 1 deletions
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngine.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngine.java
index ebae57a7..58285845 100644
--- a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngine.java
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngine.java
@@ -9,7 +9,6 @@
9 9
10package tools.refinery.viatra.runtime.api; 10package tools.refinery.viatra.runtime.api;
11 11
12import org.eclipse.emf.common.notify.Notifier;
13import tools.refinery.viatra.runtime.api.scope.IBaseIndex; 12import tools.refinery.viatra.runtime.api.scope.IBaseIndex;
14import tools.refinery.viatra.runtime.api.scope.QueryScope; 13import tools.refinery.viatra.runtime.api.scope.QueryScope;
15import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException; 14import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/counting/CountingAlg.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/counting/CountingAlg.java
new file mode 100644
index 00000000..d0367cde
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/counting/CountingAlg.java
@@ -0,0 +1,226 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.alg.counting;
11
12import java.util.List;
13import java.util.Set;
14
15import tools.refinery.viatra.runtime.base.itc.alg.misc.DFSPathFinder;
16import tools.refinery.viatra.runtime.base.itc.alg.misc.IGraphPathFinder;
17import tools.refinery.viatra.runtime.base.itc.alg.misc.ITcRelation;
18import tools.refinery.viatra.runtime.base.itc.igraph.IBiDirectionalGraphDataSource;
19import tools.refinery.viatra.runtime.base.itc.igraph.IBiDirectionalWrapper;
20import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource;
21import tools.refinery.viatra.runtime.base.itc.igraph.IGraphObserver;
22import tools.refinery.viatra.runtime.base.itc.igraph.ITcDataSource;
23import tools.refinery.viatra.runtime.base.itc.igraph.ITcObserver;
24import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
25import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
26
27/**
28 * This class is the optimized implementation of the Counting algorithm.
29 *
30 * @author Tamas Szabo
31 *
32 * @param <V>
33 * the type parameter of the nodes in the graph data source
34 */
35public class CountingAlg<V> implements IGraphObserver<V>, ITcDataSource<V> {
36
37 private CountingTcRelation<V> tc = null;
38 private IBiDirectionalGraphDataSource<V> gds = null;
39 private List<ITcObserver<V>> observers;
40
41 /**
42 * Constructs a new Counting algorithm and initializes the transitive closure relation with the given graph data
43 * source. Attach itself on the graph data source as an observer.
44 *
45 * @param gds
46 * the graph data source instance
47 */
48 public CountingAlg(IGraphDataSource<V> gds) {
49
50 if (gds instanceof IBiDirectionalGraphDataSource<?>) {
51 this.gds = (IBiDirectionalGraphDataSource<V>) gds;
52 } else {
53 this.gds = new IBiDirectionalWrapper<V>(gds);
54 }
55
56 observers = CollectionsFactory.<ITcObserver<V>>createObserverList();
57 tc = new CountingTcRelation<V>(true);
58
59 initTc();
60 gds.attachObserver(this);
61 }
62
63 /**
64 * Initializes the transitive closure relation.
65 */
66 private void initTc() {
67 this.setTcRelation(CountingTcRelation.createFrom(gds));
68 }
69
70 @Override
71 public void edgeInserted(V source, V target) {
72 if (!source.equals(target)) {
73 deriveTc(source, target, true);
74 }
75 }
76
77 @Override
78 public void edgeDeleted(V source, V target) {
79 if (!source.equals(target)) {
80 deriveTc(source, target, false);
81 }
82 }
83
84 @Override
85 public void nodeInserted(V n) {
86
87 }
88
89 @Override
90 public void nodeDeleted(V n) {
91 this.tc.deleteTupleEnd(n);
92 }
93
94 /**
95 * Derives the transitive closure relation when an edge is inserted or deleted.
96 *
97 * @param source
98 * the source of the edge
99 * @param target
100 * the target of the edge
101 * @param dCount
102 * the value is -1 if an edge was deleted and +1 if an edge was inserted
103 */
104 private void deriveTc(V source, V target, boolean isInsertion) {
105
106 // if (dCount == 1 && isReachable(target, source)) {
107 // System.out.println("The graph contains cycle with (" + source + ","+ target + ") edge!");
108 // }
109
110 CountingTcRelation<V> dtc = new CountingTcRelation<V>(false);
111 Set<V> tupEnds = null;
112
113 // 1. d(tc(x,y)) :- d(l(x,y))
114 if (tc.updateTuple(source, target, isInsertion)) {
115 dtc.updateTuple(source, target, true /* deltas implicitly have the same sign as isInsertion*/);
116 notifyTcObservers(source, target, isInsertion);
117 }
118
119 // 2. d(tc(x,y)) :- d(l(x,z)) & tc(z,y)
120 tupEnds = tc.getTupleEnds(target);
121 if (tupEnds != null) {
122 for (V tupEnd : tupEnds) {
123 if (!tupEnd.equals(source)) {
124 if (tc.updateTuple(source, tupEnd, isInsertion)) {
125 dtc.updateTuple(source, tupEnd, true /* deltas implicitly have the same sign as isInsertion*/);
126 notifyTcObservers(source, tupEnd, isInsertion);
127 }
128 }
129 }
130 }
131
132 // 3. d(tc(x,y)) :- lv(x,z) & d(tc(z,y))
133 CountingTcRelation<V> newTuples = dtc;
134 CountingTcRelation<V> tmp = null;
135 dtc = new CountingTcRelation<V>(false);
136
137 IMemoryView<V> nodes = null;
138
139 while (!newTuples.isEmpty()) {
140
141 tmp = dtc;
142 dtc = newTuples;
143 newTuples = tmp;
144 newTuples.clear();
145
146 for (V tS : dtc.getTupleStarts()) {
147 nodes = gds.getSourceNodes(tS);
148 for (V nS : nodes.distinctValues()) {
149 int count = nodes.getCount(nS);
150 for (int i = 0; i < count; i++) {
151 tupEnds = dtc.getTupleEnds(tS);
152 if (tupEnds != null) {
153 for (V tT : tupEnds) {
154 if (!nS.equals(tT)) {
155 if (tc.updateTuple(nS, tT, isInsertion)) {
156 newTuples.updateTuple(nS, tT, true /* deltas implicitly have the same sign as isInsertion*/);
157 notifyTcObservers(nS, tT, isInsertion);
158 }
159 }
160 }
161 }
162 }
163 }
164 }
165 }
166
167 // System.out.println(tc);
168 }
169
170 public ITcRelation<V> getTcRelation() {
171 return this.tc;
172 }
173
174 public void setTcRelation(CountingTcRelation<V> tc) {
175 this.tc = tc;
176 }
177
178 @Override
179 public boolean isReachable(V source, V target) {
180 return tc.containsTuple(source, target);
181 }
182
183 @Override
184 public void attachObserver(ITcObserver<V> to) {
185 this.observers.add(to);
186
187 }
188
189 @Override
190 public void detachObserver(ITcObserver<V> to) {
191 this.observers.remove(to);
192 }
193
194 @Override
195 public Set<V> getAllReachableTargets(V source) {
196 return tc.getTupleEnds(source);
197 }
198
199 @Override
200 public Set<V> getAllReachableSources(V target) {
201 return tc.getTupleStarts(target);
202 }
203
204 private void notifyTcObservers(V source, V target, boolean isInsertion) {
205 if (isInsertion) {
206 for (ITcObserver<V> o : observers) {
207 o.tupleInserted(source, target);
208 }
209 } else {
210 for (ITcObserver<V> o : observers) {
211 o.tupleDeleted(source, target);
212 }
213 }
214 }
215
216 @Override
217 public void dispose() {
218 tc.clear();
219 this.gds.detachObserver(this);
220 }
221
222 @Override
223 public IGraphPathFinder<V> getPathFinder() {
224 return new DFSPathFinder<V>(gds, this);
225 }
226} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/counting/CountingTcRelation.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/counting/CountingTcRelation.java
new file mode 100644
index 00000000..44abbc3d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/counting/CountingTcRelation.java
@@ -0,0 +1,259 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.alg.counting;
11
12import java.util.Collections;
13import java.util.List;
14import java.util.Set;
15
16import tools.refinery.viatra.runtime.base.itc.alg.misc.topsort.TopologicalSorting;
17import tools.refinery.viatra.runtime.base.itc.alg.misc.ITcRelation;
18import tools.refinery.viatra.runtime.base.itc.igraph.IBiDirectionalGraphDataSource;
19import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
20import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
21import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
22import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
23import tools.refinery.viatra.runtime.matchers.util.IMultiLookup.ChangeGranularity;
24
25/**
26 * Transitive closure relation implementation for the Counting algorithm.
27 *
28 * @author Tamas Szabo
29 *
30 * @param <V>
31 */
32public class CountingTcRelation<V> implements ITcRelation<V> {
33
34 private IMultiLookup<V, V> tuplesForward = null;
35 private IMultiLookup<V, V> tuplesBackward = null;
36
37 protected CountingTcRelation(boolean backwardIndexing) {
38 tuplesForward = CollectionsFactory.createMultiLookup(Object.class, MemoryType.MULTISETS, Object.class);
39 if (backwardIndexing)
40 tuplesBackward = CollectionsFactory.createMultiLookup(Object.class, MemoryType.MULTISETS, Object.class);
41 }
42
43 protected boolean isEmpty() {
44 return 0 == this.tuplesForward.countKeys();
45 }
46
47 protected void clear() {
48 this.tuplesForward.clear();
49
50 if (tuplesBackward != null) {
51 this.tuplesBackward.clear();
52 }
53 }
54
55 protected void union(CountingTcRelation<V> rA) {
56 IMultiLookup<V, V> rForward = rA.tuplesForward;
57 for (V source : rForward.distinctKeys()) {
58 IMemoryView<V> targetBag = rForward.lookup(source);
59 for (V target : targetBag.distinctValues()) {
60 this.addTuple(source, target, targetBag.getCount(target));
61 }
62 }
63 }
64
65 public int getCount(V source, V target) {
66 IMemoryView<V> bucket = tuplesForward.lookup(source);
67 return bucket == null ? 0 : bucket.getCount(target);
68 }
69
70 /**
71 * Returns true if the tc relation did not contain previously such a tuple that is defined by (source,target), false
72 * otherwise (in this case count is incremented with the given count parameter).
73 *
74 * @param source
75 * the source of the tuple
76 * @param target
77 * the target of the tuple
78 * @param count
79 * the count of the tuple, must be positive
80 * @return true if the relation did not contain previously the tuple
81 */
82 public boolean addTuple(V source, V target, int count) {
83 if (tuplesBackward != null) {
84 tuplesBackward.addPairPositiveMultiplicity(target, source, count);
85 }
86
87 ChangeGranularity change =
88 tuplesForward.addPairPositiveMultiplicity(source, target, count);
89
90 return change != ChangeGranularity.DUPLICATE;
91 }
92
93 /**
94 * Derivation count of the tuple (source,target) is incremented or decremented.
95 * Returns true iff updated to / from zero derivation count.
96 * @since 1.7
97 */
98 public boolean updateTuple(V source, V target, boolean isInsertion) {
99 if (isInsertion) {
100 if (tuplesBackward != null) {
101 tuplesBackward.addPair(target, source);
102 }
103 ChangeGranularity change =
104 tuplesForward.addPair(source, target);
105 return change != ChangeGranularity.DUPLICATE;
106 } else {
107 if (tuplesBackward != null) {
108 tuplesBackward.removePair(target, source);
109 }
110 ChangeGranularity change =
111 tuplesForward.removePair(source, target);
112 return change != ChangeGranularity.DUPLICATE;
113 }
114 }
115
116 public void deleteTupleEnd(V deleted) {
117 Set<V> sourcesToDelete = CollectionsFactory.createSet();
118 Set<V> targetsToDelete = CollectionsFactory.createSet();
119
120 for (V target : tuplesForward.lookupOrEmpty(deleted).distinctValues()) {
121 targetsToDelete.add(target);
122 }
123 if (tuplesBackward != null) {
124 for (V source : tuplesBackward.lookupOrEmpty(deleted).distinctValues()) {
125 sourcesToDelete.add(source);
126 }
127 } else {
128 for (V sourceCandidate : tuplesForward.distinctKeys()) {
129 if (tuplesForward.lookupOrEmpty(sourceCandidate).containsNonZero(deleted))
130 sourcesToDelete.add(sourceCandidate);
131 }
132 }
133
134 for (V source : sourcesToDelete) {
135 int count = tuplesForward.lookupOrEmpty(source).getCount(deleted);
136 for (int i=0; i< count; ++i) tuplesForward.removePair(source, deleted);
137 }
138 for (V target : targetsToDelete) {
139 int count = tuplesForward.lookupOrEmpty(deleted).getCount(target);
140 for (int i=0; i< count; ++i) tuplesForward.removePair(deleted, target);
141 }
142
143 if (tuplesBackward != null) {
144 for (V source : sourcesToDelete) {
145 int count = tuplesBackward.lookupOrEmpty(deleted).getCount(source);
146 for (int i=0; i< count; ++i) tuplesBackward.removePair(deleted, source);
147 }
148 for (V target : targetsToDelete) {
149 int count = tuplesBackward.lookupOrEmpty(target).getCount(deleted);
150 for (int i=0; i< count; ++i) tuplesBackward.removePair(target, deleted);
151 }
152 }
153 }
154
155 @Override
156 public String toString() {
157 StringBuilder sb = new StringBuilder("TcRelation = ");
158
159 for (V source : tuplesForward.distinctKeys()) {
160 IMemoryView<V> targets = tuplesForward.lookup(source);
161 for (V target : targets.distinctValues()) {
162 sb.append("{(" + source + "," + target + ")," + targets.getCount(target) + "} ");
163 }
164 }
165
166 return sb.toString();
167 }
168
169 @Override
170 public Set<V> getTupleEnds(V source) {
171 IMemoryView<V> tupEnds = tuplesForward.lookup(source);
172 if (tupEnds == null)
173 return null;
174 return tupEnds.distinctValues();
175 }
176
177 /**
178 * Returns the set of nodes from which the target node is reachable, if already computed.
179 *
180 * @param target
181 * the target node
182 * @return the set of source nodes
183 * @throws UnsupportedOperationException if backwards index not computed
184 */
185 public Set<V> getTupleStarts(V target) {
186 if (tuplesBackward != null) {
187 IMemoryView<V> tupStarts = tuplesBackward.lookup(target);
188 if (tupStarts == null)
189 return null;
190 return tupStarts.distinctValues();
191 } else {
192 throw new UnsupportedOperationException("built without backward indexing");
193 }
194 }
195
196 @Override
197 public Set<V> getTupleStarts() {
198 Set<V> nodes = CollectionsFactory.createSet();
199 for (V s : tuplesForward.distinctKeys()) {
200 nodes.add(s);
201 }
202 return nodes;
203 }
204
205 /**
206 * Returns true if a (source, target) node is present in the transitive closure relation, false otherwise.
207 *
208 * @param source
209 * the source node
210 * @param target
211 * the target node
212 * @return true if tuple is present, false otherwise
213 */
214 public boolean containsTuple(V source, V target) {
215 return tuplesForward.lookupOrEmpty(source).containsNonZero(target);
216 }
217
218 @SuppressWarnings("unchecked")
219 @Override
220 public boolean equals(Object obj) {
221 if (this == obj) {
222 return true;
223 } else if (obj == null || this.getClass() != obj.getClass()) {
224 return false;
225 } else {
226 CountingTcRelation<V> aTR = (CountingTcRelation<V>) obj;
227
228 return tuplesForward.equals(aTR.tuplesForward);
229 }
230 }
231
232 @Override
233 public int hashCode() {
234 return tuplesForward.hashCode();
235 }
236
237 public static <V> CountingTcRelation<V> createFrom(IBiDirectionalGraphDataSource<V> gds) {
238 List<V> topologicalSorting = TopologicalSorting.compute(gds);
239 CountingTcRelation<V> tc = new CountingTcRelation<V>(true);
240 Collections.reverse(topologicalSorting);
241 for (V n : topologicalSorting) {
242 IMemoryView<V> sourceNodes = gds.getSourceNodes(n);
243 Set<V> tupEnds = tc.getTupleEnds(n);
244 for (V s : sourceNodes.distinctValues()) {
245 int count = sourceNodes.getCount(s);
246 for (int i = 0; i < count; i++) {
247 tc.updateTuple(s, n, true);
248 if (tupEnds != null) {
249 for (V t : tupEnds) {
250 tc.updateTuple(s, t, true);
251 }
252 }
253 }
254 }
255 }
256
257 return tc;
258 }
259}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/dred/DRedAlg.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/dred/DRedAlg.java
new file mode 100644
index 00000000..b92d08bf
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/dred/DRedAlg.java
@@ -0,0 +1,308 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.alg.dred;
11
12import java.util.ArrayList;
13import java.util.HashMap;
14import java.util.HashSet;
15import java.util.List;
16import java.util.Map;
17import java.util.Map.Entry;
18import java.util.Set;
19
20import tools.refinery.viatra.runtime.base.itc.alg.misc.DFSPathFinder;
21import tools.refinery.viatra.runtime.base.itc.alg.misc.IGraphPathFinder;
22import tools.refinery.viatra.runtime.base.itc.alg.misc.Tuple;
23import tools.refinery.viatra.runtime.base.itc.alg.misc.dfs.DFSAlg;
24import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource;
25import tools.refinery.viatra.runtime.base.itc.igraph.IGraphObserver;
26import tools.refinery.viatra.runtime.base.itc.igraph.ITcDataSource;
27import tools.refinery.viatra.runtime.base.itc.igraph.ITcObserver;
28import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
29
30/**
31 * This class is the optimized implementation of the DRED algorithm.
32 *
33 * @author Tamas Szabo
34 *
35 * @param <V>
36 * the type parameter of the nodes in the graph data source
37 */
38public class DRedAlg<V> implements IGraphObserver<V>, ITcDataSource<V> {
39
40 private IGraphDataSource<V> graphDataSource = null;
41 private DRedTcRelation<V> tc = null;
42 private DRedTcRelation<V> dtc = null;
43 private List<ITcObserver<V>> observers;
44
45 /**
46 * Constructs a new DRED algorithm and initializes the transitive closure relation with the given graph data source.
47 * Attach itself on the graph data source as an observer.
48 *
49 * @param gds
50 * the graph data source instance
51 */
52 public DRedAlg(IGraphDataSource<V> gds) {
53 this.observers = new ArrayList<ITcObserver<V>>();
54 this.graphDataSource = gds;
55 this.tc = new DRedTcRelation<V>();
56 this.dtc = new DRedTcRelation<V>();
57 initTc();
58 graphDataSource.attachObserver(this);
59 }
60
61 /**
62 * Constructs a new DRED algorithm and initializes the transitive closure relation with the given relation. Attach
63 * itself on the graph data source as an observer.
64 *
65 * @param gds
66 * the graph data source instance
67 * @param tc
68 * the transitive closure instance
69 */
70 public DRedAlg(IGraphDataSource<V> gds, DRedTcRelation<V> tc) {
71 this.graphDataSource = gds;
72 this.tc = tc;
73 this.dtc = new DRedTcRelation<V>();
74 graphDataSource.attachObserver(this);
75 }
76
77 /**
78 * Initializes the transitive closure relation.
79 */
80 private void initTc() {
81 DFSAlg<V> dfsa = new DFSAlg<V>(this.graphDataSource);
82 this.setTcRelation(dfsa.getTcRelation());
83 this.graphDataSource.detachObserver(dfsa);
84 }
85
86 @Override
87 public void edgeInserted(V source, V target) {
88 if (!source.equals(target)) {
89 Set<V> tupStarts = null;
90 Set<V> tupEnds = null;
91 Set<Tuple<V>> tuples = new HashSet<Tuple<V>>();
92
93 if (!source.equals(target) && tc.addTuple(source, target)) {
94 tuples.add(new Tuple<V>(source, target));
95 }
96
97 // 2. d+(tc(x,y)) :- d+(tc(x,z)) & lv(z,y) Descartes product
98 tupStarts = tc.getTupleStarts(source);
99 tupEnds = tc.getTupleEnds(target);
100
101 for (V s : tupStarts) {
102 for (V t : tupEnds) {
103 if (!s.equals(t) && tc.addTuple(s, t)) {
104 tuples.add(new Tuple<V>(s, t));
105 }
106 }
107 }
108
109 // (s, source) -> (source, target)
110 // tupStarts = tc.getTupleStarts(source);
111 for (V s : tupStarts) {
112 if (!s.equals(target) && tc.addTuple(s, target)) {
113 tuples.add(new Tuple<V>(s, target));
114 }
115 }
116
117 // (source, target) -> (target, t)
118 // tupEnds = tc.getTupleEnds(target);
119 for (V t : tupEnds) {
120 if (!source.equals(t) && tc.addTuple(source, t)) {
121 tuples.add(new Tuple<V>(source, t));
122 }
123 }
124
125 notifyTcObservers(tuples, 1);
126 }
127 }
128
129 @Override
130 public void edgeDeleted(V source, V target) {
131 if (!source.equals(target)) {
132
133 // Computing overestimate, Descartes product of A and B sets, where
134 // A: those nodes from which source is reachable
135 // B: those nodes which is reachable from target
136
137 Map<Tuple<V>, Integer> tuples = new HashMap<Tuple<V>, Integer>();
138 Set<V> sources = tc.getTupleStarts(source);
139 Set<V> targets = tc.getTupleEnds(target);
140
141 tc.removeTuple(source, target);
142 tuples.put(new Tuple<V>(source, target), -1);
143
144 for (V s : sources) {
145 for (V t : targets) {
146 if (!s.equals(t)) {
147 tc.removeTuple(s, t);
148 tuples.put(new Tuple<V>(s, t), -1);
149 }
150 }
151 }
152
153 for (V s : sources) {
154 if (!s.equals(target)) {
155 tc.removeTuple(s, target);
156 tuples.put(new Tuple<V>(s, target), -1);
157 }
158 }
159
160 for (V t : targets) {
161 if (!source.equals(t)) {
162 tc.removeTuple(source, t);
163 tuples.put(new Tuple<V>(source, t), -1);
164 }
165 }
166
167 // System.out.println("overestimate: "+dtc);
168
169 // Modify overestimate with those tuples that have alternative derivations
170 // 1. q+(tc(x,y)) :- lv(x,y)
171 for (V s : graphDataSource.getAllNodes()) {
172 IMemoryView<V> targetNodes = graphDataSource.getTargetNodes(s);
173 for (Entry<V, Integer> entry : targetNodes.entriesWithMultiplicities()) {
174 for (int i = 0; i < entry.getValue(); i++) {
175 V t = entry.getKey();
176 if (!s.equals(t)) {
177 tc.addTuple(s, t);
178 Tuple<V> tuple = new Tuple<V>(s, t);
179 Integer count = tuples.get(tuple);
180 if (count != null && count == -1) {
181 tuples.remove(tuple);
182 }
183 }
184
185 }
186 }
187 }
188
189 // 2. q+(tc(x,y)) :- tcv(x,z) & lv(z,y)
190 DRedTcRelation<V> newTups = new DRedTcRelation<V>();
191 dtc.clear();
192 dtc.union(tc);
193
194 while (!dtc.isEmpty()) {
195
196 newTups.clear();
197 newTups.union(dtc);
198 dtc.clear();
199
200 for (V s : newTups.getTupleStarts()) {
201 for (V t : newTups.getTupleEnds(s)) {
202 IMemoryView<V> targetNodes = graphDataSource.getTargetNodes(t);
203 if (targetNodes != null) {
204 for (Entry<V, Integer> entry : targetNodes.entriesWithMultiplicities()) {
205 for (int i = 0; i < entry.getValue(); i++) {
206 V tn = entry.getKey();
207 if (!s.equals(tn) && tc.addTuple(s, tn)) {
208 dtc.addTuple(s, tn);
209 tuples.remove(new Tuple<V>(s, tn));
210 }
211 }
212 }
213 }
214 }
215 }
216 }
217
218 notifyTcObservers(tuples.keySet(), -1);
219 }
220 }
221
222 @Override
223 public void nodeInserted(V n) {
224 // Node inserted does not result new tc tuple.
225 }
226
227 @Override
228 public void nodeDeleted(V n) {
229 // FIXME node deletion may involve the deletion of incoming and outgoing edges too
230 Set<V> set = tc.getTupleEnds(n);
231 Set<V> modSet = null;
232
233 // n -> target
234 modSet = new HashSet<V>(set);
235
236 for (V tn : modSet) {
237 this.tc.removeTuple(n, tn);
238 }
239
240 // source -> n
241 set = tc.getTupleStarts(n);
242
243 modSet = new HashSet<V>(set);
244
245 for (V sn : modSet) {
246 this.tc.removeTuple(sn, n);
247 }
248 }
249
250 public DRedTcRelation<V> getTcRelation() {
251 return this.tc;
252 }
253
254 public void setTcRelation(DRedTcRelation<V> tc) {
255 this.tc = tc;
256 }
257
258 @Override
259 public boolean isReachable(V source, V target) {
260 return tc.containsTuple(source, target);
261 }
262
263 @Override
264 public void attachObserver(ITcObserver<V> to) {
265 this.observers.add(to);
266 }
267
268 @Override
269 public void detachObserver(ITcObserver<V> to) {
270 this.observers.remove(to);
271 }
272
273 @Override
274 public Set<V> getAllReachableTargets(V source) {
275 return tc.getTupleEnds(source);
276 }
277
278 @Override
279 public Set<V> getAllReachableSources(V target) {
280 return tc.getTupleStarts(target);
281 }
282
283 protected void notifyTcObservers(Set<Tuple<V>> tuples, int dir) {
284 for (ITcObserver<V> o : observers) {
285 for (Tuple<V> t : tuples) {
286 if (!t.getSource().equals(t.getTarget())) {
287 if (dir == 1) {
288 o.tupleInserted(t.getSource(), t.getTarget());
289 }
290 if (dir == -1) {
291 o.tupleDeleted(t.getSource(), t.getTarget());
292 }
293 }
294 }
295 }
296 }
297
298 @Override
299 public void dispose() {
300 tc = null;
301 dtc = null;
302 }
303
304 @Override
305 public IGraphPathFinder<V> getPathFinder() {
306 return new DFSPathFinder<V>(graphDataSource, this);
307 }
308}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/dred/DRedTcRelation.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/dred/DRedTcRelation.java
new file mode 100644
index 00000000..8543b79c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/dred/DRedTcRelation.java
@@ -0,0 +1,223 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.alg.dred;
11
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.Map;
15import java.util.Map.Entry;
16import java.util.Set;
17
18import tools.refinery.viatra.runtime.base.itc.alg.misc.ITcRelation;
19
20public class DRedTcRelation<V> implements ITcRelation<V> {
21
22 // tc(a,b) means that b is transitively reachable from a
23 private Map<V, Set<V>> tuplesForward;
24
25 // data structure to efficiently get those nodes from which a given node is reachable
26 // symmetric to tuplesForward
27 private Map<V, Set<V>> tuplesBackward;
28
29 public DRedTcRelation() {
30 this.tuplesForward = new HashMap<V, Set<V>>();
31 this.tuplesBackward = new HashMap<V, Set<V>>();
32 }
33
34 public void clear() {
35 this.tuplesForward.clear();
36 this.tuplesBackward.clear();
37 }
38
39 public boolean isEmpty() {
40 return tuplesForward.isEmpty();
41 }
42
43 public void removeTuple(V source, V target) {
44
45 // removing tuple from 'forward' tc relation
46 Set<V> sSet = tuplesForward.get(source);
47 if (sSet != null) {
48 sSet.remove(target);
49 if (sSet.size() == 0)
50 tuplesForward.remove(source);
51 }
52
53 // removing tuple from 'backward' tc relation
54 Set<V> tSet = tuplesBackward.get(target);
55 if (tSet != null) {
56 tSet.remove(source);
57 if (tSet.size() == 0)
58 tuplesBackward.remove(target);
59 }
60 }
61
62 /**
63 * Returns true if the tc relation did not contain previously such a tuple that is defined by (source,target), false
64 * otherwise.
65 *
66 * @param source
67 * the source of the tuple
68 * @param target
69 * the target of the tuple
70 * @return true if the relation did not contain previously the tuple
71 */
72 public boolean addTuple(V source, V target) {
73
74 // symmetric modification, it is sufficient to check the return value in one collection
75 // adding tuple to 'forward' tc relation
76 Set<V> sSet = tuplesForward.get(source);
77 if (sSet == null) {
78 Set<V> newSet = new HashSet<V>();
79 newSet.add(target);
80 tuplesForward.put(source, newSet);
81 } else {
82 sSet.add(target);
83 }
84
85 // adding tuple to 'backward' tc relation
86 Set<V> tSet = tuplesBackward.get(target);
87 if (tSet == null) {
88 Set<V> newSet = new HashSet<V>();
89 newSet.add(source);
90 tuplesBackward.put(target, newSet);
91 return true;
92 } else {
93 boolean ret = tSet.add(source);
94 return ret;
95 }
96
97 }
98
99 /**
100 * Union operation of two tc realtions.
101 *
102 * @param rA
103 * the other tc relation
104 */
105 public void union(DRedTcRelation<V> rA) {
106 for (V source : rA.tuplesForward.keySet()) {
107 for (V target : rA.tuplesForward.get(source)) {
108 this.addTuple(source, target);
109 }
110 }
111 }
112
113 /**
114 * Computes the difference of this tc relation and the given rA parameter.
115 *
116 * @param rA
117 * the subtrahend relation
118 */
119 public void difference(DRedTcRelation<V> rA) {
120 for (V source : rA.tuplesForward.keySet()) {
121 for (V target : rA.tuplesForward.get(source)) {
122 this.removeTuple(source, target);
123 }
124 }
125 }
126
127 @Override
128 public Set<V> getTupleEnds(V source) {
129 Set<V> t = tuplesForward.get(source);
130 return (t == null) ? new HashSet<V>() : new HashSet<V>(t);
131 }
132
133 /**
134 * Returns the set of nodes from which the target node is reachable.
135 *
136 * @param target
137 * the target node
138 * @return the set of source nodes
139 */
140 public Set<V> getTupleStarts(V target) {
141 Set<V> t = tuplesBackward.get(target);
142 return (t == null) ? new HashSet<V>() : new HashSet<V>(t);
143 }
144
145 @Override
146 public Set<V> getTupleStarts() {
147 Set<V> t = tuplesForward.keySet();
148 return new HashSet<V>(t);
149 }
150
151 @Override
152 public String toString() {
153 StringBuilder sb = new StringBuilder("TcRelation = ");
154
155 for (Entry<V, Set<V>> entry : this.tuplesForward.entrySet()) {
156 V source = entry.getKey();
157 for (V target : entry.getValue()) {
158 sb.append("(" + source + "," + target + ") ");
159 }
160 }
161 return sb.toString();
162 }
163
164 /**
165 * Returns true if a (source, target) node is present in the transitive closure relation, false otherwise.
166 *
167 * @param source
168 * the source node
169 * @param target
170 * the target node
171 * @return true if tuple is present, false otherwise
172 */
173 public boolean containsTuple(V source, V target) {
174 if (tuplesForward.containsKey(source)) {
175 if (tuplesForward.get(source).contains(target))
176 return true;
177 }
178 return false;
179 }
180
181 @SuppressWarnings("unchecked")
182 @Override
183 public boolean equals(Object obj) {
184 if (this == obj) {
185 return true;
186 }
187 if ((obj == null) || (obj.getClass() != this.getClass())) {
188 return false;
189 }
190
191 DRedTcRelation<V> aTR = (DRedTcRelation<V>) obj;
192
193 for (Entry<V, Set<V>> entry : aTR.tuplesForward.entrySet()) {
194 V source = entry.getKey();
195 for (V target : entry.getValue()) {
196 if (!this.containsTuple(source, target))
197 return false;
198 }
199 }
200
201 for (Entry<V, Set<V>> entry : this.tuplesForward.entrySet()) {
202 V source = entry.getKey();
203 for (V target : entry.getValue()) {
204 if (!aTR.containsTuple(source, target))
205 return false;
206 }
207 }
208
209 return true;
210 }
211
212 @Override
213 public int hashCode() {
214 int hash = 7;
215 hash = 31 * hash + tuplesForward.hashCode();
216 hash = 31 * hash + tuplesBackward.hashCode();
217 return hash;
218 }
219
220 public Map<V, Set<V>> getTuplesForward() {
221 return tuplesForward;
222 }
223}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/fw/FloydWarshallAlg.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/fw/FloydWarshallAlg.java
new file mode 100644
index 00000000..8b8908b1
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/fw/FloydWarshallAlg.java
@@ -0,0 +1,110 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.alg.fw;
11
12import java.util.HashMap;
13import java.util.Map;
14
15import tools.refinery.viatra.runtime.base.itc.alg.dred.DRedTcRelation;
16import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource;
17import tools.refinery.viatra.runtime.base.itc.igraph.IGraphObserver;
18import tools.refinery.viatra.runtime.base.itc.igraph.IBiDirectionalGraphDataSource;
19import tools.refinery.viatra.runtime.base.itc.igraph.IBiDirectionalWrapper;
20import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
21
22public class FloydWarshallAlg<V> implements IGraphObserver<V> {
23
24 private DRedTcRelation<V> tc = null;
25 private IBiDirectionalGraphDataSource<V> gds = null;
26
27 public FloydWarshallAlg(IGraphDataSource<V> gds) {
28 if (gds instanceof IBiDirectionalGraphDataSource<?>) {
29 this.gds = (IBiDirectionalGraphDataSource<V>) gds;
30 } else {
31 this.gds = new IBiDirectionalWrapper<V>(gds);
32 }
33
34 this.tc = new DRedTcRelation<V>();
35 gds.attachObserver(this);
36 generateTc();
37 }
38
39 private void generateTc() {
40
41 tc.clear();
42
43 int n = gds.getAllNodes().size();
44 Map<V, Integer> mapForw = new HashMap<V, Integer>();
45 Map<Integer, V> mapBackw = new HashMap<Integer, V>();
46 int[][] P = new int[n][n];
47
48 int i, j, k;
49
50 // initialize adjacent matrix
51 for (i = 0; i < n; i++) {
52 for (j = 0; j < n; j++) {
53 P[i][j] = 0;
54 }
55 }
56
57 i = 0;
58 for (V node : gds.getAllNodes()) {
59 mapForw.put(node, i);
60 mapBackw.put(i, node);
61 i++;
62 }
63
64 for (V source : gds.getAllNodes()) {
65 IMemoryView<V> targets = gds.getTargetNodes(source);
66 for (V target : targets.distinctValues()) {
67 P[mapForw.get(source)][mapForw.get(target)] = 1;
68 }
69 }
70
71 for (k = 0; k < n; k++) {
72 for (i = 0; i < n; i++) {
73 for (j = 0; j < n; j++) {
74 P[i][j] = P[i][j] | (P[i][k] & P[k][j]);
75 }
76 }
77 }
78
79 for (i = 0; i < n; i++) {
80 for (j = 0; j < n; j++) {
81 if (P[i][j] == 1 && i != j)
82 tc.addTuple(mapBackw.get(i), mapBackw.get(j));
83 }
84 }
85 }
86
87 @Override
88 public void edgeInserted(V source, V target) {
89 generateTc();
90 }
91
92 @Override
93 public void edgeDeleted(V source, V target) {
94 generateTc();
95 }
96
97 @Override
98 public void nodeInserted(V n) {
99 generateTc();
100 }
101
102 @Override
103 public void nodeDeleted(V n) {
104 generateTc();
105 }
106
107 public DRedTcRelation<V> getTcRelation() {
108 return this.tc;
109 }
110}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/incscc/CountingListener.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/incscc/CountingListener.java
new file mode 100644
index 00000000..fdf64f77
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/incscc/CountingListener.java
@@ -0,0 +1,36 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.base.itc.alg.incscc;
10
11import tools.refinery.viatra.runtime.base.itc.igraph.ITcObserver;
12import tools.refinery.viatra.runtime.matchers.util.Direction;
13
14/**
15 * @author Tamas Szabo
16 *
17 */
18public class CountingListener<V> implements ITcObserver<V> {
19
20 private IncSCCAlg<V> alg;
21
22 public CountingListener(IncSCCAlg<V> alg) {
23 this.alg = alg;
24 }
25
26 @Override
27 public void tupleInserted(V source, V target) {
28 alg.notifyTcObservers(alg.sccs.getPartition(source), alg.sccs.getPartition(target), Direction.INSERT);
29 }
30
31 @Override
32 public void tupleDeleted(V source, V target) {
33 alg.notifyTcObservers(alg.sccs.getPartition(source), alg.sccs.getPartition(target), Direction.DELETE);
34 }
35
36} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/incscc/IncSCCAlg.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/incscc/IncSCCAlg.java
new file mode 100644
index 00000000..5d720e75
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/incscc/IncSCCAlg.java
@@ -0,0 +1,645 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.alg.incscc;
11
12import java.util.ArrayList;
13import java.util.HashSet;
14import java.util.Iterator;
15import java.util.List;
16import java.util.Map;
17import java.util.Map.Entry;
18import java.util.Objects;
19import java.util.Set;
20
21import tools.refinery.viatra.runtime.base.itc.alg.counting.CountingAlg;
22import tools.refinery.viatra.runtime.base.itc.alg.misc.bfs.BFS;
23import tools.refinery.viatra.runtime.base.itc.alg.misc.scc.SCC;
24import tools.refinery.viatra.runtime.base.itc.alg.misc.scc.SCCResult;
25import tools.refinery.viatra.runtime.base.itc.alg.util.CollectionHelper;
26import tools.refinery.viatra.runtime.base.itc.alg.dred.DRedTcRelation;
27import tools.refinery.viatra.runtime.base.itc.alg.misc.DFSPathFinder;
28import tools.refinery.viatra.runtime.base.itc.alg.misc.GraphHelper;
29import tools.refinery.viatra.runtime.base.itc.alg.misc.IGraphPathFinder;
30import tools.refinery.viatra.runtime.base.itc.alg.misc.Tuple;
31import tools.refinery.viatra.runtime.base.itc.graphimpl.Graph;
32import tools.refinery.viatra.runtime.base.itc.igraph.IBiDirectionalGraphDataSource;
33import tools.refinery.viatra.runtime.base.itc.igraph.IBiDirectionalWrapper;
34import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource;
35import tools.refinery.viatra.runtime.base.itc.igraph.IGraphObserver;
36import tools.refinery.viatra.runtime.base.itc.igraph.ITcDataSource;
37import tools.refinery.viatra.runtime.base.itc.igraph.ITcObserver;
38import tools.refinery.viatra.runtime.matchers.algorithms.UnionFind;
39import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
40import tools.refinery.viatra.runtime.matchers.util.Direction;
41import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
42
43/**
44 * Incremental SCC maintenance + counting algorithm.
45 *
46 * @author Tamas Szabo
47 *
48 * @param <V>
49 * the type parameter of the nodes in the graph data source
50 */
51public class IncSCCAlg<V> implements IGraphObserver<V>, ITcDataSource<V> {
52
53 public UnionFind<V> sccs;
54 public IBiDirectionalGraphDataSource<V> gds;
55 private CountingAlg<V> counting;
56 private Graph<V> reducedGraph;
57 private IBiDirectionalGraphDataSource<V> reducedGraphIndexer;
58 private List<ITcObserver<V>> observers;
59 private CountingListener<V> countingListener;
60
61 public IncSCCAlg(IGraphDataSource<V> graphDataSource) {
62
63 if (graphDataSource instanceof IBiDirectionalGraphDataSource<?>) {
64 gds = (IBiDirectionalGraphDataSource<V>) graphDataSource;
65 } else {
66 gds = new IBiDirectionalWrapper<V>(graphDataSource);
67 }
68 observers = CollectionsFactory.createObserverList();
69 sccs = new UnionFind<V>();
70 reducedGraph = new Graph<V>();
71 reducedGraphIndexer = new IBiDirectionalWrapper<V>(reducedGraph);
72 countingListener = new CountingListener<V>(this);
73 initalizeInternalDataStructures();
74 gds.attachObserver(this);
75 }
76
77 private void initalizeInternalDataStructures() {
78 SCCResult<V> _sccres = SCC.computeSCC(gds);
79 Set<Set<V>> _sccs = _sccres.getSccs();
80
81 for (Set<V> _set : _sccs) {
82 sccs.makeSet(_set);
83 }
84
85 // Initalization of the reduced graph
86 for (V n : sccs.getPartitionHeads()) {
87 reducedGraph.insertNode(n);
88 }
89
90 for (V source : gds.getAllNodes()) {
91 final IMemoryView<V> targetNodes = gds.getTargetNodes(source);
92 for (Entry<V, Integer> entry : targetNodes.entriesWithMultiplicities()) {
93 for (int i = 0; i < entry.getValue(); i++) {
94 V target = entry.getKey();
95 V sourceRoot = sccs.find(source);
96 V targetRoot = sccs.find(target);
97
98 if (!sourceRoot.equals(targetRoot)) {
99 reducedGraph.insertEdge(sourceRoot, targetRoot);
100 }
101 }
102 }
103 }
104
105 counting = new CountingAlg<V>(reducedGraph);
106 }
107
108 @Override
109 public void edgeInserted(V source, V target) {
110 V sourceRoot = sccs.find(source);
111 V targetRoot = sccs.find(target);
112
113 // Different SCC
114 if (!sourceRoot.equals(targetRoot)) {
115
116 // source is reachable from target?
117 if (counting.isReachable(targetRoot, sourceRoot)) {
118
119 Set<V> predecessorRoots = counting.getAllReachableSources(sourceRoot);
120 Set<V> successorRoots = counting.getAllReachableTargets(targetRoot);
121
122 // 1. intersection of source and target roots, these will be in the merged SCC
123 Set<V> isectRoots = CollectionHelper.intersection(predecessorRoots, successorRoots);
124 isectRoots.add(sourceRoot);
125 isectRoots.add(targetRoot);
126
127 // notifications must be issued before Union-Find modifications
128 if (observers.size() > 0) {
129 Set<V> sourceSCCs = createSetNullTolerant(predecessorRoots);
130 sourceSCCs.add(sourceRoot);
131 Set<V> targetSCCs = createSetNullTolerant(successorRoots);
132 targetSCCs.add(targetRoot);
133
134 // tracing back to actual nodes
135 for (V sourceSCC : sourceSCCs) {
136 targetLoop: for (V targetSCC : targetSCCs) {
137 if (counting.isReachable(sourceSCC, targetSCC)) continue targetLoop;
138
139 boolean needsNotification =
140 // Case 1. sourceSCC and targetSCC are the same and it is a one sized scc.
141 // Issue notifications only if there is no self-loop present at the moment
142 (sourceSCC.equals(targetSCC) && sccs.getPartition(sourceSCC).size() == 1 && GraphHelper
143 .getEdgeCount(sccs.getPartition(sourceSCC).iterator().next(), gds) == 0)
144 ||
145 // Case 2. sourceSCC and targetSCC are different sccs.
146 (!sourceSCC.equals(targetSCC));
147 // if self loop is already present omit the notification
148 if (needsNotification) {
149 notifyTcObservers(sccs.getPartition(sourceSCC), sccs.getPartition(targetSCC),
150 Direction.INSERT);
151 }
152 }
153 }
154 }
155
156 // 2. delete edges, nodes
157 List<V> sourceSCCs = new ArrayList<V>();
158 List<V> targetSCCs = new ArrayList<V>();
159
160 for (V r : isectRoots) {
161 List<V> sourceSCCsOfSCC = getSourceSCCsOfSCC(r);
162 List<V> targetSCCsOfSCC = getTargetSCCsOfSCC(r);
163
164 for (V sourceSCC : sourceSCCsOfSCC) {
165 if (!sourceSCC.equals(r)) {
166 reducedGraph.deleteEdgeIfExists(sourceSCC, r);
167 }
168 }
169
170 for (V targetSCC : targetSCCsOfSCC) {
171 if (!isectRoots.contains(targetSCC) && !r.equals(targetSCC)) {
172 reducedGraph.deleteEdgeIfExists(r, targetSCC);
173 }
174 }
175
176 sourceSCCs.addAll(sourceSCCsOfSCC);
177 targetSCCs.addAll(targetSCCsOfSCC);
178 }
179
180 for (V r : isectRoots) {
181 reducedGraph.deleteNode(r);
182 }
183
184 // 3. union
185 Iterator<V> iterator = isectRoots.iterator();
186 V newRoot = iterator.next();
187 while (iterator.hasNext()) {
188 newRoot = sccs.union(newRoot, iterator.next());
189 }
190
191 // 4. add new node
192 reducedGraph.insertNode(newRoot);
193
194 // 5. add edges
195 Set<V> containedNodes = sccs.getPartition(newRoot);
196
197 for (V sourceSCC : sourceSCCs) {
198 if (!containedNodes.contains(sourceSCC) && !sourceSCC.equals(newRoot)) {
199 reducedGraph.insertEdge(sourceSCC, newRoot);
200 }
201 }
202 for (V targetSCC : targetSCCs) {
203 if (!containedNodes.contains(targetSCC) && !targetSCC.equals(newRoot)) {
204 reducedGraph.insertEdge(newRoot, targetSCC);
205 }
206 }
207 } else {
208 if (observers.size() > 0 && GraphHelper.getEdgeCount(source, target, gds) == 1) {
209 counting.attachObserver(countingListener);
210 }
211 reducedGraph.insertEdge(sourceRoot, targetRoot);
212 counting.detachObserver(countingListener);
213 }
214 } else {
215 // Notifications about self-loops
216 if (observers.size() > 0 && sccs.getPartition(sourceRoot).size() == 1
217 && GraphHelper.getEdgeCount(source, target, gds) == 1) {
218 notifyTcObservers(source, source, Direction.INSERT);
219 }
220 }
221 }
222
223 @Override
224 public void edgeDeleted(V source, V target) {
225 V sourceRoot = sccs.find(source);
226 V targetRoot = sccs.find(target);
227
228 if (!sourceRoot.equals(targetRoot)) {
229 if (observers.size() > 0 && GraphHelper.getEdgeCount(source, target, gds) == 0) {
230 counting.attachObserver(countingListener);
231 }
232 reducedGraph.deleteEdgeIfExists(sourceRoot, targetRoot);
233 counting.detachObserver(countingListener);
234 } else {
235 // get the graph for the scc whose root is sourceRoot
236 Graph<V> g = GraphHelper.getSubGraph(sccs.getPartition(sourceRoot), gds);
237
238 // if source is not reachable from target anymore
239 if (!BFS.isReachable(source, target, g)) {
240 // create copies of the current state before destructive manipulation
241 Map<V, Integer> reachableSources = CollectionsFactory.createMap();
242 for (Entry<V, Integer> entry : reducedGraphIndexer.getSourceNodes(sourceRoot).entriesWithMultiplicities()) {
243 reachableSources.put(entry.getKey(), entry.getValue());
244 }
245 Map<V, Integer> reachableTargets = CollectionsFactory.createMap();
246 for (Entry<V, Integer> entry : reducedGraphIndexer.getTargetNodes(sourceRoot).entriesWithMultiplicities()) {
247 reachableTargets.put(entry.getKey(), entry.getValue());
248 }
249
250 SCCResult<V> _newSccs = SCC.computeSCC(g);
251
252 // delete scc node (and with its edges too)
253 for (Entry<V, Integer> entry : reachableSources.entrySet()) {
254 V s = entry.getKey();
255 for (int i = 0; i < entry.getValue(); i++) {
256 reducedGraph.deleteEdgeIfExists(s, sourceRoot);
257 }
258 }
259
260 for (Entry<V, Integer> entry : reachableTargets.entrySet()) {
261 V t = entry.getKey();
262 for (int i = 0; i < entry.getValue(); i++) {
263 reducedGraph.deleteEdgeIfExists(sourceRoot, t);
264 }
265 }
266
267 sccs.deleteSet(sourceRoot);
268 reducedGraph.deleteNode(sourceRoot);
269
270 Set<Set<V>> newSCCs = _newSccs.getSccs();
271 Set<V> newSCCRoots = CollectionsFactory.createSet();
272
273 // add new nodes and edges to the reduced graph
274 for (Set<V> newSCC : newSCCs) {
275 V newRoot = sccs.makeSet(newSCC);
276 reducedGraph.insertNode(newRoot);
277 newSCCRoots.add(newRoot);
278 }
279 for (V newSCCRoot : newSCCRoots) {
280 List<V> sourceSCCsOfSCC = getSourceSCCsOfSCC(newSCCRoot);
281 List<V> targetSCCsOfSCC = getTargetSCCsOfSCC(newSCCRoot);
282
283 for (V sourceSCC : sourceSCCsOfSCC) {
284 if (!sourceSCC.equals(newSCCRoot)) {
285 reducedGraph.insertEdge(sccs.find(sourceSCC), newSCCRoot);
286 }
287 }
288 for (V targetSCC : targetSCCsOfSCC) {
289 if (!newSCCRoots.contains(targetSCC) && !targetSCC.equals(newSCCRoot))
290 reducedGraph.insertEdge(newSCCRoot, targetSCC);
291 }
292 }
293
294 // Must be after the union-find modifications
295 if (observers.size() > 0) {
296 V newSourceRoot = sccs.find(source);
297 V newTargetRoot = sccs.find(target);
298
299 Set<V> sourceSCCs = createSetNullTolerant(counting.getAllReachableSources(newSourceRoot));
300 sourceSCCs.add(newSourceRoot);
301
302 Set<V> targetSCCs = createSetNullTolerant(counting.getAllReachableTargets(newTargetRoot));
303 targetSCCs.add(newTargetRoot);
304
305 for (V sourceSCC : sourceSCCs) {
306 targetLoop: for (V targetSCC : targetSCCs) {
307 if (counting.isReachable(sourceSCC, targetSCC)) continue targetLoop;
308
309 boolean needsNotification =
310 // Case 1. sourceSCC and targetSCC are the same and it is a one sized scc.
311 // Issue notifications only if there is no self-loop present at the moment
312 (sourceSCC.equals(targetSCC) && sccs.getPartition(sourceSCC).size() == 1 && GraphHelper
313 .getEdgeCount(sccs.getPartition(sourceSCC).iterator().next(), gds) == 0)
314 ||
315 // Case 2. sourceSCC and targetSCC are different sccs.
316 (!sourceSCC.equals(targetSCC));
317 // if self loop is already present omit the notification
318 if (needsNotification) {
319 notifyTcObservers(sccs.getPartition(sourceSCC), sccs.getPartition(targetSCC),
320 Direction.DELETE);
321 }
322 }
323 }
324 }
325 } else {
326 // only handle self-loop notifications - sourceRoot equals to targetRoot
327 if (observers.size() > 0 && sccs.getPartition(sourceRoot).size() == 1
328 && GraphHelper.getEdgeCount(source, target, gds) == 0) {
329 notifyTcObservers(source, source, Direction.DELETE);
330 }
331 }
332 }
333 }
334
335 @Override
336 public void nodeInserted(V n) {
337 sccs.makeSet(n);
338 reducedGraph.insertNode(n);
339 }
340
341 @Override
342 public void nodeDeleted(V n) {
343 IMemoryView<V> sources = gds.getSourceNodes(n);
344 IMemoryView<V> targets = gds.getTargetNodes(n);
345
346 for (Entry<V, Integer> entry : sources.entriesWithMultiplicities()) {
347 for (int i = 0; i < entry.getValue(); i++) {
348 V source = entry.getKey();
349 edgeDeleted(source, n);
350 }
351 }
352
353 for (Entry<V, Integer> entry : targets.entriesWithMultiplicities()) {
354 for (int i = 0; i < entry.getValue(); i++) {
355 V target = entry.getKey();
356 edgeDeleted(n, target);
357 }
358 }
359
360 sccs.deleteSet(n);
361 }
362
363 @Override
364 public void attachObserver(ITcObserver<V> to) {
365 observers.add(to);
366 }
367
368 @Override
369 public void detachObserver(ITcObserver<V> to) {
370 observers.remove(to);
371 }
372
373 @Override
374 public Set<V> getAllReachableTargets(V source) {
375 V sourceRoot = sccs.find(source);
376 Set<V> containedNodes = sccs.getPartition(sourceRoot);
377 Set<V> targets = CollectionsFactory.createSet();
378
379 if (containedNodes.size() > 1 || GraphHelper.getEdgeCount(source, gds) == 1) {
380 targets.addAll(containedNodes);
381 }
382
383 Set<V> rootSet = counting.getAllReachableTargets(sourceRoot);
384 if (rootSet != null) {
385 for (V _root : rootSet) {
386 targets.addAll(sccs.getPartition(_root));
387 }
388 }
389
390 return targets;
391 }
392
393 @Override
394 public Set<V> getAllReachableSources(V target) {
395 V targetRoot = sccs.find(target);
396 Set<V> containedNodes = sccs.getPartition(targetRoot);
397 Set<V> sources = CollectionsFactory.createSet();
398
399 if (containedNodes.size() > 1 || GraphHelper.getEdgeCount(target, gds) == 1) {
400 sources.addAll(containedNodes);
401 }
402
403 Set<V> rootSet = counting.getAllReachableSources(targetRoot);
404 if (rootSet != null) {
405 for (V _root : rootSet) {
406 sources.addAll(sccs.getPartition(_root));
407 }
408 }
409 return sources;
410 }
411
412 @Override
413 public boolean isReachable(V source, V target) {
414 V sourceRoot = sccs.find(source);
415 V targetRoot = sccs.find(target);
416
417 if (sourceRoot.equals(targetRoot))
418 return true;
419 else
420 return counting.isReachable(sourceRoot, targetRoot);
421 }
422
423 public List<V> getReachabilityPath(V source, V target) {
424 if (!isReachable(source, target)) {
425 return null;
426 } else {
427 Set<V> sccsInSubGraph = CollectionHelper.intersection(counting.getAllReachableTargets(source),
428 counting.getAllReachableSources(target));
429 sccsInSubGraph.add(sccs.find(source));
430 sccsInSubGraph.add(sccs.find(target));
431 Set<V> nodesInSubGraph = CollectionsFactory.createSet();
432
433 for (V sccRoot : sccsInSubGraph) {
434 nodesInSubGraph.addAll(sccs.getPartition(sccRoot));
435 }
436
437 return GraphHelper.constructPath(source, target, nodesInSubGraph, gds);
438 }
439 }
440
441 // for JUnit
442 public boolean checkTcRelation(DRedTcRelation<V> tc) {
443
444 for (V s : tc.getTupleStarts()) {
445 for (V t : tc.getTupleEnds(s)) {
446 if (!isReachable(s, t))
447 return false;
448 }
449 }
450
451 for (V root : counting.getTcRelation().getTupleStarts()) {
452 for (V end : counting.getTcRelation().getTupleEnds(root)) {
453 for (V s : sccs.getPartition(root)) {
454 for (V t : sccs.getPartition(end)) {
455 if (!tc.containsTuple(s, t))
456 return false;
457 }
458 }
459 }
460 }
461
462 return true;
463 }
464
465 /**
466 * Return the SCCs from which the SCC represented by the root node is reachable. Note that an SCC can be present
467 * multiple times in the returned list (multiple edges between the two SCCs).
468 *
469 * @param root
470 * @return the list of reachable target SCCs
471 */
472 private List<V> getSourceSCCsOfSCC(V root) {
473 List<V> sourceSCCs = new ArrayList<V>();
474
475 for (V containedNode : this.sccs.getPartition(root)) {
476 IMemoryView<V> sourceNodes = this.gds.getSourceNodes(containedNode);
477 for (V source : sourceNodes.distinctValues()) {
478 sourceSCCs.add(this.sccs.find(source));
479 }
480 }
481
482 return sourceSCCs;
483 }
484
485 /**
486 * Returns true if the SCC represented by the given root node has incoming edges in the reduced graph,
487 * false otherwise (if this SCC is a source in the reduced graph).
488 *
489 * @param root the root node of an SCC
490 * @return true if it has incoming edges, false otherwise
491 * @since 1.6
492 */
493 public boolean hasIncomingEdges(final V root) {
494 for (final V containedNode : this.sccs.getPartition(root)) {
495 final IMemoryView<V> sourceNodes = this.gds.getSourceNodes(containedNode);
496 for (final V source : sourceNodes.distinctValues()) {
497 final V otherRoot = this.sccs.find(source);
498 if (!Objects.equals(root, otherRoot)) {
499 return true;
500 }
501 }
502 }
503 return false;
504 }
505
506 /**
507 * Return the SCCs which are reachable from the SCC represented by the root node. Note that an SCC can be present
508 * multiple times in the returned list (multiple edges between the two SCCs).
509 *
510 * @param root
511 * @return the list of reachable target SCCs
512 */
513 private List<V> getTargetSCCsOfSCC(V root) {
514 List<V> targetSCCs = new ArrayList<V>();
515
516 for (V containedNode : this.sccs.getPartition(root)) {
517 IMemoryView<V> targetNodes = this.gds.getTargetNodes(containedNode);
518 for (V target : targetNodes.distinctValues()) {
519 targetSCCs.add(this.sccs.find(target));
520 }
521 }
522
523 return targetSCCs;
524 }
525
526 /**
527 * Returns true if the SCC represented by the given root node has outgoing edges in the reduced graph,
528 * false otherwise (if this SCC is a sink in the reduced graph).
529 *
530 * @param root the root node of an SCC
531 * @return true if it has outgoing edges, false otherwise
532 * @since 1.6
533 */
534 public boolean hasOutgoingEdges(V root) {
535 for (final V containedNode : this.sccs.getPartition(root)) {
536 final IMemoryView<V> targetNodes = this.gds.getTargetNodes(containedNode);
537 for (final V target : targetNodes.distinctValues()) {
538 final V otherRoot = this.sccs.find(target);
539 if (!Objects.equals(root, otherRoot)) {
540 return true;
541 }
542 }
543 }
544 return false;
545 }
546
547 @Override
548 public void dispose() {
549 gds.detachObserver(this);
550 counting.dispose();
551 }
552
553 /**
554 * Call this method to notify the observers of the transitive closure relation. The tuples used in the notification
555 * will be the Descartes product of the two sets given.
556 *
557 * @param sources
558 * the source nodes
559 * @param targets
560 * the target nodes
561 * @param direction
562 */
563 protected void notifyTcObservers(Set<V> sources, Set<V> targets, Direction direction) {
564 for (V s : sources) {
565 for (V t : targets) {
566 notifyTcObservers(s, t, direction);
567 }
568 }
569 }
570
571 private void notifyTcObservers(V source, V target, Direction direction) {
572 for (ITcObserver<V> observer : observers) {
573 if (direction == Direction.INSERT) {
574 observer.tupleInserted(source, target);
575 }
576 if (direction == Direction.DELETE) {
577 observer.tupleDeleted(source, target);
578 }
579 }
580 }
581
582 /**
583 * Returns the node that is selected as the representative of the SCC containing the argument.
584 * @since 1.6
585 */
586 public V getRepresentative(V node) {
587 return sccs.find(node);
588 }
589
590 public Set<Tuple<V>> getTcRelation() {
591 Set<Tuple<V>> resultSet = new HashSet<Tuple<V>>();
592
593 for (V sourceRoot : sccs.getPartitionHeads()) {
594 Set<V> sources = sccs.getPartition(sourceRoot);
595 if (sources.size() > 1 || GraphHelper.getEdgeCount(sources.iterator().next(), gds) == 1) {
596 for (V source : sources) {
597 for (V target : sources) {
598 resultSet.add(new Tuple<V>(source, target));
599 }
600 }
601 }
602
603 Set<V> reachableTargets = counting.getAllReachableTargets(sourceRoot);
604 if (reachableTargets != null) {
605 for (V targetRoot : reachableTargets) {
606 for (V source : sources) {
607 for (V target : sccs.getPartition(targetRoot)) {
608 resultSet.add(new Tuple<V>(source, target));
609 }
610 }
611 }
612 }
613 }
614
615 return resultSet;
616 }
617
618 public boolean isIsolated(V node) {
619 IMemoryView<V> targets = gds.getTargetNodes(node);
620 IMemoryView<V> sources = gds.getSourceNodes(node);
621 return targets.isEmpty() && sources.isEmpty();
622 }
623
624 @Override
625 public IGraphPathFinder<V> getPathFinder() {
626 return new DFSPathFinder<V>(gds, this);
627 }
628
629 /**
630 * The graph of SCCs; each SCC is represented by its representative node (see {@link #getRepresentative(Object)})
631 * @since 1.6
632 */
633 public Graph<V> getReducedGraph() {
634 return reducedGraph;
635 }
636
637 private static <V> Set<V> createSetNullTolerant(Set<V> initial) {
638 if (initial != null)
639 return CollectionsFactory.createSet(initial);
640 else
641 return CollectionsFactory.createSet();
642 }
643
644
645}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/DFSPathFinder.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/DFSPathFinder.java
new file mode 100644
index 00000000..51017b1a
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/DFSPathFinder.java
@@ -0,0 +1,146 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Abel Hegedus and IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.base.itc.alg.misc;
10
11import java.util.ArrayList;
12import java.util.Deque;
13import java.util.HashSet;
14import java.util.Iterator;
15import java.util.LinkedList;
16import java.util.List;
17import java.util.Set;
18
19import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource;
20import tools.refinery.viatra.runtime.base.itc.igraph.ITcDataSource;
21import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
22
23/**
24 * A depth-first search implementation of the {@link IGraphPathFinder}.
25 *
26 * TODO use ITC to filter nodes that must be traversed, instead of checks
27 *
28 * @author Abel Hegedus
29 *
30 * @param <V>
31 * the node type of the graph
32 */
33public class DFSPathFinder<V> implements IGraphPathFinder<V> {
34
35 private IGraphDataSource<V> graph;
36 private ITcDataSource<V> itc;
37
38 public DFSPathFinder(IGraphDataSource<V> graph, ITcDataSource<V> itc) {
39 this.graph = graph;
40 this.itc = itc;
41 }
42
43 @Override
44 public Iterable<Deque<V>> getAllPaths(V sourceNode, V targetNode) {
45 Set<V> endNodes = new HashSet<V>();
46 endNodes.add(targetNode);
47 return getAllPathsToTargets(sourceNode, endNodes);
48 }
49
50 @Override
51 public Iterable<Deque<V>> getAllPathsToTargets(V sourceNode, Set<V> targetNodes) {
52 List<Deque<V>> paths = new ArrayList<Deque<V>>();
53 Deque<V> visited = new LinkedList<V>();
54 Set<V> reachableTargets = new HashSet<V>();
55 for (V targetNode : targetNodes) {
56 if (itc.isReachable(sourceNode, targetNode)) {
57 reachableTargets.add(targetNode);
58 }
59 }
60 if (!reachableTargets.isEmpty()) {
61 return paths;
62 }
63 visited.add(sourceNode);
64 return getPaths(paths, visited, reachableTargets);
65 }
66
67 protected Iterable<Deque<V>> getPaths(List<Deque<V>> paths, Deque<V> visited, Set<V> targetNodes) {
68 IMemoryView<V> nodes = graph.getTargetNodes(visited.getLast());
69 // examine adjacent nodes
70 for (V node : nodes.distinctValues()) {
71 if (visited.contains(node)) {
72 continue;
73 }
74 if (targetNodes.contains(node)) {
75 visited.add(node);
76 // clone visited LinkedList
77 Deque<V> visitedClone = new LinkedList<V>(visited);
78 paths.add(visitedClone);
79 visited.removeLast();
80 break;
81 }
82 }
83
84 // in breadth-first, recursion needs to come after visiting connected nodes
85 for (V node : nodes.distinctValues()) {
86 if (visited.contains(node) || targetNodes.contains(node)) {
87 continue;
88 }
89 boolean canReachTarget = false;
90 for (V target : targetNodes) {
91 if (itc.isReachable(node, target)) {
92 canReachTarget = true;
93 break;
94 }
95 }
96 if (canReachTarget) {
97 visited.addLast(node);
98 getPaths(paths, visited, targetNodes);
99 visited.removeLast();
100 }
101 }
102
103 return paths;
104 }
105
106 public String printPaths(List<Deque<V>> paths) {
107 StringBuilder sb = new StringBuilder();
108 for (Deque<V> visited : paths) {
109 sb.append("Path: ");
110 for (V node : visited) {
111 sb.append(node);
112 sb.append(" --> ");
113 }
114 sb.append("\n");
115 }
116 return sb.toString();
117 }
118
119 @Override
120 public Deque<V> getPath(V sourceNode, V targetNode) {
121 // TODO optimize
122 Iterable<Deque<V>> allPaths = getAllPaths(sourceNode, targetNode);
123 Iterator<Deque<V>> pathIterator = allPaths.iterator();
124 return pathIterator.hasNext() ? pathIterator.next() : new LinkedList<V>();
125 }
126
127 @Override
128 public Iterable<Deque<V>> getShortestPaths(V sourceNode, V targetNode) {
129 // TODO optimize
130 Iterable<Deque<V>> allPaths = getAllPaths(sourceNode, targetNode);
131 List<Deque<V>> shortestPaths = new ArrayList<Deque<V>>();
132 int shortestPathLength = -1;
133 for (Deque<V> path : allPaths) {
134 int pathLength = path.size();
135 if (shortestPathLength == -1 || pathLength < shortestPathLength) {
136 shortestPaths.clear();
137 shortestPathLength = pathLength;
138 }
139 if (pathLength == shortestPathLength) {
140 shortestPaths.add(path);
141 }
142 }
143 return shortestPaths;
144 }
145
146}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/Edge.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/Edge.java
new file mode 100644
index 00000000..cf68d36a
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/Edge.java
@@ -0,0 +1,38 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.alg.misc;
11
12public class Edge<V> {
13 private V source;
14 private V target;
15
16 public Edge(V source, V target) {
17 super();
18 this.source = source;
19 this.target = target;
20 }
21
22 public V getSource() {
23 return source;
24 }
25
26 public void setSource(V source) {
27 this.source = source;
28 }
29
30 public V getTarget() {
31 return target;
32 }
33
34 public void setTarget(V target) {
35 this.target = target;
36 }
37
38}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/GraphHelper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/GraphHelper.java
new file mode 100644
index 00000000..194e979b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/GraphHelper.java
@@ -0,0 +1,173 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.base.itc.alg.misc;
10
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.HashSet;
14import java.util.List;
15import java.util.Map.Entry;
16import java.util.Set;
17
18import tools.refinery.viatra.runtime.base.itc.graphimpl.Graph;
19import tools.refinery.viatra.runtime.base.itc.igraph.IBiDirectionalGraphDataSource;
20import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource;
21import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
22
23/**
24 * Utility class for graph related operations.
25 *
26 * @author Tamas Szabo
27 */
28public class GraphHelper {
29
30 private GraphHelper() {/*Utility class constructor*/}
31
32 /**
33 * Returns the subgraph from the given {@link IBiDirectionalGraphDataSource} which contains the given set of nodes.
34 *
35 * @param nodesInSubGraph
36 * the nodes that are present in the subgraph
37 * @param graphDataSource
38 * the graph data source for the original graph
39 * @return the subgraph associated to the given nodes
40 */
41 public static <V> Graph<V> getSubGraph(Collection<V> nodesInSubGraph,
42 IBiDirectionalGraphDataSource<V> graphDataSource) {
43 Graph<V> g = new Graph<V>();
44 if (nodesInSubGraph != null) {
45 for (V node : nodesInSubGraph) {
46 g.insertNode(node);
47 }
48
49 for (V node : nodesInSubGraph) {
50 IMemoryView<V> sources = graphDataSource.getSourceNodes(node);
51 for (Entry<V, Integer> entry : sources.entriesWithMultiplicities()) {
52 for (int i = 0; i < entry.getValue(); i++) {
53 V s = entry.getKey();
54 if (nodesInSubGraph.contains(s)) {
55 g.insertEdge(s, node);
56 }
57 }
58 }
59 }
60 }
61
62 return g;
63 }
64
65 /**
66 * Constructs a path between source and target in the given graph. Both the {@link IGraphDataSource} and the set of
67 * nodes are used, this way it is possible to construct a path in a given subgraph.
68 *
69 * The returned {@link List} contains the nodes along the path (this means that there is an edge in the graph
70 * between two consecutive nodes). A self loop (one edge) is indicated with the source node being present two times
71 * in the returned {@link List}.
72 *
73 * @param source
74 * the source node
75 * @param target
76 * the target node
77 * @param nodesInGraph
78 * the nodes that are present in the subgraph
79 * @param graphDataSource
80 * the graph data source
81 * @return the path between the two nodes
82 */
83 public static <V> List<V> constructPath(V source, V target, Set<V> nodesInGraph,
84 IGraphDataSource<V> graphDataSource) {
85 Set<V> visitedNodes = new HashSet<V>();
86 List<V> path = new ArrayList<V>();
87
88 visitedNodes.add(source);
89 path.add(source);
90 V act = source;
91
92 // if source and target are the same node
93 if (source.equals(target) && graphDataSource.getTargetNodes(source).containsNonZero(target)) {
94 // the node will be present in the path two times
95 path.add(source);
96 return path;
97 } else {
98 while (act != null) {
99 V nextNode = getNextNodeToVisit(act, graphDataSource, nodesInGraph, visitedNodes);
100 if (nextNode == null && path.size() > 1) {
101 // needs to backtrack along path
102 // remove the last element in the path because we can't go
103 // anywhere from there
104 path.remove(path.size() - 1);
105 while (nextNode == null && path.size() > 0) {
106 V lastPathElement = path.get(path.size() - 1);
107 nextNode = getNextNodeToVisit(lastPathElement, graphDataSource, nodesInGraph, visitedNodes);
108 if (nextNode == null) {
109 path.remove(path.size() - 1);
110 }
111 }
112 }
113
114 if (nextNode != null) {
115 visitedNodes.add(nextNode);
116 path.add(nextNode);
117 if (nextNode.equals(target)) {
118 return path;
119 }
120 }
121 act = nextNode;
122 }
123 return null;
124 }
125 }
126
127 private static <V> V getNextNodeToVisit(V act, IGraphDataSource<V> graphDataSource, Set<V> nodesInSubGraph,
128 Set<V> visitedNodes) {
129 IMemoryView<V> targetNodes = graphDataSource.getTargetNodes(act);
130 for (Entry<V, Integer> entry : targetNodes.entriesWithMultiplicities()) {
131 for (int i = 0; i < entry.getValue(); i++) {
132 V node = entry.getKey();
133 if (nodesInSubGraph.contains(node) && !visitedNodes.contains(node)) {
134 return node;
135 }
136 }
137 }
138 return null;
139 }
140
141 /**
142 * Returns the number of self-loop edges for the given node.
143 *
144 * @param node
145 * the node
146 * @param graphDataSource
147 * the graph data source
148 * @return the number of self-loop edges
149 */
150 public static <V> int getEdgeCount(V node, IGraphDataSource<V> graphDataSource) {
151 return getEdgeCount(node, node, graphDataSource);
152 }
153
154 /**
155 * Returns the number of edges between the given source and target nodes.
156 *
157 * @param source
158 * the source node
159 * @param target
160 * the target node
161 * @param graphDataSource
162 * the graph data source
163 * @return the number of parallel edges between the two nodes
164 */
165 public static <V> int getEdgeCount(V source, V target, IGraphDataSource<V> graphDataSource) {
166 Integer count = graphDataSource.getTargetNodes(source).getCount(target);
167 if (count == null) {
168 return 0;
169 } else {
170 return count;
171 }
172 }
173}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/IGraphPathFinder.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/IGraphPathFinder.java
new file mode 100644
index 00000000..cebb09c8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/IGraphPathFinder.java
@@ -0,0 +1,67 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Abel Hegedus, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.base.itc.alg.misc;
10
11import java.util.Deque;
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.base.itc.igraph.ITcDataSource;
15
16/**
17 * The path finder provides methods for retrieving paths in a graph between a source node and one or more target nodes.
18 * Use {@link ITcDataSource#getPathFinder()} for instantiating.
19 *
20 * @author Abel Hegedus
21 *
22 * @param <V> the node type of the graph
23 */
24public interface IGraphPathFinder<V> {
25
26 /**
27 * Returns an arbitrary path from the source node to the target node (if such exists). If there is no path
28 * between them, an empty collection is returned.
29 *
30 * @param sourceNode the source node of the path
31 * @param targetNode the target node of the path
32 * @return the path from the source to the target, or empty collection if target is not reachable from source.
33 */
34 Deque<V> getPath(V sourceNode, V targetNode);
35
36 /**
37 * Returns the collection of shortest paths from the source node to the target node (if such exists). If there is no path
38 * between them, an empty collection is returned.
39 *
40 * @param sourceNode the source node of the path
41 * @param targetNode the target node of the path
42 * @return the collection of shortest paths from the source to the target, or empty collection if target is not reachable from source.
43 */
44 Iterable<Deque<V>> getShortestPaths(V sourceNode, V targetNode);
45
46 /**
47 * Returns the collection of paths from the source node to the target node (if such exists). If there is no path
48 * between them, an empty collection is returned.
49 *
50 * @param sourceNode the source node of the path
51 * @param targetNode the target node of the path
52 * @return the collection of paths from the source to the target, or empty collection if target is not reachable from source.
53 */
54 Iterable<Deque<V>> getAllPaths(V sourceNode, V targetNode);
55
56 /**
57 * Returns the collection of paths from the source node to any of the target nodes (if such exists). If there is no path
58 * between them, an empty collection is returned.
59 *
60 * @param sourceNode the source node of the path
61 * @param targetNodes the set of target nodes of the paths
62 * @return the collection of paths from the source to any of the targets, or empty collection if neither target is reachable from source.
63 */
64 Iterable<Deque<V>> getAllPathsToTargets(V sourceNode, Set<V> targetNodes);
65
66
67} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/ITcRelation.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/ITcRelation.java
new file mode 100644
index 00000000..a41ff6c7
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/ITcRelation.java
@@ -0,0 +1,31 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.alg.misc;
11
12import java.util.Set;
13
14public interface ITcRelation<V> {
15
16 /**
17 * Returns the starting nodes from a transitive closure relation.
18 *
19 * @return the set of starting nodes
20 */
21 public Set<V> getTupleStarts();
22
23 /**
24 * Returns the set of nodes that are reachable from the given node.
25 *
26 * @param start
27 * the starting node
28 * @return the set of reachable nodes
29 */
30 public Set<V> getTupleEnds(V start);
31}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/Tuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/Tuple.java
new file mode 100644
index 00000000..a2d54a59
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/Tuple.java
@@ -0,0 +1,60 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.alg.misc;
11
12public class Tuple<V> {
13
14 private V source;
15 private V target;
16
17 public Tuple(V source, V target) {
18 super();
19 this.source = source;
20 this.target = target;
21 }
22
23 public V getSource() {
24 return source;
25 }
26
27 public void setSource(V source) {
28 this.source = source;
29 }
30
31 public V getTarget() {
32 return target;
33 }
34
35 public void setTarget(V target) {
36 this.target = target;
37 }
38
39 @Override
40 public String toString() {
41 return "(" + source.toString() + "," + target.toString() + ")";
42 }
43
44 @Override
45 public boolean equals(Object o) {
46 if (o instanceof Tuple) {
47 Tuple<?> t = (Tuple<?>) o;
48
49 if (t.getSource().equals(this.source) && t.getTarget().equals(this.target)) {
50 return true;
51 }
52 }
53 return false;
54 }
55
56 @Override
57 public int hashCode() {
58 return source.hashCode() + target.hashCode();
59 }
60}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/bfs/BFS.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/bfs/BFS.java
new file mode 100644
index 00000000..798f31d2
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/bfs/BFS.java
@@ -0,0 +1,151 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.alg.misc.bfs;
11
12import java.util.ArrayList;
13import java.util.HashSet;
14import java.util.List;
15import java.util.Set;
16
17import tools.refinery.viatra.runtime.base.itc.igraph.IBiDirectionalGraphDataSource;
18import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource;
19
20public class BFS<V> {
21
22 private BFS() {/*Utility class constructor*/}
23
24 /**
25 * Performs a breadth first search on the given graph to determine whether source is reachable from target.
26 *
27 * @param <V>
28 * the type parameter of the nodes in the graph
29 * @param source
30 * the source node
31 * @param target
32 * the target node
33 * @param graph
34 * the graph data source
35 * @return true if source is reachable from target, false otherwise
36 */
37 public static <V> boolean isReachable(V source, V target, IGraphDataSource<V> graph) {
38 List<V> nodeQueue = new ArrayList<V>();
39 Set<V> visited = new HashSet<V>();
40
41 nodeQueue.add(source);
42 visited.add(source);
43
44 boolean ret = _isReachable(target, graph, nodeQueue, visited);
45 return ret;
46 }
47
48 private static <V> boolean _isReachable(V target, IGraphDataSource<V> graph, List<V> nodeQueue, Set<V> visited) {
49
50 while (!nodeQueue.isEmpty()) {
51 V node = nodeQueue.remove(0);
52 for (V t : graph.getTargetNodes(node).distinctValues()){
53 if (t.equals(target)) {
54 return true;
55 }
56 if (!visited.contains(t)) {
57 visited.add(t);
58 nodeQueue.add(t);
59 }
60 }
61 }
62 return false;
63 }
64
65 public static <V> Set<V> reachableSources(IBiDirectionalGraphDataSource<V> graph, V target) {
66 Set<V> retSet = new HashSet<V>();
67 retSet.add(target);
68 List<V> nodeQueue = new ArrayList<V>();
69 nodeQueue.add(target);
70
71 _reachableSources(graph, nodeQueue, retSet);
72
73 return retSet;
74 }
75
76 private static <V> void _reachableSources(IBiDirectionalGraphDataSource<V> graph, List<V> nodeQueue,
77 Set<V> retSet) {
78 while (!nodeQueue.isEmpty()) {
79 V node = nodeQueue.remove(0);
80 for (V _node : graph.getSourceNodes(node).distinctValues()) {
81 if (!retSet.contains(_node)) {
82 retSet.add(_node);
83 nodeQueue.add(_node);
84 }
85 }
86 }
87 }
88
89 public static <V> Set<V> reachableTargets(IGraphDataSource<V> graph, V source) {
90 Set<V> retSet = new HashSet<V>();
91 retSet.add(source);
92 List<V> nodeQueue = new ArrayList<V>();
93 nodeQueue.add(source);
94
95 _reachableTargets(graph, nodeQueue, retSet);
96
97 return retSet;
98 }
99
100 private static <V> void _reachableTargets(IGraphDataSource<V> graph, List<V> nodeQueue, Set<V> retSet) {
101 while (!nodeQueue.isEmpty()) {
102 V node = nodeQueue.remove(0);
103
104 for (V _node : graph.getTargetNodes(node).distinctValues()) {
105
106 if (!retSet.contains(_node)) {
107 retSet.add(_node);
108 nodeQueue.add(_node);
109 }
110 }
111 }
112 }
113
114 /**
115 * Performs a breadth first search on the given graph and collects all the nodes along the path from source to
116 * target if such path exists.
117 *
118 * @param <V>
119 * the type parameter of the nodes in the graph
120 * @param source
121 * the source node
122 * @param target
123 * the target node
124 * @param graph
125 * the graph data source
126 * @return the set of nodes along the path
127 */
128 public static <V> Set<V> collectNodesAlongPath(V source, V target, IGraphDataSource<V> graph) {
129 Set<V> path = new HashSet<V>();
130 _collectNodesAlongPath(source, target, graph, path);
131 return path;
132 }
133
134 private static <V> boolean _collectNodesAlongPath(V node, V target, IGraphDataSource<V> graph, Set<V> path) {
135
136 boolean res = false;
137
138 // end recursion
139 if (node.equals(target)) {
140 path.add(node);
141 return true;
142 } else {
143 for (V _nodeT : graph.getTargetNodes(node).distinctValues()) {
144 res = (_collectNodesAlongPath(_nodeT, target, graph, path)) || res;
145 }
146 if (res)
147 path.add(node);
148 return res;
149 }
150 }
151}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/dfs/DFSAlg.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/dfs/DFSAlg.java
new file mode 100644
index 00000000..c8d25c4e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/dfs/DFSAlg.java
@@ -0,0 +1,93 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.alg.misc.dfs;
11
12import java.util.HashMap;
13
14import tools.refinery.viatra.runtime.base.itc.alg.dred.DRedTcRelation;
15import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource;
16import tools.refinery.viatra.runtime.base.itc.igraph.IGraphObserver;
17
18public class DFSAlg<V> implements IGraphObserver<V> {
19
20 private IGraphDataSource<V> gds;
21 private DRedTcRelation<V> tc;
22 private int[] visited;
23 private HashMap<V, Integer> nodeMap;
24
25 public DFSAlg(IGraphDataSource<V> gds) {
26 this.gds = gds;
27 this.tc = new DRedTcRelation<V>();
28 gds.attachObserver(this);
29 deriveTc();
30 }
31
32 private void deriveTc() {
33 tc.clear();
34
35 this.visited = new int[gds.getAllNodes().size()];
36 nodeMap = new HashMap<V, Integer>();
37
38 int j = 0;
39 for (V n : gds.getAllNodes()) {
40 nodeMap.put(n, j);
41 j++;
42 }
43
44 for (V n : gds.getAllNodes()) {
45 oneDFS(n, n);
46 initVisitedArray();
47 }
48 }
49
50 private void initVisitedArray() {
51 for (int i = 0; i < visited.length; i++)
52 visited[i] = 0;
53 }
54
55 private void oneDFS(V act, V source) {
56
57 if (!act.equals(source)) {
58 tc.addTuple(source, act);
59 }
60
61 visited[nodeMap.get(act)] = 1;
62
63 for (V t : gds.getTargetNodes(act).distinctValues()) {
64 if (visited[nodeMap.get(t)] == 0) {
65 oneDFS(t, source);
66 }
67 }
68 }
69
70 public DRedTcRelation<V> getTcRelation() {
71 return this.tc;
72 }
73
74 @Override
75 public void edgeInserted(V source, V target) {
76 deriveTc();
77 }
78
79 @Override
80 public void edgeDeleted(V source, V target) {
81 deriveTc();
82 }
83
84 @Override
85 public void nodeInserted(V n) {
86 deriveTc();
87 }
88
89 @Override
90 public void nodeDeleted(V n) {
91 deriveTc();
92 }
93}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/PKAlg.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/PKAlg.java
new file mode 100644
index 00000000..c99a48ab
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/PKAlg.java
@@ -0,0 +1,179 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.alg.misc.scc;
11
12import java.util.ArrayList;
13import java.util.Collections;
14import java.util.HashMap;
15import java.util.List;
16import java.util.Map;
17
18import tools.refinery.viatra.runtime.base.itc.igraph.IBiDirectionalGraphDataSource;
19import tools.refinery.viatra.runtime.base.itc.igraph.IBiDirectionalWrapper;
20import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource;
21import tools.refinery.viatra.runtime.base.itc.igraph.IGraphObserver;
22
23public class PKAlg<V> implements IGraphObserver<V> {
24
25 /**
26 * Maps the nodes to their indicies.
27 */
28 private Map<V, Integer> node2index;
29 private Map<Integer, V> index2node;
30 private Map<V, Boolean> node2mark;
31
32 /**
33 * Maps the index of a node to the index in the topsort.
34 */
35 private Map<Integer, Integer> index2topsort;
36 private Map<Integer, Integer> topsort2index;
37
38 /**
39 * Index associated to the inserted nodes (incrementing with every insertion).
40 */
41 private int index;
42
43 /**
44 * Index within the topsort for the target node when edge insertion occurs.
45 */
46 private int lower_bound;
47
48 /**
49 * Index within the topsort for the source node when edge insertion occurs.
50 */
51 private int upper_bound;
52
53 private List<V> RF;
54 private List<V> RB;
55 private IBiDirectionalGraphDataSource<V> gds;
56
57 public PKAlg(IGraphDataSource<V> gds) {
58 if (gds instanceof IBiDirectionalGraphDataSource<?>) {
59 this.gds = (IBiDirectionalGraphDataSource<V>) gds;
60 } else {
61 this.gds = new IBiDirectionalWrapper<V>(gds);
62 }
63
64 node2mark = new HashMap<V, Boolean>();
65 node2index = new HashMap<V, Integer>();
66 index2node = new HashMap<Integer, V>();
67 index2topsort = new HashMap<Integer, Integer>();
68 topsort2index = new HashMap<Integer, Integer>();
69 index = 0;
70
71 gds.attachObserver(this);
72 }
73
74 @Override
75 public void edgeInserted(V source, V target) {
76
77 RF = new ArrayList<V>();
78 RB = new ArrayList<V>();
79
80 lower_bound = index2topsort.get(node2index.get(target));
81 upper_bound = index2topsort.get(node2index.get(source));
82
83 if (lower_bound < upper_bound) {
84 dfsForward(target);
85 dfsBackward(source);
86 reorder();
87 }
88 }
89
90 private List<Integer> getIndicies(List<V> list) {
91 List<Integer> indicies = new ArrayList<Integer>();
92
93 for (V n : list)
94 indicies.add(index2topsort.get(node2index.get(n)));
95
96 return indicies;
97 }
98
99 private void reorder() {
100
101 Collections.reverse(RB);
102
103 // azon csomopontok indexei amelyek sorrendje nem jo
104 List<Integer> L = getIndicies(RF);
105 L.addAll(getIndicies(RB));
106 Collections.sort(L);
107
108 for (int i = 0; i < RB.size(); i++) {
109 index2topsort.put(node2index.get(RB.get(i)), L.get(i));
110 topsort2index.put(L.get(i), node2index.get(RB.get(i)));
111 }
112
113 for (int i = 0; i < RF.size(); i++) {
114 index2topsort.put(node2index.get(RF.get(i)), L.get(i + RB.size()));
115 topsort2index.put(L.get(i + RB.size()), node2index.get(RF.get(i)));
116 }
117 }
118
119 @SuppressWarnings("unused")
120 private List<V> getTopSort() {
121 List<V> topsort = new ArrayList<V>();
122
123 for (int i : topsort2index.values()) {
124 topsort.add(index2node.get(i));
125 }
126
127 return topsort;
128 }
129
130 private void dfsBackward(V node) {
131 node2mark.put(node, true);
132 RB.add(node);
133
134 for (V sn : gds.getSourceNodes(node).distinctValues()) {
135 int top_id = index2topsort.get(node2index.get(sn));
136
137 if (!node2mark.get(sn) && lower_bound < top_id)
138 dfsBackward(sn);
139 }
140 }
141
142 private void dfsForward(V node) {
143 node2mark.put(node, true);
144 RF.add(node);
145
146 for (V tn : gds.getTargetNodes(node).distinctValues()) {
147 int top_id = index2topsort.get(node2index.get(tn));
148
149 if (top_id == upper_bound)
150 System.out.println("!!!Cycle detected!!!");
151 else if (!node2mark.get(tn) && top_id < upper_bound)
152 dfsForward(tn);
153 }
154 }
155
156 @Override
157 public void edgeDeleted(V source, V target) {
158 // Edge deletion does not affect topsort
159 }
160
161 @Override
162 public void nodeInserted(V n) {
163 node2mark.put(n, false);
164 node2index.put(n, index);
165 index2node.put(index, n);
166 index2topsort.put(index, index);
167 topsort2index.put(index, index);
168 index++;
169 }
170
171 @Override
172 public void nodeDeleted(V n) {
173 node2mark.remove(n);
174 int node_id = node2index.remove(n);
175 index2node.remove(node_id);
176 int top_id = index2topsort.remove(node_id);
177 topsort2index.remove(top_id);
178 }
179}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCC.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCC.java
new file mode 100644
index 00000000..8915998b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCC.java
@@ -0,0 +1,146 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.alg.misc.scc;
11
12import java.util.HashSet;
13import java.util.Map;
14import java.util.Set;
15import java.util.Stack;
16
17import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource;
18import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
19
20/**
21 * Efficient algorithms to compute the Strongly Connected Components in a directed graph.
22 *
23 * @author Tamas Szabo
24 *
25 * @param <V>
26 * the type parameter of the nodes in the graph
27 */
28public class SCC<V> {
29
30 private SCC() {/*Utility class constructor*/}
31
32 public static long sccId = 0;
33
34 /**
35 * Computes the SCCs for the given graph and returns them as a multiset. (Iterative version of Tarjan's algorithm)
36 *
37 * @param g
38 * the directed graph data source
39 * @return the set of SCCs
40 */
41 public static <V> SCCResult<V> computeSCC(IGraphDataSource<V> g) {
42 int index = 0;
43 Set<Set<V>> ret = new HashSet<Set<V>>();
44
45 // stores the lowlink and index information for the given node
46 Map<V, SCCProperty> nodeMap = CollectionsFactory.createMap();
47
48 // stores all target nodes of a given node - the list will be modified
49 Map<V, Set<V>> targetNodeMap = CollectionsFactory.createMap();
50
51 // stores those target nodes for a given node which have not been visited
52 Map<V, Set<V>> notVisitedMap = CollectionsFactory.createMap();
53
54 // stores the nodes during the traversal
55 Stack<V> nodeStack = new Stack<V>();
56
57 // stores the nodes which belong to an scc (there can be many sccs in the stack at the same time)
58 Stack<V> sccStack = new Stack<V>();
59
60 boolean sink = false, finishedTraversal = true;
61
62 // initialize all nodes with 0 index and 0 lowlink
63 Set<V> allNodes = g.getAllNodes();
64 for (V n : allNodes) {
65 nodeMap.put(n, new SCCProperty(0, 0));
66 }
67
68 for (V n : allNodes) {
69 // if the node has not been visited yet
70 if (nodeMap.get(n).getIndex() == 0) {
71 nodeStack.push(n);
72
73 while (!nodeStack.isEmpty()) {
74 V currentNode = nodeStack.peek();
75 sink = false;
76 finishedTraversal = false;
77 SCCProperty prop = nodeMap.get(currentNode);
78
79 if (nodeMap.get(currentNode).getIndex() == 0) {
80 index++;
81 sccStack.push(currentNode);
82 prop.setIndex(index);
83 prop.setLowlink(index);
84
85 notVisitedMap.put(currentNode, new HashSet<V>());
86
87 // storing the target nodes of the actual node
88 if (g.getTargetNodes(currentNode) != null) {
89 Set<V> targets = g.getTargetNodes(currentNode).distinctValues();
90 targetNodeMap.put(currentNode, CollectionsFactory.createSet(targets));
91 }
92 }
93
94 if (targetNodeMap.get(currentNode) != null) {
95
96 // remove node from stack, the exploration of its children has finished
97 if (targetNodeMap.get(currentNode).size() == 0) {
98 targetNodeMap.remove(currentNode);
99
100 nodeStack.pop();
101
102 for (V targetNode : g.getTargetNodes(currentNode).distinctValues()) {
103 if (notVisitedMap.get(currentNode).contains(targetNode)) {
104 prop.setLowlink(Math.min(prop.getLowlink(), nodeMap.get(targetNode).getLowlink()));
105 } else if (sccStack.contains(targetNode)) {
106 prop.setLowlink(Math.min(prop.getLowlink(), nodeMap.get(targetNode).getIndex()));
107 }
108 }
109
110 finishedTraversal = true;
111 } else {
112 V targetNode = targetNodeMap.get(currentNode).iterator().next();
113 targetNodeMap.get(currentNode).remove(targetNode);
114 // if the targetNode has not yet been visited push it to the stack
115 // and mark it in the notVisitedMap
116 if (nodeMap.get(targetNode).getIndex() == 0) {
117 notVisitedMap.get(currentNode).add(targetNode);
118 nodeStack.add(targetNode);
119 }
120 }
121 }
122 // if currentNode has no target nodes
123 else {
124 nodeStack.pop();
125 sink = true;
126 }
127
128 // create scc if node is a sink or an scc has been found
129 if ((sink || finishedTraversal) && (prop.getLowlink() == prop.getIndex())) {
130 Set<V> sc = new HashSet<V>();
131 V targetNode = null;
132
133 do {
134 targetNode = sccStack.pop();
135 sc.add(targetNode);
136 } while (!targetNode.equals(currentNode));
137
138 ret.add(sc);
139 }
140 }
141 }
142 }
143
144 return new SCCResult<V>(ret, g);
145 }
146}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCCProperty.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCCProperty.java
new file mode 100644
index 00000000..b26e3d37
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCCProperty.java
@@ -0,0 +1,37 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.alg.misc.scc;
11
12public class SCCProperty {
13 private int index;
14 private int lowlink;
15
16 public SCCProperty(int index, int lowlink) {
17 super();
18 this.index = index;
19 this.lowlink = lowlink;
20 }
21
22 public int getIndex() {
23 return index;
24 }
25
26 public void setIndex(int index) {
27 this.index = index;
28 }
29
30 public int getLowlink() {
31 return lowlink;
32 }
33
34 public void setLowlink(int lowlink) {
35 this.lowlink = lowlink;
36 }
37}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCCResult.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCCResult.java
new file mode 100644
index 00000000..fde59d3b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/scc/SCCResult.java
@@ -0,0 +1,81 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.alg.misc.scc;
11
12import java.util.Map.Entry;
13import java.util.Set;
14
15import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource;
16
17public class SCCResult<V> {
18
19 private Set<Set<V>> sccs;
20 private IGraphDataSource<V> gds;
21
22 public SCCResult(Set<Set<V>> sccs, IGraphDataSource<V> gds) {
23 this.sccs = sccs;
24 this.gds = gds;
25 }
26
27 public Set<Set<V>> getSccs() {
28 return sccs;
29 }
30
31 public int getSCCCount() {
32 return sccs.size();
33 }
34
35 public double getAverageNodeCount() {
36 double a = 0;
37
38 for (Set<V> s : sccs) {
39 a += s.size();
40 }
41
42 return a / sccs.size();
43 }
44
45 public double getAverageEdgeCount() {
46 long edgeSum = 0;
47
48 for (Set<V> scc : sccs) {
49 for (V source : scc) {
50 for (Entry<V, Integer> entry : gds.getTargetNodes(source).entriesWithMultiplicities()) {
51 if (scc.contains(entry.getKey())) {
52 edgeSum += entry.getValue();
53 }
54 }
55 }
56 }
57
58 return (double) edgeSum / (double) sccs.size();
59 }
60
61 public int getBiggestSCCSize() {
62 int max = 0;
63
64 for (Set<V> scc : sccs) {
65 if (scc.size() > max)
66 max = scc.size();
67 }
68
69 return max;
70 }
71
72 public long getSumOfSquares() {
73 long sum = 0;
74
75 for (Set<V> scc : sccs) {
76 sum += scc.size() * scc.size();
77 }
78
79 return sum;
80 }
81}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/topsort/TopologicalSorting.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/topsort/TopologicalSorting.java
new file mode 100644
index 00000000..dd18e6c8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/misc/topsort/TopologicalSorting.java
@@ -0,0 +1,77 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.alg.misc.topsort;
11
12import java.util.HashSet;
13import java.util.LinkedList;
14import java.util.List;
15import java.util.Set;
16import java.util.Stack;
17
18import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource;
19
20/**
21 * @since 1.6
22 */
23public class TopologicalSorting {
24
25 private TopologicalSorting() {/*Utility class constructor*/}
26
27 private static final class Pair<T> {
28 public T element;
29 public boolean isParent;
30
31 public Pair(final T element, final boolean isParent) {
32 this.element = element;
33 this.isParent = isParent;
34 }
35 }
36
37 /**
38 * Returns a topological ordering for the given graph data source.
39 * Output format: if there is an a -> b (transitive) reachability, then node <code>a</code> will come before node <code>b</code> in the resulting list.
40 *
41 * @param gds the graph data source
42 * @return a topological ordering
43 */
44 public static <T> List<T> compute(final IGraphDataSource<T> gds) {
45 final Set<T> visited = new HashSet<T>();
46 final LinkedList<T> result = new LinkedList<T>();
47 final Stack<Pair<T>> dfsStack = new Stack<Pair<T>>();
48
49 for (final T node : gds.getAllNodes()) {
50 if (!visited.contains(node)) {
51 dfsStack.push(new Pair<T>(node, false));
52 }
53
54 while (!dfsStack.isEmpty()) {
55 final Pair<T> head = dfsStack.pop();
56 final T source = head.element;
57
58 if (head.isParent) {
59 // we have already seen source, push it to the resulting stack
60 result.addFirst(source);
61 } else {
62 // first time we see source, continue with its children
63 visited.add(source);
64 dfsStack.push(new Pair<T>(source, true));
65
66 for (final T target : gds.getTargetNodes(source).distinctValues()) {
67 if (!visited.contains(target)) {
68 dfsStack.push(new Pair<T>(target, false));
69 }
70 }
71 }
72 }
73 }
74
75 return result;
76 }
77}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/representative/RepresentativeElectionAlgorithm.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/representative/RepresentativeElectionAlgorithm.java
new file mode 100644
index 00000000..51015404
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/representative/RepresentativeElectionAlgorithm.java
@@ -0,0 +1,140 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.viatra.runtime.base.itc.alg.representative;
7
8import tools.refinery.viatra.runtime.base.itc.graphimpl.Graph;
9import tools.refinery.viatra.runtime.base.itc.igraph.IGraphObserver;
10import tools.refinery.viatra.runtime.matchers.util.Direction;
11
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.Map;
15import java.util.Set;
16
17public abstract class RepresentativeElectionAlgorithm implements IGraphObserver<Object> {
18 protected final Graph<Object> graph;
19 protected final Map<Object, Object> representatives = new HashMap<>();
20 protected final Map<Object, Set<Object>> components = new HashMap<>();
21 private RepresentativeObserver observer;
22
23 protected RepresentativeElectionAlgorithm(Graph<Object> graph) {
24 this.graph = graph;
25 initializeComponents();
26 graph.attachObserver(this);
27 }
28
29 protected abstract void initializeComponents();
30
31 protected void initializeSet(Set<Object> set) {
32 var iterator = set.iterator();
33 if (!iterator.hasNext()) {
34 // Set is empty.
35 return;
36 }
37 var representative = iterator.next();
38 for (var node : set) {
39 var oldRepresentative = representatives.put(node, representative);
40 if (oldRepresentative != null && !representative.equals(oldRepresentative)) {
41 throw new IllegalStateException("Node %s is already in a set represented by %s, cannot add it to %s"
42 .formatted(node, oldRepresentative, set));
43 }
44 }
45 components.put(representative, set);
46 }
47
48 protected void merge(Object leftRepresentative, Object rightRepresentative) {
49 if (leftRepresentative.equals(rightRepresentative)) {
50 return;
51 }
52 var leftSet = getComponent(leftRepresentative);
53 var rightSet = getComponent(rightRepresentative);
54 if (leftSet.size() < rightSet.size()) {
55 merge(rightRepresentative, rightSet, leftRepresentative, leftSet);
56 } else {
57 merge(leftRepresentative, leftSet, rightRepresentative, rightSet);
58 }
59 }
60
61 private void merge(Object preservedRepresentative, Set<Object> preservedSet, Object removedRepresentative,
62 Set<Object> removedSet) {
63 components.remove(removedRepresentative);
64 for (var node : removedSet) {
65 representatives.put(node, preservedRepresentative);
66 preservedSet.add(node);
67 notifyToObservers(node, removedRepresentative, preservedRepresentative);
68 }
69 }
70
71 protected void assignNewRepresentative(Object oldRepresentative, Set<Object> set) {
72 var iterator = set.iterator();
73 if (!iterator.hasNext()) {
74 return;
75 }
76 var newRepresentative = iterator.next();
77 components.put(newRepresentative, set);
78 for (var node : set) {
79 var oldRepresentativeOfNode = representatives.put(node, newRepresentative);
80 if (!oldRepresentative.equals(oldRepresentativeOfNode)) {
81 throw new IllegalArgumentException("Node %s was not represented by %s but by %s"
82 .formatted(node, oldRepresentative, oldRepresentativeOfNode));
83 }
84 notifyToObservers(node, oldRepresentative, newRepresentative);
85 }
86 }
87
88 public void setObserver(RepresentativeObserver observer) {
89 this.observer = observer;
90 }
91
92 public Map<Object, Set<Object>> getComponents() {
93 return components;
94 }
95
96 public Object getRepresentative(Object node) {
97 return representatives.get(node);
98 }
99
100 public Set<Object> getComponent(Object representative) {
101 return components.get(representative);
102 }
103
104 public void dispose() {
105 graph.detachObserver(this);
106 }
107
108 @Override
109 public void nodeInserted(Object n) {
110 var component = new HashSet<>(1);
111 component.add(n);
112 initializeSet(component);
113 notifyToObservers(n, n, Direction.INSERT);
114 }
115
116 @Override
117 public void nodeDeleted(Object n) {
118 var representative = representatives.remove(n);
119 if (!representative.equals(n)) {
120 throw new IllegalStateException("Trying to delete node with dangling edges");
121 }
122 components.remove(representative);
123 notifyToObservers(n, representative, Direction.DELETE);
124 }
125
126 protected void notifyToObservers(Object node, Object oldRepresentative, Object newRepresentative) {
127 notifyToObservers(node, oldRepresentative, Direction.DELETE);
128 notifyToObservers(node, newRepresentative, Direction.INSERT);
129 }
130
131 protected void notifyToObservers(Object node, Object representative, Direction direction) {
132 if (observer != null) {
133 observer.tupleChanged(node, representative, direction);
134 }
135 }
136
137 public interface Factory {
138 RepresentativeElectionAlgorithm create(Graph<Object> graph);
139 }
140}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/representative/RepresentativeObserver.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/representative/RepresentativeObserver.java
new file mode 100644
index 00000000..93cce1ea
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/representative/RepresentativeObserver.java
@@ -0,0 +1,12 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.viatra.runtime.base.itc.alg.representative;
7
8import tools.refinery.viatra.runtime.matchers.util.Direction;
9
10public interface RepresentativeObserver {
11 void tupleChanged(Object node, Object representative, Direction direction);
12}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/representative/StronglyConnectedComponentAlgorithm.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/representative/StronglyConnectedComponentAlgorithm.java
new file mode 100644
index 00000000..ba42bb13
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/representative/StronglyConnectedComponentAlgorithm.java
@@ -0,0 +1,66 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.viatra.runtime.base.itc.alg.representative;
7
8import tools.refinery.viatra.runtime.base.itc.alg.misc.GraphHelper;
9import tools.refinery.viatra.runtime.base.itc.alg.misc.bfs.BFS;
10import tools.refinery.viatra.runtime.base.itc.alg.misc.scc.SCC;
11import tools.refinery.viatra.runtime.base.itc.graphimpl.Graph;
12
13import java.util.Collection;
14import java.util.Set;
15
16public class StronglyConnectedComponentAlgorithm extends RepresentativeElectionAlgorithm {
17 public StronglyConnectedComponentAlgorithm(Graph<Object> graph) {
18 super(graph);
19 }
20
21 @Override
22 protected void initializeComponents() {
23 var computedSCCs = SCC.computeSCC(graph).getSccs();
24 for (var computedSCC : computedSCCs) {
25 initializeSet(computedSCC);
26 }
27 }
28
29 @Override
30 public void edgeInserted(Object source, Object target) {
31 var sourceRoot = getRepresentative(source);
32 var targetRoot = getRepresentative(target);
33 if (sourceRoot.equals(targetRoot)) {
34 // New edge does not change strongly connected components.
35 return;
36 }
37 if (BFS.isReachable(target, source, graph)) {
38 merge(sourceRoot, targetRoot);
39 }
40 }
41
42 @Override
43 public void edgeDeleted(Object source, Object target) {
44 var sourceRoot = getRepresentative(source);
45 var targetRoot = getRepresentative(target);
46 if (!sourceRoot.equals(targetRoot)) {
47 // New edge does not change strongly connected components.
48 return;
49 }
50 var component = GraphHelper.getSubGraph(getComponent(sourceRoot), graph);
51 if (!BFS.isReachable(source, target, component)) {
52 var newSCCs = SCC.computeSCC(component).getSccs();
53 split(sourceRoot, newSCCs);
54 }
55 }
56
57 private void split(Object preservedRepresentative, Collection<? extends Set<Object>> sets) {
58 for (var set : sets) {
59 if (set.contains(preservedRepresentative)) {
60 components.put(preservedRepresentative, set);
61 } else {
62 assignNewRepresentative(preservedRepresentative, set);
63 }
64 }
65 }
66}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/representative/WeaklyConnectedComponentAlgorithm.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/representative/WeaklyConnectedComponentAlgorithm.java
new file mode 100644
index 00000000..22159499
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/representative/WeaklyConnectedComponentAlgorithm.java
@@ -0,0 +1,85 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.viatra.runtime.base.itc.alg.representative;
7
8import tools.refinery.viatra.runtime.base.itc.graphimpl.Graph;
9
10import java.util.ArrayDeque;
11import java.util.HashSet;
12import java.util.Set;
13
14public class WeaklyConnectedComponentAlgorithm extends RepresentativeElectionAlgorithm {
15 public WeaklyConnectedComponentAlgorithm(Graph<Object> graph) {
16 super(graph);
17 }
18
19 @Override
20 protected void initializeComponents() {
21 for (var node : graph.getAllNodes()) {
22 if (representatives.containsKey(node)) {
23 continue;
24 }
25 var reachable = getReachableNodes(node);
26 initializeSet(reachable);
27 }
28 }
29
30 @Override
31 public void edgeInserted(Object source, Object target) {
32 var sourceRoot = getRepresentative(source);
33 var targetRoot = getRepresentative(target);
34 merge(sourceRoot, targetRoot);
35 }
36
37 @Override
38 public void edgeDeleted(Object source, Object target) {
39 var sourceRoot = getRepresentative(source);
40 var targetRoot = getRepresentative(target);
41 if (!sourceRoot.equals(targetRoot)) {
42 throw new IllegalArgumentException("Trying to remove edge not in graph");
43 }
44 var targetReachable = getReachableNodes(target);
45 if (!targetReachable.contains(source)) {
46 split(sourceRoot, targetReachable);
47 }
48 }
49
50 private void split(Object sourceRepresentative, Set<Object> targetReachable) {
51 var sourceComponent = getComponent(sourceRepresentative);
52 sourceComponent.removeAll(targetReachable);
53 if (targetReachable.contains(sourceRepresentative)) {
54 components.put(sourceRepresentative, targetReachable);
55 assignNewRepresentative(sourceRepresentative, sourceComponent);
56 } else {
57 assignNewRepresentative(sourceRepresentative, targetReachable);
58 }
59 }
60
61 private Set<Object> getReachableNodes(Object source) {
62 var retSet = new HashSet<>();
63 retSet.add(source);
64 var nodeQueue = new ArrayDeque<>();
65 nodeQueue.addLast(source);
66
67 while (!nodeQueue.isEmpty()) {
68 var node = nodeQueue.removeFirst();
69 for (var neighbor : graph.getTargetNodes(node).distinctValues()) {
70 if (!retSet.contains(neighbor)) {
71 retSet.add(neighbor);
72 nodeQueue.addLast(neighbor);
73 }
74 }
75 for (var neighbor : graph.getSourceNodes(node).distinctValues()) {
76 if (!retSet.contains(neighbor)) {
77 retSet.add(neighbor);
78 nodeQueue.addLast(neighbor);
79 }
80 }
81 }
82
83 return retSet;
84 }
85}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/util/CollectionHelper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/util/CollectionHelper.java
new file mode 100644
index 00000000..c9b3cafa
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/alg/util/CollectionHelper.java
@@ -0,0 +1,64 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.base.itc.alg.util;
10
11import java.util.Set;
12
13import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
14
15/**
16 * @author Tamas Szabo
17 *
18 */
19public class CollectionHelper {
20
21 private CollectionHelper() {/*Utility class constructor*/}
22
23 /**
24 * Returns the intersection of two sets. It calls {@link Set#retainAll(java.util.Collection)} but returns a new set
25 * containing the elements of the intersection.
26 *
27 * @param set1
28 * the first set (can be null, interpreted as empty)
29 * @param set2
30 * the second set (can be null, interpreted as empty)
31 * @return the intersection of the sets
32 * @since 1.7
33 */
34 public static <V> Set<V> intersection(Set<V> set1, Set<V> set2) {
35 if (set1 == null || set2 == null)
36 return CollectionsFactory.createSet();
37
38 Set<V> intersection = CollectionsFactory.createSet(set1);
39 intersection.retainAll(set2);
40 return intersection;
41 }
42
43
44 /**
45 * Returns the difference of two sets (S1\S2). It calls {@link Set#removeAll(java.util.Collection)} but returns a
46 * new set containing the elements of the difference.
47 *
48 * @param set1
49 * the first set (can be null, interpreted as empty)
50 * @param set2
51 * the second set (can be null, interpreted as empty)
52 * @return the difference of the sets
53 * @since 1.7
54 */
55 public static <V> Set<V> difference(Set<V> set1, Set<V> set2) {
56 if (set1 == null)
57 return CollectionsFactory.createSet();
58
59 Set<V> difference = CollectionsFactory.createSet(set1);
60 if (set2 != null) difference.removeAll(set2);
61 return difference;
62 }
63
64}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/graphimpl/DotGenerator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/graphimpl/DotGenerator.java
new file mode 100644
index 00000000..0e21f323
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/graphimpl/DotGenerator.java
@@ -0,0 +1,160 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.base.itc.graphimpl;
10
11import tools.refinery.viatra.runtime.base.itc.alg.misc.scc.SCC;
12import tools.refinery.viatra.runtime.base.itc.alg.misc.scc.SCCResult;
13import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
14
15import java.util.HashMap;
16import java.util.Map;
17import java.util.Set;
18import java.util.function.Function;
19
20/**
21 * This class contains utility methods to generate dot representations for {@link Graph} instances.
22 *
23 * @author Tamas Szabo
24 * @since 2.3
25 */
26public class DotGenerator {
27
28 private static final String[] colors = new String[] { "yellow", "blue", "red", "green", "gray", "cyan" };
29
30 private DotGenerator() {
31
32 }
33
34 /**
35 * Generates the dot representation for the given graph.
36 *
37 * @param graph
38 * the graph
39 * @param colorSCCs
40 * specifies if the strongly connected components with size greater than shall be colored
41 * @param nameFunction
42 * use this function to provide custom names to nodes, null if the default toString shall be used
43 * @param colorFunction
44 * use this function to provide custom color to nodes, null if the default white color shall be used
45 * @param edgeFunction
46 * use this function to provide custom edge labels, null if no edge label shall be printed
47 * @return the dot representation as a string
48 */
49 public static <V> String generateDot(final Graph<V> graph, final boolean colorSCCs,
50 final Function<V, String> nameFunction, final Function<V, String> colorFunction,
51 final Function<V, Function<V, String>> edgeFunction) {
52 final Map<V, String> colorMap = new HashMap<V, String>();
53
54 if (colorSCCs) {
55 final SCCResult<V> result = SCC.computeSCC(graph);
56 final Set<Set<V>> sccs = result.getSccs();
57
58 int i = 0;
59 for (final Set<V> scc : sccs) {
60 if (scc.size() > 1) {
61 for (final V node : scc) {
62 final String color = colorMap.get(node);
63 if (color == null) {
64 colorMap.put(node, colors[i % colors.length]);
65 } else {
66 colorMap.put(node, colorMap.get(node) + ":" + colors[i % colors.length]);
67 }
68 }
69 i++;
70 }
71 }
72
73 // if a node has no color yet, then make it white
74 for (final V node : graph.getAllNodes()) {
75 if (!colorMap.containsKey(node)) {
76 colorMap.put(node, "white");
77 }
78 }
79 } else {
80 for (final V node : graph.getAllNodes()) {
81 colorMap.put(node, "white");
82 }
83 }
84
85 if (colorFunction != null) {
86 for (final V node : graph.getAllNodes()) {
87 colorMap.put(node, colorFunction.apply(node));
88 }
89 }
90
91 final StringBuilder builder = new StringBuilder();
92 builder.append("digraph g {\n");
93
94 for (final V node : graph.getAllNodes()) {
95 final String nodePresentation = nameFunction == null ? node.toString() : nameFunction.apply(node);
96 builder.append("\"" + nodePresentation + "\"");
97 builder.append("[style=filled,fillcolor=" + colorMap.get(node) + "]");
98 builder.append(";\n");
99 }
100
101 for (final V source : graph.getAllNodes()) {
102 final IMemoryView<V> targets = graph.getTargetNodes(source);
103 if (!targets.isEmpty()) {
104 final String sourcePresentation = nameFunction == null ? source.toString() : nameFunction.apply(source);
105 for (final V target : targets.distinctValues()) {
106 String edgeLabel = null;
107 if (edgeFunction != null) {
108 final Function<V, String> v1 = edgeFunction.apply(source);
109 if (v1 != null) {
110 edgeLabel = v1.apply(target);
111 }
112 }
113
114 final String targetPresentation = nameFunction == null ? target.toString()
115 : nameFunction.apply(target);
116
117 builder.append("\"" + sourcePresentation + "\" -> \"" + targetPresentation + "\"");
118 if (edgeLabel != null) {
119 builder.append("[label=\"" + edgeLabel + "\"]");
120 }
121 builder.append(";\n");
122 }
123 }
124 }
125
126 builder.append("}");
127 return builder.toString();
128 }
129
130 /**
131 * Generates the dot representation for the given graph. No special pretty printing customization will be applied.
132 *
133 * @param graph
134 * the graph
135 * @return the dot representation as a string
136 */
137 public static <V> String generateDot(final Graph<V> graph) {
138 return generateDot(graph, false, null, null, null);
139 }
140
141 /**
142 * Returns a simple name shortener function that can be used in the graphviz visualization to help with readability.
143 * WARNING: if you shorten the name of the {@link Node}s too much, the visualization may become incorrect because
144 * grahpviz will treat different nodes as the same if their shortened names are the same.
145 *
146 * @param maxLength
147 * the maximum length of the text that is kept from the toString of the objects in the graph
148 * @return the shrunk toString value
149 */
150 public static <V> Function<V, String> getNameShortener(final int maxLength) {
151 return new Function<V, String>() {
152 @Override
153 public String apply(final V obj) {
154 final String value = obj.toString();
155 return value.substring(0, Math.min(value.length(), maxLength));
156 }
157 };
158 }
159
160}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/graphimpl/Graph.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/graphimpl/Graph.java
new file mode 100644
index 00000000..4267579c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/graphimpl/Graph.java
@@ -0,0 +1,185 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.graphimpl;
11
12import tools.refinery.viatra.runtime.base.itc.igraph.IGraphDataSource;
13import tools.refinery.viatra.runtime.base.itc.igraph.IGraphObserver;
14import tools.refinery.viatra.runtime.base.itc.igraph.IBiDirectionalGraphDataSource;
15import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
16import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
17import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
18import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
19
20import java.util.List;
21import java.util.Map;
22import java.util.Map.Entry;
23import java.util.Set;
24
25public class Graph<V> implements IGraphDataSource<V>, IBiDirectionalGraphDataSource<V> {
26
27 // source -> target -> count
28 private IMultiLookup<V, V> outgoingEdges;
29 // target -> source -> count
30 private IMultiLookup<V, V> incomingEdges;
31
32 private Set<V> nodes;
33
34 private List<IGraphObserver<V>> observers;
35
36 public Graph() {
37 outgoingEdges = CollectionsFactory.createMultiLookup(Object.class, MemoryType.MULTISETS, Object.class);
38 incomingEdges = CollectionsFactory.createMultiLookup(Object.class, MemoryType.MULTISETS, Object.class);
39 nodes = CollectionsFactory.createSet();
40 observers = CollectionsFactory.createObserverList();
41 }
42
43 public void insertEdge(V source, V target) {
44 outgoingEdges.addPair(source, target);
45 incomingEdges.addPair(target, source);
46
47 for (IGraphObserver<V> go : observers) {
48 go.edgeInserted(source, target);
49 }
50 }
51
52 /**
53 * No-op if trying to delete edge that does not exist
54 *
55 * @since 2.0
56 * @see #deleteEdgeIfExists(Object, Object)
57 */
58 public void deleteEdgeIfExists(V source, V target) {
59 boolean containedEdge = outgoingEdges.lookupOrEmpty(source).containsNonZero(target);
60 if (containedEdge) {
61 deleteEdgeThatExists(source, target);
62 }
63 }
64
65 /**
66 * @throws IllegalStateException
67 * if trying to delete edge that does not exist
68 * @since 2.0
69 * @see #deleteEdgeIfExists(Object, Object)
70 */
71 public void deleteEdgeThatExists(V source, V target) {
72 outgoingEdges.removePair(source, target);
73 incomingEdges.removePair(target, source);
74 for (IGraphObserver<V> go : observers) {
75 go.edgeDeleted(source, target);
76 }
77 }
78
79 /**
80 * @deprecated use explicitly {@link #deleteEdgeThatExists(Object, Object)} or
81 * {@link #deleteEdgeIfExists(Object, Object)} instead. To preserve backwards compatibility, this method
82 * delegates to the latter.
83 *
84 */
85 @Deprecated
86 public void deleteEdge(V source, V target) {
87 deleteEdgeIfExists(source, target);
88 }
89
90 /**
91 * Insert the given node into the graph.
92 */
93 public void insertNode(V node) {
94 if (nodes.add(node)) {
95 for (IGraphObserver<V> go : observers) {
96 go.nodeInserted(node);
97 }
98 }
99 }
100
101 /**
102 * Deletes the given node AND all of the edges going in and out from the node.
103 */
104 public void deleteNode(V node) {
105 if (nodes.remove(node)) {
106 IMemoryView<V> incomingView = incomingEdges.lookup(node);
107 if (incomingView != null) {
108 Map<V, Integer> incoming = CollectionsFactory.createMap(incomingView.asMap());
109
110 for (Entry<V, Integer> entry : incoming.entrySet()) {
111 for (int i = 0; i < entry.getValue(); i++) {
112 deleteEdgeThatExists(entry.getKey(), node);
113 }
114 }
115 }
116
117 IMemoryView<V> outgoingView = outgoingEdges.lookup(node);
118 if (outgoingView != null) {
119 Map<V, Integer> outgoing = CollectionsFactory.createMap(outgoingView.asMap());
120
121 for (Entry<V, Integer> entry : outgoing.entrySet()) {
122 for (int i = 0; i < entry.getValue(); i++) {
123 deleteEdgeThatExists(node, entry.getKey());
124 }
125 }
126 }
127
128 for (IGraphObserver<V> go : observers) {
129 go.nodeDeleted(node);
130 }
131 }
132 }
133
134 @Override
135 public void attachObserver(IGraphObserver<V> go) {
136 observers.add(go);
137 }
138
139 @Override
140 public void attachAsFirstObserver(IGraphObserver<V> observer) {
141 observers.add(0, observer);
142 }
143
144 @Override
145 public void detachObserver(IGraphObserver<V> go) {
146 observers.remove(go);
147 }
148
149 @Override
150 public Set<V> getAllNodes() {
151 return nodes;
152 }
153
154 @Override
155 public IMemoryView<V> getTargetNodes(V source) {
156 return outgoingEdges.lookupOrEmpty(source);
157 }
158
159 @Override
160 public IMemoryView<V> getSourceNodes(V target) {
161 return incomingEdges.lookupOrEmpty(target);
162 }
163
164 @Override
165 public String toString() {
166 StringBuilder sb = new StringBuilder();
167 sb.append("nodes = ");
168 for (V n : getAllNodes()) {
169 sb.append(n.toString());
170 sb.append(" ");
171 }
172 sb.append(" edges = ");
173 for (V source : outgoingEdges.distinctKeys()) {
174 IMemoryView<V> targets = outgoingEdges.lookup(source);
175 for (V target : targets.distinctValues()) {
176 int count = targets.getCount(target);
177 for (int i = 0; i < count; i++) {
178 sb.append("(" + source + "," + target + ") ");
179 }
180 }
181 }
182 return sb.toString();
183 }
184
185}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/IBiDirectionalGraphDataSource.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/IBiDirectionalGraphDataSource.java
new file mode 100644
index 00000000..64659447
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/IBiDirectionalGraphDataSource.java
@@ -0,0 +1,37 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.igraph;
11
12import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
13import tools.refinery.viatra.runtime.matchers.util.IMultiset;
14
15/**
16 * A bi-directional graph data source supports all operations that an {@link IGraphDataSource} does, but it
17 * also makes it possible to query the incoming edges of nodes, not only the outgoing edges.
18 *
19 * @author Tamas Szabo
20 *
21 * @param <V> the type of the nodes in the graph
22 */
23public interface IBiDirectionalGraphDataSource<V> extends IGraphDataSource<V> {
24
25 /**
26 * Returns the source nodes for the given target node.
27 * The returned data structure is an {@link IMultiset} because of potential parallel edges in the graph data source.
28 *
29 * The method must not return null.
30 *
31 * @param target the target node
32 * @return the multiset of source nodes
33 * @since 2.0
34 */
35 public IMemoryView<V> getSourceNodes(V target);
36
37}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/IBiDirectionalWrapper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/IBiDirectionalWrapper.java
new file mode 100644
index 00000000..becab0eb
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/IBiDirectionalWrapper.java
@@ -0,0 +1,110 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.igraph;
11
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
15import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
16import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
17import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
18
19/**
20 * This class can be used to wrap an {@link IGraphDataSource} into an {@link IBiDirectionalGraphDataSource}. This class
21 * provides support for the retrieval of source nodes for a given target which is not supported by standard
22 * {@link IGraphDataSource} implementations.
23 *
24 * @author Tamas Szabo
25 *
26 * @param <V>
27 * the type parameter of the nodes in the graph data source
28 */
29public class IBiDirectionalWrapper<V> implements IBiDirectionalGraphDataSource<V>, IGraphObserver<V> {
30
31 private IGraphDataSource<V> wrappedDataSource;
32 // target -> source -> count
33 private IMultiLookup<V, V> incomingEdges;
34
35 public IBiDirectionalWrapper(IGraphDataSource<V> gds) {
36 this.wrappedDataSource = gds;
37
38 this.incomingEdges = CollectionsFactory.createMultiLookup(
39 Object.class, MemoryType.MULTISETS, Object.class);
40
41 if (gds.getAllNodes() != null) {
42 for (V source : gds.getAllNodes()) {
43 IMemoryView<V> targets = gds.getTargetNodes(source);
44 for (V target : targets.distinctValues()) {
45 int count = targets.getCount(target);
46 for (int i = 0; i < count; i++) {
47 edgeInserted(source, target);
48 }
49 }
50 }
51 }
52
53 gds.attachAsFirstObserver(this);
54 }
55
56 @Override
57 public void attachObserver(IGraphObserver<V> observer) {
58 wrappedDataSource.attachObserver(observer);
59 }
60
61 @Override
62 public void attachAsFirstObserver(IGraphObserver<V> observer) {
63 wrappedDataSource.attachAsFirstObserver(observer);
64 }
65
66 @Override
67 public void detachObserver(IGraphObserver<V> observer) {
68 wrappedDataSource.detachObserver(observer);
69 }
70
71 @Override
72 public Set<V> getAllNodes() {
73 return wrappedDataSource.getAllNodes();
74 }
75
76 @Override
77 public IMemoryView<V> getTargetNodes(V source) {
78 return wrappedDataSource.getTargetNodes(source);
79 }
80
81 @Override
82 public IMemoryView<V> getSourceNodes(V target) {
83 return incomingEdges.lookupOrEmpty(target);
84 }
85
86 @Override
87 public void edgeInserted(V source, V target) {
88 incomingEdges.addPair(target, source);
89 }
90
91 @Override
92 public void edgeDeleted(V source, V target) {
93 incomingEdges.removePair(target, source);
94 }
95
96 @Override
97 public void nodeInserted(V n) {
98
99 }
100
101 @Override
102 public void nodeDeleted(V node) {
103
104 }
105
106 @Override
107 public String toString() {
108 return wrappedDataSource.toString();
109 }
110}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/IGraphDataSource.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/IGraphDataSource.java
new file mode 100644
index 00000000..3fa65936
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/IGraphDataSource.java
@@ -0,0 +1,70 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.igraph;
11
12import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
13import tools.refinery.viatra.runtime.matchers.util.IMultiset;
14
15import java.util.Set;
16
17/**
18 * The interface prescribes the set of operations that a graph data source must support.
19 * <p> Note that the old version of the interface is broken at version 1.6;
20 * MultiSets are now presented as Maps instead of Lists.
21 *
22 * @author Tamas Szabo
23 *
24 * @param <V>
25 * the type of the nodes in the graph
26 */
27public interface IGraphDataSource<V> {
28
29 /**
30 * Attaches a new graph observer to this graph data source. Observers will be notified in the order they have been registered.
31 *
32 * @param observer the graph observer
33 */
34 public void attachObserver(IGraphObserver<V> observer);
35
36 /**
37 * Attaches a new graph observer to this graph data source as the first one.
38 * In the notification order this observer will be the first one as long as another call to this method happens.
39 *
40 * @param observer the graph observer
41 * @since 1.6
42 */
43 public void attachAsFirstObserver(IGraphObserver<V> observer);
44
45 /**
46 * Detaches an already registered graph observer from this graph data source.
47 *
48 * @param observer the graph observer
49 */
50 public void detachObserver(IGraphObserver<V> observer);
51
52 /**
53 * Returns the complete set of nodes in the graph data source.
54 *
55 * @return the set of all nodes
56 */
57 public Set<V> getAllNodes();
58
59 /**
60 * Returns the target nodes for the given source node.
61 * The returned data structure is an {@link IMultiset} because of potential parallel edges in the graph data source.
62 *
63 * The method must not return null.
64 *
65 * @param source the source node
66 * @return the multiset of target nodes
67 * @since 2.0
68 */
69 public IMemoryView<V> getTargetNodes(V source);
70}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/IGraphObserver.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/IGraphObserver.java
new file mode 100644
index 00000000..5cb2d9fa
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/IGraphObserver.java
@@ -0,0 +1,55 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.igraph;
11
12/**
13 * Interface GraphObserver is used to observ the changes in a graph; edge and node insertion/deleteion.
14 *
15 * @author Tamas Szabo
16 *
17 */
18public interface IGraphObserver<V> {
19
20 /**
21 * Used to notify when an edge is inserted into the graph.
22 *
23 * @param source
24 * the source of the edge
25 * @param target
26 * the target of the edge
27 */
28 public void edgeInserted(V source, V target);
29
30 /**
31 * Used to notify when an edge is deleted from the graph.
32 *
33 * @param source
34 * the source of the edge
35 * @param target
36 * the target of the edge
37 */
38 public void edgeDeleted(V source, V target);
39
40 /**
41 * Used to notify when a node is inserted into the graph.
42 *
43 * @param n
44 * the node
45 */
46 public void nodeInserted(V n);
47
48 /**
49 * Used to notify when a node is deleted from the graph.
50 *
51 * @param n
52 * the node
53 */
54 public void nodeDeleted(V n);
55}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/ITcDataSource.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/ITcDataSource.java
new file mode 100644
index 00000000..5924b723
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/ITcDataSource.java
@@ -0,0 +1,82 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.igraph;
11
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.base.itc.alg.misc.IGraphPathFinder;
15
16/**
17 * This interface defines those methods that a transitive reachability data source should provide.
18 *
19 * @author Tamas Szabo
20 *
21 * @param <V>
22 * the type parameter of the node
23 */
24public interface ITcDataSource<V> {
25
26 /**
27 * Attach a transitive closure relation observer.
28 *
29 * @param to
30 * the observer object
31 */
32 public void attachObserver(ITcObserver<V> to);
33
34 /**
35 * Detach a transitive closure relation observer.
36 *
37 * @param to
38 * the observer object
39 */
40 public void detachObserver(ITcObserver<V> to);
41
42 /**
43 * Returns all nodes which are reachable from the source node.
44 *
45 * @param source
46 * the source node
47 * @return the set of target nodes
48 */
49 public Set<V> getAllReachableTargets(V source);
50
51 /**
52 * Returns all nodes from which the target node is reachable.
53 *
54 * @param target
55 * the target node
56 * @return the set of source nodes
57 */
58 public Set<V> getAllReachableSources(V target);
59
60 /**
61 * Returns true if the target node is reachable from the source node.
62 *
63 * @param source
64 * the source node
65 * @param target
66 * the target node
67 * @return true if target is reachable from source, false otherwise
68 */
69 public boolean isReachable(V source, V target);
70
71 /**
72 * The returned {@link IGraphPathFinder} can be used to retrieve paths between nodes using transitive reachability.
73 *
74 * @return a path finder for the graph.
75 */
76 public IGraphPathFinder<V> getPathFinder();
77
78 /**
79 * Call this method to properly dispose the data structures of a transitive closure algorithm.
80 */
81 public void dispose();
82}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/ITcObserver.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/ITcObserver.java
new file mode 100644
index 00000000..fded53f1
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/base/itc/igraph/ITcObserver.java
@@ -0,0 +1,39 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.base.itc.igraph;
11
12/**
13 * Interface ITcObserver is used to observe the changes in a transitive closure relation; tuple insertion/deletion.
14 *
15 * @author Szabo Tamas
16 *
17 */
18public interface ITcObserver<V> {
19
20 /**
21 * Used to notify when a tuple is inserted into the transitive closure relation.
22 *
23 * @param source
24 * the source of the tuple
25 * @param target
26 * the target of the tuple
27 */
28 public void tupleInserted(V source, V target);
29
30 /**
31 * Used to notify when a tuple is deleted from the transitive closure relation.
32 *
33 * @param source
34 * the source of the tuple
35 * @param target
36 * the target of the tuple
37 */
38 public void tupleDeleted(V source, V target);
39}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/ViatraQueryRuntimeException.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/ViatraQueryRuntimeException.java
new file mode 100644
index 00000000..83f6f766
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/ViatraQueryRuntimeException.java
@@ -0,0 +1,42 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers;
10
11/**
12 * A common base class for all exceptions thrown by various VIATRA Query Runtime APIs.
13 *
14 * @author Zoltan Ujhelyi
15 * @since 2.0
16 */
17public abstract class ViatraQueryRuntimeException extends RuntimeException {
18
19 private static final long serialVersionUID = -8505253058035069310L;
20
21 public ViatraQueryRuntimeException() {
22 super();
23 }
24
25 public ViatraQueryRuntimeException(String message) {
26 super(message);
27 }
28
29 public ViatraQueryRuntimeException(Throwable cause) {
30 super(cause);
31 }
32
33 public ViatraQueryRuntimeException(String message, Throwable cause) {
34 super(message, cause);
35 }
36
37 public ViatraQueryRuntimeException(String message, Throwable cause, boolean enableSuppression,
38 boolean writableStackTrace) {
39 super(message, cause, enableSuppression, writableStackTrace);
40 }
41
42}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/AverageAccumulator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/AverageAccumulator.java
new file mode 100644
index 00000000..2c09ede1
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/AverageAccumulator.java
@@ -0,0 +1,24 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11/**
12 * @since 2.0
13 */
14class AverageAccumulator<Domain> {
15 Domain value;
16 long count;
17
18 public AverageAccumulator(Domain value, long count) {
19 super();
20 this.value = value;
21 this.count = count;
22 }
23
24} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleAverageOperator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleAverageOperator.java
new file mode 100644
index 00000000..e8a26afd
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleAverageOperator.java
@@ -0,0 +1,82 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import java.util.OptionalDouble;
12import java.util.stream.Stream;
13
14import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator;
15
16/**
17 * @author Zoltan Ujhelyi
18 * @since 2.0
19 */
20public class DoubleAverageOperator implements IMultisetAggregationOperator<Double, AverageAccumulator<Double>, Double> {
21
22 public static final DoubleAverageOperator INSTANCE = new DoubleAverageOperator();
23
24 private DoubleAverageOperator() {
25 // Singleton, do not call.
26 }
27
28 @Override
29 public String getShortDescription() {
30 return "avg<Integer> incrementally computes the average of java.lang.Integer values";
31 }
32
33 @Override
34 public String getName() {
35 return "avg<Integer>";
36 }
37
38 @Override
39 public AverageAccumulator<Double> createNeutral() {
40 return new AverageAccumulator<Double>(0d, 0l);
41 }
42
43 @Override
44 public boolean isNeutral(AverageAccumulator<Double> result) {
45 return result.count == 0l;
46 }
47
48 @Override
49 public AverageAccumulator<Double> update(AverageAccumulator<Double> oldResult, Double updateValue,
50 boolean isInsertion) {
51 if (isInsertion) {
52 oldResult.value += updateValue;
53 oldResult.count++;
54 } else {
55 oldResult.value -= updateValue;
56 oldResult.count--;
57 }
58 return oldResult;
59 }
60
61 @Override
62 public Double getAggregate(AverageAccumulator<Double> result) {
63 return (result.count == 0)
64 ? null
65 : result.value/result.count;
66 }
67
68 @Override
69 public Double aggregateStream(Stream<Double> stream) {
70 final OptionalDouble averageOpt = stream.mapToDouble(Double::doubleValue).average();
71 return averageOpt.isPresent() ? averageOpt.getAsDouble() : null;
72 }
73
74 /**
75 * @since 2.4
76 */
77 @Override
78 public AverageAccumulator<Double> clone(AverageAccumulator<Double> original) {
79 return new AverageAccumulator<Double>(original.value, original.count);
80 }
81
82} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleSumOperator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleSumOperator.java
new file mode 100644
index 00000000..744b0cd1
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleSumOperator.java
@@ -0,0 +1,62 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import java.util.stream.Stream;
12
13import tools.refinery.viatra.runtime.matchers.psystem.aggregations.AbstractMemorylessAggregationOperator;
14
15/**
16 * Incrementally computes the sum of java.lang.Double values
17 * @author Gabor Bergmann
18 * @since 1.4
19 */
20public class DoubleSumOperator extends AbstractMemorylessAggregationOperator<Double, Double> {
21 public static final DoubleSumOperator INSTANCE = new DoubleSumOperator();
22
23 private DoubleSumOperator() {
24 // Singleton, do not call.
25 }
26
27 @Override
28 public String getShortDescription() {
29 return "sum<Double> incrementally computes the sum of java.lang.Double values";
30 }
31 @Override
32 public String getName() {
33 return "sum<Double>";
34 }
35
36 @Override
37 public Double createNeutral() {
38 return 0d;
39 }
40
41 @Override
42 public boolean isNeutral(Double result) {
43 return createNeutral().equals(result);
44 }
45
46 @Override
47 public Double update(Double oldResult, Double updateValue, boolean isInsertion) {
48 return isInsertion ?
49 oldResult + updateValue :
50 oldResult - updateValue;
51 }
52
53 /**
54 * @since 2.0
55 */
56 @Override
57 public Double aggregateStream(Stream<Double> stream) {
58 return stream.mapToDouble(Double::doubleValue).sum();
59 }
60
61
62}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/ExtremumOperator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/ExtremumOperator.java
new file mode 100644
index 00000000..ee4ceeb8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/ExtremumOperator.java
@@ -0,0 +1,135 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import java.util.Comparator;
12import java.util.SortedMap;
13import java.util.TreeMap;
14import java.util.stream.Stream;
15
16import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator;
17
18/**
19 * Incrementally computes the minimum or maximum of java.lang.Comparable values, using the default comparison
20 *
21 * @author Gabor Bergmann
22 * @since 1.4
23 */
24public class ExtremumOperator<T extends Comparable<T>>
25 implements IMultisetAggregationOperator<T, SortedMap<T, Integer>, T> {
26
27 public enum Extreme {
28 MIN, MAX;
29
30 /**
31 * @since 2.0
32 */
33 public <T> T pickFrom(SortedMap<T, Integer> nonEmptyMultiSet) {
34 switch(this) {
35 case MIN:
36 return nonEmptyMultiSet.firstKey();
37 case MAX:
38 return nonEmptyMultiSet.lastKey();
39 default:
40 return null;
41 }
42 }
43 }
44
45 private static final ExtremumOperator MIN_OP = new ExtremumOperator<>(Extreme.MIN);
46 private static final ExtremumOperator MAX_OP = new ExtremumOperator<>(Extreme.MAX);
47
48 public static <T extends Comparable<T>> ExtremumOperator<T> getMin() {
49 return MIN_OP;
50 }
51 public static <T extends Comparable<T>> ExtremumOperator<T> getMax() {
52 return MAX_OP;
53 }
54
55 Extreme extreme;
56 private ExtremumOperator(Extreme extreme) {
57 super();
58 this.extreme = extreme;
59 }
60
61 @Override
62 public String getShortDescription() {
63 String opName = getName();
64 return String.format(
65 "%s incrementally computes the %simum of java.lang.Comparable values, using the default comparison",
66 opName, opName);
67 }
68
69 @Override
70 public String getName() {
71 return extreme.name().toLowerCase();
72 }
73
74 /**
75 * @since 2.0
76 */
77 @Override
78 public SortedMap<T, Integer> createNeutral() {
79 return new TreeMap<>();
80 }
81
82 /**
83 * @since 2.0
84 */
85 @Override
86 public boolean isNeutral(SortedMap<T, Integer> result) {
87 return result.isEmpty();
88 }
89
90 /**
91 * @since 2.0
92 */
93 @Override
94 public SortedMap<T, Integer> update(SortedMap<T, Integer> oldResult, T updateValue, boolean isInsertion) {
95 oldResult.compute(updateValue, (value, c) -> {
96 int count = (c == null) ? 0 : c;
97 int result = (isInsertion) ? count+1 : count-1;
98 return (result == 0) ? null : result;
99 });
100 return oldResult;
101 }
102
103 /**
104 * @since 2.0
105 */
106 @Override
107 public T getAggregate(SortedMap<T, Integer> result) {
108 return result.isEmpty() ? null :
109 extreme.pickFrom(result);
110 }
111
112 /**
113 * @since 2.0
114 */
115 @Override
116 public T aggregateStream(Stream<T> stream) {
117 switch (extreme) {
118 case MIN:
119 return stream.min(Comparator.naturalOrder()).orElse(null);
120 case MAX:
121 return stream.max(Comparator.naturalOrder()).orElse(null);
122 default:
123 return null;
124 }
125 }
126
127 /**
128 * @since 2.4
129 */
130 @Override
131 public SortedMap<T, Integer> clone(SortedMap<T, Integer> original) {
132 return new TreeMap<T, Integer>(original);
133 }
134
135}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerAverageOperator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerAverageOperator.java
new file mode 100644
index 00000000..bf422476
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerAverageOperator.java
@@ -0,0 +1,82 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import java.util.OptionalDouble;
12import java.util.stream.Stream;
13
14import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator;
15
16/**
17 * @author Zoltan Ujhelyi
18 * @since 2.0
19 */
20public class IntegerAverageOperator implements IMultisetAggregationOperator<Integer, AverageAccumulator<Integer>, Double> {
21
22 public static final IntegerAverageOperator INSTANCE = new IntegerAverageOperator();
23
24 private IntegerAverageOperator() {
25 // Singleton, do not call.
26 }
27
28 @Override
29 public String getShortDescription() {
30 return "avg<Integer> incrementally computes the average of java.lang.Integer values";
31 }
32
33 @Override
34 public String getName() {
35 return "avg<Integer>";
36 }
37
38 @Override
39 public AverageAccumulator<Integer> createNeutral() {
40 return new AverageAccumulator<Integer>(0, 0l);
41 }
42
43 @Override
44 public boolean isNeutral(AverageAccumulator<Integer> result) {
45 return result.count == 0l;
46 }
47
48 @Override
49 public AverageAccumulator<Integer> update(AverageAccumulator<Integer> oldResult, Integer updateValue,
50 boolean isInsertion) {
51 if (isInsertion) {
52 oldResult.value += updateValue;
53 oldResult.count++;
54 } else {
55 oldResult.value -= updateValue;
56 oldResult.count--;
57 }
58 return oldResult;
59 }
60
61 @Override
62 public Double getAggregate(AverageAccumulator<Integer> result) {
63 return (result.count == 0)
64 ? null
65 : ((double)result.value)/result.count;
66 }
67
68 @Override
69 public Double aggregateStream(Stream<Integer> stream) {
70 final OptionalDouble averageOpt = stream.mapToInt(Integer::intValue).average();
71 return averageOpt.isPresent() ? averageOpt.getAsDouble() : null;
72 }
73
74 /**
75 * @since 2.4
76 */
77 @Override
78 public AverageAccumulator<Integer> clone(AverageAccumulator<Integer> original) {
79 return new AverageAccumulator<Integer>(original.value, original.count);
80 }
81
82} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerSumOperator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerSumOperator.java
new file mode 100644
index 00000000..18584256
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerSumOperator.java
@@ -0,0 +1,61 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import java.util.stream.Stream;
12
13import tools.refinery.viatra.runtime.matchers.psystem.aggregations.AbstractMemorylessAggregationOperator;
14
15/**
16 * Incrementally computes the sum of java.lang.Integer values
17 * @author Gabor Bergmann
18 * @since 1.4
19 */
20public class IntegerSumOperator extends AbstractMemorylessAggregationOperator<Integer, Integer> {
21 public static final IntegerSumOperator INSTANCE = new IntegerSumOperator();
22
23 private IntegerSumOperator() {
24 // Singleton, do not call.
25 }
26
27 @Override
28 public String getShortDescription() {
29 return "sum<Integer> incrementally computes the sum of java.lang.Integer values";
30 }
31 @Override
32 public String getName() {
33 return "sum<Integer>";
34 }
35
36 @Override
37 public Integer createNeutral() {
38 return 0;
39 }
40
41 @Override
42 public boolean isNeutral(Integer result) {
43 return createNeutral().equals(result);
44 }
45
46 @Override
47 public Integer update(Integer oldResult, Integer updateValue, boolean isInsertion) {
48 return isInsertion ?
49 oldResult + updateValue :
50 oldResult - updateValue;
51 }
52
53 /**
54 * @since 2.0
55 */
56 @Override
57 public Integer aggregateStream(Stream<Integer> stream) {
58 return stream.mapToInt(Integer::intValue).sum();
59 }
60
61}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongAverageOperator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongAverageOperator.java
new file mode 100644
index 00000000..d56c9507
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongAverageOperator.java
@@ -0,0 +1,82 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import java.util.OptionalDouble;
12import java.util.stream.Stream;
13
14import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator;
15
16/**
17 * @author Zoltan Ujhelyi
18 * @since 2.0
19 */
20public class LongAverageOperator implements IMultisetAggregationOperator<Long, AverageAccumulator<Long>, Double> {
21
22 public static final LongAverageOperator INSTANCE = new LongAverageOperator();
23
24 private LongAverageOperator() {
25 // Singleton, do not call.
26 }
27
28 @Override
29 public String getShortDescription() {
30 return "avg<Integer> incrementally computes the average of java.lang.Integer values";
31 }
32
33 @Override
34 public String getName() {
35 return "avg<Integer>";
36 }
37
38 @Override
39 public AverageAccumulator<Long> createNeutral() {
40 return new AverageAccumulator<Long>(0l, 0l);
41 }
42
43 @Override
44 public boolean isNeutral(AverageAccumulator<Long> result) {
45 return result.count == 0l;
46 }
47
48 @Override
49 public AverageAccumulator<Long> update(AverageAccumulator<Long> oldResult, Long updateValue,
50 boolean isInsertion) {
51 if (isInsertion) {
52 oldResult.value += updateValue;
53 oldResult.count++;
54 } else {
55 oldResult.value -= updateValue;
56 oldResult.count--;
57 }
58 return oldResult;
59 }
60
61 @Override
62 public Double getAggregate(AverageAccumulator<Long> result) {
63 return (result.count == 0)
64 ? null
65 : ((double)result.value)/result.count;
66 }
67
68 @Override
69 public Double aggregateStream(Stream<Long> stream) {
70 final OptionalDouble averageOpt = stream.mapToLong(Long::longValue).average();
71 return averageOpt.isPresent() ? averageOpt.getAsDouble() : null;
72 }
73
74 /**
75 * @since 2.4
76 */
77 @Override
78 public AverageAccumulator<Long> clone(AverageAccumulator<Long> original) {
79 return new AverageAccumulator<Long>(original.value, original.count);
80 }
81
82} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongSumOperator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongSumOperator.java
new file mode 100644
index 00000000..29ded090
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongSumOperator.java
@@ -0,0 +1,61 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import java.util.stream.Stream;
12
13import tools.refinery.viatra.runtime.matchers.psystem.aggregations.AbstractMemorylessAggregationOperator;
14
15/**
16 * Incrementally computes the sum of java.lang.Long values
17 * @author Gabor Bergmann
18 * @since 1.4
19 */
20public class LongSumOperator extends AbstractMemorylessAggregationOperator<Long, Long> {
21 public static final LongSumOperator INSTANCE = new LongSumOperator();
22
23 private LongSumOperator() {
24 // Singleton, do not call.
25 }
26
27 @Override
28 public String getShortDescription() {
29 return "sum<Long> incrementally computes the sum of java.lang.Long values";
30 }
31 @Override
32 public String getName() {
33 return "sum<Long>";
34 }
35
36 @Override
37 public Long createNeutral() {
38 return 0L;
39 }
40
41 @Override
42 public boolean isNeutral(Long result) {
43 return createNeutral().equals(result);
44 }
45
46 @Override
47 public Long update(Long oldResult, Long updateValue, boolean isInsertion) {
48 return isInsertion ?
49 oldResult + updateValue :
50 oldResult - updateValue;
51 }
52
53 /**
54 * @since 2.0
55 */
56 @Override
57 public Long aggregateStream(Stream<Long> stream) {
58 return stream.mapToLong(Long::longValue).sum();
59 }
60
61}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/avg.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/avg.java
new file mode 100644
index 00000000..c25678aa
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/avg.java
@@ -0,0 +1,39 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import tools.refinery.viatra.runtime.matchers.psystem.aggregations.AggregatorType;
12import tools.refinery.viatra.runtime.matchers.psystem.aggregations.BoundAggregator;
13import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IAggregatorFactory;
14
15/**
16 * This aggregator calculates the average of the values of a selected aggregate parameter of a called pattern. The aggregate
17 * parameter is selected with the '#' symbol; the aggregate parameter must not be used outside the aggregator call. The
18 * other parameters of the call might be bound or unbound; bound parameters limit the matches to consider for the
19 * summation.
20 *
21 * @since 2.0
22 *
23 */
24@AggregatorType(
25 parameterTypes = {Integer.class, Double.class, Long.class},
26 returnTypes = {Double.class, Double.class, Double.class})
27public final class avg implements IAggregatorFactory {
28
29 @Override
30 public BoundAggregator getAggregatorLogic(Class<?> domainClass) {
31 if (Integer.class.equals(domainClass))
32 return new BoundAggregator(IntegerAverageOperator.INSTANCE, Integer.class, Double.class);
33 if (Double.class.equals(domainClass))
34 return new BoundAggregator(DoubleAverageOperator.INSTANCE, Double.class, Double.class);
35 if (Long.class.equals(domainClass))
36 return new BoundAggregator(LongAverageOperator.INSTANCE, Long.class, Double.class);
37 else throw new IllegalArgumentException();
38 }
39}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/count.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/count.java
new file mode 100644
index 00000000..8310a0ce
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/count.java
@@ -0,0 +1,33 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import tools.refinery.viatra.runtime.matchers.psystem.aggregations.AggregatorType;
12import tools.refinery.viatra.runtime.matchers.psystem.aggregations.BoundAggregator;
13import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IAggregatorFactory;
14
15/**
16 * An aggregator to count the number of matches a pattern has. The return of the aggregator is an non-negative integer
17 * number.
18 *
19 * @since 1.4
20 *
21 */
22@AggregatorType(parameterTypes = {Void.class}, returnTypes = {Integer.class})
23public final class count implements IAggregatorFactory {
24
25 @Override
26 public BoundAggregator getAggregatorLogic(Class<?> domainClass) {
27 if (Void.class.equals(domainClass))
28 return new BoundAggregator(null, Void.class, Integer.class);
29 else throw new IllegalArgumentException();
30 }
31
32
33}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/max.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/max.java
new file mode 100644
index 00000000..e0236223
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/max.java
@@ -0,0 +1,44 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import java.math.BigDecimal;
12import java.math.BigInteger;
13import java.util.Calendar;
14import java.util.Date;
15
16import tools.refinery.viatra.runtime.matchers.psystem.aggregations.AggregatorType;
17import tools.refinery.viatra.runtime.matchers.psystem.aggregations.BoundAggregator;
18import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IAggregatorFactory;
19
20/**
21 * This aggregator calculates the maximum value of a selected aggregate parameter of a called pattern. The aggregate
22 * parameter is selected with the '#' symbol; the aggregate parameter must not be used outside the aggregator call. The
23 * other parameters of the call might be bound or unbound; bound parameters limit the matches to consider for the
24 * minimum calculation.
25 *
26 * @since 1.4
27 * @author Gabor Bergmann
28 */
29@AggregatorType(
30 // TODO T extends Comparable?
31 parameterTypes = {BigDecimal.class, BigInteger.class, Boolean.class, Byte.class, Calendar.class, Character.class,
32 Date.class, Double.class, Enum.class, Float.class, Integer.class, Long.class, Short.class, String.class},
33 returnTypes = {BigDecimal.class, BigInteger.class, Boolean.class, Byte.class, Calendar.class, Character.class,
34 Date.class, Double.class, Enum.class, Float.class, Integer.class, Long.class, Short.class, String.class})
35public final class max implements IAggregatorFactory {
36
37 @Override
38 public BoundAggregator getAggregatorLogic(Class<?> domainClass) {
39 if (Comparable.class.isAssignableFrom(domainClass))
40 return new BoundAggregator(ExtremumOperator.getMax(), domainClass, domainClass);
41 else throw new IllegalArgumentException();
42 }
43
44}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/min.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/min.java
new file mode 100644
index 00000000..6408c57b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/min.java
@@ -0,0 +1,44 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import java.math.BigDecimal;
12import java.math.BigInteger;
13import java.util.Calendar;
14import java.util.Date;
15
16import tools.refinery.viatra.runtime.matchers.psystem.aggregations.AggregatorType;
17import tools.refinery.viatra.runtime.matchers.psystem.aggregations.BoundAggregator;
18import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IAggregatorFactory;
19
20/**
21 * This aggregator calculates the minimum value of a selected aggregate parameter of a called pattern. The aggregate
22 * parameter is selected with the '#' symbol; the aggregate parameter must not be used outside the aggregator call. The
23 * other parameters of the call might be bound or unbound; bound parameters limit the matches to consider for the
24 * minimum calculation.
25 *
26 * @since 1.4
27 *
28 */
29@AggregatorType(
30 // TODO T extends Comparable?
31 parameterTypes = {BigDecimal.class, BigInteger.class, Boolean.class, Byte.class, Calendar.class, Character.class,
32 Date.class, Double.class, Enum.class, Float.class, Integer.class, Long.class, Short.class, String.class},
33 returnTypes = {BigDecimal.class, BigInteger.class, Boolean.class, Byte.class, Calendar.class, Character.class,
34 Date.class, Double.class, Enum.class, Float.class, Integer.class, Long.class, Short.class, String.class})
35public final class min implements IAggregatorFactory {
36
37 @Override
38 public BoundAggregator getAggregatorLogic(Class<?> domainClass) {
39 if (Comparable.class.isAssignableFrom(domainClass))
40 return new BoundAggregator(ExtremumOperator.getMin(), domainClass, domainClass);
41 else throw new IllegalArgumentException();
42 }
43
44}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/sum.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/sum.java
new file mode 100644
index 00000000..69ff2e75
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/sum.java
@@ -0,0 +1,39 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import tools.refinery.viatra.runtime.matchers.psystem.aggregations.AggregatorType;
12import tools.refinery.viatra.runtime.matchers.psystem.aggregations.BoundAggregator;
13import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IAggregatorFactory;
14
15/**
16 * This aggregator calculates the sum of the values of a selected aggregate parameter of a called pattern. The aggregate
17 * parameter is selected with the '#' symbol; the aggregate parameter must not be used outside the aggregator call. The
18 * other parameters of the call might be bound or unbound; bound parameters limit the matches to consider for the
19 * summation.
20 *
21 * @since 1.4
22 *
23 */
24@AggregatorType(
25 parameterTypes = {Integer.class, Double.class, Long.class},
26 returnTypes = {Integer.class, Double.class, Long.class})
27public final class sum implements IAggregatorFactory {
28
29 @Override
30 public BoundAggregator getAggregatorLogic(Class<?> domainClass) {
31 if (Integer.class.equals(domainClass))
32 return new BoundAggregator(IntegerSumOperator.INSTANCE, Integer.class, Integer.class);
33 if (Double.class.equals(domainClass))
34 return new BoundAggregator(DoubleSumOperator.INSTANCE, Double.class, Double.class);
35 if (Long.class.equals(domainClass))
36 return new BoundAggregator(LongSumOperator.INSTANCE, Long.class, Long.class);
37 else throw new IllegalArgumentException();
38 }
39}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/OrderedIterableMerge.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/OrderedIterableMerge.java
new file mode 100644
index 00000000..1917e909
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/OrderedIterableMerge.java
@@ -0,0 +1,83 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.algorithms;
10
11import java.util.Comparator;
12import java.util.Iterator;
13import java.util.NoSuchElementException;
14
15/**
16 * @author Gabor Bergmann
17 * @since 2.1
18 *
19 */
20public class OrderedIterableMerge {
21
22 private OrderedIterableMerge() {
23 // Hidden utility class constructor
24 }
25
26 /**
27 * Lazily merges two iterables, each ordered according to a given comparator.
28 * Retains order in the result, and also eliminates any duplicates that appear in both arguments.
29 */
30 public static <T> Iterable<T> mergeUniques(Iterable<T> first, Iterable<T> second, Comparator<T> comparator) {
31 return () -> new Iterator<T>() {
32 Iterator<T> firstIterator = first.iterator();
33 Iterator<T> secondIterator = second.iterator();
34 T firstItem;
35 T secondItem;
36
37 {
38 fetchFirst();
39 fetchSecond();
40 }
41
42 private T fetchFirst() {
43 T previous = firstItem;
44 if (firstIterator.hasNext())
45 firstItem = firstIterator.next();
46 else
47 firstItem = null;
48 return previous;
49 }
50 private T fetchSecond() {
51 T previous = secondItem;
52 if (secondIterator.hasNext())
53 secondItem = secondIterator.next();
54 else
55 secondItem = null;
56 return previous;
57 }
58
59 @Override
60 public boolean hasNext() {
61 return firstItem != null || secondItem != null;
62 }
63 @Override
64 public T next() {
65 if (!hasNext()) throw new NoSuchElementException();
66 if (firstItem != null && secondItem != null) {
67 if (secondItem == firstItem) { // duplicates
68 fetchFirst();
69 return fetchSecond();
70 } else if (comparator.compare(firstItem, secondItem) < 0) {
71 return fetchFirst();
72 } else {
73 return fetchSecond();
74 }
75 } else if (firstItem != null) {
76 return fetchFirst();
77 } else { // secondItem must be non-null
78 return fetchSecond();
79 }
80 }
81 };
82 }
83}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFind.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFind.java
new file mode 100644
index 00000000..c69f08e5
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFind.java
@@ -0,0 +1,214 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.algorithms;
11
12import java.util.Collection;
13import java.util.HashSet;
14import java.util.Iterator;
15import java.util.Map;
16import java.util.Set;
17
18import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
19
20/**
21 * Union-find data structure implementation. Note that the implementation relies on the correct implementation of the
22 * equals method of the type parameter's class.
23 *
24 * @author Tamas Szabo
25 *
26 * @param <V>
27 * the type parameter of the element's stored in the union-find data structure
28 */
29public class UnionFind<V> {
30
31 private final Map<V, UnionFindNodeProperty<V>> nodeMap;
32 final Map<V, Set<V>> setMap;
33
34 /**
35 * Instantiate a new union-find data structure.
36 */
37 public UnionFind() {
38 nodeMap = CollectionsFactory.createMap();
39 setMap = CollectionsFactory.createMap();
40 }
41
42 /**
43 * Instantiate a new union-find data structure with the given elements as separate sets.
44 */
45 public UnionFind(Iterable<V> elements) {
46 this();
47 for (V element : elements) {
48 makeSet(element);
49 }
50 }
51
52 /**
53 * Creates a new union set from a collection of elements.
54 *
55 * @param nodes
56 * the collection of elements
57 * @return the root element
58 */
59 public V makeSet(Collection<V> nodes) {
60 if (!nodes.isEmpty()) {
61 Iterator<V> iterator = nodes.iterator();
62 V root = makeSet(iterator.next());
63 while (iterator.hasNext()) {
64 root = union(root, iterator.next());
65 }
66 return root;
67 } else {
68 return null;
69 }
70 }
71
72 /**
73 * This method creates a single set containing the given node.
74 *
75 * @param node
76 * the root node of the set
77 * @return the root element
78 */
79 public V makeSet(V node) {
80 if (!nodeMap.containsKey(node)) {
81 UnionFindNodeProperty<V> prop = new UnionFindNodeProperty<V>(0, node);
82 nodeMap.put(node, prop);
83 Set<V> set = new HashSet<V>();
84 set.add(node);
85 setMap.put(node, set);
86 }
87 return node;
88 }
89
90 /**
91 * Find method with path compression.
92 *
93 * @param node
94 * the node to find
95 * @return the root node of the set in which the given node can be found
96 */
97 public V find(V node) {
98 UnionFindNodeProperty<V> prop = nodeMap.get(node);
99
100 if (prop != null) {
101 if (prop.parent.equals(node)) {
102 return node;
103 } else {
104 prop.parent = find(prop.parent);
105 return prop.parent;
106 }
107 }
108 return null;
109 }
110
111 /**
112 * Union by rank implementation of the two sets which contain x and y; x and/or y can be a single element from the
113 * universe.
114 *
115 * @param x
116 * set or single element of the universe
117 * @param y
118 * set or single element of the universe
119 * @return the new root of the two sets
120 */
121 public V union(V x, V y) {
122 V xRoot = find(x);
123 V yRoot = find(y);
124
125 if ((xRoot == null) || (yRoot == null)) {
126 return union( (xRoot == null) ? makeSet(x) : xRoot, (yRoot == null) ? makeSet(y) : yRoot);
127 }
128 else if (!xRoot.equals(yRoot)) {
129 UnionFindNodeProperty<V> xRootProp = nodeMap.get(xRoot);
130 UnionFindNodeProperty<V> yRootProp = nodeMap.get(yRoot);
131
132 if (xRootProp.rank < yRootProp.rank) {
133 xRootProp.parent = yRoot;
134 setMap.get(yRoot).addAll(setMap.get(xRoot));
135 setMap.remove(xRoot);
136 return yRoot;
137 } else {// (xRootProp.rank >= yRootProp.rank)
138 yRootProp.parent = xRoot;
139 yRootProp.rank = (xRootProp.rank == yRootProp.rank) ? yRootProp.rank + 1 : yRootProp.rank;
140 setMap.get(xRoot).addAll(setMap.get(yRoot));
141 setMap.remove(yRoot);
142 return xRoot;
143 }
144 } else {
145 return xRoot;
146 }
147 }
148
149 /**
150 * Places the given elements in to the same partition.
151 */
152 public void unite(Set<V> elements) {
153 if (elements.size() > 1) {
154 V current = null;
155 for (V element : elements) {
156 if (current != null) {
157 if (getPartition(element) != null) {
158 union(current, element);
159 }
160 } else {
161 if (getPartition(element) != null) {
162 current = element;
163 }
164 }
165 }
166 }
167 }
168
169 /**
170 * Delete the set whose root is the given node.
171 *
172 * @param root
173 * the root node
174 */
175 public void deleteSet(V root) {
176 // if (setMap.containsKey(root))
177 for (V n : setMap.get(root)) {
178 nodeMap.remove(n);
179 }
180 setMap.remove(root);
181 }
182
183 /**
184 * Returns if all given elements are in the same partition.
185 */
186 public boolean isSameUnion(Set<V> elements) {
187 for (Set<V> partition : setMap.values()) {
188 if (partition.containsAll(elements)) {
189 return true;
190 }
191 }
192 return false;
193 }
194
195
196 /**
197 * Returns the partition in which the given element can be found, or null otherwise.
198 */
199 public Set<V> getPartition(V element) {
200 V root = find(element);
201 return setMap.get(root);
202 }
203
204 /**
205 * Returns all partitions.
206 */
207 public Collection<Set<V>> getPartitions() {
208 return setMap.values();
209 }
210
211 public Set<V> getPartitionHeads() {
212 return setMap.keySet();
213 }
214}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFindNodeProperty.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFindNodeProperty.java
new file mode 100644
index 00000000..82852f9c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFindNodeProperty.java
@@ -0,0 +1,32 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.algorithms;
11
12public class UnionFindNodeProperty<V> {
13
14 public int rank;
15 public V parent;
16
17 public UnionFindNodeProperty() {
18 this.rank = 0;
19 this.parent = null;
20 }
21
22 public UnionFindNodeProperty(int rank, V parent) {
23 super();
24 this.rank = rank;
25 this.parent = parent;
26 }
27
28 @Override
29 public String toString() {
30 return "[rank:" + rank + ", parent:" + parent.toString() + "]";
31 }
32}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/CommonQueryHintOptions.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/CommonQueryHintOptions.java
new file mode 100644
index 00000000..317293bf
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/CommonQueryHintOptions.java
@@ -0,0 +1,36 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IRewriterTraceCollector;
12import tools.refinery.viatra.runtime.matchers.psystem.rewriters.NopTraceCollector;
13
14/**
15 * Query evaluation hints applicable to any engine
16 * @since 1.6
17 *
18 */
19public final class CommonQueryHintOptions {
20
21 private CommonQueryHintOptions() {
22 // Hiding constructor for utility class
23 }
24
25 /**
26 * This hint instructs the query backends to record trace information into the given trace collector
27 */
28 public static final QueryHintOption<IRewriterTraceCollector> normalizationTraceCollector =
29 hintOption("normalizationTraceCollector", NopTraceCollector.INSTANCE);
30
31 // internal helper for conciseness
32 private static <T> QueryHintOption<T> hintOption(String hintKeyLocalName, T defaultValue) {
33 return new QueryHintOption<>(CommonQueryHintOptions.class, hintKeyLocalName, defaultValue);
34 }
35
36}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ICallDelegationStrategy.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ICallDelegationStrategy.java
new file mode 100644
index 00000000..40853f46
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ICallDelegationStrategy.java
@@ -0,0 +1,89 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import tools.refinery.viatra.runtime.matchers.context.IQueryResultProviderAccess;
12import tools.refinery.viatra.runtime.matchers.psystem.IQueryReference;
13import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
14
15/**
16 * Function object that specifies how hints (including backend preferences) shall propagate through pattern calls.
17 *
18 * <p> A few useful default implementations are included as static fields.
19 *
20 * <p> As of 2.1, only suppported by the local search backend, and only if the pattern call is not flattened.
21 *
22 * @author Gabor Bergmann
23 * @since 2.1
24 */
25@FunctionalInterface
26public interface ICallDelegationStrategy {
27
28 /**
29 * Specifies how hints (including backend preferences) shall propagate through pattern calls.
30 *
31 * @param call a {@link PConstraint} in a query that calls another query.
32 * @param callerHint a hint under which the calling pattern is evaluated,
33 * @param callerBackend the actual backend evaluating the calling pattern.
34 * @param calleeHintProvider the provider of hints for the called pattern.
35 * @return the hints, including backend selection,
36 * that the backend responsible for the caller pattern must specify when
37 * requesting the {@link IQueryResultProvider} for the called pattern via {@link IQueryResultProviderAccess}.
38 */
39 public QueryEvaluationHint transformHints(IQueryReference call,
40 QueryEvaluationHint callerHint,
41 IQueryBackend callerBackend,
42 IQueryBackendHintProvider calleeHintProvider);
43
44
45 /**
46 * Options known for callee are used to override caller options, except the backend selection.
47 * Always use the same backend for the callee and the caller, regardless what is specified for the callee pattern.
48 * @author Gabor Bergmann
49 */
50 public static final ICallDelegationStrategy FULL_BACKEND_ADHESION = (call, callerHint, callerBackend, calleeHintProvider) -> {
51 QueryEvaluationHint calleeHint =
52 calleeHintProvider.getQueryEvaluationHint(call.getReferredQuery());
53 QueryEvaluationHint result =
54 callerHint == null ? calleeHint : callerHint.overrideBy(calleeHint);
55
56 QueryEvaluationHint backendAdhesion = new QueryEvaluationHint(
57 null /* settings-ignorant */, callerBackend.getFactory());
58 result = result.overrideBy(backendAdhesion);
59 return result;
60 };
61 /**
62 * Options known for callee are used to override caller options, including the backend selection.
63 * If callee does not specify a backend requirement, the backend of the caller is kept.
64 * @author Gabor Bergmann
65 */
66 public static final ICallDelegationStrategy PARTIAL_BACKEND_ADHESION = (call, callerHint, callerBackend, calleeHintProvider) -> {
67 QueryEvaluationHint backendAdhesion = new QueryEvaluationHint(
68 null /* settings-ignorant */, callerBackend.getFactory());
69
70 QueryEvaluationHint result =
71 callerHint == null ? backendAdhesion : callerHint.overrideBy(backendAdhesion);
72
73 QueryEvaluationHint calleeHint = calleeHintProvider.getQueryEvaluationHint(call.getReferredQuery());
74 result = result.overrideBy(calleeHint);
75
76 return result;
77 };
78 /**
79 * Options known for callee are used to override caller options, including the backend selection.
80 * Always use the backend specified for the callee (or the default if none), regardless of the backend of the caller.
81 * @author Gabor Bergmann
82 */
83 public static final ICallDelegationStrategy NO_BACKEND_ADHESION = (call, callerHint, callerBackend, calleeHintProvider) -> {
84 QueryEvaluationHint calleeHint = calleeHintProvider.getQueryEvaluationHint(call.getReferredQuery());
85 return callerHint == null ? calleeHint : callerHint.overrideBy(calleeHint);
86 };
87
88
89}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IMatcherCapability.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IMatcherCapability.java
new file mode 100644
index 00000000..104b68a8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IMatcherCapability.java
@@ -0,0 +1,26 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11/**
12 * Implementations of this interface can be used to decide whether a matcher created by an arbitrary backend can
13 * potentially be used as a substitute for another matcher.
14 *
15 * @author Grill Balázs
16 * @since 1.4
17 *
18 */
19public interface IMatcherCapability {
20
21 /**
22 * Returns true if matchers of this capability can be used as a substitute for a matcher implementing the given capability
23 */
24 public boolean canBeSubstitute(IMatcherCapability capability);
25
26}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackend.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackend.java
new file mode 100644
index 00000000..c85f10a4
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackend.java
@@ -0,0 +1,68 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
12import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
13
14/**
15 * Internal interface for a VIATRA query specification. Each query is associated with a pattern. Methods instantiate a matcher
16 * of the pattern with various parameters.
17 *
18 * @author Bergmann Gábor
19 * @since 0.9
20 * @noextend This interface is not intended to be extended by users of the VIATRA framework, and should only be used by the query engine
21 */
22public interface IQueryBackend {
23
24 /**
25 * @return true iff this backend is incremental, i.e. it caches the results of queries for quick retrieval,
26 * and can provide update notifications on result set changes.
27 */
28 public boolean isCaching();
29
30 /**
31 * Returns a result provider for a given query. Repeated calls may return the same instance.
32 * @throws ViatraQueryRuntimeException
33 */
34 public IQueryResultProvider getResultProvider(PQuery query);
35
36 /**
37 * Returns a result provider for a given query. Repeated calls may return the same instance.
38 * @param optional hints that may override engine and query defaults (as provided by {@link IQueryBackendHintProvider}). Can be null.
39 * @throws ViatraQueryRuntimeException
40 * @since 1.4
41 */
42 public IQueryResultProvider getResultProvider(PQuery query, QueryEvaluationHint hints);
43
44 /**
45 * Returns an existing result provider for a given query, if it was previously constructed, returns null otherwise.
46 * Will not construct and initialize new result providers.
47 */
48 public IQueryResultProvider peekExistingResultProvider(PQuery query);
49
50 /**
51 * Propagates all pending updates in this query backend. The implementation of this method is optional, and it
52 * can be ignored entirely if the backend does not delay updates.
53 * @since 1.6
54 */
55 public void flushUpdates();
56
57 /**
58 * Disposes the query backend.
59 */
60 public abstract void dispose();
61
62 /**
63 * @return the factory that created this backend, if this functionality is supported
64 * @since 2.1
65 */
66 public IQueryBackendFactory getFactory();
67
68}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactory.java
new file mode 100644
index 00000000..e264ab3f
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactory.java
@@ -0,0 +1,52 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
12import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
13
14/**
15 * A Query Backend Factory identifies a query evaluator implementation, and can create an evaluator instance (an {@link IQueryBackend}) tied to a specific VIATRA Query engine upon request.
16 *
17 * <p> The factory is used as a lookup key for the backend instance,
18 * therefore implementors should either be singletons, or implement equals() / hashCode() accordingly.
19 *
20 * @author Bergmann Gabor
21 *
22 */
23public interface IQueryBackendFactory {
24
25 /**
26 * Creates a new {@link IQueryBackend} instance tied to the given context elements.
27 *
28 * @return an instance of the class returned by {@link #getBackendClass()} that operates in the given context.
29 * @since 1.5
30 */
31 public IQueryBackend
32 create(IQueryBackendContext context);
33
34
35 /**
36 * The backend instances created by this factory are guaranteed to conform to the returned class.
37 */
38 public Class<? extends IQueryBackend> getBackendClass();
39
40 /**
41 * Calculate the required capabilities, which are needed to execute the given pattern
42 *
43 * @since 1.4
44 */
45 public IMatcherCapability calculateRequiredCapability(PQuery query, QueryEvaluationHint hint);
46
47 /**
48 * Returns whether the current backend is caching
49 * @since 2.0
50 */
51 public boolean isCaching();
52}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactoryProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactoryProvider.java
new file mode 100644
index 00000000..8787814e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactoryProvider.java
@@ -0,0 +1,46 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11/**
12 * A provider interface for {@link IQueryBackendFactory} instances.
13 * @since 2.0
14 */
15public interface IQueryBackendFactoryProvider {
16
17 /**
18 * Returns a query backend factory instance. The method should return the same instance in case of repeated calls.
19 */
20 IQueryBackendFactory getFactory();
21
22 /**
23 * Returns whether the given query backend should be considered as system default. If multiple backends are
24 * registered as system default, it is undefined which one will be chosen.
25 */
26 default boolean isSystemDefaultEngine() {
27 return false;
28 }
29
30 /**
31 * Returns whether the given query backend should be considered as system default search backend. If multiple
32 * backends are registered as system default, it is undefined which one will be chosen.
33 */
34 default boolean isSystemDefaultSearchBackend() {
35 return false;
36 }
37
38
39 /**
40 * Returns whether the given query backend should be considered as system default caching backend. If multiple
41 * backends are registered as system default, it is undefined which one will be chosen.
42 */
43 default boolean isSystemDefaultCachingBackend() {
44 return false;
45 }
46}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendHintProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendHintProvider.java
new file mode 100644
index 00000000..9bb76349
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendHintProvider.java
@@ -0,0 +1,32 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
12
13/**
14 * Provides query evaluation hints consisting of the Engine default hints and
15 * the hints provided by the pattern itself.
16 *
17 * @author Bergmann Gabor
18 * @since 0.9
19 * @noimplement This interface is not intended to be implemented by clients, except in the tools.refinery.viatra.runtime plugin.
20 */
21public interface IQueryBackendHintProvider {
22
23 /**
24 * Suggests query evaluation hints regarding a query. The returned hints reflects the default hints of the
25 * query engine merged with the hints provided by the pattern itself. These can be overridden via specific
26 * advanced API of the engine.
27 *
28 * @since 1.4
29 */
30 QueryEvaluationHint getQueryEvaluationHint(PQuery query);
31
32}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryResultProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryResultProvider.java
new file mode 100644
index 00000000..cd7d050f
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryResultProvider.java
@@ -0,0 +1,202 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import java.util.Optional;
12import java.util.stream.Stream;
13
14import tools.refinery.viatra.runtime.matchers.planning.helpers.StatisticsHelper;
15import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
16import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
17import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
18import tools.refinery.viatra.runtime.matchers.util.Accuracy;
19
20/**
21 * An internal interface of the query backend that provides results of a given query.
22 * @author Bergmann Gabor
23 * @noimplement This interface is not intended to be implemented by clients.
24 */
25public interface IQueryResultProvider {
26
27 /**
28 * Decides whether there are any matches of the pattern that conform to the given fixed values of some parameters.
29 *
30 * @param parameters
31 * array where each non-null element binds the corresponding pattern parameter to a fixed value.
32 * @pre size of input array must be equal to the number of parameters.
33 * @since 2.0
34 */
35 public boolean hasMatch(Object[] parameters);
36
37 /**
38 * Decides whether there are any matches of the pattern that conform to the given fixed values of some parameters.
39 *
40 * @param parameterSeedMask
41 * a mask that extracts those parameters of the query (from the entire parameter list) that should be
42 * bound to a fixed value
43 * @param parameters
44 * the tuple of fixed values restricting the match set to be considered, in the same order as given in
45 * parameterSeedMask, so that for each considered match tuple,
46 * projectedParameterSeed.equals(parameterSeedMask.transform(match)) should hold
47 * @since 2.0
48 */
49 public boolean hasMatch(TupleMask parameterSeedMask, ITuple projectedParameterSeed);
50
51 /**
52 * Returns the number of all matches of the pattern that conform to the given fixed values of some parameters.
53 *
54 * @param parameters
55 * array where each non-null element binds the corresponding pattern parameter to a fixed value.
56 * @pre size of input array must be equal to the number of parameters.
57 * @return the number of pattern matches found.
58 */
59 public int countMatches(Object[] parameters);
60
61 /**
62 * Returns the number of all matches of the pattern that conform to the given fixed values of some parameters.
63 *
64 * @param parameterSeedMask
65 * a mask that extracts those parameters of the query (from the entire parameter list) that should be
66 * bound to a fixed value
67 * @param parameters
68 * the tuple of fixed values restricting the match set to be considered, in the same order as given in
69 * parameterSeedMask, so that for each considered match tuple,
70 * projectedParameterSeed.equals(parameterSeedMask.transform(match)) should hold
71 * @return the number of pattern matches found.
72 * @since 1.7
73 */
74 public int countMatches(TupleMask parameterSeedMask, ITuple projectedParameterSeed);
75
76 /**
77 * Gives an estimate of the number of different groups the matches are projected into by the given mask
78 * (e.g. for an identity mask, this means the full match set size). The estimate must meet the required accuracy.
79 *
80 * <p> If there is insufficient information to provide an answer up to the required precision, {@link Optional#empty()} may be returned.
81 * In other words, query backends may deny an answer, or do their best to give an estimate without actually determining the match set of the query.
82 * However, caching backends are expected to simply return the indexed (projection) size, initialized on-demand if necessary.
83 *
84 * <p> PRE: {@link TupleMask#isNonrepeating()} must hold for the group mask.
85 *
86 * @return if available, an estimate of the cardinality of the projection of the match set, with the desired accuracy.
87 *
88 * @since 2.1
89 */
90 public Optional<Long> estimateCardinality(TupleMask groupMask, Accuracy requiredAccuracy);
91
92 /**
93 * Gives an estimate of the average size of different groups the matches are projected into by the given mask
94 * (e.g. for an identity mask, this means 1, while for an empty mask, the result is match set size).
95 * The estimate must meet the required accuracy.
96 *
97 * <p> If there is insufficient information to provide an answer up to the required precision, {@link Optional#empty()} may be returned.
98 * In other words, query backends may deny an answer, or do their best to give an estimate without actually determining the match set of the query.
99 * However, caching backends are expected to simply return the exact value from the index, initialized on-demand if necessary.
100 *
101 * <p> For an empty match set, zero is acceptable as an exact answer.
102 *
103 * <p> PRE: {@link TupleMask#isNonrepeating()} must hold for the group mask.
104 *
105 * @return if available, an estimate of the average size of each projection group of the match set, with the desired accuracy.
106 *
107 * @since 2.1
108 */
109 public default Optional<Double> estimateAverageBucketSize(TupleMask groupMask, Accuracy requiredAccuracy) {
110 return StatisticsHelper.estimateAverageBucketSize(groupMask, requiredAccuracy, this::estimateCardinality);
111 }
112
113 /**
114 * Returns an arbitrarily chosen match of the pattern that conforms to the given fixed values of some parameters.
115 * Neither determinism nor randomness of selection is guaranteed.
116 *
117 * @param parameters
118 * array where each non-null element binds the corresponding pattern parameter to a fixed value.
119 * @pre size of input array must be equal to the number of parameters.
120 * @return a match represented in the internal {@link Tuple} representation.
121 * @since 2.0
122 */
123 public Optional<Tuple> getOneArbitraryMatch(Object[] parameters);
124
125 /**
126 * Returns an arbitrarily chosen match of the pattern that conforms to the given fixed values of some parameters.
127 * Neither determinism nor randomness of selection is guaranteed.
128 *
129 * @param parameterSeedMask
130 * a mask that extracts those parameters of the query (from the entire parameter list) that should be
131 * bound to a fixed value
132 * @param parameters
133 * the tuple of fixed values restricting the match set to be considered, in the same order as given in
134 * parameterSeedMask, so that for each considered match tuple,
135 * projectedParameterSeed.equals(parameterSeedMask.transform(match)) should hold
136 * @return a match represented in the internal {@link Tuple} representation.
137 * @since 2.0
138 */
139 public Optional<Tuple> getOneArbitraryMatch(TupleMask parameterSeedMask, ITuple parameters);
140
141 /**
142 * Returns the set of all matches of the pattern that conform to the given fixed values of some parameters.
143 *
144 * @param parameters
145 * array where each non-null element binds the corresponding pattern parameter to a fixed value.
146 * @pre size of input array must be equal to the number of parameters.
147 * @return matches represented in the internal {@link Tuple} representation.
148 * @since 2.0
149 */
150 public Stream<Tuple> getAllMatches(Object[] parameters);
151
152 /**
153 * Returns the set of all matches of the pattern that conform to the given fixed values of some parameters.
154 *
155 * @param parameterSeedMask
156 * a mask that extracts those parameters of the query (from the entire parameter list) that should be
157 * bound to a fixed value
158 * @param parameters
159 * the tuple of fixed values restricting the match set to be considered, in the same order as given in
160 * parameterSeedMask, so that for each considered match tuple,
161 * projectedParameterSeed.equals(parameterSeedMask.transform(match)) should hold
162 * @return matches represented in the internal {@link Tuple} representation.
163 * @since 2.0
164 */
165 public Stream<Tuple> getAllMatches(TupleMask parameterSeedMask, ITuple parameters);
166
167 /**
168 * The underlying query evaluator backend.
169 */
170 public IQueryBackend getQueryBackend();
171
172 /**
173 * Internal method that registers low-level callbacks for match appearance and disappearance.
174 *
175 * <p>
176 * <b>Caution: </b> This is a low-level callback that is invoked when the pattern matcher is not necessarily in a
177 * consistent state yet. Importantly, no model modification permitted during the callback.
178 *
179 * <p>
180 * The callback can be unregistered via invoking {@link #removeUpdateListener(Object)} with the same tag.
181 *
182 * @param listener
183 * the listener that will be notified of each new match that appears or disappears, starting from now.
184 * @param listenerTag
185 * a tag by which to identify the listener for later removal by {@link #removeUpdateListener(Object)}.
186 * @param fireNow
187 * if true, the insertion update allback will be immediately invoked on all current matches as a one-time effect.
188 *
189 * @throws UnsupportedOperationException if this is a non-incremental backend
190 * (i.e. {@link IQueryBackend#isCaching()} on {@link #getQueryBackend()} returns false)
191 */
192 public void addUpdateListener(final IUpdateable listener, final Object listenerTag, boolean fireNow);
193
194 /**
195 * Removes an existing listener previously registered with the given tag.
196 *
197 * @throws UnsupportedOperationException if this is a non-incremental backend
198 * (i.e. {@link IQueryBackend#isCaching()} on {@link #getQueryBackend()} returns false)
199 */
200 public void removeUpdateListener(final Object listenerTag);
201
202}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IUpdateable.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IUpdateable.java
new file mode 100644
index 00000000..baf7144a
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IUpdateable.java
@@ -0,0 +1,27 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
12
13/**
14 * Internal interface for the query backend to singal an update to a query result.
15 * @author Bergmann Gabor
16 * @since 0.9
17 *
18 */
19public interface IUpdateable {
20
21 /**
22 * This callback method must be free of exceptions, even {@link RuntimeException}s (though not {@link Error}s).
23 * @param updateElement the tuple that is changed
24 * @param isInsertion true if the tuple appeared in the result set, false if disappeared from the result set
25 */
26 public void update(Tuple updateElement, boolean isInsertion);
27}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryEvaluationHint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryEvaluationHint.java
new file mode 100644
index 00000000..eab92128
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryEvaluationHint.java
@@ -0,0 +1,241 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import java.util.AbstractMap;
12import java.util.Collections;
13import java.util.HashMap;
14import java.util.Map;
15import java.util.Objects;
16import java.util.stream.Collectors;
17
18import tools.refinery.viatra.runtime.matchers.util.Preconditions;
19
20/**
21 * Provides VIATRA Query with additional hints on how a query should be evaluated. The same hint can be provided to multiple queries.
22 *
23 * <p> This class is immutable. Overriding options will create a new instance.
24 *
25 * <p>
26 * Here be dragons: for advanced users only.
27 *
28 * @author Bergmann Gabor
29 *
30 */
31public class QueryEvaluationHint {
32
33 /**
34 * @since 2.0
35 *
36 */
37 public enum BackendRequirement {
38 /**
39 * The current hint does not specify any backend requirement
40 */
41 UNSPECIFIED,
42 /**
43 * The current hint specifies that the default search backend of the engine should be used
44 */
45 DEFAULT_SEARCH,
46 /**
47 * The current hint specifies that the default caching backend of the engine should be used
48 */
49 DEFAULT_CACHING,
50 /**
51 * The current hint specifies that a specific backend is to be used
52 */
53 SPECIFIC
54 }
55
56 final IQueryBackendFactory queryBackendFactory;
57 final Map<QueryHintOption<?>, Object> backendHintSettings;
58 final BackendRequirement requirement;
59
60 /**
61 * Specifies the suggested query backend requirements, and value settings for additional backend-specific options.
62 *
63 * <p>
64 * The backend requirement type must not be {@link BackendRequirement#SPECIFIC} - for that case, use the constructor
65 * {@link #QueryEvaluationHint(Map, IQueryBackendFactory)}.
66 *
67 * @param backendHintSettings
68 * if non-null, each entry in the map overrides backend-specific options regarding query evaluation
69 * (null-valued map entries permitted to erase hints); passing null means default options associated with
70 * the query
71 * @param backendRequirementType
72 * defines the kind of backend requirement
73 * @since 2.0
74 */
75 public QueryEvaluationHint(Map<QueryHintOption<?>, Object> backendHintSettings, BackendRequirement backendRequirementType) {
76 super();
77 Preconditions.checkArgument(backendRequirementType != null, "Specific requirement needs to be set");
78 Preconditions.checkArgument(backendRequirementType != BackendRequirement.SPECIFIC, "Specific backend requirement needs providing a corresponding backend type");
79 this.queryBackendFactory = null;
80 this.requirement = backendRequirementType;
81 this.backendHintSettings = (backendHintSettings == null)
82 ? Collections.<QueryHintOption<?>, Object> emptyMap()
83 : new HashMap<>(backendHintSettings);
84 }
85
86 /**
87 * Specifies the suggested query backend, and value settings for additional backend-specific options. The first
88 * parameter can be null; if the second parameter is null, it is expected that the other constructor is called
89 * instead with a {@link BackendRequirement#UNSPECIFIED} parameter.
90 *
91 * @param backendHintSettings
92 * if non-null, each entry in the map overrides backend-specific options regarding query evaluation
93 * (null-valued map entries permitted to erase hints); passing null means default options associated with
94 * the query
95 * @param queryBackendFactory
96 * overrides the query evaluator algorithm; passing null retains the default algorithm associated with
97 * the query
98 * @since 1.5
99 */
100 public QueryEvaluationHint(
101 Map<QueryHintOption<?>, Object> backendHintSettings,
102 IQueryBackendFactory queryBackendFactory) {
103 super();
104 this.queryBackendFactory = queryBackendFactory;
105 this.requirement = (queryBackendFactory == null) ? BackendRequirement.UNSPECIFIED : BackendRequirement.SPECIFIC;
106 this.backendHintSettings = (backendHintSettings == null)
107 ? Collections.<QueryHintOption<?>, Object> emptyMap()
108 : new HashMap<>(backendHintSettings);
109 }
110
111 /**
112 * Returns the backend requirement described by this hint. If a specific backend is required, that can be queried by {@link #getQueryBackendFactory()}.
113 * @since 2.0
114 */
115 public BackendRequirement getQueryBackendRequirementType() {
116 return requirement;
117 }
118
119 /**
120 * A suggestion for choosing the query evaluator algorithm.
121 *
122 * <p>
123 * Returns null iff {@link #getQueryBackendRequirementType()} does not return {@link BackendRequirement#SPECIFIC};
124 * in such cases a corresponding default backend is selected inside the engine
125 */
126 public IQueryBackendFactory getQueryBackendFactory() {
127 return queryBackendFactory;
128 }
129
130 /**
131 * Each entry in the immutable map overrides backend-specific options regarding query evaluation.
132 *
133 * <p>The map is non-null, even if empty.
134 * Null-valued map entries are also permitted to erase hints via {@link #overrideBy(QueryEvaluationHint)}.
135 *
136 * @since 1.5
137 */
138 public Map<QueryHintOption<?>, Object> getBackendHintSettings() {
139 return backendHintSettings;
140 }
141
142
143 /**
144 * Override values in this hint and return a consolidated instance.
145 *
146 * @since 1.4
147 */
148 public QueryEvaluationHint overrideBy(QueryEvaluationHint overridingHint){
149 if (overridingHint == null)
150 return this;
151
152 BackendRequirement overriddenRequirement = this.getQueryBackendRequirementType();
153 if (overridingHint.getQueryBackendRequirementType() != BackendRequirement.UNSPECIFIED) {
154 overriddenRequirement = overridingHint.getQueryBackendRequirementType();
155 }
156 Map<QueryHintOption<?>, Object> hints = new HashMap<>(this.getBackendHintSettings());
157 if (overridingHint.getBackendHintSettings() != null) {
158 hints.putAll(overridingHint.getBackendHintSettings());
159 }
160 if (overriddenRequirement == BackendRequirement.SPECIFIC) {
161 IQueryBackendFactory factory = this.getQueryBackendFactory();
162 if (overridingHint.getQueryBackendFactory() != null) {
163 factory = overridingHint.getQueryBackendFactory();
164 }
165 return new QueryEvaluationHint(hints, factory);
166 } else {
167 return new QueryEvaluationHint(hints, overriddenRequirement);
168 }
169 }
170
171 /**
172 * Returns whether the given hint option is overridden.
173 * @since 1.5
174 */
175 public boolean isOptionOverridden(QueryHintOption<?> option) {
176 return getBackendHintSettings().containsKey(option);
177 }
178
179 /**
180 * Returns the value of the given hint option from the given hint collection, or null if not defined.
181 * @since 1.5
182 */
183 @SuppressWarnings("unchecked")
184 public <HintValue> HintValue getValueOrNull(QueryHintOption<HintValue> option) {
185 return (HintValue) getBackendHintSettings().get(option);
186 }
187
188 /**
189 * Returns the value of the given hint option from the given hint collection, or the default value if not defined.
190 * Intended to be called by backends to find out the definitive value that should be considered.
191 * @since 1.5
192 */
193 public <HintValue> HintValue getValueOrDefault(QueryHintOption<HintValue> option) {
194 return option.getValueOrDefault(this);
195 }
196
197 @Override
198 public int hashCode() {
199 return Objects.hash(backendHintSettings, queryBackendFactory, requirement);
200 }
201
202 @Override
203 public boolean equals(Object obj) {
204 if (this == obj)
205 return true;
206 if (obj == null)
207 return false;
208 if (getClass() != obj.getClass())
209 return false;
210 QueryEvaluationHint other = (QueryEvaluationHint) obj;
211 return Objects.equals(backendHintSettings, other.backendHintSettings)
212 &&
213 Objects.equals(queryBackendFactory, other.queryBackendFactory)
214 &&
215 Objects.equals(requirement, other.requirement)
216 ;
217 }
218
219 @Override
220 public String toString() {
221 StringBuilder sb = new StringBuilder();
222
223 if (getQueryBackendFactory() != null)
224 sb.append("backend: ").append(getQueryBackendFactory().getBackendClass().getSimpleName());
225 if (! backendHintSettings.isEmpty()) {
226 sb.append("hints: ");
227 if(backendHintSettings instanceof AbstractMap){
228 sb.append(backendHintSettings.toString());
229 } else {
230 // we have to iterate on the contents
231
232 String joinedHintMap = backendHintSettings.entrySet().stream()
233 .map(setting -> setting.getKey() + "=" + setting.getValue()).collect(Collectors.joining(", "));
234 sb.append('{').append(joinedHintMap).append('}');
235 }
236 }
237
238 final String result = sb.toString();
239 return result.isEmpty() ? "defaults" : result;
240 }
241}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryHintOption.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryHintOption.java
new file mode 100644
index 00000000..2c6bb4de
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryHintOption.java
@@ -0,0 +1,122 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import java.util.Map;
12import java.util.Objects;
13
14/**
15 * Each instance of this class corresponds to a given hint option.
16 *
17 * It is recommended to expose options to clients (and query backends) as public static fields.
18 *
19 * @author Gabor Bergmann
20 * @since 1.5
21 */
22public class QueryHintOption<HintValue> {
23
24 private String optionQualifiedName;
25 private HintValue defaultValue;
26
27 /**
28 * Instantiates an option object with the given name and default value.
29 */
30 public QueryHintOption(String optionQualifiedName, HintValue defaultValue) {
31 this.optionQualifiedName = optionQualifiedName;
32 this.defaultValue = defaultValue;
33 }
34
35 /**
36 * This is the recommended constructor for hint options defined as static fields within an enclosing class.
37 * Combines the qualified name of the hint from the (qualified) name of the enclosing class and a local name (unique within that class).
38 */
39 public <T extends HintValue> QueryHintOption(Class<?> optionNamespace, String optionLocalName, T defaultValue) {
40 this(String.format("%s@%s", optionLocalName, optionNamespace.getName()), defaultValue);
41 }
42
43 /**
44 * Returns the qualified name, a unique string identifier of the option.
45 */
46 public String getQualifiedName() {
47 return optionQualifiedName;
48 }
49
50 /**
51 * Returns the default value of this hint option, which is to be used by query backends in the case no overriding value is assigned.
52 */
53 public HintValue getDefaultValue() {
54 return defaultValue;
55 }
56
57 /**
58 * Returns the value of this hint option from the given hint collection, or the default value if not defined.
59 * Intended to be called by backends to find out the definitive value that should be considered.
60 */
61 @SuppressWarnings("unchecked")
62 public HintValue getValueOrDefault(QueryEvaluationHint hints) {
63 Object value = hints.getValueOrNull(this);
64 if (value == null)
65 return getDefaultValue();
66 else {
67 return (HintValue) value;
68 }
69 }
70
71
72 /**
73 * Returns the value of this hint option from the given hint collection, or null if not defined.
74 */
75 public HintValue getValueOrNull(QueryEvaluationHint hints) {
76 return hints.getValueOrNull(this);
77 }
78
79 /**
80 * Returns whether this hint option is defined in the given hint collection.
81 */
82 public boolean isOverriddenIn(QueryEvaluationHint hints) {
83 return hints.isOptionOverridden(this);
84 }
85
86 /**
87 * Puts a value of this hint option into an option-to-value map.
88 *
89 * <p> This method is offered in lieu of a builder API.
90 * Use this method on any number of hint options in order to populate an option-value map.
91 * Then instantiate the immutable {@link QueryEvaluationHint} using the map.
92 *
93 * @see #insertValueIfNondefault(Map, Object)
94 * @return the hint value that was previously present in the map under this hint option, carrying over the semantics of {@link Map#put(Object, Object)}.
95 */
96 @SuppressWarnings("unchecked")
97 public HintValue insertOverridingValue(Map<QueryHintOption<?>, Object> hints, HintValue overridingValue) {
98 return (HintValue) hints.put(this, overridingValue);
99 }
100
101 /**
102 * Puts a value of this hint option into an option-to-value map, if the given value differs from the default value of the option.
103 * If the default value is provided instead, then the map is not updated.
104 *
105 * <p> This method is offered in lieu of a builder API.
106 * Use this method on any number of hint options in order to populate an option-value map.
107 * Then instantiate the immutable {@link QueryEvaluationHint} using the map.
108 *
109 * @see #insertOverridingValue(Map, Object)
110 * @since 2.0
111 */
112 public void insertValueIfNondefault(Map<QueryHintOption<?>, Object> hints, HintValue overridingValue) {
113 if (!Objects.equals(defaultValue, overridingValue))
114 hints.put(this, overridingValue);
115 }
116
117 @Override
118 public String toString() {
119 return optionQualifiedName;
120 }
121
122}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ResultProviderRequestor.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ResultProviderRequestor.java
new file mode 100644
index 00000000..6ec6d53e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ResultProviderRequestor.java
@@ -0,0 +1,74 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import tools.refinery.viatra.runtime.matchers.context.IQueryResultProviderAccess;
12import tools.refinery.viatra.runtime.matchers.psystem.IQueryReference;
13import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
14
15/**
16 * Uniform way of requesting result providers for pattern calls within queries.
17 * Intended users are query backends, for calling other backends to deliver results of dependee queries.
18 *
19 * @author Gabor Bergmann
20 * @since 2.1
21 */
22public class ResultProviderRequestor {
23 IQueryBackend callerBackend;
24 IQueryResultProviderAccess resultProviderAccess;
25 IQueryBackendHintProvider hintProvider;
26 ICallDelegationStrategy delegationStrategy;
27 QueryEvaluationHint callerHint;
28 QueryEvaluationHint universalOverride;
29
30
31 /**
32 * @param callerBackend the actual backend evaluating the calling pattern.
33 * @param resultProviderAccess
34 * @param hintProvider
35 * @param delegationStrategy
36 * @param callerHint a hint under which the calling pattern is evaluated,
37 * @param universalOverride if non-null, overrides the hint with extra options <i>after</i> the {@link ICallDelegationStrategy}
38 */
39 public ResultProviderRequestor(IQueryBackend callerBackend, IQueryResultProviderAccess resultProviderAccess,
40 IQueryBackendHintProvider hintProvider, ICallDelegationStrategy delegationStrategy,
41 QueryEvaluationHint callerHint, QueryEvaluationHint universalOverride) {
42 super();
43 this.callerBackend = callerBackend;
44 this.resultProviderAccess = resultProviderAccess;
45 this.hintProvider = hintProvider;
46 this.delegationStrategy = delegationStrategy;
47 this.callerHint = callerHint;
48 this.universalOverride = universalOverride;
49 }
50
51
52
53
54 /**
55 *
56 * @param call a {@link PConstraint} in a query that calls another query.
57 * @param spotOverride if non-null, overrides the hint with extra options <i>after</i> the {@link ICallDelegationStrategy}
58 * and the universal override specified in the constructor
59 * @return the obtained result provider
60 */
61 public IQueryResultProvider requestResultProvider(IQueryReference call, QueryEvaluationHint spotOverride) {
62 QueryEvaluationHint hints =
63 delegationStrategy.transformHints(call, callerHint, callerBackend, hintProvider);
64
65 if (universalOverride != null)
66 hints = hints.overrideBy(universalOverride);
67
68 if (spotOverride != null)
69 hints = hints.overrideBy(spotOverride);
70
71 return resultProviderAccess.getResultProvider(call.getReferredQuery(), hints);
72 }
73
74}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryMetaContext.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryMetaContext.java
new file mode 100644
index 00000000..99611758
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryMetaContext.java
@@ -0,0 +1,69 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.Comparator;
14import java.util.HashMap;
15import java.util.Map;
16import java.util.Set;
17
18/**
19 * Common abstract class for implementers of {@link IQueryMetaContext}
20 *
21 * @author Grill Balázs
22 * @since 1.3
23 *
24 */
25public abstract class AbstractQueryMetaContext implements IQueryMetaContext {
26
27 /**
28 * @since 2.0
29 */
30 @Override
31 public Map<InputKeyImplication, Set<InputKeyImplication>> getConditionalImplications(IInputKey implyingKey) {
32 return new HashMap<>();
33 }
34
35 /**
36 * @since 1.6
37 */
38 @Override
39 public boolean canLeadOutOfScope(IInputKey key) {
40 return key.getArity() > 1;
41 }
42
43 /**
44 * @since 1.6
45 */
46 @Override
47 public Comparator<IInputKey> getSuggestedEliminationOrdering() {
48 return (o1, o2) -> 0;
49 }
50
51 /**
52 * @since 1.6
53 */
54 @Override
55 public Collection<InputKeyImplication> getWeakenedAlternatives(IInputKey implyingKey) {
56 return Collections.emptySet();
57 }
58
59 @Override
60 public boolean isPosetKey(IInputKey key) {
61 return false;
62 }
63
64 @Override
65 public IPosetComparator getPosetComparator(Iterable<IInputKey> key) {
66 return null;
67 }
68
69}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryRuntimeContext.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryRuntimeContext.java
new file mode 100644
index 00000000..c797eff9
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryRuntimeContext.java
@@ -0,0 +1,21 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11/**
12 * This class is intended to be extended by implementors. The main purpose of this abstract implementation to protect
13 * implementors from future changes in the interface.
14 *
15 * @author Grill Balázs
16 * @since 1.4
17 *
18 */
19public abstract class AbstractQueryRuntimeContext implements IQueryRuntimeContext {
20
21}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IInputKey.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IInputKey.java
new file mode 100644
index 00000000..4dbcca88
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IInputKey.java
@@ -0,0 +1,45 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11/**
12 * An input key identifies an input (extensional) relation, such as the instance set of a given node or edge type, or the direct containment relation.
13 *
14 * <p> The input key, at the very minimum, is associated with an arity (number of columns), a user-friendly name, and a string identifier (for distributive purposes).
15 *
16 * <p> The input key itself must be an immutable data object that properly overrides equals() and hashCode().
17 * It must be instantiable without using the query context object, so that query specifications may construct the appropriate PQueries.
18 *
19 * @author Bergmann Gabor
20 *
21 */
22public interface IInputKey {
23
24 /**
25 * A user-friendly name that can be shown on screen for debug purposes, included in exceptions, etc.
26 */
27 public String getPrettyPrintableName();
28 /**
29 * An internal string identifier that can be used to uniquely identify to input key (relevant for distributed applications).
30 */
31 public String getStringID();
32
33 /**
34 * The width of tuples in this relation.
35 */
36 public int getArity();
37
38 /**
39 * Returns true iff instance tuples of the key can be enumerated.
40 * <p> If false, the runtime can only test tuple membership in the extensional relation identified by the key, but not enumerate member tuples in general.
41 */
42 boolean isEnumerable();
43
44
45}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IPosetComparator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IPosetComparator.java
new file mode 100644
index 00000000..e2d5bcee
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IPosetComparator.java
@@ -0,0 +1,35 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
12
13/**
14 * Implementations of this interface aid the query engine with the ordering of poset elements. This information is
15 * particularly important in the delete and re-derive evaluation mode because they let the engine identify monotone
16 * change pairs.
17 *
18 * @author Tamas Szabo
19 * @since 1.6
20 */
21public interface IPosetComparator {
22
23 /**
24 * Returns true if the 'left' tuple of poset elements is smaller or equal than the 'right' tuple of poset elements according to
25 * the partial order that this poset comparator employs.
26 *
27 * @param left
28 * the left tuple of poset elements
29 * @param right
30 * the right tuple of poset elements
31 * @return true if left is smaller or equal to right, false otherwise
32 */
33 public boolean isLessOrEqual(final Tuple left, final Tuple right);
34
35}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryBackendContext.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryBackendContext.java
new file mode 100644
index 00000000..04f00aaa
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryBackendContext.java
@@ -0,0 +1,49 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11import org.apache.log4j.Logger;
12import tools.refinery.viatra.runtime.matchers.backend.IMatcherCapability;
13import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendHintProvider;
14import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
15import tools.refinery.viatra.runtime.matchers.psystem.analysis.QueryAnalyzer;
16import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
17
18/**
19 * This interface is a collector which holds every API that is provided by the engine to control
20 * the operation of the backends.
21 *
22 * @since 1.5
23 * @noimplement This interface is not intended to be implemented by clients.
24 */
25public interface IQueryBackendContext {
26
27 Logger getLogger();
28
29 IQueryRuntimeContext getRuntimeContext();
30
31 IQueryCacheContext getQueryCacheContext();
32
33 IQueryBackendHintProvider getHintProvider();
34
35 IQueryResultProviderAccess getResultProviderAccess();
36
37 QueryAnalyzer getQueryAnalyzer();
38
39 /**
40 * @since 2.0
41 */
42 IMatcherCapability getRequiredMatcherCapability(PQuery query, QueryEvaluationHint overrideHints);
43
44 /**
45 * @since 1.6
46 */
47 boolean areUpdatesDelayed();
48
49}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryCacheContext.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryCacheContext.java
new file mode 100644
index 00000000..617207f6
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryCacheContext.java
@@ -0,0 +1,39 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
12import tools.refinery.viatra.runtime.matchers.backend.IQueryBackend;
13import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
14import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
15
16/**
17 * Provides information on already cached queries to query evaluator backends at runtime.
18 *
19 * @author Bergmann Gabor
20 *
21 */
22public interface IQueryCacheContext {
23
24 /**
25 * Checks if there already is a caching result provider for the given query.
26 * <p> Returns false if called while the caching result provider of the given query is being constructed in the first place.
27 */
28 public boolean isResultCached(PQuery query);
29
30 /**
31 * Returns a caching result provider for the given query; it must be constructed if it does not exist yet.
32 * <p> <b>Caution:</b> behavior undefined if called while the caching result provider of the given query is being constructed.
33 * Beware of infinite loops.
34 * <p> <b>Postcondition:</b> {@link IQueryBackend#isCaching()} returns true for the {@link #getQueryBackend()} of the returned provider
35 *
36 * @throws ViatraQueryRuntimeException
37 */
38 public IQueryResultProvider getCachingResultProvider(PQuery query);
39}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryMetaContext.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryMetaContext.java
new file mode 100644
index 00000000..4c22a3cb
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryMetaContext.java
@@ -0,0 +1,98 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11import java.util.Collection;
12import java.util.Comparator;
13import java.util.Map;
14import java.util.Set;
15
16/**
17 * Provides metamodel information (relationship of input keys) to query evaluator backends at runtime and at query planning time.
18 *
19 * @noimplement Implementors should extend {@link AbstractQueryMetaContext} instead of directly implementing this interface.
20 * @author Bergmann Gabor
21 */
22public interface IQueryMetaContext {
23
24 /**
25 * Returns true iff instance tuples of the given key can be enumerated.
26 * <p> If false, the runtime can only test tuple membership in the extensional relation identified by the key, but not enumerate member tuples in general.
27 * <p> Equivalent to {@link IInputKey#isEnumerable()}.
28 */
29 boolean isEnumerable(IInputKey key);
30
31 /**
32 * Returns true iff the set of instance tuples of the given key is immutable.
33 * <p> If false, the runtime provides notifications upon change.
34 */
35 boolean isStateless(IInputKey key);
36
37 /**
38 * Returns a set of implications (weakened alternatives),
39 * with a suggestion for the query planner that satisfying them first may help in satisfying the implying key.
40 * <p> Note that for the obvious reasons, enumerable keys can only be implied by enumerable keys.
41 * <p> Must follow directly or transitively from implications of {@link #getImplications(IInputKey)}.
42 * @since 1.6
43 */
44 Collection<InputKeyImplication> getWeakenedAlternatives(IInputKey implyingKey);
45
46 /**
47 * Returns known direct implications, e.g. edge supertypes, edge opposites, node type constraints, etc.
48 * <p> Note that for the obvious reasons, enumerable keys can only be implied by enumerable keys.
49 */
50 Collection<InputKeyImplication> getImplications(IInputKey implyingKey);
51
52 /**
53 * Returns known "double dispatch" implications, where the given implying key implies other input keys under certain additional conditions (themselves input keys).
54 * For example, a "type x, unscoped" input key may imply the "type x, in scope" input key under the condition of the input key "x is in scope"
55 *
56 * <p> Note that for the obvious reasons, enumerable keys can only be implied by enumerable keys (either as the implying key or as the additional condition).
57 * <p> Note that symmetry is not required, i.e. the additional conditions do not have to list the same conditional implication.
58 * @return multi-map, where the keys are additional conditions and the values are input key implications jointly implied by the condition and the given implying key.
59 * @since 2.0
60 */
61 Map<InputKeyImplication, Set<InputKeyImplication>> getConditionalImplications(IInputKey implyingKey);
62
63 /**
64 * Returns functional dependencies of the input key expressed in terms of column indices.
65 *
66 * <p> Each entry of the map is a functional dependency rule, where the entry key specifies source columns and the entry value specifies target columns.
67 */
68 Map<Set<Integer>, Set<Integer>> getFunctionalDependencies(IInputKey key);
69
70 /**
71 * For query normalizing, this is the order suggested for trying to eliminate input keys.
72 * @since 1.6
73 */
74 Comparator<IInputKey> getSuggestedEliminationOrdering();
75
76 /**
77 * Tells whether the given {@link IInputKey} is an edge and may lead out of scope.
78 *
79 * @since 1.6
80 */
81 boolean canLeadOutOfScope(IInputKey key);
82
83 /**
84 * Returns true if the given {@link IInputKey} represents a poset type.
85 * @since 1.6
86 */
87 boolean isPosetKey(IInputKey key);
88
89 /**
90 * Returns an {@link IPosetComparator} for the given set of {@link IInputKey}s.
91 *
92 * @param keys an iterable collection of input keys
93 * @return the poset comparator
94 * @since 1.6
95 */
96 IPosetComparator getPosetComparator(Iterable<IInputKey> keys);
97
98}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryResultProviderAccess.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryResultProviderAccess.java
new file mode 100644
index 00000000..7fecd01a
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryResultProviderAccess.java
@@ -0,0 +1,31 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
12import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
13import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
14
15/**
16 * This interface exposes API to request {@link IQueryResultProvider} for {@link PQuery} instances.
17 *
18 * @author Grill Balázs
19 * @since 1.5
20 * @noimplement This interface is not intended to be implemented by clients.
21 */
22public interface IQueryResultProviderAccess {
23
24 /**
25 * Get a result provider for the given {@link PQuery}, which conforms the capabilities requested by the
26 * given {@link QueryEvaluationHint} object.
27 * @throws ViatraQueryRuntimeException
28 */
29 public IQueryResultProvider getResultProvider(PQuery query, QueryEvaluationHint overrideHints);
30
31}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContext.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContext.java
new file mode 100644
index 00000000..c2e90614
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContext.java
@@ -0,0 +1,281 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11import java.lang.reflect.InvocationTargetException;
12import java.util.Optional;
13import java.util.concurrent.Callable;
14
15import tools.refinery.viatra.runtime.matchers.planning.helpers.StatisticsHelper;
16import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
17import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
18import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
19import tools.refinery.viatra.runtime.matchers.util.Accuracy;
20
21/**
22 * Provides instance model information (relations corresponding to input keys) to query evaluator backends at runtime.
23 * Implementors shall extend {@link AbstractQueryRuntimeContext} instead directly this interface.
24 *
25 * @author Bergmann Gabor
26 * @noimplement This interface is not intended to be implemented by clients. Extend {@link AbstractQueryRuntimeContext} instead.
27 */
28public interface IQueryRuntimeContext {
29 /**
30 * Provides metamodel-specific info independent of the runtime instance model.
31 */
32 public IQueryMetaContext getMetaContext();
33
34
35 /**
36 * The given callable will be executed, and all model traversals will be delayed until the execution is done. If
37 * there are any outstanding information to be read from the model, a single coalesced model traversal will
38 * initialize the caches and deliver the notifications.
39 *
40 * <p> Calls may be nested. A single coalesced traversal will happen at the end of the outermost call.
41 *
42 * <p> <b>Caution: </b> results returned by the runtime context may be incomplete during the coalescing period, to be corrected by notifications sent during the final coalesced traversal.
43 * For example, if a certain input key is not cached yet, an empty relation may be reported during <code>callable.call()</code>; the cache will be constructed after the call terminates and notifications will deliver the entire content of the relation.
44 * Non-incremental query backends should therefore never enumerate input keys while coalesced (verify using {@link #isCoalescing()}).
45 *
46 * @param callable
47 */
48 public abstract <V> V coalesceTraversals(Callable<V> callable) throws InvocationTargetException;
49 /**
50 * @return true iff currently within a coalescing section (i.e. within the callable of a call to {@link #coalesceTraversals(Callable)}).
51 */
52 public boolean isCoalescing();
53
54 /**
55 * Returns true if index is available for the given key providing the given service.
56 * @throws IllegalArgumentException if key is not enumerable or an unknown type, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
57 * @since 1.4
58 */
59 public boolean isIndexed(IInputKey key, IndexingService service);
60
61 /**
62 * If the given (enumerable) input key is not yet indexed, the model will be traversed
63 * (after the end of the outermost coalescing block, see {@link IQueryRuntimeContext#coalesceTraversals(Callable)})
64 * so that the index can be built. It is possible that the base indexer will select a higher indexing level merging
65 * multiple indexing requests to an appropriate level.
66 *
67 * <p><b>Postcondition:</b> After invoking this method, {@link #getIndexed(IInputKey, IndexingService)} for the same key
68 * and service will be guaranteed to return the requested or a highing indexing level as soon as {@link #isCoalescing()} first returns false.
69 *
70 * <p><b>Precondition:</b> the given key is enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
71 * @throws IllegalArgumentException if key is not enumerable or an unknown type, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
72 * @since 1.4
73 */
74 public void ensureIndexed(IInputKey key, IndexingService service);
75
76 /**
77 * Returns the number of tuples in the extensional relation identified by the input key seeded with the given mask and tuple.
78 *
79 * @param key an input key
80 * @param seedMask
81 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
82 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most once in seedMask.
83 * @param seed
84 * the tuple of fixed values restricting the match set to be considered, in the same order as given in
85 * parameterSeedMask, so that for each considered match tuple,
86 * projectedParameterSeed.equals(parameterSeedMask.transform(match)) should hold. Must not be null.
87 *
88 * @return the number of tuples in the model for the given key and seed
89 *
90 * <p><b>Precondition:</b> the given key is enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
91 * @throws IllegalArgumentException if key is not enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
92 * @since 1.7
93 */
94 public int countTuples(IInputKey key, TupleMask seedMask, ITuple seed);
95
96
97 /**
98 * Gives an estimate of the number of different groups the tuples of the given relation are projected into by the given mask
99 * (e.g. for an identity mask, this means the full relation size). The estimate must meet the required accuracy.
100 *
101 * <p> Must accept any input key, even non-enumerables or those not recognized by this runtime context.
102 * If there is insufficient information to provide an answer up to the required precision, {@link Optional#empty()} is returned.
103 *
104 * <p> PRE: {@link TupleMask#isNonrepeating()} must hold for the group mask.
105 *
106 * @return if available, an estimate of the cardinality of the projection of the given extensional relation, with the desired accuracy.
107 *
108 * @since 2.1
109 */
110 public Optional<Long> estimateCardinality(IInputKey key, TupleMask groupMask, Accuracy requiredAccuracy);
111
112
113 /**
114 * Gives an estimate of the average size of different groups the tuples of the given relation are projected into by the given mask
115 * (e.g. for an identity mask, this means 1, while for an empty mask, the result is the full relation size).
116 * The estimate must meet the required accuracy.
117 *
118 * <p> Must accept any input key, even non-enumerables or those not recognized by this runtime context.
119 * If there is insufficient information to provide an answer up to the required precision, {@link Optional#empty()} may be returned.
120 *
121 * <p> For an empty relation, zero is acceptable as an exact answer.
122 *
123 * <p> PRE: {@link TupleMask#isNonrepeating()} must hold for the group mask.
124 *
125 * @return if available, an estimate of the average size of each projection group of the given extensional relation, with the desired accuracy.
126 *
127 * @since 2.1
128 */
129 public default Optional<Double> estimateAverageBucketSize(IInputKey key, TupleMask groupMask, Accuracy requiredAccuracy) {
130 if (key.isEnumerable()) {
131 return StatisticsHelper.estimateAverageBucketSize(groupMask, requiredAccuracy,
132 (mask, accuracy) -> this.estimateCardinality(key, mask, accuracy));
133 } else return groupMask.isIdentity() ? Optional.of(1.0) : Optional.empty();
134 }
135
136
137 /**
138 * Returns the tuples in the extensional relation identified by the input key, optionally seeded with the given tuple.
139 *
140 * @param key an input key
141 * @param seedMask
142 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
143 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most once in seedMask.
144 * @param seed
145 * the tuple of fixed values restricting the match set to be considered, in the same order as given in
146 * parameterSeedMask, so that for each considered match tuple,
147 * projectedParameterSeed.equals(parameterSeedMask.transform(match)) should hold. Must not be null.
148 * @return the tuples in the model for the given key and seed
149 *
150 * <p><b>Precondition:</b> the given key is enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
151 * @throws IllegalArgumentException if key is not enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
152 * @since 1.7
153 */
154 public Iterable<Tuple> enumerateTuples(IInputKey key, TupleMask seedMask, ITuple seed);
155
156 /**
157 * Simpler form of {@link #enumerateTuples(IInputKey, TupleMask, Tuple)} in the case where all values of the tuples
158 * are bound by the seed except for one.
159 *
160 * <p>
161 * Selects the tuples in the extensional relation identified by the input key, optionally seeded with the given
162 * tuple, and then returns the single value from each tuple which is not bound by the ssed mask.
163 *
164 * @param key
165 * an input key
166 * @param seedMask
167 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
168 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most
169 * once in seedMask, and seedMask must include all parameters in any arbitrary order except one.
170 * @param seed
171 * the tuple of fixed values restricting the match set to be considered, in the same order as given in
172 * parameterSeedMask, so that for each considered match tuple,
173 * projectedParameterSeed.equals(parameterSeedMask.transform(match)) should hold. Must not be null.
174 * @return the objects in the model for the given key and seed
175 *
176 * <p>
177 * <b>Precondition:</b> the given key is enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
178 * @throws IllegalArgumentException
179 * if key is not enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
180 * @since 1.7
181 */
182 public Iterable<? extends Object> enumerateValues(IInputKey key, TupleMask seedMask, ITuple seed);
183
184 /**
185 * Simpler form of {@link #enumerateTuples(IInputKey, TupleMask, Tuple)} in the case where all values of the tuples
186 * are bound by the seed.
187 *
188 * <p>
189 * Returns whether the given tuple is in the extensional relation identified by the input key.
190 *
191 * <p>
192 * Note: this call works for non-enumerable input keys as well.
193 *
194 * @param key
195 * an input key
196 * @param seed
197 * the tuple of fixed values restricting the match set to be considered, in the same order as given in
198 * parameterSeedMask, so that for each considered match tuple,
199 * projectedParameterSeed.equals(parameterSeedMask.transform(match)) should hold. Must not be null.
200 * @return true iff there is at least a single tuple contained in the relation that corresponds to the seed tuple
201 * @since 2.0
202 */
203 public boolean containsTuple(IInputKey key, ITuple seed);
204
205
206 /**
207 * Subscribes for updates in the extensional relation identified by the input key, optionally seeded with the given tuple.
208 * <p> This should be called after invoking
209 *
210 * @param key an input key
211 * @param seed can be null or a tuple with matching arity;
212 * if non-null, only those updates in the model are notified about
213 * that match the seed at positions where the seed is non-null.
214 * @param listener will be notified of future changes
215 *
216 * <p><b>Precondition:</b> the given key is enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
217 * @throws IllegalArgumentException if key is not enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
218 */
219 public void addUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener);
220
221 /**
222 * Unsubscribes from updates in the extensional relation identified by the input key, optionally seeded with the given tuple.
223 *
224 * @param key an input key
225 * @param seed can be null or a tuple with matching arity;
226 * if non-null, only those updates in the model are notified about
227 * that match the seed at positions where the seed is non-null.
228 * @param listener will no longer be notified of future changes
229 *
230 * <p><b>Precondition:</b> the given key is enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
231 * @throws IllegalArgumentException if key is not enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
232 */
233 public void removeUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener);
234 /*
235 TODO: uniqueness
236 */
237
238 /**
239 * Wraps the external element into the internal representation that is to be used by the query backend
240 * <p> model element -> internal object.
241 * <p> null must be mapped to null.
242 */
243 public Object wrapElement(Object externalElement);
244
245 /**
246 * Unwraps the internal representation of the element into its original form
247 * <p> internal object -> model element
248 * <p> null must be mapped to null.
249 */
250 public Object unwrapElement(Object internalElement);
251
252 /**
253 * Unwraps the tuple of elements into the internal representation that is to be used by the query backend
254 * <p> model elements -> internal objects
255 * <p> null must be mapped to null.
256 */
257 public Tuple wrapTuple(Tuple externalElements);
258
259 /**
260 * Unwraps the tuple of internal representations of elements into their original forms
261 * <p> internal objects -> model elements
262 * <p> null must be mapped to null.
263 */
264 public Tuple unwrapTuple(Tuple internalElements);
265
266 /**
267 * Starts wildcard indexing for the given service. After this call, no registration is required for this {@link IndexingService}.
268 * a previously set wildcard level cannot be lowered, only extended.
269 * @since 1.4
270 */
271 public void ensureWildcardIndexing(IndexingService service);
272
273 /**
274 * Execute the given runnable after traversal. It is guaranteed that the runnable is executed as soon as
275 * the indexing is finished. The callback is executed only once, then is removed from the callback queue.
276 * @param traversalCallback
277 * @throws InvocationTargetException
278 * @since 1.4
279 */
280 public void executeAfterTraversal(Runnable runnable) throws InvocationTargetException;
281}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContextListener.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContextListener.java
new file mode 100644
index 00000000..7be27d56
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContextListener.java
@@ -0,0 +1,27 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
12
13/**
14 * Listens for changes in the runtime context.
15 * @author Bergmann Gabor
16 *
17 */
18public interface IQueryRuntimeContextListener {
19
20 /**
21 * The given tuple was inserted into or removed from the input relation indicated by the given key.
22 * @param key the key identifying the input relation that was updated
23 * @param updateTuple the tuple that was inserted or removed
24 * @param isInsertion true if it was an insertion, false otherwise.
25 */
26 public void update(IInputKey key, Tuple updateTuple, boolean isInsertion);
27}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IndexingService.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IndexingService.java
new file mode 100644
index 00000000..8210765d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IndexingService.java
@@ -0,0 +1,36 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11/**
12 * These are the different services which can be provided by an {@link IQueryRuntimeContext} implementation.
13 *
14 * @author Grill Balázs
15 * @since 1.4
16 *
17 */
18public enum IndexingService {
19
20 /**
21 * Cardinality information is available. Makes possible to calculate
22 * unseeded calls of {@link IQueryRuntimeContext#countTuples(IInputKey, tools.refinery.viatra.runtime.matchers.tuple.Tuple)}
23 */
24 STATISTICS,
25
26 /**
27 * The indexer can provide notifications about changes in the model.
28 */
29 NOTIFICATIONS,
30
31 /**
32 * Enables enumeration of instances and reverse-navigation.
33 */
34 INSTANCES
35
36}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/InputKeyImplication.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/InputKeyImplication.java
new file mode 100644
index 00000000..2a403810
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/InputKeyImplication.java
@@ -0,0 +1,103 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11import java.util.ArrayList;
12import java.util.Collections;
13import java.util.List;
14
15/**
16 * Data object representing the implication of an input key, in use cases including edge supertypes, edge opposites, node type constraints, etc.
17 *
18 * <p> Each instance tuple of the <i>implying input key</i> (if given) implies the presence of an instance tuple of the <i>implied input key</i> consisting of elements of the original tuple at given positions.
19 * When the input key is null, it is not an input constraint but some other source that implies input keys.
20 *
21 * <p> The implication is an immutable data object.
22 *
23 * @author Bergmann Gabor
24 *
25 */
26public final class InputKeyImplication {
27 private IInputKey implyingKey;
28 private IInputKey impliedKey;
29 private List<Integer> impliedIndices;
30
31 /**
32 * Optional. Instance tuples of this input key imply an instance tuple of another key.
33 * Sometimes it is not an input key that implies other input keys, so this attribute can be null.
34 */
35 public IInputKey getImplyingKey() {
36 return implyingKey;
37 }
38 /**
39 * An instance tuple of this input key is implied by another key.
40 */
41 public IInputKey getImpliedKey() {
42 return impliedKey;
43 }
44 /**
45 * The implied instance tuple consists of the values in the implying tuple at these indices.
46 */
47 public List<Integer> getImpliedIndices() {
48 return impliedIndices;
49 }
50 /**
51 * @param implyingKey instance tuples of this input key imply an instance tuple of the other key.
52 * @param impliedKey instance tuple of this input key is implied by the other key.
53 * @param implyingIndices the implied instance tuple consists of the values in the implying tuple at these indices.
54 */
55 public InputKeyImplication(IInputKey implyingKey, IInputKey impliedKey,
56 List<Integer> implyingIndices) {
57 super();
58 this.implyingKey = implyingKey;
59 this.impliedKey = impliedKey;
60 this.impliedIndices = Collections.unmodifiableList(new ArrayList<>(implyingIndices));
61 }
62
63 @Override
64 public int hashCode() {
65 final int prime = 31;
66 int result = 1;
67 result = prime * result
68 + ((impliedIndices == null) ? 0 : impliedIndices.hashCode());
69 result = prime * result
70 + ((impliedKey == null) ? 0 : impliedKey.hashCode());
71 result = prime * result
72 + ((implyingKey == null) ? 0 : implyingKey.hashCode());
73 return result;
74 }
75 @Override
76 public boolean equals(Object obj) {
77 if (this == obj)
78 return true;
79 if (obj == null)
80 return false;
81 if (!(obj instanceof InputKeyImplication))
82 return false;
83 InputKeyImplication other = (InputKeyImplication) obj;
84 if (impliedIndices == null) {
85 if (other.impliedIndices != null)
86 return false;
87 } else if (!impliedIndices.equals(other.impliedIndices))
88 return false;
89 if (impliedKey == null) {
90 if (other.impliedKey != null)
91 return false;
92 } else if (!impliedKey.equals(other.impliedKey))
93 return false;
94 if (implyingKey == null) {
95 if (other.implyingKey != null)
96 return false;
97 } else if (!implyingKey.equals(other.implyingKey))
98 return false;
99 return true;
100 }
101
102
103}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/BaseInputKeyWrapper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/BaseInputKeyWrapper.java
new file mode 100644
index 00000000..f9b05e5b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/BaseInputKeyWrapper.java
@@ -0,0 +1,55 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context.common;
10
11import tools.refinery.viatra.runtime.matchers.context.IInputKey;
12
13
14/**
15 * An input key that is identified by a single wrapped object and the class of the wrapper.
16 * @author Bergmann Gabor
17 *
18 */
19public abstract class BaseInputKeyWrapper<Wrapped> implements IInputKey {
20 protected Wrapped wrappedKey;
21
22 public BaseInputKeyWrapper(Wrapped wrappedKey) {
23 super();
24 this.wrappedKey = wrappedKey;
25 }
26
27 public Wrapped getWrappedKey() {
28 return wrappedKey;
29 }
30
31
32 @Override
33 public int hashCode() {
34 return ((wrappedKey == null) ? 0 : wrappedKey.hashCode());
35 }
36
37 @Override
38 public boolean equals(Object obj) {
39 if (this == obj)
40 return true;
41 if (obj == null)
42 return false;
43 if (!(this.getClass().equals(obj.getClass())))
44 return false;
45 BaseInputKeyWrapper other = (BaseInputKeyWrapper) obj;
46 if (wrappedKey == null) {
47 if (other.wrappedKey != null)
48 return false;
49 } else if (!wrappedKey.equals(other.wrappedKey))
50 return false;
51 return true;
52 }
53
54
55}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/JavaTransitiveInstancesKey.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/JavaTransitiveInstancesKey.java
new file mode 100644
index 00000000..eb972c2d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/JavaTransitiveInstancesKey.java
@@ -0,0 +1,165 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context.common;
10
11
12
13/**
14 * Instance tuples are of form (x), where object x is an instance of the given Java class or its subclasses.
15 * <p> Fine print 1: classes with the same name are considered equivalent.
16 * Can be instantiated with class name, even if the class itself is not loaded yet; but if the class is available, passing it in the constructor is beneficial to avoid classloading troubles.
17 * <p> Fine print 2: primitive types (char, etc.) are transparently treated as their wrapper class (Character, etc.).
18 * <p> Non-enumerable type, can only be checked.
19 * <p> Stateless type (objects can't change their type)
20 * @author Bergmann Gabor
21 *
22*/
23public class JavaTransitiveInstancesKey extends BaseInputKeyWrapper<String> {
24
25 /**
26 * The actual Class whose (transitive) instances this relation contains. Can be null at compile time, if only the name is available.
27 * Can be a primitive.
28 */
29 private Class<?> cachedOriginalInstanceClass;
30
31 /**
32 * Same as {@link #cachedOriginalInstanceClass}, but primitive classes are replaced with their wrapper classes (e.g. int --> java.lang.Integer).
33 */
34 private Class<?> cachedWrapperInstanceClass;
35
36 /**
37 * Preferred constructor.
38 */
39 public JavaTransitiveInstancesKey(Class<?> instanceClass) {
40 this(primitiveTypeToWrapperClass(instanceClass).getName());
41 this.cachedOriginalInstanceClass = instanceClass;
42 }
43
44 /**
45 * Call this constructor only in contexts where the class itself is not available for loading, e.g. it has not yet been compiled.
46 */
47 public JavaTransitiveInstancesKey(String className) {
48 super(className);
49 }
50
51
52 /**
53 * Returns null if class cannot be loaded.
54 */
55 private Class<?> getOriginalInstanceClass() {
56 if (cachedOriginalInstanceClass == null) {
57 try {
58 resolveClassInternal();
59 } catch (ClassNotFoundException e) {
60 // class not yet available at this point
61 }
62 }
63 return cachedOriginalInstanceClass;
64 }
65
66
67 /**
68 * @return non-null instance class
69 * @throws ClassNotFoundException
70 */
71 private Class<?> forceGetOriginalInstanceClass() throws ClassNotFoundException {
72 if (cachedOriginalInstanceClass == null) {
73 resolveClassInternal();
74 }
75 return cachedOriginalInstanceClass;
76 }
77
78 /**
79 * @return non-null instance class, wrapped if primitive class
80 * @throws ClassNotFoundException
81 */
82 public Class<?> forceGetWrapperInstanceClass() throws ClassNotFoundException {
83 forceGetOriginalInstanceClass();
84 return getWrapperInstanceClass();
85 }
86 /**
87 * @return non-null instance class, wrapped if primitive class
88 * @throws ClassNotFoundException
89 */
90 public Class<?> forceGetInstanceClass() throws ClassNotFoundException {
91 return forceGetWrapperInstanceClass();
92 }
93
94 /**
95 * @return instance class, wrapped if primitive class, null if class cannot be loaded
96 */
97 public Class<?> getWrapperInstanceClass() {
98 if (cachedWrapperInstanceClass == null) {
99 cachedWrapperInstanceClass = primitiveTypeToWrapperClass(getOriginalInstanceClass());
100 }
101 return cachedWrapperInstanceClass;
102 }
103 /**
104 * @return instance class, wrapped if primitive class, null if class cannot be loaded
105 */
106 public Class<?> getInstanceClass() {
107 return getWrapperInstanceClass();
108 }
109
110 private void resolveClassInternal() throws ClassNotFoundException {
111 cachedOriginalInstanceClass = Class.forName(wrappedKey);
112 }
113
114 @Override
115 public String getPrettyPrintableName() {
116 getWrapperInstanceClass();
117 return cachedWrapperInstanceClass == null ? wrappedKey == null ? "<null>" : wrappedKey : cachedWrapperInstanceClass.getName();
118 }
119
120 @Override
121 public String getStringID() {
122 return "javaClass#"+ getPrettyPrintableName();
123 }
124
125 @Override
126 public int getArity() {
127 return 1;
128 }
129
130 @Override
131 public boolean isEnumerable() {
132 return false;
133 }
134
135 @Override
136 public String toString() {
137 return this.getPrettyPrintableName();
138 }
139
140 private static Class<?> primitiveTypeToWrapperClass(Class<?> instanceClass) {
141 if (instanceClass != null && instanceClass.isPrimitive()) {
142 if (Void.TYPE.equals(instanceClass))
143 return Void.class;
144 if (Boolean.TYPE.equals(instanceClass))
145 return Boolean.class;
146 if (Character.TYPE.equals(instanceClass))
147 return Character.class;
148 if (Byte.TYPE.equals(instanceClass))
149 return Byte.class;
150 if (Short.TYPE.equals(instanceClass))
151 return Short.class;
152 if (Integer.TYPE.equals(instanceClass))
153 return Integer.class;
154 if (Long.TYPE.equals(instanceClass))
155 return Long.class;
156 if (Float.TYPE.equals(instanceClass))
157 return Float.class;
158 if (Double.TYPE.equals(instanceClass))
159 return Double.class;
160 }
161 return instanceClass;
162 }
163
164
165}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/surrogate/SurrogateQueryRegistry.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/surrogate/SurrogateQueryRegistry.java
new file mode 100644
index 00000000..bb24ec8c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/surrogate/SurrogateQueryRegistry.java
@@ -0,0 +1,153 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Abel Hegedus, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context.surrogate;
10
11import java.util.Collections;
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.Map;
15import java.util.NoSuchElementException;
16import java.util.Set;
17
18import tools.refinery.viatra.runtime.matchers.context.IInputKey;
19import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
20import tools.refinery.viatra.runtime.matchers.util.IProvider;
21import tools.refinery.viatra.runtime.matchers.util.Preconditions;
22import tools.refinery.viatra.runtime.matchers.util.SingletonInstanceProvider;
23
24/**
25 * @author Abel Hegedus
26 *
27 */
28public class SurrogateQueryRegistry {
29
30 private Map<IInputKey, IProvider<PQuery>> registeredSurrogateQueryMap = new HashMap<>();
31 private Map<IInputKey, IProvider<PQuery>> dynamicSurrogateQueryMap = new HashMap<>();
32
33 /**
34 * Hidden constructor
35 */
36 private SurrogateQueryRegistry() {
37 }
38
39 private static final SurrogateQueryRegistry INSTANCE = new SurrogateQueryRegistry();
40
41 public static SurrogateQueryRegistry instance() {
42 return INSTANCE;
43 }
44
45 /**
46 *
47 * @param feature
48 * @param surrogateQuery
49 * @return the previous surrogate query associated with feature, or null if there was no such query FQN registered
50 * @throws IllegalArgumentException if feature or surrogateQuery is null
51 */
52 public IProvider<PQuery> registerSurrogateQueryForFeature(IInputKey feature, PQuery surrogateQuery) {
53 Preconditions.checkArgument(surrogateQuery != null, "Surrogate query must not be null!");
54 return registerSurrogateQueryForFeature(feature, new SingletonInstanceProvider<PQuery>(surrogateQuery));
55 }
56
57 /**
58 *
59 * @param feature
60 * @param surrogateQuery
61 * @return the previous surrogate query associated with feature, or null
62 * if there was no such query registered
63 * @throws IllegalArgumentException
64 * if feature or surrogateQuery is null
65 */
66 public IProvider<PQuery> registerSurrogateQueryForFeature(IInputKey feature, IProvider<PQuery> surrogateQueryProvider) {
67 Preconditions.checkArgument(feature != null, "Feature must not be null!");
68 Preconditions.checkArgument(surrogateQueryProvider != null, "Surrogate query must not be null!");
69 return registeredSurrogateQueryMap.put(feature, surrogateQueryProvider);
70 }
71
72 public IProvider<PQuery> addDynamicSurrogateQueryForFeature(IInputKey feature, PQuery surrogateQuery) {
73 Preconditions.checkArgument(surrogateQuery != null, "Surrogate query FQN must not be null!");
74 return addDynamicSurrogateQueryForFeature(feature, new SingletonInstanceProvider<PQuery>(surrogateQuery));
75 }
76
77 public IProvider<PQuery> addDynamicSurrogateQueryForFeature(IInputKey feature, IProvider<PQuery> surrogateQuery) {
78 Preconditions.checkArgument(feature != null, "Feature must not be null!");
79 Preconditions.checkArgument(surrogateQuery != null, "Surrogate query FQN must not be null!");
80 return dynamicSurrogateQueryMap.put(feature, surrogateQuery);
81 }
82
83 public IProvider<PQuery> removeDynamicSurrogateQueryForFeature(IInputKey feature) {
84 Preconditions.checkArgument(feature != null, "Feature must not be null!");
85 return dynamicSurrogateQueryMap.remove(feature);
86 }
87
88 /**
89 *
90 * @param feature that may have surrogate query defined, null not allowed
91 * @return true if the feature has a surrogate query defined
92 * @throws IllegalArgumentException if feature is null
93 */
94 public boolean hasSurrogateQueryFQN(IInputKey feature) {
95 Preconditions.checkArgument(feature != null, "Feature must not be null!");
96 boolean surrogateExists = dynamicSurrogateQueryMap.containsKey(feature);
97 if(!surrogateExists){
98 surrogateExists = registeredSurrogateQueryMap.containsKey(feature);
99 }
100 return surrogateExists;
101 }
102
103 /**
104 *
105 * @param feature for which the surrogate query FQN should be returned
106 * @return the surrogate query FQN defined for the feature
107 * @throws IllegalArgumentException if feature is null
108 * @throws NoSuchElementException if the feature has no surrogate query defined, use {@link #hasSurrogateQueryFQN} to check
109 */
110 public PQuery getSurrogateQuery(IInputKey feature) {
111 Preconditions.checkArgument(feature != null, "Feature must not be null!");
112 IProvider<PQuery> surrogate = dynamicSurrogateQueryMap.get(feature);
113 if(surrogate == null) {
114 surrogate = registeredSurrogateQueryMap.get(feature);
115 }
116 if(surrogate != null) {
117 return surrogate.get();
118 } else {
119 throw new NoSuchElementException(String.format("Feature %s has no surrogate query defined! Use #hasSurrogateQueryFQN to check existence.", feature));
120 }
121 }
122
123 /**
124 * @return an unmodifiable set of features with registered surrogate queries
125 */
126 public Set<IInputKey> getRegisteredSurrogateQueries() {
127 return Collections.unmodifiableSet(getRegisteredSurrogateQueriesInternal());
128 }
129
130 private Set<IInputKey> getRegisteredSurrogateQueriesInternal() {
131 return registeredSurrogateQueryMap.keySet();
132 }
133
134 /**
135 * @return an unmodifiable set of features with dynamically added surrogate queries
136 */
137 public Set<IInputKey> getDynamicSurrogateQueries() {
138 return Collections.unmodifiableSet(getDynamicSurrogateQueriesInternal());
139 }
140
141 private Set<IInputKey> getDynamicSurrogateQueriesInternal() {
142 return dynamicSurrogateQueryMap.keySet();
143 }
144
145 /**
146 * @return an unmodifiable set that contains all features with surrogate queries.
147 */
148 public Set<IInputKey> getAllSurrogateQueries() {
149 Set<IInputKey> results = new HashSet<>(getRegisteredSurrogateQueriesInternal());
150 results.addAll(getDynamicSurrogateQueriesInternal());
151 return results;
152 }
153}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/AbstractTrivialMaskedMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/AbstractTrivialMaskedMemory.java
new file mode 100644
index 00000000..66587f77
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/AbstractTrivialMaskedMemory.java
@@ -0,0 +1,58 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories;
10
11import java.util.Iterator;
12import java.util.Map;
13
14import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
15import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
16import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
17import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
18import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
19import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
20import tools.refinery.viatra.runtime.matchers.util.IMemory;
21
22/**
23 * Common parts of nullary and identity specializations.
24 *
25 * @noextend This class is not intended to be subclassed by clients.
26 * @author Gabor Bergmann
27 * @since 2.0
28 */
29abstract class AbstractTrivialMaskedMemory<Timestamp extends Comparable<Timestamp>> extends MaskedTupleMemory<Timestamp> {
30
31 protected IMemory<Tuple> tuples;
32
33 protected AbstractTrivialMaskedMemory(TupleMask mask, MemoryType bucketType, Object owner) {
34 super(mask, owner);
35 tuples = CollectionsFactory.createMemory(Object.class, bucketType);
36 }
37
38 @Override
39 public Map<Tuple, Timeline<Timestamp>> getWithTimeline(ITuple signature) {
40 throw new UnsupportedOperationException("Timeless memories do not support timestamp-based lookup!");
41 }
42
43 @Override
44 public void clear() {
45 tuples.clear();
46 }
47
48 @Override
49 public int getTotalSize() {
50 return tuples.size();
51 }
52
53 @Override
54 public Iterator<Tuple> iterator() {
55 return tuples.iterator();
56 }
57
58}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/DefaultMaskedTupleMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/DefaultMaskedTupleMemory.java
new file mode 100644
index 00000000..92081409
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/DefaultMaskedTupleMemory.java
@@ -0,0 +1,127 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.memories;
11
12import java.util.Collection;
13import java.util.Iterator;
14import java.util.Map;
15
16import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
17import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
18import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
19import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
20import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
21import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
22import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
23import tools.refinery.viatra.runtime.matchers.util.IMultiLookup.ChangeGranularity;
24import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
25
26/**
27 * @author Gabor Bergmann
28 *
29 * Default implementation that covers all cases.
30 *
31 * @since 2.0
32 */
33public final class DefaultMaskedTupleMemory<Timestamp extends Comparable<Timestamp>>
34 extends MaskedTupleMemory<Timestamp> {
35 /**
36 * Maps a signature tuple to the bucket of tuples with the given signature.
37 *
38 * @since 2.0
39 */
40 protected IMultiLookup<Tuple, Tuple> signatureToTuples;
41
42 /**
43 * @param mask
44 * The mask used to index the matchings
45 * @param owner
46 * the object "owning" this memory
47 * @param bucketType
48 * the kind of tuple collection maintained for each indexer bucket
49 * @since 2.0
50 */
51 public DefaultMaskedTupleMemory(TupleMask mask, MemoryType bucketType, Object owner) {
52 super(mask, owner);
53 signatureToTuples = CollectionsFactory.<Tuple, Tuple> createMultiLookup(Object.class, bucketType, Object.class);
54 }
55
56 @Override
57 public boolean add(Tuple tuple) {
58 Tuple signature = mask.transform(tuple);
59 return add(tuple, signature);
60 }
61
62 @Override
63 public boolean add(Tuple tuple, Tuple signature) {
64 try {
65 return signatureToTuples.addPair(signature, tuple) == ChangeGranularity.KEY;
66 } catch (IllegalStateException ex) { // ignore worthless internal exception details
67 throw raiseDuplicateInsertion(tuple);
68 }
69
70 }
71
72 @Override
73 public boolean remove(Tuple tuple) {
74 Tuple signature = mask.transform(tuple);
75 return remove(tuple, signature);
76 }
77
78 @Override
79 public boolean remove(Tuple tuple, Tuple signature) {
80 try {
81 return signatureToTuples.removePair(signature, tuple) == ChangeGranularity.KEY;
82 } catch (IllegalStateException ex) { // ignore worthless internal exception details
83 throw raiseDuplicateDeletion(tuple);
84 }
85 }
86
87 @Override
88 public Map<Tuple, Timeline<Timestamp>> getWithTimeline(ITuple signature) {
89 throw new UnsupportedOperationException("Timeless memories do not support timestamp-based lookup!");
90 }
91
92 @Override
93 public Collection<Tuple> get(ITuple signature) {
94 IMemoryView<Tuple> bucket = signatureToTuples.lookupUnsafe(signature);
95 return bucket == null ? null : bucket.distinctValues();
96 }
97
98 @Override
99 public void clear() {
100 signatureToTuples.clear();
101 }
102
103 @Override
104 public Iterable<Tuple> getSignatures() {
105 return signatureToTuples.distinctKeys();
106 }
107
108 @Override
109 public Iterator<Tuple> iterator() {
110 return signatureToTuples.distinctValues().iterator();
111 }
112
113 @Override
114 public int getTotalSize() {
115 int i = 0;
116 for (Tuple key : signatureToTuples.distinctKeys()) {
117 i += signatureToTuples.lookup(key).size();
118 }
119 return i;
120 }
121
122 @Override
123 public int getKeysetSize() {
124 return signatureToTuples.countKeys();
125 }
126
127}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/IdentityMaskedTupleMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/IdentityMaskedTupleMemory.java
new file mode 100644
index 00000000..dc59daf5
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/IdentityMaskedTupleMemory.java
@@ -0,0 +1,77 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories;
10
11import java.util.Collection;
12import java.util.Collections;
13
14import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
15import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
16import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
17import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
18
19/**
20 * Specialized for identity mask; tuples are stored as a simple set/multiset memory.
21 *
22 * @author Gabor Bergmann
23 * @since 2.0
24 */
25public final class IdentityMaskedTupleMemory<Timestamp extends Comparable<Timestamp>> extends AbstractTrivialMaskedMemory<Timestamp> {
26
27 /**
28 * @param mask
29 * The mask used to index the matchings
30 * @param owner the object "owning" this memory
31 * @param bucketType the kind of tuple collection maintained for each indexer bucket
32 * @since 2.0
33 */
34 public IdentityMaskedTupleMemory(TupleMask mask, MemoryType bucketType, Object owner) {
35 super(mask, bucketType, owner);
36 if (!mask.isIdentity()) throw new IllegalArgumentException(mask.toString());
37 }
38
39 @Override
40 public int getKeysetSize() {
41 return tuples.size();
42 }
43
44 @Override
45 public Iterable<Tuple> getSignatures() {
46 return tuples;
47 }
48
49 @Override
50 public Collection<Tuple> get(ITuple signature) {
51 Tuple contained = tuples.theContainedVersionOfUnsafe(signature);
52 return contained != null ?
53 Collections.singleton(contained) :
54 null;
55 }
56
57 @Override
58 public boolean remove(Tuple tuple, Tuple signature) {
59 return tuples.removeOne(tuple);
60 }
61
62 @Override
63 public boolean remove(Tuple tuple) {
64 return tuples.removeOne(tuple);
65 }
66
67 @Override
68 public boolean add(Tuple tuple, Tuple signature) {
69 return tuples.addOne(tuple);
70 }
71
72 @Override
73 public boolean add(Tuple tuple) {
74 return tuples.addOne(tuple);
75 }
76
77}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/MaskedTupleMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/MaskedTupleMemory.java
new file mode 100644
index 00000000..62377624
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/MaskedTupleMemory.java
@@ -0,0 +1,385 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.Iterator;
14import java.util.Map;
15
16import tools.refinery.viatra.runtime.matchers.memories.timely.TimelyDefaultMaskedTupleMemory;
17import tools.refinery.viatra.runtime.matchers.memories.timely.TimelyIdentityMaskedTupleMemory;
18import tools.refinery.viatra.runtime.matchers.memories.timely.TimelyNullaryMaskedTupleMemory;
19import tools.refinery.viatra.runtime.matchers.memories.timely.TimelyUnaryMaskedTupleMemory;
20import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
21import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
22import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
23import tools.refinery.viatra.runtime.matchers.util.Clearable;
24import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
25import tools.refinery.viatra.runtime.matchers.util.resumable.MaskedResumable;
26import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
27import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
28
29/**
30 * Indexes a collection of tuples by their signature (i.e. footprint, projection) obtained according to a mask. May
31 * belong to an "owner" (for documentation / traceability purposes).
32 * <p>
33 * There are timeless and timely versions of the different memories. Timely versions associate {@link Timeline}s with
34 * the stored tuples.
35 *
36 * @noextend This class is not intended to be subclassed by clients.
37 * @author Gabor Bergmann
38 * @author Tamas Szabo
39 * @since 2.0
40 */
41public abstract class MaskedTupleMemory<Timestamp extends Comparable<Timestamp>>
42 implements Clearable, MaskedResumable<Timestamp> {
43
44 /**
45 * Creates a new memory for the given owner that indexes tuples according to the given mask.
46 */
47 public static <T extends Comparable<T>> MaskedTupleMemory<T> create(final TupleMask mask,
48 final MemoryType bucketType, final Object owner) {
49 return create(mask, bucketType, owner, false);
50 }
51
52 /**
53 * Creates a new memory for the given owner that indexes tuples according to the given mask. Clients can specify if
54 * the created memory should be timely or not. <br>
55 * <br>
56 * Timely means that tuples are associated with a timeline.
57 *
58 * @since 2.3
59 */
60 public static <T extends Comparable<T>> MaskedTupleMemory<T> create(final TupleMask mask,
61 final MemoryType bucketType, final Object owner, final boolean isTimely) {
62 return create(mask, bucketType, owner, isTimely, false);
63 }
64
65 /**
66 * Creates a new memory for the given owner that indexes tuples according to the given mask. Clients can specify if
67 * the created memory should be timely or not. In case of timely memory, clients can also specify if the memory is
68 * lazy or not. <br>
69 * <br>
70 * Timely means that tuples are associated with a timeline. <br>
71 * <br>
72 * Lazyness can only be used together with timely memories. It means that the maintenance of the timelines is lazy,
73 * that is, the memory only updates its internal data structures at the timestamp affected by an update, and can be
74 * instructed later to resume the maintenance at higher timestamps, as well.
75 *
76 * @since 2.4
77 */
78 public static <T extends Comparable<T>> MaskedTupleMemory<T> create(final TupleMask mask,
79 final MemoryType bucketType, final Object owner, final boolean isTimely, final boolean isLazy) {
80 if (isTimely) {
81 if (bucketType != MemoryType.SETS) {
82 throw new IllegalArgumentException("Timely memories only support SETS as the bucket type!");
83 }
84 if (mask.isIdentity()) {
85 return new TimelyIdentityMaskedTupleMemory<T>(mask, owner, isLazy);
86 } else if (0 == mask.getSize()) {
87 return new TimelyNullaryMaskedTupleMemory<T>(mask, owner, isLazy);
88 } else if (1 == mask.getSize()) {
89 return new TimelyUnaryMaskedTupleMemory<T>(mask, owner, isLazy);
90 } else {
91 return new TimelyDefaultMaskedTupleMemory<T>(mask, owner, isLazy);
92 }
93 } else {
94 if (isLazy) {
95 throw new IllegalArgumentException("Lazy maintenance is only supported by timely memories!");
96 }
97 if (mask.isIdentity()) {
98 return new IdentityMaskedTupleMemory<T>(mask, bucketType, owner);
99 } else if (0 == mask.getSize()) {
100 return new NullaryMaskedTupleMemory<T>(mask, bucketType, owner);
101 } else if (1 == mask.getSize()) {
102 return new UnaryMaskedTupleMemory<T>(mask, bucketType, owner);
103 } else {
104 return new DefaultMaskedTupleMemory<T>(mask, bucketType, owner);
105 }
106 }
107 }
108
109 @Override
110 public Map<Tuple, Map<Tuple, Diff<Timestamp>>> resumeAt(final Timestamp timestamp) {
111 throw new UnsupportedOperationException("This is only supported by lazy timely memory implementations!");
112 }
113
114 @Override
115 public Iterable<Tuple> getResumableSignatures() {
116 throw new UnsupportedOperationException("This is only supported by lazy timely memory implementations!");
117 }
118
119 @Override
120 public Timestamp getResumableTimestamp() {
121 return null;
122 }
123
124 /**
125 * Initializes the contents of this memory based on the contents of another memory. The default value is associated
126 * with each tuple in the timely memories.
127 *
128 * @since 2.3
129 */
130 public void initializeWith(final MaskedTupleMemory<Timestamp> other, final Timestamp defaultValue) {
131 throw new UnsupportedOperationException("This is only supported by timely memory implementations!");
132 }
133
134 /**
135 * Returns true if there is any tuple with the given signature that is present at the timestamp +inf, false
136 * otherwise.
137 * @since 2.4
138 */
139 public boolean isPresentAtInfinity(final ITuple signature) {
140 return get(signature) != null;
141 }
142
143 /**
144 * Returns true of this memory is timely, false otherwise.
145 *
146 * @since 2.3
147 */
148 public boolean isTimely() {
149 return false;
150 }
151
152 /**
153 * The mask by which the tuples are indexed.
154 */
155 protected final TupleMask mask;
156
157 /**
158 * The object "owning" this memory. May be null.
159 *
160 * @since 1.7
161 */
162 protected final Object owner;
163
164 /**
165 * The node owning this memory. May be null.
166 *
167 * @since 2.0
168 */
169 public Object getOwner() {
170 return owner;
171 }
172
173 /**
174 * The mask according to which tuples are projected and indexed.
175 *
176 * @since 2.0
177 */
178 public TupleMask getMask() {
179 return mask;
180 }
181
182 /**
183 * @return the number of distinct signatures of all stored tuples.
184 */
185 public abstract int getKeysetSize();
186
187 /**
188 * @return the total number of distinct tuples stored. Multiple copies of the same tuple, if allowed, are counted as
189 * one.
190 *
191 * <p>
192 * This is currently not cached but computed on demand. It is therefore not efficient, and shall only be
193 * used for debug / profiling purposes.
194 */
195 public abstract int getTotalSize();
196
197 /**
198 * Iterates over distinct tuples stored in the memory, regardless of their signatures.
199 */
200 public abstract Iterator<Tuple> iterator();
201
202 /**
203 * Retrieves a read-only view of exactly those signatures for which at least one tuple is stored
204 *
205 * @since 2.0
206 */
207 public abstract Iterable<Tuple> getSignatures();
208
209 /**
210 * Retrieves tuples that have the specified signature
211 *
212 * @return collection of tuples found, null if none
213 */
214 public abstract Collection<Tuple> get(final ITuple signature);
215
216 /**
217 * Retrieves the tuples and their associated timelines that have the specified signature.
218 *
219 * @return the mappings from tuples to timelines, null if there is no mapping for the signature
220 * @since 2.4
221 */
222 public abstract Map<Tuple, Timeline<Timestamp>> getWithTimeline(final ITuple signature);
223
224 /**
225 * Retrieves tuples that have the specified signature.
226 *
227 * @return collection of tuples found, never null
228 * @since 2.1
229 */
230 public Collection<Tuple> getOrEmpty(final ITuple signature) {
231 final Collection<Tuple> result = get(signature);
232 return result == null ? Collections.emptySet() : result;
233 }
234
235 /**
236 * Retrieves tuples with their associated timelines that have the specified signature.
237 *
238 * @return map of tuples and timelines found, never null
239 * @since 2.4
240 */
241 public Map<Tuple, Timeline<Timestamp>> getOrEmptyWithTimeline(final ITuple signature) {
242 final Map<Tuple, Timeline<Timestamp>> result = getWithTimeline(signature);
243 return result == null ? Collections.emptyMap() : result;
244 }
245
246 /**
247 * Removes a tuple occurrence from the memory with the given signature.
248 *
249 * @param tuple
250 * the tuple to be removed from the memory
251 * @param signature
252 * precomputed footprint of the tuple according to the mask
253 *
254 * @return true if this was the the last occurrence of the signature (according to the mask)
255 */
256 public boolean remove(final Tuple tuple, final Tuple signature) {
257 throw new UnsupportedOperationException("This is only supported by timeless memory implementations!");
258 }
259
260 /**
261 * Removes a tuple occurrence from the memory with the given signature and timestamp.
262 *
263 * @param tuple
264 * the tuple to be removed from the memory
265 * @param signature
266 * precomputed footprint of the tuple according to the mask
267 * @param timestamp
268 * the timestamp associated with the tuple
269 *
270 * @return A {@link Diff} describing how the timeline of the given tuple changed.
271 *
272 * @since 2.4
273 */
274 public Diff<Timestamp> removeWithTimestamp(final Tuple tuple, final Tuple signature, final Timestamp timestamp) {
275 throw new UnsupportedOperationException("This is only supported by timely memory implementations!");
276 }
277
278 /**
279 * Removes a tuple occurrence from the memory.
280 *
281 * @param tuple
282 * the tuple to be removed from the memory
283 *
284 * @return true if this was the the last occurrence of the signature (according to the mask)
285 */
286 public boolean remove(final Tuple tuple) {
287 throw new UnsupportedOperationException("This is only supported by timeless memory implementations!");
288 }
289
290 /**
291 * Removes a tuple occurrence from the memory with the given timestamp.
292 *
293 * @param tuple
294 * the tuple to be removed from the memory
295 * @param timestamp
296 * the timestamp associated with the tuple
297 *
298 * @return A {@link Diff} describing how the timeline of the given tuple changed.
299 *
300 * @since 2.4
301 */
302 public Diff<Timestamp> removeWithTimestamp(final Tuple tuple, final Timestamp timestamp) {
303 throw new UnsupportedOperationException("This is only supported by timely memory implementations!");
304 }
305
306 /**
307 * Adds a tuple occurrence to the memory with the given signature.
308 *
309 * @param tuple
310 * the tuple to be added to the memory
311 * @param signature
312 * precomputed footprint of the tuple according to the mask
313 *
314 * @return true if new signature encountered (according to the mask)
315 */
316 public boolean add(final Tuple tuple, final Tuple signature) {
317 throw new UnsupportedOperationException("This is only supported by timeless memory implementations!");
318 }
319
320 /**
321 * Adds a tuple occurrence to the memory with the given signature and timestamp.
322 *
323 * @param tuple
324 * the tuple to be added to the memory
325 * @param signature
326 * precomputed footprint of the tuple according to the mask
327 * @param timestamp
328 * the timestamp associated with the tuple
329 *
330 * @return A {@link Diff} describing how the timeline of the given tuple changed.
331 *
332 * @since 2.4
333 */
334 public Diff<Timestamp> addWithTimestamp(final Tuple tuple, final Tuple signature, final Timestamp timestamp) {
335 throw new UnsupportedOperationException("This is only supported by timely memory implementations!");
336 }
337
338 /**
339 * Adds a tuple occurrence to the memory.
340 *
341 * @param tuple
342 * the tuple to be added to the memory
343 *
344 * @return true if new signature encountered (according to the mask)
345 */
346 public boolean add(final Tuple tuple) {
347 throw new UnsupportedOperationException("This is only supported by timeless memory implementations!");
348 }
349
350 /**
351 * Adds a tuple occurrence to the memory with the given timestamp.
352 *
353 * @param tuple
354 * the tuple to be added to the memory
355 * @param timestamp
356 * the timestamp associated with the tuple
357 *
358 * @return A {@link Diff} describing how the timeline of the given tuple changed.
359 *
360 * @since 2.4
361 */
362 public Diff<Timestamp> addWithTimestamp(final Tuple tuple, final Timestamp timestamp) {
363 throw new UnsupportedOperationException("This is only supported by timely memory implementations!");
364 }
365
366 protected MaskedTupleMemory(final TupleMask mask, final Object owner) {
367 super();
368 this.mask = mask;
369 this.owner = owner;
370 }
371
372 protected IllegalStateException raiseDuplicateInsertion(final Tuple tuple) {
373 return new IllegalStateException(String.format("Duplicate insertion of tuple %s into %s", tuple, owner));
374 }
375
376 protected IllegalStateException raiseDuplicateDeletion(final Tuple tuple) {
377 return new IllegalStateException(String.format("Duplicate deletion of tuple %s from %s", tuple, owner));
378 }
379
380 @Override
381 public String toString() {
382 return getClass().getSimpleName() + "<" + mask + ">@" + owner;
383 }
384
385} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/NullaryMaskedTupleMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/NullaryMaskedTupleMemory.java
new file mode 100644
index 00000000..7fa9e053
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/NullaryMaskedTupleMemory.java
@@ -0,0 +1,85 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.Set;
14
15import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
16import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
17import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
19import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
20
21/**
22 * Specialized for nullary mask; tuples are stored as a simple set/multiset memory.
23 *
24 * @author Gabor Bergmann
25 * @since 2.0
26 */
27public final class NullaryMaskedTupleMemory<Timestamp extends Comparable<Timestamp>> extends AbstractTrivialMaskedMemory<Timestamp> {
28
29 protected static final Set<Tuple> UNIT_RELATION =
30 Collections.singleton(Tuples.staticArityFlatTupleOf());
31 protected static final Set<Tuple> EMPTY_RELATION =
32 Collections.emptySet();
33 /**
34 * @param mask
35 * The mask used to index the matchings
36 * @param owner the object "owning" this memory
37 * @param bucketType the kind of tuple collection maintained for each indexer bucket
38 * @since 2.0
39 */
40 public NullaryMaskedTupleMemory(TupleMask mask, MemoryType bucketType, Object owner) {
41 super(mask, bucketType, owner);
42 if (0 != mask.getSize()) throw new IllegalArgumentException(mask.toString());
43 }
44
45 @Override
46 public int getKeysetSize() {
47 return tuples.isEmpty() ? 0 : 1;
48 }
49
50 @Override
51 public Iterable<Tuple> getSignatures() {
52 return tuples.isEmpty() ? EMPTY_RELATION : UNIT_RELATION;
53 }
54
55 @Override
56 public Collection<Tuple> get(ITuple signature) {
57 if (0 == signature.getSize())
58 return tuples.distinctValues();
59 else return null;
60 }
61
62 @Override
63 public boolean remove(Tuple tuple, Tuple signature) {
64 tuples.removeOne(tuple);
65 return tuples.isEmpty();
66 }
67
68 @Override
69 public boolean remove(Tuple tuple) {
70 return remove(tuple, null);
71 }
72
73 @Override
74 public boolean add(Tuple tuple, Tuple signature) {
75 boolean wasEmpty = tuples.isEmpty();
76 tuples.addOne(tuple);
77 return wasEmpty;
78 }
79
80 @Override
81 public boolean add(Tuple tuple) {
82 return add(tuple, null);
83 }
84
85}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/UnaryMaskedTupleMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/UnaryMaskedTupleMemory.java
new file mode 100644
index 00000000..f34cc9e3
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/UnaryMaskedTupleMemory.java
@@ -0,0 +1,143 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories;
10
11import java.util.Collection;
12import java.util.Iterator;
13import java.util.Map;
14
15import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
16import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
17import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
19import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
20import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
21import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
22import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
23import tools.refinery.viatra.runtime.matchers.util.IMultiLookup.ChangeGranularity;
24import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
25
26/**
27 * Specialized for unary mask; tuples are indexed by a single column as opposed to a projection (signature) tuple.
28 *
29 * @author Gabor Bergmann
30 * @since 2.0
31 */
32public final class UnaryMaskedTupleMemory<Timestamp extends Comparable<Timestamp>> extends MaskedTupleMemory<Timestamp> {
33
34 protected IMultiLookup<Object, Tuple> columnToTuples;
35 protected final int keyPosition;
36
37 /**
38 * @param mask
39 * The mask used to index the matchings
40 * @param owner the object "owning" this memory
41 * @param bucketType the kind of tuple collection maintained for each indexer bucket
42 * @since 2.0
43 */
44 public UnaryMaskedTupleMemory(TupleMask mask, MemoryType bucketType, Object owner) {
45 super(mask, owner);
46 if (1 != mask.getSize()) throw new IllegalArgumentException(mask.toString());
47
48 columnToTuples = CollectionsFactory.<Object, Tuple>createMultiLookup(
49 Object.class, bucketType, Object.class);
50 keyPosition = mask.indices[0];
51 }
52
53 @Override
54 public void clear() {
55 columnToTuples.clear();
56 }
57
58 @Override
59 public int getKeysetSize() {
60 return columnToTuples.countKeys();
61 }
62
63 @Override
64 public int getTotalSize() {
65 int i = 0;
66 for (Object key : columnToTuples.distinctKeys()) {
67 i += columnToTuples.lookup(key).size();
68 }
69 return i;
70 }
71
72 @Override
73 public Iterator<Tuple> iterator() {
74 return columnToTuples.distinctValues().iterator();
75 }
76
77 @Override
78 public Iterable<Tuple> getSignatures() {
79 return () -> {
80 Iterator<Object> wrapped = columnToTuples.distinctKeys().iterator();
81 return new Iterator<Tuple>() {
82 @Override
83 public boolean hasNext() {
84 return wrapped.hasNext();
85 }
86 @Override
87 public Tuple next() {
88 Object key = wrapped.next();
89 return Tuples.staticArityFlatTupleOf(key);
90 }
91 };
92 };
93 }
94
95 @Override
96 public Collection<Tuple> get(ITuple signature) {
97 Object key = signature.get(0);
98 IMemoryView<Tuple> bucket = columnToTuples.lookup(key);
99 return bucket == null ? null : bucket.distinctValues();
100 }
101
102 @Override
103 public Map<Tuple, Timeline<Timestamp>> getWithTimeline(ITuple signature) {
104 throw new UnsupportedOperationException("Timeless memories do not support timestamp-based lookup!");
105 }
106
107 @Override
108 public boolean remove(Tuple tuple, Tuple signature) {
109 return removeInternal(tuple, tuple.get(keyPosition));
110 }
111
112 @Override
113 public boolean remove(Tuple tuple) {
114 return removeInternal(tuple, tuple.get(keyPosition));
115 }
116
117 @Override
118 public boolean add(Tuple tuple, Tuple signature) {
119 return addInternal(tuple, tuple.get(keyPosition));
120 }
121
122 @Override
123 public boolean add(Tuple tuple) {
124 return addInternal(tuple, tuple.get(keyPosition));
125 }
126
127 protected boolean addInternal(Tuple tuple, Object key) {
128 try {
129 return columnToTuples.addPair(key, tuple) == ChangeGranularity.KEY;
130 } catch (IllegalStateException ex) { // ignore worthless internal exception details
131 throw raiseDuplicateInsertion(tuple);
132 }
133 }
134
135 protected boolean removeInternal(Tuple tuple, Object key) {
136 try {
137 return columnToTuples.removePair(key, tuple) == ChangeGranularity.KEY;
138 } catch (IllegalStateException ex) { // ignore worthless internal exception details
139 throw raiseDuplicateDeletion(tuple);
140 }
141 }
142
143}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyMaskedMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyMaskedMemory.java
new file mode 100644
index 00000000..45ce3a4e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyMaskedMemory.java
@@ -0,0 +1,228 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories.timely;
10
11import java.util.Collection;
12import java.util.Iterator;
13import java.util.Map;
14import java.util.Map.Entry;
15import java.util.Objects;
16import java.util.Set;
17import java.util.TreeMap;
18
19import tools.refinery.viatra.runtime.matchers.memories.MaskedTupleMemory;
20import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
21import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
22import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
23import tools.refinery.viatra.runtime.matchers.util.Direction;
24import tools.refinery.viatra.runtime.matchers.util.Signed;
25import tools.refinery.viatra.runtime.matchers.util.TimelyMemory;
26import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
27import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
28
29/**
30 * Common parts of timely default and timely unary implementations.
31 *
32 * @noextend This class is not intended to be subclassed by clients.
33 * @author Tamas Szabo
34 * @since 2.3
35 */
36abstract class AbstractTimelyMaskedMemory<Timestamp extends Comparable<Timestamp>, KeyType>
37 extends MaskedTupleMemory<Timestamp> {
38
39 protected final TreeMap<Timestamp, Set<KeyType>> foldingStates;
40 protected final Map<KeyType, TimelyMemory<Timestamp>> memoryMap;
41 protected final boolean isLazy;
42
43 public AbstractTimelyMaskedMemory(final TupleMask mask, final Object owner, final boolean isLazy) {
44 super(mask, owner);
45 this.isLazy = isLazy;
46 this.memoryMap = CollectionsFactory.createMap();
47 this.foldingStates = this.isLazy ? CollectionsFactory.createTreeMap() : null;
48 }
49
50 @Override
51 public void initializeWith(final MaskedTupleMemory<Timestamp> other, final Timestamp defaultValue) {
52 final Iterable<Tuple> signatures = other.getSignatures();
53 for (final Tuple signature : signatures) {
54 if (other.isTimely()) {
55 final Map<Tuple, Timeline<Timestamp>> tupleMap = other.getWithTimeline(signature);
56 for (final Entry<Tuple, Timeline<Timestamp>> entry : tupleMap.entrySet()) {
57 for (final Signed<Timestamp> signed : entry.getValue().asChangeSequence()) {
58 if (signed.getDirection() == Direction.DELETE) {
59 this.removeWithTimestamp(entry.getKey(), signed.getPayload());
60 } else {
61 this.addWithTimestamp(entry.getKey(), signed.getPayload());
62 }
63 }
64 }
65 } else {
66 final Collection<Tuple> tuples = other.get(signature);
67 for (final Tuple tuple : tuples) {
68 this.addWithTimestamp(tuple, defaultValue);
69 }
70 }
71 }
72 }
73
74 public boolean isPresentAtInfinityInteral(KeyType key) {
75 final TimelyMemory<Timestamp> values = this.memoryMap.get(key);
76 if (values == null) {
77 return false;
78 } else {
79 return values.getCountAtInfinity() != 0;
80 }
81 }
82
83 @Override
84 public void clear() {
85 this.memoryMap.clear();
86 }
87
88 @Override
89 public int getKeysetSize() {
90 return this.memoryMap.keySet().size();
91 }
92
93 @Override
94 public int getTotalSize() {
95 int i = 0;
96 for (final Entry<KeyType, TimelyMemory<Timestamp>> entry : this.memoryMap.entrySet()) {
97 i += entry.getValue().size();
98 }
99 return i;
100 }
101
102 @Override
103 public Iterator<Tuple> iterator() {
104 return this.memoryMap.values().stream().flatMap(e -> e.keySet().stream()).iterator();
105 }
106
107 protected Collection<Tuple> getInternal(final KeyType key) {
108 final TimelyMemory<Timestamp> memory = this.memoryMap.get(key);
109 if (memory == null) {
110 return null;
111 } else {
112 return memory.getTuplesAtInfinity();
113 }
114 }
115
116 public Map<Tuple, Timeline<Timestamp>> getWithTimestampInternal(final KeyType key) {
117 final TimelyMemory<Timestamp> memory = this.memoryMap.get(key);
118 if (memory == null) {
119 return null;
120 } else {
121 return memory.asMap();
122 }
123 }
124
125 protected Diff<Timestamp> removeInternal(final KeyType key, final Tuple tuple, final Timestamp timestamp) {
126 Timestamp oldResumableTimestamp = null;
127 Timestamp newResumableTimestamp = null;
128
129 final TimelyMemory<Timestamp> keyMemory = this.memoryMap.get(key);
130 if (keyMemory == null) {
131 throw raiseDuplicateDeletion(tuple);
132 }
133
134 if (this.isLazy) {
135 oldResumableTimestamp = keyMemory.getResumableTimestamp();
136 }
137
138 Diff<Timestamp> diff = null;
139 try {
140 diff = keyMemory.remove(tuple, timestamp);
141 } catch (final IllegalStateException e) {
142 throw raiseDuplicateDeletion(tuple);
143 }
144 if (keyMemory.isEmpty()) {
145 this.memoryMap.remove(key);
146 }
147
148 if (this.isLazy) {
149 newResumableTimestamp = keyMemory.getResumableTimestamp();
150 if (!Objects.equals(oldResumableTimestamp, newResumableTimestamp)) {
151 unregisterFoldingState(oldResumableTimestamp, key);
152 registerFoldingState(newResumableTimestamp, key);
153 }
154 }
155
156 return diff;
157 }
158
159 protected Diff<Timestamp> addInternal(final KeyType key, final Tuple tuple, final Timestamp timestamp) {
160 Timestamp oldResumableTimestamp = null;
161 Timestamp newResumableTimestamp = null;
162
163 final TimelyMemory<Timestamp> keyMemory = this.memoryMap.computeIfAbsent(key,
164 k -> new TimelyMemory<Timestamp>(this.isLazy));
165
166 if (this.isLazy) {
167 oldResumableTimestamp = keyMemory.getResumableTimestamp();
168 }
169
170 final Diff<Timestamp> diff = keyMemory.put(tuple, timestamp);
171
172 if (this.isLazy) {
173 newResumableTimestamp = keyMemory.getResumableTimestamp();
174 if (!Objects.equals(oldResumableTimestamp, newResumableTimestamp)) {
175 unregisterFoldingState(oldResumableTimestamp, key);
176 registerFoldingState(newResumableTimestamp, key);
177 }
178 }
179
180 return diff;
181 }
182
183 @Override
184 public Diff<Timestamp> removeWithTimestamp(final Tuple tuple, final Timestamp timestamp) {
185 return removeWithTimestamp(tuple, null, timestamp);
186 }
187
188 @Override
189 public Diff<Timestamp> addWithTimestamp(final Tuple tuple, final Timestamp timestamp) {
190 return addWithTimestamp(tuple, null, timestamp);
191 }
192
193 @Override
194 public boolean isTimely() {
195 return true;
196 }
197
198 protected void registerFoldingState(final Timestamp timestamp, final KeyType key) {
199 if (timestamp != null) {
200 this.foldingStates.compute(timestamp, (k, v) -> {
201 if (v == null) {
202 v = CollectionsFactory.createSet();
203 }
204 v.add(key);
205 return v;
206 });
207 }
208 }
209
210 protected void unregisterFoldingState(final Timestamp timestamp, final KeyType key) {
211 if (timestamp != null) {
212 this.foldingStates.compute(timestamp, (k, v) -> {
213 v.remove(key);
214 return v.isEmpty() ? null : v;
215 });
216 }
217 }
218
219 @Override
220 public Timestamp getResumableTimestamp() {
221 if (this.foldingStates == null || this.foldingStates.isEmpty()) {
222 return null;
223 } else {
224 return this.foldingStates.firstKey();
225 }
226 }
227
228}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyTrivialMaskedMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyTrivialMaskedMemory.java
new file mode 100644
index 00000000..ca06685a
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyTrivialMaskedMemory.java
@@ -0,0 +1,100 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories.timely;
10
11import java.util.Collection;
12import java.util.Iterator;
13import java.util.Map;
14import java.util.Map.Entry;
15
16import tools.refinery.viatra.runtime.matchers.memories.MaskedTupleMemory;
17import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
18import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
19import tools.refinery.viatra.runtime.matchers.util.Direction;
20import tools.refinery.viatra.runtime.matchers.util.Signed;
21import tools.refinery.viatra.runtime.matchers.util.TimelyMemory;
22import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
23import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
24
25/**
26 * Common parts of timely nullary and timely identity implementations.
27 *
28 * @noextend This class is not intended to be subclassed by clients.
29 * @author Tamas Szabo
30 * @since 2.3
31 */
32abstract class AbstractTimelyTrivialMaskedMemory<Timestamp extends Comparable<Timestamp>> extends MaskedTupleMemory<Timestamp> {
33
34 protected final TimelyMemory<Timestamp> memory;
35
36 protected AbstractTimelyTrivialMaskedMemory(final TupleMask mask, final Object owner, final boolean isLazy) {
37 super(mask, owner);
38 this.memory = new TimelyMemory<Timestamp>(isLazy);
39 }
40
41 @Override
42 public void initializeWith(final MaskedTupleMemory<Timestamp> other, final Timestamp defaultValue) {
43 final Iterable<Tuple> signatures = other.getSignatures();
44 for (final Tuple signature : signatures) {
45 if (other.isTimely()) {
46 final Map<Tuple, Timeline<Timestamp>> tupleMap = other.getWithTimeline(signature);
47 for (final Entry<Tuple, Timeline<Timestamp>> entry : tupleMap.entrySet()) {
48 for (final Signed<Timestamp> signed : entry.getValue().asChangeSequence()) {
49 if (signed.getDirection() == Direction.DELETE) {
50 this.removeWithTimestamp(entry.getKey(), signed.getPayload());
51 } else {
52 this.addWithTimestamp(entry.getKey(), signed.getPayload());
53 }
54 }
55 }
56 } else {
57 final Collection<Tuple> tuples = other.get(signature);
58 for (final Tuple tuple : tuples) {
59 this.removeWithTimestamp(tuple, defaultValue);
60 }
61 }
62 }
63 }
64
65 @Override
66 public void clear() {
67 this.memory.clear();
68 }
69
70 @Override
71 public int getTotalSize() {
72 return this.memory.size();
73 }
74
75 @Override
76 public Iterator<Tuple> iterator() {
77 return this.memory.keySet().iterator();
78 }
79
80 @Override
81 public Diff<Timestamp> removeWithTimestamp(final Tuple tuple, final Timestamp timestamp) {
82 return removeWithTimestamp(tuple, null, timestamp);
83 }
84
85 @Override
86 public Diff<Timestamp> addWithTimestamp(final Tuple tuple, final Timestamp timestamp) {
87 return addWithTimestamp(tuple, null, timestamp);
88 }
89
90 @Override
91 public boolean isTimely() {
92 return true;
93 }
94
95 @Override
96 public Timestamp getResumableTimestamp() {
97 return this.memory.getResumableTimestamp();
98 }
99
100}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyDefaultMaskedTupleMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyDefaultMaskedTupleMemory.java
new file mode 100644
index 00000000..623d7399
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyDefaultMaskedTupleMemory.java
@@ -0,0 +1,98 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.memories.timely;
11
12import java.util.Collection;
13import java.util.Collections;
14import java.util.Map;
15import java.util.Set;
16
17import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
19import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
20import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
21import tools.refinery.viatra.runtime.matchers.util.TimelyMemory;
22import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
23import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
24
25/**
26 * Default timely implementation that covers all cases.
27 *
28 * @author Tamas Szabo
29 * @since 2.3
30 */
31public final class TimelyDefaultMaskedTupleMemory<Timestamp extends Comparable<Timestamp>>
32 extends AbstractTimelyMaskedMemory<Timestamp, Tuple> {
33
34 public TimelyDefaultMaskedTupleMemory(final TupleMask mask, final Object owner, final boolean isLazy) {
35 super(mask, owner, isLazy);
36 }
37
38 @Override
39 public Iterable<Tuple> getSignatures() {
40 return this.memoryMap.keySet();
41 }
42
43 @Override
44 public Diff<Timestamp> removeWithTimestamp(final Tuple tuple, final Tuple signature,
45 final Timestamp timestamp) {
46 final Tuple key = mask.transform(tuple);
47 return removeInternal(key, tuple, timestamp);
48 }
49
50 @Override
51 public Diff<Timestamp> addWithTimestamp(final Tuple tuple, final Tuple signature,
52 final Timestamp timestamp) {
53 final Tuple key = this.mask.transform(tuple);
54 return addInternal(key, tuple, timestamp);
55 }
56
57 @Override
58 public Collection<Tuple> get(final ITuple signature) {
59 return getInternal(signature.toImmutable());
60 }
61
62 @Override
63 public Map<Tuple, Timeline<Timestamp>> getWithTimeline(final ITuple signature) {
64 return getWithTimestampInternal(signature.toImmutable());
65 }
66
67 @Override
68 public boolean isPresentAtInfinity(final ITuple signature) {
69 return isPresentAtInfinityInteral(signature.toImmutable());
70 }
71
72 @Override
73 public Set<Tuple> getResumableSignatures() {
74 if (this.foldingStates == null || this.foldingStates.isEmpty()) {
75 return Collections.emptySet();
76 } else {
77 return this.foldingStates.firstEntry().getValue();
78 }
79 }
80
81 @Override
82 public Map<Tuple, Map<Tuple, Diff<Timestamp>>> resumeAt(final Timestamp timestamp) {
83 final Map<Tuple, Map<Tuple, Diff<Timestamp>>> result = CollectionsFactory.createMap();
84 final Timestamp resumableTimestamp = this.getResumableTimestamp();
85 if (resumableTimestamp == null || resumableTimestamp.compareTo(timestamp) != 0) {
86 throw new IllegalStateException("Expected to continue folding at " + resumableTimestamp + "!");
87 }
88 final Set<Tuple> signatures = this.foldingStates.remove(timestamp);
89 for (final Tuple signature : signatures) {
90 final TimelyMemory<Timestamp> memory = this.memoryMap.get(signature);
91 final Map<Tuple, Diff<Timestamp>> diffMap = memory.resumeAt(resumableTimestamp);
92 result.put(signature, diffMap);
93 registerFoldingState(memory.getResumableTimestamp(), signature);
94 }
95 return result;
96 }
97
98}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyIdentityMaskedTupleMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyIdentityMaskedTupleMemory.java
new file mode 100644
index 00000000..568f274d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyIdentityMaskedTupleMemory.java
@@ -0,0 +1,106 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories.timely;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.Map;
14import java.util.Map.Entry;
15import java.util.Set;
16
17import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
19import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
20import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
21import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
22import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
23
24/**
25 * Timely specialization for identity mask.
26 *
27 * @author Tamas Szabo
28 * @since 2.3
29 */
30public final class TimelyIdentityMaskedTupleMemory<Timestamp extends Comparable<Timestamp>>
31 extends AbstractTimelyTrivialMaskedMemory<Timestamp> {
32
33 public TimelyIdentityMaskedTupleMemory(final TupleMask mask, final Object owner, final boolean isLazy) {
34 super(mask, owner, isLazy);
35 if (!mask.isIdentity())
36 throw new IllegalArgumentException(mask.toString());
37 }
38
39 @Override
40 public int getKeysetSize() {
41 return this.memory.size();
42 }
43
44 @Override
45 public Iterable<Tuple> getSignatures() {
46 return this.memory.keySet();
47 }
48
49 @Override
50 public Collection<Tuple> get(final ITuple signature) {
51 if (this.memory.getTuplesAtInfinity().contains(signature)) {
52 return Collections.singleton(signature.toImmutable());
53 } else {
54 return null;
55 }
56 }
57
58 @Override
59 public Map<Tuple, Timeline<Timestamp>> getWithTimeline(final ITuple signature) {
60 final Timeline<Timestamp> value = this.memory.get(signature);
61 if (value != null) {
62 return Collections.singletonMap(signature.toImmutable(), value);
63 } else {
64 return null;
65 }
66 }
67
68 @Override
69 public Diff<Timestamp> removeWithTimestamp(final Tuple tuple, final Tuple signature, final Timestamp timestamp) {
70 try {
71 return this.memory.remove(tuple, timestamp);
72 } catch (final IllegalStateException e) {
73 throw raiseDuplicateDeletion(tuple);
74 }
75 }
76
77 @Override
78 public Diff<Timestamp> addWithTimestamp(final Tuple tuple, final Tuple signature, final Timestamp timestamp) {
79 return this.memory.put(tuple, timestamp);
80 }
81
82 @Override
83 public boolean isPresentAtInfinity(final ITuple signature) {
84 return this.memory.isPresentAtInfinity(signature.toImmutable());
85 }
86
87 @Override
88 public Set<Tuple> getResumableSignatures() {
89 if (this.memory.getResumableTimestamp() != null) {
90 return this.memory.getResumableTuples();
91 } else {
92 return Collections.emptySet();
93 }
94 }
95
96 @Override
97 public Map<Tuple, Map<Tuple, Diff<Timestamp>>> resumeAt(final Timestamp timestamp) {
98 final Map<Tuple, Diff<Timestamp>> diffMap = this.memory.resumeAt(timestamp);
99 final Map<Tuple, Map<Tuple, Diff<Timestamp>>> result = CollectionsFactory.createMap();
100 for (final Entry<Tuple, Diff<Timestamp>> entry : diffMap.entrySet()) {
101 result.put(entry.getKey(), Collections.singletonMap(entry.getKey(), entry.getValue()));
102 }
103 return result;
104 }
105
106}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyNullaryMaskedTupleMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyNullaryMaskedTupleMemory.java
new file mode 100644
index 00000000..75987a89
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyNullaryMaskedTupleMemory.java
@@ -0,0 +1,108 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories.timely;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.Map;
14import java.util.Set;
15
16import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
17import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
18import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
19import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
20import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
21import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
22
23/**
24 * Timely specialization for nullary mask.
25 *
26 * @author Tamas Szabo
27 * @since 2.3
28 */
29public final class TimelyNullaryMaskedTupleMemory<Timestamp extends Comparable<Timestamp>>
30 extends AbstractTimelyTrivialMaskedMemory<Timestamp> {
31
32 protected static final Tuple EMPTY_TUPLE = Tuples.staticArityFlatTupleOf();
33 protected static final Set<Tuple> UNIT_RELATION = Collections.singleton(EMPTY_TUPLE);
34 protected static final Set<Tuple> EMPTY_RELATION = Collections.emptySet();
35
36 public TimelyNullaryMaskedTupleMemory(final TupleMask mask, final Object owner, final boolean isLazy) {
37 super(mask, owner, isLazy);
38 if (0 != mask.getSize()) {
39 throw new IllegalArgumentException(mask.toString());
40 }
41 }
42
43 @Override
44 public int getKeysetSize() {
45 return this.memory.isEmpty() ? 0 : 1;
46 }
47
48 @Override
49 public Iterable<Tuple> getSignatures() {
50 return this.memory.isEmpty() ? EMPTY_RELATION : UNIT_RELATION;
51 }
52
53 @Override
54 public Collection<Tuple> get(final ITuple signature) {
55 if (0 == signature.getSize()) {
56 return this.memory.getTuplesAtInfinity();
57 } else {
58 return null;
59 }
60 }
61
62 @Override
63 public Map<Tuple, Timeline<Timestamp>> getWithTimeline(final ITuple signature) {
64 if (0 == signature.getSize()) {
65 return this.memory.asMap();
66 } else {
67 return null;
68 }
69 }
70
71 @Override
72 public Diff<Timestamp> removeWithTimestamp(final Tuple tuple, final Tuple signature, final Timestamp timestamp) {
73 try {
74 return this.memory.remove(tuple, timestamp);
75 } catch (final IllegalStateException e) {
76 throw raiseDuplicateDeletion(tuple);
77 }
78 }
79
80 @Override
81 public Diff<Timestamp> addWithTimestamp(final Tuple tuple, final Tuple signature, final Timestamp timestamp) {
82 return this.memory.put(tuple, timestamp);
83 }
84
85 @Override
86 public boolean isPresentAtInfinity(final ITuple signature) {
87 if (0 == signature.getSize()) {
88 return this.memory.getCountAtInfinity() > 0;
89 } else {
90 return false;
91 }
92 }
93
94 @Override
95 public Set<Tuple> getResumableSignatures() {
96 if (this.memory.getResumableTimestamp() != null) {
97 return UNIT_RELATION;
98 } else {
99 return EMPTY_RELATION;
100 }
101 }
102
103 @Override
104 public Map<Tuple, Map<Tuple, Diff<Timestamp>>> resumeAt(final Timestamp timestamp) {
105 return Collections.singletonMap(EMPTY_TUPLE, this.memory.resumeAt(timestamp));
106 }
107
108}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyUnaryMaskedTupleMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyUnaryMaskedTupleMemory.java
new file mode 100644
index 00000000..178193af
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyUnaryMaskedTupleMemory.java
@@ -0,0 +1,133 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories.timely;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.Iterator;
14import java.util.Map;
15import java.util.Set;
16
17import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
19import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
20import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
21import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
22import tools.refinery.viatra.runtime.matchers.util.TimelyMemory;
23import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
24import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
25
26/**
27 * Timely specialization for unary mask.
28 *
29 * @author Tamas Szabo
30 * @since 2.3
31 */
32public final class TimelyUnaryMaskedTupleMemory<Timestamp extends Comparable<Timestamp>>
33 extends AbstractTimelyMaskedMemory<Timestamp, Object> {
34
35 protected final int keyPosition;
36
37 public TimelyUnaryMaskedTupleMemory(final TupleMask mask, final Object owner, final boolean isLazy) {
38 super(mask, owner, isLazy);
39 if (1 != mask.getSize())
40 throw new IllegalArgumentException(mask.toString());
41 this.keyPosition = mask.indices[0];
42 }
43
44 @Override
45 public Iterable<Tuple> getSignatures() {
46 return () -> {
47 final Iterator<Object> wrapped = this.memoryMap.keySet().iterator();
48 return new Iterator<Tuple>() {
49 @Override
50 public boolean hasNext() {
51 return wrapped.hasNext();
52 }
53
54 @Override
55 public Tuple next() {
56 final Object key = wrapped.next();
57 return Tuples.staticArityFlatTupleOf(key);
58 }
59 };
60 };
61 }
62
63 @Override
64 public Diff<Timestamp> removeWithTimestamp(final Tuple tuple, final Tuple signature, final Timestamp timestamp) {
65 final Object key = tuple.get(keyPosition);
66 return removeInternal(key, tuple, timestamp);
67 }
68
69 @Override
70 public Diff<Timestamp> addWithTimestamp(final Tuple tuple, final Tuple signature, final Timestamp timestamp) {
71 final Object key = tuple.get(keyPosition);
72 return addInternal(key, tuple, timestamp);
73 }
74
75 @Override
76 public Collection<Tuple> get(final ITuple signature) {
77 return getInternal(signature.get(0));
78 }
79
80 @Override
81 public Map<Tuple, Timeline<Timestamp>> getWithTimeline(final ITuple signature) {
82 return getWithTimestampInternal(signature.get(0));
83 }
84
85 @Override
86 public boolean isPresentAtInfinity(ITuple signature) {
87 return isPresentAtInfinityInteral(signature.get(0));
88 }
89
90 @Override
91 public Iterable<Tuple> getResumableSignatures() {
92 if (this.foldingStates == null || this.foldingStates.isEmpty()) {
93 return Collections.emptySet();
94 } else {
95 return () -> {
96 final Iterator<Object> wrapped = this.foldingStates.firstEntry().getValue().iterator();
97 return new Iterator<Tuple>() {
98 @Override
99 public boolean hasNext() {
100 return wrapped.hasNext();
101 }
102
103 @Override
104 public Tuple next() {
105 final Object key = wrapped.next();
106 return Tuples.staticArityFlatTupleOf(key);
107 }
108 };
109 };
110 }
111 }
112
113 @Override
114 public Map<Tuple, Map<Tuple, Diff<Timestamp>>> resumeAt(final Timestamp timestamp) {
115 final Map<Tuple, Map<Tuple, Diff<Timestamp>>> result = CollectionsFactory.createMap();
116 final Timestamp resumableTimestamp = this.getResumableTimestamp();
117 if (resumableTimestamp == null) {
118 throw new IllegalStateException("There is nothing to fold!");
119 } else if (resumableTimestamp.compareTo(timestamp) != 0) {
120 throw new IllegalStateException("Expected to continue folding at " + resumableTimestamp + "!");
121 }
122
123 final Set<Object> signatures = this.foldingStates.remove(timestamp);
124 for (final Object signature : signatures) {
125 final TimelyMemory<Timestamp> memory = this.memoryMap.get(signature);
126 final Map<Tuple, Diff<Timestamp>> diffMap = memory.resumeAt(resumableTimestamp);
127 result.put(Tuples.staticArityFlatTupleOf(signature), diffMap);
128 registerFoldingState(memory.getResumableTimestamp(), signature);
129 }
130 return result;
131 }
132
133}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IOperationCompiler.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IOperationCompiler.java
new file mode 100644
index 00000000..c9f4b305
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IOperationCompiler.java
@@ -0,0 +1,108 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.planning;
11
12import java.util.Map;
13
14import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
15import tools.refinery.viatra.runtime.matchers.psystem.IExpressionEvaluator;
16import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
17import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
18import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
19
20/**
21 *
22 * An implicit common parameter is the "effort" PatternDescription. This
23 * indicates that the build request is part of an effort to build the matcher of
24 * the given pattern; it it important to record this during code generation so
25 * that the generated code can be separated according to patterns.
26 *
27 * @param <Collector>
28 * the handle of a receiver-like RETE ending to which plans can be
29 * connected
30 * @author Gabor Bergmann
31 * @noimplement This interface is not intended to be implemented by clients.
32 */
33public interface IOperationCompiler<Collector> {
34
35 /**
36 * @throws ViatraQueryRuntimeException
37 */
38 public Collector patternCollector(PQuery pattern);
39
40 public void buildConnection(SubPlan parentPlan, Collector collector);
41
42 /**
43 * @since 0.9
44 */
45 public void patternFinished(PQuery pattern, Collector collector);
46
47 /**
48 * @throws ViatraQueryRuntimeException
49 */
50 public SubPlan patternCallPlan(Tuple nodes, PQuery supplierKey);
51
52 public SubPlan transitiveInstantiationPlan(Tuple nodes);
53
54 public SubPlan directInstantiationPlan(Tuple nodes);
55
56 public SubPlan transitiveGeneralizationPlan(Tuple nodes);
57
58 public SubPlan directGeneralizationPlan(Tuple nodes);
59
60 public SubPlan transitiveContainmentPlan(Tuple nodes);
61
62 public SubPlan directContainmentPlan(Tuple nodes);
63
64 public SubPlan binaryEdgeTypePlan(Tuple nodes, Object supplierKey);
65
66 public SubPlan ternaryEdgeTypePlan(Tuple nodes, Object supplierKey);
67
68 public SubPlan unaryTypePlan(Tuple nodes, Object supplierKey);
69
70 public SubPlan buildStartingPlan(Object[] constantValues, Object[] constantNames);
71
72 public SubPlan buildEqualityChecker(SubPlan parentPlan, int[] indices);
73
74 public SubPlan buildInjectivityChecker(SubPlan parentPlan, int subject, int[] inequalIndices);
75
76 public SubPlan buildTransitiveClosure(SubPlan parentPlan);
77
78 public SubPlan buildTrimmer(SubPlan parentPlan, TupleMask trimMask, boolean enforceUniqueness);
79
80 public SubPlan buildBetaNode(SubPlan primaryPlan, SubPlan sidePlan,
81 TupleMask primaryMask, TupleMask sideMask, TupleMask complementer, boolean negative);
82
83 public SubPlan buildCounterBetaNode(SubPlan primaryPlan, SubPlan sidePlan,
84 TupleMask primaryMask, TupleMask originalSideMask, TupleMask complementer,
85 Object aggregateResultCalibrationElement);
86
87 public SubPlan buildCountCheckBetaNode(SubPlan primaryPlan, SubPlan sidePlan,
88 TupleMask primaryMask, TupleMask originalSideMask, int resultPositionInSignature);
89
90 public SubPlan buildPredicateChecker(IExpressionEvaluator evaluator, Map<String, Integer> tupleNameMap,
91 SubPlan parentPlan);
92 public SubPlan buildFunctionEvaluator(IExpressionEvaluator evaluator, Map<String, Integer> tupleNameMap,
93 SubPlan parentPlan, Object computedResultCalibrationElement);
94
95 /**
96 * @return an operation compiler that potentially acts on a separate container
97 */
98 public IOperationCompiler<Collector> getNextContainer();
99
100 /**
101 * @return an operation compiler that puts build actions on the tab of the given pattern
102 * @since 0.9
103 */
104 public IOperationCompiler<Collector> putOnTab(PQuery effort /*, IPatternMatcherContext context*/);
105
106 public void reinitialize();
107
108} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IQueryPlannerStrategy.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IQueryPlannerStrategy.java
new file mode 100644
index 00000000..6ce9d91b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IQueryPlannerStrategy.java
@@ -0,0 +1,29 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.planning;
11
12import org.apache.log4j.Logger;
13import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
14import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
15import tools.refinery.viatra.runtime.matchers.psystem.PBody;
16
17/**
18 * An algorithm that builds a query plan based on a PSystem representation of a body of constraints. This interface is
19 * for internal use of the various query backends.
20 *
21 * @author Gabor Bergmann
22 */
23public interface IQueryPlannerStrategy {
24
25 /**
26 * @throws ViatraQueryRuntimeException
27 */
28 public SubPlan plan(PBody pSystem, Logger logger, IQueryMetaContext context);
29}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/QueryProcessingException.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/QueryProcessingException.java
new file mode 100644
index 00000000..501ddf73
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/QueryProcessingException.java
@@ -0,0 +1,102 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning;
10
11import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
12
13/**
14 * @author Zoltan Ujhelyi
15 * @since 0.9
16 */
17public class QueryProcessingException extends ViatraQueryRuntimeException {
18
19 private static final long serialVersionUID = -8272290113656867086L;
20 /**
21 * Binding the '{n}' (n = 1..N) strings to contextual conditions in 'context'
22 *
23 * @param context
24 * : array of context-sensitive Strings
25 */
26 protected static String bind(String message, String[] context) {
27 if (context == null)
28 return message;
29
30 String internal = message;
31 for (int i = 0; i < context.length; i++) {
32 internal = internal.replace("{" + (i + 1) + "}", context[i] != null ? context[i] : "<<null>>");
33 }
34 return internal;
35 }
36
37 private Object patternDescription;
38 private String shortMessage;
39
40 /**
41 * @param message
42 * The template of the exception message
43 * @param context
44 * The data elements to be used to instantiate the template. Can be null if no context parameter is
45 * defined
46 * @param patternDescription
47 * the PatternDescription where the exception occurred
48 * @since 2.0
49 */
50 public QueryProcessingException(String message, Object patternDescription) {
51 super(message);
52 initializeFields(message, patternDescription);
53 }
54
55 /**
56 * @param message
57 * The template of the exception message
58 * @param context
59 * The data elements to be used to instantiate the template. Can be null if no context parameter is
60 * defined
61 * @param patternDescription
62 * the PatternDescription where the exception occurred
63 */
64 public QueryProcessingException(String message, String[] context, String shortMessage, Object patternDescription) {
65 super(bind(message, context));
66 initializeFields(shortMessage, patternDescription);
67 }
68
69 /**
70 * @param message
71 * The template of the exception message
72 * @param context
73 * The data elements to be used to instantiate the template. Can be null if no context parameter is
74 * defined
75 * @param patternDescription
76 * the PatternDescription where the exception occurred
77 */
78 public QueryProcessingException(String message, String[] context, String shortMessage, Object patternDescription,
79 Throwable cause) {
80 super(bind(message, context), cause);
81 initializeFields(shortMessage, patternDescription);
82 }
83
84 public Object getPatternDescription() {
85 return patternDescription;
86 }
87
88 public String getShortMessage() {
89 return shortMessage;
90 }
91
92 private void initializeFields(String shortMessage, Object patternDescription) {
93 this.patternDescription = patternDescription;
94 this.shortMessage = shortMessage;
95 }
96
97
98 public void setPatternDescription(Object patternDescription) {
99 this.patternDescription = patternDescription;
100 }
101
102} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlan.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlan.java
new file mode 100644
index 00000000..1998df9d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlan.java
@@ -0,0 +1,240 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.planning;
11
12import java.util.Arrays;
13import java.util.HashSet;
14import java.util.List;
15import java.util.Set;
16import java.util.WeakHashMap;
17import java.util.stream.Collectors;
18
19import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
20import tools.refinery.viatra.runtime.matchers.planning.helpers.TypeHelper;
21import tools.refinery.viatra.runtime.matchers.planning.operations.POperation;
22import tools.refinery.viatra.runtime.matchers.planning.operations.PProject;
23import tools.refinery.viatra.runtime.matchers.planning.operations.PStart;
24import tools.refinery.viatra.runtime.matchers.psystem.PBody;
25import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
26import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
27import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
28
29/**
30 * A plan representing a subset of (or possibly all the) constraints evaluated. A SubPlan instance is responsible for
31 * representing a state of the plan; but after it is initialized it is expected be immutable
32 * (exception: inferred constraints, see {@link #inferConstraint(PConstraint)}).
33 *
34 * <p> A SubPlan is constructed by applying a {@link POperation} on zero or more parent SubPlans.
35 * Important maintained information: <ul>
36 * <li>set of <b>variables</b> whose values are known when the runtime evaluation is at this stage,
37 * <li>set of <b>constraints</b> that are known to hold true at this point.
38 * </ul>
39 *
40 * <p> Recommended to instantiate via a {@link SubPlanFactory} or subclasses,
41 * so that query planners can subclass SubPlan if needed.
42 *
43 * @author Gabor Bergmann
44 *
45 */
46public class SubPlan {
47 private PBody body;
48 private List<? extends SubPlan> parentPlans;
49 private POperation operation;
50
51 private final Set<PVariable> visibleVariables;
52 private final Set<PVariable> allVariables;
53 private final Set<PVariable> introducedVariables; // delta compared to first parent
54 private Set<PConstraint> allConstraints;
55 private Set<PConstraint> deltaConstraints; // delta compared to all parents
56 private Set<PConstraint> externallyInferredConstraints; // inferred in addition to direct consequences of the operation and parents
57
58
59
60
61
62 /**
63 * A SubPlan is constructed by applying a {@link POperation} on zero or more parent SubPlans.
64 */
65 public SubPlan(PBody body, POperation operation, SubPlan... parentPlans) {
66 this(body, operation, Arrays.asList(parentPlans));
67 }
68 /**
69 * A SubPlan is constructed by applying a {@link POperation} on zero or more parent SubPlans.
70 */
71 public SubPlan(PBody body, POperation operation, List<? extends SubPlan> parentPlans) {
72 super();
73 this.body = body;
74 this.parentPlans = parentPlans;
75 this.operation = operation;
76
77 this.externallyInferredConstraints = new HashSet<PConstraint>();
78 this.deltaConstraints = new HashSet<PConstraint>(operation.getDeltaConstraints());
79
80 this.allVariables = new HashSet<PVariable>();
81 for (PConstraint constraint: deltaConstraints) {
82 this.allVariables.addAll(constraint.getDeducedVariables());
83 }
84 this.allConstraints = new HashSet<PConstraint>(deltaConstraints);
85 for (SubPlan parentPlan: parentPlans) {
86 this.allConstraints.addAll(parentPlan.getAllEnforcedConstraints());
87 this.allVariables.addAll(parentPlan.getAllDeducedVariables());
88 }
89
90 // TODO this is ugly a bit
91 if (operation instanceof PStart) {
92 this.visibleVariables = new HashSet<PVariable>(((PStart) operation).getAPrioriVariables());
93 this.allVariables.addAll(visibleVariables);
94 } else if (operation instanceof PProject) {
95 this.visibleVariables = new HashSet<PVariable>(((PProject) operation).getToVariables());
96 } else {
97 this.visibleVariables = new HashSet<PVariable>();
98 for (SubPlan parentPlan: parentPlans)
99 this.visibleVariables.addAll(parentPlan.getVisibleVariables());
100 for (PConstraint constraint: deltaConstraints)
101 this.visibleVariables.addAll(constraint.getDeducedVariables());
102 }
103
104 this.introducedVariables = new HashSet<PVariable>(this.visibleVariables);
105 if (!parentPlans.isEmpty())
106 introducedVariables.removeAll(parentPlans.get(0).getVisibleVariables());
107
108 operation.checkConsistency(this);
109 }
110
111
112 @Override
113 public String toString() {
114 return toLongString();
115 }
116 public String toShortString() {
117 return String.format("Plan{%s}:%s",
118 visibleVariables.stream().map(PVariable::getName).collect(Collectors.joining(",")),
119 operation.getShortName());
120 }
121 public String toLongString() {
122 return String.format("%s<%s>",
123 toShortString(),
124 parentPlans.stream().map(Object::toString).collect(Collectors.joining("; ")));
125 }
126
127
128 /**
129 * All constraints that are known to hold at this point
130 */
131 public Set<PConstraint> getAllEnforcedConstraints() {
132 return allConstraints;
133 }
134
135 /**
136 * The new constraints enforced at this stage of plan, that aren't yet enforced at parents
137 * (results are also included in {@link SubPlan#getAllEnforcedConstraints()})
138 */
139 public Set<PConstraint> getDeltaEnforcedConstraints() {
140 return deltaConstraints;
141 }
142
143 /**
144 * Indicate that a given constraint was found to be automatically satisfied at this point
145 * without additional operations.
146 * (results are also included in {@link SubPlan#getDeltaEnforcedConstraints()})
147 *
148 * <p>Warning: not propagated automatically to child plans,
149 * so best to invoke before constructing further SubPlans. </p>
150 */
151 public void inferConstraint(PConstraint constraint) {
152 externallyInferredConstraints.add(constraint);
153 deltaConstraints.add(constraint);
154 allConstraints.add(constraint);
155 }
156
157 public PBody getBody() {
158 return body;
159 }
160
161 /**
162 * Variables which are assigned a value at this point
163 * (results are also included in {@link SubPlan#getAllDeducedVariables()})
164 */
165 public Set<PVariable> getVisibleVariables() {
166 return visibleVariables;
167 }
168 /**
169 * Variables which have been assigned a value;
170 * includes visible variables (see {@link #getVisibleVariables()})
171 * and additionally any variables hidden by a projection (see {@link PProject}).
172 */
173 public Set<PVariable> getAllDeducedVariables() {
174 return allVariables;
175 }
176 /**
177 * Delta compared to first parent: variables that are visible here but were not visible at the first parent.
178 */
179 public Set<PVariable> getIntroducedVariables() {
180 return introducedVariables;
181 }
182 public List<? extends SubPlan> getParentPlans() {
183 return parentPlans;
184 }
185 public POperation getOperation() {
186 return operation;
187 }
188
189
190 /**
191 * The closure of all type judgments of enforced constraints at this point.
192 * <p> No subsumption applied.
193 */
194 public Set<TypeJudgement> getAllImpliedTypeJudgements(IQueryMetaContext context) {
195 Set<TypeJudgement> impliedJudgements = allImpliedTypeJudgements.get(context);
196 if (impliedJudgements == null) {
197 Set<TypeJudgement> equivalentJudgements = TypeHelper.getDirectJudgements(getAllEnforcedConstraints(), context);
198 impliedJudgements = TypeHelper.typeClosure(equivalentJudgements, context);
199
200 allImpliedTypeJudgements.put(context, impliedJudgements);
201 }
202 return impliedJudgements;
203 }
204 private WeakHashMap<IQueryMetaContext, Set<TypeJudgement>> allImpliedTypeJudgements = new WeakHashMap<IQueryMetaContext, Set<TypeJudgement>>();
205
206
207 @Override
208 public int hashCode() {
209 final int prime = 31;
210 int result = 1;
211 result = prime * result
212 + ((operation == null) ? 0 : operation.hashCode());
213 result = prime * result
214 + ((parentPlans == null) ? 0 : parentPlans.hashCode());
215 return result;
216 }
217 @Override
218 public boolean equals(Object obj) {
219 if (this == obj)
220 return true;
221 if (obj == null)
222 return false;
223 if (!(obj instanceof SubPlan))
224 return false;
225 SubPlan other = (SubPlan) obj;
226 if (operation == null) {
227 if (other.operation != null)
228 return false;
229 } else if (!operation.equals(other.operation))
230 return false;
231 if (parentPlans == null) {
232 if (other.parentPlans != null)
233 return false;
234 } else if (!parentPlans.equals(other.parentPlans))
235 return false;
236 return true;
237 }
238
239
240}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlanFactory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlanFactory.java
new file mode 100644
index 00000000..d0df5fac
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlanFactory.java
@@ -0,0 +1,33 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning;
10
11import tools.refinery.viatra.runtime.matchers.planning.operations.POperation;
12import tools.refinery.viatra.runtime.matchers.psystem.PBody;
13
14/**
15 * Single entry point for creating subplans.
16 * Can be subclassed by query planner to provide specialized SubPlans.
17 * @author Bergmann Gabor
18 *
19 */
20public class SubPlanFactory {
21
22 protected PBody body;
23
24 public SubPlanFactory(PBody body) {
25 super();
26 this.body = body;
27 }
28
29 public SubPlan createSubPlan(POperation operation, SubPlan... parentPlans) {
30 return new SubPlan(body, operation, parentPlans);
31 }
32
33}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/BuildHelper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/BuildHelper.java
new file mode 100644
index 00000000..ed5d1cbb
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/BuildHelper.java
@@ -0,0 +1,165 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.planning.helpers;
11
12import java.util.Collection;
13import java.util.HashSet;
14import java.util.Map;
15import java.util.Set;
16
17import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
18import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
19import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
20import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
21import tools.refinery.viatra.runtime.matchers.planning.SubPlanFactory;
22import tools.refinery.viatra.runtime.matchers.planning.operations.PProject;
23import tools.refinery.viatra.runtime.matchers.psystem.PBody;
24import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
25import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
26import tools.refinery.viatra.runtime.matchers.psystem.analysis.QueryAnalyzer;
27import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExportedParameter;
28
29/**
30 * @author Gabor Bergmann
31 *
32 */
33public class BuildHelper {
34
35 private BuildHelper() {
36 // Hiding constructor for utility class
37 }
38
39// public static SubPlan naturalJoin(IOperationCompiler buildable,
40// SubPlan primaryPlan, SubPlan secondaryPlan) {
41// JoinHelper joinHelper = new JoinHelper(primaryPlan, secondaryPlan);
42// return buildable.buildBetaNode(primaryPlan, secondaryPlan, joinHelper.getPrimaryMask(),
43// joinHelper.getSecondaryMask(), joinHelper.getComplementerMask(), false);
44// }
45
46
47 /**
48 * Reduces the number of tuples by trimming (existentially quantifying) the set of variables that <ul>
49 * <li> are visible in the subplan,
50 * <li> are not exported parameters,
51 * <li> have all their constraints already enforced in the subplan,
52 * </ul> and thus will not be needed anymore.
53 *
54 * @param onlyIfNotDetermined if true, no trimming performed unless there is at least one variable that is not functionally determined
55 * @return the plan after the trimming (possibly the original)
56 * @since 1.5
57 */
58 public static SubPlan trimUnneccessaryVariables(SubPlanFactory planFactory, /*IOperationCompiler buildable,*/
59 SubPlan plan, boolean onlyIfNotDetermined, QueryAnalyzer analyzer) {
60 Set<PVariable> canBeTrimmed = new HashSet<PVariable>();
61 Set<PVariable> variablesInPlan = plan.getVisibleVariables();
62 for (PVariable trimCandidate : variablesInPlan) {
63 if (trimCandidate.getReferringConstraintsOfType(ExportedParameter.class).isEmpty()) {
64 if (plan.getAllEnforcedConstraints().containsAll(trimCandidate.getReferringConstraints()))
65 canBeTrimmed.add(trimCandidate);
66 }
67 }
68 final Set<PVariable> retainedVars = setMinus(variablesInPlan, canBeTrimmed);
69 if (!canBeTrimmed.isEmpty() && !(onlyIfNotDetermined && areVariablesDetermined(plan, retainedVars, canBeTrimmed, analyzer, false))) {
70 // TODO add smart ordering?
71 plan = planFactory.createSubPlan(new PProject(retainedVars), plan);
72 }
73 return plan;
74 }
75
76 /**
77 * @return true iff a set of given variables functionally determine all visible variables in the subplan according to the subplan's constraints
78 * @param strict if true, only "hard" dependencies are taken into account that are strictly enforced by the model representation;
79 * if false, user-provided soft dependencies are included as well, that are anticipated but not guaranteed by the storage mechanism;
80 * use true if superfluous dependencies may taint the correctness of a computation, false if they would merely impact performance
81 * @since 1.5
82 */
83 public static boolean areAllVariablesDetermined(SubPlan plan, Collection<PVariable> determining, QueryAnalyzer analyzer, boolean strict) {
84 return areVariablesDetermined(plan, determining, plan.getVisibleVariables(), analyzer, strict);
85 }
86
87 /**
88 * @return true iff one set of given variables functionally determine the other set according to the subplan's constraints
89 * @param strict if true, only "hard" dependencies are taken into account that are strictly enforced by the model representation;
90 * if false, user-provided soft dependencies are included as well, that are anticipated but not guaranteed by the storage mechanism;
91 * use true if superfluous dependencies may taint the correctness of a computation, false if they would merely impact performance
92 * @since 1.5
93 */
94 public static boolean areVariablesDetermined(SubPlan plan, Collection<PVariable> determining, Collection<PVariable> determined,
95 QueryAnalyzer analyzer, boolean strict) {
96 Map<Set<PVariable>, Set<PVariable>> dependencies = analyzer.getFunctionalDependencies(plan.getAllEnforcedConstraints(), strict);
97 final Set<PVariable> closure = FunctionalDependencyHelper.closureOf(determining, dependencies);
98 final boolean isDetermined = closure.containsAll(determined);
99 return isDetermined;
100 }
101
102 private static <T> Set<T> setMinus(Set<T> a, Set<T> b) {
103 Set<T> difference = new HashSet<T>(a);
104 difference.removeAll(b);
105 return difference;
106 }
107
108 /**
109 * Finds an arbitrary constraint that is not enforced at the given plan.
110 *
111 * @param pSystem
112 * @param plan
113 * @return a PConstraint that is not enforced, if any, or null if all are enforced
114 */
115 public static PConstraint getAnyUnenforcedConstraint(PBody pSystem,
116 SubPlan plan) {
117 Set<PConstraint> allEnforcedConstraints = plan.getAllEnforcedConstraints();
118 Set<PConstraint> constraints = pSystem.getConstraints();
119 for (PConstraint pConstraint : constraints) {
120 if (!allEnforcedConstraints.contains(pConstraint))
121 return pConstraint;
122 }
123 return null;
124 }
125
126 /**
127 * Skips the last few steps, if any, that are projections, so that a custom projection can be added instead.
128 * Useful for connecting body final plans into the production node.
129 *
130 * @since 2.1
131 */
132 public static SubPlan eliminateTrailingProjections(SubPlan plan) {
133 while (plan.getOperation() instanceof PProject)
134 plan = plan.getParentPlans().get(0);
135 return plan;
136 }
137
138 /**
139 * Verifies whether all constraints are enforced and exported parameters are present.
140 *
141 * @param pSystem
142 * @param plan
143 * @throws ViatraQueryRuntimeException
144 */
145 public static void finalCheck(final PBody pSystem, SubPlan plan, IQueryMetaContext context) {
146 PConstraint unenforcedConstraint = getAnyUnenforcedConstraint(pSystem, plan);
147 if (unenforcedConstraint != null) {
148 throw new QueryProcessingException(
149 "Pattern matcher construction terminated without successfully enforcing constraint {1}."
150 + " Could be caused if the value of some variables can not be deduced, e.g. by circularity of pattern constraints.",
151 new String[] { unenforcedConstraint.toString() }, "Could not enforce a pattern constraint", null);
152 }
153 for (ExportedParameter export : pSystem
154 .getConstraintsOfType(ExportedParameter.class)) {
155 if (!export.isReadyAt(plan, context)) {
156 throw new QueryProcessingException(
157 "Exported pattern parameter {1} could not be deduced during pattern matcher construction."
158 + " A pattern constraint is required to positively deduce its value.",
159 new String[] { export.getParameterName() }, "Could not calculate pattern parameter",
160 null);
161 }
162 }
163 }
164
165}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/FunctionalDependencyHelper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/FunctionalDependencyHelper.java
new file mode 100644
index 00000000..40835f52
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/FunctionalDependencyHelper.java
@@ -0,0 +1,143 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Adam Dudas, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning.helpers;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.HashMap;
14import java.util.HashSet;
15import java.util.Map;
16import java.util.Map.Entry;
17import java.util.Set;
18
19import tools.refinery.viatra.runtime.matchers.util.Sets;
20
21/**
22 * Helper utility class for functional dependency analysis.
23 *
24 * Throughout this class attribute sets are represented as generic sets and functional dependencies as maps from
25 * attribute set (generic sets) to attribute set (generic sets)
26 *
27 * @author Adam Dudas
28 *
29 */
30public class FunctionalDependencyHelper {
31
32 private FunctionalDependencyHelper() {
33 // Hiding constructor for utility class
34 }
35
36 /**
37 * Get the closure of the specified attribute set relative to the specified functional dependencies.
38 *
39 * @param attributes
40 * The attributes to get the closure of.
41 * @param dependencies
42 * The functional dependencies of which the closure operation is relative to.
43 * @return The closure of the specified attribute set relative to the specified functional dependencies.
44 */
45 public static <A> Set<A> closureOf(Collection<A> attributes, Map<Set<A>, Set<A>> dependencies) {
46 Set<A> closureSet = new HashSet<A>();
47
48 for (Set<A> closureSet1 = new HashSet<A>(attributes); closureSet.addAll(closureSet1);) {
49 closureSet1 = new HashSet<A>();
50 for (Entry<Set<A>, Set<A>> dependency : dependencies.entrySet()) {
51 if (closureSet.containsAll(dependency.getKey()))
52 closureSet1.addAll(dependency.getValue());
53 }
54 }
55
56 return closureSet;
57 }
58
59 /**
60 * @return true if the dependency from the left set to the right set is trivial
61 * @since 1.5
62 */
63 public static <A> boolean isTrivial(Set<A> left, Set<A> right) {
64 return left.containsAll(right);
65 }
66
67 /***
68 * Returns the dependency set over attributes in {@link targetAttributes} that are implied by a given source dependency set.
69 * <p> Note: exponential in the size of the target attribute set.
70 * <p> Note: minimality of the returned dependency set is currently not guaranteed.
71 * @param originalDependencies all dependencies that are known to hold on a wider set of attributes
72 * @param targetAttributes the set of attributes we are interested in
73 * @since 1.5
74 */
75 public static <A> Map<Set<A>, Set<A>> projectDependencies(Map<Set<A>, Set<A>> originalDependencies, Set<A> targetAttributes) {
76 // only those attributes are considered as left-hand-side candidates that occur at least once in dependencies
77 Set<A> leftCandidates = new HashSet<A>();
78 for (Entry<Set<A>, Set<A>> dependency : originalDependencies.entrySet()) {
79 if (!isTrivial(dependency.getKey(), dependency.getValue())) // only if non-trivial
80 leftCandidates.addAll(Sets.intersection(dependency.getKey(), targetAttributes));
81 }
82
83 // Compute an initial list of nontrivial projected dependencies - it does not have to be minimal yet
84 Map<Set<A>, Set<A>> initialDependencies = new HashMap<Set<A>, Set<A>>();
85 for (Set<A> leftSet : Sets.powerSet(leftCandidates)) {
86 Set<A> rightSet = Sets.intersection(closureOf(leftSet, originalDependencies), targetAttributes);
87 if (!isTrivial(leftSet, rightSet)) {
88 initialDependencies.put(leftSet, rightSet);
89 }
90 }
91 // Don't forget to include constants!
92 Set<A> constants = Sets.intersection(closureOf(Collections.<A>emptySet(), originalDependencies), targetAttributes);
93 if (! constants.isEmpty()) {
94 initialDependencies.put(Collections.<A>emptySet(), constants);
95 }
96
97 // Omit those dependencies where the LHS has superfluous attributes
98 Map<Set<A>, Set<A>> solidDependencies = new HashMap<Set<A>, Set<A>>();
99 for (Entry<Set<A>, Set<A>> dependency : initialDependencies.entrySet()) {
100 Set<A> leftSet = dependency.getKey();
101 Set<A> rightSet = dependency.getValue();
102 boolean solid = true;
103 for (A skipped : leftSet) { // what if we skip one attribute from the left set?
104 Set<A> singleton = Collections.singleton(skipped);
105 Set<A> candidate = Sets.difference(leftSet, singleton);
106 Set<A> rightCandidate = initialDependencies.get(candidate);
107 if (rightCandidate != null) {
108 if (Sets.union(rightCandidate, singleton).containsAll(rightSet)) {
109 solid = false;
110 break;
111 }
112 }
113 }
114 if (solid) {
115 solidDependencies.put(leftSet, rightSet);
116 }
117 }
118
119 // TODO perform proper minimization,
120 // see e.g. page 45 in http://www.cs.ubc.ca/~hkhosrav/db/slides/03.design%20theory.pdf
121
122 return Collections.unmodifiableMap(solidDependencies);
123 }
124
125 /**
126 * Adds a given dependency to a mutable accumulator.
127 * @since 1.5
128 */
129 public static <A> void includeDependency(Map<Set<A>, Set<A>> accumulator, Set<A> left, Set<A> right) {
130 Set<A> accumulatorRights = accumulator.computeIfAbsent(left, l -> new HashSet<>());
131 accumulatorRights.addAll(right);
132 }
133
134 /**
135 * Adds all given dependencies to a mutable accumulator.
136 * @since 1.5
137 */
138 public static <A> void includeDependencies(Map<Set<A>, Set<A>> accumulator, Map<Set<A>, Set<A>> additionalDependencies) {
139 for (Entry<Set<A>, Set<A>> entry : additionalDependencies.entrySet()) {
140 includeDependency(accumulator, entry.getKey(), entry.getValue());
141 }
142 }
143}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/StatisticsHelper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/StatisticsHelper.java
new file mode 100644
index 00000000..b4f848a7
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/StatisticsHelper.java
@@ -0,0 +1,62 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning.helpers;
10
11import java.util.Optional;
12import java.util.function.BiFunction;
13
14import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
15import tools.refinery.viatra.runtime.matchers.util.Accuracy;
16
17/**
18 * Helpers dealing with optionally present statistics information
19 *
20 * @author Gabor Bergmann
21 * @since 2.1
22 *
23 */
24public class StatisticsHelper {
25
26 private StatisticsHelper() {
27 // Hidden utility class constructor
28 }
29
30 public static Optional<Double> estimateAverageBucketSize(TupleMask groupMask, Accuracy requiredAccuracy,
31 BiFunction<TupleMask, Accuracy, Optional<Long>> estimateCardinality)
32 {
33 if (groupMask.isIdentity()) return Optional.of(1.0);
34
35 Accuracy numeratorAccuracy = requiredAccuracy;
36 Accuracy denominatorAccuracy = requiredAccuracy.reciprocal();
37 TupleMask identityMask = TupleMask.identity(groupMask.sourceWidth);
38
39 Optional<Long> totalCountEstimate = estimateCardinality.apply(identityMask, numeratorAccuracy);
40 Optional<Long> bucketCountEstimate = estimateCardinality.apply(groupMask, denominatorAccuracy);
41
42 return totalCountEstimate.flatMap(matchCount ->
43 bucketCountEstimate.map(bucketCount ->
44 bucketCount == 0L ? 0L : ((double) matchCount) / bucketCount
45 ));
46 }
47
48 public static Optional<Double> min(Optional<Double> a, Optional<Double> b) {
49 if (b.isPresent()) {
50 if (a.isPresent()) {
51 return Optional.of(Math.min(a.get(), b.get()));
52 } else return b;
53 } else return a;
54 }
55 public static Optional<Double> min(Optional<Double> a, double b) {
56 if (a.isPresent()) {
57 return Optional.of(Math.min(a.get(), b));
58 } else return Optional.of(b);
59 }
60
61
62}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/TypeHelper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/TypeHelper.java
new file mode 100644
index 00000000..926a591f
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/TypeHelper.java
@@ -0,0 +1,217 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.planning.helpers;
11
12import java.util.Collections;
13import java.util.HashMap;
14import java.util.HashSet;
15import java.util.LinkedList;
16import java.util.Map;
17import java.util.Map.Entry;
18import java.util.Queue;
19import java.util.Set;
20import java.util.stream.Collectors;
21
22import tools.refinery.viatra.runtime.matchers.context.IInputKey;
23import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
24import tools.refinery.viatra.runtime.matchers.psystem.ITypeInfoProviderConstraint;
25import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
26import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
27import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
28
29/**
30 * @author Gabor Bergmann
31 * @author Tamas Szabo
32 */
33public class TypeHelper {
34
35 private TypeHelper() {
36 // Hiding constructor for utility class
37 }
38
39 /**
40 * Collects the type constraints for the specified collection of variables. The type constraints consist of the
41 * constraints directly enforced on the variable itself, plus all of those that the given variable is unified with
42 * through equalities.
43 *
44 * @param variables
45 * the variables in question
46 * @param constraints
47 * the constraints in the pattern body
48 * @param context
49 * the query meta context
50 * @return the mapping from variable to set of type constraints
51 * @since 1.6
52 */
53 public static Map<PVariable, Set<IInputKey>> inferUnaryTypesFor(Iterable<PVariable> variables,
54 Set<PConstraint> constraints, IQueryMetaContext context) {
55 Map<PVariable, Set<TypeJudgement>> typeMap = TypeHelper.inferUnaryTypes(constraints, context);
56 return inferUnaryTypesFor(variables, typeMap);
57 }
58
59 /**
60 * Collects the type constraints for the specified collection of variables. The type constraints consist of the
61 * constraints directly enforced on the variable itself, plus all of those that the given variable is unified with
62 * through equalities.
63 *
64 * The method accepts a type map which is the result of the basic type inference from the
65 * {@link TypeHelper.inferUnaryTypes} method. The purpose of this method is that the type map can be reused across
66 * several calls to this method.
67 *
68 * @param variables
69 * the variables in question
70 * @param typeMap
71 * the type map of inference results
72 * @return the mapping from variable to set of type constraints
73 * @since 1.6
74 */
75 public static Map<PVariable, Set<IInputKey>> inferUnaryTypesFor(Iterable<PVariable> variables,
76 Map<PVariable, Set<TypeJudgement>> typeMap) {
77 Map<PVariable, Set<IInputKey>> result = new HashMap<PVariable, Set<IInputKey>>();
78
79 for (PVariable original : variables) {
80 // it can happen that the variable was unified into an other one due to equalities
81 Set<IInputKey> keys = new HashSet<IInputKey>();
82 PVariable current = original;
83
84 while (current != null) {
85 Set<TypeJudgement> judgements = typeMap.get(current);
86 if (judgements != null) {
87 for (TypeJudgement judgement : judgements) {
88 keys.add(judgement.getInputKey());
89 }
90 }
91 current = current.getDirectUnifiedInto();
92 }
93
94 result.put(original, keys);
95 }
96
97 return result;
98 }
99
100 /**
101 * Infers unary type information for variables, based on the given constraints.
102 *
103 * Subsumptions are not taken into account.
104 *
105 * @param constraints
106 * the set of constraints to extract type info from
107 */
108 public static Map<PVariable, Set<TypeJudgement>> inferUnaryTypes(Set<PConstraint> constraints,
109 IQueryMetaContext context) {
110 Set<TypeJudgement> equivalentJudgements = getDirectJudgements(constraints, context);
111 Set<TypeJudgement> impliedJudgements = typeClosure(equivalentJudgements, context);
112
113 Map<PVariable, Set<TypeJudgement>> results = new HashMap<PVariable, Set<TypeJudgement>>();
114 for (TypeJudgement typeJudgement : impliedJudgements) {
115 final IInputKey inputKey = typeJudgement.getInputKey();
116 if (inputKey.getArity() == 1) {
117 PVariable variable = (PVariable) typeJudgement.getVariablesTuple().get(0);
118 Set<TypeJudgement> inferredTypes = results.computeIfAbsent(variable, v -> new HashSet<>());
119 inferredTypes.add(typeJudgement);
120 }
121 }
122 return results;
123 }
124
125 /**
126 * Gets direct judgements reported by constraints. No closure is applied yet.
127 */
128 public static Set<TypeJudgement> getDirectJudgements(Set<PConstraint> constraints, IQueryMetaContext context) {
129 Set<TypeJudgement> equivalentJudgements = new HashSet<TypeJudgement>();
130 for (PConstraint pConstraint : constraints) {
131 if (pConstraint instanceof ITypeInfoProviderConstraint) {
132 equivalentJudgements.addAll(((ITypeInfoProviderConstraint) pConstraint).getImpliedJudgements(context));
133 }
134 }
135 return equivalentJudgements;
136 }
137
138 /**
139 * Calculates the closure of a set of type judgements, with respect to supertyping.
140 *
141 * @return the set of all type judgements in typesToClose and all their direct and indirect supertypes
142 */
143 public static Set<TypeJudgement> typeClosure(Set<TypeJudgement> typesToClose, IQueryMetaContext context) {
144 return typeClosure(Collections.<TypeJudgement> emptySet(), typesToClose, context);
145 }
146
147 /**
148 * Calculates the closure of a set of type judgements (with respect to supertyping), where the closure has been
149 * calculated before for a given base set, but not for a separate delta set.
150 * <p>
151 * Precondition: the set (typesToClose MINUS delta) is already closed w.r.t. supertyping.
152 *
153 * @return the set of all type judgements in typesToClose and all their direct and indirect supertypes
154 * @since 1.6
155 */
156 public static Set<TypeJudgement> typeClosure(Set<TypeJudgement> preclosedBaseSet, Set<TypeJudgement> delta,
157 IQueryMetaContext context) {
158 Queue<TypeJudgement> queue = delta.stream().filter(input -> !preclosedBaseSet.contains(input)).collect(Collectors.toCollection(LinkedList::new));
159 if (queue.isEmpty())
160 return preclosedBaseSet;
161
162 Set<TypeJudgement> closure = new HashSet<TypeJudgement>(preclosedBaseSet);
163
164 Map<TypeJudgement, Set<TypeJudgement>> conditionalImplications = new HashMap<>();
165 for (TypeJudgement typeJudgement : closure) {
166 conditionalImplications.putAll(typeJudgement.getConditionalImpliedJudgements(context));
167 }
168
169 do {
170 TypeJudgement deltaType = queue.poll();
171 if (closure.add(deltaType)) {
172 // direct implications
173 queue.addAll(deltaType.getDirectlyImpliedJudgements(context));
174
175 // conditional implications, source key processed before, this is the condition key
176 final Set<TypeJudgement> implicationSet = conditionalImplications.get(deltaType);
177 if (implicationSet != null) {
178 queue.addAll(implicationSet);
179 }
180
181 // conditional implications, this is the source key
182 Map<TypeJudgement, Set<TypeJudgement>> deltaConditionalImplications = deltaType
183 .getConditionalImpliedJudgements(context);
184 for (Entry<TypeJudgement, Set<TypeJudgement>> entry : deltaConditionalImplications.entrySet()) {
185 if (closure.contains(entry.getKey())) {
186 // condition processed before
187 queue.addAll(entry.getValue());
188 } else {
189 // condition not processed yet
190 conditionalImplications.computeIfAbsent(entry.getKey(), key -> new HashSet<>())
191 .addAll(entry.getValue());
192 }
193 }
194 }
195 } while (!queue.isEmpty());
196
197 return closure;
198 }
199
200 /**
201 * Calculates a remainder set of types from a larger set, that are not subsumed by a given set of subsuming types.
202 *
203 * @param subsumableTypes
204 * a set of types from which some may be implied by the subsuming types
205 * @param subsumingTypes
206 * a set of types that may imply some of the subsuming types
207 * @return the collection of types in subsumableTypes that are NOT identical to or supertypes of any type in
208 * subsumingTypes.
209 */
210 public static Set<TypeJudgement> subsumeTypes(Set<TypeJudgement> subsumableTypes, Set<TypeJudgement> subsumingTypes,
211 IQueryMetaContext context) {
212 Set<TypeJudgement> closure = typeClosure(subsumingTypes, context);
213 Set<TypeJudgement> subsumed = new HashSet<TypeJudgement>(subsumableTypes);
214 subsumed.removeAll(closure);
215 return subsumed;
216 }
217}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PApply.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PApply.java
new file mode 100644
index 00000000..2c285b54
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PApply.java
@@ -0,0 +1,94 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning.operations;
10
11import java.util.Collections;
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
15import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
16import tools.refinery.viatra.runtime.matchers.util.Preconditions;
17
18/**
19 * Represents a constraint application on a single parent SubPlan.
20 * <p> Either a "selection" filter operation according to a deferred PConstraint (or transform in case of eval/aggregate), or
21 * alternatively a shorthand for PJoin + a PEnumerate on the right input for an enumerable PConstraint.
22 *
23 * <p> <b>WARNING</b>: if there are coinciding variables in the variable tuple of the enumerable constraint,
24 * it is the responsibility of the compiler to check them for equality.
25 *
26 * @author Bergmann Gabor
27 *
28 */
29public class PApply extends POperation {
30
31 private PConstraint pConstraint;
32
33 public PApply(PConstraint pConstraint) {
34 super();
35 this.pConstraint = pConstraint;
36 }
37 public PConstraint getPConstraint() {
38 return pConstraint;
39 }
40
41 @Override
42 public String getShortName() {
43 return String.format("APPLY_%s", pConstraint.toString());
44 }
45
46 @Override
47 public Set<? extends PConstraint> getDeltaConstraints() {
48 return Collections.singleton(pConstraint);
49 }
50
51 @Override
52 public int numParentSubPlans() {
53 return 1;
54 }
55
56 @Override
57 public void checkConsistency(SubPlan subPlan) {
58 super.checkConsistency(subPlan);
59 for (SubPlan parentPlan : subPlan.getParentPlans())
60 Preconditions.checkArgument(!parentPlan.getAllEnforcedConstraints().contains(pConstraint),
61 "Double-checking constraint %s", pConstraint);
62 // TODO obtain context?
63 //if (pConstraint instanceof DeferredPConstraint)
64 // Preconditions.checkArgument(((DeferredPConstraint) pConstraint).isReadyAt(subPlan, context))
65 }
66
67 @Override
68 public int hashCode() {
69 final int prime = 31;
70 int result = 1;
71 result = prime
72 * result
73 + ((pConstraint == null) ? 0 : pConstraint
74 .hashCode());
75 return result;
76 }
77 @Override
78 public boolean equals(Object obj) {
79 if (this == obj)
80 return true;
81 if (obj == null)
82 return false;
83 if (!(obj instanceof PApply))
84 return false;
85 PApply other = (PApply) obj;
86 if (pConstraint == null) {
87 if (other.pConstraint != null)
88 return false;
89 } else if (!pConstraint.equals(other.pConstraint))
90 return false;
91 return true;
92 }
93
94}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PEnumerate.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PEnumerate.java
new file mode 100644
index 00000000..a975d50c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PEnumerate.java
@@ -0,0 +1,76 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning.operations;
10
11import java.util.Collections;
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.psystem.EnumerablePConstraint;
15import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
16
17/**
18 * Represents a base relation defined by the instance set of an enumerable PConstraint; there are no parent SubPlans.
19 *
20 * <p> <b>WARNING</b>: if there are coinciding variables in the variable tuple of the enumerable constraint,
21 * it is the responsibility of the compiler to check them for equality.
22 * @author Bergmann Gabor
23 *
24 */
25public class PEnumerate extends POperation {
26
27 EnumerablePConstraint enumerablePConstraint;
28
29 public PEnumerate(EnumerablePConstraint enumerablePConstraint) {
30 super();
31 this.enumerablePConstraint = enumerablePConstraint;
32 }
33 public EnumerablePConstraint getEnumerablePConstraint() {
34 return enumerablePConstraint;
35 }
36
37 @Override
38 public Set<? extends PConstraint> getDeltaConstraints() {
39 return Collections.singleton(enumerablePConstraint);
40 }
41 @Override
42 public int numParentSubPlans() {
43 return 0;
44 }
45 @Override
46 public String getShortName() {
47 return enumerablePConstraint.toString();
48 }
49 @Override
50 public int hashCode() {
51 final int prime = 31;
52 int result = 1;
53 result = prime
54 * result
55 + ((enumerablePConstraint == null) ? 0 : enumerablePConstraint
56 .hashCode());
57 return result;
58 }
59 @Override
60 public boolean equals(Object obj) {
61 if (this == obj)
62 return true;
63 if (obj == null)
64 return false;
65 if (!(obj instanceof PEnumerate))
66 return false;
67 PEnumerate other = (PEnumerate) obj;
68 if (enumerablePConstraint == null) {
69 if (other.enumerablePConstraint != null)
70 return false;
71 } else if (!enumerablePConstraint.equals(other.enumerablePConstraint))
72 return false;
73 return true;
74 }
75
76}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PJoin.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PJoin.java
new file mode 100644
index 00000000..10e0a85a
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PJoin.java
@@ -0,0 +1,64 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning.operations;
10
11import java.util.Collections;
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
15
16/**
17 * Represents a natural join of two parent SubPlans.
18 * @author Bergmann Gabor
19 *
20 */
21public class PJoin extends POperation {
22
23// // TODO leave here? is this a problem in equivalnece checking?
24// private Set<PVariable> onVariables;
25
26 public PJoin(/*Set<PVariable> onVariables*/) {
27 super();
28 //this.onVariables = new HashSet<PVariable>(onVariables);
29 }
30// public Set<PVariable> getOnVariables() {
31// return onVariables;
32// }
33
34 @Override
35 public Set<? extends PConstraint> getDeltaConstraints() {
36 return Collections.emptySet();
37 }
38 @Override
39 public int numParentSubPlans() {
40 return 2;
41 }
42
43 @Override
44 public String getShortName() {
45 return "JOIN"; //String.format("JOIN_{%s}", Joiner.on(",").join(onVariables));
46 }
47
48 @Override
49 public int hashCode() {
50 return getClass().hashCode();
51 }
52 @Override
53 public boolean equals(Object obj) {
54 if (this == obj)
55 return true;
56 if (obj == null)
57 return false;
58 if (!(obj instanceof PJoin))
59 return false;
60 return true;
61 }
62
63
64}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/POperation.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/POperation.java
new file mode 100644
index 00000000..e71cf217
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/POperation.java
@@ -0,0 +1,52 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning.operations;
10
11import java.util.Set;
12
13import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
14import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
15import tools.refinery.viatra.runtime.matchers.util.Preconditions;
16
17/**
18 * Abstract superclass for representing a high-level query evaluation operation.
19 *
20 * <p> Subclasses correspond to various POperations modeled after relational algebra.
21 *
22 * @author Bergmann Gabor
23 *
24 */
25public abstract class POperation {
26
27 /**
28 * Newly enforced constraints
29 */
30 public abstract Set<? extends PConstraint> getDeltaConstraints();
31
32 public abstract String getShortName();
33
34 /**
35 * @return the number of SubPlans that must be specified as parents
36 */
37 public abstract int numParentSubPlans();
38
39 /**
40 * Checks whether this constraint can be properly applied at the given SubPlan.
41 */
42 public void checkConsistency(SubPlan subPlan) {
43 Preconditions.checkArgument(this == subPlan.getOperation(), "POperation misalignment");
44 Preconditions.checkArgument(subPlan.getParentPlans().size() == numParentSubPlans(), "Incorrect number of parent SubPlans");
45 }
46
47 @Override
48 public String toString() {
49 return getShortName();
50 }
51
52}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PProject.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PProject.java
new file mode 100644
index 00000000..d0539b2c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PProject.java
@@ -0,0 +1,109 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning.operations;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.List;
14import java.util.Set;
15import java.util.stream.Collectors;
16
17import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
18import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
19import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
20import tools.refinery.viatra.runtime.matchers.util.Preconditions;
21
22/**
23 * Represents a projection of a single parent SubPlan onto a limited set of variables.
24 * <p> May optionally prescribe an ordering of variables (List, as opposed to Set).
25 *
26 * @author Bergmann Gabor
27 *
28 */
29public class PProject extends POperation {
30
31 private Collection<PVariable> toVariables;
32 private boolean ordered;
33
34
35 public PProject(Set<PVariable> toVariables) {
36 super();
37 this.toVariables = toVariables;
38 this.ordered = false;
39 }
40 public PProject(List<PVariable> toVariables) {
41 super();
42 this.toVariables = toVariables;
43 this.ordered = true;
44 }
45
46 public Collection<PVariable> getToVariables() {
47 return toVariables;
48 }
49 public boolean isOrdered() {
50 return ordered;
51 }
52
53 @Override
54 public Set<? extends PConstraint> getDeltaConstraints() {
55 return Collections.emptySet();
56 }
57 @Override
58 public int numParentSubPlans() {
59 return 1;
60 }
61 @Override
62 public void checkConsistency(SubPlan subPlan) {
63 super.checkConsistency(subPlan);
64 final SubPlan parentPlan = subPlan.getParentPlans().get(0);
65
66 Preconditions.checkArgument(parentPlan.getVisibleVariables().containsAll(toVariables),
67 () -> toVariables.stream()
68 .filter(input -> !parentPlan.getVisibleVariables().contains(input)).map(PVariable::getName)
69 .collect(Collectors.joining(",", "Variables missing from project: ", "")));
70 }
71
72 @Override
73 public String getShortName() {
74 return String.format("PROJECT%s_{%s}", ordered? "!" : "",
75 toVariables.stream().map(PVariable::getName).collect(Collectors.joining(",")));
76 }
77
78 @Override
79 public int hashCode() {
80 final int prime = 31;
81 int result = 1;
82 result = prime * result + (ordered ? 1231 : 1237);
83 result = prime * result
84 + ((toVariables == null) ? 0 : toVariables.hashCode());
85 return result;
86 }
87 @Override
88 public boolean equals(Object obj) {
89 if (this == obj)
90 return true;
91 if (obj == null)
92 return false;
93 if (!(obj instanceof PProject))
94 return false;
95 PProject other = (PProject) obj;
96 if (ordered != other.ordered)
97 return false;
98 if (toVariables == null) {
99 if (other.toVariables != null)
100 return false;
101 } else if (!toVariables.equals(other.toVariables))
102 return false;
103 return true;
104 }
105
106
107
108
109}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PStart.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PStart.java
new file mode 100644
index 00000000..9e6ea10e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PStart.java
@@ -0,0 +1,90 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning.operations;
10
11import java.util.Arrays;
12import java.util.Collections;
13import java.util.HashSet;
14import java.util.Set;
15import java.util.stream.Collectors;
16
17import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
18import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
19
20/**
21 * No constraints, and no parent SubPlan, just a (possibly empty) set of a priori known (input) variables. Satisfied by a single tuple.
22 *
23 * <p> Can also be used without a priori variables,
24 * e.g. as a "virtual parent" in extreme cases,
25 * such as <code>pattern foo(Bar) = {Bar = eval (3*4)} </code>
26 *
27 * @author Bergmann Gabor
28 *
29 */
30public class PStart extends POperation {
31
32 private Set<PVariable> aPrioriVariables;
33
34
35 public PStart(Set<PVariable> aPrioriVariables) {
36 super();
37 this.aPrioriVariables = aPrioriVariables;
38 }
39 public PStart(PVariable... aPrioriVariables) {
40 this(new HashSet<PVariable>(Arrays.asList(aPrioriVariables)));
41 }
42 public Set<PVariable> getAPrioriVariables() {
43 return aPrioriVariables;
44 }
45
46 @Override
47 public String getShortName() {
48 return aPrioriVariables.stream().map(PVariable::getName).collect(Collectors.joining(",", "START_{", "}"));
49 }
50 @Override
51 public int numParentSubPlans() {
52 return 0;
53 }
54
55 @Override
56 public Set<? extends PConstraint> getDeltaConstraints() {
57 return Collections.emptySet();
58 }
59
60 @Override
61 public int hashCode() {
62 final int prime = 31;
63 int result = 1;
64 result = prime
65 * result
66 + ((aPrioriVariables == null) ? 0 : aPrioriVariables.hashCode());
67 return result;
68 }
69
70 @Override
71 public boolean equals(Object obj) {
72 if (this == obj)
73 return true;
74 if (obj == null)
75 return false;
76 if (!(obj instanceof PStart))
77 return false;
78 PStart other = (PStart) obj;
79 if (aPrioriVariables == null) {
80 if (other.aPrioriVariables != null)
81 return false;
82 } else if (!aPrioriVariables.equals(other.aPrioriVariables))
83 return false;
84 return true;
85 }
86
87
88
89
90}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/BasePConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/BasePConstraint.java
new file mode 100644
index 00000000..eda4aa25
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/BasePConstraint.java
@@ -0,0 +1,108 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem;
11
12import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
13
14import java.util.Collections;
15import java.util.HashSet;
16import java.util.Map;
17import java.util.Set;
18import java.util.concurrent.atomic.AtomicInteger;
19
20/**
21 * @author Gabor Bergmann
22 *
23 */
24public abstract class BasePConstraint implements PConstraint {
25
26
27 protected PBody pBody;
28 private final Set<PVariable> affectedVariables;
29
30
31 private final int sequentialID = nextID.getAndIncrement();
32
33 // Use a static atomic integer to avoid race conditions when creating new constraints.
34 private static AtomicInteger nextID = new AtomicInteger(0);
35
36 public BasePConstraint(PBody pBody, Set<PVariable> affectedVariables) {
37 super();
38 this.pBody = pBody;
39 this.affectedVariables = new HashSet<PVariable>(affectedVariables);
40
41 for (PVariable pVariable : affectedVariables) {
42 pVariable.refer(this);
43 }
44 pBody.registerConstraint(this);
45 }
46
47 @Override
48 public String toString() {
49 return "PC[" + getClass().getSimpleName() + ":" + toStringRest() + "]";
50 }
51
52 protected abstract String toStringRest();
53
54 @Override
55 public Set<PVariable> getAffectedVariables() {
56 return affectedVariables;
57 }
58
59 @Override
60 public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context) {
61 return Collections.emptyMap();
62 }
63
64 @Override
65 public void replaceVariable(PVariable obsolete, PVariable replacement) {
66 pBody.checkMutability();
67 if (affectedVariables.remove(obsolete)) {
68 affectedVariables.add(replacement);
69 obsolete.unrefer(this);
70 replacement.refer(this);
71 doReplaceVariable(obsolete, replacement);
72 }
73 }
74
75 protected abstract void doReplaceVariable(PVariable obsolete, PVariable replacement);
76
77 @Override
78 public void delete() {
79 pBody.checkMutability();
80 for (PVariable pVariable : affectedVariables) {
81 pVariable.unrefer(this);
82 }
83 pBody.unregisterConstraint(this);
84 }
85
86 @Override
87 public void checkSanity() {
88 }
89
90 /**
91 * For backwards compatibility. Equivalent to {@link #getBody()}
92 */
93 public PBody getPSystem() {
94 return pBody;
95 }
96 /**
97 * @since 2.1
98 */
99 @Override
100 public PBody getBody() {
101 return pBody;
102 }
103
104 @Override
105 public int getMonotonousID() {
106 return sequentialID;
107 }
108}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/DeferredPConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/DeferredPConstraint.java
new file mode 100644
index 00000000..d2bf088c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/DeferredPConstraint.java
@@ -0,0 +1,31 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem;
11
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
15import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
16
17/**
18 * Any constraint that can only be checked on certain SubPlans (e.g. those plans that already contain some variables).
19 *
20 * @author Gabor Bergmann
21 *
22 */
23public abstract class DeferredPConstraint extends BasePConstraint {
24
25 public DeferredPConstraint(PBody pBody, Set<PVariable> affectedVariables) {
26 super(pBody, affectedVariables);
27 }
28
29 public abstract boolean isReadyAt(SubPlan plan, IQueryMetaContext context);
30
31}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/EnumerablePConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/EnumerablePConstraint.java
new file mode 100644
index 00000000..9129aa47
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/EnumerablePConstraint.java
@@ -0,0 +1,59 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem;
11
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
15
16/**
17 * A constraint for which all satisfying tuples of variable values can be enumerated at any point during run-time.
18 *
19 * @author Gabor Bergmann
20 *
21 */
22public abstract class EnumerablePConstraint extends BasePConstraint {
23 protected Tuple variablesTuple;
24
25 protected EnumerablePConstraint(PBody pBody, Tuple variablesTuple) {
26 super(pBody, variablesTuple.<PVariable> getDistinctElements());
27 this.variablesTuple = variablesTuple;
28 }
29
30 @Override
31 public void doReplaceVariable(PVariable obsolete, PVariable replacement) {
32 variablesTuple = variablesTuple.replaceAll(obsolete, replacement);
33 }
34
35 @Override
36 protected String toStringRest() {
37 String stringRestRest = toStringRestRest();
38 String tupleString = "@" + variablesTuple.toString();
39 return stringRestRest == null ? tupleString : ":" + stringRestRest + tupleString;
40 }
41
42 protected String toStringRestRest() {
43 return null;
44 }
45
46 public Tuple getVariablesTuple() {
47 return variablesTuple;
48 }
49
50 @Override
51 public Set<PVariable> getDeducedVariables() {
52 return getAffectedVariables();
53 }
54
55 public PVariable getVariableInTuple(int index) {
56 return (PVariable) this.variablesTuple.get(index);
57 }
58
59}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IExpressionEvaluator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IExpressionEvaluator.java
new file mode 100644
index 00000000..686999f7
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IExpressionEvaluator.java
@@ -0,0 +1,42 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem;
10
11/**
12 * An expression evaluator is used to execute arbitrary Java code during pattern matching. In order to include the
13 * evaluation in the planning seemlessly it is expected from the evaluator implementors to report all used PVariables by
14 * name.
15 *
16 * @author Zoltan Ujhelyi
17 *
18 */
19public interface IExpressionEvaluator {
20
21 /**
22 * A textual description of the expression. Used only for debug purposes, but must not be null.
23 */
24 String getShortDescription();
25
26 /**
27 * All input parameter names should be reported correctly.
28 */
29 Iterable<String> getInputParameterNames();
30
31 /**
32 * The expression evaluator code
33 *
34 * @param provider
35 * the value provider is an engine-specific way of reading internal variable tuples to evaluate the
36 * expression with
37 * @return the result of the expression: in case of predicate evaluation the return value must be true or false;
38 * otherwise the result can be an arbitrary object. No null values should be returned.
39 * @throws Exception
40 */
41 Object evaluateExpression(IValueProvider provider) throws Exception;
42}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IMultiQueryReference.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IMultiQueryReference.java
new file mode 100644
index 00000000..8f647c64
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IMultiQueryReference.java
@@ -0,0 +1,26 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2022, Tamas Szabo, GitHub
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem;
10
11import java.util.Collection;
12
13import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
14
15/**
16 * A {@link PConstraint} that implements this interface refers to a list of PQueries.
17 *
18 * @author Tamas Szabo
19 * @since 2.8
20 *
21 */
22public interface IMultiQueryReference {
23
24 Collection<PQuery> getReferredQueries();
25
26}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IQueryReference.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IQueryReference.java
new file mode 100644
index 00000000..9ee05b39
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IQueryReference.java
@@ -0,0 +1,33 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem;
10
11import java.util.Collections;
12import java.util.List;
13
14import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
15
16/**
17 * A {@link PConstraint} that implements this interface refers to a {@link PQuery}.
18 *
19 * @author Zoltan Ujhelyi
20 *
21 */
22public interface IQueryReference extends IMultiQueryReference {
23
24 PQuery getReferredQuery();
25
26 /**
27 * @since 2.8
28 */
29 @Override
30 default List<PQuery> getReferredQueries() {
31 return Collections.singletonList(getReferredQuery());
32 }
33}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IRelationEvaluator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IRelationEvaluator.java
new file mode 100644
index 00000000..e4c396d8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IRelationEvaluator.java
@@ -0,0 +1,47 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2022, Tamas Szabo, GitHub
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem;
10
11import java.util.List;
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
15
16/**
17 * Implementations of this interface take an arbitrary number of input relations with their contents and compute the
18 * tuples of a single output relation.
19 *
20 * @author Tamas Szabo
21 * @since 2.8
22 *
23 */
24public interface IRelationEvaluator {
25
26 /**
27 * A textual description of the evaluator. Used only for debug purposes, but must not be null.
28 */
29 String getShortDescription();
30
31 /**
32 * The relation evaluator code. For performance reasons, it is expected that the returned set is a mutable
33 * collection, and the caller must be allowed to actually perform mutations!
34 */
35 Set<Tuple> evaluateRelation(List<Set<Tuple>> inputs) throws Exception;
36
37 /**
38 * For each input relation that this evaluator requires, this method returns the expected arities of the relations in order.
39 */
40 List<Integer> getInputArities();
41
42 /**
43 * Returns the arity of the output relation that this evaluator computes.
44 */
45 int getOutputArity();
46
47}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeConstraint.java
new file mode 100644
index 00000000..b72035a8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeConstraint.java
@@ -0,0 +1,65 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem;
10
11import java.util.HashMap;
12import java.util.HashSet;
13import java.util.Map;
14import java.util.Map.Entry;
15
16import tools.refinery.viatra.runtime.matchers.context.IInputKey;
17import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
19
20import java.util.Set;
21
22/**
23 * Common superinterface of enumerable and deferred type constraints.
24 * @author Bergmann Gabor
25 *
26 */
27public interface ITypeConstraint extends ITypeInfoProviderConstraint {
28
29 public abstract TypeJudgement getEquivalentJudgement();
30
31 /**
32 * Static internal utility class for implementations of {@link ITypeConstraint}s.
33 * @author Bergmann Gabor
34 */
35 public static class TypeConstraintUtil {
36
37 private TypeConstraintUtil() {
38 // Hiding constructor for utility class
39 }
40
41 public static Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context, IInputKey inputKey, Tuple variablesTuple) {
42 final Map<Set<PVariable>, Set<PVariable>> result = new HashMap<Set<PVariable>, Set<PVariable>>();
43
44 Set<Entry<Set<Integer>, Set<Integer>>> dependencies = context.getFunctionalDependencies(inputKey).entrySet();
45 for (Entry<Set<Integer>, Set<Integer>> dependency : dependencies) {
46 result.put(
47 transcribeVariables(dependency.getKey(), variablesTuple),
48 transcribeVariables(dependency.getValue(), variablesTuple)
49 );
50 }
51
52 return result;
53 }
54
55 private static Set<PVariable> transcribeVariables(Set<Integer> indices, Tuple variablesTuple) {
56 Set<PVariable> result = new HashSet<PVariable>();
57 for (Integer index : indices) {
58 result.add((PVariable) variablesTuple.get(index));
59 }
60 return result;
61 }
62
63 }
64
65}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeInfoProviderConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeInfoProviderConstraint.java
new file mode 100644
index 00000000..ff127d38
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeInfoProviderConstraint.java
@@ -0,0 +1,28 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem;
11
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
15
16/**
17 * @author Gabor Bergmann
18 *
19 */
20public interface ITypeInfoProviderConstraint extends PConstraint {
21
22 /**
23 * Returns type information implied by this constraint.
24 *
25 */
26 public Set<TypeJudgement> getImpliedJudgements(IQueryMetaContext context);
27
28}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IValueProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IValueProvider.java
new file mode 100644
index 00000000..d959adc4
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IValueProvider.java
@@ -0,0 +1,27 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem;
10
11/**
12 * Helper interface to get values from a tuple of variables. All pattern matching engines are expected to implement this
13 * to handle their internal structures.
14 *
15 * @author Zoltan Ujhelyi
16 *
17 */
18public interface IValueProvider {
19
20 /**
21 * Returns the value of the selected variable
22 * @param variableName
23 * @return the value of the variable; never null
24 * @throws IllegalArgumentException if the variable is not defined
25 */
26 Object getValue(String variableName);
27}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/InitializablePQuery.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/InitializablePQuery.java
new file mode 100644
index 00000000..a82d12ec
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/InitializablePQuery.java
@@ -0,0 +1,56 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem;
10
11import java.util.Set;
12
13import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
14import tools.refinery.viatra.runtime.matchers.psystem.annotations.PAnnotation;
15import tools.refinery.viatra.runtime.matchers.psystem.queries.PProblem;
16import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
17
18/**
19 * Adds extra methods to the PQuery interface to initialize its contents.
20 *
21 * @author Zoltan Ujhelyi
22 *
23 */
24public interface InitializablePQuery extends PQuery {
25
26 /**
27 * Sets the query status. Only applicable if the pattern is still {@link PQueryStatus#UNINITIALIZED uninitialized}.
28 *
29 * @param status the new status
30 */
31 void setStatus(PQueryStatus status);
32
33 /**
34 * Adds a detected error. Only applicable if the pattern is still {@link PQueryStatus#UNINITIALIZED uninitialized}.
35 *
36 * @param problem the new problem
37 */
38 void addError(PProblem problem);
39
40 /**
41 * Sets up the bodies of the pattern. Only applicable if the pattern is still {@link PQueryStatus#UNINITIALIZED
42 * uninitialized}.
43 *
44 * @param bodies
45 * @throws ViatraQueryRuntimeException
46 */
47 void initializeBodies(Set<PBody> bodies);
48
49 /**
50 * Adds an annotation to the specification. Only applicable if the pattern is still
51 * {@link PQueryStatus#UNINITIALIZED uninitialized}.
52 *
53 * @param annotation
54 */
55 void addAnnotation(PAnnotation annotation);
56}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/KeyedEnumerablePConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/KeyedEnumerablePConstraint.java
new file mode 100644
index 00000000..91eea817
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/KeyedEnumerablePConstraint.java
@@ -0,0 +1,39 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem;
11
12import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
13
14/**
15 * @author Gabor Bergmann
16 *
17 */
18public abstract class KeyedEnumerablePConstraint<KeyType> extends EnumerablePConstraint {
19
20 protected KeyType supplierKey;
21
22 public KeyedEnumerablePConstraint(PBody pBody, Tuple variablesTuple,
23 KeyType supplierKey) {
24 super(pBody, variablesTuple);
25 this.supplierKey = supplierKey;
26 }
27
28 @Override
29 protected String toStringRestRest() {
30 return supplierKey == null ? "$any(null)" : keyToString();
31 }
32
33 protected abstract String keyToString();
34
35 public KeyType getSupplierKey() {
36 return supplierKey;
37 }
38
39}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PBody.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PBody.java
new file mode 100644
index 00000000..c38dc23a
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PBody.java
@@ -0,0 +1,289 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem;
11
12import java.util.ArrayList;
13import java.util.HashMap;
14import java.util.HashSet;
15import java.util.LinkedHashSet;
16import java.util.List;
17import java.util.Map;
18import java.util.Set;
19import java.util.WeakHashMap;
20import java.util.stream.Collectors;
21
22import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
23import tools.refinery.viatra.runtime.matchers.planning.helpers.TypeHelper;
24import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExportedParameter;
25import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.ConstantValue;
26import tools.refinery.viatra.runtime.matchers.psystem.queries.PDisjunction;
27import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
28import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery.PQueryStatus;
29import tools.refinery.viatra.runtime.matchers.util.Preconditions;
30
31/**
32 * A set of constraints representing a pattern body
33 *
34 * @author Gabor Bergmann
35 *
36 */
37public class PBody implements PTraceable {
38
39 public static final String VIRTUAL_VARIABLE_PREFIX = ".virtual";
40 private static final String VIRTUAL_VARIABLE_PATTERN = VIRTUAL_VARIABLE_PREFIX + "{%d}";
41
42 private PQuery query;
43
44 /**
45 * If null, then parent query status is reused
46 */
47 private PQueryStatus status = PQueryStatus.UNINITIALIZED;
48
49 private Set<PVariable> allVariables;
50 private Set<PVariable> uniqueVariables;
51 private List<ExportedParameter> symbolicParameters;
52 private Map<Object, PVariable> variablesByName;
53 private Set<PConstraint> constraints;
54 private int nextVirtualNodeID;
55 private PDisjunction containerDisjunction;
56
57 public PBody(PQuery query) {
58 super();
59 this.query = query;
60 allVariables = new LinkedHashSet<>();
61 uniqueVariables = new LinkedHashSet<>();
62 variablesByName = new HashMap<>();
63 constraints = new LinkedHashSet<>();
64 }
65
66 /**
67 * @return whether the submission of the new variable was successful
68 */
69 private boolean addVariable(PVariable var) {
70 checkMutability();
71 Object name = var.getName();
72 if (!variablesByName.containsKey(name)) {
73 allVariables.add(var);
74 if (var.isUnique())
75 uniqueVariables.add(var);
76 variablesByName.put(name, var);
77 return true;
78 } else {
79 return false;
80 }
81 }
82
83 /**
84 * Use this method to add a newly created constraint to the pSystem.
85 *
86 * @return whether the submission of the new constraint was successful
87 */
88 boolean registerConstraint(PConstraint constraint) {
89 checkMutability();
90 return constraints.add(constraint);
91 }
92
93 /**
94 * Use this method to remove an obsolete constraint from the pSystem.
95 *
96 * @return whether the removal of the constraint was successful
97 */
98 boolean unregisterConstraint(PConstraint constraint) {
99 checkMutability();
100 return constraints.remove(constraint);
101 }
102
103 @SuppressWarnings("unchecked")
104 public <ConstraintType> Set<ConstraintType> getConstraintsOfType(Class<ConstraintType> constraintClass) {
105 Set<ConstraintType> result = new HashSet<ConstraintType>();
106 for (PConstraint pConstraint : constraints) {
107 if (constraintClass.isInstance(pConstraint))
108 result.add((ConstraintType) pConstraint);
109 }
110 return result;
111 }
112
113 public PVariable newVirtualVariable() {
114 checkMutability();
115 String name;
116 do {
117
118 name = String.format(VIRTUAL_VARIABLE_PATTERN, nextVirtualNodeID++);
119 } while (variablesByName.containsKey(name));
120 PVariable var = new PVariable(this, name, true);
121 addVariable(var);
122 return var;
123 }
124
125 public PVariable newVirtualVariable(String name) {
126 checkMutability();
127 Preconditions.checkArgument(!variablesByName.containsKey(name), "ID %s already used for a virtual variable", name);
128 PVariable var = new PVariable(this, name, true);
129 addVariable(var);
130 return var;
131 }
132
133 public PVariable newConstantVariable(Object value) {
134 checkMutability();
135 PVariable virtual = newVirtualVariable();
136 new ConstantValue(this, virtual, value);
137 return virtual;
138 }
139
140 public Set<PVariable> getAllVariables() {
141 return allVariables;
142 }
143
144 public Set<PVariable> getUniqueVariables() {
145 return uniqueVariables;
146 }
147
148 private PVariable getVariableByName(Object name) {
149 return variablesByName.get(name).getUnifiedIntoRoot();
150 }
151
152 /**
153 * Find a PVariable by name
154 *
155 * @param name
156 * @return the found variable
157 * @throws IllegalArgumentException
158 * if no PVariable is found with the selected name
159 */
160 public PVariable getVariableByNameChecked(Object name) {
161 if (!variablesByName.containsKey(name))
162 throw new IllegalArgumentException(String.format("Cannot find PVariable %s", name));
163 return getVariableByName(name);
164 }
165
166 /**
167 * Finds and returns a PVariable by name. If no PVariable exists with the name in the body, a new one is created. If
168 * the name of the variable starts with {@value #VIRTUAL_VARIABLE_PREFIX}, the created variable will be considered
169 * virtual.
170 *
171 * @param name
172 * @return a PVariable with the selected name; never null
173 */
174 public PVariable getOrCreateVariableByName(String name) {
175 checkMutability();
176 if (!variablesByName.containsKey(name)) {
177 addVariable(new PVariable(this, name, name.startsWith(VIRTUAL_VARIABLE_PREFIX)));
178 }
179 return getVariableByName(name);
180 }
181
182 public Set<PConstraint> getConstraints() {
183 return constraints;
184 }
185
186 public PQuery getPattern() {
187 return query;
188 }
189
190 void noLongerUnique(PVariable pVariable) {
191 assert (!pVariable.isUnique());
192 uniqueVariables.remove(pVariable);
193 }
194
195 /**
196 * Returns the symbolic parameters of the body. </p>
197 *
198 * <p>
199 * <strong>Warning</strong>: if two PVariables are unified, the returned list changes. If you want to have a stable
200 * version, consider using {@link #getSymbolicParameters()}.
201 *
202 * @return a non-null, but possibly empty list
203 */
204 public List<PVariable> getSymbolicParameterVariables() {
205 return getSymbolicParameters().stream().map(ExportedParameter::getParameterVariable)
206 .collect(Collectors.toList());
207 }
208
209 /**
210 * Returns the exported parameter constraints of the body.
211 *
212 * @return a non-null, but possibly empty list
213 */
214 public List<ExportedParameter> getSymbolicParameters() {
215 if (symbolicParameters == null)
216 symbolicParameters = new ArrayList<>();
217 return symbolicParameters;
218 }
219
220 /**
221 * Sets the exported parameter constraints of the body, if this instance is mutable.
222 * @param symbolicParameters the new value
223 */
224 public void setSymbolicParameters(List<ExportedParameter> symbolicParameters) {
225 checkMutability();
226 this.symbolicParameters = new ArrayList<>(symbolicParameters);
227 }
228
229 /**
230 * Sets a specific status for the body. If set, the parent PQuery status will not be checked; if set to null, its corresponding PQuery
231 * status is checked for mutability.
232 *
233 * @param status
234 * the status to set
235 */
236 public void setStatus(PQueryStatus status) {
237 this.status = status;
238 }
239
240 public boolean isMutable() {
241 if (status == null) {
242 return query.isMutable();
243 } else {
244 return status.equals(PQueryStatus.UNINITIALIZED);
245 }
246 }
247
248 void checkMutability() {
249 if (status == null) {
250 query.checkMutability();
251 } else {
252 Preconditions.checkState(status.equals(PQueryStatus.UNINITIALIZED), "Initialized queries are not mutable");
253 }
254 }
255
256 /**
257 * Returns the disjunction the body is contained with. This disjunction may either be the
258 * {@link PQuery#getDisjunctBodies() canonical disjunction of the corresponding query} or something equivalent.
259 *
260 * @return the container disjunction of the body. Can be null if body is not in a disjunction yet.
261 */
262 public PDisjunction getContainerDisjunction() {
263 return containerDisjunction;
264 }
265
266 /**
267 * @param containerDisjunction the containerDisjunction to set
268 */
269 public void setContainerDisjunction(PDisjunction containerDisjunction) {
270 Preconditions.checkArgument(query.equals(containerDisjunction.getQuery()), "Disjunction of pattern %s incompatible with body %s", containerDisjunction.getQuery().getFullyQualifiedName(), query.getFullyQualifiedName());
271 Preconditions.checkState(this.containerDisjunction == null, "Disjunction is already set.");
272 this.containerDisjunction = containerDisjunction;
273 }
274
275 /**
276 * All unary input keys directly prescribed by constraints, grouped by variable.
277 * <p> to supertype inference or subsumption applied at this point.
278 */
279 public Map<PVariable, Set<TypeJudgement>> getAllUnaryTypeRestrictions(IQueryMetaContext context) {
280 Map<PVariable, Set<TypeJudgement>> currentRestrictions = allUnaryTypeRestrictions.get(context);
281 if (currentRestrictions == null) {
282 currentRestrictions = TypeHelper.inferUnaryTypes(getConstraints(), context);
283 allUnaryTypeRestrictions.put(context, currentRestrictions);
284 }
285 return currentRestrictions;
286 }
287 private WeakHashMap<IQueryMetaContext, Map<PVariable, Set<TypeJudgement>>> allUnaryTypeRestrictions = new WeakHashMap<IQueryMetaContext, Map<PVariable,Set<TypeJudgement>>>();
288
289}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PConstraint.java
new file mode 100644
index 00000000..ae2c4632
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PConstraint.java
@@ -0,0 +1,70 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem;
11
12import java.util.Comparator;
13import java.util.Map;
14import java.util.Set;
15
16import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
17import tools.refinery.viatra.runtime.matchers.psystem.analysis.QueryAnalyzer;
18
19/**
20 * @author Gabor Bergmann
21 *
22 */
23public interface PConstraint extends PTraceable {
24
25 /**
26 * @since 2.1
27 * @return the query body this constraint belongs to
28 */
29 public PBody getBody();
30
31 /**
32 * All variables affected by this constraint.
33 */
34 public Set<PVariable> getAffectedVariables();
35
36 /**
37 * The set of variables whose potential values can be enumerated (once all non-deduced variables have known values).
38 */
39 public Set<PVariable> getDeducedVariables();
40
41 /**
42 * A (preferably minimal) cover of known functional dependencies between variables.
43 * @noreference Use {@link QueryAnalyzer} instead to properly handle dependencies of pattern calls.
44 * @return non-trivial functional dependencies in the form of {variables} --> {variables}, where dependencies with the same lhs are unified.
45 */
46 public Map<Set<PVariable>,Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context);
47
48 public void replaceVariable(PVariable obsolete, PVariable replacement);
49
50 public void delete();
51
52 public void checkSanity();
53
54 /**
55 * Returns an integer ID that is guaranteed to increase strictly monotonously for constraints within a pBody.
56 */
57 public abstract int getMonotonousID();
58
59
60 /**
61 * A comparator that orders constraints by their {@link #getMonotonousID() monotonous identifiers}. Should only used
62 * for tiebreaking in other comparators.
63 *
64 * @since 2.0
65 */
66 public static final Comparator<PConstraint> COMPARE_BY_MONOTONOUS_ID = (arg0, arg1) -> arg0.getMonotonousID() - arg1.getMonotonousID();
67
68
69
70}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PTraceable.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PTraceable.java
new file mode 100644
index 00000000..f0241a9c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PTraceable.java
@@ -0,0 +1,16 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Dénes Harmath, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem;
10
11/**
12 * Marker interface for PSystem elements that can be traced.
13 * @since 1.6
14 */
15public interface PTraceable {
16}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PVariable.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PVariable.java
new file mode 100644
index 00000000..b6ea4861
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PVariable.java
@@ -0,0 +1,203 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem;
11
12import java.util.HashSet;
13import java.util.Set;
14
15/**
16 * @author Gabor Bergmann
17 *
18 */
19public class PVariable {
20 private PBody pBody;
21 /**
22 * The name of the pattern variable. This is the unique key of the pattern node.
23 */
24 private String name;
25 /**
26 * virtual pVariables are nodes that do not correspond to actual pattern variables; they represent constants or Term
27 * substitutes
28 */
29 private boolean virtual;
30
31 /**
32 * Set of constraints that mention this variable
33 */
34 private Set<PConstraint> referringConstraints;
35
36 /**
37 * Determines whether there are any constraints that can deduce this variable
38 */
39 private Boolean deducable;
40
41 /**
42 * Another PVariable this variable has been unified into. Please use the other variable instead of this. Null iff
43 * this is still a first-class variable.
44 */
45 private PVariable unifiedInto;
46
47 PVariable(PBody pBody, String name) {
48 this(pBody, name, false);
49 }
50
51 PVariable(PBody pBody, String name, boolean virtual) {
52 super();
53 this.pBody = pBody;
54 this.name = name;
55 this.virtual = virtual;
56 // this.exportedParameter = false;
57 this.referringConstraints = new HashSet<PConstraint>();
58 this.unifiedInto = null;
59 this.deducable = false;
60 }
61
62 /**
63 * Replaces this variable with a given other, resulting in their unification. This variable will no longer be
64 * unique.
65 *
66 * @param replacement
67 */
68 public void unifyInto(PVariable replacement) {
69 pBody.checkMutability();
70 replacementCheck();
71 replacement = replacement.getUnifiedIntoRoot();
72
73 if (this.equals(replacement))
74 return;
75
76 if (!this.isVirtual() && replacement.isVirtual()) {
77 replacement.unifyInto(this);
78 } else {
79 // replacement.referringConstraints.addAll(this.referringConstraints);
80 // replacement.exportedParameter |= this.exportedParameter;
81 replacement.virtual &= this.virtual;
82 if (replacement.deducable != null && this.deducable != null)
83 replacement.deducable |= this.deducable;
84 else
85 replacement.deducable = null;
86 Set<PConstraint> snapshotConstraints = // avoid ConcurrentModificationX
87 new HashSet<PConstraint>(this.referringConstraints);
88 for (PConstraint constraint : snapshotConstraints) {
89 constraint.replaceVariable(this, replacement);
90 }
91 // replacementCheck() will fail from this point
92 this.unifiedInto = replacement;
93 pBody.noLongerUnique(this);
94 }
95 }
96
97 /**
98 * Determines whether there are any constraints that can deduce this variable
99 */
100 public boolean isDeducable() {
101 replacementCheck();
102 if (deducable == null) {
103 deducable = false;
104 for (PConstraint pConstraint : getReferringConstraints()) {
105 if (pConstraint.getDeducedVariables().contains(this)) {
106 deducable = true;
107 break;
108 }
109 }
110 }
111 return deducable;
112 }
113
114 /**
115 * Register that this variable is referred by the given constraint.
116 *
117 * @param constraint
118 */
119 public void refer(PConstraint constraint) {
120 pBody.checkMutability();
121 replacementCheck();
122 deducable = null;
123 referringConstraints.add(constraint);
124 }
125
126 /**
127 * Register that this variable is no longer referred by the given constraint.
128 *
129 * @param constraint
130 */
131 public void unrefer(PConstraint constraint) {
132 pBody.checkMutability();
133 replacementCheck();
134 deducable = null;
135 referringConstraints.remove(constraint);
136 }
137
138 /**
139 * @return the name of the pattern variable. This is the unique key of the pattern node.
140 */
141 public String getName() {
142 replacementCheck();
143 return name;
144 }
145
146 /**
147 * @return the virtual
148 */
149 public boolean isVirtual() {
150 replacementCheck();
151 return virtual;
152 }
153
154 /**
155 * @return the referringConstraints
156 */
157 public Set<PConstraint> getReferringConstraints() {
158 replacementCheck();
159 return referringConstraints;
160 }
161
162 @SuppressWarnings("unchecked")
163 public <ConstraintType> Set<ConstraintType> getReferringConstraintsOfType(Class<ConstraintType> constraintClass) {
164 replacementCheck();
165 Set<ConstraintType> result = new HashSet<ConstraintType>();
166 for (PConstraint pConstraint : referringConstraints) {
167 if (constraintClass.isInstance(pConstraint))
168 result.add((ConstraintType) pConstraint);
169 }
170 return result;
171 }
172
173 @Override
174 public String toString() {
175 // replacementCheck();
176 return name;// + ":PatternNode";
177 }
178
179 public PVariable getDirectUnifiedInto() {
180 return unifiedInto;
181 }
182
183 public PVariable getUnifiedIntoRoot() {
184 PVariable nextUnified = unifiedInto;
185 PVariable oldUnifiedInto = this;
186 while (nextUnified != null) {
187 oldUnifiedInto = nextUnified;
188 nextUnified = oldUnifiedInto.getDirectUnifiedInto();
189 }
190 return oldUnifiedInto; // unifiedInto;
191 }
192
193 public boolean isUnique() {
194 return unifiedInto == null;
195 }
196
197 private void replacementCheck() {
198 if (unifiedInto != null)
199 throw new IllegalStateException("Illegal usage of variable " + name + " which has been replaced with "
200 + unifiedInto.name);
201 }
202
203}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/TypeJudgement.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/TypeJudgement.java
new file mode 100644
index 00000000..4447b225
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/TypeJudgement.java
@@ -0,0 +1,153 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem;
10
11import java.util.Collection;
12import java.util.HashSet;
13import java.util.List;
14import java.util.Map;
15import java.util.stream.Collectors;
16import java.util.Set;
17
18import tools.refinery.viatra.runtime.matchers.context.IInputKey;
19import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
20import tools.refinery.viatra.runtime.matchers.context.InputKeyImplication;
21import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.TypeFilterConstraint;
22import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.TypeConstraint;
23import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
24import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
25
26/**
27 * A judgement that means that the given tuple of variables will represent a tuple of values that is a member of the extensional relation identified by the given input key.
28 * @author Bergmann Gabor
29 *
30 */
31public class TypeJudgement {
32
33 private IInputKey inputKey;
34 private Tuple variablesTuple;
35 /**
36 * @param inputKey
37 * @param variablesTuple
38 */
39 public TypeJudgement(IInputKey inputKey, Tuple variablesTuple) {
40 super();
41 this.inputKey = inputKey;
42 this.variablesTuple = variablesTuple;
43 }
44 public IInputKey getInputKey() {
45 return inputKey;
46 }
47 public Tuple getVariablesTuple() {
48 return variablesTuple;
49 }
50 @Override
51 public int hashCode() {
52 final int prime = 31;
53 int result = 1;
54 result = prime * result
55 + ((inputKey == null) ? 0 : inputKey.hashCode());
56 result = prime * result
57 + ((variablesTuple == null) ? 0 : variablesTuple.hashCode());
58 return result;
59 }
60 @Override
61 public boolean equals(Object obj) {
62 if (this == obj)
63 return true;
64 if (obj == null)
65 return false;
66 if (!(obj instanceof TypeJudgement))
67 return false;
68 TypeJudgement other = (TypeJudgement) obj;
69 if (inputKey == null) {
70 if (other.inputKey != null)
71 return false;
72 } else if (!inputKey.equals(other.inputKey))
73 return false;
74 if (variablesTuple == null) {
75 if (other.variablesTuple != null)
76 return false;
77 } else if (!variablesTuple.equals(other.variablesTuple))
78 return false;
79 return true;
80 }
81
82 public Set<TypeJudgement> getDirectlyImpliedJudgements(IQueryMetaContext context) {
83 Set<TypeJudgement> results = new HashSet<TypeJudgement>();
84 results.add(this);
85
86 Collection<InputKeyImplication> implications = context.getImplications(this.inputKey);
87 for (InputKeyImplication inputKeyImplication : implications) {
88 results.add(
89 transcribeImplication(inputKeyImplication)
90 );
91 }
92
93 return results;
94 }
95
96 /**
97 * @since 1.6
98 */
99 public Set<TypeJudgement> getWeakenedAlternativeJudgements(IQueryMetaContext context) {
100 Set<TypeJudgement> results = new HashSet<TypeJudgement>();
101
102 Collection<InputKeyImplication> implications = context.getWeakenedAlternatives(this.inputKey);
103 for (InputKeyImplication inputKeyImplication : implications) {
104 results.add(
105 transcribeImplication(inputKeyImplication)
106 );
107 }
108
109 return results;
110 }
111
112 /**
113 * @since 2.0
114 */
115 public Map<TypeJudgement, Set<TypeJudgement>> getConditionalImpliedJudgements(IQueryMetaContext context) {
116 return context.getConditionalImplications(this.inputKey).entrySet().stream().collect(Collectors.toMap(
117 entry -> transcribeImplication(entry.getKey()),
118 entry -> entry.getValue().stream().map(this::transcribeImplication).collect(Collectors.toSet())));
119 }
120
121
122
123 private TypeJudgement transcribeImplication(InputKeyImplication inputKeyImplication) {
124 return new TypeJudgement(
125 inputKeyImplication.getImpliedKey(),
126 transcribeVariablesToTuple(inputKeyImplication.getImpliedIndices())
127 );
128 }
129 private Tuple transcribeVariablesToTuple(List<Integer> indices) {
130 Object[] elements = new Object[indices.size()];
131 for (int i = 0; i < indices.size(); ++i)
132 elements[i] = variablesTuple.get(indices.get(i));
133 return Tuples.flatTupleOf(elements);
134 }
135
136 @Override
137 public String toString() {
138 return "TypeJudgement:" + inputKey.getPrettyPrintableName() + "@" + variablesTuple.toString();
139 }
140
141 /**
142 * Creates this judgement as a direct type constraint in the given PBody under construction.
143 * <p> pre: the variables tuple must be formed of variables of that PBody.
144 * @since 1.6
145 */
146 public PConstraint createConstraintFor(PBody pBody) {
147 if (inputKey.isEnumerable()) {
148 return new TypeConstraint(pBody, variablesTuple, inputKey);
149 } else {
150 return new TypeFilterConstraint(pBody, variablesTuple, inputKey);
151 }
152 }
153}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/VariableDeferredPConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/VariableDeferredPConstraint.java
new file mode 100644
index 00000000..8ea6bb93
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/VariableDeferredPConstraint.java
@@ -0,0 +1,40 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem;
11
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
15import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
16
17/**
18 * A kind of deferred constraint that can only be checked when a set of deferring variables are all present in a plan.
19 *
20 * @author Gabor Bergmann
21 *
22 */
23public abstract class VariableDeferredPConstraint extends DeferredPConstraint {
24
25 public VariableDeferredPConstraint(PBody pBody,
26 Set<PVariable> affectedVariables) {
27 super(pBody, affectedVariables);
28 }
29
30 public abstract Set<PVariable> getDeferringVariables();
31
32 /**
33 * Refine further if needed
34 */
35 @Override
36 public boolean isReadyAt(SubPlan plan, IQueryMetaContext context) {
37 return plan.getVisibleVariables().containsAll(getDeferringVariables());
38 }
39
40}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AbstractMemorylessAggregationOperator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AbstractMemorylessAggregationOperator.java
new file mode 100644
index 00000000..63a37bbe
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AbstractMemorylessAggregationOperator.java
@@ -0,0 +1,31 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.aggregations;
10
11/**
12 *
13 * An aggregation operator that does not store interim results beyond the final aggregated value.
14 * @author Gabor Bergmann
15 * @since 1.4
16 */
17public abstract class AbstractMemorylessAggregationOperator<Domain, AggregateResult>
18 implements IMultisetAggregationOperator<Domain, AggregateResult, AggregateResult>
19{
20
21 @Override
22 public AggregateResult getAggregate(AggregateResult result) {
23 return result;
24 }
25
26 @Override
27 public AggregateResult clone(AggregateResult original) {
28 return original;
29 }
30
31}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AggregatorType.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AggregatorType.java
new file mode 100644
index 00000000..4cc40a2b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AggregatorType.java
@@ -0,0 +1,49 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.aggregations;
10
11import java.lang.annotation.ElementType;
12import java.lang.annotation.Inherited;
13import java.lang.annotation.Retention;
14import java.lang.annotation.RetentionPolicy;
15import java.lang.annotation.Target;
16
17import tools.refinery.viatra.runtime.matchers.aggregators.count;
18
19/**
20 * The aggregator type annotation describes the type constraints for the selected aggregator. In version 1.4, two kinds of
21 * aggregators are supported:
22 *
23 * <ol>
24 * <li>An aggregator that does not consider any parameter value from the call ({@link count}), just calculates the
25 * number of matches. This is represented by a single {@link Void} and a single corresponding return type.</li>
26 * <li>An aggregator that considers a single parameter from the call, and executes some aggregate operations over it.
27 * Such an aggregate operation can be defined over multiple types, where each possible parameter type has a corresponding return type declared.</li>
28 * </ol>
29 *
30 * <strong>Important!</strong> The parameterTypes and returnTypes arrays must have
31 * <ul>
32 * <li>The same number of classes defined each.</li>
33 * <li>Items are corresponded by index.</li>
34 * <li>Items should represent data types</li>
35 * </ul>
36 *
37 * @author Zoltan Ujhelyi
38 * @since 1.4
39 *
40 */
41@Target({ ElementType.TYPE })
42@Retention(RetentionPolicy.RUNTIME)
43@Inherited
44public @interface AggregatorType {
45
46 Class<?>[] parameterTypes();
47
48 Class<?>[] returnTypes();
49}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/BoundAggregator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/BoundAggregator.java
new file mode 100644
index 00000000..e6972544
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/BoundAggregator.java
@@ -0,0 +1,61 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.aggregations;
10
11import tools.refinery.viatra.runtime.matchers.context.IInputKey;
12import tools.refinery.viatra.runtime.matchers.context.common.JavaTransitiveInstancesKey;
13
14/**
15 * Augments an aggregator operator with type bindings for the type of values being aggregated and the aggregate result.
16 * <p> In case of <em>count</em>, the operator should be null.
17 * @author Gabor Bergmann
18 * @since 1.4
19 */
20public class BoundAggregator {
21 private final IMultisetAggregationOperator<?, ?, ?> operator;
22 private final Class<?> domainType;
23 private final Class<?> aggregateResultType;
24
25 public BoundAggregator(IMultisetAggregationOperator<?, ?, ?> operator,
26 Class<?> domainType,
27 Class<?> aggregateResultType) {
28 super();
29 this.operator = operator;
30 this.domainType = domainType;
31 this.aggregateResultType = aggregateResultType;
32 }
33
34 public IMultisetAggregationOperator<?, ?, ?> getOperator() {
35 return operator;
36 }
37
38 public Class<?> getDomainType() {
39 return domainType;
40 }
41
42 public Class<?> getAggregateResultType() {
43 return aggregateResultType;
44 }
45
46 public IInputKey getDomainTypeAsInputKey() {
47 return toJavaInputKey(domainType);
48 }
49
50 public IInputKey getAggregateResultTypeAsInputKey() {
51 return toJavaInputKey(aggregateResultType);
52 }
53
54 private static IInputKey toJavaInputKey(Class<?> type) {
55 if (type==null) {
56 return null;
57 } else {
58 return new JavaTransitiveInstancesKey(type);
59 }
60 }
61}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IAggregatorFactory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IAggregatorFactory.java
new file mode 100644
index 00000000..c970bd6a
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IAggregatorFactory.java
@@ -0,0 +1,40 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Zoltan Ujhelyi, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.aggregations;
10
11/**
12 *
13 * Describes an aggregation operator keyword, potentially with type polymorphism. The actual runtime
14 * {@link IMultisetAggregationOperator} that implements the aggregation logic may depend on the type context.
15 *
16 * <p>
17 * Implementors are suggested to use lower-case classnames (as it will end up in the language) and are required use the
18 * annotation {@link AggregatorType} to indicate type inference rules.
19 *
20 * <p>
21 * <strong>Important!</strong> Implemented aggregators must be (1) deterministic (2) pure and (3)support incremental
22 * value updates in the internal operation.
23 *
24 * @author Zoltan Ujhelyi
25 * @since 1.4
26 */
27
28public interface IAggregatorFactory {
29
30 /**
31 * Given type parameters selected from {@link AggregatorType} annotations, returns a run-time aggregator operator
32 * that is bound to the actual types.
33 *
34 * @param domainClass
35 * Java type of the values that are being aggregated
36 * @return the actual run-time aggregator logic, with type bindings
37 */
38 public BoundAggregator getAggregatorLogic(Class<?> domainClass);
39
40}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IMultisetAggregationOperator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IMultisetAggregationOperator.java
new file mode 100644
index 00000000..3bc22274
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IMultisetAggregationOperator.java
@@ -0,0 +1,106 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.aggregations;
10
11import java.util.Collection;
12import java.util.stream.Stream;
13
14import tools.refinery.viatra.runtime.matchers.aggregators.ExtremumOperator;
15
16/**
17 * A single column aggregator is used to incrementally compute the aggregate of a multiset of values according to an aggregator operator.
18 *
19 * <p> The operator provides two methods of computation: <ul>
20 * <li>Stateless aggregation of an explicit multiset, provided by {@link #aggregateStatelessly(Collection)}.</li>
21 * <li>Incremental aggregation, provided by {@link #createNeutral()}, {@link #update(Object, Object, boolean)}, {@link #isNeutral(Object)}, {@link #getAggregate(Object)}.
22 * </ul>
23 *
24 * <p> In case of incremental computation, the aggregable multiset is conceptual; it is not represented by an explicit Collection<Domain> object, but its update operations are tracked.
25 *
26 * <p> In case of incremental computation, internal results, potentially distinct from the final aggregate result, may be stored in a helper data structure called <b>accumulator</b>.
27 * The goal of this distinction is that the final result may not be sufficient for incremental updates (see e.g. {@link ExtremumOperator}).
28 *
29 * @author Gabor Bergmann
30 *
31 * @param <Domain> the type of elements to be aggregated.
32 * @param <Accumulator> the type used to store the interim results of the aggregate computation,
33 * that may be incrementally refreshed upon updates to the multiset, and that can easily yield the final result.
34 * @param <AggregateResult> the type of the final result of the aggregation to be output.
35 *
36 * @since 1.4
37 */
38public interface IMultisetAggregationOperator<Domain, Accumulator, AggregateResult> {
39
40 /**
41 * A textual description of the operator.
42 */
43 String getShortDescription();
44
45 /**
46 * A name or identifier of the operator.
47 */
48 String getName();
49
50 /**
51 * @return the neutral element, i.e. the interim result of aggregating an empty multiset.
52 */
53 Accumulator createNeutral();
54
55 /**
56 * @return true if the interim result is equivalent to the neutral element, as if there are no values in the multiset.
57 * Must return true if the multiset is empty.
58 */
59 boolean isNeutral(Accumulator result);
60
61 /**
62 * @return an updated intermediate result,
63 * changed to reflect that a given object was added to / removed from the multiset
64 * (as indicated by the parameter isInsertion)
65 */
66 Accumulator update(Accumulator oldResult, Domain updateValue, boolean isInsertion);
67
68 /**
69 * @return the aggregate result obtained from the given intermediate result.
70 * May be null to indicate that the current multiset cannot be aggregated (e.g. 0 elements have no minimum).
71 */
72 AggregateResult getAggregate(Accumulator result);
73
74 /**
75 * Calculates the aggregate results from a given stream of values; all values are considered as inserted
76 * @return the aggregate result, or null if no result can be calculated (e.g. because of an empty stream)
77 * @since 2.0
78 */
79 AggregateResult aggregateStream(Stream<Domain> stream);
80
81 /**
82 * Clones the given accumulator (with all its internal contents).
83 */
84 default Accumulator clone(Accumulator original) {
85 throw new UnsupportedOperationException();
86 }
87
88 /**
89 * Combines the given aggregate result and accumulator into a single aggregate result.
90 */
91 default AggregateResult combine(AggregateResult left, Accumulator right) {
92 throw new UnsupportedOperationException();
93 }
94
95 default boolean contains(Domain value, Accumulator accumulator) {
96 throw new UnsupportedOperationException();
97 }
98
99 /**
100 * Pretty prints the contents of the given accumulator.
101 */
102 default String prettyPrint(final Accumulator accumulator) {
103 return accumulator.toString();
104 }
105
106}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/analysis/QueryAnalyzer.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/analysis/QueryAnalyzer.java
new file mode 100644
index 00000000..e3f28cff
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/analysis/QueryAnalyzer.java
@@ -0,0 +1,194 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.analysis;
10
11import java.util.HashMap;
12import java.util.HashSet;
13import java.util.Map;
14import java.util.Map.Entry;
15import java.util.Set;
16import java.util.stream.Collectors;
17
18import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
19import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
20import tools.refinery.viatra.runtime.matchers.planning.helpers.FunctionalDependencyHelper;
21import tools.refinery.viatra.runtime.matchers.psystem.PBody;
22import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
23import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
24import tools.refinery.viatra.runtime.matchers.psystem.annotations.PAnnotation;
25import tools.refinery.viatra.runtime.matchers.psystem.annotations.ParameterReference;
26import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExportedParameter;
27import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
28import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
29import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
30
31/**
32 * Object responsible for computing and caching static query analysis results.
33 * <p> Any client can instantiate this to statically analyze queries.
34 * Query backends should share an instance obtained via {@link IQueryBackendContext} to save resources.
35 * <p> Precondition: all involved queries must be initialized.
36 * @noinstantiate Considered unstable API; subject to change in future versions.
37 * Either use the analyzer provided by {@link IQueryBackendContext}, or anticipate
38 * potential future breakage when instantiating your own analyzer.
39 * @author Gabor Bergmann
40 * @since 1.5
41 */
42public final class QueryAnalyzer {
43
44 private IQueryMetaContext metaContext;
45
46 public QueryAnalyzer(IQueryMetaContext metaContext) {
47 this.metaContext = metaContext;
48 }
49
50 // Functional dependencies
51
52 /**
53 * Maps query and strictness to functional dependencies
54 */
55 private Map<PQuery, Map<Set<Integer>, Set<Integer>>> strictFunctionalDependencyGuarantees =
56 new HashMap<>();
57 private Map<PQuery, Map<Set<Integer>, Set<Integer>>> softFunctionalDependencyGuarantees =
58 new HashMap<>();
59
60 /**
61 * Functional dependency information, expressed on query parameters, that the match set of the query is guaranteed to respect.
62 * <p> The type dependencies shall be expressed on the <i>parameter index</i> integers, NOT the {@link PParameter} object.
63 * @return a non-null map of functional dependencies on parameters that can be processed by {@link FunctionalDependencyHelper}
64 * @param strict if true, only "hard" dependencies are taken into account that are strictly enforced by the model representation;
65 * if false, user-provided soft dependencies (@FunctionalDependency) are included as well, that are anticipated but not guaranteed by the storage mechanism;
66 * use true if superfluous dependencies may taint the correctness of a computation, false if they would merely impact performance
67 * @since 1.5
68 */
69 public Map<Set<Integer>, Set<Integer>> getProjectedFunctionalDependencies(PQuery query, boolean strict) {
70 Map<PQuery, Map<Set<Integer>, Set<Integer>>> guaranteeStore = strict ? strictFunctionalDependencyGuarantees : softFunctionalDependencyGuarantees;
71 Map<Set<Integer>, Set<Integer>> dependencies = guaranteeStore.get(query);
72 // Why not computeIfAbsent? See Bug 532507
73 // Invoked method #computeFunctionalDependencies may trigger functional dependency computation for called queries;
74 // and may thus recurs back into #getProjectedFunctionalDependencies, causing a ConcurrentModificationException
75 // if the called query has not been previously analyzed.
76 //
77 // Note: if patterns are recursive, the empty accumulator will be found in the store
78 // (this yields a safe lower estimate and guarantees termination for #getProjectedFunctionalDependencies)
79 // But this case probably will not occur due to recursive queries having a disjunction at some point,
80 // and thus ignored by #computeFunctionalDependencies
81 if (dependencies == null) {
82 dependencies = new HashMap<>(); // accumulator
83 guaranteeStore.put(query, dependencies);
84 computeFunctionalDependencies(dependencies, query, strict);
85 }
86 return dependencies;
87 }
88
89 private void computeFunctionalDependencies(Map<Set<Integer>, Set<Integer>> accumulator, PQuery query, boolean strict) {
90 Set<PBody> bodies = query.getDisjunctBodies().getBodies();
91 if (bodies.size() == 1) { // no support for recursion or disjunction
92
93 PBody body = bodies.iterator().next();
94
95 // collect parameter variables
96 Map<PVariable, Integer> parameters = body.getSymbolicParameters().stream()
97 .collect(Collectors.toMap(ExportedParameter::getParameterVariable,
98 param -> query.getParameters().indexOf(param.getPatternParameter())));
99
100 // collect all internal dependencies
101 Map<Set<PVariable>, Set<PVariable>> internalDependencies =
102 getFunctionalDependencies(body.getConstraints(), strict);
103
104 // project onto parameter variables
105 Map<Set<PVariable>, Set<PVariable>> projectedDeps =
106 FunctionalDependencyHelper.projectDependencies(internalDependencies, parameters.keySet());
107
108 // translate into indices
109 for (Entry<Set<PVariable>, Set<PVariable>> entry : projectedDeps.entrySet()) {
110 Set<Integer> left = new HashSet<Integer>();
111 Set<Integer> right = new HashSet<Integer>();
112 for (PVariable pVariable : entry.getKey()) {
113 left.add(parameters.get(pVariable));
114 }
115 for (PVariable pVariable : entry.getValue()) {
116 right.add(parameters.get(pVariable));
117 }
118 accumulator.put(left, right);
119 }
120
121 } else {
122 // Disjunctive case, no dependencies are inferred
123 // TODO: we can still salvage the intersection of dependencies IF
124 // - all bodies have disjoint match sets
125 // - and we avoid recursion
126 }
127
128 // add annotation-based soft dependencies (regardless of number of bodies)
129 if (!strict) {
130 outer:
131 for (PAnnotation annotation : query.getAnnotationsByName("FunctionalDependency")) {
132 Set<Integer> lefts = new HashSet<Integer>();
133 Set<Integer> rights = new HashSet<Integer>();
134
135 for (Object object : annotation.getAllValues("forEach")) {
136 ParameterReference parameter = (ParameterReference) object;
137 Integer position = query.getPositionOfParameter(parameter.getName());
138 if (position == null) continue outer;
139 lefts.add(position);
140 }
141 for (Object object : annotation.getAllValues("unique")) {
142 ParameterReference parameter = (ParameterReference) object;
143 Integer position = query.getPositionOfParameter(parameter.getName());
144 if (position == null) continue outer;
145 rights.add(position);
146 }
147
148 FunctionalDependencyHelper.includeDependency(accumulator, lefts, rights);
149 }
150 }
151 }
152
153 /**
154 * Functional dependency information, expressed on PVariables within a body, that the selected constraints imply.
155 * @return a non-null map of functional dependencies on PVariables that can be processed by {@link FunctionalDependencyHelper}
156 * @param constraints the set of constraints whose consequences will be analyzed
157 * @param strict if true, only "hard" dependencies are taken into account that are strictly enforced by the model representation;
158 * if false, user-provided soft dependencies (@FunctionalDependency) are included as well, that are anticipated but not guaranteed by the storage mechanism;
159 * use true if superfluous dependencies may taint the correctness of a computation, false if they would merely impact performance
160 * @since 1.5
161 */
162 public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(Set<? extends PConstraint> constraints, boolean strict) {
163 Map<Set<PVariable>, Set<PVariable>> accumulator = new HashMap<Set<PVariable>, Set<PVariable>>();
164 for (PConstraint pConstraint : constraints){
165 if (pConstraint instanceof PositivePatternCall) {
166 // use query analysis results instead
167 PositivePatternCall call = (PositivePatternCall) pConstraint;
168 PQuery query = call.getSupplierKey();
169 Map<Set<Integer>, Set<Integer>> paramDependencies = getProjectedFunctionalDependencies(query, strict);
170 for (Entry<Set<Integer>, Set<Integer>> entry : paramDependencies.entrySet()) {
171 Set<PVariable> lefts = new HashSet<PVariable>();
172 Set<PVariable> rights = new HashSet<PVariable>();
173
174 for (Integer index : entry.getKey()) {
175 lefts.add(call.getVariableInTuple(index));
176 }
177 for (Integer index : entry.getValue()) {
178 rights.add(call.getVariableInTuple(index));
179 }
180
181 FunctionalDependencyHelper.includeDependency(accumulator,
182 lefts, rights);
183 }
184 } else {
185 // delegate to PConstraint
186 FunctionalDependencyHelper.includeDependencies(accumulator,
187 pConstraint.getFunctionalDependencies(metaContext));
188 }
189 }
190 return accumulator;
191 }
192
193
194}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/PAnnotation.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/PAnnotation.java
new file mode 100644
index 00000000..c4fbe0e9
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/PAnnotation.java
@@ -0,0 +1,94 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.annotations;
10
11import java.util.List;
12import java.util.Optional;
13import java.util.Set;
14import java.util.function.BiConsumer;
15
16import org.eclipse.collections.api.multimap.MutableMultimap;
17import org.eclipse.collections.impl.multimap.list.FastListMultimap;
18
19/**
20 * A container describing query annotations
21 * @author Zoltan Ujhelyi
22 *
23 */
24public class PAnnotation {
25
26 private final String name;
27 private MutableMultimap<String, Object> attributes = FastListMultimap.newMultimap();
28
29 public PAnnotation(String name) {
30 this.name = name;
31
32 }
33
34 /**
35 * Adds an attribute to the annotation
36 * @param attributeName
37 * @param value
38 */
39 public void addAttribute(String attributeName, Object value) {
40 attributes.put(attributeName, value);
41 }
42
43 /**
44 * Return the name of the annotation
45 */
46 public String getName() {
47 return name;
48 }
49
50 /**
51 * Returns the value of the first occurrence of an attribute
52 * @param attributeName
53 * @return the attribute value, or null, if attribute is not available
54 * @since 2.0
55 */
56 public Optional<Object> getFirstValue(String attributeName) {
57 return getAllValues(attributeName).stream().findFirst();
58 }
59
60 /**
61 * Returns the value of the first occurrence of an attribute
62 * @param attributeName
63 * @return the attribute value, or null, if attribute is not available
64 * @since 2.0
65 */
66 public <T> Optional<T> getFirstValue(String attributeName, Class<T> clazz) {
67 return getAllValues(attributeName).stream().filter(clazz::isInstance).map(clazz::cast).findFirst();
68 }
69
70 /**
71 * Returns all values of a selected attribute
72 * @param attributeName
73 * @return a non-null, but possibly empty list of attributes
74 */
75 public List<Object> getAllValues(String attributeName) {
76 return attributes.get(attributeName).toList();
77 }
78
79 /**
80 * Executes a consumer over all attributes. A selected attribute name (key) can appear (and thus consumed) multiple times.
81 * @since 2.0
82 */
83 public void forEachValue(BiConsumer<String, Object> consumer) {
84 attributes.forEachKeyValue(consumer::accept);
85 }
86
87 /**
88 * Returns a set of all attribute names used in this annotation
89 * @since 2.1
90 */
91 public Set<String> getAllAttributeNames() {
92 return attributes.keySet().toSet();
93 }
94}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/ParameterReference.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/ParameterReference.java
new file mode 100644
index 00000000..c67e9046
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/ParameterReference.java
@@ -0,0 +1,30 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.annotations;
10
11/**
12 * An annotation parameter referencing a query parameter by name. Does not check whether the parameter exists.
13 *
14 * @author Zoltan Ujhelyi
15 *
16 */
17public class ParameterReference {
18
19 final String name;
20
21 public ParameterReference(String name) {
22 super();
23 this.name = name;
24 }
25
26 public String getName() {
27 return name;
28 }
29
30}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/AggregatorConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/AggregatorConstraint.java
new file mode 100644
index 00000000..56f86e89
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/AggregatorConstraint.java
@@ -0,0 +1,98 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
10
11import java.util.Collections;
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.Map;
15import java.util.Set;
16
17import tools.refinery.viatra.runtime.matchers.context.IInputKey;
18import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
19import tools.refinery.viatra.runtime.matchers.psystem.ITypeInfoProviderConstraint;
20import tools.refinery.viatra.runtime.matchers.psystem.PBody;
21import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
22import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
23import tools.refinery.viatra.runtime.matchers.psystem.aggregations.BoundAggregator;
24import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
25import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
26import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
27
28/**
29 * The PSystem representation of an aggregation.
30 *
31 * @author Tamas Szabo
32 * @since 1.4
33 */
34public class AggregatorConstraint extends PatternCallBasedDeferred implements ITypeInfoProviderConstraint {
35
36 protected PVariable resultVariable;
37 private BoundAggregator aggregator;
38 protected int aggregatedColumn;
39
40 public AggregatorConstraint(BoundAggregator aggregator, PBody pBody, Tuple actualParametersTuple, PQuery query,
41 PVariable resultVariable, int aggregatedColumn) {
42 super(pBody, actualParametersTuple, query, Collections.singleton(resultVariable));
43 this.resultVariable = resultVariable;
44 this.aggregatedColumn = aggregatedColumn;
45 this.aggregator = aggregator;
46 }
47
48 public int getAggregatedColumn() {
49 return this.aggregatedColumn;
50 }
51
52 public BoundAggregator getAggregator() {
53 return this.aggregator;
54 }
55
56 @Override
57 public Set<PVariable> getDeducedVariables() {
58 return Collections.singleton(resultVariable);
59 }
60
61 @Override
62 public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context) {
63 final Map<Set<PVariable>, Set<PVariable>> result = new HashMap<Set<PVariable>, Set<PVariable>>();
64 result.put(getDeferringVariables(), getDeducedVariables());
65 return result;
66 }
67
68 @Override
69 protected void doDoReplaceVariables(PVariable obsolete, PVariable replacement) {
70 if (resultVariable.equals(obsolete))
71 resultVariable = replacement;
72 }
73
74 @Override
75 protected Set<PVariable> getCandidateQuantifiedVariables() {
76 return actualParametersTuple.<PVariable> getDistinctElements();
77 }
78
79 @Override
80 protected String toStringRest() {
81 return query.getFullyQualifiedName() + "@" + actualParametersTuple.toString() + "->"
82 + resultVariable.toString();
83 }
84
85 public PVariable getResultVariable() {
86 return resultVariable;
87 }
88
89 @Override
90 public Set<TypeJudgement> getImpliedJudgements(IQueryMetaContext context) {
91 Set<TypeJudgement> result = new HashSet<TypeJudgement>();
92 IInputKey aggregateResultType = aggregator.getAggregateResultTypeAsInputKey();
93 if (aggregateResultType != null) {
94 result.add(new TypeJudgement(aggregateResultType, Tuples.staticArityFlatTupleOf(resultVariable)));
95 }
96 return result;
97 }
98}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/BaseTypeSafeConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/BaseTypeSafeConstraint.java
new file mode 100644
index 00000000..7bc949a8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/BaseTypeSafeConstraint.java
@@ -0,0 +1,99 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
11
12import java.util.Collections;
13import java.util.Set;
14import java.util.stream.Collectors;
15import java.util.stream.Stream;
16
17import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
18import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
19import tools.refinery.viatra.runtime.matchers.psystem.PBody;
20import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
21import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
22import tools.refinery.viatra.runtime.matchers.psystem.VariableDeferredPConstraint;
23
24/**
25 * @author Gabor Bergmann
26 *
27 */
28public abstract class BaseTypeSafeConstraint extends
29 VariableDeferredPConstraint {
30
31 protected Set<PVariable> inputVariables;
32 protected PVariable outputVariable;
33
34 public PVariable getOutputVariable() {
35 return outputVariable;
36 }
37
38 /**
39 * @param pBody
40 * @param inputVariables
41 * @param outputVariable null iff no output (check-only)
42 */
43 public BaseTypeSafeConstraint(PBody pBody,
44 Set<PVariable> inputVariables, final PVariable outputVariable) {
45 super(pBody,
46 (outputVariable == null) ?
47 inputVariables :
48 Stream.concat(inputVariables.stream(), Stream.of(outputVariable)).collect(Collectors.toSet())
49 );
50 this.inputVariables = inputVariables;
51 this.outputVariable = outputVariable;
52 }
53
54 @Override
55 public Set<PVariable> getDeducedVariables() {
56 if (outputVariable == null)
57 return Collections.emptySet();
58 else
59 return Collections.singleton(outputVariable);
60 }
61
62 @Override
63 public Set<PVariable> getDeferringVariables() {
64 return inputVariables;
65 }
66
67 @Override
68 public boolean isReadyAt(SubPlan plan, IQueryMetaContext context) {
69 if (super.isReadyAt(plan, context)) {
70 return checkTypeSafety(plan, context) == null;
71 }
72 return false;
73 }
74
75 /**
76 * Checks whether all type restrictions are already enforced on affected variables.
77 *
78 * @param plan
79 * @return a variable whose type safety is not enforced yet, or null if the plan is typesafe
80 */
81 public PVariable checkTypeSafety(SubPlan plan, IQueryMetaContext context) {
82 Set<TypeJudgement> impliedJudgements = plan.getAllImpliedTypeJudgements(context);
83
84 for (PVariable pVariable : inputVariables) {
85 Set<TypeJudgement> allTypeRestrictionsForVariable = pBody.getAllUnaryTypeRestrictions(context).get(pVariable);
86 if (allTypeRestrictionsForVariable != null && !impliedJudgements.containsAll(allTypeRestrictionsForVariable))
87 return pVariable;
88 }
89 return null;
90 }
91
92 @Override
93 protected void doReplaceVariable(PVariable obsolete, PVariable replacement) {
94 if (inputVariables.remove(obsolete))
95 inputVariables.add(replacement);
96 if (outputVariable == obsolete)
97 outputVariable = replacement;
98 }
99}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Equality.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Equality.java
new file mode 100644
index 00000000..b978b62c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Equality.java
@@ -0,0 +1,96 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
11
12import java.util.Collections;
13import java.util.HashMap;
14import java.util.HashSet;
15import java.util.Map;
16import java.util.Set;
17
18import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
19import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
20import tools.refinery.viatra.runtime.matchers.psystem.DeferredPConstraint;
21import tools.refinery.viatra.runtime.matchers.psystem.PBody;
22import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
23
24/**
25 * @author Gabor Bergmann
26 *
27 */
28public class Equality extends DeferredPConstraint {
29
30 private PVariable who;
31 private PVariable withWhom;
32
33 public Equality(PBody pBody, PVariable who, PVariable withWhom) {
34 super(pBody, buildSet(who, withWhom));
35 this.who = who;
36 this.withWhom = withWhom;
37 }
38
39 private static Set<PVariable> buildSet(PVariable who, PVariable withWhom) {
40 Set<PVariable> set = new HashSet<PVariable>();
41 set.add(who);
42 set.add(withWhom);
43 return set;
44 }
45
46 /**
47 * An equality is moot if it compares the a variable with itself.
48 *
49 * @return true, if the equality is moot
50 */
51 public boolean isMoot() {
52 return who.equals(withWhom);
53 }
54
55 @Override
56 public void doReplaceVariable(PVariable obsolete, PVariable replacement) {
57 if (obsolete.equals(who))
58 who = replacement;
59 if (obsolete.equals(withWhom))
60 withWhom = replacement;
61 }
62
63 @Override
64 protected String toStringRest() {
65 return who.getName() + "=" + withWhom.getName();
66 }
67
68 public PVariable getWho() {
69 return who;
70 }
71
72 public PVariable getWithWhom() {
73 return withWhom;
74 }
75
76 @Override
77 public Set<PVariable> getDeducedVariables() {
78 return Collections.emptySet();
79 }
80
81 @Override
82 public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context) {
83 final Map<Set<PVariable>, Set<PVariable>> result = new HashMap<Set<PVariable>, Set<PVariable>>();
84 result.put(Collections.singleton(who), Collections.singleton(withWhom));
85 result.put(Collections.singleton(withWhom), Collections.singleton(who));
86 return result;
87 }
88
89 @Override
90 public boolean isReadyAt(SubPlan plan, IQueryMetaContext context) {
91 return plan.getVisibleVariables().contains(who) && plan.getVisibleVariables().contains(withWhom);
92 // will be replaced by || if copierNode is available;
93 // until then, LayoutHelper.unifyVariablesAlongEqualities(PSystem<PatternDescription, StubHandle, Collector>) is
94 // recommended.
95 }
96}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExportedParameter.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExportedParameter.java
new file mode 100644
index 00000000..80706792
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExportedParameter.java
@@ -0,0 +1,108 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
11
12import java.util.Collections;
13import java.util.Set;
14
15import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
16import tools.refinery.viatra.runtime.matchers.psystem.PBody;
17import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
18import tools.refinery.viatra.runtime.matchers.psystem.VariableDeferredPConstraint;
19import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
20import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
21
22/**
23 * @author Gabor Bergmann
24 *
25 */
26public class ExportedParameter extends VariableDeferredPConstraint {
27 PVariable parameterVariable;
28 final String parameterName;
29 final PParameter patternParameter;
30
31 /**
32 * @since 1.4
33 */
34 public ExportedParameter(PBody pBody, PVariable parameterVariable, PParameter patternParameter) {
35 super(pBody, Collections.singleton(parameterVariable));
36 this.parameterVariable = parameterVariable;
37 this.patternParameter = patternParameter;
38 parameterName = patternParameter.getName();
39 }
40
41 @Override
42 public void doReplaceVariable(PVariable obsolete, PVariable replacement) {
43 if (obsolete.equals(parameterVariable))
44 parameterVariable = replacement;
45 }
46
47 @Override
48 protected String toStringRest() {
49 Object varName = parameterVariable.getName();
50 return parameterName.equals(varName) ? parameterName : parameterName + "(" + varName + ")";
51 }
52
53 @Override
54 public Set<PVariable> getDeducedVariables() {
55 return Collections.emptySet();
56 }
57
58 /**
59 * The name of the parameter; usually, it is expected that {@link #getParameterVariable()} is more useful, except
60 * maybe for debugging purposes.
61 *
62 * @return a non-null name of the parameter
63 */
64 public String getParameterName() {
65 return parameterName;
66 }
67
68 public PVariable getParameterVariable() {
69 return parameterVariable;
70 }
71
72 /**
73 * @since 1.4
74 */
75 public PParameter getPatternParameter() {
76 if (patternParameter == null) {
77 PQuery query = pBody.getPattern();
78 Integer index = query.getPositionOfParameter(parameterName);
79 if (index == null) {
80 throw new IllegalStateException(String.format("Pattern %s does not have a parameter named %s",
81 query.getFullyQualifiedName(), parameterName));
82 }
83 return query.getParameters().get(index);
84 } else {
85 return patternParameter;
86 }
87 }
88
89 @Override
90 public Set<PVariable> getDeferringVariables() {
91 return Collections.singleton(parameterVariable);
92 }
93
94 @Override
95 public void checkSanity() {
96 super.checkSanity();
97 if (!parameterVariable.isDeducable()) {
98 String[] args = { parameterName };
99 String msg = "Impossible to match pattern: "
100 + "exported pattern variable {1} can not be determined based on the pattern constraints. "
101 + "HINT: certain constructs (e.g. negative patterns or check expressions) cannot output symbolic parameters.";
102 String shortMsg = "Could not deduce value of parameter";
103 throw new QueryProcessingException(msg, args, shortMsg, null);
104 }
105
106 }
107
108}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExpressionEvaluation.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExpressionEvaluation.java
new file mode 100644
index 00000000..06688c36
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExpressionEvaluation.java
@@ -0,0 +1,80 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
10
11import java.util.ArrayList;
12import java.util.Collections;
13import java.util.LinkedHashSet;
14import java.util.Map;
15import java.util.Set;
16
17import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
18import tools.refinery.viatra.runtime.matchers.psystem.IExpressionEvaluator;
19import tools.refinery.viatra.runtime.matchers.psystem.PBody;
20import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
21import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
22
23/**
24 * @author Zoltan Ujhelyi
25 *
26 */
27public class ExpressionEvaluation extends BaseTypeSafeConstraint {
28
29 private IExpressionEvaluator evaluator;
30 private boolean isUnwinding;
31
32 public ExpressionEvaluation(PBody pBody, IExpressionEvaluator evaluator, PVariable outputVariable) {
33 this(pBody, evaluator, outputVariable, false);
34 }
35
36 /**
37 * @since 2.4
38 */
39 public ExpressionEvaluation(PBody pBody, IExpressionEvaluator evaluator, PVariable outputVariable,
40 boolean isUnwinding) {
41 super(pBody, getPVariablesOfExpression(pBody, evaluator), outputVariable);
42 this.evaluator = evaluator;
43 this.isUnwinding = isUnwinding;
44 }
45
46 /**
47 * @since 2.4
48 */
49 public boolean isUnwinding() {
50 return isUnwinding;
51 }
52
53 public IExpressionEvaluator getEvaluator() {
54 return evaluator;
55 }
56
57 @Override
58 protected String toStringRest() {
59 return Tuples.flatTupleOf(new ArrayList<PVariable>(inputVariables).toArray()).toString() + "|="
60 + evaluator.getShortDescription();
61 }
62
63 @Override
64 public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context) {
65 if (outputVariable == null)
66 return Collections.emptyMap();
67 else
68 return Collections.singletonMap(inputVariables, Collections.singleton(outputVariable));
69 }
70
71 private static Set<PVariable> getPVariablesOfExpression(PBody pBody, IExpressionEvaluator evaluator) {
72 // use a linked set, so that the variables will come in the order of the parameters
73 Set<PVariable> result = new LinkedHashSet<PVariable>();
74 for (String name : evaluator.getInputParameterNames()) {
75 PVariable variable = pBody.getOrCreateVariableByName(name);
76 result.add(variable);
77 }
78 return result;
79 }
80}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Inequality.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Inequality.java
new file mode 100644
index 00000000..5cac33dc
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Inequality.java
@@ -0,0 +1,151 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
11
12import java.util.Arrays;
13import java.util.Collections;
14import java.util.HashSet;
15import java.util.Set;
16
17import tools.refinery.viatra.runtime.matchers.psystem.PBody;
18import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
19import tools.refinery.viatra.runtime.matchers.psystem.VariableDeferredPConstraint;
20
21/**
22 * @author Gabor Bergmann
23 *
24 */
25public class Inequality extends VariableDeferredPConstraint {
26
27 private PVariable who;
28 private PVariable withWhom;
29
30 /**
31 * The inequality constraint is weak if it can be ignored when who is the same as withWhom, or if any if them is
32 * undeducible.
33 */
34 private boolean weak;
35
36 public Inequality(PBody pBody, PVariable who, PVariable withWhom) {
37 this(pBody, who, withWhom, false);
38 }
39
40 public Inequality(PBody pBody, PVariable who, PVariable withWhom,
41 boolean weak) {
42 super(pBody, new HashSet<>(Arrays.asList(who, withWhom) ));
43 this.who = who;
44 this.withWhom = withWhom;
45 this.weak = weak;
46 }
47
48 // private Inequality(
49 // PSystem<PatternDescription, StubHandle, ?> pSystem,
50 // PVariable subject, Set<PVariable> inequals)
51 // {
52 // super(pSystem, include(inequals, subject));
53 // this.subject = subject;
54 // this.inequals = inequals;
55 // }
56
57 // private static HashSet<PVariable> include(Set<PVariable> inequals, PVariable subject) {
58 // HashSet<PVariable> hashSet = new HashSet<PVariable>(inequals);
59 // hashSet.add(subject);
60 // return hashSet;
61 // }
62
63 @Override
64 public Set<PVariable> getDeferringVariables() {
65 return getAffectedVariables();
66 }
67
68 // private static int[] mapIndices(Map<Object, Integer> variablesIndex, Set<PVariable> keys) {
69 // int[] result = new int[keys.size()];
70 // int k = 0;
71 // for (PVariable key : keys) {
72 // result[k++] = variablesIndex.get(key);
73 // }
74 // return result;
75 // }
76
77 // @Override
78 // public IFoldablePConstraint getIncorporator() {
79 // return incorporator;
80 // }
81 //
82 // @Override
83 // public void registerIncorporatationInto(IFoldablePConstraint incorporator) {
84 // this.incorporator = incorporator;
85 // }
86 //
87 // @Override
88 // public boolean incorporate(IFoldablePConstraint other) {
89 // if (other instanceof Inequality<?, ?>) {
90 // Inequality other2 = (Inequality) other;
91 // if (subject.equals(other2.subject)) {
92 // Set<PVariable> newInequals = new HashSet<PVariable>(inequals);
93 // newInequals.addAll(other2.inequals);
94 // return new Inequality<PatternDescription, StubHandle>(buildable, subject, newInequals);
95 // }
96 // } else return false;
97 // }
98
99 @Override
100 protected String toStringRest() {
101 return who.toString() + (isWeak() ? "!=?" : "!=") + withWhom.toString();
102 }
103
104 @Override
105 public void doReplaceVariable(PVariable obsolete, PVariable replacement) {
106 if (obsolete.equals(who))
107 who = replacement;
108 if (obsolete.equals(withWhom))
109 withWhom = replacement;
110 }
111
112 @Override
113 public Set<PVariable> getDeducedVariables() {
114 return Collections.emptySet();
115 }
116
117 /**
118 * The inequality constraint is weak if it can be ignored when who is the same as withWhom, or if any if them is
119 * undeducible.
120 *
121 * @return the weak
122 */
123 public boolean isWeak() {
124 return weak;
125 }
126
127 /**
128 * A weak inequality constraint is eliminable if who is the same as withWhom, or if any if them is undeducible.
129 */
130 public boolean isEliminable() {
131 return isWeak() && (who.equals(withWhom) || !who.isDeducable() || !withWhom.isDeducable());
132 }
133
134 /**
135 * Eliminates a weak inequality constraint if it can be ignored when who is the same as withWhom, or if any if them
136 * is undeducible.
137 */
138 public void eliminateWeak() {
139 if (isEliminable())
140 delete();
141 }
142
143 public PVariable getWho() {
144 return who;
145 }
146
147 public PVariable getWithWhom() {
148 return withWhom;
149 }
150
151}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/NegativePatternCall.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/NegativePatternCall.java
new file mode 100644
index 00000000..87d9d9fc
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/NegativePatternCall.java
@@ -0,0 +1,52 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
11
12import java.util.Collections;
13import java.util.Set;
14
15import tools.refinery.viatra.runtime.matchers.psystem.PBody;
16import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
17import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
19
20/**
21 * @author Gabor Bergmann
22 *
23 */
24public class NegativePatternCall extends PatternCallBasedDeferred {
25
26 public NegativePatternCall(PBody pBody, Tuple actualParametersTuple, PQuery query) {
27 super(pBody, actualParametersTuple, query);
28 }
29
30 @Override
31 public Set<PVariable> getDeducedVariables() {
32 return Collections.emptySet();
33 }
34
35 /**
36 * @return all variables that may potentially be quantified they are not used anywhere else
37 */
38 @Override
39 protected Set<PVariable> getCandidateQuantifiedVariables() {
40 return getAffectedVariables();
41 }
42
43 @Override
44 protected void doDoReplaceVariables(PVariable obsolete, PVariable replacement) {
45 }
46
47 @Override
48 protected String toStringRest() {
49 return "!" + query.getFullyQualifiedName() + "@" + actualParametersTuple.toString();
50 }
51
52}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternCallBasedDeferred.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternCallBasedDeferred.java
new file mode 100644
index 00000000..93eeffec
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternCallBasedDeferred.java
@@ -0,0 +1,118 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
11
12import java.util.Collections;
13import java.util.HashSet;
14import java.util.Set;
15
16import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
17import tools.refinery.viatra.runtime.matchers.psystem.IQueryReference;
18import tools.refinery.viatra.runtime.matchers.psystem.PBody;
19import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
20import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
21import tools.refinery.viatra.runtime.matchers.psystem.VariableDeferredPConstraint;
22import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
23import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
24
25/**
26 * @author Gabor Bergmann
27 *
28 */
29public abstract class PatternCallBasedDeferred extends VariableDeferredPConstraint implements IQueryReference {
30
31 protected Tuple actualParametersTuple;
32
33 protected abstract void doDoReplaceVariables(PVariable obsolete, PVariable replacement);
34
35 protected abstract Set<PVariable> getCandidateQuantifiedVariables();
36
37 protected PQuery query;
38 private Set<PVariable> deferringVariables;
39
40 public PatternCallBasedDeferred(PBody pBody, Tuple actualParametersTuple,
41 PQuery pattern, Set<PVariable> additionalAffectedVariables) {
42 super(pBody, union(actualParametersTuple.<PVariable> getDistinctElements(), additionalAffectedVariables));
43 this.actualParametersTuple = actualParametersTuple;
44 this.query = pattern;
45 }
46
47 public PatternCallBasedDeferred(PBody pBody, Tuple actualParametersTuple,
48 PQuery pattern) {
49 this(pBody, actualParametersTuple, pattern, Collections.<PVariable> emptySet());
50 }
51
52 private static Set<PVariable> union(Set<PVariable> a, Set<PVariable> b) {
53 Set<PVariable> result = new HashSet<PVariable>();
54 result.addAll(a);
55 result.addAll(b);
56 return result;
57 }
58
59 @Override
60 public Set<PVariable> getDeferringVariables() {
61 if (deferringVariables == null) {
62 deferringVariables = new HashSet<PVariable>();
63 for (PVariable var : getCandidateQuantifiedVariables()) {
64 if (var.isDeducable())
65 deferringVariables.add(var);
66 }
67 }
68 return deferringVariables;
69 }
70
71 @Override
72 public void checkSanity() {
73 super.checkSanity();
74 for (Object obj : this.actualParametersTuple.getDistinctElements()) {
75 PVariable var = (PVariable) obj;
76 if (!getDeferringVariables().contains(var)) {
77 // so this is a free variable of the NAC / aggregation?
78 for (PConstraint pConstraint : var.getReferringConstraints()) {
79 if (pConstraint != this
80 && !(pConstraint instanceof Equality && ((Equality) pConstraint).isMoot()))
81 throw new QueryProcessingException (
82 "Variable {1} of constraint {2} is not a positively determined part of the pattern, yet it is also affected by {3}.",
83 new String[] { var.toString(), this.toString(), pConstraint.toString() },
84 "Read-only variable can not be deduced", null);
85 }
86 }
87 }
88
89 }
90
91// public SubPlan getSidePlan(IOperationCompiler compiler) throws QueryPlannerException {
92// SubPlan sidePlan = compiler.patternCallPlan(actualParametersTuple, query);
93// sidePlan = BuildHelper.enforceVariableCoincidences(compiler, sidePlan);
94// return sidePlan;
95// }
96
97 @Override
98 protected void doReplaceVariable(PVariable obsolete, PVariable replacement) {
99 if (deferringVariables != null) {
100 // FAIL instead of hopeless attempt to fix
101 // if (deferringVariables.remove(obsolete)) deferringVariables.add(replacement);
102 throw new IllegalStateException("Cannot replace variables on " + this
103 + " when deferring variables have already been identified.");
104 }
105 actualParametersTuple = actualParametersTuple.replaceAll(obsolete, replacement);
106 doDoReplaceVariables(obsolete, replacement);
107 }
108
109 public Tuple getActualParametersTuple() {
110 return actualParametersTuple;
111 }
112
113 @Override
114 public PQuery getReferredQuery() {
115 return query;
116 }
117
118}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternMatchCounter.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternMatchCounter.java
new file mode 100644
index 00000000..0c40d91e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternMatchCounter.java
@@ -0,0 +1,70 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
11
12import java.util.Collections;
13import java.util.HashMap;
14import java.util.Map;
15import java.util.Set;
16
17import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
18import tools.refinery.viatra.runtime.matchers.psystem.PBody;
19import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
20import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
21import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
22
23/**
24 * @author Gabor Bergmann
25 */
26public class PatternMatchCounter extends PatternCallBasedDeferred {
27
28 private PVariable resultVariable;
29
30 public PatternMatchCounter(PBody pBody, Tuple actualParametersTuple,
31 PQuery query, PVariable resultVariable) {
32 super(pBody, actualParametersTuple, query, Collections.singleton(resultVariable));
33 this.resultVariable = resultVariable;
34 }
35
36 @Override
37 public Set<PVariable> getDeducedVariables() {
38 return Collections.singleton(resultVariable);
39 }
40
41 @Override
42 public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context) {
43 final Map<Set<PVariable>, Set<PVariable>> result = new HashMap<Set<PVariable>, Set<PVariable>>();
44 result.put(getDeferringVariables(), getDeducedVariables());
45 return result;
46 }
47
48 @Override
49 protected void doDoReplaceVariables(PVariable obsolete, PVariable replacement) {
50 if (resultVariable.equals(obsolete))
51 resultVariable = replacement;
52 }
53
54 @Override
55 protected Set<PVariable> getCandidateQuantifiedVariables() {
56 return actualParametersTuple.<PVariable> getDistinctElements();
57 }
58
59
60 @Override
61 protected String toStringRest() {
62 return query.getFullyQualifiedName() + "@" + actualParametersTuple.toString() + "->"
63 + resultVariable.toString();
64 }
65
66 public PVariable getResultVariable() {
67 return resultVariable;
68 }
69
70} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/RelationEvaluation.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/RelationEvaluation.java
new file mode 100644
index 00000000..336a83fb
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/RelationEvaluation.java
@@ -0,0 +1,57 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2022, Tamas Szabo, GitHub
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
10
11import java.util.List;
12
13import tools.refinery.viatra.runtime.matchers.psystem.EnumerablePConstraint;
14import tools.refinery.viatra.runtime.matchers.psystem.IMultiQueryReference;
15import tools.refinery.viatra.runtime.matchers.psystem.IRelationEvaluator;
16import tools.refinery.viatra.runtime.matchers.psystem.PBody;
17import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
19
20/**
21 * A constraint which prescribes the evaluation of custom Java logic that takes an arbitrary number of input relations
22 * and produces one output relation. Contrast this to {@link ExpressionEvaluation}, which produces a single output value
23 * given an input tuple.
24 *
25 * The assumption is that the relation evaluation logic is not incremental, that is, it can only perform from-scratch
26 * computation of the output relation given the complete input relations. To this end, the relation evaluator always
27 * receives the complete input relations with all their contents as input. However, the evaluator engine makes sure that
28 * the output of the relation evaluation is at least "seemingly" incremental. This means that the underlying computation
29 * network computes the delta on the output compared to the previous output and only propagates the delta further.
30 *
31 * @author Tamas Szabo
32 *
33 * @since 2.8
34 *
35 */
36public class RelationEvaluation extends EnumerablePConstraint implements IMultiQueryReference {
37
38 private final IRelationEvaluator evaluator;
39 private final List<PQuery> inputQueries;
40
41 public RelationEvaluation(final PBody body, final Tuple variablesTuple, final List<PQuery> inputQueries,
42 final IRelationEvaluator evaluator) {
43 super(body, variablesTuple);
44 this.evaluator = evaluator;
45 this.inputQueries = inputQueries;
46 }
47
48 public IRelationEvaluator getEvaluator() {
49 return this.evaluator;
50 }
51
52 @Override
53 public List<PQuery> getReferredQueries() {
54 return this.inputQueries;
55 }
56
57}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/TypeFilterConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/TypeFilterConstraint.java
new file mode 100644
index 00000000..8b6e29ef
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/TypeFilterConstraint.java
@@ -0,0 +1,105 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
10
11import java.util.Collections;
12import java.util.Map;
13import java.util.Set;
14
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
16import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
17import tools.refinery.viatra.runtime.matchers.psystem.ITypeConstraint;
18import tools.refinery.viatra.runtime.matchers.psystem.PBody;
19import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
20import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
21import tools.refinery.viatra.runtime.matchers.psystem.VariableDeferredPConstraint;
22import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.TypeConstraint;
23import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
24
25/**
26 * Represents a non-enumerable type constraint that asserts that values substituted for the given tuple of variables
27 * form a tuple that belongs to a (typically non-enumerable) extensional relation identified by an {@link IInputKey}.
28 *
29 * <p> The InputKey is typically not enumerable. If it is enumerable, use {@link TypeConstraint} instead, so that the PConstraint carries over the property of enumerability.
30 *
31 * @author Bergmann Gabor
32 *
33 */
34public class TypeFilterConstraint extends VariableDeferredPConstraint implements
35 ITypeConstraint {
36
37 private Tuple variablesTuple;
38 private IInputKey inputKey;
39
40 private TypeJudgement equivalentJudgement;
41
42
43 public TypeFilterConstraint(PBody pBody, Tuple variablesTuple, IInputKey inputKey) {
44 super(pBody, variablesTuple.<PVariable> getDistinctElements());
45 this.equivalentJudgement = new TypeJudgement(inputKey, variablesTuple);
46
47 this.variablesTuple = variablesTuple;
48 this.inputKey = inputKey;
49
50 if (variablesTuple.getSize() != inputKey.getArity())
51 throw new IllegalArgumentException(
52 this.getClass().getSimpleName() +
53 " applied for variable tuple " + variablesTuple + " having wrong arity for input key " +
54 inputKey);
55 }
56
57
58
59 public Tuple getVariablesTuple() {
60 return variablesTuple;
61 }
62
63 public IInputKey getInputKey() {
64 return inputKey;
65 }
66
67 @Override
68 public TypeJudgement getEquivalentJudgement() {
69 return equivalentJudgement;
70 }
71
72 @Override
73 protected void doReplaceVariable(PVariable obsolete, PVariable replacement) {
74 variablesTuple = variablesTuple.replaceAll(obsolete, replacement);
75 this.equivalentJudgement = new TypeJudgement(inputKey, variablesTuple);
76 }
77
78 @Override
79 public Set<TypeJudgement> getImpliedJudgements(IQueryMetaContext context) {
80 return Collections.singleton(equivalentJudgement);
81 }
82
83 @Override
84 public Set<PVariable> getDeducedVariables() {
85 return Collections.emptySet();
86 }
87
88 @Override
89 public Set<PVariable> getDeferringVariables() {
90 return getAffectedVariables();
91 }
92
93 @Override
94 protected String toStringRest() {
95 return inputKey.getPrettyPrintableName() + "@" + variablesTuple;
96 }
97
98 @Override
99 public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context) {
100 return TypeConstraintUtil.getFunctionalDependencies(context, inputKey, variablesTuple);
101 }
102
103
104
105}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/AbstractTransitiveClosure.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/AbstractTransitiveClosure.java
new file mode 100644
index 00000000..7bbf7118
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/AbstractTransitiveClosure.java
@@ -0,0 +1,44 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.basicenumerables;
10
11import java.util.Set;
12
13import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
14import tools.refinery.viatra.runtime.matchers.psystem.IQueryReference;
15import tools.refinery.viatra.runtime.matchers.psystem.ITypeInfoProviderConstraint;
16import tools.refinery.viatra.runtime.matchers.psystem.KeyedEnumerablePConstraint;
17import tools.refinery.viatra.runtime.matchers.psystem.PBody;
18import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
19import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
20import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
21
22/**
23 * @since 2.0
24 */
25public abstract class AbstractTransitiveClosure extends KeyedEnumerablePConstraint<PQuery> implements IQueryReference, ITypeInfoProviderConstraint {
26
27 public AbstractTransitiveClosure(PBody pBody, Tuple variablesTuple, PQuery supplierKey) {
28 super(pBody, variablesTuple, supplierKey);
29 }
30
31 @Override
32 public PQuery getReferredQuery() {
33 return supplierKey;
34 }
35
36 /**
37 * @since 1.3
38 */
39 @Override
40 public Set<TypeJudgement> getImpliedJudgements(IQueryMetaContext context) {
41 return PositivePatternCall.getTypesImpliedByCall(supplierKey, variablesTuple);
42 }
43
44} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryReflexiveTransitiveClosure.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryReflexiveTransitiveClosure.java
new file mode 100644
index 00000000..e3dae240
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryReflexiveTransitiveClosure.java
@@ -0,0 +1,57 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Zoltan Ujhelyi, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicenumerables;
11
12import tools.refinery.viatra.runtime.matchers.context.IInputKey;
13import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
14import tools.refinery.viatra.runtime.matchers.psystem.PBody;
15import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
16import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
17
18/**
19 * For a binary base pattern over an enumerable universe type, computes the reflexive transitive closure (base)*
20 *
21 * @author Gabor Bergmann, Zoltan Ujhelyi
22 * @since 2.0
23 */
24public class BinaryReflexiveTransitiveClosure extends AbstractTransitiveClosure {
25
26 private final IInputKey universeType;
27
28 public BinaryReflexiveTransitiveClosure(PBody pBody, Tuple variablesTuple,
29 PQuery pattern, IInputKey universeType) {
30 super(pBody, variablesTuple, pattern);
31 this.universeType = universeType;
32 }
33
34 @Override
35 protected String keyToString() {
36 return supplierKey.getFullyQualifiedName() + "*";
37 }
38
39 /**
40 * Returns the type whose instances should be returned as 0-long paths.
41 * @since 2.0
42 */
43 public IInputKey getUniverseType() {
44 return universeType;
45 }
46
47 @Override
48 public void checkSanity() {
49 if (!universeType.isEnumerable() || universeType.getArity() != 1) {
50 throw new QueryProcessingException(
51 String.format("Invalid universe type %s - it should be enumerable and must have an arity of 1.",
52 universeType.getPrettyPrintableName()),
53 pBody.getPattern());
54 }
55 }
56
57}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryTransitiveClosure.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryTransitiveClosure.java
new file mode 100644
index 00000000..716d043b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryTransitiveClosure.java
@@ -0,0 +1,33 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicenumerables;
11
12import tools.refinery.viatra.runtime.matchers.psystem.PBody;
13import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
14import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
15
16/**
17 * For a binary base pattern, computes the irreflexive transitive closure (base)+
18 *
19 * @author Gabor Bergmann
20 *
21 */
22public class BinaryTransitiveClosure extends AbstractTransitiveClosure {
23
24 public BinaryTransitiveClosure(PBody pBody, Tuple variablesTuple,
25 PQuery pattern) {
26 super(pBody, variablesTuple, pattern);
27 }
28
29 @Override
30 protected String keyToString() {
31 return supplierKey.getFullyQualifiedName() + "+";
32 }
33}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/Connectivity.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/Connectivity.java
new file mode 100644
index 00000000..10da2e21
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/Connectivity.java
@@ -0,0 +1,11 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.viatra.runtime.matchers.psystem.basicenumerables;
7
8public enum Connectivity {
9 WEAK,
10 STRONG;
11}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/ConstantValue.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/ConstantValue.java
new file mode 100644
index 00000000..251146c8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/ConstantValue.java
@@ -0,0 +1,57 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicenumerables;
11
12import java.util.Collections;
13import java.util.HashMap;
14import java.util.Map;
15import java.util.Set;
16
17import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
18import tools.refinery.viatra.runtime.matchers.psystem.KeyedEnumerablePConstraint;
19import tools.refinery.viatra.runtime.matchers.psystem.PBody;
20import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
21import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
22
23/**
24 * @author Gabor Bergmann
25 *
26 */
27public class ConstantValue extends KeyedEnumerablePConstraint<Object> {
28
29 private PVariable variable;
30
31 public ConstantValue(PBody pBody, PVariable variable, Object value) {
32 super(pBody, Tuples.staticArityFlatTupleOf(variable), value);
33 this.variable = variable;
34 }
35
36 @Override
37 protected String keyToString() {
38 return supplierKey.toString();
39 }
40
41 /**
42 * @since 1.7
43 */
44 public PVariable getVariable() {
45 return variable;
46 }
47
48 @Override
49 public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context) {
50 final Map<Set<PVariable>, Set<PVariable>> result = new HashMap<Set<PVariable>, Set<PVariable>>();
51 final Set<PVariable> emptySet = Collections.emptySet(); // a constant value is functionally determined by everything
52 result.put(emptySet, Collections.singleton(getVariableInTuple(0)));
53 return result;
54 }
55
56
57}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/PositivePatternCall.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/PositivePatternCall.java
new file mode 100644
index 00000000..25ab34b4
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/PositivePatternCall.java
@@ -0,0 +1,76 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicenumerables;
11
12import java.util.HashSet;
13import java.util.Set;
14
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
16import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
17import tools.refinery.viatra.runtime.matchers.psystem.IQueryReference;
18import tools.refinery.viatra.runtime.matchers.psystem.ITypeInfoProviderConstraint;
19import tools.refinery.viatra.runtime.matchers.psystem.KeyedEnumerablePConstraint;
20import tools.refinery.viatra.runtime.matchers.psystem.PBody;
21import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
22import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
23import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
24import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
25
26/**
27 * @author Gabor Bergmann
28 *
29 */
30public class PositivePatternCall extends KeyedEnumerablePConstraint<PQuery> implements IQueryReference, ITypeInfoProviderConstraint {
31
32 public PositivePatternCall(PBody pBody, Tuple variablesTuple,
33 PQuery pattern) {
34 super(pBody, variablesTuple, pattern);
35 }
36
37 @Override
38 protected String keyToString() {
39 return supplierKey.getFullyQualifiedName();
40 }
41
42 // Note: #getFunctionalDependencies is intentionally not implemented - use QueryAnalyzer instead!
43// @Override
44// public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context) {
45// return super.getFunctionalDependencies(context);
46// }
47
48 @Override
49 public PQuery getReferredQuery() {
50 return supplierKey;
51 }
52
53 @Override
54 public Set<TypeJudgement> getImpliedJudgements(IQueryMetaContext context) {
55 return getTypesImpliedByCall(supplierKey, variablesTuple);
56 }
57
58 /**
59 * @since 1.3
60 */
61 public static Set<TypeJudgement> getTypesImpliedByCall(PQuery calledQuery, Tuple actualParametersTuple) {
62 Set<TypeJudgement> result = new HashSet<TypeJudgement>();
63 for (TypeJudgement parameterJudgement : calledQuery.getTypeGuarantees()) {
64 IInputKey inputKey = parameterJudgement.getInputKey();
65 Tuple judgementIndexTuple = parameterJudgement.getVariablesTuple();
66
67 Object[] judgementVariables = new Object[judgementIndexTuple.getSize()];
68 for (int i=0; i<judgementVariables.length; ++i)
69 judgementVariables[i] = actualParametersTuple.get((int) judgementIndexTuple.get(i));
70
71 result.add(new TypeJudgement(inputKey, Tuples.flatTupleOf(judgementVariables)));
72 }
73 return result;
74 }
75
76}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/RepresentativeElectionConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/RepresentativeElectionConstraint.java
new file mode 100644
index 00000000..b97ff55f
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/RepresentativeElectionConstraint.java
@@ -0,0 +1,43 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.viatra.runtime.matchers.psystem.basicenumerables;
7
8import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
9import tools.refinery.viatra.runtime.matchers.psystem.*;
10import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
11import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
12
13import java.util.Set;
14
15public class RepresentativeElectionConstraint extends KeyedEnumerablePConstraint<PQuery>
16 implements IQueryReference, ITypeInfoProviderConstraint {
17 private final Connectivity connectivity;
18
19 public RepresentativeElectionConstraint(PBody pBody, Tuple variablesTuple, PQuery supplierKey,
20 Connectivity connectivity) {
21 super(pBody, variablesTuple, supplierKey);
22 this.connectivity = connectivity;
23 }
24
25 public Connectivity getConnectivity() {
26 return connectivity;
27 }
28
29 @Override
30 public PQuery getReferredQuery() {
31 return supplierKey;
32 }
33
34 @Override
35 public Set<TypeJudgement> getImpliedJudgements(IQueryMetaContext context) {
36 return PositivePatternCall.getTypesImpliedByCall(supplierKey, variablesTuple);
37 }
38
39 @Override
40 protected String keyToString() {
41 return supplierKey.getFullyQualifiedName() + "#" + connectivity + "#representative";
42 }
43}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/TypeConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/TypeConstraint.java
new file mode 100644
index 00000000..2ca54cc0
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/TypeConstraint.java
@@ -0,0 +1,79 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.basicenumerables;
10
11import java.util.Collections;
12import java.util.Map;
13import java.util.Set;
14
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
16import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
17import tools.refinery.viatra.runtime.matchers.psystem.ITypeConstraint;
18import tools.refinery.viatra.runtime.matchers.psystem.KeyedEnumerablePConstraint;
19import tools.refinery.viatra.runtime.matchers.psystem.PBody;
20import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
21import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
22import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
23
24/**
25 * Represents an enumerable type constraint that asserts that values substituted for the given tuple of variables
26 * form a tuple that belongs to an enumerable extensional relation identified by an {@link IInputKey}.
27 *
28 * <p> The InputKey must be enumerable!
29 *
30 * @author Zoltan Ujhelyi
31 *
32 */
33public class TypeConstraint extends KeyedEnumerablePConstraint<IInputKey> implements ITypeConstraint {
34
35 private TypeJudgement equivalentJudgement;
36
37 public TypeConstraint(PBody pBody, Tuple variablesTuple, IInputKey inputKey) {
38 super(pBody, variablesTuple, inputKey);
39 this.equivalentJudgement = new TypeJudgement(inputKey, variablesTuple);
40
41 if (! inputKey.isEnumerable())
42 throw new IllegalArgumentException(
43 this.getClass().getSimpleName() +
44 " applicable for enumerable input keys only; received instead " +
45 inputKey);
46 if (variablesTuple.getSize() != inputKey.getArity())
47 throw new IllegalArgumentException(
48 this.getClass().getSimpleName() +
49 " applied for variable tuple " + variablesTuple + " having wrong arity for input key " +
50 inputKey);
51 }
52
53 @Override
54 protected String keyToString() {
55 return supplierKey.getPrettyPrintableName();
56 }
57
58 @Override
59 public TypeJudgement getEquivalentJudgement() {
60 return equivalentJudgement;
61 }
62
63 @Override
64 public Set<TypeJudgement> getImpliedJudgements(IQueryMetaContext context) {
65 return Collections.singleton(equivalentJudgement);
66 //return equivalentJudgement.getDirectlyImpliedJudgements(context);
67 }
68
69 @Override
70 public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context) {
71 return TypeConstraintUtil.getFunctionalDependencies(context, supplierKey, variablesTuple);
72 }
73
74 @Override
75 public void doReplaceVariable(PVariable obsolete, PVariable replacement) {
76 super.doReplaceVariable(obsolete, replacement);
77 this.equivalentJudgement = new TypeJudgement(getSupplierKey(), variablesTuple);
78 }
79} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/BasePQuery.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/BasePQuery.java
new file mode 100644
index 00000000..2c03a894
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/BasePQuery.java
@@ -0,0 +1,231 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11import java.util.ArrayList;
12import java.util.Collections;
13import java.util.HashSet;
14import java.util.List;
15import java.util.Objects;
16import java.util.Optional;
17import java.util.Set;
18import java.util.stream.Collectors;
19import java.util.stream.Stream;
20
21import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
22import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendFactory;
23import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
24import tools.refinery.viatra.runtime.matchers.context.IInputKey;
25import tools.refinery.viatra.runtime.matchers.psystem.PBody;
26import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
27import tools.refinery.viatra.runtime.matchers.psystem.annotations.PAnnotation;
28import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
29import tools.refinery.viatra.runtime.matchers.util.Preconditions;
30
31/**
32 * Default implementation of PQuery.
33 *
34 * @author Bergmann Gabor
35 */
36public abstract class BasePQuery implements PQuery {
37
38 protected PQueryStatus status = PQueryStatus.UNINITIALIZED;
39 /**
40 * @since 2.0
41 */
42 protected final PVisibility visibility;
43 protected List<PProblem> pProblems = new ArrayList<PProblem>();
44 private List<PAnnotation> annotations = new ArrayList<PAnnotation>();
45 private QueryEvaluationHint evaluationHints = new QueryEvaluationHint(null, (IQueryBackendFactory)null);
46 PDisjunction canonicalDisjunction;
47 private List<String> parameterNames = null; // Lazy initialization
48
49 /** For traceability only. */
50 private List<Object> wrappingQuerySpecifications = new ArrayList<Object>(1);
51
52 @Override
53 public Integer getPositionOfParameter(String parameterName) {
54 ensureInitialized();
55 int index = getParameterNames().indexOf(parameterName);
56 return index != -1 ? index : null;
57 }
58
59 protected void setStatus(PQueryStatus newStatus) {
60 this.status = newStatus;
61 }
62
63 protected void addError(PProblem problem) {
64 status = PQueryStatus.ERROR;
65 pProblems.add(problem);
66 }
67
68 @Override
69 public PQueryStatus getStatus() {
70 return status;
71 }
72
73 @Override
74 public List<PProblem> getPProblems() {
75 return Collections.unmodifiableList(pProblems);
76 }
77
78 @Override
79 public boolean isMutable() {
80 return status.equals(PQueryStatus.UNINITIALIZED) || status.equals(PQueryStatus.INITIALIZING);
81 }
82
83 @Override
84 public void checkMutability() {
85 Preconditions.checkState(isMutable(), "Cannot edit query definition %s", getFullyQualifiedName());
86 }
87
88 /**
89 * @since 1.5
90 */
91 public void setEvaluationHints(QueryEvaluationHint hints) {
92 checkMutability();
93 this.evaluationHints = hints;
94 }
95
96 @Override
97 public QueryEvaluationHint getEvaluationHints() {
98 ensureInitialized();
99 return evaluationHints;
100 // TODO instead of field, compute something from annotations?
101 }
102
103 protected void addAnnotation(PAnnotation annotation) {
104 checkMutability();
105 annotations.add(annotation);
106 }
107
108 @Override
109 public List<PAnnotation> getAllAnnotations() {
110 ensureInitialized();
111 return new ArrayList<>(annotations);
112 }
113
114 private Stream<PAnnotation> getAnnotationStreamByName(final String name) {
115 ensureInitialized();
116 return annotations.stream().filter(Objects::nonNull).filter(annotation -> Objects.equals(name, annotation.getName()));
117 }
118
119 @Override
120 public List<PAnnotation> getAnnotationsByName(final String annotationName) {
121 return getAnnotationStreamByName(annotationName).collect(Collectors.toList());
122 }
123
124 @Override
125 public Optional<PAnnotation> getFirstAnnotationByName(String annotationName) {
126 return getAnnotationStreamByName(annotationName).findFirst();
127 }
128
129 @Override
130 public List<String> getParameterNames() {
131 ensureInitialized();
132 if (parameterNames == null) {
133 parameterNames = getParameters().stream().map(PParameter::getName).collect(Collectors.toList());
134 }
135 return parameterNames;
136 }
137
138 @Override
139 public Set<PQuery> getDirectReferredQueries() {
140 ensureInitialized();
141 return canonicalDisjunction.getDirectReferredQueries();
142 }
143
144 @Override
145 public Set<PQuery> getAllReferredQueries() {
146 ensureInitialized();
147 return canonicalDisjunction.getAllReferredQueries();
148 }
149
150
151 @Override
152 public List<Object> publishedAs() {
153 return wrappingQuerySpecifications;
154 }
155
156 @Override
157 public Set<TypeJudgement> getTypeGuarantees() {
158 ensureInitialized();
159 Set<TypeJudgement> result = new HashSet<TypeJudgement>();
160
161 List<PParameter> parameters = getParameters();
162 for (int i=0; i<parameters.size(); ++i) {
163 PParameter parameter = parameters.get(i);
164 IInputKey declaredUnaryType = parameter.getDeclaredUnaryType();
165 if (declaredUnaryType != null) {
166 result.add(new TypeJudgement(declaredUnaryType, Tuples.staticArityFlatTupleOf(i)));
167 }
168 }
169
170 return result;
171 }
172
173 /**
174 * @since 2.0
175 */
176 public BasePQuery(PVisibility visibility) {
177 super();
178 this.visibility = visibility;
179 }
180
181 @Override
182 public PDisjunction getDisjunctBodies() {
183 ensureInitialized();
184 Preconditions.checkState(!status.equals(PQueryStatus.ERROR), "Query %s contains errors.", getFullyQualifiedName());
185 return canonicalDisjunction;
186 }
187
188 @Override
189 public final void ensureInitialized() {
190 try {
191 if (status.equals(PQueryStatus.UNINITIALIZED)) {
192 setStatus(PQueryStatus.INITIALIZING);
193 setBodies(doGetContainedBodies());
194 setStatus(PQueryStatus.OK);
195 }
196 } catch (QueryInitializationException e) {
197 addError(new PProblem(e, e.getShortMessage()));
198 throw e;
199 }
200 }
201
202 protected final void setBodies(Set<PBody> bodies) {
203 canonicalDisjunction = new PDisjunction(this, bodies);
204 for (PBody body : canonicalDisjunction.getBodies()) {
205 body.setStatus(null);
206 }
207 setStatus(PQueryStatus.OK);
208 }
209
210 /**
211 * Creates and returns the bodies of the query. If recalled again, a new instance is created.
212 *
213 * @return
214 * @throws ViatraQueryRuntimeException
215 */
216 protected abstract Set<PBody> doGetContainedBodies();
217
218 @Override
219 public String toString() {
220 return String.format("PQuery<%s>=%s", getFullyQualifiedName(), super.toString());
221 }
222
223 /**
224 * @since 2.0
225 */
226 @Override
227 public PVisibility getVisibility() {
228 return visibility;
229 }
230
231} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PDisjunction.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PDisjunction.java
new file mode 100644
index 00000000..eae4eacf
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PDisjunction.java
@@ -0,0 +1,104 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11import java.util.Collections;
12import java.util.LinkedHashSet;
13import java.util.Set;
14import java.util.stream.Collectors;
15
16import tools.refinery.viatra.runtime.matchers.psystem.PBody;
17
18/**
19 *
20 * A disjunction is a set of bodies representing separate conditions. A {@link PQuery} has a single, canonical
21 * PDisjunction, that can be replaced using rewriter
22 *
23 * @author Zoltan Ujhelyi
24 *
25 */
26public class PDisjunction {
27
28 private Set<PBody> bodies;
29 private PQuery query;
30
31 public PDisjunction(Set<PBody> bodies) {
32 this(bodies.iterator().next().getPattern(), bodies);
33 }
34
35 public PDisjunction(PQuery query, Set<PBody> bodies) {
36 super();
37 this.query = query;
38 this.bodies = Collections.unmodifiableSet(new LinkedHashSet<>(bodies));
39 this.bodies.forEach(body -> body.setContainerDisjunction(this));
40 }
41
42 /**
43 * Returns an immutable set of bodies that consists of this disjunction
44 *
45 * @return the bodies
46 */
47 public Set<PBody> getBodies() {
48 return bodies;
49 }
50
51 /**
52 * Returns the corresponding query specification. May be null if not set.
53 */
54 public PQuery getQuery() {
55 return query;
56 }
57
58 /**
59 * Returns all queries directly referred in the constraints. They are all required to evaluate this query
60 *
61 * @return a non-null, but possibly empty list of query definitions
62 */
63 public Set<PQuery> getDirectReferredQueries() {
64 return this.getBodies().stream().
65 flatMap(PQueries.directlyReferencedQueriesFunction()). // flatten stream of streams
66 collect(Collectors.toCollection(LinkedHashSet::new));
67 }
68
69 /**
70 * Returns all queries required to evaluate this query (transitively).
71 *
72 * @return a non-null, but possibly empty list of query definitions
73 */
74 public Set<PQuery> getAllReferredQueries() {
75 Set<PQuery> processedQueries = new LinkedHashSet<>();
76 processedQueries.add(this.getQuery());
77 Set<PQuery> foundQueries = getDirectReferredQueries();
78 Set<PQuery> newQueries = new LinkedHashSet<>(foundQueries);
79
80 while(!processedQueries.containsAll(newQueries)) {
81 PQuery query = newQueries.iterator().next();
82 processedQueries.add(query);
83 newQueries.remove(query);
84 Set<PQuery> referred = query.getDirectReferredQueries();
85 referred.removeAll(processedQueries);
86 foundQueries.addAll(referred);
87 newQueries.addAll(referred);
88 }
89 return foundQueries;
90 }
91
92 /**
93 * Decides whether a disjunction is mutable. A disjunction is mutable if all its contained bodies are mutable.
94 *
95 */
96 public boolean isMutable() {
97 for (PBody body : bodies) {
98 if (!body.isMutable()) {
99 return false;
100 }
101 }
102 return true;
103 }
104}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameter.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameter.java
new file mode 100644
index 00000000..07165aa2
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameter.java
@@ -0,0 +1,105 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11import java.util.Objects;
12
13import tools.refinery.viatra.runtime.matchers.context.IInputKey;
14
15/**
16 * A descriptor for declared PQuery parameters. A parameter has a name, a declared type and a direction constraint
17 *
18 * @author Zoltan Ujhelyi
19 *
20 */
21public class PParameter {
22
23 private final String name;
24 private final String typeName;
25 private final IInputKey declaredUnaryType;
26 private final PParameterDirection direction;
27
28 public PParameter(String name) {
29 this(name, (String) null);
30 }
31
32 public PParameter(String name, String typeName) {
33 this(name, typeName, (IInputKey) null);
34 }
35
36 public PParameter(String name, String typeName, IInputKey declaredUnaryType) {
37 this(name, typeName, declaredUnaryType, PParameterDirection.INOUT);
38 }
39
40 /**
41 * @since 1.4
42 */
43 public PParameter(String name, String typeName, IInputKey declaredUnaryType, PParameterDirection direction) {
44 super();
45 this.name = name;
46 this.typeName = typeName;
47 this.declaredUnaryType = declaredUnaryType;
48 this.direction = direction;
49
50 if (declaredUnaryType != null && declaredUnaryType.getArity() != 1) {
51 throw new IllegalArgumentException(
52 "PParameter declared type must be unary instead of " + declaredUnaryType.getPrettyPrintableName());
53 }
54 }
55
56 /**
57 * @return the direction
58 * @since 1.4
59 */
60 public PParameterDirection getDirection() {
61 return direction;
62 }
63
64 /**
65 * @return the name of the parameter
66 */
67 public String getName() {
68 return name;
69 }
70
71 /**
72 * Returns a textual representation of the declared type of the parameter
73 *
74 * @return the type description, or null if not available
75 */
76 public String getTypeName() {
77 return typeName;
78 }
79
80 /**
81 * Yield an {@link IInputKey} representation of the type declared for this parameter.
82 *
83 * @return the unary type that was declared on this parameter in the query header, or null if not available
84 */
85 public IInputKey getDeclaredUnaryType() {
86 return declaredUnaryType;
87 }
88
89 @Override
90 public boolean equals(Object obj) {
91 if (obj instanceof PParameter) {
92 return Objects.equals(name, ((PParameter) obj).name)
93 && Objects.equals(typeName, ((PParameter) obj).typeName)
94 && Objects.equals(declaredUnaryType, ((PParameter) obj).declaredUnaryType)
95 && Objects.equals(direction, ((PParameter) obj).direction);
96 }
97 return false;
98 }
99
100 @Override
101 public int hashCode() {
102 return Objects.hash(name, typeName, declaredUnaryType);
103 }
104
105}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameterDirection.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameterDirection.java
new file mode 100644
index 00000000..c94d4797
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameterDirection.java
@@ -0,0 +1,35 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11/**
12 * Values of this enum describe a constraint to the calling of patterns regarding its parameters.
13 *
14 * @author Grill Balázs
15 * @since 1.4
16 *
17 */
18public enum PParameterDirection {
19
20 /**
21 * Default value, no additional constraint is applied
22 */
23 INOUT,
24
25 /**
26 * The parameters marked with this constraints shall be set to a value before calling the pattern
27 */
28 IN,
29
30 /**
31 * The parameters marked with this constraints shall not be set to a value before calling the pattern
32 */
33 OUT
34
35}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PProblem.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PProblem.java
new file mode 100644
index 00000000..1fe4f541
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PProblem.java
@@ -0,0 +1,68 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
12
13/**
14 * Represents an error that was detected while the {@link PQuery} object was built from a source.
15 * @author Bergmann Gabor
16 *
17 */
18public class PProblem {
19
20 private final String shortMessage;
21 private final String location;
22 private final Exception exception;
23
24 public PProblem(String shortMessage) {
25 this(null, shortMessage, null, null);
26 }
27 /**
28 * @since 2.0
29 */
30 public PProblem(String shortMessage, Integer line, Integer column) {
31 this(null, shortMessage, line, column);
32 }
33 public PProblem(QueryProcessingException exception) {
34 this(exception, exception.getShortMessage(), null, null);
35 }
36 public PProblem(Exception exception, String shortMessage) {
37 this(exception, shortMessage, null, null);
38 }
39
40 /**
41 * @since 2.0
42 */
43 public PProblem(Exception exception, String shortMessage, Integer line, Integer column) {
44 this.shortMessage = shortMessage;
45 this.exception = exception;
46 if (line == null) {
47 location = "Unspecified location";
48 } else if (column == null) {
49 location = String.format("Line %d", line);
50 } else {
51 location = String.format("Line %d Column %d", line, column);
52 }
53 }
54
55 public String getShortMessage() {
56 return shortMessage;
57 }
58 public Exception getException() {
59 return exception;
60 }
61 /**
62 * @since 2.0
63 */
64 public String getLocation() {
65 return location;
66 }
67
68}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueries.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueries.java
new file mode 100644
index 00000000..56f8ca76
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueries.java
@@ -0,0 +1,110 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11import java.util.HashSet;
12import java.util.Set;
13import java.util.function.Function;
14import java.util.function.Predicate;
15import java.util.stream.Stream;
16
17import tools.refinery.viatra.runtime.matchers.context.IInputKey;
18import tools.refinery.viatra.runtime.matchers.psystem.IMultiQueryReference;
19import tools.refinery.viatra.runtime.matchers.psystem.ITypeConstraint;
20import tools.refinery.viatra.runtime.matchers.psystem.PBody;
21import tools.refinery.viatra.runtime.matchers.psystem.PTraceable;
22import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.TypeConstraint;
23import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery.PQueryStatus;
24
25/**
26 * Utility class for using PQueries in functional/streaming collection operations effectively
27 *
28 * @author Zoltan Ujhelyi
29 *
30 */
31public final class PQueries {
32
33 /**
34 * Hidden constructor for utility class
35 */
36 private PQueries() {
37 }
38
39 /**
40 * Predicate checking for the status of selected queries
41 *
42 */
43 public static Predicate<PQuery> queryStatusPredicate(final PQueryStatus status) {
44 return query -> query.getStatus().equals(status);
45 }
46
47 /**
48 * Enumerates referred queries (without duplicates) for the given body
49 */
50 public static Function<PBody, Stream<PQuery>> directlyReferencedQueriesFunction() {
51 return body -> (body.getConstraintsOfType(IMultiQueryReference.class).stream()
52 .flatMap(e -> e.getReferredQueries().stream()).distinct());
53 }
54
55 /**
56 * Enumerates directly referred extensional relations (without duplicates) in the canonical form of the given query
57 *
58 * @param enumerablesOnly
59 * only enumerable type constraints are considered
60 * @since 2.0
61 */
62 public static Stream<IInputKey> directlyRequiredTypesOfQuery(PQuery query, boolean enumerablesOnly) {
63 return directlyRequiredTypesOfDisjunction(query.getDisjunctBodies(), enumerablesOnly);
64 }
65
66 /**
67 * Enumerates directly referred extensional relations (without duplicates) for the given formulation of a query.
68 *
69 * @param enumerablesOnly
70 * only enumerable type constraints are considered
71 * @since 2.0
72 */
73 public static Stream<IInputKey> directlyRequiredTypesOfDisjunction(PDisjunction disjunctBodies,
74 boolean enumerablesOnly) {
75 Class<? extends ITypeConstraint> filterClass = enumerablesOnly ? TypeConstraint.class : ITypeConstraint.class;
76 return disjunctBodies.getBodies().stream().flatMap(body -> body.getConstraintsOfType(filterClass).stream())
77 .map(constraint -> constraint.getEquivalentJudgement().getInputKey()).distinct();
78 }
79
80 /**
81 * @since 1.4
82 */
83 public static Predicate<PParameter> parameterDirectionPredicate(final PParameterDirection direction) {
84 return input -> input.getDirection() == direction;
85 }
86
87 /**
88 * Returns all {@link PTraceable}s contained in the given {@link PQuery}: itself, its bodies and their constraints.
89 *
90 * @since 1.6
91 */
92 public static Set<PTraceable> getTraceables(PQuery query) {
93 final Set<PTraceable> traceables = new HashSet<>();
94 traceables.add(query);
95 query.getDisjunctBodies().getBodies().forEach(body -> {
96 traceables.add(body);
97 body.getConstraints().forEach(traceables::add);
98 });
99 return traceables;
100 }
101
102 /**
103 * Calculates the simple name related from a given qualified name by finding the part after the last '.' character.
104 *
105 * @since 2.0
106 */
107 public static String calculateSimpleName(String qualifiedName) {
108 return qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1);
109 }
110}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQuery.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQuery.java
new file mode 100644
index 00000000..a909c650
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQuery.java
@@ -0,0 +1,154 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11import java.util.List;
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
15import tools.refinery.viatra.runtime.matchers.backend.IQueryBackend;
16import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendHintProvider;
17import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
18import tools.refinery.viatra.runtime.matchers.psystem.PBody;
19import tools.refinery.viatra.runtime.matchers.psystem.PTraceable;
20import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
21
22/**
23 * Internal representation of a query / graph pattern (using a constraint system formalism),
24 * to be interpreted by a query evaluator ({@link IQueryBackend}).
25 * End-users of VIATRA Query should access a query as an IQuerySpecification instead.
26 *
27 * <p>
28 * PQuerys are definitions of queries usable inside pattern descriptions. Such description always has (a non-null) name. The query
29 * itself is defined as a (non-empty) set of {@link PBody} instances, the result is the disjunction of the single
30 * {@link PBody} instances. </p>
31 * <p>
32 * A PQuery might be constructed from erroneous patterns or might be uninitialized - this is represented by its status.
33 *
34 * @author Zoltan Ujhelyi
35 * @since 0.8.0
36 * @noimplement This interface is not intended to be implemented by clients. Use {@link BasePQuery} as a base class instead.
37 */
38public interface PQuery extends PQueryHeader, PTraceable {
39
40 // TODO rewritten as / rewritten from traceability to PDisjunction?
41
42 /**
43 * @author Zoltan Ujhelyi
44 *
45 */
46 public enum PQueryStatus {
47 /**
48 * Marks that the query definition is not initialized
49 */
50 UNINITIALIZED,
51 /**
52 * Marks that the query definition is being initialized
53 * @since 1.4
54 */
55 INITIALIZING,
56 /**
57 * The query definition was successfully initialized
58 */
59 OK,
60 /**
61 * The query definition was initialized, but some issues were present
62 */
63 WARNING,
64 /**
65 * The query definition was not successfully initialized because of an error
66 */
67 ERROR
68 }
69
70 /**
71 * Returns all bodies associated with the query in their canonical form. If called multiple times, the same set with
72 * the same contents will be returned.
73 *
74 */
75 PDisjunction getDisjunctBodies();
76
77 /**
78 * Returns all queries directly referred in the constraints. They are all required to evaluate this query
79 *
80 * @return a non-null, but possibly empty list of query definitions
81 */
82 Set<PQuery> getDirectReferredQueries();
83
84 /**
85 * Returns all queries required to evaluate this query (transitively).
86 *
87 * @return a non-null, but possibly empty list of query definitions
88 */
89 Set<PQuery> getAllReferredQueries();
90
91 /**
92 * Returns the initialization status of the definition
93 *
94 */
95 PQueryStatus getStatus();
96
97 /**
98 * Returns a list describing the problems that were found in this query.
99 *
100 * <p> TODO: formulate invariant connecting {@link #getPProblems()} and {@link #getStatus()}.
101 *
102 * @return a non-null, but possibly empty list of problems
103 */
104 List<PProblem> getPProblems();
105
106 /**
107 * Before a modification operation is executed, a mutability check is performed (via the {@link #getStatus()}
108 * implementation, and in case of problems an {@link IllegalStateException} is thrown.
109 */
110 void checkMutability();
111
112 /**
113 * An option to check mutability of the query. It can be used to avoid getting an {@link IllegalStateException} by
114 * the execution of {@link #checkMutability()}.
115 *
116 * @return true if the query specification is still editable
117 */
118 boolean isMutable();
119
120 /**
121 * Optional hints regarding the query evaluation strategy, to be interpreted by the query engine.
122 * <p> To ensure the possibility of external overrides,
123 * the evaluation engine should not directly consult this field,
124 * but use an {@link IQueryBackendHintProvider} instead.
125 */
126 public QueryEvaluationHint getEvaluationHints();
127
128
129 /**
130 * Type information, expressed on query parameters, that all matches of the query are guaranteed to respect.
131 * <p> At the very minimum, this should include the declared types of the parameters.
132 * <p> The type judgement tuples shall contain the <i>parameter index</i>, NOT the {@link PParameter} object.
133 *
134 * @return a non-null set of type judgements that the query guarantees for its matches
135 */
136 public Set<TypeJudgement> getTypeGuarantees();
137
138 /**
139 * If the query definition is uninitialized, initializes it.
140 * @throws ViatraQueryRuntimeException if initialization of query specification fails
141 */
142 public abstract void ensureInitialized();
143
144 /**
145 * Returns the end-user query specification API objects that wrap this query.
146 *
147 * <p> Intended for traceability and debug purposes, not part of normal operation.
148 * Returned list is intended to be appended during query specification construction time.
149 *
150 * @return a non-null, but possibly empty list of query specification objects;
151 */
152 List<Object> publishedAs();
153
154} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueryHeader.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueryHeader.java
new file mode 100644
index 00000000..f3671934
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueryHeader.java
@@ -0,0 +1,101 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11import java.util.List;
12import java.util.Optional;
13
14import tools.refinery.viatra.runtime.matchers.psystem.annotations.PAnnotation;
15
16/**
17 * Represents header information (metainfo) about a query.
18 * <p> To be implemented both by IQuerySpecifications intended for end users,
19 * and the internal query representation {@link PQuery}.
20 *
21 *
22 * @author Bergmann Gabor
23 * @since 0.9
24 */
25public interface PQueryHeader {
26
27 /**
28 * Identifies the pattern for which matchers can be instantiated.
29 */
30 public String getFullyQualifiedName();
31
32 /**
33 * Return the list of parameter names
34 *
35 * @return a non-null, but possibly empty list of parameter names
36 */
37 public List<String> getParameterNames();
38
39 /**
40 * Returns a list of parameter descriptions
41 *
42 * @return a non-null, but possibly empty list of parameter descriptions
43 */
44 public List<PParameter> getParameters();
45
46 /**
47 * Returns the index of a named parameter
48 *
49 * @param parameterName
50 * @return the index, or null of no such parameter is available
51 */
52 public Integer getPositionOfParameter(String parameterName);
53
54 /**
55 * Returns a parameter by name if exists
56 * @since 2.1
57 */
58 default Optional<PParameter> getParameter(String parameterName) {
59 return Optional.ofNullable(getPositionOfParameter(parameterName))
60 .map(getParameters()::get);
61 }
62
63 /**
64 * Returns the list of annotations specified for this query
65 *
66 * @return a non-null, but possibly empty list of annotations
67 */
68 public List<PAnnotation> getAllAnnotations();
69
70 /**
71 * Returns the list of annotations with a specified name
72 *
73 * @param annotationName
74 * @return a non-null, but possibly empty list of annotations
75 */
76 public List<PAnnotation> getAnnotationsByName(String annotationName);
77
78 /**
79 * Returns the first annotation with a specified name
80 *
81 * @since 2.0
82 */
83 public Optional<PAnnotation> getFirstAnnotationByName(String annotationName);
84
85 /**
86 * Returns the visibility information about the query.
87 * @since 2.0
88 */
89 public PVisibility getVisibility();
90
91 /**
92 * Returns the non-qualified name of the query. By default this means returning the qualified name after the last
93 * '.' character.
94 *
95 * @since 2.0
96 */
97 public default String getSimpleName() {
98 return PQueries.calculateSimpleName(getFullyQualifiedName());
99 }
100
101} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PVisibility.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PVisibility.java
new file mode 100644
index 00000000..7cb312bd
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PVisibility.java
@@ -0,0 +1,37 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11/**
12 * @author Zoltan Ujhelyi
13 * @since 2.0
14 *
15 */
16public enum PVisibility {
17
18 /**
19 * A public (default) visibility means a pattern can be called at any time.
20 */
21 PUBLIC,
22 /**
23 * A private query is not expected to be called directly, only by a different query matcher.
24 */
25 PRIVATE,
26 /**
27 * A query that is only used inside a single caller query and is not visible outside its container query. Such
28 * patterns must also fulfill the following additional constraints:
29 *
30 * <ul>
31 * <li>An embedded query must have only a single body.</li>
32 * <li>An embedded query must not be recursice.</li>
33 * </ul>
34 */
35 EMBEDDED
36
37}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/QueryInitializationException.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/QueryInitializationException.java
new file mode 100644
index 00000000..470d7287
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/QueryInitializationException.java
@@ -0,0 +1,35 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
12
13/**
14 * Represent an exception that occurred while initializing the specification of a query.
15 * @author Bergmann Gabor
16 * @since 0.9
17 *
18 */
19public class QueryInitializationException extends QueryProcessingException {
20
21 public QueryInitializationException(String message, String[] context, String shortMessage, Object patternDescription,
22 Throwable cause) {
23 super(message, context, shortMessage, patternDescription, cause);
24 }
25
26 public QueryInitializationException(String message, String[] context, String shortMessage, Object patternDescription) {
27 super(message, context, shortMessage, patternDescription);
28 }
29
30 private static final long serialVersionUID = 9106033062252951489L;
31
32
33
34
35}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/AbstractRewriterTraceSource.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/AbstractRewriterTraceSource.java
new file mode 100644
index 00000000..276b2b42
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/AbstractRewriterTraceSource.java
@@ -0,0 +1,53 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import java.util.Objects;
12
13import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
14import tools.refinery.viatra.runtime.matchers.psystem.PTraceable;
15
16/**
17 * @since 1.6
18 *
19 */
20public class AbstractRewriterTraceSource {
21
22 private IRewriterTraceCollector traceCollector = NopTraceCollector.INSTANCE;
23
24 public void setTraceCollector(IRewriterTraceCollector traceCollector) {
25 this.traceCollector = Objects.requireNonNull(traceCollector);
26 }
27
28 public IPTraceableTraceProvider getTraces() {
29 return traceCollector;
30 }
31
32 protected IRewriterTraceCollector getTraceCollector() {
33 return traceCollector;
34 }
35
36 /**
37 * Mark the given derivative to be originated from the given original constraint.
38 * @since 1.6
39 */
40 protected void addTrace(PTraceable original, PTraceable derivative){
41 traceCollector.addTrace(original, derivative);
42 }
43
44 /**
45 * Indicate that the given derivative is removed from the resulting query, thus its trace
46 * information should be removed also.
47 * @since 1.6
48 */
49 protected void derivativeRemoved(PConstraint derivative, IDerivativeModificationReason reason){
50 traceCollector.derivativeRemoved(derivative, reason);
51 }
52
53}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/ConstraintRemovalReason.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/ConstraintRemovalReason.java
new file mode 100644
index 00000000..237a762d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/ConstraintRemovalReason.java
@@ -0,0 +1,23 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11/**
12 * Common reasons for removing constraint through rewriters
13 *
14 * @noreference This enum is not intended to be referenced by clients.
15 */
16public enum ConstraintRemovalReason implements IDerivativeModificationReason {
17
18 MOOT_EQUALITY,
19 WEAK_INEQUALITY_SELF_LOOP,
20 TYPE_SUBSUMED,
21 DUPLICATE
22
23}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/DefaultFlattenCallPredicate.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/DefaultFlattenCallPredicate.java
new file mode 100644
index 00000000..3b5d7390
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/DefaultFlattenCallPredicate.java
@@ -0,0 +1,23 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Marton Bur, Zoltan Ujhelyi, Akos Horvath, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
11
12/**
13 * @author Marton Bur
14 *
15 */
16public class DefaultFlattenCallPredicate implements IFlattenCallPredicate {
17
18 @Override
19 public boolean shouldFlatten(PositivePatternCall positivePatternCall) {
20 return true;
21 }
22
23}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/FlattenerCopier.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/FlattenerCopier.java
new file mode 100644
index 00000000..06b8d372
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/FlattenerCopier.java
@@ -0,0 +1,129 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Marton Bur, Akos Horvath, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import java.util.HashMap;
12import java.util.List;
13import java.util.Map;
14import java.util.Map.Entry;
15import java.util.Objects;
16import java.util.Set;
17import java.util.stream.Collectors;
18
19import tools.refinery.viatra.runtime.matchers.psystem.PBody;
20import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
21import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
22import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.Equality;
23import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExportedParameter;
24import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExpressionEvaluation;
25import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
26import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
27import tools.refinery.viatra.runtime.matchers.util.Preconditions;
28
29/**
30 * This rewriter class can add new equality constraints to the copied body
31 *
32 * @author Marton Bur
33 *
34 */
35class FlattenerCopier extends PBodyCopier {
36
37 private final Map<PositivePatternCall, CallInformation> calls;
38
39 private static class CallInformation {
40 final PBody body;
41 final Map<PVariable, PVariable> variableMapping;
42
43 private CallInformation(PBody body) {
44 this.body = body;
45 this.variableMapping = new HashMap<>();
46 }
47 }
48
49 public FlattenerCopier(PQuery query, Map<PositivePatternCall, PBody> callsToFlatten) {
50 super(query);
51 this.calls = callsToFlatten.entrySet().stream().collect(Collectors.toMap(Entry::getKey, entry -> new CallInformation(entry.getValue())));
52 }
53
54 protected void copyVariable(PositivePatternCall contextPatternCall, PVariable variable, String newName) {
55 PVariable newPVariable = body.getOrCreateVariableByName(newName);
56 calls.get(contextPatternCall).variableMapping.put(variable, newPVariable);
57 variableMapping.put(variable, newPVariable);
58 }
59
60 /**
61 * Merge all variables and constraints from the body called through the given pattern call to a target body. If
62 * multiple bodies are merged into a single one, use the renamer and filter options to avoid collisions.
63 *
64 * @param sourceBody
65 * @param namingTool
66 * @param filter
67 */
68 public void mergeBody(PositivePatternCall contextPatternCall, IVariableRenamer namingTool,
69 IConstraintFilter filter) {
70
71 PBody sourceBody = calls.get(contextPatternCall).body;
72
73 // Copy variables
74 Set<PVariable> allVariables = sourceBody.getAllVariables();
75 for (PVariable pVariable : allVariables) {
76 if (pVariable.isUnique()) {
77 copyVariable(contextPatternCall, pVariable,
78 namingTool.createVariableName(pVariable, sourceBody.getPattern()));
79 }
80 }
81
82 // Copy constraints which are not filtered
83 Set<PConstraint> constraints = sourceBody.getConstraints();
84 for (PConstraint pConstraint : constraints) {
85 if (!(pConstraint instanceof ExportedParameter) && !filter.filter(pConstraint)) {
86 copyConstraint(pConstraint);
87 }
88 }
89 }
90
91 @Override
92 protected void copyPositivePatternCallConstraint(PositivePatternCall positivePatternCall) {
93
94 if (!calls.containsKey(positivePatternCall)) {
95 // If the call was not flattened, copy the constraint
96 super.copyPositivePatternCallConstraint(positivePatternCall);
97 } else {
98 PBody calledBody = Objects.requireNonNull(calls.get(positivePatternCall).body);
99 Preconditions.checkArgument(positivePatternCall.getReferredQuery().equals(calledBody.getPattern()));
100
101 List<PVariable> symbolicParameters = calledBody.getSymbolicParameterVariables();
102 Object[] elements = positivePatternCall.getVariablesTuple().getElements();
103 for (int i = 0; i < elements.length; i++) {
104 // Create equality constraints between the caller PositivePatternCall and the corresponding body
105 // parameter variables
106 createEqualityConstraint((PVariable) elements[i], symbolicParameters.get(i), positivePatternCall);
107 }
108
109 }
110 }
111
112 private void createEqualityConstraint(PVariable pVariable1, PVariable pVariable2,
113 PositivePatternCall contextPatternCall) {
114 PVariable who = variableMapping.get(pVariable1);
115 PVariable withWhom = calls.get(contextPatternCall).variableMapping.get(pVariable2);
116 addTrace(contextPatternCall, new Equality(body, who, withWhom));
117 }
118
119 @Override
120 protected void copyExpressionEvaluationConstraint(final ExpressionEvaluation expressionEvaluation) {
121 Map<PVariable, PVariable> variableMapping = this.variableMapping.entrySet().stream()
122 .filter(input -> expressionEvaluation.getPSystem().getAllVariables().contains(input.getKey()))
123 .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
124
125 PVariable mappedOutputVariable = variableMapping.get(expressionEvaluation.getOutputVariable());
126 addTrace(expressionEvaluation, new ExpressionEvaluation(body, new VariableMappingExpressionEvaluatorWrapper(expressionEvaluation.getEvaluator(), variableMapping), mappedOutputVariable, expressionEvaluation.isUnwinding()));
127 }
128
129}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IConstraintFilter.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IConstraintFilter.java
new file mode 100644
index 00000000..518b9c64
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IConstraintFilter.java
@@ -0,0 +1,48 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Zoltan Ujhelyi, Marton Bur, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
12import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExportedParameter;
13
14/**
15 * Helper interface to exclude constraints from PBody copy processes
16 *
17 * @author Marton Bur
18 *
19 */
20public interface IConstraintFilter {
21 /**
22 * Returns true, if the given constraint should be filtered (thus should not be copied)
23 *
24 * @param constraint
25 * to check
26 * @return true, if the constraint should be filtered
27 */
28 boolean filter(PConstraint constraint);
29
30 public static class ExportedParameterFilter implements IConstraintFilter {
31
32 @Override
33 public boolean filter(PConstraint constraint) {
34 return constraint instanceof ExportedParameter;
35 }
36
37 }
38
39 public static class AllowAllFilter implements IConstraintFilter {
40
41 @Override
42 public boolean filter(PConstraint constraint) {
43 // Nothing is filtered
44 return false;
45 }
46
47 }
48} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IDerivativeModificationReason.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IDerivativeModificationReason.java
new file mode 100644
index 00000000..dbd6a78d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IDerivativeModificationReason.java
@@ -0,0 +1,19 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11/**
12 * This is a role indication interface, implementations may provide a reason about
13 * why a modification is made during PQuery normalization.
14 * @since 1.6
15 *
16 */
17public interface IDerivativeModificationReason {
18
19}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IFlattenCallPredicate.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IFlattenCallPredicate.java
new file mode 100644
index 00000000..7e224e98
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IFlattenCallPredicate.java
@@ -0,0 +1,50 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Marton Bur, Zoltan Ujhelyi, Akos Horvath, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
12
13
14/**
15 * Interface used by the PQueryFlattener to decide which positive pattern calls to flatten
16 *
17 * @author Marton Bur
18 *
19 */
20public interface IFlattenCallPredicate {
21
22 /**
23 * Decides whether the called query by the pattern call should be flattened into the caller or not.
24 *
25 * @param positivePatternCall
26 * the pattern call
27 * @return true if the call should be flattened
28 */
29 boolean shouldFlatten(PositivePatternCall positivePatternCall);
30
31 /**
32 * Flattens only if all operand predicates vote for flattening.
33 * @author Gabor Bergmann
34 * @since 2.1
35 */
36 public static class And implements IFlattenCallPredicate {
37 private IFlattenCallPredicate[] operands;
38 public And(IFlattenCallPredicate... operands) {
39 this.operands = operands;
40 }
41
42 @Override
43 public boolean shouldFlatten(PositivePatternCall positivePatternCall) {
44 for (IFlattenCallPredicate operand : operands) {
45 if (!operand.shouldFlatten(positivePatternCall)) return false;
46 }
47 return true;
48 }
49 }
50}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IPTraceableTraceProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IPTraceableTraceProvider.java
new file mode 100644
index 00000000..84da4d1b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IPTraceableTraceProvider.java
@@ -0,0 +1,55 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import java.util.stream.Stream;
12
13import tools.refinery.viatra.runtime.matchers.psystem.PTraceable;
14import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
15
16/**
17 * This interface provides methods to trace the {@link PTraceable}s of a transformed {@link PQuery} produced by
18 * a {@link PDisjunctionRewriter}. In case the associated rewriter is a composite (a.k.a. {@link PDisjunctionRewriterCacher}),
19 * this trace provider handles traces end-to-end, hiding all the intermediate transformation steps.
20 *
21 * @since 1.6
22 * @noimplement This interface is not intended to be implemented by clients.
23 */
24public interface IPTraceableTraceProvider {
25
26 /**
27 * Find and return the canonical {@link PTraceable}s in the original query which are the sources of the given derivative
28 * {@link PTraceable} according to the transformation.
29 *
30 * @param derivative a {@link PTraceable} which is contained by the {@link PQuery} produced by the associated rewriter
31 * @since 2.0
32 */
33 public Stream<PTraceable> getCanonicalTraceables(PTraceable derivative);
34
35 /**
36 * Find and return the {@link PTraceable}s in the rewritten query which are the destinations of the given source
37 * {@link PTraceable} according to the transformation.
38 *
39 * @param source a {@link PTraceable} which is contained by a {@link PQuery} before rewriting
40 * @since 2.0
41 */
42 public Stream<PTraceable> getRewrittenTraceables(PTraceable source);
43
44 /**
45 * Returns whether the given traceable element has been removed by every rewriter for a reason.
46 */
47 public boolean isRemoved(PTraceable traceable);
48
49 /**
50 * Returns the reasons for which the traceable element has been removed by the rewriters.
51 * @return the reasons of removal during rewriting
52 * @since 2.0
53 */
54 public Stream<IDerivativeModificationReason> getRemovalReasons(PTraceable traceable);
55}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IRewriterTraceCollector.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IRewriterTraceCollector.java
new file mode 100644
index 00000000..70771ea7
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IRewriterTraceCollector.java
@@ -0,0 +1,33 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import tools.refinery.viatra.runtime.matchers.psystem.PTraceable;
12
13/**
14 * This is the internal API of {@link IPTraceableTraceProvider} expected to be used by
15 * copier and rewriter implementations.
16 *
17 * @since 1.6
18 * @noreference This interface is not intended to be referenced by clients.
19 */
20public interface IRewriterTraceCollector extends IPTraceableTraceProvider {
21
22 /**
23 * Mark the given derivative to be originated from the given original constraint.
24 */
25 public void addTrace(PTraceable origin, PTraceable derivative);
26
27 /**
28 * Indicate that the given derivative is removed from the resulting query, thus its trace
29 * information should be removed also.
30 */
31 public void derivativeRemoved(PTraceable derivative, IDerivativeModificationReason reason);
32
33}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IVariableRenamer.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IVariableRenamer.java
new file mode 100644
index 00000000..ce446e0d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IVariableRenamer.java
@@ -0,0 +1,59 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Zoltan Ujhelyi, Marton Bur, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
12import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
13
14/**
15 * Helper interface to ease the naming of the new variables during flattening
16 *
17 * @author Marton Bur
18 *
19 */
20public interface IVariableRenamer {
21 /**
22 * Creates a variable name based on a given variable and a given query. It only creates a String, doesn't set
23 * anything.
24 *
25 * @param pVariable
26 * @param query
27 * @return the new variable name as a String
28 */
29 String createVariableName(PVariable pVariable, PQuery query);
30
31 public class SameName implements IVariableRenamer {
32 @Override
33 public String createVariableName(PVariable pVariable, PQuery query) {
34 return pVariable.getName();
35 }
36 }
37
38 public class HierarchicalName implements IVariableRenamer {
39
40 private int callCount;
41
42 public void setCallCount(int callCount) {
43 this.callCount = callCount;
44 }
45
46 @Override
47 public String createVariableName(PVariable pVariable, PQuery query) {
48 // make sure to keep the "_" prefix before anonymous variables
49 String newVarName = getShortName(query) + "<" + callCount + ">" + "_" + pVariable.getName();
50 return pVariable.getName().startsWith("_") ? "_" + newVarName : newVarName ;
51 }
52
53 private String getShortName(PQuery query) {
54 String fullyQualifiedName = query.getFullyQualifiedName();
55 int beginIndex = fullyQualifiedName.lastIndexOf('.') + 1;
56 return fullyQualifiedName.substring(beginIndex);
57 }
58 }
59} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/MappingTraceCollector.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/MappingTraceCollector.java
new file mode 100644
index 00000000..7429fc60
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/MappingTraceCollector.java
@@ -0,0 +1,135 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import java.util.Collections;
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.LinkedList;
15import java.util.Map;
16import java.util.Queue;
17import java.util.Set;
18import java.util.function.Predicate;
19import java.util.stream.Stream;
20
21import tools.refinery.viatra.runtime.matchers.psystem.PTraceable;
22import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
23import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
24import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
25import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
26import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
27import tools.refinery.viatra.runtime.matchers.util.Preconditions;
28
29/**
30 * Multimap-based implementation to contain and query traces
31 *
32 * @since 1.6
33 *
34 */
35public class MappingTraceCollector implements IRewriterTraceCollector {
36
37 /**
38 * Traces from derivative to original
39 */
40 private final IMultiLookup<PTraceable, PTraceable> traces = CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, Object.class);
41
42 /**
43 * Traces from original to derivative
44 */
45 private final IMultiLookup<PTraceable, PTraceable> inverseTraces = CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, Object.class);
46
47 /**
48 * Reasons for removing {@link PTraceable}s
49 */
50 private final Map<PTraceable, IDerivativeModificationReason> removals = new HashMap<>();
51
52 /**
53 * Decides whether {@link PTraceable} is removed
54 */
55 private final Predicate<PTraceable> removed = removals::containsKey;
56
57 /**
58 * @since 2.0
59 */
60 @Override
61 public Stream<PTraceable> getCanonicalTraceables(PTraceable derivative) {
62 return findTraceEnds(derivative, traces).stream();
63 }
64
65 /**
66 * @since 2.0
67 */
68 @Override
69 public Stream<PTraceable> getRewrittenTraceables(PTraceable source) {
70 return findTraceEnds(source, inverseTraces).stream();
71 }
72
73 /**
74 * Returns the end of trace chains starting from the given {@link PTraceable} along the given trace edges.
75 */
76 private Set<PTraceable> findTraceEnds(PTraceable traceable, IMultiLookup<PTraceable, PTraceable> traceRecords) {
77 if (traceable instanceof PQuery) { // PQueries are preserved
78 return Collections.singleton(traceable);
79 }
80 Set<PTraceable> visited = new HashSet<>();
81 Set<PTraceable> result = new HashSet<>();
82 Queue<PTraceable> queue = new LinkedList<>();
83 queue.add(traceable);
84 while(!queue.isEmpty()){
85 PTraceable aDerivative = queue.poll();
86 // Track visited elements to avoid infinite loop via directed cycles in traces
87 visited.add(aDerivative);
88 IMemoryView<PTraceable> nextOrigins = traceRecords.lookup(aDerivative);
89 if (nextOrigins == null){
90 // End of trace chain
91 result.add(aDerivative);
92 } else {
93 // Follow traces
94 for(PTraceable nextOrigin : nextOrigins){
95 if (!visited.contains(nextOrigin)){
96 queue.add(nextOrigin);
97 }
98 }
99 }
100 }
101 return result;
102 }
103
104 @Override
105 public void addTrace(PTraceable original, PTraceable derivative){
106 traces.addPairOrNop(derivative, original);
107 inverseTraces.addPairOrNop(original, derivative);
108 // Even if this element was marked as removed earlier, now we replace it with another constraint!
109 removals.remove(original);
110 }
111
112 @Override
113 public void derivativeRemoved(PTraceable derivative, IDerivativeModificationReason reason){
114 Preconditions.checkState(!removals.containsKey(derivative), "Traceable %s removed multiple times", derivative);
115 // XXX the derivative must not be removed from the trace chain, as some rewriters, e.g. the normalizer keeps trace links to deleted elements
116 if (!inverseTraces.lookupExists(derivative)) {
117 // If there already exists a trace link, this removal means an update
118 removals.put(derivative, reason);
119 }
120 }
121
122 @Override
123 public boolean isRemoved(PTraceable traceable) {
124 return getRewrittenTraceables(traceable).allMatch(removed);
125 }
126
127 /**
128 * @since 2.0
129 */
130 @Override
131 public Stream<IDerivativeModificationReason> getRemovalReasons(PTraceable traceable) {
132 return getRewrittenTraceables(traceable).filter(removed).map(removals::get);
133 }
134
135}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NeverFlattenCallPredicate.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NeverFlattenCallPredicate.java
new file mode 100644
index 00000000..96c0b205
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NeverFlattenCallPredicate.java
@@ -0,0 +1,26 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
12
13/**
14 * @author Grill Balázs
15 * @since 1.4
16 *
17 */
18public class NeverFlattenCallPredicate implements IFlattenCallPredicate {
19
20
21 @Override
22 public boolean shouldFlatten(PositivePatternCall positivePatternCall) {
23 return false;
24 }
25
26}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NopTraceCollector.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NopTraceCollector.java
new file mode 100644
index 00000000..15cf577e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NopTraceCollector.java
@@ -0,0 +1,68 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import java.util.stream.Stream;
12
13import tools.refinery.viatra.runtime.matchers.psystem.PTraceable;
14
15/**
16 * This implementation does not store any traces and scales to NOP for every traceability feature.
17 * @since 1.6
18 *
19 */
20public class NopTraceCollector implements IRewriterTraceCollector {
21
22 public static final IRewriterTraceCollector INSTANCE = new NopTraceCollector();
23
24 private NopTraceCollector() {
25 // Private constructor to force using the common instance
26 }
27
28 /**
29 * @since 2.0
30 */
31 @Override
32 public Stream<PTraceable> getCanonicalTraceables(PTraceable derivative) {
33 return Stream.empty();
34 }
35
36 /**
37 * @since 2.0
38 */
39 @Override
40 public Stream<PTraceable> getRewrittenTraceables(PTraceable source) {
41 return Stream.empty();
42 }
43
44
45 @Override
46 public void addTrace(PTraceable origin, PTraceable derivative) {
47 // ignored
48 }
49
50 @Override
51 public void derivativeRemoved(PTraceable derivative, IDerivativeModificationReason reason) {
52 // ignored
53 }
54
55 @Override
56 public boolean isRemoved(PTraceable traceable) {
57 return false;
58 }
59
60 /**
61 * @since 2.0
62 */
63 @Override
64 public Stream<IDerivativeModificationReason> getRemovalReasons(PTraceable traceable) {
65 return Stream.empty();
66 }
67
68}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyCopier.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyCopier.java
new file mode 100644
index 00000000..e66c4eea
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyCopier.java
@@ -0,0 +1,306 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Marton Bur, Akos Horvath, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
12import tools.refinery.viatra.runtime.matchers.psystem.EnumerablePConstraint;
13import tools.refinery.viatra.runtime.matchers.psystem.PBody;
14import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
15import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
16import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.*;
17import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.*;
18import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
19import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
20import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IConstraintFilter.AllowAllFilter;
21import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IVariableRenamer.SameName;
22import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
23import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
24
25import java.util.*;
26import java.util.stream.Collectors;
27
28/**
29 * This class can create a new PBody for a PQuery. The result body contains a copy of given variables and constraints.
30 *
31 * @author Marton Bur
32 *
33 */
34public class PBodyCopier extends AbstractRewriterTraceSource {
35
36 /**
37 * The created body
38 */
39 protected PBody body;
40 /**
41 * Mapping between the original and the copied variables
42 */
43 protected Map<PVariable, PVariable> variableMapping = new HashMap<>();
44
45 public Map<PVariable, PVariable> getVariableMapping() {
46 return variableMapping;
47 }
48
49 /**
50 * @since 1.6
51 */
52 public PBodyCopier(PBody body, IRewriterTraceCollector traceCollector) {
53 this.body = new PBody(body.getPattern());
54 setTraceCollector(traceCollector);
55
56 // do the actual copying
57 mergeBody(body);
58 }
59
60 /**
61 * @since 1.6
62 */
63 public PBodyCopier(PQuery query) {
64 this.body = new PBody(query);
65 }
66
67 public void mergeBody(PBody sourceBody) {
68 mergeBody(sourceBody, new SameName(), new AllowAllFilter());
69 }
70
71 /**
72 * Merge all variables and constraints from a source body to a target body. If multiple bodies are merged into a
73 * single one, use the renamer and filter options to avoid collisions.
74 */
75 public void mergeBody(PBody sourceBody, IVariableRenamer namingTool, IConstraintFilter filter) {
76
77 // Copy variables
78 Set<PVariable> allVariables = sourceBody.getAllVariables();
79 for (PVariable pVariable : allVariables) {
80 if (pVariable.isUnique()) {
81 copyVariable(pVariable, namingTool.createVariableName(pVariable, sourceBody.getPattern()));
82 }
83 }
84
85 // Copy exported parameters
86 this.body.setSymbolicParameters(sourceBody.getSymbolicParameters().stream()
87 .map(this::copyExportedParameterConstraint).collect(Collectors.toList()));
88
89 // Copy constraints which are not filtered
90 Set<PConstraint> constraints = sourceBody.getConstraints();
91 for (PConstraint pConstraint : constraints) {
92 if (!(pConstraint instanceof ExportedParameter) && !filter.filter(pConstraint)) {
93 copyConstraint(pConstraint);
94 }
95 }
96
97 // Add trace between original and copied body
98 addTrace(sourceBody, body);
99 }
100
101 protected void copyVariable(PVariable variable, String newName) {
102 PVariable newPVariable = body.getOrCreateVariableByName(newName);
103 variableMapping.put(variable, newPVariable);
104 }
105
106 /**
107 * Returns the body with the copied variables and constraints. The returned body is still uninitialized.
108 */
109 public PBody getCopiedBody() {
110 return body;
111 }
112
113 protected void copyConstraint(PConstraint constraint) {
114 if (constraint instanceof ExportedParameter) {
115 copyExportedParameterConstraint((ExportedParameter) constraint);
116 } else if (constraint instanceof Equality) {
117 copyEqualityConstraint((Equality) constraint);
118 } else if (constraint instanceof Inequality) {
119 copyInequalityConstraint((Inequality) constraint);
120 } else if (constraint instanceof TypeConstraint) {
121 copyTypeConstraint((TypeConstraint) constraint);
122 } else if (constraint instanceof TypeFilterConstraint) {
123 copyTypeFilterConstraint((TypeFilterConstraint) constraint);
124 } else if (constraint instanceof ConstantValue) {
125 copyConstantValueConstraint((ConstantValue) constraint);
126 } else if (constraint instanceof PositivePatternCall) {
127 copyPositivePatternCallConstraint((PositivePatternCall) constraint);
128 } else if (constraint instanceof NegativePatternCall) {
129 copyNegativePatternCallConstraint((NegativePatternCall) constraint);
130 } else if (constraint instanceof BinaryTransitiveClosure) {
131 copyBinaryTransitiveClosureConstraint((BinaryTransitiveClosure) constraint);
132 } else if (constraint instanceof RepresentativeElectionConstraint) {
133 copyRepresentativeElectionConstraint((RepresentativeElectionConstraint) constraint);
134 } else if (constraint instanceof RelationEvaluation) {
135 copyRelationEvaluationConstraint((RelationEvaluation) constraint);
136 } else if (constraint instanceof BinaryReflexiveTransitiveClosure) {
137 copyBinaryReflexiveTransitiveClosureConstraint((BinaryReflexiveTransitiveClosure) constraint);
138 } else if (constraint instanceof PatternMatchCounter) {
139 copyPatternMatchCounterConstraint((PatternMatchCounter) constraint);
140 } else if (constraint instanceof AggregatorConstraint) {
141 copyAggregatorConstraint((AggregatorConstraint) constraint);
142 } else if (constraint instanceof ExpressionEvaluation) {
143 copyExpressionEvaluationConstraint((ExpressionEvaluation) constraint);
144 } else {
145 throw new QueryProcessingException("Unknown PConstraint {0} encountered while copying PBody",
146 new String[] { constraint.getClass().getName() }, "Unknown PConstraint", body.getPattern());
147 }
148 }
149
150 protected ExportedParameter copyExportedParameterConstraint(ExportedParameter exportedParameter) {
151 PVariable mappedPVariable = variableMapping.get(exportedParameter.getParameterVariable());
152 PParameter parameter = exportedParameter.getPatternParameter();
153 ExportedParameter newExportedParameter;
154 newExportedParameter = new ExportedParameter(body, mappedPVariable, parameter);
155 body.getSymbolicParameters().add(newExportedParameter);
156 addTrace(exportedParameter, newExportedParameter);
157 return newExportedParameter;
158 }
159
160 protected void copyEqualityConstraint(Equality equality) {
161 PVariable who = equality.getWho();
162 PVariable withWhom = equality.getWithWhom();
163 addTrace(equality, new Equality(body, variableMapping.get(who), variableMapping.get(withWhom)));
164 }
165
166 protected void copyInequalityConstraint(Inequality inequality) {
167 PVariable who = inequality.getWho();
168 PVariable withWhom = inequality.getWithWhom();
169 addTrace(inequality, new Inequality(body, variableMapping.get(who), variableMapping.get(withWhom)));
170 }
171
172 protected void copyTypeConstraint(TypeConstraint typeConstraint) {
173 PVariable[] mappedVariables = extractMappedVariables(typeConstraint);
174 Tuple variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
175 addTrace(typeConstraint, new TypeConstraint(body, variablesTuple, typeConstraint.getSupplierKey()));
176 }
177
178 protected void copyTypeFilterConstraint(TypeFilterConstraint typeConstraint) {
179 PVariable[] mappedVariables = extractMappedVariables(typeConstraint);
180 Tuple variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
181 addTrace(typeConstraint, new TypeFilterConstraint(body, variablesTuple, typeConstraint.getInputKey()));
182 }
183
184 protected void copyConstantValueConstraint(ConstantValue constantValue) {
185 PVariable pVariable = (PVariable) constantValue.getVariablesTuple().getElements()[0];
186 addTrace(constantValue,
187 new ConstantValue(body, variableMapping.get(pVariable), constantValue.getSupplierKey()));
188 }
189
190 protected void copyPositivePatternCallConstraint(PositivePatternCall positivePatternCall) {
191 PVariable[] mappedVariables = extractMappedVariables(positivePatternCall);
192 Tuple variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
193 addTrace(positivePatternCall,
194 new PositivePatternCall(body, variablesTuple, positivePatternCall.getReferredQuery()));
195 }
196
197 protected void copyNegativePatternCallConstraint(NegativePatternCall negativePatternCall) {
198 PVariable[] mappedVariables = extractMappedVariables(negativePatternCall);
199 Tuple variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
200 addTrace(negativePatternCall,
201 new NegativePatternCall(body, variablesTuple, negativePatternCall.getReferredQuery()));
202 }
203
204 protected void copyBinaryTransitiveClosureConstraint(BinaryTransitiveClosure binaryTransitiveClosure) {
205 PVariable[] mappedVariables = extractMappedVariables(binaryTransitiveClosure);
206 Tuple variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
207 addTrace(binaryTransitiveClosure,
208 new BinaryTransitiveClosure(body, variablesTuple, binaryTransitiveClosure.getReferredQuery()));
209 }
210
211 protected void copyRepresentativeElectionConstraint(RepresentativeElectionConstraint constraint) {
212 var mappedVariables = extractMappedVariables(constraint);
213 var variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
214 addTrace(constraint, new RepresentativeElectionConstraint(body, variablesTuple, constraint.getReferredQuery(),
215 constraint.getConnectivity()));
216 }
217
218 /**
219 * @since 2.8
220 */
221 protected void copyRelationEvaluationConstraint(RelationEvaluation relationEvaluation) {
222 PVariable[] mappedVariables = extractMappedVariables(relationEvaluation);
223 Tuple variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
224 addTrace(relationEvaluation, new RelationEvaluation(body, variablesTuple, relationEvaluation.getReferredQueries(),
225 relationEvaluation.getEvaluator()));
226 }
227
228 /**
229 * @since 2.0
230 */
231 protected void copyBinaryReflexiveTransitiveClosureConstraint(
232 BinaryReflexiveTransitiveClosure binaryReflexiveTransitiveClosure) {
233 PVariable[] mappedVariables = extractMappedVariables(binaryReflexiveTransitiveClosure);
234 Tuple variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
235 addTrace(binaryReflexiveTransitiveClosure,
236 new BinaryReflexiveTransitiveClosure(body, variablesTuple,
237 binaryReflexiveTransitiveClosure.getReferredQuery(),
238 binaryReflexiveTransitiveClosure.getUniverseType()));
239 }
240
241 protected void copyPatternMatchCounterConstraint(PatternMatchCounter patternMatchCounter) {
242 PVariable[] mappedVariables = extractMappedVariables(patternMatchCounter);
243 PVariable mappedResultVariable = variableMapping.get(patternMatchCounter.getResultVariable());
244 Tuple variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
245 addTrace(patternMatchCounter, new PatternMatchCounter(body, variablesTuple,
246 patternMatchCounter.getReferredQuery(), mappedResultVariable));
247 }
248
249 /**
250 * @since 1.4
251 */
252 protected void copyAggregatorConstraint(AggregatorConstraint constraint) {
253 PVariable[] mappedVariables = extractMappedVariables(constraint);
254 PVariable mappedResultVariable = variableMapping.get(constraint.getResultVariable());
255 Tuple variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
256 addTrace(constraint, new AggregatorConstraint(constraint.getAggregator(), body, variablesTuple,
257 constraint.getReferredQuery(), mappedResultVariable, constraint.getAggregatedColumn()));
258 }
259
260 protected void copyExpressionEvaluationConstraint(ExpressionEvaluation expressionEvaluation) {
261 PVariable mappedOutputVariable = variableMapping.get(expressionEvaluation.getOutputVariable());
262 addTrace(expressionEvaluation, new ExpressionEvaluation(body,
263 new VariableMappingExpressionEvaluatorWrapper(expressionEvaluation.getEvaluator(), variableMapping),
264 mappedOutputVariable, expressionEvaluation.isUnwinding()));
265 }
266
267 /**
268 * For positive pattern calls
269 *
270 * @param positivePatternCall
271 * @return the mapped variables to the pattern's parameters
272 */
273 protected PVariable[] extractMappedVariables(EnumerablePConstraint enumerablePConstraint) {
274 Object[] pVariables = enumerablePConstraint.getVariablesTuple().getElements();
275 return mapVariableList(pVariables);
276 }
277
278 /**
279 * For negative and count pattern calls.
280 *
281 * @param patternMatchCounter
282 * @return the mapped variables to the pattern's parameters
283 */
284 private PVariable[] extractMappedVariables(PatternCallBasedDeferred patternCallBasedDeferred) {
285 Object[] pVariables = patternCallBasedDeferred.getActualParametersTuple().getElements();
286 return mapVariableList(pVariables);
287 }
288
289 /**
290 * For type filters.
291 */
292 private PVariable[] extractMappedVariables(TypeFilterConstraint typeFilterConstraint) {
293 Object[] pVariables = typeFilterConstraint.getVariablesTuple().getElements();
294 return mapVariableList(pVariables);
295 }
296
297 private PVariable[] mapVariableList(Object[] pVariables) {
298 List<PVariable> list = new ArrayList<PVariable>();
299 for (int i = 0; i < pVariables.length; i++) {
300 PVariable mappedVariable = variableMapping.get(pVariables[i]);
301 list.add(mappedVariable);
302 }
303 return list.toArray(new PVariable[0]);
304 }
305
306}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyNormalizer.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyNormalizer.java
new file mode 100644
index 00000000..90943129
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyNormalizer.java
@@ -0,0 +1,310 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
11
12import java.util.ArrayList;
13import java.util.Collection;
14import java.util.Collections;
15import java.util.Comparator;
16import java.util.HashMap;
17import java.util.HashSet;
18import java.util.Iterator;
19import java.util.LinkedHashSet;
20import java.util.LinkedList;
21import java.util.List;
22import java.util.Map;
23import java.util.Queue;
24import java.util.Set;
25
26import tools.refinery.viatra.runtime.matchers.context.IInputKey;
27import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
28import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
29import tools.refinery.viatra.runtime.matchers.planning.helpers.TypeHelper;
30import tools.refinery.viatra.runtime.matchers.psystem.ITypeConstraint;
31import tools.refinery.viatra.runtime.matchers.psystem.ITypeInfoProviderConstraint;
32import tools.refinery.viatra.runtime.matchers.psystem.PBody;
33import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
34import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
35import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.Equality;
36import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.Inequality;
37import tools.refinery.viatra.runtime.matchers.psystem.queries.PDisjunction;
38import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
39import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery.PQueryStatus;
40import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
41
42/**
43 * A disjunction rewriter for creating a normalized form of specification, unifying variables and running basic sanity
44 * checks. This rewriter does not copy but modifies directly the original specification, requiring a mutable
45 * disjunction.
46 *
47 * @author Gabor Bergmann
48 *
49 */
50public class PBodyNormalizer extends PDisjunctionRewriter {
51
52 private IQueryMetaContext context;
53
54 public PBodyNormalizer(IQueryMetaContext context) {
55 this.context = context;
56 }
57
58 /**
59 * Returns whether unary constraint elimination is enabled. This behavior can be customized by creating a subclass
60 * with a custom implementation.
61 *
62 * @since 1.6
63 */
64 protected boolean shouldCalculateImpliedTypes(PQuery query) {
65 return true;
66 }
67
68 /**
69 * Returns whether 'weakened alternative' suggestions of the context shall be expanded as additional PConstraints.
70 * This behavior can be customized by creating a subclass
71 * with a custom implementation.
72 *
73 * @since 1.6
74 */
75 protected boolean shouldExpandWeakenedAlternatives(PQuery query) {
76 return false;
77 }
78
79 @Override
80 public PDisjunction rewrite(PDisjunction disjunction) {
81 Set<PBody> normalizedBodies = new LinkedHashSet<>();
82 for (PBody body : disjunction.getBodies()) {
83 PBodyCopier copier = new PBodyCopier(body, getTraceCollector());
84 PBody modifiedBody = copier.getCopiedBody();
85 normalizeBody(modifiedBody);
86 normalizedBodies.add(modifiedBody);
87 modifiedBody.setStatus(PQueryStatus.OK);
88 }
89 return new PDisjunction(normalizedBodies);
90 }
91
92 public void setContext(IQueryMetaContext context) {
93 this.context = context;
94 }
95
96 /**
97 * Provides a normalized version of the pattern body. May return a different version than the original version if
98 * needed.
99 *
100 * @param body
101 */
102 public PBody normalizeBody(PBody body) {
103 try {
104 return normalizeBodyInternal(body);
105 } catch (QueryProcessingException e) {
106 throw new RewriterException("Error during rewriting: {1}", new String[] { e.getMessage() },
107 e.getShortMessage(), body.getPattern(), e);
108 }
109 }
110
111 PBody normalizeBodyInternal(PBody body) {
112 // UNIFICATION AND WEAK INEQUALITY ELIMINATION
113 unifyVariablesAlongEqualities(body);
114 eliminateWeakInequalities(body);
115 removeMootEqualities(body);
116
117 // ADDING WEAKENED ALTERNATIVES
118 if (shouldExpandWeakenedAlternatives(body.getPattern())) {
119 expandWeakenedAlternativeConstraints(body);
120 }
121
122 // CONSTRAINT ELIMINATION WITH TYPE INFERENCE
123 if (shouldCalculateImpliedTypes(body.getPattern())) {
124 eliminateInferrableTypes(body, context);
125 } else {
126 // ELIMINATE DUPLICATE TYPE CONSTRAINTS
127 eliminateDuplicateTypeConstraints(body);
128 }
129
130
131 // PREVENTIVE CHECKS
132 checkSanity(body);
133 return body;
134 }
135
136 private void removeMootEqualities(PBody body) {
137 Set<Equality> equals = body.getConstraintsOfType(Equality.class);
138 for (Equality equality : equals) {
139 if (equality.isMoot()) {
140 equality.delete();
141 derivativeRemoved(equality, ConstraintRemovalReason.MOOT_EQUALITY);
142 }
143 }
144 }
145
146 /**
147 * Unifies allVariables along equalities so that they can be handled as one.
148 *
149 * @param body
150 */
151 void unifyVariablesAlongEqualities(PBody body) {
152 Set<Equality> equals = body.getConstraintsOfType(Equality.class);
153 for (Equality equality : equals) {
154 if (!equality.isMoot()) {
155 equality.getWho().unifyInto(equality.getWithWhom());
156 }
157 }
158 }
159
160 /**
161 * Eliminates weak inequalities if they are not substantiated.
162 *
163 * @param body
164 */
165 void eliminateWeakInequalities(PBody body) {
166 for (Inequality inequality : body.getConstraintsOfType(Inequality.class)){
167 if (inequality.isEliminable()){
168 inequality.eliminateWeak();
169 derivativeRemoved(inequality, ConstraintRemovalReason.WEAK_INEQUALITY_SELF_LOOP);
170 }
171 }
172 }
173
174 /**
175 * Eliminates all type constraints that are inferrable from other constraints.
176 */
177 void eliminateInferrableTypes(final PBody body, IQueryMetaContext context) {
178 Set<TypeJudgement> subsumedByRetainedConstraints = new HashSet<TypeJudgement>();
179 LinkedList<ITypeConstraint> allTypeConstraints = new LinkedList<ITypeConstraint>();
180 for (PConstraint pConstraint : body.getConstraints()) {
181 if (pConstraint instanceof ITypeConstraint) {
182 allTypeConstraints.add((ITypeConstraint) pConstraint);
183 } else if (pConstraint instanceof ITypeInfoProviderConstraint) {
184 // non-type constraints are all retained
185 final Set<TypeJudgement> directJudgements = ((ITypeInfoProviderConstraint) pConstraint)
186 .getImpliedJudgements(context);
187 subsumedByRetainedConstraints = TypeHelper.typeClosure(subsumedByRetainedConstraints, directJudgements,
188 context);
189 }
190 }
191 Comparator<ITypeConstraint> eliminationOrder = (o1, o2) -> {
192 IInputKey type1 = o1.getEquivalentJudgement().getInputKey();
193 IInputKey type2 = o2.getEquivalentJudgement().getInputKey();
194
195 int result = context.getSuggestedEliminationOrdering().compare(type1, type2);
196 return (result == 0)
197 ? PConstraint.COMPARE_BY_MONOTONOUS_ID.compare(o1, o2)
198 : result;
199 };
200
201 Collections.sort(allTypeConstraints, eliminationOrder);
202 Queue<ITypeConstraint> potentialConstraints = allTypeConstraints; // rename for better comprehension
203
204 while (!potentialConstraints.isEmpty()) {
205 ITypeConstraint candidate = potentialConstraints.poll();
206
207 boolean isSubsumed = subsumedByRetainedConstraints.contains(candidate.getEquivalentJudgement());
208 if (!isSubsumed) {
209 Set<TypeJudgement> typeClosure = subsumedByRetainedConstraints;
210 for (ITypeConstraint subsuming : potentialConstraints) { // the remaining ones
211 final Set<TypeJudgement> directJudgements = subsuming.getImpliedJudgements(context);
212 typeClosure = TypeHelper.typeClosure(typeClosure, directJudgements, context);
213
214 if (typeClosure.contains(candidate.getEquivalentJudgement())) {
215 isSubsumed = true;
216 break;
217 }
218 }
219 }
220 if (isSubsumed) { // eliminated
221 candidate.delete();
222 derivativeRemoved(candidate, ConstraintRemovalReason.TYPE_SUBSUMED);
223 } else { // retained
224 subsumedByRetainedConstraints = TypeHelper.typeClosure(subsumedByRetainedConstraints,
225 candidate.getImpliedJudgements(context), context);
226 }
227 }
228 }
229
230 /**
231 * Inserts "weakened alternative" constraints suggested by the meta context that aid in coming up with a query plan.
232 */
233 void expandWeakenedAlternativeConstraints(PBody body) {
234 Set<TypeJudgement> allJudgements = new HashSet<TypeJudgement>();
235 Set<TypeJudgement> newJudgementsToAdd = new HashSet<TypeJudgement>();
236 Queue<TypeJudgement> judgementsToProcess = new LinkedList<TypeJudgement>();
237 Map<TypeJudgement, List<PConstraint>> traceability = CollectionsFactory.createMap();
238
239 for (ITypeConstraint typeConstraint : body.getConstraintsOfType(ITypeConstraint.class)) {
240 TypeJudgement equivalentJudgement = typeConstraint.getEquivalentJudgement();
241 judgementsToProcess.add(equivalentJudgement);
242 allJudgements.add(equivalentJudgement);
243 traceability.computeIfAbsent(equivalentJudgement, k-> new ArrayList<>()).add(typeConstraint);
244 }
245
246 while (!judgementsToProcess.isEmpty()) {
247 TypeJudgement judgement = judgementsToProcess.poll();
248 for (TypeJudgement alternativeJudgement : judgement.getWeakenedAlternativeJudgements(context)) {
249 if (allJudgements.add(alternativeJudgement)) {
250 newJudgementsToAdd.add(alternativeJudgement);
251 judgementsToProcess.add(alternativeJudgement);
252 traceability.merge(
253 alternativeJudgement,
254 traceability.getOrDefault(judgement, new ArrayList<>()),
255 (old,further) -> {old.addAll(further); return old;}
256 );
257 }
258 }
259 }
260
261 for (TypeJudgement typeJudgement : newJudgementsToAdd) {
262 PConstraint newConstraint = typeJudgement.createConstraintFor(body);
263 for (PConstraint source : traceability.getOrDefault(typeJudgement, Collections.emptyList())) {
264 addTrace(source, newConstraint);
265 }
266 }
267 }
268
269 private Object getConstraintKey(PConstraint constraint) {
270 if (constraint instanceof ITypeConstraint) {
271 return ((ITypeConstraint) constraint).getEquivalentJudgement();
272 }
273 // Do not check duplication for any other types
274 return constraint;
275 }
276
277 void eliminateDuplicateTypeConstraints(PBody body) {
278 Map<Object, PConstraint> constraints = new HashMap<>();
279 for (PConstraint constraint : body.getConstraints()) {
280 Object key = getConstraintKey(constraint);
281 // Retain first found instance of a constraint
282 if (!constraints.containsKey(key)) {
283 constraints.put(key, constraint);
284 }
285 }
286
287 // Retain collected constraints, remove everything else
288 Iterator<PConstraint> iterator = body.getConstraints().iterator();
289 Collection<PConstraint> toRetain = constraints.values();
290 while(iterator.hasNext()){
291 PConstraint next = iterator.next();
292 if (!toRetain.contains(next)){
293 derivativeRemoved(next, ConstraintRemovalReason.DUPLICATE);
294 iterator.remove();
295 }
296 }
297 }
298
299 /**
300 * Verifies the sanity of all constraints. Should be issued as a preventive check before layouting.
301 *
302 * @param body
303 * @throws RetePatternBuildException
304 */
305 void checkSanity(PBody body) {
306 for (PConstraint pConstraint : body.getConstraints())
307 pConstraint.checkSanity();
308 }
309
310}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriter.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriter.java
new file mode 100644
index 00000000..c844ccf7
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriter.java
@@ -0,0 +1,27 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import tools.refinery.viatra.runtime.matchers.psystem.queries.PDisjunction;
12import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
13
14/**
15 * An abstract base class for creating alternative representations for PDisjunctions.
16 * @author Zoltan Ujhelyi
17 *
18 */
19public abstract class PDisjunctionRewriter extends AbstractRewriterTraceSource{
20
21 public abstract PDisjunction rewrite(PDisjunction disjunction);
22
23 public PDisjunction rewrite(PQuery query) {
24 return rewrite(query.getDisjunctBodies());
25 }
26
27}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriterCacher.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriterCacher.java
new file mode 100644
index 00000000..eb5422ca
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriterCacher.java
@@ -0,0 +1,64 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import java.util.ArrayList;
12import java.util.Arrays;
13import java.util.Collections;
14import java.util.List;
15import java.util.WeakHashMap;
16
17import tools.refinery.viatra.runtime.matchers.psystem.queries.PDisjunction;
18
19/**
20 * A rewriter that stores the previously computed results of a rewriter or a rewriter chain.
21 *
22 * @author Zoltan Ujhelyi
23 * @since 1.0
24 */
25public class PDisjunctionRewriterCacher extends PDisjunctionRewriter {
26
27 private final List<PDisjunctionRewriter> rewriterChain;
28 private WeakHashMap<PDisjunction, PDisjunction> cachedResults =
29 new WeakHashMap<PDisjunction, PDisjunction>();
30
31 private void setupTraceCollectorInChain(){
32 IRewriterTraceCollector collector = getTraceCollector();
33 for(PDisjunctionRewriter rewriter: rewriterChain){
34 rewriter.setTraceCollector(collector);
35 }
36 }
37
38 public PDisjunctionRewriterCacher(PDisjunctionRewriter rewriter) {
39 rewriterChain = Collections.singletonList(rewriter);
40 }
41
42 public PDisjunctionRewriterCacher(PDisjunctionRewriter... rewriters) {
43 rewriterChain = new ArrayList<>(Arrays.asList(rewriters));
44 }
45
46 public PDisjunctionRewriterCacher(List<PDisjunctionRewriter> rewriterChain) {
47 this.rewriterChain = new ArrayList<>(rewriterChain);
48 }
49
50 @Override
51 public PDisjunction rewrite(PDisjunction disjunction) {
52 if (!cachedResults.containsKey(disjunction)) {
53 PDisjunction rewritten = disjunction;
54 setupTraceCollectorInChain();
55 for (PDisjunctionRewriter rewriter : rewriterChain) {
56 rewritten = rewriter.rewrite(rewritten);
57 }
58
59 cachedResults.put(disjunction, rewritten);
60 }
61 return cachedResults.get(disjunction);
62 }
63
64}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PQueryFlattener.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PQueryFlattener.java
new file mode 100644
index 00000000..76311d8f
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PQueryFlattener.java
@@ -0,0 +1,253 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Marton Bur, Akos Horvath, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import java.util.ArrayDeque;
12import java.util.ArrayList;
13import java.util.Collections;
14import java.util.Deque;
15import java.util.HashMap;
16import java.util.HashSet;
17import java.util.LinkedHashSet;
18import java.util.LinkedList;
19import java.util.List;
20import java.util.Map;
21import java.util.Set;
22
23import tools.refinery.viatra.runtime.matchers.psystem.PBody;
24import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
25import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
26import tools.refinery.viatra.runtime.matchers.psystem.queries.PDisjunction;
27import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
28import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery.PQueryStatus;
29import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IConstraintFilter.AllowAllFilter;
30import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IConstraintFilter.ExportedParameterFilter;
31import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IVariableRenamer.HierarchicalName;
32import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IVariableRenamer.SameName;
33import tools.refinery.viatra.runtime.matchers.util.Preconditions;
34import tools.refinery.viatra.runtime.matchers.util.Sets;
35
36/**
37 * This rewriter class holds the query flattening logic
38 *
39 * @author Marton Bur
40 *
41 */
42public class PQueryFlattener extends PDisjunctionRewriter {
43
44 /**
45 * Utility function to produce the permutation of every possible mapping of values.
46 *
47 * @param values
48 * @return
49 */
50 private static <K, V> Set<Map<K, V>> permutation(Map<K, Set<V>> values) {
51 // An ordering of keys is defined here which will help restoring the appropriate values after the execution of
52 // the cartesian product
53 List<K> keyList = new ArrayList<>(values.keySet());
54
55 // Produce list of value sets with the ordering defined by keyList
56 List<Set<V>> valuesList = new ArrayList<Set<V>>(keyList.size());
57 for (K key : keyList) {
58 valuesList.add(values.get(key));
59 }
60
61 // Cartesian product will obey ordering of the list
62 Set<List<V>> valueMappings = Sets.cartesianProduct(valuesList);
63
64 // Build result
65 Set<Map<K, V>> result = new LinkedHashSet<>();
66 for (List<V> valueList : valueMappings) {
67 Map<K, V> map = new HashMap<>();
68 for (int i = 0; i < keyList.size(); i++) {
69 map.put(keyList.get(i), valueList.get(i));
70 }
71 result.add(map);
72 }
73
74 return result;
75 }
76
77 private IFlattenCallPredicate flattenCallPredicate;
78
79 public PQueryFlattener(IFlattenCallPredicate flattenCallPredicate) {
80 this.flattenCallPredicate = flattenCallPredicate;
81 }
82
83 @Override
84 public PDisjunction rewrite(PDisjunction disjunction) {
85 PQuery query = disjunction.getQuery();
86
87 // Check for recursion
88 Set<PQuery> allReferredQueries = disjunction.getAllReferredQueries();
89 for (PQuery referredQuery : allReferredQueries) {
90 if (referredQuery.getAllReferredQueries().contains(referredQuery)) {
91 throw new RewriterException("Recursive queries are not supported, can't flatten query named \"{1}\"",
92 new String[] { query.getFullyQualifiedName() }, "Unsupported recursive query", query);
93 }
94 }
95
96 return this.doFlatten(disjunction);
97 }
98
99 /**
100 * Return the list of dependencies (including the root) in chronological order
101 *
102 * @param rootDisjunction
103 * @return
104 */
105 private List<PDisjunction> disjunctionDependencies(PDisjunction rootDisjunction) {
106 // Disjunctions are first collected into a list usign a depth-first approach,
107 // which can be iterated backwards while removing duplicates
108 Deque<PDisjunction> stack = new ArrayDeque<>();
109 LinkedList<PDisjunction> list = new LinkedList<>();
110 stack.push(rootDisjunction);
111 list.add(rootDisjunction);
112
113 while (!stack.isEmpty()) {
114 PDisjunction disjunction = stack.pop();
115 // Collect dependencies
116 for (PBody pBody : disjunction.getBodies()) {
117 for (PConstraint constraint : pBody.getConstraints()) {
118 if (constraint instanceof PositivePatternCall) {
119 PositivePatternCall positivePatternCall = (PositivePatternCall) constraint;
120 if (flattenCallPredicate.shouldFlatten(positivePatternCall)) {
121 // If the above preconditions meet, the call should be flattened
122 PDisjunction calledDisjunction = positivePatternCall.getReferredQuery().getDisjunctBodies();
123 stack.push(calledDisjunction);
124 list.add(calledDisjunction);
125 }
126 }
127 }
128 }
129 }
130
131 // Remove duplicates (keeping the last instance) and reverse order
132 Set<PDisjunction> visited = new HashSet<PDisjunction>();
133 List<PDisjunction> result = new ArrayList<PDisjunction>(list.size());
134
135 list.descendingIterator().forEachRemaining(item -> {
136 if (!visited.contains(item)) {
137 result.add(item);
138 visited.add(item);
139 }
140
141 });
142
143 return result;
144 }
145
146 /**
147 * This function holds the actual flattening logic for a PQuery
148 *
149 * @param rootDisjunction
150 * to be flattened
151 * @return the flattened bodies of the pQuery
152 */
153 private PDisjunction doFlatten(PDisjunction rootDisjunction) {
154
155 Map<PDisjunction, Set<PBody>> flatBodyMapping = new HashMap<>();
156
157 List<PDisjunction> dependencies = disjunctionDependencies(rootDisjunction);
158
159 for (PDisjunction disjunction : dependencies) {
160 Set<PBody> flatBodies = new LinkedHashSet<>();
161 for (PBody body : disjunction.getBodies()) {
162 if (isFlatteningNeeded(body)) {
163 Map<PositivePatternCall, Set<PBody>> flattenedBodies = new HashMap<>();
164 for (PConstraint pConstraint : body.getConstraints()) {
165
166 if (pConstraint instanceof PositivePatternCall) {
167 PositivePatternCall positivePatternCall = (PositivePatternCall) pConstraint;
168 if (flattenCallPredicate.shouldFlatten(positivePatternCall)) {
169 // If the above preconditions meet, do the flattening and return the disjoint bodies
170 PDisjunction calledDisjunction = positivePatternCall.getReferredQuery()
171 .getDisjunctBodies();
172
173 Set<PBody> flattenedBodySet = flatBodyMapping.get(calledDisjunction);
174 Preconditions.checkArgument(!flattenedBodySet.isEmpty());
175 flattenedBodies.put(positivePatternCall, flattenedBodySet);
176 }
177 }
178 }
179 flatBodies.addAll(createSetOfFlatPBodies(body, flattenedBodies));
180 } else {
181 flatBodies.add(prepareFlatPBody(body));
182 }
183 }
184 flatBodyMapping.put(disjunction, flatBodies);
185 }
186
187 return new PDisjunction(rootDisjunction.getQuery(), flatBodyMapping.get(rootDisjunction));
188 }
189
190 /**
191 * Creates the flattened bodies based on the caller body and the called (and already flattened) disjunctions
192 *
193 * @param pBody
194 * the body to flatten
195 * @param flattenedDisjunctions
196 * the
197 * @param flattenedCalls
198 * @return
199 */
200 private Set<PBody> createSetOfFlatPBodies(PBody pBody, Map<PositivePatternCall, Set<PBody>> flattenedCalls) {
201 PQuery pQuery = pBody.getPattern();
202
203 Set<Map<PositivePatternCall, PBody>> conjunctedCalls = permutation(flattenedCalls);
204
205 // The result set containing the merged conjuncted bodies
206 Set<PBody> conjunctedBodies = new HashSet<>();
207
208 for (Map<PositivePatternCall, PBody> calledBodies : conjunctedCalls) {
209 FlattenerCopier copier = createBodyCopier(pQuery, calledBodies);
210
211 int i = 0;
212 HierarchicalName hierarchicalNamingTool = new HierarchicalName();
213 for (PositivePatternCall patternCall : calledBodies.keySet()) {
214 // Merge each called body
215 hierarchicalNamingTool.setCallCount(i++);
216 copier.mergeBody(patternCall, hierarchicalNamingTool, new ExportedParameterFilter());
217 }
218
219 // Merge the caller's constraints to the conjunct body
220 copier.mergeBody(pBody);
221
222 PBody copiedBody = copier.getCopiedBody();
223 copiedBody.setStatus(PQueryStatus.OK);
224 conjunctedBodies.add(copiedBody);
225 }
226
227 return conjunctedBodies;
228 }
229
230 private FlattenerCopier createBodyCopier(PQuery query, Map<PositivePatternCall, PBody> calledBodies) {
231 FlattenerCopier flattenerCopier = new FlattenerCopier(query, calledBodies);
232 flattenerCopier.setTraceCollector(getTraceCollector());
233 return flattenerCopier;
234 }
235
236 private PBody prepareFlatPBody(PBody pBody) {
237 PBodyCopier copier = createBodyCopier(pBody.getPattern(), Collections.<PositivePatternCall, PBody> emptyMap());
238 copier.mergeBody(pBody, new SameName(), new AllowAllFilter());
239 // the copying of the body here is necessary for only one containing PDisjunction can be assigned to a PBody
240 return copier.getCopiedBody();
241 }
242
243 private boolean isFlatteningNeeded(PBody pBody) {
244 // Check if the body contains positive pattern call AND if it should be flattened
245 for (PConstraint pConstraint : pBody.getConstraints()) {
246 if (pConstraint instanceof PositivePatternCall) {
247 return flattenCallPredicate.shouldFlatten((PositivePatternCall) pConstraint);
248 }
249 }
250 return false;
251 }
252
253}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/RewriterException.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/RewriterException.java
new file mode 100644
index 00000000..d0fc286b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/RewriterException.java
@@ -0,0 +1,31 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import tools.refinery.viatra.runtime.matchers.psystem.queries.QueryInitializationException;
12
13/**
14 * An exception to wrap various issues during PDisjunction rewriting.
15 * @author Zoltan Ujhelyi
16 *
17 */
18public class RewriterException extends QueryInitializationException {
19
20 private static final long serialVersionUID = -4703825954995497932L;
21
22 public RewriterException(String message, String[] context, String shortMessage, Object patternDescription,
23 Throwable cause) {
24 super(message, context, shortMessage, patternDescription, cause);
25 }
26
27 public RewriterException(String message, String[] context, String shortMessage, Object patternDescription) {
28 super(message, context, shortMessage, patternDescription);
29 }
30
31}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/SurrogateQueryRewriter.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/SurrogateQueryRewriter.java
new file mode 100644
index 00000000..71459558
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/SurrogateQueryRewriter.java
@@ -0,0 +1,63 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import java.util.LinkedHashSet;
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.context.IInputKey;
15import tools.refinery.viatra.runtime.matchers.context.surrogate.SurrogateQueryRegistry;
16import tools.refinery.viatra.runtime.matchers.psystem.PBody;
17import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
18import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
19import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.TypeConstraint;
20import tools.refinery.viatra.runtime.matchers.psystem.queries.PDisjunction;
21import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
22import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery.PQueryStatus;
23import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
24import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
25
26/**
27 * @author Zoltan Ujhelyi
28 *
29 */
30public class SurrogateQueryRewriter extends PDisjunctionRewriter {
31
32 @Override
33 public PDisjunction rewrite(PDisjunction disjunction) {
34 Set<PBody> replacedBodies = new LinkedHashSet<>();
35 for (PBody body : disjunction.getBodies()) {
36 PBodyCopier copier = new PBodyCopier(body, getTraceCollector()) {
37
38 @Override
39 protected void copyTypeConstraint(TypeConstraint typeConstraint) {
40 PVariable[] mappedVariables = extractMappedVariables(typeConstraint);
41 Tuple variablesTuple = Tuples.flatTupleOf((Object[])mappedVariables);
42 final IInputKey supplierKey = typeConstraint.getSupplierKey();
43 if(SurrogateQueryRegistry.instance().hasSurrogateQueryFQN(supplierKey)) {
44 PQuery surrogateQuery = SurrogateQueryRegistry.instance().getSurrogateQuery(supplierKey);
45 if (surrogateQuery == null) {
46 throw new IllegalStateException(
47 String.format("Surrogate query for feature %s not found",
48 supplierKey.getPrettyPrintableName()));
49 }
50 addTrace(typeConstraint, new PositivePatternCall(getCopiedBody(), variablesTuple, surrogateQuery));
51 } else {
52 addTrace(typeConstraint, new TypeConstraint(getCopiedBody(), variablesTuple, supplierKey));
53 }
54 }
55 };
56 PBody modifiedBody = copier.getCopiedBody();
57 replacedBodies.add(modifiedBody);
58 modifiedBody.setStatus(PQueryStatus.OK);
59 }
60 return new PDisjunction(replacedBodies);
61 }
62
63}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/VariableMappingExpressionEvaluatorWrapper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/VariableMappingExpressionEvaluatorWrapper.java
new file mode 100644
index 00000000..10337979
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/VariableMappingExpressionEvaluatorWrapper.java
@@ -0,0 +1,88 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import java.util.HashMap;
12import java.util.LinkedHashMap;
13import java.util.Map;
14
15import tools.refinery.viatra.runtime.matchers.psystem.IExpressionEvaluator;
16import tools.refinery.viatra.runtime.matchers.psystem.IValueProvider;
17import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
18import tools.refinery.viatra.runtime.matchers.util.Preconditions;
19
20/**
21 * A wrapper for {@link IExpressionEvaluator} which is capable of correctly mapping variable names used by the
22 * expression.
23 *
24 * @author Grill Balázs
25 *
26 */
27class VariableMappingExpressionEvaluatorWrapper implements IExpressionEvaluator {
28
29 private final IExpressionEvaluator wrapped;
30 private final Map<String, String> variableMapping;
31
32 public VariableMappingExpressionEvaluatorWrapper(IExpressionEvaluator wrapped,
33 Map<PVariable, PVariable> variableMapping) {
34
35 // Support to rewrap an already wrapped expression.
36 boolean rewrap = wrapped instanceof VariableMappingExpressionEvaluatorWrapper;
37 this.wrapped = rewrap ? ((VariableMappingExpressionEvaluatorWrapper)wrapped).wrapped : wrapped;
38
39 // Instead of just saving the reference of the mapping, save the actual (trimmed) state of the mapping as it
40 // may change during copying (especially during flattening). A LinkedHashMap is used to retain ordering of
41 // original parameter names iterator.
42 this.variableMapping = new LinkedHashMap<>();
43
44 // Index map by variable names
45 Map<String, PVariable> names = new HashMap<>();
46 for (PVariable originalVar : variableMapping.keySet()) {
47 names.put(originalVar.getName(), originalVar);
48 }
49
50 // In case of rewrapping, current names are contained by the previous mapping
51 Map<String, String> previousMapping = null;
52 if (rewrap){
53 previousMapping = ((VariableMappingExpressionEvaluatorWrapper)wrapped).variableMapping;
54 }
55
56 // Populate mapping
57 for (String inputParameterName : this.wrapped.getInputParameterNames()) {
58 String parameterName = rewrap ? previousMapping.get(inputParameterName) : inputParameterName;
59 Preconditions.checkArgument(parameterName != null);
60 PVariable original = names.get(parameterName);
61 Preconditions.checkArgument(original != null);
62 PVariable mapped = variableMapping.get(original);
63 if (mapped != null){
64 this.variableMapping.put(inputParameterName, mapped.getName());
65 }
66 }
67 }
68
69 @Override
70 public String getShortDescription() {
71 return wrapped.getShortDescription();
72 }
73
74 @Override
75 public Iterable<String> getInputParameterNames() {
76 return variableMapping.values();
77 }
78
79 @Override
80 public Object evaluateExpression(final IValueProvider provider) throws Exception {
81 return wrapped.evaluateExpression(variableName -> {
82 String mappedVariableName = variableMapping.get(variableName);
83 Preconditions.checkArgument(mappedVariableName != null, "Could not find variable %s", variableName);
84 return provider.getValue(mappedVariableName);
85 });
86 }
87
88}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/AbstractTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/AbstractTuple.java
new file mode 100644
index 00000000..a26d9193
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/AbstractTuple.java
@@ -0,0 +1,136 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.ArrayList;
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.List;
15import java.util.Map;
16import java.util.Objects;
17import java.util.Set;
18
19/**
20 * Common implementation methods for immutable and volatile tuples. The class should not be used directly in client
21 * code, except for the definition of new tuple implementations.
22 *
23 * @author Zoltan Ujhelyi
24 * @since 1.7
25 */
26public abstract class AbstractTuple implements ITuple {
27
28 /**
29 * As the tuple is supposed to be immutable, do not modify the returned array.
30 *
31 * @return the array containing all elements of this Tuple
32 */
33 @Override
34 public Object[] getElements() {
35 Object[] allElements = new Object[getSize()];
36 for (int i = 0; i < allElements.length; ++i)
37 allElements[i] = get(i);
38 return allElements;
39 }
40
41 /**
42 * @return the set containing all distinct elements of this Tuple, cast as type T
43 */
44 @Override
45 @SuppressWarnings("unchecked")
46 public <T> Set<T> getDistinctElements() {
47 Set<T> result = new HashSet<T>();
48 Object[] elements = getElements();
49 for (Object object : elements) {
50 result.add((T) object);
51 }
52 return result;
53 }
54
55 /**
56 * Calculates an inverted index of the elements of this pattern. For each element, the index of the (last)
57 * occurrence is calculated.
58 *
59 * @return the inverted index mapping each element of this pattern to its index in the array
60 */
61 @Override
62 public Map<Object, Integer> invertIndex() {
63 Map<Object, Integer> result = new HashMap<Object, Integer>();
64 for (int i = 0; i < getSize(); i++)
65 result.put(get(i), i);
66 return result;
67 }
68
69 /**
70 * Calculates an inverted index of the elements of this pattern. For each element, the index of all of its
71 * occurrences is calculated.
72 *
73 * @return the inverted index mapping each element of this pattern to its index in the array
74 */
75 @Override
76 public Map<Object, List<Integer>> invertIndexWithMupliplicity() {
77 Map<Object, List<Integer>> result = new HashMap<Object, List<Integer>>();
78 for (int i = 0; i < getSize(); i++) {
79 Object value = get(i);
80 List<Integer> indices = result.computeIfAbsent(value, v -> new ArrayList<>());
81 indices.add(i);
82 }
83 return result;
84 }
85
86 /**
87 * @since 1.7
88 */
89 protected IndexOutOfBoundsException raiseIndexingError(int index) {
90 return new IndexOutOfBoundsException(
91 String.format("No value at position %d for %s instance %s", index, getClass().getSimpleName(), this));
92 }
93
94 /**
95 * Compares the elements stored in this tuple to another tuple
96 */
97 protected boolean internalEquals(ITuple other) {
98 if (getSize() != other.getSize())
99 return false;
100 boolean result = true;
101 for (int i = 0; result && i < getSize(); ++i) {
102 Object ours = get(i);
103 Object theirs = other.get(i);
104 result = result && Objects.equals(ours, theirs);
105 }
106 return result;
107 }
108
109 @Override
110 public String toString() {
111 StringBuilder s = new StringBuilder();
112 s.append("T(");
113 for (Object o : getElements()) {
114 s.append(o == null ? "null" : o.toString());
115 s.append(';');
116 }
117 s.append(')');
118 return s.toString();
119 }
120
121 /**
122 * @since 1.7
123 */
124 protected int doCalcHash() {
125 final int PRIME = 31;
126 int hash = 1;
127 for (int i = 0; i < getSize(); i++) {
128 hash = PRIME * hash;
129 Object element = get(i);
130 if (element != null)
131 hash += element.hashCode();
132 }
133 return hash;
134 }
135
136} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseFlatTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseFlatTuple.java
new file mode 100644
index 00000000..6f46b763
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseFlatTuple.java
@@ -0,0 +1,20 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11/**
12 * Base class for all flat tuple implementations.
13 * Flat tuples store all elements locally (do not reference other tuples).
14 *
15 * @author Gabor Bergmann
16 * @since 1.7
17 */
18public abstract class BaseFlatTuple extends Tuple {
19
20}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseLeftInheritanceTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseLeftInheritanceTuple.java
new file mode 100644
index 00000000..03f9ea89
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseLeftInheritanceTuple.java
@@ -0,0 +1,65 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11/**
12 * Common functionality of left inheritance tuple implementations.
13 *
14 * <p>Left inheritance tuples inherit their first few elements from another tuple,
15 * and extend it with additional "local" elements.
16 *
17 * @author Gabor Bergmann
18 * @since 1.7
19 */
20public abstract class BaseLeftInheritanceTuple extends Tuple {
21
22 /**
23 * The number of elements that aren't stored locally, but inherited from an ancestor Tuple instead.
24 */
25 protected final int inheritedIndex;
26 /**
27 * This object contains the same elements as the ancestor on the first inheritedIndex positions
28 */
29 protected final Tuple ancestor;
30
31 /**
32 * @param ancestor
33 */
34 public BaseLeftInheritanceTuple(Tuple ancestor) {
35 super();
36 this.ancestor = ancestor;
37 this.inheritedIndex = ancestor.getSize();
38 }
39
40 /**
41 * @return the number of local (non-inherited) elements
42 */
43 public abstract int getLocalSize();
44
45 /**
46 * Optimized equals calculation (prediction: true, since hash values match)
47 */
48 @Override
49 protected boolean internalEquals(ITuple other) {
50 if (other instanceof BaseLeftInheritanceTuple) {
51 BaseLeftInheritanceTuple blit = (BaseLeftInheritanceTuple) other;
52 if (blit.inheritedIndex == this.inheritedIndex) {
53 if (this.ancestor.equals(blit.ancestor)) {
54 return localEquals(blit);
55 } else return false;
56 }
57 }
58 return super.internalEquals(other);
59 }
60
61 /**
62 * Checks the equivalence of local elements only, after ancestor tuple has been determined to be equal.
63 */
64 protected abstract boolean localEquals(BaseLeftInheritanceTuple other);
65}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple.java
new file mode 100644
index 00000000..8bbb0ac2
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple.java
@@ -0,0 +1,60 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.tuple;
11
12import java.util.Arrays;
13
14/**
15 * Default Tuple implementation, with statically unknown arity.
16 * @author Gabor Bergmann
17 */
18public final class FlatTuple extends BaseFlatTuple {
19
20 /**
21 * Array of substituted values. DO NOT MODIFY! Use Constructor to build a new instance instead.
22 */
23 private final Object[] elements;
24
25 /**
26 * Creates a FlatTuple instance, fills it with the given array.
27 * <p> Users should consider calling {@link Tuples#flatTupleOf(Object...)} instead to save memory on low-arity tuples.
28 *
29 * @param elements
30 * array of substitution values
31 */
32 protected FlatTuple(Object... elements) {
33 this.elements = Arrays.copyOf(elements, elements.length);
34 calcHash();
35 }
36
37 @Override
38 public Object get(int index) {
39 return elements[index];
40 }
41
42 @Override
43 public int getSize() {
44 return elements.length;
45 }
46
47 @Override
48 public Object[] getElements() {
49 return elements;
50 }
51
52 @Override
53 protected boolean internalEquals(ITuple other) {
54 if (other instanceof FlatTuple) {
55 return Arrays.equals(elements, ((FlatTuple) other).elements);
56 } else
57 return super.internalEquals(other);
58 }
59
60}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple0.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple0.java
new file mode 100644
index 00000000..93f412b7
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple0.java
@@ -0,0 +1,46 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11/**
12 * Flat tuple with statically known arity of 0.
13 *
14 * @author Gabor Bergmann
15 * @since 1.7
16 *
17 */
18public final class FlatTuple0 extends BaseFlatTuple {
19 protected static final FlatTuple0 INSTANCE = new FlatTuple0();
20
21 private FlatTuple0() {
22 calcHash();
23 }
24
25 @Override
26 public int getSize() {
27 return 0;
28 }
29
30 @Override
31 public Object get(int index) {
32 throw raiseIndexingError(index);
33 }
34
35 private static final Object[] NULLARY_ARRAY = new Object[0];
36
37 @Override
38 public Object[] getElements() {
39 return NULLARY_ARRAY;
40 }
41
42 @Override
43 protected boolean internalEquals(ITuple other) {
44 return 0 == other.getSize();
45 }
46}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple1.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple1.java
new file mode 100644
index 00000000..b3b1c312
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple1.java
@@ -0,0 +1,44 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Objects;
12
13/**
14 * Flat tuple with statically known arity of 1.
15 *
16 * @author Gabor Bergmann
17 * @since 1.7
18 *
19 */
20public final class FlatTuple1 extends BaseFlatTuple {
21 private final Object element0;
22
23 protected FlatTuple1(Object element0) {
24 this.element0 = element0;
25 calcHash();
26 }
27
28 @Override
29 public int getSize() {
30 return 1;
31 }
32
33 @Override
34 public Object get(int index) {
35 if (index == 0) return element0;
36 else throw raiseIndexingError(index);
37 }
38
39 @Override
40 protected boolean internalEquals(ITuple other) {
41 return 1 == other.getSize() &&
42 Objects.equals(element0, other.get(0));
43 }
44}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple2.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple2.java
new file mode 100644
index 00000000..2dcfd718
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple2.java
@@ -0,0 +1,51 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Objects;
12
13/**
14 * Flat tuple with statically known arity of 2.
15 *
16 * @author Gabor Bergmann
17 * @since 1.7
18 *
19 */
20public final class FlatTuple2 extends BaseFlatTuple {
21 private final Object element0;
22 private final Object element1;
23
24 protected FlatTuple2(Object element0, Object element1) {
25 this.element0 = element0;
26 this.element1 = element1;
27 calcHash();
28 }
29
30 @Override
31 public int getSize() {
32 return 2;
33 }
34
35 @Override
36 public Object get(int index) {
37 switch(index) {
38 case 0 : return element0;
39 case 1 : return element1;
40 default: throw raiseIndexingError(index);
41 }
42 }
43
44 @Override
45 protected boolean internalEquals(ITuple other) {
46 return 2 == other.getSize() &&
47 Objects.equals(element0, other.get(0)) &&
48 Objects.equals(element1, other.get(1));
49 }
50
51}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple3.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple3.java
new file mode 100644
index 00000000..50cee57e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple3.java
@@ -0,0 +1,55 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Objects;
12
13/**
14 * Flat tuple with statically known arity of 3.
15 *
16 * @author Gabor Bergmann
17 * @since 1.7
18 *
19 */
20public final class FlatTuple3 extends BaseFlatTuple {
21 private final Object element0;
22 private final Object element1;
23 private final Object element2;
24
25 protected FlatTuple3(Object element0, Object element1, Object element2) {
26 this.element0 = element0;
27 this.element1 = element1;
28 this.element2 = element2;
29 calcHash();
30 }
31
32 @Override
33 public int getSize() {
34 return 3;
35 }
36
37 @Override
38 public Object get(int index) {
39 switch (index) {
40 case 0: return element0;
41 case 1: return element1;
42 case 2: return element2;
43 default: throw raiseIndexingError(index);
44 }
45 }
46
47 @Override
48 protected boolean internalEquals(ITuple other) {
49 return 3 == other.getSize() &&
50 Objects.equals(element0, other.get(0)) &&
51 Objects.equals(element1, other.get(1)) &&
52 Objects.equals(element2, other.get(2));
53 }
54
55}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple4.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple4.java
new file mode 100644
index 00000000..024c94f4
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple4.java
@@ -0,0 +1,59 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Objects;
12
13/**
14 * Flat tuple with statically known arity of 4.
15 *
16 * @author Gabor Bergmann
17 * @since 1.7
18 *
19 */
20public final class FlatTuple4 extends BaseFlatTuple {
21 private final Object element0;
22 private final Object element1;
23 private final Object element2;
24 private final Object element3;
25
26 protected FlatTuple4(Object element0, Object element1, Object element2, Object element3) {
27 this.element0 = element0;
28 this.element1 = element1;
29 this.element2 = element2;
30 this.element3 = element3;
31 calcHash();
32 }
33
34 @Override
35 public int getSize() {
36 return 4;
37 }
38
39 @Override
40 public Object get(int index) {
41 switch(index) {
42 case 0: return element0;
43 case 1: return element1;
44 case 2: return element2;
45 case 3: return element3;
46 default: throw raiseIndexingError(index);
47 }
48 }
49
50 @Override
51 protected boolean internalEquals(ITuple other) {
52 return 4 == other.getSize() &&
53 Objects.equals(element0, other.get(0)) &&
54 Objects.equals(element1, other.get(1)) &&
55 Objects.equals(element2, other.get(2)) &&
56 Objects.equals(element3, other.get(3));
57 }
58
59}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/IModifiableTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/IModifiableTuple.java
new file mode 100644
index 00000000..f5dab2a5
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/IModifiableTuple.java
@@ -0,0 +1,27 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11/**
12 * A tuple that allows modifying the underlying value. Should not be used for non-volatile tuples.
13 *
14 * @author Zoltan Ujhelyi
15 * @since 1.7
16 */
17public interface IModifiableTuple extends ITuple {
18
19 /**
20 * Sets the selected value for a tuple
21 *
22 * @pre: 0 <= index < getSize()
23 *
24 */
25 void set(int index, Object value);
26
27}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/ITuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/ITuple.java
new file mode 100644
index 00000000..92014781
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/ITuple.java
@@ -0,0 +1,64 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.List;
12import java.util.Map;
13import java.util.Set;
14
15/**
16 * Represents both mutable and immutable tuples
17 *
18 * @author Zoltan Ujhelyi
19 * @since 1.7
20 *
21 */
22public interface ITuple {
23
24 /**
25 * @pre: 0 <= index < getSize()
26 *
27 * @return the element at the specified index
28 */
29 Object get(int index);
30
31 /**
32 * As the tuple is supposed to be immutable, do not modify the returned array.
33 * @return the array containing all elements of this Tuple
34 */
35 Object[] getElements();
36
37 /**
38 * @return the set containing all distinct elements of this Tuple, cast as type T
39 */
40 <T> Set<T> getDistinctElements();
41
42 /**
43 * @return number of elements
44 */
45 int getSize();
46
47 /**
48 * Calculates an inverted index of the elements of this pattern. For each element, the index of the (last)
49 * occurrence is calculated.
50 *
51 * @return the inverted index mapping each element of this pattern to its index in the array
52 */
53 Map<Object, Integer> invertIndex();
54
55 /**
56 * Calculates an inverted index of the elements of this pattern. For each element, the index of all of its
57 * occurrences is calculated.
58 *
59 * @return the inverted index mapping each element of this pattern to its index in the array
60 */
61 Map<Object, List<Integer>> invertIndexWithMupliplicity();
62
63 Tuple toImmutable();
64} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple.java
new file mode 100644
index 00000000..dcdfc376
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple.java
@@ -0,0 +1,172 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.tuple;
11
12import java.util.Arrays;
13import java.util.Objects;
14
15/**
16 *
17 * Tuple that inherits another tuple on the left.
18 *
19 * @author Gabor Bergmann
20 *
21 */
22public final class LeftInheritanceTuple extends BaseLeftInheritanceTuple {
23 /**
24 * Array of substituted values above inheritedIndex. DO NOT MODIFY! Use Constructor to build a new instance instead.
25 */
26 private final Object[] localElements;
27
28 //
29 // /**
30 // * Creates a Tuple instance, fills it with the given array.
31 // * @pre: no elements are null
32 // * @param elements array of substitution values
33 // */
34 // public Tuple(Object[] elements)
35 // {
36 // this.localElements = elements;
37 // this.ancestor=null;
38 // this.inheritedIndex = 0;
39 // calcHash();
40 // }
41
42
43
44 /**
45 * Creates a Tuple instance, lets it inherit from an ancestor, extends it with a given array. @pre: no elements are
46 * null
47 *
48 * @param localElements
49 * array of substitution values
50 */
51 LeftInheritanceTuple(Tuple ancestor, Object[] localElements) {
52 super(ancestor);
53 this.localElements = localElements;
54 calcHash();
55 }
56
57 //
58 // /**
59 // * Creates a Tuple instance of size one, fills it with the given object.
60 // * @pre: o!=null
61 // * @param o the single substitution
62 // */
63 // public Tuple(Object o)
64 // {
65 // localElements = new Object [1];
66 // localElements[0] = o;
67 // this.ancestor=null;
68 // this.inheritedIndex = 0;
69 // calcHash();
70 // }
71 //
72 // /**
73 // * Creates a Tuple instance of size two, fills it with the given objects.
74 // * @pre: o1!=null, o2!=null
75 // */
76 // public Tuple(Object o1, Object o2)
77 // {
78 // localElements = new Object [2];
79 // localElements[0] = o1;
80 // localElements[1] = o2;
81 // this.ancestor=null;
82 // this.inheritedIndex = 0;
83 // calcHash();
84 // }
85 //
86 // /**
87 // * Creates a Tuple instance of size three, fills it with the given
88 // objects.
89 // * @pre: o1!=null, o2!=null, o3!=null
90 // */
91 // public Tuple(Object o1, Object o2, Object o3)
92 // {
93 // localElements = new Object [3];
94 // localElements[0] = o1;
95 // localElements[1] = o2;
96 // localElements[2] = o3;
97 // this.ancestor=null;
98 // this.inheritedIndex = 0;
99 // calcHash();
100 // }
101
102 /**
103 * @return number of elements
104 */
105 public int getSize() {
106 return inheritedIndex + localElements.length;
107 }
108
109 @Override
110 public int getLocalSize() {
111 return localElements.length;
112 }
113
114 /**
115 * @pre: 0 <= index < getSize()
116 *
117 * @return the element at the specified index
118 */
119 public Object get(int index) {
120 return (index < inheritedIndex) ? ancestor.get(index) : localElements[index - inheritedIndex];
121 }
122
123 /**
124 * Optimized hash calculation
125 */
126 @Override
127 void calcHash() {
128 final int PRIME = 31;
129 cachedHash = ancestor.hashCode();
130 for (int i = 0; i < localElements.length; i++) {
131 cachedHash = PRIME * cachedHash;
132 Object element = localElements[i];
133 if (element != null)
134 cachedHash += element.hashCode();
135 }
136 }
137
138 /**
139 * Optimized equals calculation (prediction: true, since hash values match)
140 */
141 @Override
142 protected boolean localEquals(BaseLeftInheritanceTuple other) {
143 if (other instanceof LeftInheritanceTuple) {
144 LeftInheritanceTuple lit = (LeftInheritanceTuple)other;
145 return Arrays.equals(this.localElements, lit.localElements);
146 } else {
147 if (localElements.length != other.getLocalSize())
148 return false;
149 int index = inheritedIndex;
150 for (int i = 0; i<localElements.length; ++i) {
151 if (! Objects.equals(localElements[i], other.get(index++)))
152 return false;
153 }
154 return true;
155 }
156 }
157
158 // public int compareTo(Object arg0) {
159 // Tuple other = (Tuple) arg0;
160 //
161 // int retVal = cachedHash - other.cachedHash;
162 // if (retVal==0) retVal = elements.length - other.elements.length;
163 // for (int i=0; retVal==0 && i<elements.length; ++i)
164 // {
165 // if (elements[i] == null && other.elements[i] != null) retVal = -1;
166 // else if (other.elements[i] == null) retVal = 1;
167 // else retVal = elements[i].compareTo(other.elements[i]);
168 // }
169 // return retVal;
170 // }
171
172}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple1.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple1.java
new file mode 100644
index 00000000..61123176
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple1.java
@@ -0,0 +1,83 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Objects;
12
13/**
14 * @author Gabor Bergmann
15 * @since 1.7
16 */
17public final class LeftInheritanceTuple1 extends BaseLeftInheritanceTuple {
18 /**
19 * A single substituted value after inheritedIndex.
20 */
21 private final Object localElement;
22
23 /**
24 * @param ancestor
25 * @param localElement
26 */
27 protected LeftInheritanceTuple1(Tuple ancestor, Object localElement) {
28 super(ancestor);
29 this.localElement = localElement;
30 calcHash();
31 }
32
33 /**
34 * @return number of elements
35 */
36 public int getSize() {
37 return inheritedIndex + 1;
38 }
39
40 @Override
41 public int getLocalSize() {
42 return 1;
43 }
44
45 /**
46 * @pre: 0 <= index < getSize()
47 *
48 * @return the element at the specified index
49 */
50 public Object get(int index) {
51 int local = index - inheritedIndex;
52 if (local < 0)
53 return ancestor.get(index);
54 else if (local == 0) return localElement;
55 else throw raiseIndexingError(index);
56 }
57
58 /**
59 * Optimized hash calculation
60 */
61 @Override
62 void calcHash() {
63 final int PRIME = 31;
64 cachedHash = ancestor.hashCode();
65 cachedHash = PRIME * cachedHash;
66 if (localElement != null) cachedHash += localElement.hashCode();
67 }
68
69 /**
70 * Optimized equals calculation (prediction: true, since hash values match)
71 */
72 @Override
73 protected boolean localEquals(BaseLeftInheritanceTuple other) {
74 if (other instanceof LeftInheritanceTuple1) {
75 LeftInheritanceTuple1 lit = (LeftInheritanceTuple1)other;
76 return Objects.equals(this.localElement, lit.localElement);
77 } else {
78 return (1 == other.getLocalSize()) &&
79 Objects.equals(localElement, other.get(inheritedIndex));
80 }
81 }
82
83}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple2.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple2.java
new file mode 100644
index 00000000..e9fb98e8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple2.java
@@ -0,0 +1,73 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Objects;
12
13/**
14 * @author Gabor Bergmann
15 * @since 1.7
16 */
17public final class LeftInheritanceTuple2 extends BaseLeftInheritanceTuple {
18 private final Object localElement0;
19 private final Object localElement1;
20
21 protected LeftInheritanceTuple2(Tuple ancestor, Object localElement0, Object localElement1) {
22 super(ancestor);
23 this.localElement0 = localElement0;
24 this.localElement1 = localElement1;
25 calcHash();
26 }
27
28 @Override
29 public int getLocalSize() {
30 return 2;
31 }
32
33 @Override
34 public int getSize() {
35 return inheritedIndex + 2;
36 }
37
38 @Override
39 public Object get(int index) {
40 int local = index - inheritedIndex;
41 if (local < 0)
42 return ancestor.get(index);
43 else if (local == 0) return localElement0;
44 else if (local == 1) return localElement1;
45 else throw raiseIndexingError(index);
46 }
47
48 /**
49 * Optimized hash calculation
50 */
51 @Override
52 void calcHash() {
53 final int PRIME = 31;
54 cachedHash = ancestor.hashCode();
55 cachedHash = PRIME * cachedHash;
56 if (localElement0 != null) cachedHash += localElement0.hashCode();
57 cachedHash = PRIME * cachedHash;
58 if (localElement1 != null) cachedHash += localElement1.hashCode();
59 }
60
61 @Override
62 protected boolean localEquals(BaseLeftInheritanceTuple other) {
63 if (other instanceof LeftInheritanceTuple2) {
64 LeftInheritanceTuple2 lit = (LeftInheritanceTuple2)other;
65 return Objects.equals(this.localElement0, lit.localElement0) &&
66 Objects.equals(this.localElement1, lit.localElement1);
67 } else {
68 return (2 == other.getLocalSize()) &&
69 Objects.equals(localElement0, other.get(inheritedIndex)) &&
70 Objects.equals(localElement1, other.get(inheritedIndex + 1));
71 }
72 }
73}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple3.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple3.java
new file mode 100644
index 00000000..e61d196f
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple3.java
@@ -0,0 +1,81 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Objects;
12
13/**
14 * @author Gabor Bergmann
15 * @since 1.7
16 */
17public final class LeftInheritanceTuple3 extends BaseLeftInheritanceTuple {
18 private final Object localElement0;
19 private final Object localElement1;
20 private final Object localElement2;
21
22 protected LeftInheritanceTuple3(Tuple ancestor, Object localElement0, Object localElement1, Object localElement2) {
23 super(ancestor);
24 this.localElement0 = localElement0;
25 this.localElement1 = localElement1;
26 this.localElement2 = localElement2;
27 calcHash();
28 }
29
30 @Override
31 public int getLocalSize() {
32 return 3;
33 }
34
35 @Override
36 public int getSize() {
37 return inheritedIndex + 3;
38 }
39
40 @Override
41 public Object get(int index) {
42 int local = index - inheritedIndex;
43 if (local < 0)
44 return ancestor.get(index);
45 else if (local == 0) return localElement0;
46 else if (local == 1) return localElement1;
47 else if (local == 2) return localElement2;
48 else throw raiseIndexingError(index);
49 }
50
51 /**
52 * Optimized hash calculation
53 */
54 @Override
55 void calcHash() {
56 final int PRIME = 31;
57 cachedHash = ancestor.hashCode();
58 cachedHash = PRIME * cachedHash;
59 if (localElement0 != null) cachedHash += localElement0.hashCode();
60 cachedHash = PRIME * cachedHash;
61 if (localElement1 != null) cachedHash += localElement1.hashCode();
62 cachedHash = PRIME * cachedHash;
63 if (localElement2 != null) cachedHash += localElement2.hashCode();
64 }
65
66 @Override
67 protected boolean localEquals(BaseLeftInheritanceTuple other) {
68 if (other instanceof LeftInheritanceTuple3) {
69 LeftInheritanceTuple3 lit = (LeftInheritanceTuple3)other;
70 return Objects.equals(this.localElement0, lit.localElement0) &&
71 Objects.equals(this.localElement1, lit.localElement1) &&
72 Objects.equals(this.localElement2, lit.localElement2);
73 } else {
74 return (3 == other.getLocalSize()) &&
75 Objects.equals(localElement0, other.get(inheritedIndex)) &&
76 Objects.equals(localElement1, other.get(inheritedIndex + 1)) &&
77 Objects.equals(localElement2, other.get(inheritedIndex + 2));
78 }
79 }
80
81}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple4.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple4.java
new file mode 100644
index 00000000..4e50f1e1
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple4.java
@@ -0,0 +1,88 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Objects;
12
13/**
14 * @author Gabor Bergmann
15 * @since 1.7
16 */
17public final class LeftInheritanceTuple4 extends BaseLeftInheritanceTuple {
18 private final Object localElement0;
19 private final Object localElement1;
20 private final Object localElement2;
21 private final Object localElement3;
22
23 protected LeftInheritanceTuple4(Tuple ancestor, Object localElement0, Object localElement1, Object localElement2,
24 Object localElement3) {
25 super(ancestor);
26 this.localElement0 = localElement0;
27 this.localElement1 = localElement1;
28 this.localElement2 = localElement2;
29 this.localElement3 = localElement3;
30 calcHash();
31 }
32
33 @Override
34 public int getLocalSize() {
35 return 4;
36 }
37
38 @Override
39 public int getSize() {
40 return inheritedIndex + 4;
41 }
42
43 @Override
44 public Object get(int index) {
45 int local = index - inheritedIndex;
46 if (local < 0)
47 return ancestor.get(index);
48 else if (local == 0) return localElement0;
49 else if (local == 1) return localElement1;
50 else if (local == 2) return localElement2;
51 else if (local == 3) return localElement3;
52 else throw raiseIndexingError(index);
53 }
54
55 /**
56 * Optimized hash calculation
57 */
58 @Override
59 void calcHash() {
60 final int PRIME = 31;
61 cachedHash = ancestor.hashCode();
62 cachedHash = PRIME * cachedHash;
63 if (localElement0 != null) cachedHash += localElement0.hashCode();
64 cachedHash = PRIME * cachedHash;
65 if (localElement1 != null) cachedHash += localElement1.hashCode();
66 cachedHash = PRIME * cachedHash;
67 if (localElement2 != null) cachedHash += localElement2.hashCode();
68 cachedHash = PRIME * cachedHash;
69 if (localElement3 != null) cachedHash += localElement3.hashCode();
70 }
71
72 @Override
73 protected boolean localEquals(BaseLeftInheritanceTuple other) {
74 if (other instanceof LeftInheritanceTuple4) {
75 LeftInheritanceTuple4 lit = (LeftInheritanceTuple4)other;
76 return Objects.equals(this.localElement0, lit.localElement0) &&
77 Objects.equals(this.localElement1, lit.localElement1) &&
78 Objects.equals(this.localElement2, lit.localElement2) &&
79 Objects.equals(this.localElement3, lit.localElement3);
80 } else {
81 return (4 == other.getLocalSize()) &&
82 Objects.equals(localElement0, other.get(inheritedIndex)) &&
83 Objects.equals(localElement1, other.get(inheritedIndex + 1)) &&
84 Objects.equals(localElement2, other.get(inheritedIndex + 2)) &&
85 Objects.equals(localElement3, other.get(inheritedIndex + 3));
86 }
87 }
88}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/MaskedTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/MaskedTuple.java
new file mode 100644
index 00000000..a5d1991c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/MaskedTuple.java
@@ -0,0 +1,48 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2009 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.tuple;
11
12/**
13 * A tuple that transparently provides a masked (transformed) view of another tuple.
14 *
15 * @author Gabor Bergmann
16 * @since 2.0
17 *
18 */
19public class MaskedTuple extends Tuple {
20
21 Tuple wrapped;
22 TupleMask mask;
23
24 public MaskedTuple(Tuple wrapped, TupleMask mask) {
25 super();
26 // if (wrapped instanceof MaskedTuple) {
27 // MaskedTuple parent = (MaskedTuple)wrapped;
28 // this.wrapped = parent.wrapped;
29 // this.mask = mask.transform(parent.mask);
30 // }
31 // else
32 //{
33 this.wrapped = wrapped;
34 this.mask = mask;
35 //}
36 }
37
38 @Override
39 public Object get(int index) {
40 return wrapped.get(mask.indices[index]);
41 }
42
43 @Override
44 public int getSize() {
45 return mask.indices.length;
46 }
47
48}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuple.java
new file mode 100644
index 00000000..d94f545f
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuple.java
@@ -0,0 +1,69 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.tuple;
11
12/**
13 * Immutable tuple. Obtain instances via utility class {@link Tuples}.
14 * @author Gabor Bergmann
15 *
16 */
17public abstract class Tuple extends AbstractTuple {
18
19 /**
20 * Caches precalculated hash value
21 */
22 protected int cachedHash;
23
24 /**
25 * Creates a Tuple instance Derivatives should call calcHash()
26 */
27 protected Tuple() {
28 // calcHash();
29 }
30
31 /**
32 * Hash calculation. Overrides should keep semantics.
33 */
34 void calcHash() {
35 cachedHash = doCalcHash();
36 }
37
38 @Override
39 public boolean equals(Object obj) {
40 if (this == obj)
41 return true;
42 if (obj instanceof ITuple) {
43 final ITuple other = (ITuple) obj;
44 return cachedHash == other.hashCode() && internalEquals(other);
45 }
46 return false;
47 }
48
49 @Override
50 public int hashCode() {
51 // Calculated by #calcHash
52 return cachedHash;
53 }
54
55 public Tuple replaceAll(Object obsolete, Object replacement) {
56 Object[] oldElements = getElements();
57 Object[] newElements = new Object[oldElements.length];
58 for (int i = 0; i < oldElements.length; ++i) {
59 newElements[i] = obsolete.equals(oldElements[i]) ? replacement : oldElements[i];
60 }
61 return Tuples.flatTupleOf(newElements);
62 }
63
64 @Override
65 public Tuple toImmutable() {
66 return this;
67 }
68
69}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask.java
new file mode 100644
index 00000000..49c55fef
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask.java
@@ -0,0 +1,560 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.tuple;
11
12import java.util.ArrayList;
13import java.util.Arrays;
14import java.util.Collection;
15import java.util.HashSet;
16import java.util.LinkedList;
17import java.util.List;
18import java.util.OptionalInt;
19import java.util.Set;
20
21/**
22 *
23 * Specifies select indices of a tuple. If viewed through this mask (see {@link #transform(ITuple)}), the signature of the pattern will consist of its
24 * individual substitutions at the given positions, in the exact same order as they appear in indices[].
25 *
26 * @author Gabor Bergmann
27 */
28public class TupleMask {
29 /**
30 * indices[i] specifies the index of the substitution in the original tuple that occupies the i-th place in the
31 * masked signature.
32 */
33 public final int[] indices;
34 /**
35 * the size of the tuple this mask is applied to
36 */
37 public int sourceWidth;
38 /**
39 * indicesSorted is indices, sorted in ascending order.
40 * null by default, call {@link #ensureIndicesSorted()} before using
41 */
42 int[] indicesSorted;
43
44 /**
45 * true if no index occurs twice; computed on demand by {@link #isNonrepeating()}
46 */
47 Boolean isNonrepeating;
48
49 /**
50 * Creates a TupleMask instance with the given indices array
51 * <p> indicesSorted and isNonrepeating may be OPTIONALLY given if known.
52 * @since 2.0
53 */
54 protected TupleMask(int[] indices, int sourceWidth, int[] indicesSorted, Boolean isNonrepeating) {
55 this.indices = indices;
56 this.sourceWidth = sourceWidth;
57 this.indicesSorted = indicesSorted;
58 this.isNonrepeating = isNonrepeating;
59 }
60
61 /**
62 * Creates a TupleMask instance that selects given positions.
63 * The mask takes ownership of the array selectedIndices, the client must not modify it afterwards.
64 *
65 * <p> indicesSorted and isNonrepeating may be OPTIONALLY given if known.
66 * @since 2.0
67 */
68 protected static TupleMask fromSelectedIndicesInternal(
69 int[] selectedIndices, int sourceArity,
70 int[] indicesSorted, Boolean isNonrepeating)
71 {
72 if (selectedIndices.length == 0) // is it nullary?
73 return new TupleMask0(sourceArity);
74
75 // is it identity?
76 boolean identity = sourceArity == selectedIndices.length;
77 if (identity) {
78 for (int k=0; k < sourceArity; ++k) {
79 if (selectedIndices[k] != k) {
80 identity = false;
81 break;
82 }
83 }
84 }
85 if (identity)
86 return new TupleMaskIdentity(selectedIndices, sourceArity);
87
88 // generic case
89 return new TupleMask(selectedIndices, sourceArity, indicesSorted, isNonrepeating);
90 }
91
92 /**
93 * Creates a TupleMask instance that selects given positions in monotonically increasing order.
94 * The mask takes ownership of the array selectedIndices, the client must not modify it afterwards.
95 * @since 2.0
96 */
97 protected static TupleMask fromSelectedMonotonicIndicesInternal(int[] selectedIndices, int sourceArity)
98 {
99 return fromSelectedIndicesInternal(selectedIndices, sourceArity, selectedIndices /* also sorted */, true);
100 }
101
102 /**
103 * Creates a TupleMask instance of the given size that maps the first 'size' elements intact
104 */
105 public static TupleMask linear(int size, int sourceWidth) {
106 if (size == sourceWidth) return new TupleMaskIdentity(sourceWidth);
107 int[] indices = constructLinearSequence(size);
108 return fromSelectedMonotonicIndicesInternal(indices, sourceWidth);
109 }
110
111 /**
112 * An array containing the first {@link size} nonnegative integers in order
113 * @since 2.0
114 */
115 protected static int[] constructLinearSequence(int size) {
116 int[] indices = new int[size];
117 for (int i = 0; i < size; i++)
118 indices[i] = i;
119 return indices;
120 }
121
122 /**
123 * Creates a TupleMask instance of the given size that maps every single element intact
124 */
125 public static TupleMask identity(int size) {
126 return new TupleMaskIdentity(size);
127 }
128
129 /**
130 * Creates a TupleMask instance of the given size that does not emit output.
131 */
132 public static TupleMask empty(int sourceWidth) {
133 return linear(0, sourceWidth);
134 }
135
136 /**
137 * Creates a TupleMask instance that maps the tuple intact save for a single element at the specified index which is
138 * omitted
139 */
140 public static TupleMask omit(int omission, int sourceWidth) {
141 int size = sourceWidth - 1;
142 int[] indices = new int[size];
143 for (int i = 0; i < omission; i++)
144 indices[i] = i;
145 for (int i = omission; i < size; i++)
146 indices[i] = i + 1;
147 return fromSelectedMonotonicIndicesInternal(indices, sourceWidth);
148 }
149
150
151 /**
152 * Creates a TupleMask instance that selects positions where keep is true
153 * @since 1.7
154 */
155 public static TupleMask fromKeepIndicators(boolean[] keep) {
156 int size = 0;
157 for (int k = 0; k < keep.length; ++k)
158 if (keep[k])
159 size++;
160 if (size == keep.length) return new TupleMaskIdentity(size);
161 int[] indices = new int[size];
162 int l = 0;
163 for (int k = 0; k < keep.length; ++k)
164 if (keep[k])
165 indices[l++] = k;
166 return fromSelectedMonotonicIndicesInternal(indices, keep.length);
167 }
168
169 /**
170 * Creates a TupleMask instance that selects given positions.
171 * @since 1.7
172 */
173 public static TupleMask fromSelectedIndices(int sourceArity, Collection<Integer> selectedIndices) {
174 int[] selected = integersToIntArray(selectedIndices);
175 return fromSelectedIndicesInternal(selected, sourceArity, null, null);
176 }
177 /**
178 * Creates a TupleMask instance that selects given positions.
179 * @since 1.7
180 */
181 public static TupleMask fromSelectedIndices(int sourceArity, int[] selectedIndices) {
182 return fromSelectedIndicesInternal(Arrays.copyOf(selectedIndices, selectedIndices.length), sourceArity, null, null);
183 }
184 /**
185 * Creates a TupleMask instance that selects non-null positions of a given tuple
186 * @since 1.7
187 */
188 public static TupleMask fromNonNullIndices(ITuple tuple) {
189 List<Integer> indices = new ArrayList<>();
190 for (int i=0; i < tuple.getSize(); i++) {
191 if (tuple.get(i) != null) {
192 indices.add(i);
193 }
194 }
195 if (indices.size() == tuple.getSize()) return new TupleMaskIdentity(indices.size());
196 return fromSelectedMonotonicIndicesInternal(integersToIntArray(indices), tuple.getSize());
197 }
198 /**
199 * @since 1.7
200 */
201 public static int[] integersToIntArray(Collection<Integer> selectedIndices) {
202 int[] selected = new int[selectedIndices.size()];
203 int k=0;
204 for (Integer integer : selectedIndices) {
205 selected[k++] = integer;
206 }
207 return selected;
208 }
209
210
211 /**
212 * Creates a TupleMask instance that moves an element from one index to other, shifting the others if neccessary.
213 */
214 public static TupleMask displace(int from, int to, int sourceWidth) {
215 if (from == to) return new TupleMaskIdentity(sourceWidth);
216 int[] indices = new int[sourceWidth];
217 for (int i = 0; i < sourceWidth; i++)
218 if (i == to)
219 indices[i] = from;
220 else if (i >= from && i < to)
221 indices[i] = i + 1;
222 else if (i > to && i <= from)
223 indices[i] = i - 1;
224 else
225 indices[i] = i;
226 return fromSelectedIndicesInternal(indices, sourceWidth, null, true);
227 }
228
229 /**
230 * Creates a TupleMask instance that selects a single element of the tuple.
231 */
232 public static TupleMask selectSingle(int selected, int sourceWidth) {
233 int[] indices = { selected };
234 return fromSelectedMonotonicIndicesInternal(indices, sourceWidth);
235 }
236
237 /**
238 * Creates a TupleMask instance that selects whatever is selected by left, and appends whatever is selected by
239 * right. PRE: left and right have the same sourcewidth
240 */
241 public static TupleMask append(TupleMask left, TupleMask right) {
242 int leftLength = left.indices.length;
243 int rightLength = right.indices.length;
244 int[] indices = new int[leftLength + rightLength];
245 for (int i = 0; i < leftLength; ++i)
246 indices[i] = left.indices[i];
247 for (int i = 0; i < rightLength; ++i)
248 indices[i + leftLength] = right.indices[i];
249 return fromSelectedIndicesInternal(indices, left.sourceWidth, null, null);
250 }
251
252 /**
253 * Generates indicesSorted from indices on demand
254 */
255 void ensureIndicesSorted() {
256 if (indicesSorted == null) {
257 indicesSorted = new int[indices.length];
258 List<Integer> list = new LinkedList<Integer>();
259 for (int i = 0; i < indices.length; ++i)
260 list.add(indices[i]);
261 java.util.Collections.sort(list);
262 int i = 0;
263 for (Integer a : list)
264 indicesSorted[i++] = a;
265 }
266 }
267
268
269
270 /**
271 * Returns the first index of the source that is not selected by the mask, or empty if all indices are selected.
272 * <p> PRE: mask indices are all different
273 * @since 2.0
274 */
275 public OptionalInt getFirstOmittedIndex() {
276 ensureIndicesSorted();
277 int column = 0;
278 while (column < getSize() && indicesSorted[column] == column) column++;
279 if (column < getSourceWidth()) return OptionalInt.of(column);
280 else return OptionalInt.empty();
281 }
282
283
284 /**
285 * Returns a selected masked value from the selected tuple.
286 * @pre: 0 <= index < getSize()
287 * @since 1.7
288 */
289 public Object getValue(ITuple original, int index) {
290 return original.get(indices[index]);
291 }
292
293 /**
294 * Sets the selected value in the original tuple based on the mask definition
295 *
296 * @pre: 0 <= index < getSize()
297 * @since 1.7
298 */
299 public void set(IModifiableTuple tuple, int index, Object value) {
300 tuple.set(indices[index], value);
301 }
302
303 /**
304 * Generates an immutable, masked view of the original tuple.
305 * <p> The new tuple will have arity {@link #getSize()},
306 * and will consist of the elements of the original tuple, at positions indicated by this mask.
307 * @since 1.7
308 */
309 public Tuple transform(ITuple original) {
310 switch (indices.length) {
311 case 0:
312 return FlatTuple0.INSTANCE;
313 case 1:
314 return new FlatTuple1(original.get(indices[0]));
315 case 2:
316 return new FlatTuple2(original.get(indices[0]), original.get(indices[1]));
317 case 3:
318 return new FlatTuple3(original.get(indices[0]), original.get(indices[1]), original.get(indices[2]));
319 case 4:
320 return new FlatTuple4(original.get(indices[0]), original.get(indices[1]), original.get(indices[2]), original.get(indices[3]));
321 default:
322 Object signature[] = new Object[indices.length];
323 for (int i = 0; i < indices.length; ++i)
324 signature[i] = original.get(indices[i]);
325 return new FlatTuple(signature);
326 }
327 }
328
329 /**
330 * @return true iff no two selected indices are the same
331 * @since 2.0
332 */
333 public boolean isNonrepeating() {
334 if (isNonrepeating == null) {
335 ensureIndicesSorted();
336 int previous = -1;
337 int i;
338 for (i = 0; i < sourceWidth && previous != indicesSorted[i]; ++i) {
339 previous = indicesSorted[i];
340 }
341 isNonrepeating = (i == sourceWidth); // if not, stopped due to detected repetition
342 }
343 return isNonrepeating;
344 }
345
346 /**
347 * Returns a tuple `result` that satisfies `this.transform(result).equals(masked)`. Positions of the result tuple
348 * that are not determined this way will be filled with null.
349 *
350 * @pre: all indices of the mask must be different, i.e {@link #isNonrepeating()} must return true
351 * @since 1.7
352 */
353 public Tuple revertFrom(ITuple masked) {
354 Object[] signature = new Object[sourceWidth];
355 for (int i = 0; i < indices.length; ++i)
356 signature[indices[i]] = masked.get(i);
357 return Tuples.flatTupleOf(signature);
358 }
359
360 /**
361 * Returns a tuple `result`, same arity as the original tuple, that satisfies
362 * `this.transform(result).equals(this.transform(tuple))`.
363 * Positions of the result tuple that are not determined this way will be filled with null.
364 * <p> In other words, a copy of the original tuple is returned,
365 * with null substituted at each position that is <em>not</em> selected by this mask.
366 *
367 * @pre: all indices of the mask must be different, i.e {@link #isNonrepeating()} must return true
368 * @since 2.1
369 */
370 public Tuple keepSelectedIndices(ITuple original) {
371 Object[] signature = new Object[sourceWidth];
372 for (int i = 0; i < indices.length; ++i)
373 signature[indices[i]] = original.get(indices[i]);
374 return Tuples.flatTupleOf(signature);
375 }
376
377 /**
378 * Generates an immutable, masked view of the original tuple.
379 * <p> The list will have arity {@link #getSize()},
380 * and will consist of the elements of the original tuple, at positions indicated by this mask.
381 */
382 public <T> List<T> transform(List<T> original) {
383 List<T> signature = new ArrayList<T>(indices.length);
384 for (int i = 0; i < indices.length; ++i)
385 signature.add(original.get(indices[i]));
386 return signature;
387 }
388
389 /**
390 * Transforms a given mask directly, instead of transforming tuples that were transformed by the other mask.
391 *
392 * @return a mask that cascades the effects this mask after the mask provided as parameter.
393 */
394 public TupleMask transform(TupleMask mask) {
395 int[] cascadeIndices = new int[indices.length];
396 for (int i = 0; i < indices.length; ++i)
397 cascadeIndices[i] = mask.indices[indices[i]];
398 return fromSelectedIndicesInternal(cascadeIndices, mask.sourceWidth, null, null);
399 }
400
401 // /**
402 // * Generates a complementer mask that maps those elements that were
403 // untouched by the original mask.
404 // * Ordering is left intact.
405 // * A Tuple is used for reference concerning possible equalities among
406 // elements.
407 // */
408 // public TupleMask complementer(Tuple reference)
409 // {
410 // HashSet<Object> touched = new HashSet<Object>();
411 // LinkedList<Integer> untouched = new LinkedList<Integer>();
412 //
413 // for (int index : indices) touched.add(reference.get(index));
414 // for (int index=0; index<reference.getSize(); ++index)
415 // {
416 // if (touched.add(reference.get(index))) untouched.addLast(index);
417 // }
418 //
419 // int[] complementer = new int[untouched.size()];
420 // int k = 0;
421 // for (Integer integer : untouched) complementer[k++] = integer;
422 // return new TupleMask(complementer, reference.getSize());
423 // }
424
425 /**
426 * Combines two substitutions. The new pattern will contain all substitutions of masked and unmasked, assuming that
427 * the elements of masked indicated by this mask are already matched against unmasked.
428 *
429 * POST: the result will start with an exact copy of unmasked
430 *
431 * @param unmasked
432 * primary pattern substitution that is left intact.
433 * @param masked
434 * secondary pattern substitution that is transformed to the end of the result.
435 * @param useInheritance
436 * whether to use inheritance or copy umasked into result instead.
437 * @param asComplementer
438 * whether this mask maps from the masked Tuple to the tail of the result or to the unmasked one.
439 * @return new pattern that is a combination of unmasked and masked.
440 */
441 public Tuple combine(Tuple unmasked, Tuple masked, boolean useInheritance, boolean asComplementer) {
442
443 int combinedLength = asComplementer ? indices.length : masked.getSize() - indices.length;
444 if (!useInheritance)
445 combinedLength += unmasked.getSize();
446 Object combined[] = new Object[combinedLength];
447
448 int cPos = 0;
449 if (!useInheritance) {
450 for (int i = 0; i < unmasked.getSize(); ++i)
451 combined[cPos++] = unmasked.get(i);
452 }
453
454 if (asComplementer) {
455 for (int i = 0; i < indices.length; ++i)
456 combined[cPos++] = masked.get(indices[i]);
457 } else {
458 ensureIndicesSorted();
459 int mPos = 0;
460 for (int i = 0; i < masked.getSize(); ++i)
461 if (mPos < indicesSorted.length && i == indicesSorted[mPos])
462 mPos++;
463 else
464 combined[cPos++] = masked.get(i);
465 }
466
467 return useInheritance ? Tuples.leftInheritanceTupleOf(unmasked, combined) : Tuples.flatTupleOf(combined);
468 }
469
470 @Override
471 public int hashCode() {
472 final int PRIME = 31;
473 int result = sourceWidth;
474 for (int i : indices)
475 result = PRIME * result + i;
476 return result;
477 }
478
479 @Override
480 public boolean equals(Object obj) {
481 if (this == obj)
482 return true;
483 if (obj == null)
484 return false;
485 if (getClass() != obj.getClass())
486 return false;
487 final TupleMask other = (TupleMask) obj;
488 if (sourceWidth != other.sourceWidth)
489 return false;
490 if (indices.length != other.indices.length)
491 return false;
492 for (int k = 0; k < indices.length; k++)
493 if (indices[k] != other.indices[k])
494 return false;
495 return true;
496 }
497
498 @Override
499 public String toString() {
500 StringBuilder s = new StringBuilder();
501 s.append("M(" + sourceWidth + "->");
502 for (int i : indices) {
503 s.append(i);
504 s.append(',');
505 }
506 s.append(')');
507 return s.toString();
508 }
509
510 /**
511 * Returns the size of the masked tuples described by this mask
512 * @since 1.7
513 */
514 public int getSize() {
515 return indices.length;
516 }
517
518 /**
519 * Returns the size of the original tuples handled by this mask
520 * @since 1.7
521 */
522 public int getSourceWidth() {
523 return sourceWidth;
524 }
525
526
527 /**
528 * @return true iff this mask is a no-op
529 * @since 2.0
530 */
531 public boolean isIdentity() {
532 // Contract: if identity mask, a specialized subclass is constructed instead
533 return false;
534 }
535
536 /**
537 * Transforms the given list by applying the mask and putting all results into a set; keeping only a single element
538 * in case of the mapping result in duplicate values.
539 *
540 * @since 1.7
541 */
542 public <T> Set<T> transformUnique(List<T> original) {
543 Set<T> signature = new HashSet<>();
544 for (int i = 0; i < indices.length; ++i)
545 signature.add(original.get(indices[i]));
546 return signature;
547 }
548
549 /**
550 * @return the list of selected indices
551 * @since 2.1
552 */
553 public List<Integer> getIndicesAsList() {
554 List<Integer> result = new ArrayList<Integer>(indices.length);
555 for (int i = 0; i < indices.length; ++i)
556 result.add(indices[i]);
557 return result;
558 }
559
560}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask0.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask0.java
new file mode 100644
index 00000000..5a0c79ff
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask0.java
@@ -0,0 +1,56 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Collections;
12import java.util.List;
13
14/**
15 * @author Gabor Bergmann
16 * @since 1.7
17 */
18public final class TupleMask0 extends TupleMask {
19
20 private final static int[] EMPTY_ARRAY = {};
21
22 /**
23 * PRE: indices.length == 0
24 */
25 TupleMask0(int sourceWidth) {
26 super(EMPTY_ARRAY, sourceWidth, EMPTY_ARRAY, true);
27 }
28
29 @Override
30 public <T> List<T> transform(List<T> original) {
31 return Collections.emptyList();
32 }
33
34 @Override
35 public Tuple transform(ITuple original) {
36 return Tuples.staticArityFlatTupleOf();
37 }
38
39 @Override
40 public TupleMask transform(TupleMask mask) {
41 return new TupleMask0(mask.sourceWidth);
42 }
43
44 @Override
45 public Tuple combine(Tuple unmasked, Tuple masked, boolean useInheritance, boolean asComplementer) {
46 if (asComplementer)
47 return unmasked;
48 else
49 return super.combine(unmasked, masked, useInheritance, asComplementer);
50 }
51
52 @Override
53 public boolean isIdentity() {
54 return 0 == sourceWidth;
55 }
56}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMaskIdentity.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMaskIdentity.java
new file mode 100644
index 00000000..62746587
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMaskIdentity.java
@@ -0,0 +1,51 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.List;
12
13/**
14 * @author Gabor Bergmann
15 * @since 1.7
16 */
17public final class TupleMaskIdentity extends TupleMask {
18
19 TupleMaskIdentity(int sourceWidth) {
20 this(constructLinearSequence(sourceWidth), sourceWidth);
21 }
22 TupleMaskIdentity(int[] indices, int sourceWidth) {
23 super(indices, sourceWidth, indices, true);
24 }
25
26 @Override
27 public <T> List<T> transform(List<T> original) {
28 return original;
29 }
30
31 @Override
32 public Tuple transform(ITuple original) {
33 return original.toImmutable();
34 }
35
36 @Override
37 public TupleMask transform(TupleMask mask) {
38 return mask;
39 }
40
41 @Override
42 public Tuple revertFrom(ITuple masked) {
43 return masked.toImmutable();
44 }
45
46 @Override
47 public boolean isIdentity() {
48 return true;
49 }
50
51}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleValueProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleValueProvider.java
new file mode 100644
index 00000000..79193516
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleValueProvider.java
@@ -0,0 +1,48 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Map;
12
13import tools.refinery.viatra.runtime.matchers.psystem.IValueProvider;
14
15/**
16 * @author Zoltan Ujhelyi
17 * @since 1.7
18 */
19public class TupleValueProvider implements IValueProvider {
20
21 final ITuple tuple;
22 final Map<String, Integer> indexMapping;
23
24 /**
25 * Wraps a tuple with an index mapping
26 * @param tuple
27 * @param indexMapping
28 */
29 public TupleValueProvider(ITuple tuple, Map<String, Integer> indexMapping) {
30 super();
31 this.tuple = tuple;
32 this.indexMapping = indexMapping;
33 }
34
35 @Override
36 public Object getValue(String variableName) {
37 Integer index = indexMapping.get(variableName);
38 if (index == null) {
39 throw new IllegalArgumentException(String.format("Variable %s is not present in mapping.", variableName));
40 }
41 Object value = tuple.get(index);
42 if (value == null) {
43 throw new IllegalArgumentException(String.format("Variable %s is not found using index %d.", variableName, index));
44 }
45 return value;
46 }
47
48}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuples.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuples.java
new file mode 100644
index 00000000..5e41d7d8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuples.java
@@ -0,0 +1,157 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11/**
12 * Common static factory utilities for tuples.
13 *
14 * @author Gabor Bergmann
15 * @since 1.7
16 */
17public class Tuples {
18
19 private Tuples() {
20 // Empty utility class constructor
21 }
22
23 /**
24 * Creates a flat tuple consisting of the given elements.
25 * For low-arity tuples, specialized implementations
26 * (such as {@link FlatTuple2}) will be instantiated.
27 *
28 * <p> In case the exact arity is <i>statically</i> known,
29 * it may be more efficient for the client to instantiate
30 * the appropriate specialized implementation
31 * (via {@link #staticArityFlatTupleOf(Object, Object)} etc.
32 * or {@link #wideFlatTupleOf(Object...)}),
33 * instead of invoking this method.
34 * This method does a runtime arity check, and therefore
35 * also appropriate if the arity is determined at runtime.
36 */
37 public static Tuple flatTupleOf(Object... elements) {
38 switch (elements.length) {
39 case 0:
40 return FlatTuple0.INSTANCE;
41 case 1:
42 return new FlatTuple1(elements[0]);
43 case 2:
44 return new FlatTuple2(elements[0], elements[1]);
45 case 3:
46 return new FlatTuple3(elements[0], elements[1], elements[2]);
47 case 4:
48 return new FlatTuple4(elements[0], elements[1], elements[2], elements[3]);
49 default:
50 return new FlatTuple(elements);
51 }
52 }
53 /**
54 * Creates a left inheritance tuple that extends an ancestor tuple
55 * by the given "local" elements.
56 * For locally low-arity tuples, specialized implementations
57 * (such as {@link LeftInheritanceTuple2}) will be instantiated.
58 *
59 * <p> In case the exact arity is <i>statically</i> known,
60 * it may be more efficient for the client to instantiate
61 * the appropriate specialized implementation
62 * (via {@link #staticArityLeftInheritanceTupleOf(Object, Object)} etc.
63 * or {@link #wideLeftInheritanceTupleOf(Object...)}),
64 * instead of invoking this method.
65 * This method does a runtime arity check, and therefore
66 * also appropriate if the arity is determined at runtime.
67 */
68 public static Tuple leftInheritanceTupleOf(Tuple ancestor, Object... localElements) {
69 switch (localElements.length) {
70 case 0:
71 return ancestor;
72 case 1:
73 return new LeftInheritanceTuple1(ancestor, localElements[0]);
74 case 2:
75 return new LeftInheritanceTuple2(ancestor, localElements[0], localElements[1]);
76 case 3:
77 return new LeftInheritanceTuple3(ancestor, localElements[0], localElements[1], localElements[2]);
78 case 4:
79 return new LeftInheritanceTuple4(ancestor, localElements[0], localElements[1], localElements[2], localElements[3]);
80 default:
81 return new LeftInheritanceTuple(ancestor, localElements);
82 }
83 }
84
85 /**
86 * Creates a flat tuple consisting of no elements.
87 */
88 public static Tuple staticArityFlatTupleOf() {
89 return FlatTuple0.INSTANCE;
90 }
91 /**
92 * Creates a flat tuple consisting of the given single element.
93 */
94 public static Tuple staticArityFlatTupleOf(Object element) {
95 return new FlatTuple1(element);
96 }
97 /**
98 * Creates a flat tuple consisting of the given elements.
99 */
100 public static Tuple staticArityFlatTupleOf(Object element0, Object element1) {
101 return new FlatTuple2(element0, element1);
102 }
103 /**
104 * Creates a flat tuple consisting of the given elements.
105 */
106 public static Tuple staticArityFlatTupleOf(Object element0, Object element1, Object element2) {
107 return new FlatTuple3(element0, element1, element2);
108 }
109 /**
110 * Creates a flat tuple consisting of the given elements.
111 */
112 public static Tuple staticArityFlatTupleOf(Object element0, Object element1, Object element2, Object element3) {
113 return new FlatTuple4(element0, element1, element2, element3);
114 }
115 /**
116 * Creates a flat tuple consisting of the given elements.
117 * <p> Invoke this only if it is statically known that the tuple will be wide.
118 * Otherwise, use {@link #flatTupleOf(Object...)}.
119 */
120 public static Tuple wideFlatTupleOf(Object... elements) {
121 return new FlatTuple(elements);
122 }
123
124 /**
125 * Creates a left inheritance tuple consisting of the given single local element.
126 */
127 public static Tuple staticArityLeftInheritanceTupleOf(Tuple ancestor, Object element) {
128 return new LeftInheritanceTuple1(ancestor, element);
129 }
130 /**
131 * Creates a left inheritance tuple consisting of the given local elements.
132 */
133 public static Tuple staticArityLeftInheritanceTupleOf(Tuple ancestor, Object element0, Object element1) {
134 return new LeftInheritanceTuple2(ancestor, element0, element1);
135 }
136 /**
137 * Creates a left inheritance tuple consisting of the given local elements.
138 */
139 public static Tuple staticArityLeftInheritanceTupleOf(Tuple ancestor, Object element0, Object element1, Object element2) {
140 return new LeftInheritanceTuple3(ancestor, element0, element1, element2);
141 }
142 /**
143 * Creates a left inheritance tuple consisting of the given local elements.
144 */
145 public static Tuple staticArityLeftInheritanceTupleOf(Tuple ancestor, Object element0, Object element1, Object element2, Object element3) {
146 return new LeftInheritanceTuple4(ancestor, element0, element1, element2, element3);
147 }
148 /**
149 * Creates a left inheritance tuple consisting of the given local elements.
150 * <p> Invoke this only if it is statically known that the tuple will be wide.
151 * Otherwise, use {@link #leftInheritanceTupleOf(Tuple, Object...)}.
152 */
153 public static Tuple wideLeftInheritanceTupleOf(Tuple ancestor, Object... elements) {
154 return new LeftInheritanceTuple(ancestor, elements);
155 }
156
157}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileMaskedTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileMaskedTuple.java
new file mode 100644
index 00000000..f683d544
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileMaskedTuple.java
@@ -0,0 +1,50 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import tools.refinery.viatra.runtime.matchers.util.Preconditions;
12
13/**
14 * This class provides a volatile tuple view with a given mask of a given tuple instance. If the masked tuple changes,
15 * the view updates as well.
16 *
17 * @author Zoltan Ujhelyi
18 * @since 1.7
19 *
20 */
21public class VolatileMaskedTuple extends VolatileTuple {
22
23 protected final TupleMask mask;
24 protected ITuple source;
25
26 public VolatileMaskedTuple(ITuple source, TupleMask mask) {
27 this.source = source;
28 this.mask = mask;
29 }
30
31 public VolatileMaskedTuple(TupleMask mask) {
32 this(null, mask);
33 }
34
35 public void updateTuple(ITuple newSource) {
36 source = newSource;
37 }
38
39 @Override
40 public Object get(int index) {
41 Preconditions.checkState(source != null, "Source tuple is not set.");
42 return mask.getValue(source, index);
43 }
44
45 @Override
46 public int getSize() {
47 return mask.getSize();
48 }
49
50}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileModifiableMaskedTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileModifiableMaskedTuple.java
new file mode 100644
index 00000000..92306c6e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileModifiableMaskedTuple.java
@@ -0,0 +1,47 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import tools.refinery.viatra.runtime.matchers.util.Preconditions;
12
13/**
14 * A masked tuple implementation that allows modifying the backing tuple.
15 * @author Zoltan Ujhelyi
16 * @since 1.7
17 *
18 */
19public class VolatileModifiableMaskedTuple extends VolatileMaskedTuple implements IModifiableTuple {
20
21 private IModifiableTuple modifiableTuple;
22
23 public VolatileModifiableMaskedTuple(IModifiableTuple source, TupleMask mask) {
24 super(source, mask);
25 modifiableTuple = source;
26 }
27
28 public VolatileModifiableMaskedTuple(TupleMask mask) {
29 this(null, mask);
30 }
31
32 @Override
33 public void updateTuple(ITuple newSource) {
34 Preconditions.checkArgument(newSource instanceof IModifiableTuple, "Provided tuple does not support updates");
35 this.updateTuple((IModifiableTuple)newSource);
36 }
37
38 public void updateTuple(IModifiableTuple newSource) {
39 super.updateTuple(newSource);
40 modifiableTuple = newSource;
41 }
42
43 @Override
44 public void set(int index, Object value) {
45 mask.set(modifiableTuple, index, value);
46 }
47}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileTuple.java
new file mode 100644
index 00000000..699105a5
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileTuple.java
@@ -0,0 +1,47 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017 Zoltan Ujhelyi, IncQuery Labs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.tuple;
11
12/**
13 * Mutable tuple without explicit modification commands. In practical terms, the values stored in a volatile tuple can
14 * be changed without any notification.
15 *
16 * @author Zoltan Ujhelyi
17 * @since 1.7
18 *
19 */
20public abstract class VolatileTuple extends AbstractTuple {
21
22 @Override
23 public boolean equals(Object obj) {
24 if (this == obj)
25 return true;
26 if (obj == null)
27 return false;
28 if (!(obj instanceof ITuple))
29 return false;
30 final ITuple other = (ITuple) obj;
31 return internalEquals(other);
32 }
33
34 @Override
35 public int hashCode() {
36 return doCalcHash();
37 }
38
39 /**
40 * Creates an immutable tuple from the values stored in the tuple. The created tuple will not be updated when the
41 * current tuple changes.
42 */
43 @Override
44 public Tuple toImmutable() {
45 return Tuples.flatTupleOf(getElements());
46 }
47}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Accuracy.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Accuracy.java
new file mode 100644
index 00000000..338990ab
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Accuracy.java
@@ -0,0 +1,48 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11/**
12 * The degree of accuracy of a cardinality estimate
13 * @author Gabor Bergmann
14 * @since 2.1
15 */
16public enum Accuracy {
17 EXACT_COUNT,
18 BEST_UPPER_BOUND,
19 BEST_LOWER_BOUND,
20 APPROXIMATION;
21
22 /**
23 * Partial order comparison.
24 */
25 public boolean atLeastAsPreciseAs(Accuracy other) {
26 switch (this) {
27 case EXACT_COUNT: return true;
28 case APPROXIMATION: return APPROXIMATION == other;
29 case BEST_UPPER_BOUND: return BEST_UPPER_BOUND == other || APPROXIMATION == other;
30 case BEST_LOWER_BOUND: return BEST_LOWER_BOUND == other || APPROXIMATION == other;
31 default: throw new IllegalArgumentException();
32 }
33 }
34
35 /**
36 * @return another accuracy value that is anti-monotonic to this one,
37 * i.e. an accuracy that should be used in the denominator to obtain a fraction with this accuracy
38 */
39 public Accuracy reciprocal() {
40 switch(this) {
41 case APPROXIMATION: return APPROXIMATION;
42 case BEST_UPPER_BOUND: return BEST_LOWER_BOUND;
43 case BEST_LOWER_BOUND: return BEST_UPPER_BOUND;
44 case EXACT_COUNT: return EXACT_COUNT;
45 default: throw new IllegalArgumentException();
46 }
47 }
48}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Clearable.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Clearable.java
new file mode 100644
index 00000000..1b09aec6
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Clearable.java
@@ -0,0 +1,23 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.util;
11
12/**
13 * @author Gabor Bergmann
14 * @since 1.7
15 * An instance of clearable pattern memory.
16 */
17public interface Clearable {
18 /**
19 * Clear all partial matchings stored in memory
20 *
21 */
22 void clear();
23}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/CollectionsFactory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/CollectionsFactory.java
new file mode 100644
index 00000000..590a1ec3
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/CollectionsFactory.java
@@ -0,0 +1,188 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Collection;
12import java.util.List;
13import java.util.Map;
14import java.util.Set;
15import java.util.TreeMap;
16import java.util.function.Function;
17
18/**
19 * Factory class used as an accessor to Collections implementations.
20 * @author istvanrath
21 */
22public final class CollectionsFactory
23{
24
25 /**
26 * Instantiates a new empty map.
27 * @since 1.7
28 */
29 public static <K, V> Map<K, V> createMap() {
30 return FRAMEWORK.createMap();
31 }
32
33 /**
34 * Instantiates a new map with the given initial contents.
35 * @since 1.7
36 */
37 public static <K, V> Map<K, V> createMap(Map<K, V> initial) {
38 return FRAMEWORK.createMap(initial);
39 }
40
41 /**
42 * Instantiates a new tree map.
43 * @since 2.3
44 */
45 public static <K, V> TreeMap<K, V> createTreeMap() {
46 return FRAMEWORK.createTreeMap();
47 }
48
49 /**
50 * Instantiates a new empty set.
51 * @since 1.7
52 */
53 public static <E> Set<E> createSet() {
54 return FRAMEWORK.createSet();
55 }
56
57 /**
58 * Instantiates a new set with the given initial contents.
59 * @since 1.7
60 */
61 public static <E> Set<E> createSet(Collection<E> initial) {
62 return FRAMEWORK.createSet(initial);
63 }
64
65 /**
66 * Instantiates an empty set; the key parameter is used to allow using this as a method reference as a
67 * {@link Function}, e.g. in {@link Map#computeIfAbsent(Object, Function)}.
68 *
69 * @param key
70 * the value of this parameter is ignored
71 * @since 2.0
72 */
73 public static <T> Set<T> emptySet(Object key) {
74 return FRAMEWORK.createSet();
75 }
76
77 /**
78 * Instantiates a new empty multiset.
79 * @since 1.7
80 */
81 public static <T> IMultiset<T> createMultiset() {
82 return FRAMEWORK.createMultiset();
83 }
84
85 /**
86 * Instantiates an empty multiset; the key parameter is used to allow using this as a method reference as a
87 * {@link Function}, e.g. in {@link Map#computeIfAbsent(Object, Function)}.
88 *
89 * @param key
90 * the value of this parameter is ignored
91 * @since 2.0
92 */
93 public static <T> IMultiset<T> emptyMultiset(Object key) {
94 return FRAMEWORK.createMultiset();
95 }
96
97 /**
98 * Instantiates a new empty delta bag.
99 * @since 1.7
100 */
101 public static <T> IDeltaBag<T> createDeltaBag() {
102 return FRAMEWORK.createDeltaBag();
103 }
104
105 /**
106 * Instantiates a new list that is optimized for registering observers / callbacks.
107 * @since 1.7
108 */
109 public static <O> List<O> createObserverList() {
110 return FRAMEWORK.createObserverList();
111 }
112
113 /**
114 * Instantiates a size-optimized multimap from keys to sets of values.
115 * <p>For a single key, many values can be associated according to the given bucket semantics.
116 * <p>The keys and values are stored as type fromKeys resp. ofValues;
117 * currently Object.class and Long.class are supported.
118 * @since 2.0
119 */
120 public static <K, V> IMultiLookup<K, V> createMultiLookup(
121 Class<? super K> fromKeys, MemoryType toBuckets, Class<? super V> ofValues) {
122 return FRAMEWORK.createMultiLookup(fromKeys, toBuckets, ofValues);
123 }
124
125 /**
126 * Instantiates a memory storing values.
127 * <p>For a single key, many values can be associated according to the given memory semantics.
128 * <p>The values are stored as type 'values';
129 * currently Object.class and Long.class are supported.
130 * @since 2.0
131 */
132 public static <T> IMemory<T> createMemory(
133 Class<? super T> values, MemoryType memoryType) {
134 return FRAMEWORK.createMemory(values, memoryType);
135 }
136
137 /**
138 * The type of {@link IMemory}
139 * @since 2.0
140 * TODO add delta as type
141 */
142 public enum MemoryType {
143 /**
144 * A single key-value pair is stored at most once
145 */
146 SETS,
147 /**
148 * Duplicate key-value pairs allowed
149 */
150 MULTISETS
151 }
152
153 /**
154 * The collections framework of the current configuration.
155 * @since 1.7
156 */
157 private static final ICollectionsFramework FRAMEWORK = new EclipseCollectionsFactory();
158
159 /**
160 * Interface abstracting over a collections technology that provides custom collection implementations.
161 * @since 1.7
162 */
163 public static interface ICollectionsFramework {
164
165 public abstract <K,V> Map<K,V> createMap();
166 public abstract <K,V> Map<K,V> createMap(Map<K,V> initial);
167 /**
168 * @since 2.3
169 */
170 public abstract <K, V> TreeMap<K, V> createTreeMap();
171 public abstract <E> Set<E> createSet();
172 public abstract <E> Set<E> createSet(Collection<E> initial);
173 public abstract <T> IMultiset<T> createMultiset();
174 public abstract <T> IDeltaBag<T> createDeltaBag();
175 public abstract <O> List<O> createObserverList();
176
177 /**
178 * @since 2.0
179 */
180 public abstract <K, V> IMultiLookup<K, V> createMultiLookup(
181 Class<? super K> fromKeys, MemoryType toBuckets, Class<? super V> ofValues);
182 /**
183 * @since 2.0
184 */
185 public abstract <T> IMemory<T> createMemory(Class<? super T> values, MemoryType memoryType);
186 }
187
188} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Direction.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Direction.java
new file mode 100644
index 00000000..88f7ec00
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Direction.java
@@ -0,0 +1,61 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, itemis AG, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11/**
12 * Indicates whether a propagated update event signals the insertion or deletion of an element
13 *
14 * @author Gabor Bergmann
15 */
16public enum Direction {
17 INSERT, DELETE;
18
19 /**
20 * @since 2.4
21 */
22 public Direction opposite() {
23 switch (this) {
24 case INSERT:
25 return DELETE;
26 default:
27 return INSERT;
28 }
29 }
30
31 /**
32 * @since 2.4
33 */
34 public char asSign() {
35 switch (this) {
36 case INSERT:
37 return '+';
38 default:
39 return '-';
40 }
41 }
42
43 /**
44 * Returns the direction that is the product of this direction and the other direction.
45 *
46 * DELETE x DELETE = INSERT
47 * DELETE x INSERT = DELETE
48 * INSERT x DELETE = DELETE
49 * INSERT x INSERT = INSERT
50 * @since 2.4
51 */
52 public Direction multiply(final Direction other) {
53 switch (this) {
54 case DELETE:
55 return other.opposite();
56 default:
57 return other;
58 }
59 }
60
61}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsBagMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsBagMemory.java
new file mode 100644
index 00000000..e24b2448
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsBagMemory.java
@@ -0,0 +1,86 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.util;
11
12import java.util.Iterator;
13import java.util.Set;
14import java.util.function.BiConsumer;
15
16import org.eclipse.collections.impl.map.mutable.primitive.ObjectIntHashMap;
17
18/**
19 * Eclipse Collections-based multiset for tuples. Can contain duplicate occurrences of the same matching.
20 *
21 * <p>Inherits Eclipse Collections' Object-to-Int primitive hashmap and counts the number of occurrences of each value.
22 * Element is deleted if # of occurences drops to 0.
23 *
24 * @author Gabor Bergmann.
25 * @since 1.7
26 * @noreference
27 */
28public abstract class EclipseCollectionsBagMemory<T> extends ObjectIntHashMap<T> implements IMemory<T> {
29
30 public EclipseCollectionsBagMemory() {
31 super();
32 }
33
34 @Override
35 public int getCount(T value) {
36 return super.getIfAbsent(value, 0);
37 }
38 @Override
39 public int getCountUnsafe(Object value) {
40 return super.getIfAbsent(value, 0);
41 }
42 @Override
43 public boolean containsNonZero(T value) {
44 return super.containsKey(value);
45 }
46 @Override
47 public boolean containsNonZeroUnsafe(Object value) {
48 return super.containsKey(value);
49 }
50
51 @Override
52 public void clearAllOf(T value) {
53 super.remove(value);
54 }
55
56
57 @Override
58 public Iterator<T> iterator() {
59 return super.keySet().iterator();
60 }
61
62 @Override
63 public String toString() {
64 return "TM" + super.toString();
65 }
66
67 @Override
68 public Set<T> distinctValues() {
69 return super.keySet();
70 }
71
72 @Override
73 public void forEachEntryWithMultiplicities(BiConsumer<T, Integer> entryConsumer) {
74 super.forEachKeyValue(entryConsumer::accept);
75 }
76
77 @Override
78 public int hashCode() {
79 return IMemoryView.hashCode(this);
80 }
81 @Override
82 public boolean equals(Object obj) {
83 return IMemoryView.equals(this, obj);
84 }
85
86}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsDeltaBag.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsDeltaBag.java
new file mode 100644
index 00000000..94ec33cd
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsDeltaBag.java
@@ -0,0 +1,41 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11/**
12 * @author Gabor Bergmann
13 * @since 1.7
14 */
15public class EclipseCollectionsDeltaBag<T> extends EclipseCollectionsBagMemory<T> implements IDeltaBag<T> {
16
17 @Override
18 public boolean addOne(T value) {
19 return addSigned(value, +1);
20 }
21
22 @Override
23 public boolean addSigned(T value, int count) {
24 int oldCount = super.getIfAbsent(value, 0);
25 int newCount = oldCount + count;
26
27 boolean becomesZero = newCount == 0;
28 if (becomesZero)
29 super.removeKey(value);
30 else
31 super.put(value, newCount);
32
33 return becomesZero || oldCount == 0;
34 }
35
36
37 @Override
38 public boolean removeOne(T value) {
39 return addSigned(value, -1);
40 }
41}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsFactory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsFactory.java
new file mode 100644
index 00000000..5a623c9b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsFactory.java
@@ -0,0 +1,159 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.List;
14import java.util.Map;
15import java.util.Set;
16import java.util.TreeMap;
17
18import org.eclipse.collections.api.map.MutableMap;
19import org.eclipse.collections.impl.factory.Maps;
20import org.eclipse.collections.impl.factory.Sets;
21import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.ICollectionsFramework;
22import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
23
24/**
25 * @author Gabor Bergmann
26 * @since 1.7
27 * @noreference This class is not intended to be referenced by clients.
28 */
29public class EclipseCollectionsFactory implements ICollectionsFramework {
30
31 @Override
32 public <K, V> Map<K, V> createMap() {
33 return Maps.mutable.empty();
34 }
35
36 @Override
37 public <K, V> Map<K, V> createMap(Map<K, V> initial) {
38 MutableMap<K, V> result = Maps.mutable.ofInitialCapacity(initial.size());
39 result.putAll(initial);
40 return result;
41 }
42
43 @Override
44 public <K, V> TreeMap<K, V> createTreeMap() {
45 // eclipse collections is doing the same
46 return new TreeMap<>();
47 }
48
49 @Override
50 public <E> Set<E> createSet() {
51 return Sets.mutable.empty();
52 }
53
54 @Override
55 public <E> Set<E> createSet(Collection<E> initial) {
56 return Sets.mutable.ofAll(initial);
57 }
58
59 @Override
60 public <T> IMultiset<T> createMultiset() {
61 return new EclipseCollectionsMultiset<T>();
62 }
63
64 @Override
65 public <T> IDeltaBag<T> createDeltaBag() {
66 return new EclipseCollectionsDeltaBag<T>();
67 }
68
69 @Override
70 public <O> List<O> createObserverList() {
71 return new ArrayList<O>(1); // keep concurrent modification exceptions for error detection
72 // Lists.mutable.empty
73
74 }
75
76 @Override
77 @SuppressWarnings({ "unchecked", "rawtypes" })
78 public <K, V> IMultiLookup<K, V> createMultiLookup(
79 Class<? super K> fromKeys,
80 MemoryType toBuckets,
81 Class<? super V> ofValues)
82 {
83 boolean longKeys = Long.class.equals(fromKeys);
84 boolean objectKeys = Object.class.equals(fromKeys);
85 if (! (longKeys || objectKeys)) throw new IllegalArgumentException(fromKeys.getName());
86 boolean longValues = Long.class.equals(ofValues);
87 boolean objectValues = Object.class.equals(ofValues);
88 if (! (longValues || objectValues)) throw new IllegalArgumentException(ofValues.getName());
89
90 if (longKeys) { // K == java.lang.Long
91 if (longValues) { // V == java.lang.Long
92 switch(toBuckets) {
93 case MULTISETS:
94 return (IMultiLookup<K, V>) new EclipseCollectionsMultiLookup.FromLongs.ToMultisets.OfLongs();
95 case SETS:
96 return (IMultiLookup<K, V>) new EclipseCollectionsMultiLookup.FromLongs.ToSets.OfLongs();
97 default:
98 throw new IllegalArgumentException(toBuckets.toString());
99 }
100 } else { // objectValues
101 switch(toBuckets) {
102 case MULTISETS:
103 return new EclipseCollectionsMultiLookup.FromLongs.ToMultisets.OfObjects();
104 case SETS:
105 return new EclipseCollectionsMultiLookup.FromLongs.ToSets.OfObjects();
106 default:
107 throw new IllegalArgumentException(toBuckets.toString());
108 }
109 }
110 } else { // objectKeys
111 if (longValues) { // V == java.lang.Long
112 switch(toBuckets) {
113 case MULTISETS:
114 return new EclipseCollectionsMultiLookup.FromObjects.ToMultisets.OfLongs();
115 case SETS:
116 return new EclipseCollectionsMultiLookup.FromObjects.ToSets.OfLongs();
117 default:
118 throw new IllegalArgumentException(toBuckets.toString());
119 }
120 } else { // objectValues
121 switch(toBuckets) {
122 case MULTISETS:
123 return new EclipseCollectionsMultiLookup.FromObjects.ToMultisets.OfObjects();
124 case SETS:
125 return new EclipseCollectionsMultiLookup.FromObjects.ToSets.OfObjects();
126 default:
127 throw new IllegalArgumentException(toBuckets.toString());
128 }
129 }
130 }
131 }
132
133 @Override
134 @SuppressWarnings("unchecked")
135 public <T> IMemory<T> createMemory(Class<? super T> values, MemoryType memoryType) {
136 if (Long.class.equals(values)) { // T == java.lang.Long
137 switch(memoryType) {
138 case MULTISETS:
139 return (IMemory<T>) new EclipseCollectionsLongMultiset();
140 case SETS:
141 return (IMemory<T>) new EclipseCollectionsLongSetMemory();
142 default:
143 throw new IllegalArgumentException(memoryType.toString());
144 }
145 } else { // objectValues
146 switch(memoryType) {
147 case MULTISETS:
148 return new EclipseCollectionsMultiset<>();
149 case SETS:
150 return new EclipseCollectionsSetMemory<>();
151 default:
152 throw new IllegalArgumentException(memoryType.toString());
153 }
154 }
155 }
156
157
158
159}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongMultiset.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongMultiset.java
new file mode 100644
index 00000000..88773c5d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongMultiset.java
@@ -0,0 +1,150 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Iterator;
12import java.util.Set;
13import java.util.function.BiConsumer;
14
15import org.eclipse.collections.impl.map.mutable.primitive.LongIntHashMap;
16
17/**
18 * @author Gabor Bergmann
19 * @since 2.0
20 * <p> TODO refactor common methods with {@link EclipseCollectionsMultiset}
21 * <p> TODO refactor into LongBagMemory etc.
22 */
23public class EclipseCollectionsLongMultiset extends LongIntHashMap implements IMultiset<Long> {
24
25 @Override
26 public boolean addOne(Long value) {
27 int oldCount = super.getIfAbsent(value, 0);
28
29 super.put(value, oldCount + 1);
30
31 return oldCount == 0;
32 }
33
34 @Override
35 public boolean addSigned(Long value, int count) {
36 int oldCount = super.getIfAbsent(value, 0);
37 int newCount = oldCount + count;
38
39 boolean becomesZero = newCount == 0;
40 if (newCount < 0)
41 throw new IllegalStateException(String.format(
42 "Cannot remove %d occurrences of value '%s' as only %d would remain in %s",
43 count, value, newCount, this));
44 else if (becomesZero)
45 super.removeKey(value);
46 else // (newCount > 0)
47 super.put(value, newCount);
48
49 return becomesZero || oldCount == 0;
50 }
51
52 @Override
53 public boolean removeOne(Long value) {
54 return removeOneInternal(value, true);
55 }
56 /**
57 * @since 2.3
58 */
59 @Override
60 public boolean removeOneOrNop(Long value) {
61 return removeOneInternal(value, false);
62 }
63
64
65 /**
66 * @since 2.3
67 */
68 protected boolean removeOneInternal(Long value, boolean throwIfImpossible) {
69 int oldCount = super.getIfAbsent(value, 0);
70 if (oldCount == 0) {
71 if (throwIfImpossible) throw new IllegalStateException(String.format(
72 "Cannot remove value '%s' that is not contained in %s",
73 value, this));
74 else return false;
75 }
76
77 int rest = oldCount - 1;
78 boolean empty = rest == 0;
79
80 if (!empty) {
81 super.put(value, rest);
82 } else {
83 super.remove(value);
84 }
85
86 return empty;
87 }
88
89 @Override
90 public void clearAllOf(Long value) {
91 super.remove(value);
92 }
93
94 @Override
95 public int getCount(Long value) {
96 return super.getIfAbsent(value, 0);
97 }
98 @Override
99 public int getCountUnsafe(Object value) {
100 return value instanceof Long ? getCount((Long) value) : 0;
101 }
102
103 @Override
104 public boolean containsNonZero(Long value) {
105 return super.containsKey(value);
106 }
107
108 @Override
109 public boolean containsNonZeroUnsafe(Object value) {
110 return value instanceof Long && containsNonZero((Long) value);
111 }
112
113 @Override
114 public Iterator<Long> iterator() {
115 return EclipseCollectionsLongSetMemory.iteratorOf(super.keySet());
116 }
117
118 @Override
119 public boolean addPositive(Long value, int count) {
120 if (count < 0) {
121 throw new IllegalArgumentException("The count value must be positive!");
122 }
123
124 int oldCount = super.getIfAbsent(value, 0);
125
126 super.put(value, oldCount + count);
127
128 return oldCount == 0;
129 }
130
131 @Override
132 public Set<Long> distinctValues() {
133 return new EclipseCollectionsLongSetMemory.SetWrapper(super.keySet());
134 }
135
136 @Override
137 public void forEachEntryWithMultiplicities(BiConsumer<Long, Integer> entryConsumer) {
138 super.forEachKeyValue(entryConsumer::accept);
139 }
140
141 @Override
142 public int hashCode() {
143 return IMemoryView.hashCode(this);
144 }
145 @Override
146 public boolean equals(Object obj) {
147 return IMemoryView.equals(this, obj);
148 }
149
150}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongSetMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongSetMemory.java
new file mode 100644
index 00000000..fceb54fc
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongSetMemory.java
@@ -0,0 +1,212 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Collection;
12import java.util.Iterator;
13import java.util.Set;
14
15import org.eclipse.collections.api.LongIterable;
16import org.eclipse.collections.api.iterator.LongIterator;
17import org.eclipse.collections.api.set.primitive.LongSet;
18import org.eclipse.collections.impl.set.mutable.primitive.LongHashSet;
19
20/**
21 * @author Gabor Bergmann
22 * @since 2.0
23 */
24public class EclipseCollectionsLongSetMemory extends LongHashSet implements ISetMemory<Long> {
25
26 @Override
27 public boolean addOne(Long value) {
28 return super.add(value);
29 }
30
31 @Override
32 public boolean addSigned(Long value, int count) {
33 if (count == 1) return addOne(value);
34 else if (count == -1) return removeOne(value);
35 else throw new IllegalStateException();
36 }
37
38 @Override
39 public boolean removeOne(Long value) {
40 // Kept for binary compatibility
41 return ISetMemory.super.removeOne(value);
42 }
43
44 /**
45 * @since 2.3
46 */
47 @Override
48 public boolean removeOneOrNop(Long value) {
49 return super.remove(value);
50 }
51
52 @Override
53 public void clearAllOf(Long value) {
54 super.remove(value);
55 }
56
57 @Override
58 public int getCount(Long value) {
59 return super.contains(value) ? 1 : 0;
60 }
61
62 @Override
63 public int getCountUnsafe(Object value) {
64 return value instanceof Long ? getCount((Long) value) : 0;
65 }
66
67 @Override
68 public boolean containsNonZero(Long value) {
69 return super.contains(value);
70 }
71
72 @Override
73 public boolean containsNonZeroUnsafe(Object value) {
74 return value instanceof Long && containsNonZero((Long) value);
75 }
76
77 @Override
78 public Iterator<Long> iterator() {
79 return iteratorOf(this);
80 }
81
82 @Override
83 public Set<Long> distinctValues() {
84 return new SetWrapper(this);
85 }
86
87 @Override
88 public boolean isEmpty() {
89 return super.isEmpty();
90 }
91
92 /**
93 * Helper for iterating a LongIterable
94 */
95 public static Iterator<Long> iteratorOf(LongIterable wrapped) {
96 return new Iterator<Long>() {
97 LongIterator longIterator = wrapped.longIterator();
98
99 @Override
100 public boolean hasNext() {
101 return longIterator.hasNext();
102 }
103
104 @Override
105 public Long next() {
106 return longIterator.next();
107 }
108 };
109 }
110
111 @Override
112 public int hashCode() {
113 return IMemoryView.hashCode(this);
114 }
115 @Override
116 public boolean equals(Object obj) {
117 return IMemoryView.equals(this, obj);
118 }
119
120
121 /**
122 * Helper that presents a primitive collection as a Set view
123 * @author Gabor Bergmann
124 */
125 public static final class SetWrapper implements Set<Long> {
126 private LongSet wrapped;
127
128 /**
129 * @param wrapped
130 */
131 public SetWrapper(LongSet wrapped) {
132 this.wrapped = wrapped;
133 }
134
135 @Override
136 public int size() {
137 return wrapped.size();
138 }
139
140 @Override
141 public boolean isEmpty() {
142 return wrapped.isEmpty();
143 }
144
145 @Override
146 public boolean contains(Object o) {
147 return o instanceof Long && wrapped.contains((Long)o);
148 }
149
150 @Override
151 public Iterator<Long> iterator() {
152 return iteratorOf(wrapped);
153 }
154
155 @Override
156 public boolean containsAll(Collection<?> c) {
157 for (Object object : c) {
158 if (contains(object))
159 return true;
160 }
161 return false;
162 }
163
164 @Override
165 public Object[] toArray() {
166 return toArray(new Long[wrapped.size()]);
167 }
168
169 @Override
170 @SuppressWarnings("unchecked")
171 public <T> T[] toArray(T[] a) {
172 int k = 0;
173 LongIterator iterator = wrapped.longIterator();
174 while (iterator.hasNext())
175 a[k++] = (T) Long.valueOf(iterator.next());
176 return a;
177 }
178
179 @Override
180 public boolean add(Long e) {
181 throw new UnsupportedOperationException();
182 }
183
184 @Override
185 public boolean remove(Object o) {
186 throw new UnsupportedOperationException();
187 }
188
189 @Override
190 public boolean addAll(Collection<? extends Long> c) {
191 throw new UnsupportedOperationException();
192 }
193
194 @Override
195 public boolean retainAll(Collection<?> c) {
196 throw new UnsupportedOperationException();
197 }
198
199 @Override
200 public boolean removeAll(Collection<?> c) {
201 throw new UnsupportedOperationException();
202 }
203
204 @Override
205 public void clear() {
206 throw new UnsupportedOperationException();
207 }
208
209
210 }
211
212}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiLookup.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiLookup.java
new file mode 100644
index 00000000..394135c9
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiLookup.java
@@ -0,0 +1,226 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import org.eclipse.collections.impl.map.mutable.UnifiedMap;
12import org.eclipse.collections.impl.map.mutable.primitive.LongObjectHashMap;
13import tools.refinery.viatra.runtime.matchers.util.MarkedMemory.MarkedMultiset;
14import tools.refinery.viatra.runtime.matchers.util.MarkedMemory.MarkedSet;
15
16import java.util.Set;
17import java.util.stream.Stream;
18
19
20
21/**
22 * Eclipse Collections-based realizations of {@link IMultiLookup}
23 *
24 * @author Gabor Bergmann
25 * @since 2.0
26 */
27class EclipseCollectionsMultiLookup {
28
29 private EclipseCollectionsMultiLookup() {/* Hidden utility class constructor */}
30
31 private static class MarkedSetImpl<Value> extends EclipseCollectionsSetMemory<Value> implements MarkedMemory.MarkedSet<Value> {}
32 private static class MarkedMultisetImpl<Value> extends EclipseCollectionsMultiset<Value> implements MarkedMemory.MarkedMultiset<Value> {}
33 private static class MarkedLongSetImpl extends EclipseCollectionsLongSetMemory implements MarkedMemory.MarkedSet<Long> {}
34 private static class MarkedLongMultisetImpl extends EclipseCollectionsLongMultiset implements MarkedMemory.MarkedMultiset<Long> {}
35
36 public abstract static class FromObjects<Key, Value, Bucket extends MarkedMemory<Value>>
37 extends UnifiedMap<Key, Object> implements IMultiLookupAbstract<Key, Value, Bucket> {
38
39 @Override
40 public boolean equals(Object obj) {
41 return IMultiLookup.equals(this, obj);
42 }
43 @Override
44 public int hashCode() {
45 return IMultiLookup.hashCode(this);
46 }
47
48
49 @Override
50 public Object lowLevelPutIfAbsent(Key key, Value value) {
51 return super.putIfAbsent(key, value);
52 }
53
54 @Override
55 public Object lowLevelGet(Key key) {
56 return super.get(key);
57 }
58
59 @Override
60 public Object lowLevelGetUnsafe(Object key) {
61 return super.get(key);
62 }
63
64 @Override
65 public Object lowLevelRemove(Key key) {
66 return super.remove(key);
67 }
68
69 @Override
70 public void lowLevelPut(Key key, Object valueOrBucket) {
71 super.put(key, valueOrBucket);
72 }
73 @Override
74 public Iterable<Object> lowLevelValues() {
75 return super.values();
76 }
77 @Override
78 public Set<Key> lowLevelKeySet() {
79 return super.keySet();
80 }
81 @Override
82 public int lowLevelSize() {
83 return super.size();
84 }
85
86 @Override
87 public Stream<Key> distinctKeysStream() {
88 // may be more efficient than the default spliterator
89 return super.keySet().stream();
90 }
91
92 public abstract static class ToSets<Key, Value> extends FromObjects<Key, Value, MarkedSet<Value>>
93 implements IMultiLookupAbstract.ToSetsAbstract<Key, Value>
94 {
95 public static class OfObjects<Key, Value> extends ToSets<Key, Value> {
96 @Override
97 public MarkedSet<Value> createMarkedSet() {
98 return new MarkedSetImpl<Value>();
99 }
100 }
101
102 public static class OfLongs<Key> extends ToSets<Key, Long> {
103 @Override
104 public MarkedSet<Long> createMarkedSet() {
105 return new MarkedLongSetImpl();
106 }
107 }
108
109 }
110
111 public abstract static class ToMultisets<Key, Value> extends FromObjects<Key, Value, MarkedMultiset<Value>>
112 implements IMultiLookupAbstract.ToMultisetsAbstract<Key, Value>
113 {
114 public static class OfObjects<Key, Value> extends ToMultisets<Key, Value> {
115 @Override
116 public MarkedMultiset<Value> createMarkedMultiset() {
117 return new MarkedMultisetImpl<Value>();
118 }
119 }
120
121 public static class OfLongs<Key> extends ToMultisets<Key, Long> {
122 @Override
123 public MarkedMultiset<Long> createMarkedMultiset() {
124 return new MarkedLongMultisetImpl();
125 }
126 }
127
128 }
129
130 }
131
132 public abstract static class FromLongs<Value, Bucket extends MarkedMemory<Value>>
133 extends LongObjectHashMap<Object> implements IMultiLookupAbstract<Long, Value, Bucket> {
134
135 @Override
136 public boolean equals(Object obj) {
137 return IMultiLookup.equals(this, obj);
138 }
139 @Override
140 public int hashCode() {
141 return IMultiLookup.hashCode(this);
142 }
143
144 @Override
145 public Object lowLevelPutIfAbsent(Long key, Value value) {
146 Object old = super.get(key);
147 if (old == null) super.put(key, value);
148 return old;
149 }
150
151 @Override
152 public Object lowLevelGet(Long key) {
153 return super.get(key);
154 }
155
156 @Override
157 public Object lowLevelGetUnsafe(Object key) {
158 return key instanceof Long ? super.get((Long)key) : null;
159 }
160
161 @Override
162 public Object lowLevelRemove(Long key) {
163 return super.remove(key);
164 }
165
166 @Override
167 public void lowLevelPut(Long key, Object valueOrBucket) {
168 super.put(key, valueOrBucket);
169 }
170 @Override
171 public Iterable<Object> lowLevelValues() {
172 return super.values();
173 }
174 @Override
175 public int lowLevelSize() {
176 return super.size();
177 }
178 @Override
179 public Iterable<Long> lowLevelKeySet() {
180 return () -> EclipseCollectionsLongSetMemory.iteratorOf(FromLongs.super.keysView());
181 }
182
183 public abstract static class ToSets<Value> extends FromLongs<Value, MarkedSet<Value>>
184 implements IMultiLookupAbstract.ToSetsAbstract<Long, Value>
185 {
186 public static class OfObjects<Value> extends ToSets<Value> {
187 @Override
188 public MarkedSet<Value> createMarkedSet() {
189 return new MarkedSetImpl<Value>();
190 }
191 }
192
193 public static class OfLongs extends ToSets<Long> {
194 @Override
195 public MarkedSet<Long> createMarkedSet() {
196 return new MarkedLongSetImpl();
197 }
198 }
199
200 }
201
202 public abstract static class ToMultisets<Value> extends FromLongs<Value, MarkedMultiset<Value>>
203 implements IMultiLookupAbstract.ToMultisetsAbstract<Long, Value>
204 {
205 public static class OfObjects<Value> extends ToMultisets<Value> {
206 @Override
207 public MarkedMultiset<Value> createMarkedMultiset() {
208 return new MarkedMultisetImpl<Value>();
209 }
210 }
211
212 public static class OfLongs extends ToMultisets<Long> {
213 @Override
214 public MarkedMultiset<Long> createMarkedMultiset() {
215 return new MarkedLongMultisetImpl();
216 }
217 }
218
219 }
220
221 }
222
223
224}
225
226
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiset.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiset.java
new file mode 100644
index 00000000..46977c8b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiset.java
@@ -0,0 +1,93 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11/**
12 * @author Gabor Bergmann
13 * @since 1.7
14 */
15public class EclipseCollectionsMultiset<T> extends EclipseCollectionsBagMemory<T> implements IMultiset<T> {
16
17 @Override
18 public boolean addOne(T value) {
19 int oldCount = super.getIfAbsent(value, 0);
20
21 super.put(value, oldCount + 1);
22
23 return oldCount == 0;
24 }
25
26 @Override
27 public boolean addPositive(T value, int count) {
28 if (count < 0) {
29 throw new IllegalArgumentException("The count value must be positive!");
30 }
31
32 int oldCount = super.getIfAbsent(value, 0);
33
34 super.put(value, oldCount + count);
35
36 return oldCount == 0;
37 }
38
39 @Override
40 public boolean addSigned(T value, int count) {
41 int oldCount = super.getIfAbsent(value, 0);
42 int newCount = oldCount + count;
43
44 boolean becomesZero = newCount == 0;
45 if (newCount < 0)
46 throw new IllegalStateException(String.format(
47 "Cannot remove %d occurrences of value '%s' as only %d would remain in %s",
48 count, value, newCount, this));
49 else if (becomesZero)
50 super.removeKey(value);
51 else // (newCount > 0)
52 super.put(value, newCount);
53
54 return becomesZero || oldCount == 0;
55 }
56
57
58 @Override
59 public boolean removeOne(T value) {
60 return removeOneInternal(value, true);
61 }
62
63 @Override
64 public boolean removeOneOrNop(T value) {
65 return removeOneInternal(value, false);
66 }
67
68 /**
69 * @since 2.3
70 */
71 protected boolean removeOneInternal(T value, boolean throwIfImpossible) {
72 int oldCount = super.getIfAbsent(value, 0);
73 if (oldCount == 0) {
74 if (throwIfImpossible) throw new IllegalStateException(String.format(
75 "Cannot remove value '%s' that is not contained in %s",
76 value, this));
77 else return false;
78 }
79
80 int rest = oldCount - 1;
81 boolean empty = rest == 0;
82
83 if (!empty) {
84 super.put(value, rest);
85 } else {
86 super.remove(value);
87 }
88
89 return empty;
90 }
91
92
93}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsSetMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsSetMemory.java
new file mode 100644
index 00000000..92f65246
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsSetMemory.java
@@ -0,0 +1,94 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Set;
12
13import org.eclipse.collections.impl.set.mutable.UnifiedSet;
14
15/**
16 * @author Gabor Bergmann
17 * @since 2.0
18 */
19public class EclipseCollectionsSetMemory<Value> extends UnifiedSet<Value> implements ISetMemory<Value> {
20 @Override
21 public int getCount(Value value) {
22 return super.contains(value) ? 1 : 0;
23 }
24 @Override
25 public int getCountUnsafe(Object value) {
26 return super.contains(value) ? 1 : 0;
27 }
28 @Override
29 public boolean containsNonZero(Value value) {
30 return super.contains(value);
31 }
32
33 @Override
34 public boolean containsNonZeroUnsafe(Object value) {
35 return super.contains(value);
36 }
37
38 @Override
39 public boolean addOne(Value value) {
40 return super.add(value);
41 }
42
43 @Override
44 public boolean addSigned(Value value, int count) {
45 if (count == 1) return addOne(value);
46 else if (count == -1) return removeOne(value);
47 else throw new IllegalStateException();
48 }
49
50 @Override
51 public boolean removeOne(Value value) {
52 // Kept for binary compatibility
53 return ISetMemory.super.removeOne(value);
54 }
55
56 @Override
57 public boolean removeOneOrNop(Value value) {
58 return super.remove(value);
59 }
60
61 @Override
62 public void clearAllOf(Value value) {
63 super.remove(value);
64 }
65
66 @Override
67 public Set<Value> distinctValues() {
68 return this;
69 }
70
71 @Override
72 public Value theContainedVersionOf(Value value) {
73 return super.get(value);
74 }
75
76 @Override
77 @SuppressWarnings("unchecked")
78 public Value theContainedVersionOfUnsafe(Object value) {
79 if (super.contains(value))
80 return super.get((Value)value);
81 else return null;
82 }
83
84 @Override
85 public int hashCode() {
86 return IMemoryView.hashCode(this);
87 }
88 @Override
89 public boolean equals(Object obj) {
90 return IMemoryView.equals(this, obj);
91 }
92
93
94}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EmptyMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EmptyMemory.java
new file mode 100644
index 00000000..a17b3a3f
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EmptyMemory.java
@@ -0,0 +1,93 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Collections;
12import java.util.Iterator;
13import java.util.Set;
14
15/**
16 * A singleton immutable empty memory.
17 * @author Gabor Bergmann
18 * @since 2.0
19 *
20 */
21public class EmptyMemory<T> implements IMemoryView<T> {
22
23 @SuppressWarnings("rawtypes")
24 private static final EmptyMemory INSTANCE = new EmptyMemory();
25
26 @SuppressWarnings("unchecked")
27 public static <T> EmptyMemory<T> instance() {
28 return INSTANCE;
29 }
30
31
32
33 /**
34 * Singleton; hidden constructor
35 */
36 private EmptyMemory() {
37 super();
38 }
39
40 @Override
41 public Iterator<T> iterator() {
42 return Collections.<T>emptySet().iterator();
43 }
44
45 @Override
46 public int getCount(T value) {
47 return 0;
48 }
49
50 @Override
51 public int getCountUnsafe(Object value) {
52 return 0;
53 }
54
55 @Override
56 public boolean containsNonZero(T value) {
57 return false;
58 }
59
60 @Override
61 public boolean containsNonZeroUnsafe(Object value) {
62 return false;
63 }
64
65 @Override
66 public int size() {
67 return 0;
68 }
69
70 @Override
71 public boolean isEmpty() {
72 return true;
73 }
74
75 @Override
76 public Set<T> distinctValues() {
77 return Collections.emptySet();
78 }
79
80 @Override
81 public int hashCode() {
82 return IMemoryView.hashCode(this);
83 }
84 @Override
85 public boolean equals(Object obj) {
86 return IMemoryView.equals(this, obj);
87 }
88
89 @Override
90 public String toString() {
91 return "{}";
92 }
93}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/ICache.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/ICache.java
new file mode 100644
index 00000000..8c2e54ad
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/ICache.java
@@ -0,0 +1,32 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.function.Supplier;
12
13/**
14 * A cache is a simple key-value pair that stores calculated values for specific key objects
15 *
16 * <p>
17 * <b>NOTE</b> These caches are not expected to be used outside query backend implementations
18 *
19 * @author Zoltan Ujhelyi
20 * @since 1.7
21 * @noreference This interface is not intended to be referenced by clients.
22 */
23public interface ICache {
24
25 /**
26 * Return a selected value for the key object. If the value is not available in the cache yet, the given provider is
27 * called once
28 * @since 2.0
29 */
30 <T> T getValue(Object key, Class<? extends T> clazz, Supplier<T> valueProvider);
31
32} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IDeltaBag.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IDeltaBag.java
new file mode 100644
index 00000000..99a4cb3b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IDeltaBag.java
@@ -0,0 +1,26 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11/**
12 * An {@link IMemory} that represents the difference between two states of a set or {@link IMultiset}, and therefore
13 * may contain values with a negative multiplicity.
14 *
15 * @author Gabor Bergmann
16 * @since 1.7
17 */
18public interface IDeltaBag<T> extends IMemory<T> {
19
20 @Override
21 default boolean removeOneOrNop(T value) {
22 // makes no difference for delta bags
23 return removeOne(value);
24 }
25
26}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemory.java
new file mode 100644
index 00000000..ea788e53
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemory.java
@@ -0,0 +1,81 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11/**
12 * A memory containing a positive or negative number of equal() copies for some values.
13 * During iterations, each distinct value is iterated only once.
14 *
15 * <p> Refined by: <ul>
16 * <li>{@link IMultiset}, which always contains values with a nonnegative multiplicity. </li>
17 * <li>{@link IDeltaBag}, which may contain values with negative multiplicity. </li>
18 * <li>{@link ISetMemory}, which is just a set (allowed multiplicities: 0 and 1). </li>
19 * </ul>
20 *
21 * @author Gabor Bergmann
22 * @since 1.7
23 * @noimplement This interface is not intended to be implemented by clients.
24 */
25public interface IMemory<T> extends IMemoryView<T>, Clearable {
26
27 /**
28 * Adds one value occurrence to the memory.
29 *
30 * @return true if the tuple was not present before in the memory, or
31 * (in case of {@link IDeltaBag}) is no longer present in the memory
32 */
33 boolean addOne(T value);
34
35 /**
36 * Adds the given number of occurrences to the memory. The count value may or may not be negative.
37 * <p> Precondition if {@link IMultiset}: at least the given amount of occurrences exist, if count is negative.
38 * <p> Precondition if {@link ISetMemory}: count is +1 or -1, the latter is only allowed if the set contains the value.
39 *
40 * @param count
41 * the number of occurrences
42 * @return true if the tuple was not present before in the memory, or is no longer present in the memory
43 * @throws IllegalStateException if {@link IMultiset} or {@link ISetMemory} and the number of occurrences in the memory would underflow to negative
44 */
45 boolean addSigned(T value, int count);
46
47 /**
48 * Removes one occurrence of the given value from the memory.
49 * <p> Precondition if {@link IMultiset} or {@link ISetMemory}: the value must have a positive amount of occurrences in the memory.
50 *
51 * @return true if this was the the last occurrence of the value, or
52 * (in case of {@link IDeltaBag}) is the first negative occurrence of the value
53 * @throws IllegalStateException if {@link IMultiset} or {@link ISetMemory} and value had no occurrences in the memory
54 */
55 boolean removeOne(T value);
56
57 /**
58 * Removes one occurrence of the given value from the memory, if possible.
59 *
60 * <p> Memory is unchanged and false is returned if
61 * {@link IMultiset} or {@link ISetMemory} and value had no occurrences in the memory
62 *
63 * @return true if this was the the last occurrence of the value, or
64 * (in case of {@link IDeltaBag}) is the first negative occurrence of the value
65 *
66 * @since 2.3
67 */
68 boolean removeOneOrNop(T value);
69
70 /**
71 * Removes all occurrences of the given value from the memory.
72 */
73 void clearAllOf(T value);
74
75 /**
76 * Empties out the memory.
77 */
78 @Override
79 void clear();
80
81} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemoryView.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemoryView.java
new file mode 100644
index 00000000..add575c6
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemoryView.java
@@ -0,0 +1,205 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Iterator;
12import java.util.Map;
13import java.util.Map.Entry;
14import java.util.Set;
15import java.util.function.BiConsumer;
16import java.util.stream.Stream;
17import java.util.stream.StreamSupport;
18
19/**
20 * A read-only view on a memory containing a positive or negative number of equal() copies for some values.
21 * During iterations, each distinct value is iterated only once.
22 *
23 * <p> See {@link IMemory}.
24 *
25 * <p> Implementors must provide semantic (not identity-based) hashCode() and equals() using the static helpers {@link #hashCode(IMemoryView)} and {@link #equals(IMemoryView, Object)} here.
26 *
27 * @author Gabor Bergmann
28 *
29 * @since 2.0
30 */
31public interface IMemoryView<T> extends Iterable<T> {
32
33 /**
34 * Returns the number of occurrences of the given value.
35 *
36 * @return the number of occurrences
37 */
38 int getCount(T value);
39
40 /**
41 * Returns the number of occurrences of the given value (which may be of any type).
42 *
43 * @return the number of occurrences
44 */
45 int getCountUnsafe(Object value);
46
47 /**
48 * @return true if the given value is contained with a nonzero multiplicity
49 */
50 boolean containsNonZero(T value);
51
52 /**
53 * @return true if the given value (which may be of any type) is contained with a nonzero multiplicity
54 */
55 boolean containsNonZeroUnsafe(Object value);
56
57 /**
58 * @return the number of distinct values
59 */
60 int size();
61
62 /**
63 *
64 * @return iff contains at least one value with non-zero occurrences
65 */
66 boolean isEmpty();
67
68 /**
69 * The set of distinct values
70 */
71 Set<T> distinctValues();
72
73
74 /**
75 * Where supported, returns the stored element that is equal to the given value, or null if none.
76 * Useful for canonicalization in case of non-identity equals().
77 *
78 * <p> For collections that do not support canonicalization, simply returns the argument if contained, null if none.
79 *
80 * @return a value equal to the argument if such a value is stored, or null if none
81 */
82 default T theContainedVersionOf(T value) {
83 if (containsNonZero(value)) return value; else return null;
84 }
85
86 /**
87 * Where supported, returns the stored element that is equal to the given value (of any type),
88 * or null if none.
89 * Useful for canonicalization in case of non-identity equals().
90 *
91 * <p> For collections that do not support canonicalization, simply returns the argument if contained, null if none.
92 *
93 * @return a value equal to the argument if such a value is stored, or null if none
94 */
95 @SuppressWarnings("unchecked")
96 default T theContainedVersionOfUnsafe(Object value) {
97 if (containsNonZeroUnsafe(value)) return (T) value; else return null;
98 }
99
100
101 /**
102 * @return an unmodifiable view of contained values with their multiplicities
103 */
104 default Iterable<Map.Entry<T, Integer>> entriesWithMultiplicities() {
105 return () -> {
106 Iterator<T> wrapped = distinctValues().iterator();
107 return new Iterator<Map.Entry<T, Integer>> () {
108 @Override
109 public boolean hasNext() {
110 return wrapped.hasNext();
111 }
112
113 @Override
114 public Map.Entry<T, Integer> next() {
115 T key = wrapped.next();
116 int count = getCount(key);
117 return new Map.Entry<T, Integer>(){
118 @Override
119 public T getKey() {
120 return key;
121 }
122
123 @Override
124 public Integer getValue() {
125 return count;
126 }
127
128 @Override
129 public Integer setValue(Integer value) {
130 throw new UnsupportedOperationException();
131 }
132
133 @Override
134 public String toString() {
135 return String.format("%d of %s", count, key);
136 }
137
138 };
139 }
140
141 };
142 };
143 }
144
145 /**
146 * Process contained values with their multiplicities
147 */
148 default void forEachEntryWithMultiplicities(BiConsumer<T, Integer> entryConsumer) {
149 for (T value : distinctValues()) {
150 entryConsumer.accept(value, getCount(value));
151 }
152 }
153
154
155 /**
156 * For compatibility with legacy code relying on element-to-integer maps.
157 * @return an unmodifiable view of contained values with their multiplicities
158 */
159 public default Map<T, Integer> asMap() {
160 return new MemoryViewBackedMapView<>(this);
161 }
162
163 /**
164 * For compatibility with legacy code relying on element-to-integer maps.
165 * @return an unmodifiable view of contained values with their multiplicities
166 */
167 public static <T> IMemoryView<T> fromMap(Map<T, Integer> wrapped) {
168 return new MapBackedMemoryView<>(wrapped);
169 }
170
171 /**
172 * @return a stream of values, iterable once
173 * @since 2.1
174 */
175 public default Stream<T> asStream() {
176 return StreamSupport.stream(spliterator(), false);
177 }
178
179 /**
180 * Provides semantic equality comparison.
181 */
182 public static <T> boolean equals(IMemoryView<T> self, Object obj) {
183 if (obj instanceof IMemoryView<?>) {
184 IMemoryView<?> other = (IMemoryView<?>) obj;
185 if (other.size() != self.size()) return false;
186 for (Entry<?, Integer> entry : other.entriesWithMultiplicities()) {
187 if ( !entry.getValue().equals(self.getCountUnsafe(entry.getKey())))
188 return false;
189 }
190 return true;
191 }
192 return false;
193 }
194
195 /**
196 * Provides semantic hashCode() comparison.
197 */
198 public static <T> int hashCode(IMemoryView<T> memory) {
199 int hashCode = 0;
200 for (T value : memory.distinctValues()) {
201 hashCode += value.hashCode() ^ Integer.hashCode(memory.getCount(value));
202 }
203 return hashCode;
204 }
205} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookup.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookup.java
new file mode 100644
index 00000000..1ce1d2c9
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookup.java
@@ -0,0 +1,216 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.stream.Stream;
12
13import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
14
15/**
16 * A multi-map that associates sets / multisets / delta sets of values to each key.
17 *
18 * <p> Implementors must provide semantic (not identity-based) hashCode() and equals() using the static helpers {@link #hashCode(IMultiLookup)} and {@link #equals(IMultiLookup, Object)} here.
19 *
20 * @author Gabor Bergmann
21 * @since 2.0
22 * @noimplement This interface is not intended to be implemented by clients.
23 */
24public interface IMultiLookup<Key, Value> {
25
26 /**
27 * Returns true if this collection is empty, false otherwise.
28 * @since 2.2
29 */
30 boolean isEmpty();
31
32
33 /**
34 * Returns true if there are any values associated with the given key.
35 * @param key a key for which associated values are sought
36 * @since 2.3
37 */
38 boolean lookupExists(Key key);
39
40 /**
41 * Returns a (read-only) bucket of values associated with the given key.
42 * Clients must not modify the returned bucket.
43 * @param key a key for which associated values are sought
44 * @return null if key not found, a bucket of values otherwise
45 */
46 IMemoryView<Value> lookup(Key key);
47
48 /**
49 * Returns a (read-only) bucket of values associated with the given key.
50 * Clients must not modify the returned bucket.
51 * @param key a key for which associated values are sought
52 * @return a bucket of values, never null
53 */
54 default IMemoryView<Value> lookupOrEmpty(Key key) {
55 IMemoryView<Value> bucket = lookup(key);
56 return bucket == null ? EmptyMemory.instance() : bucket;
57 }
58
59 /**
60 * Returns a (read-only) bucket of values associated with the given key, while simultaneously removing them.
61 * Clients must not modify the returned bucket.
62 * @param key a key for which associated values are sought
63 * @return a bucket of values, never null
64 * @since 2.3
65 */
66 IMemoryView<Value> lookupAndRemoveAll(Key key);
67
68 /**
69 * Returns a (read-only) bucket of values associated with the given key, which can be of any type.
70 * Clients must not modify the returned bucket.
71 * @param key a key for which associated values are sought (may or may not be of Key type)
72 * @return null if key not found, a bucket of values otherwise
73 */
74 IMemoryView<Value> lookupUnsafe(Object key);
75
76 /**
77 * Returns a (read-only) bucket of values associated with the given key.
78 * Clients must not modify the returned bucket.
79 * @param key a key for which associated values are sought (may or may not be of Key type)
80 * @return a bucket of values, never null
81 */
82 default IMemoryView<Value> lookupUnsafeOrEmpty(Object key) {
83 IMemoryView<Value> bucket = lookupUnsafe(key);
84 return bucket == null ? EmptyMemory.instance() : bucket;
85 }
86
87
88
89 /**
90 * @return the set of distinct keys that have values associated.
91 */
92 Iterable<Key> distinctKeys();
93
94 /**
95 * @return the set of distinct keys that have values associated.
96 * @since 2.3
97 */
98 Stream<Key> distinctKeysStream();
99
100 /**
101 * @return the number of distinct keys that have values associated.
102 */
103 int countKeys();
104
105 /**
106 * Iterates once over each distinct value.
107 */
108 Iterable<Value> distinctValues();
109
110 /**
111 * Iterates once over each distinct value.
112 * @since 2.3
113 */
114 Stream<Value> distinctValuesStream();
115
116
117
118 /**
119 * How significant was the change? *
120 * @author Gabor Bergmann
121 */
122 public enum ChangeGranularity {
123 /**
124 * First key-value pair with given key inserted, or last pair with given key deleted.
125 * (In case of delta maps, also if last negative key-value pair with given key neutralized.)
126 */
127 KEY,
128 /**
129 * First occurrence of given key-value pair inserted, or last occurrence of the pair deleted, while key still has values associated.
130 * (In case of delta maps, also if last negative occurrence of key-value pair neutralized.)
131 */
132 VALUE,
133 /**
134 * Duplicate key-value pair inserted or deleted.
135 */
136 DUPLICATE
137 }
138
139 /**
140 * Adds key-value pair to the lookup structure, or fails if not possible.
141 * <p> If the addition would cause duplicates but the bucket type does not allow it ({@link MemoryType#SETS}),
142 * the operation throws an {@link IllegalStateException}.
143 * @return the granularity of the change
144 * @throws IllegalStateException if addition would cause duplication that is not permitted
145 */
146 public ChangeGranularity addPair(Key key, Value value);
147 /**
148 * Adds key-value pair to the lookup structure.
149 * <p> If the addition would cause duplicates but the bucket type does not allow it ({@link MemoryType#SETS}),
150 * the operation is silently ignored and {@link ChangeGranularity#DUPLICATE} is returned.
151 * @return the granularity of the change, or {@link ChangeGranularity#DUPLICATE} if addition would result in a duplicate and therefore ignored
152 * @since 2.3
153 */
154 public ChangeGranularity addPairOrNop(Key key, Value value);
155 /**
156 * Removes key-value pair from the lookup structure, or fails if not possible.
157 * <p> When attempting to remove a key-value pair with zero multiplicity from a non-delta bucket type
158 * ({@link MemoryType#SETS} or {@link MemoryType#MULTISETS}}), an {@link IllegalStateException} is thrown.
159 * @return the granularity of the change
160 * @throws IllegalStateException if removing non-existing element that is not permitted
161 */
162 public ChangeGranularity removePair(Key key, Value value);
163 /**
164 * Removes key-value pair from the lookup structure.
165 * <p> When attempting to remove a key-value pair with zero multiplicity from a non-delta bucket type
166 * ({@link MemoryType#SETS} or {@link MemoryType#MULTISETS}}),
167 * the operation is silently ignored and {@link ChangeGranularity#DUPLICATE} is returned.
168 * @return the granularity of the change
169 * @throws IllegalStateException if removing non-existing element that is not permitted
170 * @since 2.3
171 */
172 public ChangeGranularity removePairOrNop(Key key, Value value);
173
174 /**
175 * Updates multiplicity of key-value pair by a positive amount.
176 *
177 * <p> PRE: count > 0
178 *
179 * @return the granularity of the change
180 * @throws IllegalStateException if addition would cause duplication that is not permitted
181 */
182 public ChangeGranularity addPairPositiveMultiplicity(Key key, Value value, int count);
183
184 /**
185 * Empties out the lookup structure.
186 */
187 public void clear();
188
189 /**
190 * Provides semantic equality comparison.
191 */
192 public static <Key, Value> boolean equals(IMultiLookup<Key, Value> self, Object obj) {
193 if (obj instanceof IMultiLookup<?, ?>) {
194 IMultiLookup<?, ?> other = (IMultiLookup<?, ?>) obj;
195 if (other.countKeys() != self.countKeys()) return false;
196 for (Object key : other.distinctKeys()) {
197 if (! other.lookupUnsafe(key).equals(self.lookupUnsafe(key)))
198 return false;
199 }
200 return true;
201 }
202 return false;
203 }
204
205 /**
206 * Provides semantic hashCode() comparison.
207 */
208 public static <Key, Value> int hashCode(IMultiLookup<Key, Value> memory) {
209 int hashCode = 0;
210 for (Key key : memory.distinctKeys()) {
211 hashCode += key.hashCode() ^ memory.lookup(key).hashCode();
212 }
213 return hashCode;
214 }
215
216}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookupAbstract.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookupAbstract.java
new file mode 100644
index 00000000..8b1944c1
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookupAbstract.java
@@ -0,0 +1,485 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Collections;
12import java.util.Iterator;
13import java.util.NoSuchElementException;
14import java.util.Objects;
15import java.util.stream.Stream;
16import java.util.stream.StreamSupport;
17
18import tools.refinery.viatra.runtime.matchers.util.MarkedMemory.MarkedSet;
19
20/**
21 * Specialized multimap implementation that saves memory
22 * by storing singleton value objects (multiplicity 1) instead of multiset buckets
23 * whenever there is only one value associated with a key.
24 *
25 * <p> See specialized {@link ToSetsAbstract}, {@link ToMultisetsAbstract} for various bucket types.
26 *
27 * <p> Implemented as a Key->Object map with invariant: <ul>
28 * <li> key maps to null if associated with no values;
29 * <li> key maps to a single Value iff it is associated with a single value of multiplicity +1;
30 * <li> key maps to Bucket otherwise
31 * </ul>
32 *
33 * Note that due to the above invariant, handling +1 and -1 are asymmetric in case of delta maps.
34 *
35 * <p> Not intended as an API, but rather as a 'base class' for implementors.
36 * Realized as an interface with default implementations, instead of an abstract class,
37 * to ensure that implementors can easily choose a base class such as UnifiedMap to augment.
38 *
39 * <p> Implementor should inherit from a Map<Key, Object>-like class (primitive map possible)
40 * and bind the lowLevel* methods accordingly.
41 *
42 * @noreference This interface is not intended to be referenced by clients.
43 * @noimplement This interface is not intended to be implemented by clients.
44 *
45 * @author Gabor Bergmann
46 * @since 2.0
47 *
48 *
49 */
50public interface IMultiLookupAbstract<Key, Value, Bucket extends MarkedMemory<Value>> extends IMultiLookup<Key, Value> {
51
52 // the following methods must be bound to a concrete Map<Key,Object>-like structure (primitive implementation allowed)
53
54 /**
55 * Implementor shall bind to the low-level get() or equivalent of the underlying Key-to-Object map
56 */
57 abstract Object lowLevelGet(Key key);
58
59 /**
60 * Implementor shall bind to the low-level get() or equivalent of the underlying Key-to-Object map
61 */
62 abstract Object lowLevelGetUnsafe(Object key);
63
64 /**
65 * Implementor shall bind to the low-level remove() or equivalent of the underlying Key-to-Object map
66 */
67 abstract Object lowLevelRemove(Key key);
68
69 /**
70 * Implementor shall bind to the low-level putIfAbsent() or equivalent of the underlying Key-to-Object map
71 */
72 abstract Object lowLevelPutIfAbsent(Key key, Value value);
73
74 /**
75 * Implementor shall bind to the low-level put() or equivalent of the underlying Key-to-Object map
76 */
77 abstract void lowLevelPut(Key key, Object valueOrBucket);
78
79 /**
80 * Implementor shall bind to the low-level values() or equivalent of the underlying Key-to-Object map
81 */
82 abstract Iterable<Object> lowLevelValues();
83
84 /**
85 * Implementor shall bind to the low-level keySet() or equivalent of the underlying Key-to-Object map
86 */
87 abstract Iterable<Key> lowLevelKeySet();
88
89 /**
90 * Implementor shall bind to the low-level size() or equivalent of the underlying Key-to-Object map
91 */
92 abstract int lowLevelSize();
93
94
95 // generic multi-lookup logic
96
97 @Override
98 default boolean lookupExists(Key key) {
99 Object object = lowLevelGet(key);
100 return null != object;
101 }
102
103 @Override
104 public default IMemoryView<Value> lookup(Key key) {
105 Object object = lowLevelGet(key);
106 if (object == null) return null;
107 if (object instanceof MarkedMemory) return (Bucket) object;
108 return yieldSingleton((Value)object);
109 }
110
111 @Override
112 default IMemoryView<Value> lookupAndRemoveAll(Key key) {
113 Object object = lowLevelRemove(key);
114 if (object == null) return EmptyMemory.instance();
115 if (object instanceof MarkedMemory) return (Bucket) object;
116 return yieldSingleton((Value)object);
117 }
118
119 @Override
120 public default IMemoryView<Value> lookupUnsafe(Object key) {
121 Object object = lowLevelGetUnsafe(key);
122 if (object == null) return null;
123 if (object instanceof MarkedMemory) return (Bucket) object;
124 return yieldSingleton((Value)object);
125 }
126
127 @Override
128 public default ChangeGranularity addPair(Key key, Value value) {
129 return addPairInternal(key, value, true);
130 }
131
132 @Override
133 default ChangeGranularity addPairOrNop(Key key, Value value) {
134 return addPairInternal(key, value, false);
135 }
136
137 public default ChangeGranularity addPairInternal(Key key, Value value, boolean throwIfImpossible) {
138 Object old = lowLevelPutIfAbsent(key, value);
139 boolean keyChange = (old == null);
140
141 if (keyChange) { // key was not present
142 return ChangeGranularity.KEY;
143 } else { // key was already present
144 Bucket bucket;
145 if (old instanceof MarkedMemory) { // ... as collection
146 bucket = (Bucket) old;
147 } else { // ... as singleton
148 if (!this.duplicatesAllowed() && Objects.equals(value, old)) {
149 if (throwIfImpossible)
150 throw new IllegalStateException();
151 else
152 return ChangeGranularity.DUPLICATE;
153 }
154 bucket = createSingletonBucket((Value) old);
155 lowLevelPut(key, bucket);
156 }
157 // will throw if forbidden duplicate, return false if allowed duplicate
158 if (addToBucket(bucket, value, throwIfImpossible)) {
159 // deltas may become empty or a singleton after addition!
160 if (negativesAllowed()) {
161 if (bucket.isEmpty()) {
162 lowLevelRemove(key);
163 return ChangeGranularity.KEY;
164 } else {
165 handleSingleton(key, bucket);
166 return ChangeGranularity.VALUE;
167 }
168 } else return ChangeGranularity.VALUE;
169 } else return ChangeGranularity.DUPLICATE;
170 }
171 }
172
173 @Override
174 // TODO deltas not supproted yet
175 default ChangeGranularity addPairPositiveMultiplicity(Key key, Value value, int count) {
176 if (count == 1) return addPair(key, value);
177 // count > 1, always end up with non-singleton bucket
178
179 Object old = lowLevelGet(key);
180 boolean keyChange = (old == null);
181
182 Bucket bucket;
183 if (keyChange) { // ... nothing associated to key yet
184 bucket = createSingletonBucket(value);
185 lowLevelPut(key, bucket);
186 --count; // one less to increment later
187 } else if (old instanceof MarkedMemory) { // ... as collection
188 bucket = (Bucket) old;
189 } else { // ... as singleton
190 bucket = createSingletonBucket((Value) old);
191 lowLevelPut(key, bucket);
192 }
193
194 boolean newValue = bucket.addSigned(value, count);
195
196 if (keyChange) return ChangeGranularity.KEY;
197 else if (newValue) return ChangeGranularity.VALUE;
198 else return ChangeGranularity.DUPLICATE;
199 }
200
201 @Override
202 public default ChangeGranularity removePair(Key key, Value value) {
203 return removePairInternal(key, value, true);
204 }
205
206 @Override
207 default ChangeGranularity removePairOrNop(Key key, Value value) {
208 return removePairInternal(key, value, false);
209 }
210
211 public default ChangeGranularity removePairInternal(Key key, Value value, boolean throwIfImpossible) {
212 Object old = lowLevelGet(key);
213 if (old instanceof MarkedMemory) { // ... as collection
214 @SuppressWarnings("unchecked")
215 Bucket bucket = (Bucket) old;
216 // will throw if removing non-existent, return false if removing duplicate
217 boolean valueChange = removeFromBucket(bucket, value, throwIfImpossible);
218 handleSingleton(key, bucket);
219 if (valueChange)
220 return ChangeGranularity.VALUE;
221 else
222 return ChangeGranularity.DUPLICATE;
223 } else if (value.equals(old)) { // matching singleton
224 lowLevelRemove(key);
225 return ChangeGranularity.KEY;
226 } else { // different singleton, will produce a delta if possible
227 if (negativesAllowed()) {
228 Bucket deltaBucket = createDeltaBucket((Value) old, value); // will throw if no deltas supported
229 lowLevelPut(key, deltaBucket);
230 return ChangeGranularity.VALUE; // no key change
231 } else {
232 if (throwIfImpossible)
233 throw new IllegalStateException();
234 else
235 return ChangeGranularity.DUPLICATE;
236 }
237 }
238 }
239
240 public default void handleSingleton(Key key, Bucket bucket) {
241 Value remainingSingleton = asSingleton(bucket);
242 if (remainingSingleton != null) { // only one remains
243 lowLevelPut(key, remainingSingleton);
244 }
245 }
246
247 @Override
248 public default Iterable<Value> distinctValues() {
249 return new Iterable<Value>() {
250 private final Iterator<Value> EMPTY_ITERATOR = Collections.<Value>emptySet().iterator();
251 @Override
252 public Iterator<Value> iterator() {
253 return new Iterator<Value>() {
254 Iterator<Object> bucketIterator = lowLevelValues().iterator();
255 Iterator<Value> elementIterator = EMPTY_ITERATOR;
256
257 @Override
258 public boolean hasNext() {
259 return (elementIterator.hasNext() || bucketIterator.hasNext());
260 }
261
262 @Override
263 public Value next() {
264 if (elementIterator.hasNext())
265 return elementIterator.next();
266 else if (bucketIterator.hasNext()) {
267 Object bucket = bucketIterator.next();
268 if (bucket instanceof MarkedMemory) {
269 elementIterator =
270 ((MarkedMemory) bucket).distinctValues().iterator();
271 return elementIterator.next();
272 } else {
273 elementIterator = EMPTY_ITERATOR;
274 return (Value) bucket;
275 }
276 } else
277 throw new NoSuchElementException();
278 }
279
280 /**
281 * Not implemented
282 */
283 @Override
284 public void remove() {
285 throw new UnsupportedOperationException();
286 }
287
288 };
289 }
290 };
291 }
292
293 @Override
294 default Stream<Value> distinctValuesStream() {
295 return StreamSupport.stream(distinctValues().spliterator(), false);
296 }
297
298 @Override
299 default Iterable<Key> distinctKeys() {
300 return lowLevelKeySet();
301 }
302
303 @Override
304 default Stream<Key> distinctKeysStream() {
305 return StreamSupport.stream(distinctKeys().spliterator(), false);
306 }
307
308 @Override
309 default int countKeys() {
310 return lowLevelSize();
311 }
312
313 // the following methods are customized for bucket type
314
315 /**
316 * @return iff negative multiplicites are allowed
317 */
318 abstract boolean negativesAllowed();
319
320 /**
321 * @return iff larger-than-1 multiplicites are allowed
322 * @since 2.3
323 */
324 abstract boolean duplicatesAllowed();
325
326 /**
327 * Increases the multiplicity of the value in the bucket.
328 * @return true iff non-duplicate
329 * @throws IllegalStateException if disallowed duplication and throwIfImpossible is specified
330 */
331 abstract boolean addToBucket(Bucket bucket, Value value, boolean throwIfImpossible);
332
333 /**
334 * Decreases the multiplicity of the value in the bucket.
335 * @return false if removing duplicate value
336 * @throws IllegalStateException if removing non-existing value (unless delta map) and throwIfImpossible is specified
337 */
338 abstract boolean removeFromBucket(Bucket bucket, Value value, boolean throwIfImpossible);
339
340 /**
341 * Checks whether the bucket is a singleton, i.e. it contains a single value with multiplicity +1
342 * @return the singleton value, or null if the bucket is not singleton
343 */
344 abstract Value asSingleton(Bucket bucket);
345
346 /**
347 * @return a new bucket consisting of a sole value
348 */
349 abstract Bucket createSingletonBucket(Value value);
350 /**
351 * @return a read-only bucket consisting of a sole value, to be returned to the user
352 */
353 default IMemoryView<Value> yieldSingleton(Value value) {
354 return new SingletonMemoryView<>(value);
355 }
356
357 /**
358 * @param positive the previously existing value, or null if the delta is to contain a single negative tuple
359 * @return a new bucket consisting of a delta of two values
360 * @throws IllegalStateException if deltas not supported
361 */
362 abstract Bucket createDeltaBucket(Value positive, Value negative);
363
364 /**
365 * A multi-lookup whose buckets are sets.
366 *
367 * <p> Not intended as an API, but rather as a 'base class' for implementors.
368 * Realized as an interface with default implementations, instead of an abstract class,
369 * to ensure that implementors can easily choose a base class such as UnifiedMap to augment.
370 *
371 * <p> Implementor should inherit from a Map<Key, Object>-like class (primitive map possible)
372 * and bind the lowLevel* methods accordingly.
373 *
374 * @noreference This interface is not intended to be referenced by clients.
375 * @noimplement This interface is not intended to be implemented by clients.
376 * @author Gabor Bergmann
377 */
378 public static interface ToSetsAbstract<Key, Value> extends IMultiLookupAbstract<Key, Value, MarkedMemory.MarkedSet<Value>> {
379 /**
380 * @return a fresh, empty marked set
381 */
382 public MarkedSet<Value> createMarkedSet();
383
384 @Override
385 public default boolean negativesAllowed() {
386 return false;
387 }
388 @Override
389 default boolean duplicatesAllowed() {
390 return false;
391 }
392
393 @Override
394 public default boolean addToBucket(MarkedSet<Value> bucket, Value value, boolean throwIfImpossible) {
395 if (bucket.addOne(value)) return true;
396 else if (throwIfImpossible) throw new IllegalStateException();
397 else return false;
398 }
399
400 @Override
401 public default boolean removeFromBucket(MarkedSet<Value> bucket, Value value, boolean throwIfImpossible) {
402 return throwIfImpossible ? bucket.removeOne(value) : bucket.removeOneOrNop(value);
403 }
404
405 @Override
406 public default Value asSingleton(MarkedSet<Value> bucket) {
407 return bucket.size() == 1 ? bucket.iterator().next() : null;
408 }
409
410 @Override
411 public default MarkedSet<Value> createSingletonBucket(Value value) {
412 MarkedSet<Value> result = createMarkedSet();
413 result.addOne(value);
414 return result;
415 }
416
417 @Override
418 public default MarkedSet<Value> createDeltaBucket(Value positive, Value negative) {
419 throw new IllegalStateException();
420 }
421 }
422
423 /**
424 * A multi-lookup whose buckets are multisets.
425 *
426 * <p> Not intended as an API, but rather as a 'base class' for implementors.
427 * Realized as an interface with default implementations, instead of an abstract class,
428 * to ensure that implementors can easily choose a base class such as UnifiedMap to augment.
429 *
430 * <p> Implementor should inherit from a Map<Key, Object>-like class (primitive map possible)
431 * and bind the lowLevel* methods accordingly.
432 *
433 * @noreference This interface is not intended to be referenced by clients.
434 * @noimplement This interface is not intended to be implemented by clients.
435 * @author Gabor Bergmann
436 */
437 public static interface ToMultisetsAbstract<Key, Value> extends IMultiLookupAbstract<Key, Value, MarkedMemory.MarkedMultiset<Value>> {
438 /**
439 * @return a fresh, empty marked multiset
440 */
441 public MarkedMemory.MarkedMultiset<Value> createMarkedMultiset();
442
443 @Override
444 public default boolean negativesAllowed() {
445 return false;
446 }
447 @Override
448 default boolean duplicatesAllowed() {
449 return true;
450 }
451
452 @Override
453 public default boolean addToBucket(MarkedMemory.MarkedMultiset<Value> bucket, Value value, boolean throwIfImpossible) {
454 return bucket.addOne(value);
455 }
456
457 @Override
458 public default boolean removeFromBucket(MarkedMemory.MarkedMultiset<Value> bucket, Value value, boolean throwIfImpossible) {
459 return throwIfImpossible ? bucket.removeOne(value) : bucket.removeOneOrNop(value);
460 }
461
462 @Override
463 public default Value asSingleton(MarkedMemory.MarkedMultiset<Value> bucket) {
464 if (bucket.size() != 1) return null;
465 Value candidate = bucket.iterator().next();
466 return bucket.getCount(candidate) == 1 ? candidate : null;
467 }
468
469 @Override
470 public default MarkedMemory.MarkedMultiset<Value> createSingletonBucket(Value value) {
471 MarkedMemory.MarkedMultiset<Value> result = createMarkedMultiset();
472 result.addOne(value);
473 return result;
474 }
475
476 @Override
477 public default MarkedMemory.MarkedMultiset<Value> createDeltaBucket(Value positive, Value negative) {
478 throw new IllegalStateException();
479 }
480 }
481
482
483 // TODO add ToDeltaBagsAbstract
484
485} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiset.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiset.java
new file mode 100644
index 00000000..bdd5d597
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiset.java
@@ -0,0 +1,30 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11/**
12 * An {@link IMemory} that always contains values with a nonnegative multiplicity.
13 *
14 * <p> In case a write operation caused underflow, an {@link IllegalStateException} is thrown.
15 *
16 * @author Gabor Bergmann
17 * @since 1.7
18 */
19public interface IMultiset<T> extends IMemory<T> {
20
21 /**
22 * Adds the given number of occurrences to the memory. The count value must be a positive number.
23 *
24 * @param count
25 * the number of occurrences
26 * @return true if the tuple was not present before in the memory
27 */
28 boolean addPositive(T value, int count);
29
30} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IProvider.java
new file mode 100644
index 00000000..cd25dc95
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IProvider.java
@@ -0,0 +1,30 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.function.Function;
12import java.util.function.Supplier;
13
14import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
15
16/**
17 * A provider interface useful in various registry instances.
18 *
19 * @author Zoltan Ujhelyi
20 *
21 */
22public interface IProvider<T> extends Supplier<T>{
23
24 public final class ProvidedValueFunction implements Function<IProvider<PQuery>, PQuery> {
25 @Override
26 public PQuery apply(IProvider<PQuery> input) {
27 return (input == null) ? null : input.get();
28 }
29 }
30}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/ISetMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/ISetMemory.java
new file mode 100644
index 00000000..0c03da48
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/ISetMemory.java
@@ -0,0 +1,37 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.function.BiConsumer;
12
13/**
14 * An {@link IMemory} that always contains values with a 0 or +1 multiplicity.
15 *
16 * <p> In case a write operation causes underflow or overflow, an {@link IllegalStateException} is thrown.
17 *
18 * @author Gabor Bergmann
19 * @since 2.0
20 */
21public interface ISetMemory<T> extends IMemory<T> {
22
23 @Override
24 default void forEachEntryWithMultiplicities(BiConsumer<T, Integer> entryConsumer) {
25 for (T t : this.distinctValues()) entryConsumer.accept(t, 1);
26 }
27
28
29 @Override
30 default boolean removeOne(T value) {
31 if (!removeOneOrNop(value))
32 throw new IllegalStateException();
33 return true;
34 }
35
36
37}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MapBackedMemoryView.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MapBackedMemoryView.java
new file mode 100644
index 00000000..3be078bd
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MapBackedMemoryView.java
@@ -0,0 +1,102 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Iterator;
12import java.util.Map;
13import java.util.Map.Entry;
14import java.util.Set;
15import java.util.function.BiConsumer;
16
17/**
18 * Wraps a Map<T, Integer> (mapping elements to non-zero multiplicities) into an {@link IMemoryView}.
19 *
20 * @author Gabor Bergmann
21 * @since 2.0
22 */
23public class MapBackedMemoryView<T> implements IMemoryView<T> {
24
25 private Map<T, Integer> wrapped;
26
27 /**
28 * @param wrapped an equivalent map from contained objects to multiplicities
29 */
30 protected MapBackedMemoryView(Map<T, Integer> wrapped) {
31 super();
32 this.wrapped = wrapped;
33 }
34
35 @Override
36 public Iterator<T> iterator() {
37 return wrapped.keySet().iterator();
38 }
39
40 @Override
41 public int getCount(T value) {
42 return getCountUnsafe(value);
43 }
44
45 @Override
46 public int getCountUnsafe(Object value) {
47 Integer count = wrapped.get(value);
48 return count == null ? 0 : count;
49 }
50
51 @Override
52 public boolean containsNonZero(T value) {
53 return wrapped.containsKey(value);
54 }
55
56 @Override
57 public boolean containsNonZeroUnsafe(Object value) {
58 return wrapped.containsKey(value);
59 }
60
61 @Override
62 public int size() {
63 return wrapped.size();
64 }
65
66 @Override
67 public boolean isEmpty() {
68 return wrapped.isEmpty();
69 }
70
71 @Override
72 public Set<T> distinctValues() {
73 return wrapped.keySet();
74 }
75
76
77 @Override
78 public void forEachEntryWithMultiplicities(BiConsumer<T, Integer> entryConsumer) {
79 for (Entry<T, Integer> entry : wrapped.entrySet()) {
80 entryConsumer.accept(entry.getKey(), entry.getValue());
81 }
82 }
83
84 @Override
85 public Iterable<Entry<T, Integer>> entriesWithMultiplicities() {
86 return wrapped.entrySet();
87 }
88
89 @Override
90 public int hashCode() {
91 return IMemoryView.hashCode(this);
92 }
93 @Override
94 public boolean equals(Object obj) {
95 return IMemoryView.equals(this, obj);
96 }
97
98 @Override
99 public String toString() {
100 return wrapped.toString();
101 }
102}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MarkedMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MarkedMemory.java
new file mode 100644
index 00000000..d22dcbe7
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MarkedMemory.java
@@ -0,0 +1,21 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11/**
12 * Internal marker type, must only be instantiated inside implementors of IMultiLookupImpl
13 * @noimplement This interface is not intended to be implemented by clients.
14 * @since 2.0
15 */
16public interface MarkedMemory<Value> extends IMemory<Value> {
17
18 static interface MarkedSet<Value> extends MarkedMemory<Value> {}
19 static interface MarkedMultiset<Value> extends MarkedMemory<Value> {}
20 static interface MarkedDeltaBag<Value> extends MarkedMemory<Value> {}
21} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MemoryViewBackedMapView.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MemoryViewBackedMapView.java
new file mode 100644
index 00000000..49711a89
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MemoryViewBackedMapView.java
@@ -0,0 +1,117 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.HashSet;
14import java.util.Map;
15import java.util.Set;
16
17/**
18 * A partial and read-only Map implementation, mapping elements to multiplicities backed by an {@link IMemoryView}.
19 *
20 * <p> Not implemented: write methods.
21 *
22 * <p> Inefficiently implemented: {@link #containsValue(Object)}, {@link #values()}, {@link #entrySet()}.
23 *
24 * @author Gabor Bergmann
25 * @since 2.0
26 */
27public class MemoryViewBackedMapView<T> implements Map<T, Integer> {
28
29 private static final String READ_ONLY = "Read only";
30 private final IMemoryView<T> wrapped;
31
32 /**
33 * @param wrapped a memory view whose contents are to be exposed as an element-to-integer map.
34 */
35 protected MemoryViewBackedMapView(IMemoryView<T> wrapped) {
36 super();
37 this.wrapped = wrapped;
38 }
39
40 @Override
41 public int size() {
42 return wrapped.size();
43 }
44
45 @Override
46 public boolean isEmpty() {
47 return wrapped.isEmpty();
48 }
49
50 @Override
51 public boolean containsKey(Object key) {
52 return wrapped.containsNonZeroUnsafe(key);
53 }
54
55 @Override
56 public boolean containsValue(Object value) {
57 if (value instanceof Integer) {
58 for (Entry<T, Integer> entry : wrapped.entriesWithMultiplicities()) {
59 if (entry.getValue().equals(value)) return true;
60 }
61 }
62 return false;
63 }
64
65 @Override
66 public Integer put(T key, Integer value) {
67 throw new UnsupportedOperationException(READ_ONLY);
68 }
69
70 @Override
71 public Integer get(Object key) {
72 int count = wrapped.getCountUnsafe(key);
73 if (count == 0) return null; else return count;
74 }
75
76 @Override
77 public Integer remove(Object key) {
78 throw new UnsupportedOperationException(READ_ONLY);
79 }
80
81 @Override
82 public void putAll(Map<? extends T, ? extends Integer> m) {
83 throw new UnsupportedOperationException(READ_ONLY);
84 }
85
86 @Override
87 public void clear() {
88 throw new UnsupportedOperationException(READ_ONLY);
89 }
90
91 @Override
92 public Set<T> keySet() {
93 return wrapped.distinctValues();
94 }
95
96 @Override
97 public Collection<Integer> values() {
98 Collection<Integer> result = new ArrayList<>();
99 wrapped.forEachEntryWithMultiplicities((value, count) -> result.add(count));
100 return result;
101 }
102
103 @Override
104 public Set<Entry<T, Integer>> entrySet() {
105 Set<Entry<T, Integer>> result = new HashSet<>();
106 for (Entry<T, Integer> entry : wrapped.entriesWithMultiplicities()) {
107 result.add(entry);
108 }
109 return result;
110 }
111
112
113 @Override
114 public String toString() {
115 return wrapped.toString();
116 }
117}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Preconditions.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Preconditions.java
new file mode 100644
index 00000000..e9e5e3a0
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Preconditions.java
@@ -0,0 +1,208 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.function.Supplier;
12
13/**
14 * This class was motivated by the similar Preconditions class from Guava to provide simple precondition checking
15 * functionality. However, as starting with version 2.0 the runtime of VIATRA Query should not depend on Guava, the
16 * relevant functionality of the Preconditions checking functionality will be implemented here.
17 *
18 * @author Zoltan Ujhelyi
19 * @since 2.0
20 *
21 */
22public final class Preconditions {
23
24 private Preconditions() {
25 /* Utility class constructor */ }
26
27 /**
28 * Ensures the truth of an expression involving one or more parameters to the calling method.
29 *
30 * @param expression
31 * a boolean expression
32 * @throws IllegalArgumentException
33 * if {@code expression} is false
34 */
35 public static void checkArgument(boolean expression) {
36 if (!expression) {
37 throw new IllegalArgumentException();
38 }
39 }
40
41 /**
42 * Ensures the truth of an expression involving one or more parameters to the calling method.
43 *
44 * @param expression
45 * a boolean expression
46 * @param errorMessage
47 * the exception message to use if the check fails
48 * @throws IllegalArgumentException
49 * if {@code expression} is false
50 */
51 public static void checkArgument(boolean expression, String errorMessage) {
52 if (!expression) {
53 throw new IllegalArgumentException(errorMessage);
54 }
55 }
56
57 /**
58 * Ensures the truth of an expression involving one or more parameters to the calling method.
59 *
60 * @param expression
61 * a boolean expression
62 * @param errorMessageTemplate
63 * a template for the exception message should the check fail using the Java Formatter syntax; the same
64 * as used by {@link String#format(String, Object...)}.
65 * @param errorMessageArgs
66 * the arguments to be substituted into the message template.
67 * @throws IllegalArgumentException
68 * if {@code expression} is false
69 * @throws NullPointerException
70 * if the check fails and either {@code errorMessageTemplate} or {@code errorMessageArgs} is null (don't
71 * let this happen)
72 */
73 public static void checkArgument(boolean expression, String errorMessageTemplate, Object... errorMessageArgs) {
74 if (!expression) {
75 throw new IllegalArgumentException(String.format(errorMessageTemplate, errorMessageArgs));
76 }
77 }
78
79 /**
80 * Ensures the truth of an expression involving one or more parameters to the calling method.
81 *
82 * @param expression
83 * a boolean expression
84 * @param messageSupplier a supplier that is called to calculate the error message if necessary
85 * @throws IllegalArgumentException
86 * if {@code expression} is false
87 */
88 public static void checkArgument(boolean expression, Supplier<String> messageSupplier) {
89 if (!expression) {
90 throw new IllegalArgumentException(messageSupplier.get());
91 }
92 }
93
94 /**
95 * Ensures the truth of an expression involving one or more fields of a class.
96 *
97 * @param expression
98 * a boolean expression
99 * @throws IllegalStateException
100 * if {@code expression} is false
101 */
102 public static void checkState(boolean expression) {
103 if (!expression) {
104 throw new IllegalStateException();
105 }
106 }
107
108 /**
109 * Ensures the truth of an expression involving one or more fields of a class.
110 *
111 * @param expression
112 * a boolean expression
113 * @param errorMessage
114 * the exception message to use if the check fails
115 * @throws IllegalStateException
116 * if {@code expression} is false
117 */
118 public static void checkState(boolean expression, String errorMessage) {
119 if (!expression) {
120 throw new IllegalStateException(errorMessage);
121 }
122 }
123
124 /**
125 * Ensures the truth of an expression involving one or more fields of a class.
126 *
127 * @param expression
128 * a boolean expression
129 * @param errorMessageTemplate
130 * a template for the exception message should the check fail using the Java Formatter syntax; the same
131 * as used by {@link String#format(String, Object...)}.
132 * @param errorMessageArgs
133 * the arguments to be substituted into the message template.
134 * @throws IllegalStateException
135 * if {@code expression} is false
136 * @throws NullPointerException
137 * if the check fails and either {@code errorMessageTemplate} or {@code errorMessageArgs} is null (don't
138 * let this happen)
139 */
140 public static void checkState(boolean expression, String errorMessageTemplate, Object... errorMessageArgs) {
141 if (!expression) {
142 throw new IllegalStateException(String.format(errorMessageTemplate, errorMessageArgs));
143 }
144 }
145
146 /**
147 * Ensures the truth of an expression involving one or more fields of a class.
148 *
149 * @param expression
150 * a boolean expression
151 * @param messageSupplier a supplier that is called to calculate the error message if necessary
152 * @throws IllegalStateException
153 * if {@code expression} is false
154 */
155 public static void checkState(boolean expression, Supplier<String> messageSupplier) {
156 if (!expression) {
157 throw new IllegalStateException(messageSupplier.get());
158 }
159 }
160
161 /**
162 * Ensures that an index is appropriate for a list or array of given size.
163 *
164 * @param index
165 * @param size
166 * @throws IndexOutOfBoundsException
167 * if index is negative or is greater or equal to size
168 */
169 public static void checkElementIndex(int index, int size) {
170 if (index < 0 || index >= size) {
171 throw new IndexOutOfBoundsException();
172 }
173 }
174
175 /**
176 * Ensures that an index is appropriate for a list or array of given size.
177 *
178 * @param index
179 * @param size
180 * @param errorMessageTemplate
181 * a template for the exception message should the check fail using the Java Formatter syntax; the same
182 * as used by {@link String#format(String, Object...)}.
183 * @param errorMessageArgs
184 * the arguments to be substituted into the message template.
185 * @throws IndexOutOfBoundsException
186 * if index is negative or is greater or equal to size
187 */
188 public static void checkElementIndex(int index, int size, String errorMessageTemplate, Object... errorMessageArgs) {
189 if (index < 0 || index >= size) {
190 throw new IndexOutOfBoundsException(String.format(errorMessageTemplate, errorMessageArgs));
191 }
192 }
193
194 /**
195 * Ensures that an index is appropriate for a list or array of given size.
196 *
197 * @param index
198 * @param size
199 * @param messageSupplier a supplier that is called to calculate the error message if necessary
200 * @throws IndexOutOfBoundsException
201 * if index is negative or is greater or equal to size
202 */
203 public static void checkElementIndex(int index, int size, Supplier<String> messageSupplier) {
204 if (index < 0 || index >= size) {
205 throw new IndexOutOfBoundsException(messageSupplier.get());
206 }
207 }
208}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/PurgableCache.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/PurgableCache.java
new file mode 100644
index 00000000..c4e6b5af
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/PurgableCache.java
@@ -0,0 +1,44 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.HashMap;
12import java.util.Map;
13import java.util.function.Supplier;
14
15/**
16 * @author Zoltan Ujhelyi
17 * @since 1.7
18 * @noreference This class is not intended to be referenced by clients.
19 */
20public class PurgableCache implements ICache {
21
22 Map<Object, Object> storage = new HashMap<>();
23
24 @Override
25 @SuppressWarnings("unchecked")
26 public <T> T getValue(Object key, Class<? extends T> clazz, Supplier<T> valueProvider) {
27 if (storage.containsKey(key)) {
28 Object value = storage.get(key);
29 Preconditions.checkState(clazz.isInstance(value), "Cache stores for key %s a value of %s that is incompatible with the requested type %s", key, value, clazz);
30 return (T) value;
31 } else {
32 T value = valueProvider.get();
33 storage.put(key, value);
34 return value;
35 }
36 }
37
38 /**
39 * Removes all values stored in the cache
40 */
41 public void purge() {
42 storage.clear();
43 }
44}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Sets.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Sets.java
new file mode 100644
index 00000000..3749fe06
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Sets.java
@@ -0,0 +1,90 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *
9 * Contributors:
10 * Gabor Bergmann - initial API and implementation
11 *******************************************************************************/
12package tools.refinery.viatra.runtime.matchers.util;
13
14import java.util.ArrayList;
15import java.util.List;
16import java.util.Set;
17import java.util.stream.Collectors;
18import java.util.stream.Stream;
19
20/**
21 * This class was motivated by the similar Sets class from Guava to provide simple set manipulation
22 * functionality. However, as starting with version 2.3 the runtime of VIATRA Query should not depend on Guava,
23 * not even internally, the relevant subset of Sets methods will be reimplemented here.
24 *
25 * <p> The current approach is to delegate to Eclipse Collections wherever possible.
26 * Such glue methods are useful so that downstream clients can avoid directly depending on Eclipse Collections.
27 *
28 * <p> Without an equivalent from Eclipse Collections, {@link #cartesianProduct(List)} is implemented here from scratch.
29 *
30 * @author Gabor Bergmann
31 * @since 2.3
32 */
33public final class Sets {
34
35 /**
36 * @since 2.4
37 */
38 public static <A> Set<A> newSet(Iterable<A> elements) {
39 return org.eclipse.collections.impl.factory.Sets.mutable.ofAll(elements);
40 }
41
42 public static <A> Set<A> intersection(Set<A> left, Set<A> right) {
43 return org.eclipse.collections.impl.factory.Sets.intersect(left, right);
44 }
45
46 public static <A> Set<A> difference(Set<A> left, Set<A> right) {
47 return org.eclipse.collections.impl.factory.Sets.difference(left, right);
48 }
49
50 public static <A> Set<A> union(Set<A> left, Set<A> right) {
51 return org.eclipse.collections.impl.factory.Sets.union(left, right);
52 }
53
54 public static <A> Set<? extends Set<A>> powerSet(Set<A> set) {
55 return org.eclipse.collections.impl.factory.Sets.powerSet(set);
56 }
57
58 public static <A> Set<List<A>> cartesianProduct(List<? extends Set<? extends A>> setsList) {
59
60 class Suffix { // simple immutable linked list
61 private A head;
62 private Suffix next;
63
64 public Suffix(A head, Suffix next) {
65 super();
66 this.head = head;
67 this.next = next;
68 }
69
70 public List<A> toList() {
71 ArrayList<A> result = new ArrayList<>();
72 for (Suffix cursor = this; cursor!=null; cursor = cursor.next)
73 result.add(cursor.head);
74 return result;
75 }
76 }
77
78 // build result lists from end to start, in the form of suffixes
79 Stream<Suffix> suffixes = Stream.of((Suffix) null /* empty suffix*/);
80 for (int i = setsList.size()-1; i>=0; --i) { // iterate sets in reverse order
81 Set<? extends A> set = setsList.get(i);
82 suffixes = suffixes.flatMap(suffix -> set.stream().map(newElement -> new Suffix(newElement, suffix)));
83 }
84
85
86 return suffixes.map(Suffix::toList).collect(Collectors.toSet());
87 }
88
89
90}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Signed.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Signed.java
new file mode 100644
index 00000000..8f8bc228
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Signed.java
@@ -0,0 +1,60 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, itemis AG, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Objects;
12
13/**
14 * A piece of data associated with a direction.
15 *
16 * @author Tamas Szabo
17 * @since 2.4
18 */
19public class Signed<Payload extends Comparable<Payload>> {
20
21 private final Payload payload;
22 private final Direction direction;
23
24 public Signed(final Direction direction, final Payload payload) {
25 this.payload = payload;
26 this.direction = direction;
27 }
28
29 public Payload getPayload() {
30 return payload;
31 }
32
33 public Direction getDirection() {
34 return direction;
35 }
36
37 @Override
38 public int hashCode() {
39 return Objects.hash(direction, payload);
40 }
41
42 @Override
43 public boolean equals(final Object obj) {
44 if (this == obj) {
45 return true;
46 } else if (obj == null || this.getClass() != obj.getClass()) {
47 return false;
48 } else {
49 @SuppressWarnings("rawtypes")
50 final Signed other = (Signed) obj;
51 return direction == other.direction && Objects.equals(payload, other.payload);
52 }
53 }
54
55 @Override
56 public String toString() {
57 return this.direction.asSign() + this.payload.toString();
58 }
59
60} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonInstanceProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonInstanceProvider.java
new file mode 100644
index 00000000..cc5963f7
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonInstanceProvider.java
@@ -0,0 +1,29 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11/**
12 * A provider implementation that always returns the same object instance.
13 * @author Zoltan Ujhelyi
14 */
15public class SingletonInstanceProvider<T> implements IProvider<T>{
16
17 private T instance;
18
19 public SingletonInstanceProvider(T instance) {
20 Preconditions.checkArgument(instance != null, "Instance parameter must not be null.");
21 this.instance = instance;
22 }
23
24 @Override
25 public T get() {
26 return instance;
27 }
28
29} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonMemoryView.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonMemoryView.java
new file mode 100644
index 00000000..b303f9ad
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonMemoryView.java
@@ -0,0 +1,105 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Collections;
12import java.util.Iterator;
13import java.util.NoSuchElementException;
14import java.util.Set;
15
16/**
17 * An immutable memory view that consists of a single non-null element with multiplicity 1.
18 * @author Gabor Bergmann
19 * @since 2.0
20 */
21public final class SingletonMemoryView<Value> implements IMemoryView<Value> {
22
23 private Value wrapped;
24 private static final int ONE_HASH = Integer.valueOf(1).hashCode();
25
26 public SingletonMemoryView(Value value) {
27 this.wrapped = value;
28 }
29
30 @Override
31 public Iterator<Value> iterator() {
32 return new Iterator<Value>() {
33 boolean hasNext = true;
34
35 @Override
36 public boolean hasNext() {
37 return hasNext;
38 }
39
40 @Override
41 public Value next() {
42 if (hasNext) {
43 hasNext = false;
44 return wrapped;
45 } else throw new NoSuchElementException();
46 }
47 };
48 }
49
50 @Override
51 public int getCount(Value value) {
52 return wrapped.equals(value) ? 1 : 0;
53 }
54
55 @Override
56 public int getCountUnsafe(Object value) {
57 return wrapped.equals(value) ? 1 : 0;
58 }
59
60 @Override
61 public boolean containsNonZero(Value value) {
62 return wrapped.equals(value);
63 }
64
65 @Override
66 public boolean containsNonZeroUnsafe(Object value) {
67 return wrapped.equals(value);
68 }
69
70 @Override
71 public int size() {
72 return 1;
73 }
74
75 @Override
76 public boolean isEmpty() {
77 return false;
78 }
79
80 @Override
81 public Set<Value> distinctValues() {
82 return Collections.singleton(wrapped);
83 }
84
85 @Override
86 public boolean equals(Object obj) {
87 if (obj instanceof IMemoryView<?>) {
88 IMemoryView<?> other = (IMemoryView<?>) obj;
89 if (1 != other.size()) return false;
90 if (1 != other.getCountUnsafe(wrapped)) return false;
91 return true;
92 }
93 return false;
94 }
95
96 @Override
97 public int hashCode() {
98 return wrapped.hashCode() ^ ONE_HASH;
99 }
100
101 @Override
102 public String toString() {
103 return "{" + wrapped + "}";
104 }
105}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/TimelyMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/TimelyMemory.java
new file mode 100644
index 00000000..90fcad4d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/TimelyMemory.java
@@ -0,0 +1,517 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, itemis AG, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Collections;
12import java.util.Map;
13import java.util.Map.Entry;
14import java.util.NavigableMap;
15import java.util.Set;
16import java.util.TreeMap;
17
18import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
19import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
20import tools.refinery.viatra.runtime.matchers.util.resumable.Resumable;
21import tools.refinery.viatra.runtime.matchers.util.resumable.UnmaskedResumable;
22import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
23import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
24import tools.refinery.viatra.runtime.matchers.util.timeline.Timelines;
25
26/**
27 * A timely memory implementation that incrementally maintains the {@link Timeline}s of tuples. The memory is capable of
28 * lazy folding (see {@link Resumable}).
29 *
30 * @author Tamas Szabo
31 * @since 2.3
32 */
33public class TimelyMemory<Timestamp extends Comparable<Timestamp>> implements Clearable, UnmaskedResumable<Timestamp> {
34
35 protected final Map<Tuple, TreeMap<Timestamp, CumulativeCounter>> counters;
36 protected final Map<Tuple, Timeline<Timestamp>> timelines;
37 public final TreeMap<Timestamp, Map<Tuple, FoldingState>> foldingState;
38 protected final Set<Tuple> presentAtInfinity;
39 protected final boolean isLazy;
40 protected final Diff<Timestamp> EMPTY_DIFF = new Diff<Timestamp>();
41
42 public TimelyMemory() {
43 this(false);
44 }
45
46 public TimelyMemory(final boolean isLazy) {
47 this.counters = CollectionsFactory.createMap();
48 this.timelines = CollectionsFactory.createMap();
49 this.presentAtInfinity = CollectionsFactory.createSet();
50 this.isLazy = isLazy;
51 if (isLazy) {
52 this.foldingState = CollectionsFactory.createTreeMap();
53 } else {
54 this.foldingState = null;
55 }
56 }
57
58 @Override
59 public Set<Tuple> getResumableTuples() {
60 if (this.foldingState == null || this.foldingState.isEmpty()) {
61 return Collections.emptySet();
62 } else {
63 return this.foldingState.firstEntry().getValue().keySet();
64 }
65 }
66
67 @Override
68 public Timestamp getResumableTimestamp() {
69 if (this.foldingState == null || this.foldingState.isEmpty()) {
70 return null;
71 } else {
72 return this.foldingState.firstKey();
73 }
74 }
75
76 /**
77 * Registers the given folding state for the specified timestamp and tuple. If there is already a state stored, the
78 * two states will be merged together.
79 */
80 protected void addFoldingState(final Tuple tuple, final FoldingState state, final Timestamp timestamp) {
81 assert state.diff != 0;
82 final Map<Tuple, FoldingState> tupleMap = this.foldingState.computeIfAbsent(timestamp,
83 k -> CollectionsFactory.createMap());
84 tupleMap.compute(tuple, (k, v) -> {
85 return v == null ? state : v.merge(state);
86 });
87 }
88
89 @Override
90 public Map<Tuple, Diff<Timestamp>> resumeAt(final Timestamp timestamp) {
91 Timestamp current = this.getResumableTimestamp();
92 if (current == null) {
93 throw new IllegalStateException("There is othing to fold!");
94 } else if (current.compareTo(timestamp) != 0) {
95 // It can happen that already registered folding states end up having zero diffs,
96 // and we are instructed to continue folding at a timestamp that is higher
97 // than the lowest timestamp with a folding state.
98 // However, we only do garbage collection in doFoldingState, so now it is time to
99 // first clean up those states with zero diffs.
100 while (current != null && current.compareTo(timestamp) < 0) {
101 final Map<Tuple, FoldingState> tupleMap = this.foldingState.remove(current);
102 for (final Entry<Tuple, FoldingState> entry : tupleMap.entrySet()) {
103 final Tuple key = entry.getKey();
104 final FoldingState value = entry.getValue();
105 if (value.diff != 0) {
106 throw new IllegalStateException("Expected zero diff during garbage collection at " + current
107 + ", but the diff was " + value.diff + "!");
108 }
109 doFoldingStep(key, value, current);
110 }
111 current = this.getResumableTimestamp();
112 }
113 if (current == null || current.compareTo(timestamp) != 0) {
114 throw new IllegalStateException("Expected to continue folding at " + timestamp + "!");
115 }
116 }
117
118 final Map<Tuple, Diff<Timestamp>> diffMap = CollectionsFactory.createMap();
119 final Map<Tuple, FoldingState> tupleMap = this.foldingState.remove(timestamp);
120 for (final Entry<Tuple, FoldingState> entry : tupleMap.entrySet()) {
121 final Tuple key = entry.getKey();
122 final FoldingState value = entry.getValue();
123 diffMap.put(key, doFoldingStep(key, value, timestamp));
124 }
125
126 if (this.foldingState.get(timestamp) != null) {
127 throw new IllegalStateException(
128 "Folding at " + timestamp + " produced more folding work at the same timestamp!");
129 }
130
131 return diffMap;
132 }
133
134 protected Diff<Timestamp> doFoldingStep(final Tuple tuple, final FoldingState state, final Timestamp timestamp) {
135 final CumulativeCounter counter = getCounter(tuple, timestamp);
136 if (state.diff == 0) {
137 gcCounters(counter, tuple, timestamp);
138 return EMPTY_DIFF;
139 } else {
140 final Diff<Timestamp> resultDiff = new Diff<>();
141 final Timestamp nextTimestamp = this.counters.get(tuple).higherKey(timestamp);
142
143 final int oldCumulative = counter.cumulative;
144
145 counter.cumulative += state.diff;
146
147 computeDiffsLazy(state.diff < 0 ? Direction.DELETE : Direction.INSERT, oldCumulative, counter.cumulative,
148 timestamp, nextTimestamp, resultDiff);
149
150 gcCounters(counter, tuple, timestamp);
151 updateTimeline(tuple, resultDiff);
152
153 // prepare folding state for next timestamp
154 if (nextTimestamp != null) {
155 // propagate the incoming diff, not the diff stored in counter
156 addFoldingState(tuple, new FoldingState(state.diff), nextTimestamp);
157 }
158
159 return resultDiff;
160 }
161 }
162
163 /**
164 * On-demand initializes and returns the counter for the given tuple and timestamp.
165 */
166 protected CumulativeCounter getCounter(final Tuple tuple, final Timestamp timestamp) {
167 final TreeMap<Timestamp, CumulativeCounter> counterTimeline = this.counters.computeIfAbsent(tuple,
168 k -> CollectionsFactory.createTreeMap());
169
170 final CumulativeCounter counter = counterTimeline.computeIfAbsent(timestamp, k -> {
171 final Entry<Timestamp, CumulativeCounter> previousCounter = counterTimeline.lowerEntry(k);
172 final int previousCumulative = previousCounter == null ? 0 : previousCounter.getValue().cumulative;
173 return new CumulativeCounter(0, previousCumulative);
174 });
175
176 return counter;
177 }
178
179 /**
180 * Garbage collects the counter of the given tuple and timestamp if the new diff is zero.
181 */
182 protected void gcCounters(final CumulativeCounter counter, final Tuple tuple, final Timestamp timestamp) {
183 if (counter.diff == 0) {
184 final TreeMap<Timestamp, CumulativeCounter> counterMap = this.counters.get(tuple);
185 counterMap.remove(timestamp);
186 if (counterMap.isEmpty()) {
187 this.counters.remove(tuple);
188 }
189 }
190 }
191
192 /**
193 * Utility method that computes the timeline diffs in case of lazy memories. The diffs will be inserted into the
194 * input parameter. This method computes diffs for entire plateaus that spans from timestamp to nextTimestamp.
195 *
196 * Compared to the eager version of this method, the lazy version makes use of both the old and the new cumulative
197 * values because it can happen that the cumulative is incremented by a value that is larger than 1 (as folding
198 * states are merged together). This means that we cant decide whether the cumulative became positive by comparing
199 * the new value to 1.
200 */
201 protected void computeDiffsLazy(final Direction direction, final int oldCumulative, final int newCumulative,
202 final Timestamp timestamp, final Timestamp nextTimestamp, final Diff<Timestamp> diffs) {
203 if (direction == Direction.INSERT) {
204 if (newCumulative == 0) {
205 throw new IllegalStateException("Cumulative count can never be negative!");
206 } else {
207 if (oldCumulative == 0 /* current became positive */) {
208 // (1) either we sent out a DELETE before and now we need to cancel it,
209 // (2) or we just INSERT this for the first time
210 diffs.add(new Signed<>(Direction.INSERT, timestamp));
211 if (nextTimestamp != null) {
212 diffs.add(new Signed<>(Direction.DELETE, nextTimestamp));
213 }
214 } else /* current stays positive */ {
215 // nothing to do
216 }
217 }
218 } else {
219 if (newCumulative < 0) {
220 throw new IllegalStateException("Cumulative count can never be negative!");
221 } else {
222 if (newCumulative == 0 /* current became zero */) {
223 diffs.add(new Signed<>(Direction.DELETE, timestamp));
224 if (nextTimestamp != null) {
225 diffs.add(new Signed<>(Direction.INSERT, nextTimestamp));
226 }
227 } else /* current stays positive */ {
228 // nothing to do
229 }
230 }
231 }
232 }
233
234 /**
235 * Utility method that computes the timeline diffs in case of eager memories. The diffs will be inserted into the
236 * input parameter. This method computes diffs that describe momentary changes instead of plateaus. Returns a
237 * {@link SignChange} that describes how the sign has changed at the given timestamp.
238 */
239 protected SignChange computeDiffsEager(final Direction direction, final CumulativeCounter counter,
240 final SignChange signChangeAtPrevious, final Timestamp timestamp, final Diff<Timestamp> diffs) {
241 if (direction == Direction.INSERT) {
242 if (counter.cumulative == 0) {
243 throw new IllegalStateException("Cumulative count can never be negative!");
244 } else {
245 if (counter.cumulative == 1 /* current became positive */) {
246 if (signChangeAtPrevious != SignChange.BECAME_POSITIVE) {
247 // (1) either we sent out a DELETE before and now we need to cancel it,
248 // (2) or we just INSERT this for the first time
249 diffs.add(new Signed<>(Direction.INSERT, timestamp));
250 } else {
251 // we have already emitted this at the previous timestamp
252 // both previous and current became positive
253 throw new IllegalStateException(
254 "This would mean that the diff at current is 0 " + counter.diff);
255 }
256
257 // remember for next timestamp
258 return SignChange.BECAME_POSITIVE;
259 } else /* current stays positive */ {
260 if (signChangeAtPrevious == SignChange.BECAME_POSITIVE) {
261 // we sent out an INSERT before and now the timeline is positive already starting at previous
262 // we need to cancel the effect of this with a DELETE
263 diffs.add(new Signed<>(Direction.DELETE, timestamp));
264 } else {
265 // this is normal, both previous and current was positive and stays positive
266 }
267
268 // remember for next timestamp
269 return SignChange.IRRELEVANT;
270 }
271 }
272 } else {
273 if (counter.cumulative < 0) {
274 throw new IllegalStateException("Cumulative count can never be negative!");
275 } else {
276 if (counter.cumulative == 0 /* current became zero */) {
277 if (signChangeAtPrevious != SignChange.BECAME_ZERO) {
278 // (1) either we sent out a INSERT before and now we need to cancel it,
279 // (2) or we just DELETE this for the first time
280 diffs.add(new Signed<>(Direction.DELETE, timestamp));
281 } else {
282 // we have already emitted this at the previous timestamp
283 // both previous and current became zero
284 throw new IllegalStateException(
285 "This would mean that the diff at current is 0 " + counter.diff);
286 }
287
288 // remember for next timestamp
289 return SignChange.BECAME_ZERO;
290 } else /* current stays positive */ {
291 if (signChangeAtPrevious == SignChange.BECAME_ZERO) {
292 // we sent out a DELETE before and now the timeline is zero already starting at previous
293 // we need to cancel the effect of this with a INSERT
294 diffs.add(new Signed<>(Direction.INSERT, timestamp));
295 } else {
296 // this is normal, both previous and current was positive and stays positive
297 }
298
299 // remember for next timestamp
300 return SignChange.IRRELEVANT;
301 }
302 }
303 }
304 }
305
306 public Diff<Timestamp> put(final Tuple tuple, final Timestamp timestamp) {
307 if (this.isLazy) {
308 return putLazy(tuple, timestamp);
309 } else {
310 return putEager(tuple, timestamp);
311 }
312 }
313
314 public Diff<Timestamp> remove(final Tuple tuple, final Timestamp timestamp) {
315 if (this.isLazy) {
316 return removeLazy(tuple, timestamp);
317 } else {
318 return removeEager(tuple, timestamp);
319 }
320 }
321
322 protected Diff<Timestamp> putEager(final Tuple tuple, final Timestamp timestamp) {
323 final Diff<Timestamp> resultDiff = new Diff<>();
324 final CumulativeCounter counter = getCounter(tuple, timestamp);
325 ++counter.diff;
326
327 // before the INSERT timestamp, no change at all
328 // it cannot happen that those became positive in this round
329 SignChange signChangeAtPrevious = SignChange.IRRELEVANT;
330
331 final NavigableMap<Timestamp, CumulativeCounter> nextCounters = this.counters.get(tuple).tailMap(timestamp,
332 true);
333 for (final Entry<Timestamp, CumulativeCounter> currentEntry : nextCounters.entrySet()) {
334 final Timestamp currentTimestamp = currentEntry.getKey();
335 final CumulativeCounter currentCounter = currentEntry.getValue();
336 ++currentCounter.cumulative;
337 signChangeAtPrevious = computeDiffsEager(Direction.INSERT, currentCounter, signChangeAtPrevious,
338 currentTimestamp, resultDiff);
339 }
340
341 gcCounters(counter, tuple, timestamp);
342 updateTimeline(tuple, resultDiff);
343
344 return resultDiff;
345 }
346
347 protected Diff<Timestamp> putLazy(final Tuple tuple, final Timestamp timestamp) {
348 final CumulativeCounter counter = getCounter(tuple, timestamp);
349 counter.diff += 1;
350 // before the INSERT timestamp, no change at all
351 // it cannot happen that those became positive in this round
352 addFoldingState(tuple, new FoldingState(+1), timestamp);
353 return EMPTY_DIFF;
354 }
355
356 protected Diff<Timestamp> removeEager(final Tuple tuple, final Timestamp timestamp) {
357 final Diff<Timestamp> resultDiff = new Diff<>();
358 final CumulativeCounter counter = getCounter(tuple, timestamp);
359 --counter.diff;
360
361 // before the DELETE timestamp, no change at all
362 // it cannot happen that those became zero in this round
363 SignChange signChangeAtPrevious = SignChange.IRRELEVANT;
364
365 final NavigableMap<Timestamp, CumulativeCounter> nextCounters = this.counters.get(tuple).tailMap(timestamp,
366 true);
367 for (final Entry<Timestamp, CumulativeCounter> currentEntry : nextCounters.entrySet()) {
368 final Timestamp currentTimestamp = currentEntry.getKey();
369 final CumulativeCounter currentCounter = currentEntry.getValue();
370 --currentCounter.cumulative;
371 signChangeAtPrevious = computeDiffsEager(Direction.DELETE, currentCounter, signChangeAtPrevious,
372 currentTimestamp, resultDiff);
373 }
374
375 gcCounters(counter, tuple, timestamp);
376 updateTimeline(tuple, resultDiff);
377
378 return resultDiff;
379 }
380
381 protected Diff<Timestamp> removeLazy(final Tuple tuple, final Timestamp timestamp) {
382 final CumulativeCounter counter = getCounter(tuple, timestamp);
383 counter.diff -= 1;
384 // before the DELETE timestamp, no change at all
385 // it cannot happen that those became zero in this round
386 addFoldingState(tuple, new FoldingState(-1), timestamp);
387 return EMPTY_DIFF;
388 }
389
390 /**
391 * Updates and garbage collects the timeline of the given tuple based on the given timeline diff.
392 */
393 protected void updateTimeline(final Tuple tuple, final Diff<Timestamp> diff) {
394 if (!diff.isEmpty()) {
395 this.timelines.compute(tuple, (k, oldTimeline) -> {
396 this.presentAtInfinity.remove(tuple);
397 final Timeline<Timestamp> timeline = oldTimeline == null ? Timelines.createFrom(diff)
398 : oldTimeline.mergeAdditive(diff);
399 if (timeline.isPresentAtInfinity()) {
400 this.presentAtInfinity.add(tuple);
401 }
402 if (timeline.isEmpty()) {
403 return null;
404 } else {
405 return timeline;
406 }
407 });
408 }
409 }
410
411 /**
412 * @since 2.8
413 */
414 public Set<Tuple> getTuplesAtInfinity() {
415 return this.presentAtInfinity;
416 }
417
418 /**
419 * Returns the number of tuples that are present at the moment 'infinity'.
420 */
421 public int getCountAtInfinity() {
422 return this.presentAtInfinity.size();
423 }
424
425 /**
426 * Returns true if the given tuple is present at the moment 'infinity'.
427 */
428 public boolean isPresentAtInfinity(final Tuple tuple) {
429 final Timeline<Timestamp> timeline = this.timelines.get(tuple);
430 if (timeline == null) {
431 return false;
432 } else {
433 return timeline.isPresentAtInfinity();
434 }
435 }
436
437 public boolean isEmpty() {
438 return this.counters.isEmpty();
439 }
440
441 public int size() {
442 return this.counters.size();
443 }
444
445 public Set<Tuple> keySet() {
446 return this.counters.keySet();
447 }
448
449 public Map<Tuple, Timeline<Timestamp>> asMap() {
450 return this.timelines;
451 }
452
453 public Timeline<Timestamp> get(final ITuple tuple) {
454 return this.timelines.get(tuple);
455 }
456
457 @Override
458 public void clear() {
459 this.counters.clear();
460 this.timelines.clear();
461 if (this.foldingState != null) {
462 this.foldingState.clear();
463 }
464 }
465
466 public boolean containsKey(final ITuple tuple) {
467 return this.counters.containsKey(tuple);
468 }
469
470 @Override
471 public String toString() {
472 return this.counters + "\n" + this.timelines + "\n" + this.foldingState + "\n";
473 }
474
475 protected static final class CumulativeCounter {
476 protected int diff;
477 protected int cumulative;
478
479 protected CumulativeCounter(final int diff, final int cumulative) {
480 this.diff = diff;
481 this.cumulative = cumulative;
482 }
483
484 @Override
485 public String toString() {
486 return "{diff=" + this.diff + ", cumulative=" + this.cumulative + "}";
487 }
488
489 }
490
491 protected static final class FoldingState {
492 protected final int diff;
493
494 protected FoldingState(final int diff) {
495 this.diff = diff;
496 }
497
498 @Override
499 public String toString() {
500 return "{diff=" + this.diff + "}";
501 }
502
503 /**
504 * The returned result will never be null, even if the resulting diff is zero.
505 */
506 public FoldingState merge(final FoldingState that) {
507 Preconditions.checkArgument(that != null);
508 return new FoldingState(this.diff + that.diff);
509 }
510
511 }
512
513 protected enum SignChange {
514 BECAME_POSITIVE, BECAME_ZERO, IRRELEVANT;
515 }
516
517}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/MaskedResumable.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/MaskedResumable.java
new file mode 100644
index 00000000..ea70e61d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/MaskedResumable.java
@@ -0,0 +1,36 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util.resumable;
10
11import java.util.Map;
12
13import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
14import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
15
16/**
17 * A masked {@link Resumable} implementation, which maintains lazy folding per tuple signature.
18 *
19 * @author Tamas Szabo
20 * @since 2.4
21 */
22public interface MaskedResumable<Timestamp extends Comparable<Timestamp>> extends Resumable<Timestamp> {
23
24 /**
25 * When called, the folding of the state shall be resumed at the given timestamp. The resumable is expected to
26 * do a folding step at the given timestamp only. Afterwards, folding shall be interrupted, even if there is more
27 * folding to do towards higher timestamps.
28 */
29 public Map<Tuple, Map<Tuple, Diff<Timestamp>>> resumeAt(final Timestamp timestamp);
30
31 /**
32 * Returns the set of signatures for which lazy folding shall be resumed at the next timestamp.
33 */
34 public Iterable<Tuple> getResumableSignatures();
35
36}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/Resumable.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/Resumable.java
new file mode 100644
index 00000000..2861df20
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/Resumable.java
@@ -0,0 +1,27 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util.resumable;
10
11/**
12 * A resumable lazily folds its state towards higher timestamps. Folding shall be done in the increasing order of
13 * timestamps, and it shall be interrupted after each step. The resumable can then be instructed to resume the folding,
14 * one step at a time.
15 *
16 * @author Tamas Szabo
17 * @since 2.4
18 */
19public interface Resumable<Timestamp extends Comparable<Timestamp>> {
20
21 /**
22 * Returns the smallest timestamp where lazy folding shall be resumed, or null if there is no more folding to do in this
23 * resumable.
24 */
25 public Timestamp getResumableTimestamp();
26
27}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/UnmaskedResumable.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/UnmaskedResumable.java
new file mode 100644
index 00000000..1671940b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/UnmaskedResumable.java
@@ -0,0 +1,36 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util.resumable;
10
11import java.util.Map;
12
13import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
14import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
15
16/**
17 * A unmasked {@link Resumable} implementation, which maintains lazy folding without caring about tuple signatures.
18 *
19 * @author Tamas Szabo
20 * @since 2.4
21 */
22public interface UnmaskedResumable<Timestamp extends Comparable<Timestamp>> extends Resumable<Timestamp> {
23
24 /**
25 * When called, the folding of the state shall be resumed at the given timestamp. The resumable is expected to
26 * do a folding step at the given timestamp only. Afterwards, folding shall be interrupted, even if there is more
27 * folding to do towards higher timestamps.
28 */
29 public Map<Tuple, Diff<Timestamp>> resumeAt(final Timestamp timestamp);
30
31 /**
32 * Returns the set of tuples for which lazy folding shall be resumed at the next timestamp.
33 */
34 public Iterable<Tuple> getResumableTuples();
35
36}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/CompactTimeline.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/CompactTimeline.java
new file mode 100644
index 00000000..0532d094
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/CompactTimeline.java
@@ -0,0 +1,111 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, itemis AG, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util.timeline;
10
11import java.util.ArrayList;
12import java.util.Iterator;
13import java.util.List;
14
15import tools.refinery.viatra.runtime.matchers.util.Direction;
16import tools.refinery.viatra.runtime.matchers.util.Signed;
17
18/**
19 * A compact timeline may cosist of an arbitrary amount of moments.
20 * It is backed by an {@link ArrayList}.
21 *
22 * @author Tamas Szabo
23 * @since 2.4
24 */
25public class CompactTimeline<Timestamp extends Comparable<Timestamp>> extends Timeline<Timestamp> {
26
27 protected final List<Timestamp> elements;
28
29 CompactTimeline() {
30 this.elements = new ArrayList<>();
31 }
32
33 CompactTimeline(final Timestamp timestamp) {
34 this();
35 this.elements.add(timestamp);
36 }
37
38 CompactTimeline(final List<Timestamp> timestamps) {
39 this.elements = new ArrayList<>(timestamps.size());
40 this.elements.addAll(timestamps);
41 }
42
43 CompactTimeline(final Diff<Timestamp> diff) {
44 this.elements = new ArrayList<>(diff.size());
45 Direction expected = Direction.INSERT;
46 for (Signed<Timestamp> signed : diff) {
47 if (!expected.equals(signed.getDirection())) {
48 throw new IllegalStateException(String.format("Expected direction (%s) constraint violated! %s @%s",
49 expected, diff, signed.getPayload()));
50 }
51 this.elements.add(signed.getPayload());
52 expected = expected.opposite();
53 }
54 }
55
56 @Override
57 public Signed<Timestamp> getSigned(final int index) {
58 final Direction direction = index % 2 == 0 ? Direction.INSERT : Direction.DELETE;
59 return new Signed<>(direction, this.getUnsigned(index));
60 }
61
62 @Override
63 public Timestamp getUnsigned(final int index) {
64 if (this.elements.size() <= index) {
65 throw new IllegalArgumentException(
66 "Timeline size (" + this.size() + ") is smaller than requested index " + index + "!");
67 } else {
68 return this.elements.get(index);
69 }
70 }
71
72 @Override
73 public int size() {
74 return this.elements.size();
75 }
76
77 @Override
78 public boolean isPresentAtInfinity() {
79 // if it has an odd length, then it ends with "INSERT"
80 return this.size() % 2 == 1;
81 }
82
83 @Override
84 public Iterable<Signed<Timestamp>> asChangeSequence() {
85 Iterable<Timestamp> outer = this.elements;
86 return () -> {
87 final Iterator<Timestamp> itr = outer.iterator();
88 return new Iterator<Signed<Timestamp>>() {
89 Direction direction = Direction.INSERT;
90
91 @Override
92 public boolean hasNext() {
93 return itr.hasNext();
94 }
95
96 @Override
97 public Signed<Timestamp> next() {
98 final Signed<Timestamp> result = new Signed<Timestamp>(direction, itr.next());
99 direction = direction.opposite();
100 return result;
101 }
102 };
103 };
104 }
105
106 @Override
107 public boolean isEmpty() {
108 return this.elements.isEmpty();
109 }
110
111}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Diff.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Diff.java
new file mode 100644
index 00000000..cec6049e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Diff.java
@@ -0,0 +1,55 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, itemis AG, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util.timeline;
10
11import java.util.ArrayList;
12
13import tools.refinery.viatra.runtime.matchers.util.Signed;
14
15/**
16 * The description of a delta that specifies how a {@link Timeline} changes. It consists of {@link Signed} timestamps that
17 * depict the moments of insertions and deletions on the timeline.
18 *
19 * @author Tamas Szabo
20 * @since 2.4
21 * @param <Timestamp>
22 * the type representing the timestamps
23 */
24public class Diff<Timestamp extends Comparable<Timestamp>> extends ArrayList<Signed<Timestamp>> {
25
26 private static final long serialVersionUID = 3853460426655994160L;
27
28 public Diff() {
29
30 }
31
32 public void appendWithCancellation(Signed<Timestamp> item) {
33 if (this.isEmpty()) {
34 this.add(item);
35 } else {
36 final Signed<Timestamp> last = this.get(this.size() - 1);
37 final int lastMinusItem = last.getPayload().compareTo(item.getPayload());
38 if (lastMinusItem == 0) {
39 if (last.getDirection() != item.getDirection()) {
40 // cancellation
41 this.remove(this.size() - 1);
42 } else {
43 throw new IllegalStateException(
44 "Trying to insert or delete for the second time at the same timestamp! " + item);
45 }
46 } else if (lastMinusItem > 0) {
47 throw new IllegalStateException(
48 "Trying to append a timestamp that is smaller than the last one! " + last + " " + item);
49 } else {
50 this.add(item);
51 }
52 }
53 }
54
55} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/SingletonTimeline.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/SingletonTimeline.java
new file mode 100644
index 00000000..526a95f5
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/SingletonTimeline.java
@@ -0,0 +1,73 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, itemis AG, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util.timeline;
10
11import java.util.Collections;
12
13import tools.refinery.viatra.runtime.matchers.util.Direction;
14import tools.refinery.viatra.runtime.matchers.util.Signed;
15
16/**
17 * A timeline which solely consists of one timestamp value, representing a single insertion. Intuitively, a singleton
18 * timeline always represents a bump which starts at the given timestamp and lasts till plus infinity.
19 *
20 * @author Tamas Szabo
21 * @since 2.4
22 */
23public class SingletonTimeline<Timestamp extends Comparable<Timestamp>> extends Timeline<Timestamp> {
24
25 protected final Timestamp start;
26
27 SingletonTimeline(final Timestamp timestamp) {
28 this.start = timestamp;
29 }
30
31 SingletonTimeline(final Diff<Timestamp> diff) {
32 if (diff.size() != 1 || diff.get(0).getDirection() == Direction.DELETE) {
33 throw new IllegalArgumentException("There is only a single (insert) timestamp in the singleton timestamp!");
34 } else {
35 this.start = diff.get(0).getPayload();
36 }
37 }
38
39 @Override
40 public Signed<Timestamp> getSigned(final int index) {
41 return new Signed<>(Direction.INSERT, this.getUnsigned(index));
42 }
43
44 @Override
45 public Timestamp getUnsigned(final int index) {
46 if (index != 0) {
47 throw new IllegalArgumentException("There is only a single (insert) timestamp in the singleton timestamp!");
48 } else {
49 return this.start;
50 }
51 }
52
53 @Override
54 public int size() {
55 return 1;
56 }
57
58 @Override
59 public boolean isPresentAtInfinity() {
60 return true;
61 }
62
63 @Override
64 public Iterable<Signed<Timestamp>> asChangeSequence() {
65 return Collections.singletonList(this.getSigned(0));
66 }
67
68 @Override
69 public boolean isEmpty() {
70 return false;
71 }
72
73}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timeline.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timeline.java
new file mode 100644
index 00000000..9214536c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timeline.java
@@ -0,0 +1,146 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, itemis AG, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util.timeline;
10
11import java.util.ArrayList;
12import java.util.Iterator;
13import java.util.List;
14
15import tools.refinery.viatra.runtime.matchers.util.Direction;
16import tools.refinery.viatra.runtime.matchers.util.Signed;
17
18/**
19 * A timeline describes the life cycle of a piece of data (typically a tuple in a relation) as a sequence of moments.
20 * Even moments represent appearances, odd moments represent disappearances. A timeline is immutable, once created, it
21 * is not possible to extend it with further moments.
22 *
23 * @author Tamas Szabo
24 * @since 2.4
25 */
26public abstract class Timeline<Timestamp extends Comparable<Timestamp>> {
27
28 public abstract Iterable<Signed<Timestamp>> asChangeSequence();
29
30 public abstract boolean isPresentAtInfinity();
31
32 public abstract boolean isEmpty();
33
34 public abstract int size();
35
36 public abstract Signed<Timestamp> getSigned(final int index);
37
38 public abstract Timestamp getUnsigned(final int index);
39
40 public Timeline<Timestamp> mergeMultiplicative(final Timeline<Timestamp> that) {
41 final List<Timestamp> result = new ArrayList<>();
42 int thisIdx = 0, thatIdx = 0;
43 Timestamp thisNext = thisIdx < this.size() ? this.getUnsigned(thisIdx) : null;
44 Timestamp thatNext = thatIdx < that.size() ? that.getUnsigned(thatIdx) : null;
45
46 while (thisNext != null || thatNext != null) {
47 int thisMinusThat = 0;
48 if (thisNext != null && thatNext != null) {
49 thisMinusThat = thisNext.compareTo(thatNext);
50 }
51 if (thisNext == null || thisMinusThat > 0) {
52 if (thisIdx % 2 == 1) {
53 result.add(thatNext);
54 }
55 thatIdx++;
56 thatNext = thatIdx < that.size() ? that.getUnsigned(thatIdx) : null;
57 } else if (thatNext == null || thisMinusThat < 0) {
58 if (thatIdx % 2 == 1) {
59 result.add(thisNext);
60 }
61 thisIdx++;
62 thisNext = thisIdx < this.size() ? this.getUnsigned(thisIdx) : null;
63 } else {
64 if (thisIdx % 2 == thatIdx % 2) {
65 result.add(thisNext);
66 }
67 thisIdx++;
68 thatIdx++;
69 thatNext = thatIdx < that.size() ? that.getUnsigned(thatIdx) : null;
70 thisNext = thisIdx < this.size() ? this.getUnsigned(thisIdx) : null;
71 }
72 }
73
74 return Timelines.createFrom(result);
75 }
76
77 /**
78 * Merges this timeline with the given timestamp diff. The expectation is that the resulting timeline starts with an
79 * insertion. The logic is similar to a merge sort; we iterate side-by-side over the timeline and the diff. During
80 * the merge, cancellation can happen if at the same timestamp we observe different signs at the corresponding
81 * timeline and diff elements.
82 */
83 public Timeline<Timestamp> mergeAdditive(final Diff<Timestamp> diff) {
84 final Iterator<Signed<Timestamp>> thisItr = this.asChangeSequence().iterator();
85 final Iterator<Signed<Timestamp>> diffItr = diff.iterator();
86 final List<Timestamp> result = new ArrayList<>();
87 Direction expected = Direction.INSERT;
88 Signed<Timestamp> thisNext = thisItr.hasNext() ? thisItr.next() : null;
89 Signed<Timestamp> diffNext = diffItr.hasNext() ? diffItr.next() : null;
90
91 while (thisNext != null || diffNext != null) {
92 int thisMinusDiff = 0;
93 if (thisNext != null && diffNext != null) {
94 thisMinusDiff = thisNext.getPayload().compareTo(diffNext.getPayload());
95 }
96
97 if (thisNext == null || thisMinusDiff > 0) {
98 if (!expected.equals(diffNext.getDirection())) {
99 throw new IllegalStateException(
100 String.format("Expected direction (%s) constraint violated! %s %s @%s", expected, this,
101 diff, diffNext.getPayload()));
102 }
103 result.add(diffNext.getPayload());
104 diffNext = diffItr.hasNext() ? diffItr.next() : null;
105 expected = expected.opposite();
106 } else if (diffNext == null || thisMinusDiff < 0) {
107 if (!expected.equals(thisNext.getDirection())) {
108 throw new IllegalStateException(
109 String.format("Expected direction (%s) constraint violated! %s %s @%s", expected, this,
110 diff, thisNext.getPayload()));
111 }
112 result.add(thisNext.getPayload());
113 thisNext = thisItr.hasNext() ? thisItr.next() : null;
114 expected = expected.opposite();
115 } else {
116 // they cancel out each other
117 if (diffNext.getDirection().equals(thisNext.getDirection())) {
118 throw new IllegalStateException(String.format("Changes do not cancel out each other! %s %s @%s",
119 this, diff, thisNext.getPayload()));
120 }
121 diffNext = diffItr.hasNext() ? diffItr.next() : null;
122 thisNext = thisItr.hasNext() ? thisItr.next() : null;
123 }
124 }
125
126 return Timelines.createFrom(result);
127 }
128
129 @Override
130 public String toString() {
131 final StringBuilder builder = new StringBuilder();
132 builder.append("[");
133 boolean first = true;
134 for (final Signed<Timestamp> element : this.asChangeSequence()) {
135 if (first) {
136 first = false;
137 } else {
138 builder.append(", ");
139 }
140 builder.append(element.toString());
141 }
142 builder.append("]");
143 return builder.toString();
144 }
145
146}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timelines.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timelines.java
new file mode 100644
index 00000000..747fda15
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timelines.java
@@ -0,0 +1,46 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, itemis AG, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util.timeline;
10
11import java.util.List;
12
13/**
14 * Utility class for creating {@link Timeline}s.
15 * @author Tamas Szabo
16 * @since 2.4
17 */
18public final class Timelines<Timestamp extends Comparable<Timestamp>> {
19
20 public static <Timestamp extends Comparable<Timestamp>> Timeline<Timestamp> createEmpty() {
21 return new CompactTimeline<Timestamp>();
22 }
23
24 public static <Timestamp extends Comparable<Timestamp>> Timeline<Timestamp> createFrom(
25 final Diff<Timestamp> diffs) {
26 if (diffs.size() == 1) {
27 return new SingletonTimeline<Timestamp>(diffs);
28 } else {
29 return new CompactTimeline<Timestamp>(diffs);
30 }
31 }
32
33 public static <Timestamp extends Comparable<Timestamp>> Timeline<Timestamp> createFrom(
34 final List<Timestamp> timestamps) {
35 if (timestamps.size() == 1) {
36 return new SingletonTimeline<Timestamp>(timestamps.get(0));
37 } else {
38 return new CompactTimeline<Timestamp>(timestamps);
39 }
40 }
41
42 public static <Timestamp extends Comparable<Timestamp>> Timeline<Timestamp> createFrom(final Timestamp timestamp) {
43 return new SingletonTimeline<Timestamp>(timestamp);
44 }
45
46}