aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime-matchers/src/main
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-08-19 02:31:57 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-08-19 02:31:57 +0200
commit9adbb3d49899a87b3026c11cb4ba3ff77f4fb75b (patch)
treefad77963c1dc9028b0a767ac3ad69a174c8eb8c6 /subprojects/viatra-runtime-matchers/src/main
parentfeat: predicate semantics (diff)
downloadrefinery-9adbb3d49899a87b3026c11cb4ba3ff77f4fb75b.tar.gz
refinery-9adbb3d49899a87b3026c11cb4ba3ff77f4fb75b.tar.zst
refinery-9adbb3d49899a87b3026c11cb4ba3ff77f4fb75b.zip
chore: import VIATRA source
Make our modifications more maintainable by editing the source code directly instead of using reflection.
Diffstat (limited to 'subprojects/viatra-runtime-matchers/src/main')
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/ViatraQueryRuntimeException.java42
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/AverageAccumulator.java24
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleAverageOperator.java82
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleSumOperator.java62
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/ExtremumOperator.java135
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerAverageOperator.java82
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerSumOperator.java61
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongAverageOperator.java82
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongSumOperator.java61
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/avg.java39
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/count.java33
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/max.java44
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/min.java44
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/sum.java39
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/OrderedIterableMerge.java83
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFind.java214
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFindNodeProperty.java32
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/CommonQueryHintOptions.java36
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ICallDelegationStrategy.java89
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IMatcherCapability.java26
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackend.java68
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactory.java52
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactoryProvider.java46
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendHintProvider.java32
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryResultProvider.java202
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IUpdateable.java27
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryEvaluationHint.java241
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryHintOption.java122
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ResultProviderRequestor.java74
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryMetaContext.java69
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryRuntimeContext.java21
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IInputKey.java45
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IPosetComparator.java35
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryBackendContext.java49
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryCacheContext.java39
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryMetaContext.java98
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryResultProviderAccess.java31
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContext.java281
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContextListener.java27
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IndexingService.java36
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/InputKeyImplication.java103
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/BaseInputKeyWrapper.java55
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/JavaTransitiveInstancesKey.java165
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/surrogate/SurrogateQueryRegistry.java153
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/AbstractTrivialMaskedMemory.java58
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/DefaultMaskedTupleMemory.java127
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/IdentityMaskedTupleMemory.java77
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/MaskedTupleMemory.java385
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/NullaryMaskedTupleMemory.java85
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/UnaryMaskedTupleMemory.java143
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyMaskedMemory.java228
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyTrivialMaskedMemory.java100
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyDefaultMaskedTupleMemory.java98
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyIdentityMaskedTupleMemory.java106
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyNullaryMaskedTupleMemory.java108
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyUnaryMaskedTupleMemory.java133
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IOperationCompiler.java108
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IQueryPlannerStrategy.java29
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/QueryProcessingException.java102
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlan.java240
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlanFactory.java33
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/BuildHelper.java165
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/FunctionalDependencyHelper.java143
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/StatisticsHelper.java62
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/TypeHelper.java217
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PApply.java94
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PEnumerate.java76
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PJoin.java64
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/POperation.java52
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PProject.java109
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PStart.java90
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/BasePConstraint.java108
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/DeferredPConstraint.java31
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/EnumerablePConstraint.java59
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IExpressionEvaluator.java42
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IMultiQueryReference.java26
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IQueryReference.java33
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IRelationEvaluator.java47
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeConstraint.java65
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeInfoProviderConstraint.java28
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IValueProvider.java27
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/InitializablePQuery.java56
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/KeyedEnumerablePConstraint.java39
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PBody.java289
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PConstraint.java70
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PTraceable.java16
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PVariable.java203
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/TypeJudgement.java153
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/VariableDeferredPConstraint.java40
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AbstractMemorylessAggregationOperator.java31
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AggregatorType.java49
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/BoundAggregator.java61
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IAggregatorFactory.java40
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IMultisetAggregationOperator.java106
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/analysis/QueryAnalyzer.java194
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/PAnnotation.java94
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/ParameterReference.java30
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/AggregatorConstraint.java98
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/BaseTypeSafeConstraint.java99
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Equality.java96
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExportedParameter.java108
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExpressionEvaluation.java80
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Inequality.java151
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/NegativePatternCall.java52
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternCallBasedDeferred.java118
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternMatchCounter.java70
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/RelationEvaluation.java57
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/TypeFilterConstraint.java105
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/AbstractTransitiveClosure.java44
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryReflexiveTransitiveClosure.java57
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryTransitiveClosure.java33
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/Connectivity.java11
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/ConstantValue.java57
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/PositivePatternCall.java76
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/RepresentativeElectionConstraint.java43
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/TypeConstraint.java79
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/BasePQuery.java231
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PDisjunction.java104
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameter.java105
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameterDirection.java35
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PProblem.java68
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueries.java110
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQuery.java154
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueryHeader.java101
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PVisibility.java37
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/QueryInitializationException.java35
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/AbstractRewriterTraceSource.java53
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/ConstraintRemovalReason.java23
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/DefaultFlattenCallPredicate.java23
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/FlattenerCopier.java129
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IConstraintFilter.java48
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IDerivativeModificationReason.java19
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IFlattenCallPredicate.java50
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IPTraceableTraceProvider.java55
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IRewriterTraceCollector.java33
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IVariableRenamer.java59
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/MappingTraceCollector.java135
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NeverFlattenCallPredicate.java26
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NopTraceCollector.java68
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyCopier.java306
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyNormalizer.java310
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriter.java27
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriterCacher.java64
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PQueryFlattener.java253
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/RewriterException.java31
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/SurrogateQueryRewriter.java63
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/VariableMappingExpressionEvaluatorWrapper.java88
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/IStorageBackend.java53
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleLocalStorageBackend.java51
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleRuntimeContext.java132
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/TabularRuntimeContext.java119
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/AbstractIndexTable.java266
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DefaultIndexTable.java143
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DisjointUnionTable.java192
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/IIndexTable.java212
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableContext.java29
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterBinary.java53
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterGeneric.java52
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterUnary.java52
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleBinaryTable.java320
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleUnaryTable.java140
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/AbstractTuple.java136
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseFlatTuple.java20
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseLeftInheritanceTuple.java65
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple.java60
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple0.java46
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple1.java44
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple2.java51
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple3.java55
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple4.java59
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/IModifiableTuple.java27
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/ITuple.java64
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple.java172
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple1.java83
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple2.java73
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple3.java81
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple4.java88
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/MaskedTuple.java48
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuple.java69
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask.java560
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask0.java56
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMaskIdentity.java51
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleValueProvider.java48
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuples.java157
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileMaskedTuple.java50
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileModifiableMaskedTuple.java47
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileTuple.java47
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/Accuracy.java48
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/Clearable.java23
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/CollectionsFactory.java188
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/Direction.java61
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsBagMemory.java86
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsDeltaBag.java41
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsFactory.java159
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongMultiset.java150
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongSetMemory.java212
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiLookup.java226
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiset.java93
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsSetMemory.java94
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EmptyMemory.java93
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/ICache.java32
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IDeltaBag.java26
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemory.java81
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemoryView.java205
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookup.java216
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookupAbstract.java485
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiset.java30
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IProvider.java30
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/ISetMemory.java37
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/MapBackedMemoryView.java102
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/MarkedMemory.java21
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/MemoryViewBackedMapView.java117
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/Preconditions.java208
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/PurgableCache.java44
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/Sets.java90
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/Signed.java60
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonInstanceProvider.java29
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonMemoryView.java105
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/TimelyMemory.java517
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/MaskedResumable.java36
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/Resumable.java27
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/UnmaskedResumable.java36
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/CompactTimeline.java111
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Diff.java55
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/SingletonTimeline.java73
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timeline.java146
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timelines.java46
227 files changed, 21337 insertions, 0 deletions
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/ViatraQueryRuntimeException.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/ViatraQueryRuntimeException.java
new file mode 100644
index 00000000..83f6f766
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/AverageAccumulator.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/AverageAccumulator.java
new file mode 100644
index 00000000..2c09ede1
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleAverageOperator.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleAverageOperator.java
new file mode 100644
index 00000000..e8a26afd
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleSumOperator.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleSumOperator.java
new file mode 100644
index 00000000..744b0cd1
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/ExtremumOperator.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/ExtremumOperator.java
new file mode 100644
index 00000000..ee4ceeb8
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerAverageOperator.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerAverageOperator.java
new file mode 100644
index 00000000..bf422476
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerSumOperator.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerSumOperator.java
new file mode 100644
index 00000000..18584256
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongAverageOperator.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongAverageOperator.java
new file mode 100644
index 00000000..d56c9507
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongSumOperator.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongSumOperator.java
new file mode 100644
index 00000000..29ded090
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/avg.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/avg.java
new file mode 100644
index 00000000..c25678aa
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/count.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/count.java
new file mode 100644
index 00000000..8310a0ce
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/max.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/max.java
new file mode 100644
index 00000000..e0236223
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/min.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/min.java
new file mode 100644
index 00000000..6408c57b
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/sum.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/sum.java
new file mode 100644
index 00000000..69ff2e75
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/OrderedIterableMerge.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/OrderedIterableMerge.java
new file mode 100644
index 00000000..1917e909
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFind.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFind.java
new file mode 100644
index 00000000..c69f08e5
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFindNodeProperty.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFindNodeProperty.java
new file mode 100644
index 00000000..82852f9c
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/CommonQueryHintOptions.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/CommonQueryHintOptions.java
new file mode 100644
index 00000000..317293bf
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ICallDelegationStrategy.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ICallDelegationStrategy.java
new file mode 100644
index 00000000..40853f46
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IMatcherCapability.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IMatcherCapability.java
new file mode 100644
index 00000000..104b68a8
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackend.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackend.java
new file mode 100644
index 00000000..c85f10a4
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactory.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactory.java
new file mode 100644
index 00000000..e264ab3f
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactoryProvider.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactoryProvider.java
new file mode 100644
index 00000000..8787814e
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendHintProvider.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendHintProvider.java
new file mode 100644
index 00000000..9bb76349
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryResultProvider.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryResultProvider.java
new file mode 100644
index 00000000..cd7d050f
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IUpdateable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IUpdateable.java
new file mode 100644
index 00000000..baf7144a
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryEvaluationHint.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryEvaluationHint.java
new file mode 100644
index 00000000..eab92128
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryHintOption.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryHintOption.java
new file mode 100644
index 00000000..2c6bb4de
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ResultProviderRequestor.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ResultProviderRequestor.java
new file mode 100644
index 00000000..6ec6d53e
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryMetaContext.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryMetaContext.java
new file mode 100644
index 00000000..99611758
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryRuntimeContext.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryRuntimeContext.java
new file mode 100644
index 00000000..c797eff9
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IInputKey.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IInputKey.java
new file mode 100644
index 00000000..4dbcca88
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IPosetComparator.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IPosetComparator.java
new file mode 100644
index 00000000..e2d5bcee
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryBackendContext.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryBackendContext.java
new file mode 100644
index 00000000..04f00aaa
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryCacheContext.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryCacheContext.java
new file mode 100644
index 00000000..617207f6
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryMetaContext.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryMetaContext.java
new file mode 100644
index 00000000..4c22a3cb
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryResultProviderAccess.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryResultProviderAccess.java
new file mode 100644
index 00000000..7fecd01a
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContext.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContext.java
new file mode 100644
index 00000000..c2e90614
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContextListener.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContextListener.java
new file mode 100644
index 00000000..7be27d56
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IndexingService.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/IndexingService.java
new file mode 100644
index 00000000..8210765d
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/InputKeyImplication.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/InputKeyImplication.java
new file mode 100644
index 00000000..2a403810
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/BaseInputKeyWrapper.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/JavaTransitiveInstancesKey.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/context/surrogate/SurrogateQueryRegistry.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/AbstractTrivialMaskedMemory.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/AbstractTrivialMaskedMemory.java
new file mode 100644
index 00000000..66587f77
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/DefaultMaskedTupleMemory.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/DefaultMaskedTupleMemory.java
new file mode 100644
index 00000000..92081409
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/IdentityMaskedTupleMemory.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/IdentityMaskedTupleMemory.java
new file mode 100644
index 00000000..dc59daf5
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/MaskedTupleMemory.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/MaskedTupleMemory.java
new file mode 100644
index 00000000..62377624
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/NullaryMaskedTupleMemory.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/NullaryMaskedTupleMemory.java
new file mode 100644
index 00000000..7fa9e053
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/UnaryMaskedTupleMemory.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/UnaryMaskedTupleMemory.java
new file mode 100644
index 00000000..f34cc9e3
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyMaskedMemory.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyTrivialMaskedMemory.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyDefaultMaskedTupleMemory.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyIdentityMaskedTupleMemory.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyNullaryMaskedTupleMemory.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyUnaryMaskedTupleMemory.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IOperationCompiler.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IOperationCompiler.java
new file mode 100644
index 00000000..c9f4b305
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IQueryPlannerStrategy.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IQueryPlannerStrategy.java
new file mode 100644
index 00000000..6ce9d91b
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/QueryProcessingException.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/QueryProcessingException.java
new file mode 100644
index 00000000..501ddf73
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlan.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlan.java
new file mode 100644
index 00000000..1998df9d
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlanFactory.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlanFactory.java
new file mode 100644
index 00000000..d0df5fac
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/BuildHelper.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/FunctionalDependencyHelper.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/StatisticsHelper.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/TypeHelper.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PApply.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PEnumerate.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PJoin.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/POperation.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PProject.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PStart.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/BasePConstraint.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/BasePConstraint.java
new file mode 100644
index 00000000..eda4aa25
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/DeferredPConstraint.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/DeferredPConstraint.java
new file mode 100644
index 00000000..d2bf088c
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/EnumerablePConstraint.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/EnumerablePConstraint.java
new file mode 100644
index 00000000..9129aa47
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IExpressionEvaluator.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IExpressionEvaluator.java
new file mode 100644
index 00000000..686999f7
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IMultiQueryReference.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IMultiQueryReference.java
new file mode 100644
index 00000000..8f647c64
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IQueryReference.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IQueryReference.java
new file mode 100644
index 00000000..9ee05b39
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IRelationEvaluator.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IRelationEvaluator.java
new file mode 100644
index 00000000..e4c396d8
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeConstraint.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeConstraint.java
new file mode 100644
index 00000000..b72035a8
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeInfoProviderConstraint.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeInfoProviderConstraint.java
new file mode 100644
index 00000000..ff127d38
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IValueProvider.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IValueProvider.java
new file mode 100644
index 00000000..d959adc4
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/InitializablePQuery.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/InitializablePQuery.java
new file mode 100644
index 00000000..a82d12ec
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/KeyedEnumerablePConstraint.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/KeyedEnumerablePConstraint.java
new file mode 100644
index 00000000..91eea817
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PBody.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PBody.java
new file mode 100644
index 00000000..c38dc23a
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PConstraint.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PConstraint.java
new file mode 100644
index 00000000..ae2c4632
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PTraceable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PTraceable.java
new file mode 100644
index 00000000..f0241a9c
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PVariable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PVariable.java
new file mode 100644
index 00000000..b6ea4861
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/TypeJudgement.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/TypeJudgement.java
new file mode 100644
index 00000000..4447b225
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/VariableDeferredPConstraint.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/VariableDeferredPConstraint.java
new file mode 100644
index 00000000..8ea6bb93
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AbstractMemorylessAggregationOperator.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AggregatorType.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/BoundAggregator.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IAggregatorFactory.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IMultisetAggregationOperator.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/analysis/QueryAnalyzer.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/PAnnotation.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/ParameterReference.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/AggregatorConstraint.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/BaseTypeSafeConstraint.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Equality.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExportedParameter.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExpressionEvaluation.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Inequality.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/NegativePatternCall.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternCallBasedDeferred.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternMatchCounter.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/RelationEvaluation.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/TypeFilterConstraint.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/AbstractTransitiveClosure.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryReflexiveTransitiveClosure.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryTransitiveClosure.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/Connectivity.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/ConstantValue.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/PositivePatternCall.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/RepresentativeElectionConstraint.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/TypeConstraint.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/BasePQuery.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PDisjunction.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameter.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameterDirection.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PProblem.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueries.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQuery.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueryHeader.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PVisibility.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/QueryInitializationException.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/AbstractRewriterTraceSource.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/ConstraintRemovalReason.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/DefaultFlattenCallPredicate.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/FlattenerCopier.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IConstraintFilter.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IDerivativeModificationReason.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IFlattenCallPredicate.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IPTraceableTraceProvider.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IRewriterTraceCollector.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IVariableRenamer.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/MappingTraceCollector.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NeverFlattenCallPredicate.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NopTraceCollector.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyCopier.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyNormalizer.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriter.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriterCacher.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PQueryFlattener.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/RewriterException.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/SurrogateQueryRewriter.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/VariableMappingExpressionEvaluatorWrapper.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/IStorageBackend.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/IStorageBackend.java
new file mode 100644
index 00000000..16f40358
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/IStorageBackend.java
@@ -0,0 +1,53 @@
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.scopes;
10
11import tools.refinery.viatra.runtime.matchers.context.IInputKey;
12import tools.refinery.viatra.runtime.matchers.scopes.tables.ITableContext;
13import tools.refinery.viatra.runtime.matchers.scopes.tables.ITableWriterBinary;
14import tools.refinery.viatra.runtime.matchers.scopes.tables.ITableWriterUnary;
15
16/**
17 * An abstract storage backend that instantiates tables and coordinates transactions.
18 *
19 * <p><strong>EXPERIMENTAL</strong>. This class or interface has been added as
20 * part of a work in progress. There is no guarantee that this API will
21 * work or that it will remain the same.
22 *
23 * @author Gabor Bergmann
24 *
25 * @since 2.1
26 */
27public interface IStorageBackend {
28
29
30 /**
31 * Marks the beginning of a transaction.
32 * In transaction mode, table updates may be temporarily delayed ({@link tools.refinery.viatra.runtime.matchers.scopes.tables.IIndexTable} methods may return stale answers) for better performance.
33 */
34 void startTransaction();
35 /**
36 * Marks the end of a transaction.
37 * Any updates delayed during the transaction must now be flushed.
38 */
39 void finishTransaction();
40
41 /**
42 * Creates an index table for a simple value set.
43 * @param unique client promises to only insert a given tuple with multiplicity one
44 */
45 ITableWriterUnary.Table<Object> createUnaryTable(IInputKey key, ITableContext tableContext, boolean unique);
46 /**
47 * Creates an index table for a simple source-target bidirectional mapping.
48 * @param unique client promises to only insert a given tuple with multiplicity one
49 */
50 ITableWriterBinary.Table<Object,Object> createBinaryTable(IInputKey key, ITableContext tableContext, boolean unique);
51
52
53}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleLocalStorageBackend.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleLocalStorageBackend.java
new file mode 100644
index 00000000..fd1f7b7e
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleLocalStorageBackend.java
@@ -0,0 +1,51 @@
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.scopes;
10
11import tools.refinery.viatra.runtime.matchers.context.IInputKey;
12import tools.refinery.viatra.runtime.matchers.scopes.tables.ITableContext;
13import tools.refinery.viatra.runtime.matchers.scopes.tables.SimpleBinaryTable;
14import tools.refinery.viatra.runtime.matchers.scopes.tables.SimpleUnaryTable;
15
16/**
17 * Basic storage backend implementation based on local collections.
18 *
19 * <p><strong>EXPERIMENTAL</strong>. This class or interface has been added as
20 * part of a work in progress. There is no guarantee that this API will
21 * work or that it will remain the same.
22 *
23 * @author Gabor Bergmann
24 * @since 2.1
25 */
26public class SimpleLocalStorageBackend implements IStorageBackend {
27
28 @Override
29 public void startTransaction() {
30 // NOP
31 }
32
33 @Override
34 public void finishTransaction() {
35 // NOP
36 }
37
38 @Override
39 public SimpleUnaryTable<Object> createUnaryTable(IInputKey key, ITableContext tableContext, boolean unique) {
40 return new SimpleUnaryTable<>(key, tableContext, unique);
41 }
42
43 @Override
44 public SimpleBinaryTable<Object, Object> createBinaryTable(IInputKey key, ITableContext tableContext,
45 boolean unique) {
46 return new SimpleBinaryTable<>(key, tableContext, unique);
47 }
48
49
50
51}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleRuntimeContext.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleRuntimeContext.java
new file mode 100644
index 00000000..a3a827dc
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleRuntimeContext.java
@@ -0,0 +1,132 @@
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 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.scopes;
11
12import java.lang.reflect.InvocationTargetException;
13import java.util.concurrent.Callable;
14
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
16import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
17import tools.refinery.viatra.runtime.matchers.context.IndexingService;
18import tools.refinery.viatra.runtime.matchers.context.common.JavaTransitiveInstancesKey;
19import tools.refinery.viatra.runtime.matchers.scopes.tables.IIndexTable;
20import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
21import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
22
23/**
24 * A simple demo implementation of the IQRC interface using tables.
25 *
26 * <p>
27 * Usage: first, instantiate {@link IIndexTable} tables with this as the 'tableContext' argument, and call
28 * {@link #registerIndexTable(IIndexTable)} manually to register them. Afterwards, they will be visible to the query
29 * backends.
30 * <p>
31 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
32 * part of a work in progress. There is no guarantee that this API will
33 * work or that it will remain the same.
34 *
35 * @author Gabor Bergmann
36 * @since 2.0
37 */
38public class SimpleRuntimeContext extends TabularRuntimeContext {
39
40 private IQueryMetaContext metaContext;
41
42 public SimpleRuntimeContext(IQueryMetaContext metaContext) {
43 this.metaContext = metaContext;
44 }
45
46 @Override
47 public void logError(String message) {
48 System.err.println(message);
49 }
50
51 @Override
52 public IQueryMetaContext getMetaContext() {
53 return metaContext;
54 }
55
56 @Override
57 public <V> V coalesceTraversals(Callable<V> callable) throws InvocationTargetException {
58 try {
59 return callable.call();
60 } catch (Exception e) {
61 throw new InvocationTargetException(e);
62 }
63 }
64
65 @Override
66 public boolean isCoalescing() {
67 return false;
68 }
69
70 @Override
71 public boolean isIndexed(IInputKey key, IndexingService service) {
72 return peekIndexTable(key) != null;
73 }
74
75 @Override
76 public void ensureIndexed(IInputKey key, IndexingService service) {
77 if (peekIndexTable(key) == null)
78 throw new IllegalArgumentException(key.getPrettyPrintableName());
79 }
80
81 @Override
82 public Object wrapElement(Object externalElement) {
83 return externalElement;
84 }
85
86 @Override
87 public Object unwrapElement(Object internalElement) {
88 return internalElement;
89 }
90
91 @Override
92 public Tuple wrapTuple(Tuple externalElements) {
93 return externalElements;
94 }
95
96 @Override
97 public Tuple unwrapTuple(Tuple internalElements) {
98 return internalElements;
99 }
100
101 @Override
102 public void ensureWildcardIndexing(IndexingService service) {
103 throw new UnsupportedOperationException();
104 }
105
106 @Override
107 public void executeAfterTraversal(Runnable runnable) throws InvocationTargetException {
108 runnable.run();
109 }
110
111 @Override
112 protected boolean isContainedInStatelessKey(IInputKey key, ITuple seed) {
113 if (key instanceof JavaTransitiveInstancesKey) {
114 Class<?> instanceClass = forceGetWrapperInstanceClass((JavaTransitiveInstancesKey) key);
115 return instanceClass != null && instanceClass.isInstance(seed.get(0));
116 } else
117 throw new IllegalArgumentException(key.getPrettyPrintableName());
118 }
119
120 private Class<?> forceGetWrapperInstanceClass(JavaTransitiveInstancesKey key) {
121 Class<?> instanceClass;
122 try {
123 instanceClass = key.forceGetWrapperInstanceClass();
124 } catch (ClassNotFoundException e) {
125 logError(
126 "Could not load instance class for type constraint " + key.getWrappedKey() + ": " + e.getMessage());
127 instanceClass = null;
128 }
129 return instanceClass;
130 }
131
132}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/TabularRuntimeContext.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/TabularRuntimeContext.java
new file mode 100644
index 00000000..e99e24d3
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/TabularRuntimeContext.java
@@ -0,0 +1,119 @@
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 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.scopes;
11
12import java.util.Map;
13import java.util.Optional;
14
15import tools.refinery.viatra.runtime.matchers.context.AbstractQueryRuntimeContext;
16import tools.refinery.viatra.runtime.matchers.context.IInputKey;
17import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContextListener;
18import tools.refinery.viatra.runtime.matchers.scopes.tables.IIndexTable;
19import tools.refinery.viatra.runtime.matchers.scopes.tables.ITableContext;
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.Accuracy;
24import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
25
26/**
27 * An abstract runtime context that serves enumerable input key instances from tables.
28 *
29 * <p>
30 * Usage: first, instantiate {@link IIndexTable} tables with this as the 'tableContext' argument. Call
31 * {@link #registerIndexTable(IIndexTable)} to register them; this may happen either during a coalesced indexing, or on
32 * external initiation. Afterwards, they will be visible to the query backends.
33 * <p>
34 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
35 * part of a work in progress. There is no guarantee that this API will
36 * work or that it will remain the same.
37 *
38 * @author Gabor Bergmann
39 * @since 2.0
40 */
41public abstract class TabularRuntimeContext extends AbstractQueryRuntimeContext implements ITableContext {
42
43 private Map<IInputKey, IIndexTable> instanceTables = CollectionsFactory.createMap();
44
45 public void registerIndexTable(IIndexTable table) {
46 IInputKey inputKey = table.getInputKey();
47 instanceTables.put(inputKey, table);
48 }
49
50 /**
51 * @return null if the table is not registered
52 */
53 public IIndexTable peekIndexTable(IInputKey key) {
54 return instanceTables.get(key);
55 }
56
57 /**
58 * If the table is not registered, {@link #handleUnregisteredTableRequest(IInputKey)} is invoked; it may handle it
59 * by raising an error or e.g. on-demand index construction
60 */
61 public IIndexTable getIndexTable(IInputKey key) {
62 IIndexTable table = instanceTables.get(key);
63 if (table != null)
64 return table;
65 else
66 return handleUnregisteredTableRequest(key);
67 }
68
69 /**
70 * Override this to provide on-demand table registration
71 */
72 protected IIndexTable handleUnregisteredTableRequest(IInputKey key) {
73 throw new IllegalArgumentException(key.getPrettyPrintableName());
74 }
75
76 @Override
77 public int countTuples(IInputKey key, TupleMask seedMask, ITuple seed) {
78 return getIndexTable(key).countTuples(seedMask, seed);
79 }
80
81 @Override
82 public Optional<Long> estimateCardinality(IInputKey key, TupleMask groupMask, Accuracy requiredAccuracy) {
83 return getIndexTable(key).estimateProjectionSize(groupMask, requiredAccuracy);
84 }
85
86 @Override
87 public Iterable<Tuple> enumerateTuples(IInputKey key, TupleMask seedMask, ITuple seed) {
88 return getIndexTable(key).enumerateTuples(seedMask, seed);
89 }
90
91 @Override
92 public Iterable<? extends Object> enumerateValues(IInputKey key, TupleMask seedMask, ITuple seed) {
93 return getIndexTable(key).enumerateValues(seedMask, seed);
94 }
95
96 @Override
97 public boolean containsTuple(IInputKey key, ITuple seed) {
98 if (key.isEnumerable()) {
99 return getIndexTable(key).containsTuple(seed);
100 } else {
101 return isContainedInStatelessKey(key, seed);
102 }
103 }
104
105 @Override
106 public void addUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) {
107 getIndexTable(key).addUpdateListener(seed, listener);
108 }
109 @Override
110 public void removeUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) {
111 getIndexTable(key).removeUpdateListener(seed, listener);
112 }
113
114 /**
115 * Handles non-enumerable input keys that are not backed by a table
116 */
117 protected abstract boolean isContainedInStatelessKey(IInputKey key, ITuple seed);
118
119}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/AbstractIndexTable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/AbstractIndexTable.java
new file mode 100644
index 00000000..7b557c33
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/AbstractIndexTable.java
@@ -0,0 +1,266 @@
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.scopes.tables;
10
11import java.util.List;
12
13import tools.refinery.viatra.runtime.matchers.context.IInputKey;
14import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContextListener;
15import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
16import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
17import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
18import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
19import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
20import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
21
22/**
23 * <p>
24 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
25 * part of a work in progress. There is no guarantee that this API will
26 * work or that it will remain the same.
27 *
28 * @since 2.0
29 * @author Gabor Bergmann
30 */
31public abstract class AbstractIndexTable implements IIndexTable {
32
33 private IInputKey inputKey;
34 protected ITableContext tableContext;
35
36 protected final TupleMask emptyMask;
37 protected final Tuple emptyTuple;
38
39
40 public AbstractIndexTable(IInputKey inputKey, ITableContext tableContext) {
41 this.inputKey = inputKey;
42 this.tableContext = tableContext;
43
44 this.emptyMask = TupleMask.empty(getInputKey().getArity());
45 this.emptyTuple = Tuples.flatTupleOf(new Object[inputKey.getArity()]);
46 }
47
48 @Override
49 public String toString() {
50 return this.getClass().getSimpleName() + ":" + inputKey.getPrettyPrintableName();
51 }
52
53 @Override
54 public IInputKey getInputKey() {
55 return inputKey;
56 }
57
58 protected void logError(String message) {
59 tableContext.logError(message);
60 }
61
62
63 /// UPDATE HANDLING SECTION
64
65 // The entire mechanism is designed to accommodate a large number of update listeners,
66 // but maybe there will typically be only a single, universal (unseeded) listener?
67 // TODO Create special handling for that case.
68
69 // Invariant: true iff #listenerGroupsAndSeed is nonempty
70 protected boolean emitNotifications = false;
71 // Subscribed listeners grouped by their seed mask (e.g. all those that seed columns 2 and 5 are together),
72 // groups are stored in a list for quick delivery-time iteration (at the expense of adding / removing);
73 // individual listeners can be looked up based on their seed tuple
74 protected List<IListenersWithSameMask> listenerGroups = CollectionsFactory.createObserverList();
75
76
77 /**
78 * Implementors shall call this to deliver all notifications.
79 * Call may be conditioned to {@link #emitNotifications}
80 */
81 protected void deliverChangeNotifications(Tuple updateTuple, boolean isInsertion) {
82 for (IListenersWithSameMask listenersForSeed : listenerGroups) {
83 listenersForSeed.deliver(updateTuple, isInsertion);
84 }
85 }
86
87 @Override
88 public void addUpdateListener(Tuple seed, IQueryRuntimeContextListener listener) {
89 TupleMask seedMask;
90 if (seed == null) {
91 seed = emptyTuple;
92 seedMask = emptyMask;
93 } else {
94 seedMask = TupleMask.fromNonNullIndices(seed);
95 }
96 IListenersWithSameMask listenerGroup = getListenerGroup(seedMask);
97 if (listenerGroup == null) { // create new group
98 switch (seedMask.getSize()) {
99 case 0:
100 listenerGroup = new UniversalListeners();
101 break;
102 case 1:
103 listenerGroup = new ColumnBoundListeners(seedMask.indices[0]);
104 break;
105 default:
106 listenerGroup = new GenericBoundListeners(seedMask);
107 }
108 listenerGroups.add(listenerGroup);
109 emitNotifications = true;
110 }
111 listenerGroup.addUpdateListener(seed, listener);
112 }
113
114 @Override
115 public void removeUpdateListener(Tuple seed, IQueryRuntimeContextListener listener) {
116 TupleMask seedMask;
117 if (seed == null) {
118 seed = emptyTuple;
119 seedMask = emptyMask;
120 } else {
121 seedMask = TupleMask.fromNonNullIndices(seed);
122 }
123 IListenersWithSameMask listenerGroup = getListenerGroup(seedMask);
124 if (listenerGroup == null)
125 throw new IllegalStateException("no listener subscribed with mask" + seedMask);
126
127 if (listenerGroup.removeUpdateListener(seed, listener)) {
128 listenerGroups.remove(listenerGroup);
129 emitNotifications = !listenerGroups.isEmpty();
130 }
131 }
132
133 protected IListenersWithSameMask getListenerGroup(TupleMask seedMask) {
134 for (IListenersWithSameMask candidateGroup : listenerGroups) { // group already exists?
135 if (seedMask.equals(candidateGroup.getSeedMask())) {
136 return candidateGroup;
137 }
138 }
139 return null;
140 }
141
142
143 /**
144 * Represents all listeners subscribed to seeds with the given seed mask.
145 *
146 * @author Bergmann Gabor
147 */
148 protected static interface IListenersWithSameMask {
149
150 public TupleMask getSeedMask();
151
152 public void deliver(Tuple updateTuple, boolean isInsertion);
153
154 public void addUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener);
155 /**
156 * @return true if this was the last listener, and the {@link IListenersWithSameMask} can be disposed of.
157 */
158 public boolean removeUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener);
159 }
160 /**
161 * Listeners interested in all tuples
162 */
163 protected final class UniversalListeners implements IListenersWithSameMask {
164 private final TupleMask mask = TupleMask.empty(inputKey.getArity());
165 private List<IQueryRuntimeContextListener> listeners = CollectionsFactory.createObserverList();
166
167 @Override
168 public TupleMask getSeedMask() {
169 return mask;
170 }
171 @Override
172 public void deliver(Tuple updateTuple, boolean isInsertion) {
173 IInputKey key = inputKey;
174 for (IQueryRuntimeContextListener listener : listeners) {
175 listener.update(key, updateTuple, isInsertion);
176 }
177 }
178 @Override
179 public void addUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener) {
180 listeners.add(listener);
181 }
182 @Override
183 public boolean removeUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener) {
184 listeners.remove(listener);
185 return listeners.isEmpty();
186 }
187 }
188 /**
189 * Listeners interested in all tuples seeded by a single columns
190 */
191 protected final class ColumnBoundListeners implements IListenersWithSameMask {
192 private int seedPosition;
193 protected final TupleMask mask;
194 // indexed by projected seed tuple
195 protected IMultiLookup<Object,IQueryRuntimeContextListener> listeners =
196 CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, Object.class);
197
198 public ColumnBoundListeners(int seedPosition) {
199 this.seedPosition = seedPosition;
200 this.mask = TupleMask.selectSingle(seedPosition, inputKey.getArity());
201 }
202
203 @Override
204 public TupleMask getSeedMask() {
205 return mask;
206 }
207 @Override
208 public void deliver(Tuple updateTuple, boolean isInsertion) {
209 IInputKey key = inputKey;
210 Object projectedSeed = updateTuple.get(seedPosition);
211 for (IQueryRuntimeContextListener listener : listeners.lookupOrEmpty(projectedSeed)) {
212 listener.update(key, updateTuple, isInsertion);
213 }
214 }
215 @Override
216 public void addUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener) {
217 Object projectedSeed = originalSeed.get(seedPosition);
218 listeners.addPair(projectedSeed, listener);
219 }
220 @Override
221 public boolean removeUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener) {
222 Object projectedSeed = originalSeed.get(seedPosition);
223 listeners.removePair(projectedSeed, listener);
224 return listeners.countKeys() == 0;
225 }
226 }
227 /**
228 * Listeners interested in all tuples seeded by a tuple of values
229 */
230 protected final class GenericBoundListeners implements IListenersWithSameMask {
231 protected final TupleMask mask;
232 // indexed by projected seed tuple
233 protected IMultiLookup<Tuple,IQueryRuntimeContextListener> listeners =
234 CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, Object.class);
235
236 public GenericBoundListeners(TupleMask mask) {
237 this.mask = mask;
238 }
239
240 @Override
241 public TupleMask getSeedMask() {
242 return mask;
243 }
244 @Override
245 public void deliver(Tuple updateTuple, boolean isInsertion) {
246 IInputKey key = inputKey;
247 Tuple projectedSeed = mask.transform(updateTuple);
248 for (IQueryRuntimeContextListener listener : listeners.lookupOrEmpty(projectedSeed)) {
249 listener.update(key, updateTuple, isInsertion);
250 }
251 }
252 @Override
253 public void addUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener) {
254 Tuple projectedSeed = mask.transform(originalSeed);
255 listeners.addPair(projectedSeed, listener);
256 }
257 @Override
258 public boolean removeUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener) {
259 Tuple projectedSeed = mask.transform(originalSeed);
260 listeners.removePair(projectedSeed, listener);
261 return listeners.countKeys() == 0;
262 }
263 }
264
265
266} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DefaultIndexTable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DefaultIndexTable.java
new file mode 100644
index 00000000..39475d11
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DefaultIndexTable.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.scopes.tables;
10
11import java.util.Map;
12import java.util.Optional;
13import java.util.stream.Stream;
14
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
16import tools.refinery.viatra.runtime.matchers.memories.MaskedTupleMemory;
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.Accuracy;
21import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
22import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
23import tools.refinery.viatra.runtime.matchers.util.Direction;
24import tools.refinery.viatra.runtime.matchers.util.IMemory;
25
26/**
27 * Demo default implementation.
28 * <p>
29 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
30 * part of a work in progress. There is no guarantee that this API will
31 * work or that it will remain the same.
32 *
33 * @since 2.0
34 * @author Gabor Bergmann
35 */
36public class DefaultIndexTable extends AbstractIndexTable implements ITableWriterGeneric {
37
38 protected IMemory<Tuple> rows = CollectionsFactory.createMultiset(); // TODO use SetMemory if unique
39 protected Map<TupleMask, MaskedTupleMemory<?>> indexMemories = CollectionsFactory.createMap();
40 private boolean unique;
41
42 /**
43 * @param unique
44 * client promises to only insert a given tuple with multiplicity one
45 */
46 public DefaultIndexTable(IInputKey inputKey, ITableContext tableContext, boolean unique) {
47 super(inputKey, tableContext);
48 this.unique = unique;
49 }
50
51 @Override
52 public void write(Direction direction, Tuple row) {
53 if (direction == Direction.INSERT) {
54 boolean changed = rows.addOne(row);
55 if (unique && !changed) {
56 String msg = String.format(
57 "Error: trying to add duplicate row %s to the unique table %s. This indicates some errors in underlying model representation.",
58 row, getInputKey().getPrettyPrintableName());
59 logError(msg);
60 }
61 if (changed) {
62 for (MaskedTupleMemory<?> indexMemory : indexMemories.values()) {
63 indexMemory.add(row);
64 }
65 if (emitNotifications) {
66 deliverChangeNotifications(row, true);
67 }
68 }
69 } else { // DELETE
70 boolean changed = rows.removeOne(row);
71 if (unique && !changed) {
72 String msg = String.format(
73 "Error: trying to remove duplicate value %s from the unique table %s. This indicates some errors in underlying model representation.",
74 row, getInputKey().getPrettyPrintableName());
75 logError(msg);
76 }
77 if (changed) {
78 for (MaskedTupleMemory<?> indexMemory : indexMemories.values()) {
79 indexMemory.remove(row);
80 }
81 if (emitNotifications) {
82 deliverChangeNotifications(row, false);
83 }
84 }
85 }
86 }
87
88 @Override
89 public boolean containsTuple(ITuple seed) {
90 return rows.distinctValues().contains(seed);
91 }
92
93 private MaskedTupleMemory<?> getIndexMemory(TupleMask seedMask) {
94 return indexMemories.computeIfAbsent(seedMask, mask -> {
95 MaskedTupleMemory<?> memory = MaskedTupleMemory.create(seedMask, MemoryType.SETS, DefaultIndexTable.this);
96 for (Tuple tuple : rows.distinctValues()) {
97 memory.add(tuple);
98 }
99 return memory;
100 });
101 }
102
103 @Override
104 public int countTuples(TupleMask seedMask, ITuple seed) {
105 switch (seedMask.getSize()) {
106 case 0: // unseeded
107 return rows.size();
108 default:
109 return getIndexMemory(seedMask).getOrEmpty(seed).size();
110 }
111 }
112
113 @Override
114 public Optional<Long> estimateProjectionSize(TupleMask groupMask, Accuracy requiredAccuracy) {
115 // always exact count
116 if (groupMask.getSize() == 0) {
117 return rows.size() == 0 ? Optional.of(0L) : Optional.of(1L);
118 } else if (groupMask.getSize() == this.emptyTuple.getSize()) {
119 return Optional.of((long) rows.size());
120 } else {
121 return Optional.of((long)getIndexMemory(groupMask).getKeysetSize());
122 }
123 }
124
125 @Override
126 public Iterable<Tuple> enumerateTuples(TupleMask seedMask, ITuple seed) {
127 return getIndexMemory(seedMask).getOrEmpty(seed);
128 }
129
130 @Override
131 public Stream<? extends Tuple> streamTuples(TupleMask seedMask, ITuple seed) {
132 return getIndexMemory(seedMask).getOrEmpty(seed).stream();
133 }
134
135 @Override
136 public Stream<? extends Object> streamValues(TupleMask seedMask, ITuple seed) {
137 // we assume there is a single omitted index in the mask
138 int queriedColumn = seedMask.getFirstOmittedIndex().getAsInt();
139 return getIndexMemory(seedMask).getOrEmpty(seed).stream()
140 .map(row2 -> row2.get(queriedColumn));
141 }
142
143}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DisjointUnionTable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DisjointUnionTable.java
new file mode 100644
index 00000000..a3a65f14
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DisjointUnionTable.java
@@ -0,0 +1,192 @@
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 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.scopes.tables;
11
12import java.util.Collections;
13import java.util.List;
14import java.util.Objects;
15import java.util.Optional;
16import java.util.stream.Stream;
17
18import tools.refinery.viatra.runtime.matchers.context.IInputKey;
19import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContextListener;
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.tuple.Tuples;
24import tools.refinery.viatra.runtime.matchers.util.Accuracy;
25import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
26
27/**
28 * Disjoint union of the provided child tables.
29 *
30 * Used e.g. to present a transitive instance table as a view composed from direct instance tables.
31 * <p>
32 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
33 * part of a work in progress. There is no guarantee that this API will
34 * work or that it will remain the same.
35 *
36 * @since 2.0
37 * @author Gabor Bergmann
38 */
39public class DisjointUnionTable extends AbstractIndexTable {
40
41 protected List<IIndexTable> childTables = CollectionsFactory.createObserverList();
42
43 public DisjointUnionTable(IInputKey inputKey, ITableContext tableContext) {
44 super(inputKey, tableContext);
45 }
46
47 public List<IIndexTable> getChildTables() {
48 return Collections.unmodifiableList(childTables);
49 }
50
51 /**
52 * Precondition: the new child currently is, and will forever stay, disjoint from any other child tables.
53 */
54 public void addChildTable(IIndexTable child) {
55 if (getInputKey().getArity() != child.getInputKey().getArity())
56 throw new IllegalArgumentException(child.toString());
57
58 childTables.add(child);
59
60 if (emitNotifications) {
61 for (Tuple tuple : child.enumerateTuples(emptyMask, Tuples.staticArityFlatTupleOf())) {
62 deliverChangeNotifications(tuple, true);
63 }
64 }
65 }
66
67 @Override
68 public int countTuples(TupleMask seedMask, ITuple seed) {
69 int count = 0;
70 for (IIndexTable child : childTables) {
71 count += child.countTuples(seedMask, seed);
72 }
73 return count;
74 }
75
76
77 @Override
78 public Optional<Long> estimateProjectionSize(TupleMask groupMask, Accuracy requiredAccuracy) {
79 // exact results for trivial projections
80 if (groupMask.getSize() == 0) {
81 for (IIndexTable child : childTables) {
82 if (0 != child.countTuples(this.emptyMask, Tuples.staticArityFlatTupleOf()))
83 return Optional.of(1L);
84 }
85 return Optional.of(0L);
86 } else if (groupMask.getSize() == emptyTuple.getSize()) {
87 return Optional.of((long)countTuples(this.emptyMask, Tuples.staticArityFlatTupleOf()));
88 }
89 // summing child tables is an upper bound
90 if (Accuracy.BEST_UPPER_BOUND.atLeastAsPreciseAs(requiredAccuracy)) {
91 return Optional.of((long)countTuples(this.emptyMask, Tuples.staticArityFlatTupleOf()));
92 } else { // (Accuracy.BEST_LOWER_BOUND == requiredAccuracy)
93 //projections of child tables may coincide, but the largest one is still a lower bound
94 Optional<Long> maxProjection = Optional.empty();
95 for (IIndexTable child : childTables) {
96 Optional<Long> estimateOfChild = child.estimateProjectionSize(groupMask, requiredAccuracy);
97 if (estimateOfChild.isPresent()) {
98 maxProjection = Optional.of(Math.max(estimateOfChild.get(), maxProjection.orElse(0L)));
99 }
100 }
101 return maxProjection;
102 }
103 }
104
105 @Override
106 public Stream<? extends Tuple> streamTuples(TupleMask seedMask, ITuple seed) {
107 Stream<? extends Tuple> stream = Stream.empty();
108 for (IIndexTable child : childTables) {
109 Stream<? extends Tuple> childStream = child.streamTuples(seedMask, seed);
110 stream = Stream.concat(stream, childStream);
111 }
112 return stream;
113 }
114
115 @Override
116 public Stream<? extends Object> streamValues(TupleMask seedMask, ITuple seed) {
117 Stream<? extends Object> stream = Stream.empty();
118 for (IIndexTable child : childTables) {
119 Stream<? extends Object> childStream = child.streamValues(seedMask, seed);
120 stream = Stream.concat(stream, childStream);
121 }
122 return stream;
123 }
124
125 @Override
126 public boolean containsTuple(ITuple seed) {
127 for (IIndexTable child : childTables) {
128 if (child.containsTuple(seed))
129 return true;
130 }
131 return false;
132 }
133
134 @Override
135 public void addUpdateListener(Tuple seed, IQueryRuntimeContextListener listener) {
136 super.addUpdateListener(seed, listener);
137
138 for (IIndexTable table : childTables) {
139 table.addUpdateListener(seed, new ListenerWrapper(listener));
140 }
141 }
142 @Override
143 public void removeUpdateListener(Tuple seed, IQueryRuntimeContextListener listener) {
144 super.removeUpdateListener(seed, listener);
145
146 for (IIndexTable table : childTables) {
147 table.removeUpdateListener(seed, new ListenerWrapper(listener));
148 }
149 }
150
151
152 // TODO this would not be necessary
153 // if we moved from IQRCL to an interface that does not expose the input key
154 private class ListenerWrapper implements IQueryRuntimeContextListener {
155
156 private IQueryRuntimeContextListener wrappedListener;
157 public ListenerWrapper(IQueryRuntimeContextListener wrappedListener) {
158 this.wrappedListener = wrappedListener;
159 }
160
161 @Override
162 public void update(IInputKey key, Tuple updateTuple, boolean isInsertion) {
163 wrappedListener.update(getInputKey(), updateTuple, isInsertion);
164 }
165
166 @Override
167 public int hashCode() {
168 return Objects.hash(wrappedListener, DisjointUnionTable.this);
169 }
170 @Override
171 public boolean equals(Object obj) {
172 if (this == obj)
173 return true;
174 if (obj == null)
175 return false;
176 if (getClass() != obj.getClass())
177 return false;
178 ListenerWrapper other = (ListenerWrapper) obj;
179 if (!getOuterType().equals(other.getOuterType()))
180 return false;
181 return Objects.equals(wrappedListener, other.wrappedListener);
182 }
183 private DisjointUnionTable getOuterType() {
184 return DisjointUnionTable.this;
185 }
186 @Override
187 public String toString() {
188 return "Wrapper to DisjointUnion("+getInputKey().getPrettyPrintableName()+") for " + wrappedListener;
189 }
190 }
191
192}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/IIndexTable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/IIndexTable.java
new file mode 100644
index 00000000..be375393
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/IIndexTable.java
@@ -0,0 +1,212 @@
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.scopes.tables;
10
11import java.util.Iterator;
12import java.util.Optional;
13import java.util.stream.Stream;
14
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
16import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
17import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
18import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContextListener;
19import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
20import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
21import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
22import tools.refinery.viatra.runtime.matchers.util.Accuracy;
23
24/**
25 * Read-only interface that provides the {@link IInputKey}-specific slice of an instance store to realize a
26 * {@link IQueryRuntimeContext}. Implemented by a customizable data store that is responsible for:
27 * <ul>
28 * <li>storing the instance tuples of the {@link IInputKey},</li>
29 * <li>providing efficient lookup via storage-specific indexing,</li>
30 * <li>delivering notifications. (TODO not designed yet)</li>
31 * </ul>
32 *
33 * <p>
34 * Can be specialized for unary / binary / etc., opposite edges or node subtypes, specific types, distributed storage,
35 * etc.
36 * <p>
37 * Writeable API is specific to the customized implementations (e.g. unary).
38 *
39 * <p>
40 * <b>Precondition:</b> the associated input key is enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
41 * <p>
42 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
43 * part of a work in progress. There is no guarantee that this API will
44 * work or that it will remain the same.
45 *
46 * @since 2.0
47 * @author Gabor Bergmann
48 * @noimplement This interface is not intended to be implemented directly. Extend {@link AbstractIndexTable} instead.
49 */
50public interface IIndexTable {
51
52 // TODO add superinterface that represents a statistics-only counter?
53
54 /**
55 * @return the input key indexed by this table
56 */
57 public IInputKey getInputKey();
58
59 /**
60 * Returns the tuples, optionally seeded with the given tuple.
61 *
62 * <p> Consider using the more idiomatic {@link #streamTuples(TupleMask, ITuple)} instead.
63 *
64 * @param seedMask
65 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
66 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most
67 * once in seedMask.
68 * @param seed
69 * the tuple of fixed values restricting the row set to be considered, in the same order as given in
70 * parameterSeedMask, so that for each considered row tuple,
71 * projectedParameterSeed.equals(parameterSeedMask.transform(row)) should hold. Must not be null.
72 * @return the tuples in the table for the given key and seed
73 */
74 @SuppressWarnings("unchecked")
75 public default Iterable<Tuple> enumerateTuples(TupleMask seedMask, ITuple seed) {
76 return () -> (Iterator<Tuple>) (streamTuples(seedMask, seed).iterator());
77 }
78
79 /**
80 * Returns the tuples, optionally seeded with the given tuple.
81 *
82 * @param seedMask
83 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
84 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most
85 * once in seedMask.
86 * @param seed
87 * the tuple of fixed values restricting the row set to be considered, in the same order as given in
88 * parameterSeedMask, so that for each considered row tuple,
89 * projectedParameterSeed.equals(parameterSeedMask.transform(row)) should hold. Must not be null.
90 * @return the tuples in the table for the given key and seed
91 * @since 2.1
92 */
93 public Stream<? extends Tuple> streamTuples(TupleMask seedMask, ITuple seed);
94
95 /**
96 * Simpler form of {@link #enumerateTuples(TupleMask, ITuple)} in the case where all values of the tuples are bound
97 * by the seed except for one.
98 *
99 * <p>
100 * Selects the tuples in the table, optionally seeded with the given tuple, and then returns the single value from
101 * each tuple which is not bound by the seed mask.
102 *
103 * <p> Consider using the more idiomatic {@link #streamValues(TupleMask, ITuple)} instead.
104 *
105 * @param seedMask
106 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
107 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most
108 * once in seedMask, and seedMask must include all parameters in any arbitrary order except one.
109 * @param seed
110 * the tuple of fixed values restricting the row set to be considered, in the same order as given in
111 * parameterSeedMask, so that for each considered row tuple,
112 * projectedParameterSeed.equals(parameterSeedMask.transform(row)) should hold. Must not be null.
113 * @return the objects in the table for the given key and seed
114 *
115 */
116 @SuppressWarnings("unchecked")
117 public default Iterable<? extends Object> enumerateValues(TupleMask seedMask, ITuple seed) {
118 return () -> (Iterator<Object>) (streamValues(seedMask, seed).iterator());
119 }
120
121 /**
122 * Simpler form of {@link #enumerateTuples(TupleMask, ITuple)} in the case where all values of the tuples are bound
123 * by the seed except for one.
124 *
125 * <p>
126 * Selects the tuples in the table, optionally seeded with the given tuple, and then returns the single value from
127 * each tuple which is not bound by the seed mask.
128 *
129 * @param seedMask
130 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
131 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most
132 * once in seedMask, and seedMask must include all parameters in any arbitrary order except one.
133 * @param seed
134 * the tuple of fixed values restricting the row set to be considered, in the same order as given in
135 * parameterSeedMask, so that for each considered row tuple,
136 * projectedParameterSeed.equals(parameterSeedMask.transform(row)) should hold. Must not be null.
137 * @return the objects in the table for the given key and seed
138 *
139 * @since 2.1
140 */
141 public Stream<? extends Object> streamValues(TupleMask seedMask, ITuple seed);
142
143 /**
144 * Simpler form of {@link #enumerateTuples(TupleMask, ITuple)} in the case where all values of the tuples are bound
145 * by the seed.
146 *
147 * <p>
148 * Returns whether the given tuple is in the table identified by the input key.
149 *
150 * @param seed
151 * a row tuple of fixed values whose presence in the table is queried
152 * @return true iff there is a row tuple contained in the table that corresponds to the given seed
153 */
154 public boolean containsTuple(ITuple seed);
155
156 /**
157 * Returns the number of tuples, optionally seeded with the given tuple.
158 *
159 * <p>
160 * Selects the tuples in the table, optionally seeded with the given tuple, and then returns their number.
161 *
162 * @param seedMask
163 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
164 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most
165 * once in seedMask.
166 * @param seed
167 * the tuple of fixed values restricting the row set to be considered, in the same order as given in
168 * parameterSeedMask, so that for each considered row tuple,
169 * projectedParameterSeed.equals(parameterSeedMask.transform(row)) should hold. Must not be null.
170 * @return the number of tuples in the table for the given key and seed
171 *
172 */
173 public int countTuples(TupleMask seedMask, ITuple seed);
174
175 /**
176 * Gives an estimate of the number of different groups the tuples of the table are projected into by the given mask
177 * (e.g. for an identity mask, this means the full relation size). The estimate must meet the required accuracy.
178 *
179 * <p> Derived tables may return {@link Optional#empty()} if it would be costly to provide an answer up to the required precision.
180 * Direct storage tables are expected to always be able to give an exact count.
181 *
182 * <p> PRE: {@link TupleMask#isNonrepeating()} must hold for the group mask.
183 *
184 * @since 2.1
185 */
186 public Optional<Long> estimateProjectionSize(TupleMask groupMask, Accuracy requiredAccuracy);
187
188 /**
189 * Subscribes for updates in the table, optionally seeded with the given tuple.
190 * <p> This should be called after initializing a result cache by an enumeration method.
191 *
192 * @param seed can be null or a tuple with matching arity;
193 * if non-null, notifications will delivered only about those updates of the table
194 * that match the seed at positions where the seed is non-null.
195 * @param listener will be notified of future changes
196 *
197 * @since 2.1
198 */
199 public void addUpdateListener(Tuple seed, IQueryRuntimeContextListener listener);
200
201 /**
202 * Unsubscribes from updates in the table, optionally seeded with the given tuple.
203 *
204 * @param seed can be null or a tuple with matching arity;
205 * see {@link #addUpdateListener(Tuple, IQueryRuntimeContextListener)} for definition.
206 * @param listener will no longer be notified of future changes
207 *
208 * @since 2.1
209 */
210 public void removeUpdateListener(Tuple seed, IQueryRuntimeContextListener listener);
211
212}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableContext.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableContext.java
new file mode 100644
index 00000000..69e83cd7
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableContext.java
@@ -0,0 +1,29 @@
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.scopes.tables;
10
11/**
12 * Callbacks that {@link IIndexTable} implementations are expected to invoke on their environment.
13 * <p>
14 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
15 * part of a work in progress. There is no guarantee that this API will
16 * work or that it will remain the same.
17 *
18 * @since 2.0
19 * @author Gabor Bergmann
20 */
21public interface ITableContext {
22
23 // TODO notifications?
24
25 /**
26 * Indicates that an error has occurred in maintaining an index table, e.g. duplicate value.
27 */
28 public void logError(String message);
29}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterBinary.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterBinary.java
new file mode 100644
index 00000000..fb614014
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterBinary.java
@@ -0,0 +1,53 @@
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 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.scopes.tables;
11
12import tools.refinery.viatra.runtime.matchers.util.Direction;
13
14/**
15 * Modifies the contents of a binary {@link IIndexTable}.
16 * <p>
17 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
18 * part of a work in progress. There is no guarantee that this API will
19 * work or that it will remain the same.
20 *
21 * @since 2.0
22 * @author Gabor Bergmann
23 */
24public interface ITableWriterBinary<Source, Target> {
25 /**
26 * Adds/removes a row to/from the table.
27 *
28 * @param direction
29 * tells whether putting a row into the table or deleting
30 *
31 * TODO: store as multiset, return bool?
32 */
33 void write(Direction direction, Source source, Target target);
34
35 /**
36 * Intersection type for writers that are also tables
37 */
38 interface Table<Source, Target> extends ITableWriterBinary<Source, Target>, IIndexTable {
39 }
40
41 /**
42 * /dev/null implementation
43 *
44 * @author Gabor Bergmann
45 */
46 static class Nop<Source, Target> implements ITableWriterBinary<Source, Target> {
47 @Override
48 public void write(Direction direction, Source source, Target target) {
49 // NO-OP
50 }
51
52 }
53}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterGeneric.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterGeneric.java
new file mode 100644
index 00000000..fb1ebcc0
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterGeneric.java
@@ -0,0 +1,52 @@
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.scopes.tables;
10
11import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
12import tools.refinery.viatra.runtime.matchers.util.Direction;
13
14/**
15 * Modifies the contents of an {@link IIndexTable}.
16 * <p>
17 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
18 * part of a work in progress. There is no guarantee that this API will
19 * work or that it will remain the same.
20 *
21 * @since 2.0
22 * @author Gabor Bergmann
23 */
24public interface ITableWriterGeneric {
25
26 /**
27 * Adds/removes a row to/from the table.
28 *
29 * @param direction
30 * tells whether putting a row into the table or deleting TODO: store as multiset, return bool?
31 */
32 void write(Direction direction, Tuple row);
33
34 /**
35 * Intersection type for writers that are also tables
36 */
37 interface Table extends ITableWriterGeneric, IIndexTable {
38 }
39
40 /**
41 * /dev/null implementation
42 *
43 * @author Gabor Bergmann
44 */
45 static class Nop implements ITableWriterGeneric {
46 @Override
47 public void write(Direction direction, Tuple row) {
48 // NO-OP
49 }
50
51 }
52}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterUnary.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterUnary.java
new file mode 100644
index 00000000..f90d5362
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterUnary.java
@@ -0,0 +1,52 @@
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 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.scopes.tables;
11
12import tools.refinery.viatra.runtime.matchers.util.Direction;
13
14/**
15 * Modifies the contents of a unary {@link IIndexTable}.
16 * <p>
17 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
18 * part of a work in progress. There is no guarantee that this API will
19 * work or that it will remain the same.
20 *
21 * @since 2.0
22 * @author Gabor Bergmann
23 *
24 */
25public interface ITableWriterUnary<Value> {
26
27 /**
28 * Adds/removes a row to/from the table.
29 *
30 * @param direction
31 * tells whether putting a row into the table or deleting TODO: store as multiset, return bool?
32 */
33 void write(Direction direction, Value value);
34
35 /**
36 * Intersection type for writers that are also tables
37 */
38 interface Table<Value> extends ITableWriterUnary<Value>, IIndexTable {
39 }
40
41 /**
42 * /dev/null implementation
43 *
44 * @author Gabor Bergmann
45 */
46 static class Nop<Value> implements ITableWriterUnary<Value> {
47 @Override
48 public void write(Direction direction, Value value) {
49 // NO-OP
50 }
51 }
52}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleBinaryTable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleBinaryTable.java
new file mode 100644
index 00000000..588ed9d2
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleBinaryTable.java
@@ -0,0 +1,320 @@
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.scopes.tables;
10
11import java.util.Collections;
12import java.util.Optional;
13import java.util.Set;
14import java.util.stream.Stream;
15
16import tools.refinery.viatra.runtime.matchers.context.IInputKey;
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.Accuracy;
22import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
23import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
24import tools.refinery.viatra.runtime.matchers.util.Direction;
25import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
26import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
27import tools.refinery.viatra.runtime.matchers.util.IMultiLookup.ChangeGranularity;
28
29/**
30 * Simple source-target bidirectional mapping.
31 *
32 * <p>
33 * TODO: specialize for to-one features and unique to-many features
34 * <p>
35 * TODO: on-demand construction of valueToHolderMap
36 * <p>
37 * TODO: support for lean indexing, opposites, long surrogate ids, etc.
38 * <p>
39 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
40 * part of a work in progress. There is no guarantee that this API will
41 * work or that it will remain the same.
42 *
43 * @since 2.0
44 * @author Gabor Bergmann
45 */
46public class SimpleBinaryTable<Source, Target> extends AbstractIndexTable
47 implements ITableWriterBinary.Table<Source, Target> {
48
49 /**
50 * value -> holder(s)
51 * <p>
52 * this is currently the primary store, may hold duplicates depending on the unique parameter
53 */
54 private IMultiLookup<Target, Source> valueToHolderMap;
55 /**
56 * holder -> value(s); constructed on-demand, null if unused
57 */
58 private IMultiLookup<Source, Target> holderToValueMap;
59 private int totalRowCount = 0;
60 private boolean unique;
61
62 /**
63 * @param unique
64 * client promises to only insert a given tuple with multiplicity one
65 */
66 public SimpleBinaryTable(IInputKey inputKey, ITableContext tableContext, boolean unique) {
67 super(inputKey, tableContext);
68 this.unique = unique;
69 valueToHolderMap = CollectionsFactory.createMultiLookup(Object.class,
70 unique ? MemoryType.SETS : MemoryType.MULTISETS, Object.class);
71 if (2 != inputKey.getArity())
72 throw new IllegalArgumentException(inputKey.toString());
73 }
74
75 @Override
76 public void write(Direction direction, Source holder, Target value) {
77 if (direction == Direction.INSERT) {
78 try {
79 // TODO we currently assume V2H map exists
80 boolean changed = addToValueToHolderMap(value, holder);
81 if (holderToValueMap != null) {
82 addToHolderToValueMap(value, holder);
83 }
84 if (changed) {
85 totalRowCount++;
86 if (emitNotifications) {
87 deliverChangeNotifications(Tuples.staticArityFlatTupleOf(holder, value), true);
88 }
89 }
90 } catch (IllegalStateException ex) { // if unique table and duplicate tuple
91 String msg = String.format(
92 "Error: trying to add duplicate value %s to the unique feature %s of host object %s. This indicates some errors in underlying model representation.",
93 value, getInputKey().getPrettyPrintableName(), holder);
94 logError(msg);
95 }
96 } else { // DELETE
97 try {
98 // TODO we currently assume V2H map exists
99 boolean changed = removeFromValueToHolderMap(value, holder);
100 if (holderToValueMap != null) {
101 removeFromHolderToValueMap(value, holder);
102 }
103 if (changed) {
104 totalRowCount--;
105 if (emitNotifications) {
106 deliverChangeNotifications(Tuples.staticArityFlatTupleOf(holder, value), false);
107 }
108 }
109 } catch (IllegalStateException ex) { // if unique table and duplicate tuple
110 String msg = String.format(
111 "Error: trying to remove non-existing value %s from the feature %s of host object %s. This indicates some errors in underlying model representation.",
112 value, getInputKey().getPrettyPrintableName(), holder);
113 logError(msg);
114 }
115 }
116 }
117
118 private boolean addToHolderToValueMap(Target value, Source holder) {
119 return ChangeGranularity.DUPLICATE != holderToValueMap.addPair(holder, value);
120 }
121
122 private boolean addToValueToHolderMap(Target value, Source holder) {
123 return ChangeGranularity.DUPLICATE != valueToHolderMap.addPair(value, holder);
124 }
125
126 /**
127 * @throws IllegalStateException
128 */
129 private boolean removeFromHolderToValueMap(Target value, Source holder) {
130 return ChangeGranularity.DUPLICATE != holderToValueMap.removePair(holder, value);
131 }
132
133 /**
134 * @throws IllegalStateException
135 */
136 private boolean removeFromValueToHolderMap(Target value, Source holder) {
137 return ChangeGranularity.DUPLICATE != valueToHolderMap.removePair(value, holder);
138 }
139
140 @SuppressWarnings("unchecked")
141 @Override
142 public int countTuples(TupleMask seedMask, ITuple seed) {
143 switch (seedMask.getSize()) {
144 case 0: // unseeded
145 // TODO we currently assume V2H map exists
146 return totalRowCount;
147 case 1: // lookup by source or target
148 int seedIndex = seedMask.indices[0];
149 if (seedIndex == 0) { // lookup by source
150 Source source = (Source) seed.get(0);
151 return getDistinctValuesOfHolder(source).size();
152 } else if (seedIndex == 1) { // lookup by target
153 Target target = (Target) seed.get(0);
154 return getDistinctHoldersOfValue(target).size();
155 } else
156 throw new IllegalArgumentException(seedMask.toString());
157 case 2: // containment check
158 // hack: if mask is not identity, then it is [1,0]/2, which is its own inverse
159 Source source = (Source) seedMask.getValue(seed, 0);
160 Target target = (Target) seedMask.getValue(seed, 1);
161 if (containsRow(source, target))
162 return 1;
163 else
164 return 0;
165 default:
166 throw new IllegalArgumentException(seedMask.toString());
167 }
168 }
169
170 @Override
171 public Optional<Long> estimateProjectionSize(TupleMask groupMask, Accuracy requiredAccuracy) {
172 // always exact count
173 if (groupMask.getSize() == 0) {
174 return totalRowCount == 0 ? Optional.of(0L) : Optional.of(1L);
175 } else if (groupMask.getSize() == 2) {
176 return Optional.of((long)totalRowCount);
177 } else if (groupMask.indices[0] == 0) { // project to holder
178 return Optional.of((long)getHolderToValueMap().countKeys());
179 } else { // (groupMask.indices[0] == 0) // project to value
180 return Optional.of((long)getValueToHolderMap().countKeys());
181 }
182 }
183
184 @Override
185 public Stream<? extends Tuple> streamTuples(TupleMask seedMask, ITuple seed) {
186 switch (seedMask.getSize()) {
187 case 0: // unseeded
188 // TODO we currently assume V2H map exists
189 return getAllDistinctValuesStream()
190 .flatMap(value -> valueToHolderMap.lookup(value).distinctValues().stream()
191 .map(source -> Tuples.staticArityFlatTupleOf(source, value)));
192
193 case 1: // lookup by source or target
194 int seedIndex = seedMask.indices[0];
195 if (seedIndex == 0) { // lookup by source
196 @SuppressWarnings("unchecked")
197 Source source = (Source) seed.get(0);
198 return getDistinctValuesOfHolder(source).stream()
199 .map(target -> Tuples.staticArityFlatTupleOf(source, target));
200 } else if (seedIndex == 1) { // lookup by target
201 @SuppressWarnings("unchecked")
202 Target target = (Target) seed.get(0);
203 return getDistinctHoldersOfValue(target).stream()
204 .map(source -> Tuples.staticArityFlatTupleOf(source, target));
205 } else
206 throw new IllegalArgumentException(seedMask.toString());
207 case 2: // containment check
208 // hack: if mask is not identity, then it is [1,0]/2, which is its own inverse
209 @SuppressWarnings("unchecked")
210 Source source = (Source) seedMask.getValue(seed, 0);
211 @SuppressWarnings("unchecked")
212 Target target = (Target) seedMask.getValue(seed, 1);
213
214 if (containsRow(source, target))
215 return Stream.of(Tuples.staticArityFlatTupleOf(source, target));
216 else
217 return Stream.empty();
218 default:
219 throw new IllegalArgumentException(seedMask.toString());
220 }
221 }
222
223 @Override
224 @SuppressWarnings("unchecked")
225 public Iterable<? extends Object> enumerateValues(TupleMask seedMask, ITuple seed) {
226 if (seedMask.getSize() != 1)
227 throw new IllegalArgumentException(seedMask.toString());
228
229 int seedIndex = seedMask.indices[0];
230 if (seedIndex == 0) { // lookup by source
231 return getDistinctValuesOfHolder((Source) seed.get(0));
232 } else if (seedIndex == 1) { // lookup by target
233 return getDistinctHoldersOfValue((Target) seed.get(0));
234 } else
235 throw new IllegalArgumentException(seedMask.toString());
236
237 }
238 @Override
239 public Stream<? extends Object> streamValues(TupleMask seedMask, ITuple seed) {
240 if (seedMask.getSize() != 1)
241 throw new IllegalArgumentException(seedMask.toString());
242
243 int seedIndex = seedMask.indices[0];
244 if (seedIndex == 0) { // lookup by source
245 return getDistinctValuesOfHolder((Source) seed.get(0)).stream();
246 } else if (seedIndex == 1) { // lookup by target
247 return getDistinctHoldersOfValue((Target) seed.get(0)).stream();
248 } else
249 throw new IllegalArgumentException(seedMask.toString());
250
251 }
252
253 @Override
254 @SuppressWarnings("unchecked")
255 public boolean containsTuple(ITuple seed) {
256 return containsRow((Source) seed.get(0), (Target) seed.get(1));
257 }
258
259 public boolean containsRow(Source source, Target target) {
260 // TODO we currently assume V2H map exists
261 if (valueToHolderMap != null) {
262 IMemoryView<Source> holders = valueToHolderMap.lookup(target);
263 return holders != null && holders.containsNonZero(source);
264 } else
265 throw new UnsupportedOperationException("TODO implement");
266 }
267
268 public Iterable<Source> getAllDistinctHolders() {
269 return getHolderToValueMap().distinctKeys();
270 }
271 public Stream<Source> getAllDistinctHoldersStream() {
272 return getHolderToValueMap().distinctKeysStream();
273 }
274 public Iterable<Target> getAllDistinctValues() {
275 return getValueToHolderMap().distinctKeys();
276 }
277 public Stream<Target> getAllDistinctValuesStream() {
278 return getValueToHolderMap().distinctKeysStream();
279 }
280
281 public Set<Source> getDistinctHoldersOfValue(Target value) {
282 IMemoryView<Source> holdersMultiset = getValueToHolderMap().lookup(value);
283 if (holdersMultiset == null)
284 return Collections.emptySet();
285 else
286 return holdersMultiset.distinctValues();
287 }
288
289 public Set<Target> getDistinctValuesOfHolder(Source holder) {
290 IMemoryView<Target> valuesMultiset = getHolderToValueMap().lookup(holder);
291 if (valuesMultiset == null)
292 return Collections.emptySet();
293 else
294 return valuesMultiset.distinctValues();
295 }
296
297 private IMultiLookup<Source, Target> getHolderToValueMap() {
298 if (holderToValueMap == null) {
299 holderToValueMap = CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, // no duplicates, as
300 // this is the
301 // secondary
302 // collection
303 Object.class);
304
305 // TODO we currently assume V2H map exists
306 for (Target value : valueToHolderMap.distinctKeys()) {
307 for (Source holder : valueToHolderMap.lookup(value).distinctValues()) {
308 holderToValueMap.addPair(holder, value);
309 }
310 }
311 }
312 return holderToValueMap;
313 }
314
315 private IMultiLookup<Target, Source> getValueToHolderMap() {
316 // TODO we currently assume V2H map exists
317 return valueToHolderMap;
318 }
319
320}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleUnaryTable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleUnaryTable.java
new file mode 100644
index 00000000..428ea78b
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleUnaryTable.java
@@ -0,0 +1,140 @@
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 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.scopes.tables;
11
12import java.util.Optional;
13import java.util.stream.Stream;
14
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
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.Accuracy;
21import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
22import tools.refinery.viatra.runtime.matchers.util.Direction;
23import tools.refinery.viatra.runtime.matchers.util.IMemory;
24
25/**
26 * Simple value set.
27 * <p>
28 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
29 * part of a work in progress. There is no guarantee that this API will
30 * work or that it will remain the same.
31 *
32 * @since 2.0
33 * @author Gabor Bergmann
34 */
35public class SimpleUnaryTable<Value> extends AbstractIndexTable implements ITableWriterUnary.Table<Value> {
36
37 protected IMemory<Value> values = CollectionsFactory.createMultiset(); // TODO use SetMemory if unique
38
39 private boolean unique;
40
41 /**
42 * @param unique
43 * client promises to only insert a given tuple with multiplicity one
44 */
45 public SimpleUnaryTable(IInputKey inputKey, ITableContext tableContext, boolean unique) {
46 super(inputKey, tableContext);
47 this.unique = unique;
48 if (1 != inputKey.getArity())
49 throw new IllegalArgumentException(inputKey.toString());
50 }
51
52 @Override
53 public void write(Direction direction, Value value) {
54 if (direction == Direction.INSERT) {
55 boolean changed = values.addOne(value);
56 if (unique && !changed) {
57 String msg = String.format(
58 "Error: trying to add duplicate value %s to the unique set %s. This indicates some errors in underlying model representation.",
59 value, getInputKey().getPrettyPrintableName());
60 logError(msg);
61 }
62 if (changed && emitNotifications) {
63 deliverChangeNotifications(Tuples.staticArityFlatTupleOf(value), true);
64 }
65 } else { // DELETE
66 boolean changed = values.removeOne(value);
67 if (unique && !changed) {
68 String msg = String.format(
69 "Error: trying to remove duplicate value %s from the unique set %s. This indicates some errors in underlying model representation.",
70 value, getInputKey().getPrettyPrintableName());
71 logError(msg);
72 }
73 if (changed && emitNotifications) {
74 deliverChangeNotifications(Tuples.staticArityFlatTupleOf(value), false);
75 }
76 }
77 }
78
79 @Override
80 @SuppressWarnings("unchecked")
81 public boolean containsTuple(ITuple seed) {
82 return values.containsNonZero((Value) seed.get(0));
83 }
84
85 @Override
86 public int countTuples(TupleMask seedMask, ITuple seed) {
87 if (seedMask.getSize() == 0) { // unseeded
88 return values.size();
89 } else {
90 @SuppressWarnings("unchecked")
91 Value value = (Value) seed.get(0);
92 return values.containsNonZero(value) ? 1 : 0;
93 }
94 }
95
96
97 @Override
98 public Optional<Long> estimateProjectionSize(TupleMask groupMask, Accuracy requiredAccuracy) {
99 // always exact count
100 if (groupMask.getSize() == 0) {
101 return values.isEmpty() ? Optional.of(0L) : Optional.of(1L);
102 } else {
103 return Optional.of((long)values.size());
104 }
105 }
106
107
108 @Override
109 public Stream<? extends Tuple> streamTuples(TupleMask seedMask, ITuple seed) {
110 if (seedMask.getSize() == 0) { // unseeded
111 return values.distinctValues().stream().map(Tuples::staticArityFlatTupleOf);
112 } else {
113 @SuppressWarnings("unchecked")
114 Value value = (Value) seed.get(0);
115 if (values.containsNonZero(value))
116 return Stream.of(Tuples.staticArityFlatTupleOf(value));
117 else
118 return Stream.empty();
119 }
120 }
121
122 @Override
123 public Iterable<? extends Object> enumerateValues(TupleMask seedMask, ITuple seed) {
124 if (seedMask.getSize() == 0) { // unseeded
125 return values;
126 } else {
127 throw new IllegalArgumentException(seedMask.toString());
128 }
129 }
130 @Override
131 public Stream<? extends Object> streamValues(TupleMask seedMask, ITuple seed) {
132 if (seedMask.getSize() == 0) { // unseeded
133 return values.asStream();
134 } else {
135 throw new IllegalArgumentException(seedMask.toString());
136 }
137 }
138
139
140}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/AbstractTuple.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/AbstractTuple.java
new file mode 100644
index 00000000..a26d9193
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseFlatTuple.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseFlatTuple.java
new file mode 100644
index 00000000..6f46b763
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseLeftInheritanceTuple.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseLeftInheritanceTuple.java
new file mode 100644
index 00000000..03f9ea89
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple.java
new file mode 100644
index 00000000..8bbb0ac2
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple0.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple0.java
new file mode 100644
index 00000000..93f412b7
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple1.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple1.java
new file mode 100644
index 00000000..b3b1c312
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple2.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple2.java
new file mode 100644
index 00000000..2dcfd718
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple3.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple3.java
new file mode 100644
index 00000000..50cee57e
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple4.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple4.java
new file mode 100644
index 00000000..024c94f4
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/IModifiableTuple.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/IModifiableTuple.java
new file mode 100644
index 00000000..f5dab2a5
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/ITuple.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/ITuple.java
new file mode 100644
index 00000000..92014781
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple.java
new file mode 100644
index 00000000..dcdfc376
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple1.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple1.java
new file mode 100644
index 00000000..61123176
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple2.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple2.java
new file mode 100644
index 00000000..e9fb98e8
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple3.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple3.java
new file mode 100644
index 00000000..e61d196f
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple4.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple4.java
new file mode 100644
index 00000000..4e50f1e1
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/MaskedTuple.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/MaskedTuple.java
new file mode 100644
index 00000000..a5d1991c
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuple.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuple.java
new file mode 100644
index 00000000..d94f545f
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask.java
new file mode 100644
index 00000000..49c55fef
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask0.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask0.java
new file mode 100644
index 00000000..5a0c79ff
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMaskIdentity.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMaskIdentity.java
new file mode 100644
index 00000000..62746587
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleValueProvider.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleValueProvider.java
new file mode 100644
index 00000000..79193516
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuples.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuples.java
new file mode 100644
index 00000000..5e41d7d8
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileMaskedTuple.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileMaskedTuple.java
new file mode 100644
index 00000000..f683d544
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileModifiableMaskedTuple.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileModifiableMaskedTuple.java
new file mode 100644
index 00000000..92306c6e
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileTuple.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileTuple.java
new file mode 100644
index 00000000..699105a5
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/Accuracy.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/Accuracy.java
new file mode 100644
index 00000000..338990ab
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/Clearable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/Clearable.java
new file mode 100644
index 00000000..1b09aec6
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/CollectionsFactory.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/CollectionsFactory.java
new file mode 100644
index 00000000..590a1ec3
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/Direction.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/Direction.java
new file mode 100644
index 00000000..88f7ec00
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsBagMemory.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsBagMemory.java
new file mode 100644
index 00000000..e24b2448
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsDeltaBag.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsDeltaBag.java
new file mode 100644
index 00000000..94ec33cd
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsFactory.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsFactory.java
new file mode 100644
index 00000000..5a623c9b
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongMultiset.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongMultiset.java
new file mode 100644
index 00000000..88773c5d
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongSetMemory.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongSetMemory.java
new file mode 100644
index 00000000..fceb54fc
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiLookup.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiLookup.java
new file mode 100644
index 00000000..394135c9
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiset.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiset.java
new file mode 100644
index 00000000..46977c8b
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsSetMemory.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsSetMemory.java
new file mode 100644
index 00000000..92f65246
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EmptyMemory.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/EmptyMemory.java
new file mode 100644
index 00000000..a17b3a3f
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/ICache.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/ICache.java
new file mode 100644
index 00000000..8c2e54ad
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IDeltaBag.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IDeltaBag.java
new file mode 100644
index 00000000..99a4cb3b
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemory.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemory.java
new file mode 100644
index 00000000..ea788e53
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemoryView.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemoryView.java
new file mode 100644
index 00000000..add575c6
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookup.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookup.java
new file mode 100644
index 00000000..1ce1d2c9
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookupAbstract.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookupAbstract.java
new file mode 100644
index 00000000..8b1944c1
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiset.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiset.java
new file mode 100644
index 00000000..bdd5d597
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IProvider.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/IProvider.java
new file mode 100644
index 00000000..cd25dc95
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/ISetMemory.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/ISetMemory.java
new file mode 100644
index 00000000..0c03da48
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/MapBackedMemoryView.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/MapBackedMemoryView.java
new file mode 100644
index 00000000..3be078bd
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/MarkedMemory.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/MarkedMemory.java
new file mode 100644
index 00000000..d22dcbe7
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/MemoryViewBackedMapView.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/MemoryViewBackedMapView.java
new file mode 100644
index 00000000..49711a89
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/Preconditions.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/Preconditions.java
new file mode 100644
index 00000000..e9e5e3a0
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/PurgableCache.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/PurgableCache.java
new file mode 100644
index 00000000..c4e6b5af
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/Sets.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/Sets.java
new file mode 100644
index 00000000..3749fe06
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/Signed.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/Signed.java
new file mode 100644
index 00000000..8f8bc228
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonInstanceProvider.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonInstanceProvider.java
new file mode 100644
index 00000000..cc5963f7
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonMemoryView.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonMemoryView.java
new file mode 100644
index 00000000..b303f9ad
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/TimelyMemory.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/TimelyMemory.java
new file mode 100644
index 00000000..90fcad4d
--- /dev/null
+++ b/subprojects/viatra-runtime-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/MaskedResumable.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/Resumable.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/UnmaskedResumable.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/CompactTimeline.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Diff.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/SingletonTimeline.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timeline.java b/subprojects/viatra-runtime-matchers/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-matchers/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-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timelines.java b/subprojects/viatra-runtime-matchers/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-matchers/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}