aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/viatra-runtime')
-rw-r--r--subprojects/viatra-runtime/about.html26
-rw-r--r--subprojects/viatra-runtime/build.gradle.kts15
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/CancellationToken.java13
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/AdvancedViatraQueryEngine.java363
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/GenericPatternMatch.java166
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/GenericPatternMatcher.java83
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/GenericQueryGroup.java82
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/GenericQuerySpecification.java76
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IMatchUpdateListener.java37
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IPatternMatch.java107
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IQueryGroup.java46
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IQuerySpecification.java86
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/MatchUpdateAdapter.java105
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngine.java153
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineInitializationListener.java26
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineLifecycleListener.java52
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineManager.java191
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineOptions.java293
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryMatcher.java258
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryModelUpdateListener.java55
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseGeneratedPatternGroup.java31
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseMatcher.java350
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BasePatternMatch.java91
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseQueryGroup.java33
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseQuerySpecification.java147
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IBaseIndex.java91
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IEngineContext.java49
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IIndexingErrorListener.java23
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IInstanceObserver.java21
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/QueryScope.java33
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/ViatraBaseIndexChangeListener.java34
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/exception/ViatraQueryException.java71
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/EngineContextFactory.java24
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/QueryResultWrapper.java32
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/ViatraQueryEngineImpl.java714
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/engine/LifecycleProvider.java138
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/engine/ListenerContainer.java43
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/engine/ModelUpdateProvider.java214
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/ViatraQueryRuntimeException.java42
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/AverageAccumulator.java24
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleAverageOperator.java82
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleSumOperator.java62
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/ExtremumOperator.java135
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerAverageOperator.java82
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerSumOperator.java61
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongAverageOperator.java82
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongSumOperator.java61
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/avg.java39
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/count.java33
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/max.java44
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/min.java44
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/sum.java39
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/OrderedIterableMerge.java83
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFind.java214
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFindNodeProperty.java32
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/CommonQueryHintOptions.java36
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ICallDelegationStrategy.java89
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IMatcherCapability.java26
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackend.java68
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactory.java52
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactoryProvider.java46
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendHintProvider.java32
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryResultProvider.java202
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IUpdateable.java27
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryEvaluationHint.java241
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryHintOption.java122
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ResultProviderRequestor.java74
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryMetaContext.java69
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryRuntimeContext.java21
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IInputKey.java45
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IPosetComparator.java35
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryBackendContext.java49
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryCacheContext.java39
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryMetaContext.java98
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryResultProviderAccess.java31
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContext.java287
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContextListener.java27
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IndexingService.java36
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/InputKeyImplication.java103
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/BaseInputKeyWrapper.java55
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/JavaTransitiveInstancesKey.java165
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/surrogate/SurrogateQueryRegistry.java153
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/AbstractTrivialMaskedMemory.java58
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/DefaultMaskedTupleMemory.java127
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/IdentityMaskedTupleMemory.java77
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/MaskedTupleMemory.java385
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/NullaryMaskedTupleMemory.java85
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/UnaryMaskedTupleMemory.java143
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyMaskedMemory.java228
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyTrivialMaskedMemory.java100
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyDefaultMaskedTupleMemory.java98
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyIdentityMaskedTupleMemory.java106
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyNullaryMaskedTupleMemory.java108
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyUnaryMaskedTupleMemory.java133
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IOperationCompiler.java108
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IQueryPlannerStrategy.java29
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/QueryProcessingException.java102
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlan.java240
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlanFactory.java33
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/BuildHelper.java165
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/FunctionalDependencyHelper.java143
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/StatisticsHelper.java62
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/TypeHelper.java217
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PApply.java94
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PEnumerate.java76
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PJoin.java64
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/POperation.java52
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PProject.java109
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PStart.java90
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/BasePConstraint.java108
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/DeferredPConstraint.java31
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/EnumerablePConstraint.java59
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IExpressionEvaluator.java42
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IMultiQueryReference.java26
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IQueryReference.java33
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IRelationEvaluator.java47
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeConstraint.java65
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeInfoProviderConstraint.java28
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IValueProvider.java27
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/InitializablePQuery.java56
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/KeyedEnumerablePConstraint.java39
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PBody.java289
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PConstraint.java70
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PTraceable.java16
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PVariable.java203
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/TypeJudgement.java153
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/VariableDeferredPConstraint.java40
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AbstractMemorylessAggregationOperator.java31
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AggregatorType.java49
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/BoundAggregator.java61
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IAggregatorFactory.java40
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IMultisetAggregationOperator.java106
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/analysis/QueryAnalyzer.java194
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/PAnnotation.java94
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/ParameterReference.java30
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/AggregatorConstraint.java98
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/BaseTypeSafeConstraint.java99
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Equality.java96
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExportedParameter.java108
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExpressionEvaluation.java80
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Inequality.java151
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/NegativePatternCall.java52
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternCallBasedDeferred.java118
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternMatchCounter.java70
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/RelationEvaluation.java57
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/TypeFilterConstraint.java105
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/AbstractTransitiveClosure.java44
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryReflexiveTransitiveClosure.java57
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryTransitiveClosure.java33
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/Connectivity.java11
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/ConstantValue.java57
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/PositivePatternCall.java76
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/RepresentativeElectionConstraint.java43
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/TypeConstraint.java79
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/BasePQuery.java231
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PDisjunction.java104
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameter.java105
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameterDirection.java35
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PProblem.java68
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueries.java110
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQuery.java154
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueryHeader.java101
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PVisibility.java37
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/QueryInitializationException.java35
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/AbstractRewriterTraceSource.java53
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/ConstraintRemovalReason.java23
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/DefaultFlattenCallPredicate.java23
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/FlattenerCopier.java129
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IConstraintFilter.java48
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IDerivativeModificationReason.java19
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IFlattenCallPredicate.java50
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IPTraceableTraceProvider.java55
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IRewriterTraceCollector.java33
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IVariableRenamer.java59
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/MappingTraceCollector.java135
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NeverFlattenCallPredicate.java26
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NopTraceCollector.java68
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyCopier.java307
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyNormalizer.java310
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriter.java27
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriterCacher.java64
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PQueryFlattener.java253
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/RewriterException.java31
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/SurrogateQueryRewriter.java63
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/VariableMappingExpressionEvaluatorWrapper.java88
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/AbstractTuple.java136
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseFlatTuple.java20
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseLeftInheritanceTuple.java65
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple.java60
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple0.java46
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple1.java44
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple2.java51
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple3.java55
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple4.java59
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/IModifiableTuple.java27
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/ITuple.java64
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple.java172
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple1.java83
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple2.java73
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple3.java81
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple4.java88
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/MaskedTuple.java48
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuple.java69
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask.java560
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask0.java56
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMaskIdentity.java51
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleValueProvider.java48
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuples.java157
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileMaskedTuple.java50
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileModifiableMaskedTuple.java47
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileTuple.java47
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Accuracy.java48
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Clearable.java23
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/CollectionsFactory.java188
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Direction.java61
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsBagMemory.java86
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsDeltaBag.java41
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsFactory.java159
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongMultiset.java150
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongSetMemory.java212
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiLookup.java226
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiset.java93
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsSetMemory.java94
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EmptyMemory.java93
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/ICache.java32
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IDeltaBag.java26
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemory.java81
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemoryView.java205
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookup.java216
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookupAbstract.java485
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiset.java30
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IProvider.java30
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/ISetMemory.java37
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MapBackedMemoryView.java102
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MarkedMemory.java21
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MemoryViewBackedMapView.java117
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Preconditions.java208
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/PurgableCache.java44
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Sets.java90
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Signed.java60
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonInstanceProvider.java29
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonMemoryView.java105
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/TimelyMemory.java517
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/MaskedResumable.java36
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/Resumable.java27
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/UnmaskedResumable.java36
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/CompactTimeline.java111
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Diff.java55
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/SingletonTimeline.java73
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timeline.java146
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timelines.java46
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/util/ViatraQueryLoggingUtil.java72
252 files changed, 23974 insertions, 0 deletions
diff --git a/subprojects/viatra-runtime/about.html b/subprojects/viatra-runtime/about.html
new file mode 100644
index 00000000..d1d5593a
--- /dev/null
+++ b/subprojects/viatra-runtime/about.html
@@ -0,0 +1,26 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
2<html>
3<!--
4 Copyright (c) 2017, Eclipse.org Foundation, Inc.
5
6 SPDX-License-Identifier: LicenseRef-EPL-Steward
7-->
8<head>
9<title>About</title>
10<meta http-equiv=Content-Type content="text/html; charset=ISO-8859-1">
11</head>
12<body lang="EN-US">
13<h2>About This Content</h2>
14
15<p>March 18, 2019</p>
16<h3>License</h3>
17
18<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the
19Eclipse Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is available at <a href="http://www.eclipse.org/org/documents/epl-v20.php">http://www.eclipse.org/legal/epl-v20.html</a>.
20For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
21
22<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
23apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
24indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
25</body>
26</html>
diff --git a/subprojects/viatra-runtime/build.gradle.kts b/subprojects/viatra-runtime/build.gradle.kts
new file mode 100644
index 00000000..c4bd9129
--- /dev/null
+++ b/subprojects/viatra-runtime/build.gradle.kts
@@ -0,0 +1,15 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7plugins {
8 id("tools.refinery.gradle.java-library")
9}
10
11dependencies {
12 implementation(libs.slf4j.log4j)
13 implementation(libs.eclipseCollections)
14 implementation(libs.eclipseCollections.api)
15}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/CancellationToken.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/CancellationToken.java
new file mode 100644
index 00000000..a2ae41e3
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/CancellationToken.java
@@ -0,0 +1,13 @@
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;
7
8@FunctionalInterface
9public interface CancellationToken {
10 CancellationToken NONE = () -> {};
11
12 void checkCancelled();
13}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/AdvancedViatraQueryEngine.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/AdvancedViatraQueryEngine.java
new file mode 100644
index 00000000..32a3430d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/AdvancedViatraQueryEngine.java
@@ -0,0 +1,363 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, 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.api;
10
11import tools.refinery.viatra.runtime.api.scope.QueryScope;
12import tools.refinery.viatra.runtime.internal.apiimpl.ViatraQueryEngineImpl;
13import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
14import tools.refinery.viatra.runtime.matchers.backend.*;
15
16import java.lang.reflect.InvocationTargetException;
17import java.util.concurrent.Callable;
18
19/**
20 * Advanced interface to a VIATRA incremental evaluation engine.
21 *
22 * <p>
23 * You can create a new, private, unmanaged {@link AdvancedViatraQueryEngine} instance using
24 * {@link #createUnmanagedEngine(QueryScope)}. Additionally, you can access the advanced interface on any
25 * {@link ViatraQueryEngine} by {@link AdvancedViatraQueryEngine#from(ViatraQueryEngine)}.
26 *
27 * <p>
28 * While the default interface {@link ViatraQueryEngine}, is suitable for most users, this advanced interface provides more
29 * control over the engine. The most important added functionality is the following:
30 * <ul>
31 * <li>You can have tighter control over the lifecycle of the engine, if you create a private, unmanaged engine
32 * instance. For instance, a (non-managed) engine can be disposed in order to detach from the EMF model and stop
33 * listening on update notifications. The indexes built previously in the engine can then be garbage collected, even if
34 * the model itself is retained. Total lifecycle control is only available for private, unmanaged engines (created using
35 * {@link #createUnmanagedEngine(QueryScope)}); a managed engine (obtained via {@link ViatraQueryEngine#on(QueryScope)}) is
36 * shared among clients and can not be disposed or wiped.
37 * <li>You can add and remove listeners to receive notification when the model or the match sets change.
38 * <li>You can add and remove listeners to receive notification on engine lifecycle events, such as creation of new
39 * matchers. For instance, if you explicitly share a private, unmanaged engine between multiple sites, you should
40 * register a callback using {@link #addLifecycleListener(ViatraQueryEngineLifecycleListener)} to learn when another client
41 * has called the destructive methods {@link #dispose()} or {@link #wipe()}.
42 * </ul>
43 *
44 * @author Bergmann Gabor
45 * @noextend This class is not intended to be subclassed by clients.
46 */
47public abstract class AdvancedViatraQueryEngine extends ViatraQueryEngine {
48
49 /**
50 * Creates a new unmanaged VIATRA Query engine to evaluate queries over a given scope specified by an {@link QueryScope}.
51 *
52 * <p> Repeated invocations will return different instances, so other clients are unable to independently access
53 * and influence the returned engine. Note that unmanaged engines do not benefit from some performance improvements
54 * that stem from sharing incrementally maintained indices and caches between multiple clients using the same managed
55 * engine instance.
56 *
57 * <p>
58 * Client is responsible for the lifecycle of the returned engine, hence the usage of the advanced interface
59 * {@link AdvancedViatraQueryEngine}.
60 *
61 * <p>
62 * The match set of any patterns will be incrementally refreshed upon updates from this scope.
63 *
64 * @param scope
65 * the scope of query evaluation; the definition of the set of model elements that this engine is operates on.
66 * Provide e.g. a {@link EMFScope} for evaluating queries on an EMF model.
67 * @return the advanced interface to a newly created unmanaged engine
68 * @since 0.9
69 */
70 public static AdvancedViatraQueryEngine createUnmanagedEngine(QueryScope scope) {
71 return new ViatraQueryEngineImpl(null, scope);
72 }
73
74 /**
75 * Creates a new unmanaged VIATRA Query engine to evaluate queries over a given scope specified by an {@link QueryScope}.
76 *
77 * <p> Repeated invocations will return different instances, so other clients are unable to independently access
78 * and influence the returned engine. Note that unmanaged engines do not benefit from some performance improvements
79 * that stem from sharing incrementally maintained indices and caches between multiple clients using the same managed
80 * engine instance.
81 *
82 * <p>
83 * Client is responsible for the lifecycle of the returned engine, hence the usage of the advanced interface
84 * {@link AdvancedViatraQueryEngine}.
85 *
86 * <p>
87 * The match set of any patterns will be incrementally refreshed upon updates from this scope.
88 *
89 * @param scope
90 * the scope of query evaluation; the definition of the set of model elements that this engine is operates on.
91 * Provide e.g. a {@link EMFScope} for evaluating queries on an EMF model.
92 * @return the advanced interface to a newly created unmanaged engine
93 * @since 1.4
94 */
95 public static AdvancedViatraQueryEngine createUnmanagedEngine(QueryScope scope, ViatraQueryEngineOptions options) {
96 return new ViatraQueryEngineImpl(null, scope, options);
97 }
98
99 /**
100 * Provides access to a given existing engine through the advanced interface.
101 *
102 * <p>
103 * Caveat: if the referenced engine is managed (i.e. created via {@link ViatraQueryEngine#on(QueryScope)}), the advanced
104 * methods {@link #dispose()} and {@link #wipe()} will not be allowed.
105 *
106 * @param engine
107 * the engine to access using the advanced interface
108 * @return a reference to the same engine conforming to the advanced interface
109 */
110 public static AdvancedViatraQueryEngine from(ViatraQueryEngine engine) {
111 return (AdvancedViatraQueryEngine) engine;
112 }
113
114 /**
115 * Add an engine lifecycle listener to this engine instance.
116 *
117 * @param listener
118 * the {@link ViatraQueryEngineLifecycleListener} that should listen to lifecycle events from this engine
119 */
120 public abstract void addLifecycleListener(ViatraQueryEngineLifecycleListener listener);
121
122 /**
123 * Remove an existing lifecycle listener from this engine instance.
124 *
125 * @param listener
126 * the {@link ViatraQueryEngineLifecycleListener} that should not listen to lifecycle events from this
127 * engine anymore
128 */
129 public abstract void removeLifecycleListener(ViatraQueryEngineLifecycleListener listener);
130
131 /**
132 * Add an model update event listener to this engine instance (that fires its callbacks according to its
133 * notification level).
134 *
135 * @param listener
136 * the {@link ViatraQueryModelUpdateListener} that should listen to model update events from this engine.
137 */
138 public abstract void addModelUpdateListener(ViatraQueryModelUpdateListener listener);
139
140 /**
141 * Remove an existing model update event listener to this engine instance.
142 *
143 * @param listener
144 * the {@link ViatraQueryModelUpdateListener} that should not listen to model update events from this engine
145 * anymore
146 */
147 public abstract void removeModelUpdateListener(ViatraQueryModelUpdateListener listener);
148
149 /**
150 * Registers low-level callbacks for match appearance and disappearance on this pattern matcher.
151 *
152 * <p>
153 * <b>Caution: </b> This is a low-level callback that is invoked when the pattern matcher is not necessarily in a
154 * consistent state yet. Importantly, no model modification permitted during the callback. Most users should use the
155 * databinding support ({@link org.eclipse.viatra.addon.databinding.runtime.api.ViatraObservables ViatraObservables}) or the event-driven API
156 * ({@link org.eclipse.viatra.transformation.evm.api.EventDrivenVM EventDrivenVM}) instead.
157 *
158 * <p>
159 * Performance note: expected to be much more efficient than polling at {@link #addCallbackAfterUpdates(Runnable)},
160 * but prone to "signal hazards", e.g. spurious match appearances that will disappear immediately afterwards.
161 *
162 * <p>
163 * The callback can be unregistered via {@link #removeCallbackOnMatchUpdate(IMatchUpdateListener)}.
164 *
165 * @param fireNow
166 * if true, appearCallback will be immediately invoked on all current matches as a one-time effect. See
167 * also {@link ViatraQueryMatcher#forEachMatch(IMatchProcessor)}.
168 * @param listener
169 * the listener that will be notified of each new match that appears or disappears, starting from now.
170 * @param matcher
171 * the {@link ViatraQueryMatcher} for which this listener should be active
172 */
173 public abstract <Match extends IPatternMatch> void addMatchUpdateListener(ViatraQueryMatcher<Match> matcher,
174 IMatchUpdateListener<? super Match> listener, boolean fireNow);
175
176 /**
177 * Remove an existing match update event listener to this engine instance.
178 *
179 * @param matcher
180 * the {@link ViatraQueryMatcher} for which this listener should not be active anymore
181 * @param listener
182 * the {@link IMatchUpdateListener} that should not receive the callbacks anymore
183 */
184 public abstract <Match extends IPatternMatch> void removeMatchUpdateListener(ViatraQueryMatcher<Match> matcher,
185 IMatchUpdateListener<? super Match> listener);
186
187
188 /**
189 * Access a pattern matcher based on a {@link IQuerySpecification}, overriding some of the default query evaluation hints.
190 * Multiple calls may return the same matcher depending on the actual evaluation hints.
191 *
192 * <p> It is guaranteed that this method will always return a matcher instance which is functionally compatible
193 * with the requested functionality (see {@link IMatcherCapability}).
194 * Otherwise, the query evaluator is free to ignore any hints.
195 *
196 * <p> For stateful query backends (Rete), hints may be effective only the first time a matcher is created.
197 * @param querySpecification a {@link IQuerySpecification} that describes a VIATRA query
198 * @return a pattern matcher corresponding to the specification
199 * @param optionalEvaluationHints additional / overriding options on query evaluation; passing null means default options associated with the query
200 * @throws ViatraQueryRuntimeException if the matcher could not be initialized
201 * @since 0.9
202 */
203 public abstract <Matcher extends ViatraQueryMatcher<? extends IPatternMatch>> Matcher getMatcher(
204 IQuerySpecification<Matcher> querySpecification,
205 QueryEvaluationHint optionalEvaluationHints);
206
207 /**
208 * Initializes matchers for a group of patterns as one step (optionally overriding some of the default query evaluation hints).
209 * If some of the pattern matchers are already
210 * constructed in the engine, no task is performed for them.
211 *
212 * <p>
213 * This preparation step has the advantage that it prepares pattern matchers for an arbitrary number of patterns in a
214 * single-pass traversal of the model.
215 * This is typically more efficient than traversing the model each time an individual pattern matcher is initialized on demand.
216 * The performance benefit only manifests itself if the engine is not in wildcard mode.
217 *
218 * @param queryGroup a {@link IQueryGroup} identifying a set of VIATRA queries
219 * @param optionalEvaluationHints additional / overriding options on query evaluation; passing null means default options associated with each query
220 * @throws ViatraQueryRuntimeException
221 * if there was an error in preparing the engine
222 * @since 0.9
223 */
224 public abstract void prepareGroup(IQueryGroup queryGroup, QueryEvaluationHint optionalEvaluationHints);
225
226 /**
227 * Indicates whether the engine is managed, i.e. the default engine assigned to the given scope root by
228 * {@link ViatraQueryEngine#on(QueryScope)}.
229 *
230 * <p>
231 * If the engine is managed, there may be other clients using it, as all calls to
232 * {@link ViatraQueryEngine#on(QueryScope)} return the same managed engine instance for a given scope root. Therefore the
233 * destructive methods {@link #wipe()} and {@link #dispose()} are not allowed.
234 *
235 * <p>
236 * On the other hand, if the engine is unmanaged (i.e. a private instance created using
237 * {@link #createUnmanagedEngine(QueryScope)}), then {@link #wipe()} and {@link #dispose()} can be called. If you
238 * explicitly share a private, unmanaged engine between multiple sites, register a callback using
239 * {@link #addLifecycleListener(ViatraQueryEngineLifecycleListener)} to learn when another client has called these
240 * destructive methods.
241 *
242 * @return true if the engine is managed, and therefore potentially shared with other clients querying the same EMF
243 * model
244 */
245 public abstract boolean isManaged();
246
247 /**
248 * Indicates whether the engine is in a tainted, inconsistent state due to some internal errors. If true, results
249 * are no longer reliable; engine should be disposed.
250 *
251 * <p>
252 * The engine is in a tainted state if any of its internal processes report back a fatal error. The
253 * {@link ViatraQueryEngineLifecycleListener} interface provides a callback method for entering the tainted state.
254 *
255 * @return the tainted state
256 */
257 public abstract boolean isTainted();
258
259 /**
260 * Discards any pattern matcher caches and forgets known patterns. The base index built directly on the underlying
261 * EMF model, however, is kept in memory to allow reuse when new pattern matchers are built. Use this method if you
262 * have e.g. new versions of the same patterns, to be matched on the same model.
263 *
264 * <p>
265 * Matcher objects will continue to return stale results. If no references are retained to the matchers, they can
266 * eventually be GC'ed.
267 * <p>
268 * Disallowed if the engine is managed (see {@link #isManaged()}), as there may be other clients using it.
269 * <p>
270 * If you explicitly share a private, unmanaged engine between multiple sites, register a callback using
271 * {@link #addLifecycleListener(ViatraQueryEngineLifecycleListener)} to learn when another client has called this
272 * destructive method.
273 *
274 * @throws UnsupportedOperationException
275 * if engine is managed
276 */
277 public abstract void wipe();
278
279 /**
280 * Completely disconnects and dismantles the engine. Cannot be reversed.
281 * <p>
282 * Matcher objects will continue to return stale results. If no references are retained to the matchers or the
283 * engine, they can eventually be GC'ed, and they won't block the EMF model from being GC'ed anymore.
284 * <p>
285 * The base indexer (see {@link #getBaseIndex()}) built on the model will be disposed alongside the engine, unless
286 * the user has manually added listeners on the base index that were not removed yet.
287 * <p>
288 * Disallowed if the engine is managed (see {@link #isManaged()}), as there may be other clients using it.
289 * <p>
290 * If you explicitly share a private, unmanaged engine between multiple sites, register a callback using
291 * {@link #addLifecycleListener(ViatraQueryEngineLifecycleListener)} to learn when another client has called this
292 * destructive method.
293 *
294 * @throws UnsupportedOperationException
295 * if engine is managed
296 */
297 public abstract void dispose();
298
299 /**
300 * Provides access to the selected query backend component of the VIATRA Query engine.
301 * @noreference for internal use only
302 * @throws ViatraQueryRuntimeException
303 */
304 public abstract IQueryBackend getQueryBackend(IQueryBackendFactory iQueryBackendFactory);
305
306 /**
307 * Access an existing pattern matcher based on a {@link IQuerySpecification}, and optional hints override.
308 * @param querySpecification a {@link IQuerySpecification} that describes a VIATRA query specification
309 * @param optionalOverrideHints a {@link QueryEvaluationHint} that may override the pattern hints (can be null)
310 * @return a pattern matcher corresponding to the specification, <code>null</code> if a matcher does not exist yet.
311 * @since 1.4
312 */
313 public abstract <Matcher extends ViatraQueryMatcher<? extends IPatternMatch>> Matcher getExistingMatcher(IQuerySpecification<Matcher> querySpecification, QueryEvaluationHint optionalOverrideHints);
314
315 /**
316 * Returns the immutable {@link ViatraQueryEngineOptions} of the engine.
317 *
318 * @return the engine options
319 * @since 1.4
320 */
321 public abstract ViatraQueryEngineOptions getEngineOptions();
322
323 /**
324 * Return the underlying result provider for the given matcher.
325 *
326 * @beta This method may change in future versions
327 * @since 1.4
328 * @noreference This method is considered internal API
329 */
330 public abstract IQueryResultProvider getResultProviderOfMatcher(ViatraQueryMatcher<? extends IPatternMatch> matcher);
331
332 /**
333 * The given callable will be executed, and all update propagation in stateful query backends
334 * will be delayed until the execution is done. Within the callback, these backends will provide stale results.
335 *
336 * <p> It is optional for a {@link IQueryBackend} to support the delaying of update propagation; stateless backends will display up-to-date results.
337 * In this case, the given callable shall be executed, and the update propagation shall happen just like in non-delayed execution.
338 *
339 * <p> Example: in the Rete network, no messages will be propagated until the given callable is executed.
340 * After the execution of the callable, all accumulated messages will be delivered.
341 *
342 * <p> The purpose of this method is that stateful query backends may save work when multiple model modifications are performed within the callback that partially cancel each other out.
343 *
344 * @param callable the callable to be executed
345 * @return the result of the callable
346 * @since 1.6
347 */
348 public abstract <V> V delayUpdatePropagation(Callable<V> callable) throws InvocationTargetException;
349
350 /**
351 * Returns true if the update propagation in this engine is currently delayed, false otherwise.
352 *
353 * @see {@link #delayUpdatePropagation(Callable)}
354 * @since 1.6
355 */
356 public abstract boolean isUpdatePropagationDelayed();
357
358 /**
359 * Returns true if the {@link #dispose()} method was called on this engine previously.
360 * @since 2.0
361 */
362 public abstract boolean isDisposed();
363}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/GenericPatternMatch.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/GenericPatternMatch.java
new file mode 100644
index 00000000..b4de2b70
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/GenericPatternMatch.java
@@ -0,0 +1,166 @@
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.api;
11
12import java.util.Arrays;
13
14import tools.refinery.viatra.runtime.api.impl.BasePatternMatch;
15
16/**
17 * Generic signature object implementation.
18 *
19 * See also the generated matcher and signature of the pattern, with pattern-specific API simplifications.
20 *
21 * @author Bergmann Gábor
22 * @since 0.9
23 *
24 */
25public abstract class GenericPatternMatch extends BasePatternMatch {
26
27 private final GenericQuerySpecification<? extends GenericPatternMatcher> specification;
28 private final Object[] array;
29
30 private GenericPatternMatch(GenericQuerySpecification<? extends GenericPatternMatcher> specification, Object[] array) {
31 super();
32 this.specification = specification;
33 this.array = array;
34 }
35
36 @Override
37 public Object get(String parameterName) {
38 Integer index = specification.getPositionOfParameter(parameterName);
39 return index == null ? null : array[index];
40 }
41
42 @Override
43 public Object get(int position) {
44 return array[position];
45 }
46
47 @Override
48 public boolean set(String parameterName, Object newValue) {
49 if (!isMutable()) throw new UnsupportedOperationException();
50 Integer index = specification.getPositionOfParameter(parameterName);
51 if (index == null)
52 return false;
53 array[index] = newValue;
54 return true;
55 }
56
57 @Override
58 public Object[] toArray() {
59 return Arrays.copyOf(array, array.length);
60 }
61
62 @Override
63 public int hashCode() {
64 final int prime = 31;
65 int result = 1;
66 for (int i = 0; i < array.length; ++i)
67 result = prime * result + ((array[i] == null) ? 0 : array[i].hashCode());
68 return result;
69 }
70
71 @Override
72 public boolean equals(Object obj) {
73 if (this == obj)
74 return true;
75 if (!(obj instanceof GenericPatternMatch)) { // this should be infrequent
76 if (obj == null)
77 return false;
78 if (!(obj instanceof IPatternMatch))
79 return false;
80 IPatternMatch other = (IPatternMatch) obj;
81 if (!specification().equals(other.specification()))
82 return false;
83 return Arrays.deepEquals(array, other.toArray());
84 }
85 final GenericPatternMatch other = (GenericPatternMatch) obj;
86 return specification().equals(other.specification()) && Arrays.deepEquals(array, other.array);
87 }
88
89 @Override
90 public String prettyPrint() {
91 StringBuilder result = new StringBuilder();
92 for (int i = 0; i < array.length; ++i) {
93 if (i != 0)
94 result.append(", ");
95 result.append("\"" + parameterNames().get(i) + "\"=" + prettyPrintValue(array[i]));
96 }
97 return result.toString();
98 }
99
100 @Override
101 public GenericQuerySpecification<? extends GenericPatternMatcher> specification() {
102 return specification;
103 }
104
105 /**
106 * Returns an empty, mutable match.
107 * Fields of the mutable match can be filled to create a partial match, usable as matcher input.
108 *
109 * @return the empty match
110 */
111 public static GenericPatternMatch newEmptyMatch(GenericQuerySpecification<? extends GenericPatternMatcher> specification) {
112 return new Mutable(specification, new Object[specification.getParameters().size()]);
113 }
114
115 /**
116 * Returns a mutable (partial) match.
117 * Fields of the mutable match can be filled to create a partial match, usable as matcher input.
118 *
119 * @param parameters
120 * the fixed value of pattern parameters, or null if not bound.
121 * @return the new, mutable (partial) match object.
122 */
123 public static GenericPatternMatch newMutableMatch(GenericQuerySpecification<? extends GenericPatternMatcher> specification, Object... parameters) {
124 return new Mutable(specification, parameters);
125 }
126
127 /**
128 * Returns a new (partial) match.
129 * This can be used e.g. to call the matcher with a partial match.
130 *
131 * <p>The returned match will be immutable. Use {@link #newEmptyMatch(GenericQuerySpecification)} to obtain a mutable match object.
132 *
133 * @param parameters
134 * the fixed value of pattern parameters, or null if not bound.
135 * @return the (partial) match object.
136 */
137 public static GenericPatternMatch newMatch(GenericQuerySpecification<? extends GenericPatternMatcher> specification, Object... parameters) {
138 return new Immutable(specification, Arrays.copyOf(parameters, parameters.length));
139 }
140
141 @Override
142 public IPatternMatch toImmutable() {
143 return isMutable() ? newMatch(specification, array) : this;
144 }
145
146 static final class Mutable extends GenericPatternMatch {
147 Mutable(GenericQuerySpecification<? extends GenericPatternMatcher> specification, Object[] array) {
148 super(specification, array);
149 }
150
151 @Override
152 public boolean isMutable() {
153 return true;
154 }
155 }
156 static final class Immutable extends GenericPatternMatch {
157 Immutable(GenericQuerySpecification<? extends GenericPatternMatcher> specification, Object[] array) {
158 super(specification, array);
159 }
160
161 @Override
162 public boolean isMutable() {
163 return false;
164 }
165 }
166}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/GenericPatternMatcher.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/GenericPatternMatcher.java
new file mode 100644
index 00000000..9a3fbb44
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/GenericPatternMatcher.java
@@ -0,0 +1,83 @@
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.api;
11
12import tools.refinery.viatra.runtime.api.impl.BaseMatcher;
13import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
14
15/**
16 * This is a generic pattern matcher for any VIATRA pattern, with "interpretative" query execution.
17 * To use the pattern matcher on a given model, obtain a {@link GenericQuerySpecification} first, then
18 * invoke e.g. {@link GenericQuerySpecification#getMatcher(ViatraQueryEngine)}.
19 * in conjunction with {@link ViatraQueryEngine#on(tools.refinery.viatra.runtime.api.scope.QueryScope)}.
20 * <p>
21 * Whenever available, consider using the pattern-specific generated matcher API instead.
22 *
23 * <p>
24 * Matches of the pattern will be represented as {@link GenericPatternMatch}.
25 *
26 * @author Bergmann Gábor
27 * @see GenericPatternMatch
28 * @see GenericMatchProcessor
29 * @see GenericQuerySpecification
30 * @since 0.9
31 */
32public class GenericPatternMatcher extends BaseMatcher<GenericPatternMatch> {
33
34 /**
35 * @since 1.4
36 */
37 public GenericPatternMatcher(GenericQuerySpecification<? extends GenericPatternMatcher> specification) {
38 super(specification);
39 }
40
41 @Override
42 public GenericPatternMatch arrayToMatch(Object[] parameters) {
43 return GenericPatternMatch.newMatch(getSpecification(), parameters);
44 }
45
46 @Override
47 public GenericPatternMatch arrayToMatchMutable(Object[] parameters) {
48 return GenericPatternMatch.newMutableMatch(getSpecification(), parameters);
49 }
50
51 @Override
52 protected GenericPatternMatch tupleToMatch(Tuple t) {
53 return new GenericPatternMatch.Immutable(getSpecification(), /*avoid re-cloning*/t.getElements());
54 }
55
56 @SuppressWarnings("unchecked")
57 @Override
58 public GenericQuerySpecification<? extends GenericPatternMatcher> getSpecification() {
59 return (GenericQuerySpecification<? extends GenericPatternMatcher>)querySpecification;
60 }
61
62 /**
63 * Internal method for {@link GenericQuerySpecification}
64 * @noreference
65 */
66 static <Matcher extends GenericPatternMatcher> GenericPatternMatcher instantiate(GenericQuerySpecification<Matcher> querySpecification) {
67 return new GenericPatternMatcher(querySpecification);
68 }
69
70 /**
71 * Internal method for {@link GenericQuerySpecification}
72 * @noreference
73 */
74 static <Matcher extends GenericPatternMatcher> GenericPatternMatcher instantiate(ViatraQueryEngine engine, GenericQuerySpecification<Matcher> querySpecification) {
75 // check if matcher already exists
76 GenericPatternMatcher matcher = engine.getExistingMatcher(querySpecification);
77 if (matcher == null) {
78 matcher = engine.getMatcher(querySpecification);
79 }
80 return matcher;
81 }
82
83}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/GenericQueryGroup.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/GenericQueryGroup.java
new file mode 100644
index 00000000..a5661bc9
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/GenericQueryGroup.java
@@ -0,0 +1,82 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Mark Czotter, 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.api;
10
11import java.util.Arrays;
12import java.util.HashSet;
13import java.util.Set;
14import java.util.stream.Collectors;
15import java.util.stream.Stream;
16
17import tools.refinery.viatra.runtime.api.impl.BaseQueryGroup;
18
19/**
20 * Generic implementation of {@link IQueryGroup}, covering an arbitrarily chosen set of patterns. Use the public
21 * constructor or static GenericQueryGroup.of(...) methods to instantiate.
22 *
23 * @author Mark Czotter
24 *
25 */
26public class GenericQueryGroup extends BaseQueryGroup {
27
28 private final Set<IQuerySpecification<?>> patterns;
29
30 /**
31 * Creates a GenericQueryGroup object with a set of patterns.
32 *
33 * @param patterns
34 */
35 public GenericQueryGroup(Set<IQuerySpecification<?>> patterns) {
36 this.patterns = patterns;
37 }
38
39 @Override
40 public Set<IQuerySpecification<?>> getSpecifications() {
41 return patterns;
42 }
43
44 /**
45 * Creates a generic {@link IQueryGroup} instance from {@link IQuerySpecification} objects.
46 *
47 * @since 2.0
48 */
49 public static IQueryGroup of(Stream<IQuerySpecification<?>> querySpecifications) {
50 return new GenericQueryGroup(querySpecifications.collect(Collectors.toSet()));
51 }
52
53 /**
54 * Creates a generic {@link IQueryGroup} instance from {@link IQuerySpecification} objects.
55 *
56 * @param querySpecifications
57 */
58 public static IQueryGroup of(Set<IQuerySpecification<?>> querySpecifications) {
59 return new GenericQueryGroup(querySpecifications);
60 }
61
62 /**
63 * Creates a generic {@link IQueryGroup} instance from {@link IQuerySpecification} objects.
64 *
65 * @param querySpecifications
66 */
67 public static IQueryGroup of(IQuerySpecification<?>... querySpecifications) {
68 return of(new HashSet<IQuerySpecification<?>>(Arrays.asList(querySpecifications)));
69 }
70
71 /**
72 * Creates a generic {@link IQueryGroup} instance from other {@link IQueryGroup} objects (subgroups).
73 *
74 */
75 public static IQueryGroup of(IQueryGroup... subGroups) {
76 Set<IQuerySpecification<?>> patterns = new HashSet<IQuerySpecification<?>>();
77 for (IQueryGroup group : subGroups) {
78 patterns.addAll(group.getSpecifications());
79 }
80 return new GenericQueryGroup(patterns);
81 }
82}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/GenericQuerySpecification.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/GenericQuerySpecification.java
new file mode 100644
index 00000000..5681ac19
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/GenericQuerySpecification.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.api;
10
11import tools.refinery.viatra.runtime.api.impl.BaseQuerySpecification;
12import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
13import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
14import tools.refinery.viatra.runtime.matchers.psystem.queries.PVisibility;
15
16/**
17 * This is a generic query specification for VIATRA pattern matchers, for "interpretative" query execution.
18 * Should be subclassed by query specification implementations specific to query languages.
19 *
20 * <p>
21 * When available, consider using the pattern-specific generated matcher API instead.
22 *
23 * <p>
24 * The created matcher will be of type {@link GenericPatternMatcher}. Matches of the pattern will be represented as
25 * {@link GenericPatternMatch}.
26 *
27 * <p>
28 * Note for overriding (if you have your own query language or ):
29 * Derived classes should use {@link #defaultInstantiate(ViatraQueryEngine)} for implementing
30 * {@link #instantiate(ViatraQueryEngine)} if they use {@link GenericPatternMatcher} proper.
31 *
32 * @see GenericPatternMatcher
33 * @see GenericPatternMatch
34 * @see GenericMatchProcessor
35 * @author Bergmann Gábor
36 * @noinstantiate This class is not intended to be instantiated by end-users.
37 * @since 0.9
38 */
39public abstract class GenericQuerySpecification<Matcher extends GenericPatternMatcher> extends
40 BaseQuerySpecification<Matcher> {
41
42 /**
43 * Instantiates query specification for the given internal query representation.
44 */
45 public GenericQuerySpecification(PQuery wrappedPQuery) {
46 super(wrappedPQuery);
47 }
48
49 @Override
50 public GenericPatternMatch newEmptyMatch() {
51 return GenericPatternMatch.newEmptyMatch(this);
52 }
53
54 @Override
55 public GenericPatternMatch newMatch(Object... parameters) {
56 return GenericPatternMatch.newMatch(this, parameters);
57 }
58
59 /**
60 * Derived classes should use this implementation of {@link #instantiate(ViatraQueryEngine)}
61 * if they use {@link GenericPatternMatcher} proper.
62 * @throws ViatraQueryRuntimeException
63 */
64 protected GenericPatternMatcher defaultInstantiate(ViatraQueryEngine engine) {
65 return GenericPatternMatcher.instantiate(engine, this);
66 }
67
68 /**
69 * @since 2.0
70 */
71 @Override
72 public PVisibility getVisibility() {
73 return getInternalQueryRepresentation().getVisibility();
74 }
75
76} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IMatchUpdateListener.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IMatchUpdateListener.java
new file mode 100644
index 00000000..23c64537
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IMatchUpdateListener.java
@@ -0,0 +1,37 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, 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.api;
10
11/**
12 * An interface for low-level notifications about match appearance and disappearance.
13 *
14 * <p>
15 * See {@link ViatraQueryMatcher#addCallbackOnMatchUpdate(IMatchUpdateListener, boolean)} for usage. Clients should
16 * consider using {@link MatchUpdateAdapter} or deriving their implementation from it.
17 *
18 * @author Bergmann Gabor
19 *
20 */
21public interface IMatchUpdateListener<Match extends IPatternMatch> {
22 /**
23 * Will be invoked on each new match that appears.
24 *
25 * @param match
26 * the match that has just appeared.
27 */
28 public void notifyAppearance(Match match);
29
30 /**
31 * Will be invoked on each existing match that disappears.
32 *
33 * @param match
34 * the match that has just disappeared.
35 */
36 public void notifyDisappearance(Match match);
37}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IPatternMatch.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IPatternMatch.java
new file mode 100644
index 00000000..be6467cc
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IPatternMatch.java
@@ -0,0 +1,107 @@
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.api;
11
12import java.util.List;
13
14/**
15 * Generic interface for a single match of a pattern. Each instance is a (partial) substitution of pattern parameters,
16 * essentially a parameter to value mapping.
17 *
18 * <p>Can also represent a partial match; unsubstituted parameters are assigned to null. Pattern matchers must never return
19 * a partial match, but they accept partial matches as method parameters.
20 *
21 * @author Bergmann Gábor
22 */
23public interface IPatternMatch extends Cloneable /* , Map<String, Object> */{
24 /** @return the pattern for which this is a match. */
25 public IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> specification();
26
27 /** Identifies the name of the pattern for which this is a match. */
28 public String patternName();
29
30 /** Returns the list of symbolic parameter names. */
31 public List<String> parameterNames();
32
33 /** Returns the value of the parameter with the given name, or null if name is invalid. */
34 public Object get(String parameterName);
35
36 /** Returns the value of the parameter at the given position, or null if position is invalid. */
37 public Object get(int position);
38
39 /**
40 * Sets the parameter with the given name to the given value.
41 *
42 * <p> Works only if match is mutable. See {@link #isMutable()}.
43 *
44 * @returns true if successful, false if parameter name is invalid. May also fail and return false if the value type
45 * is incompatible.
46 * @throws UnsupportedOperationException if match is not mutable.
47 */
48 public boolean set(String parameterName, Object newValue);
49
50 /**
51 * Sets the parameter at the given position to the given value.
52 *
53 * <p> Works only if match is mutable. See {@link #isMutable()}.
54 *
55 * @returns true if successful, false if position is invalid. May also fail and return false if the value type is
56 * incompatible.
57 * @throws UnsupportedOperationException if match is not mutable.
58 */
59 public boolean set(int position, Object newValue);
60
61 /**
62 * Returns whether the match object can be further modified after its creation. Setters work only if the match is mutable.
63 *
64 * <p>Matches computed by the pattern matchers are not mutable, so that the match set cannot be modified externally.
65 * Partial matches used as matcher input, however, can be mutable; such match objects can be created using {@link ViatraQueryMatcher#newEmptyMatch()}.
66 *
67 * @return whether the match can be modified
68 */
69 public boolean isMutable();
70
71 /**
72 * Converts the match to an array representation, with each pattern parameter at their respective position.
73 * In case of a partial match, unsubstituted parameters will be represented as null elements in the array.
74 *
75 * @return a newly constructed array containing each parameter substitution of the match in order.
76 */
77 public Object[] toArray();
78
79 /**
80 * Takes an immutable snapshot of this match.
81 * @return the match itself in case of immutable matches, an immutable copy in case of mutable ones.
82 */
83 public IPatternMatch toImmutable();
84
85 /** Prints the list of parameter-value pairs. */
86 public String prettyPrint();
87
88 /**
89 * Checks that this match is compatible with the given other match.
90 * This is used for filtering the match set of a matcher.
91 *
92 * <p/> Two non-null matches are compatible if and only if:
93 * <ul>
94 * <li>They share the same pattern.</li>
95 * <li>For each parameter, where they are set (non-null) in both matches,
96 * their values are equal.</li>
97 * </li>
98 * </ul>
99 *
100 * <p/> Furthermore, all matches are considered compatible with
101 * null matches (e.g. empty filter).
102 *
103 * @param other
104 * @return true, if this is compatible with other, or other is null
105 */
106 public boolean isCompatibleWith(IPatternMatch other);
107}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IQueryGroup.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IQueryGroup.java
new file mode 100644
index 00000000..a783f823
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IQueryGroup.java
@@ -0,0 +1,46 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Mark Czotter, 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.api;
10
11import java.util.Set;
12
13/**
14 * Generic interface for group of query specifications.
15 *
16 * <p>It handles more than one patterns as a group, and provides functionality to initialize the matchers together (which
17 * has performance benefits).
18 *
19 * @author Mark Czotter
20 *
21 */
22public interface IQueryGroup {
23
24 /**
25 * Initializes matchers for the group of patterns within an {@link ViatraQueryEngine}. If some of the pattern matchers are already
26 * constructed in the engine, no task is performed for them.
27 *
28 * <p>
29 * This preparation step has the advantage that it prepares pattern matchers for an arbitrary number of patterns in a
30 * single-pass traversal of the model.
31 * This is typically more efficient than traversing the model each time an individual pattern matcher is initialized on demand.
32 * The performance benefit only manifests itself if the engine is not in wildcard mode.
33 *
34 * @param engine
35 * the existing VIATRA Query engine in which the matchers will be created.
36 * @throws ViatraQueryRuntimeException
37 * if there was an error in preparing the engine
38 */
39 public void prepare(ViatraQueryEngine engine);
40
41 /**
42 * Returns the currently assigned {@link IQuerySpecification}s.
43 */
44 public Set<IQuerySpecification<?>> getSpecifications();
45
46}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IQuerySpecification.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IQuerySpecification.java
new file mode 100644
index 00000000..326d2202
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/IQuerySpecification.java
@@ -0,0 +1,86 @@
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.api;
11
12import tools.refinery.viatra.runtime.api.scope.QueryScope;
13import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
14import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
15import tools.refinery.viatra.runtime.matchers.psystem.queries.PQueryHeader;
16
17/**
18 * API interface for a VIATRA query specification. Each query is associated with a pattern. Methods instantiate a matcher
19 * of the pattern with various parameters.
20 *
21 * <p> As of 0.9.0, some internal details (mostly relevant for query evaluator backends) have been moved to {@link #getInternalQueryRepresentation()}.
22 *
23 * @author Bergmann Gábor
24 *
25 */
26public interface IQuerySpecification<Matcher extends ViatraQueryMatcher<? extends IPatternMatch>> extends PQueryHeader {
27
28 /**
29 * Initializes the pattern matcher within an existing {@link ViatraQueryEngine}. If the pattern matcher is already
30 * constructed in the engine, only a lightweight reference is created.
31 * <p>
32 * The match set will be incrementally refreshed upon updates.
33 *
34 * @param engine
35 * the existing VIATRA Query engine in which this matcher will be created.
36 * @throws ViatraQueryRuntimeException
37 * if an error occurs during pattern matcher creation
38 */
39 public Matcher getMatcher(ViatraQueryEngine engine);
40
41
42 /**
43 * Returns an empty, mutable Match compatible with matchers of this query.
44 * Fields of the mutable match can be filled to create a partial match, usable as matcher input.
45 * This can be used to call the matcher with a partial match
46 * even if the specific class of the matcher or the match is unknown.
47 *
48 * @return the empty match
49 */
50 public abstract IPatternMatch newEmptyMatch();
51
52 /**
53 * Returns a new (partial) Match object compatible with matchers of this query.
54 * This can be used e.g. to call the matcher with a partial
55 * match.
56 *
57 * <p>The returned match will be immutable. Use {@link #newEmptyMatch()} to obtain a mutable match object.
58 *
59 * @param parameters
60 * the fixed value of pattern parameters, or null if not bound.
61 * @return the (partial) match object.
62 */
63 public abstract IPatternMatch newMatch(Object... parameters);
64
65 /**
66 * The query is formulated over this kind of modeling platform.
67 * E.g. for queries over EMF models, the {@link EMFScope} class is returned.
68 */
69 public Class<? extends QueryScope> getPreferredScopeClass();
70
71 /**
72 * Returns the definition of the query in a format intended for consumption by the query evaluator.
73 * @return the internal representation of the query.
74 */
75 public PQuery getInternalQueryRepresentation();
76
77 /**
78 * Creates a new uninitialized matcher, which is not functional until an engine initializes it. Clients
79 * should not call this method, it is used by the {@link ViatraQueryEngine} instance to instantiate matchers.
80 * @throws ViatraQueryRuntimeException
81 * @noreference This method is not intended to be referenced by clients.
82 * @since 1.4
83 */
84 public Matcher instantiate();
85
86}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/MatchUpdateAdapter.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/MatchUpdateAdapter.java
new file mode 100644
index 00000000..7de6d2c6
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/MatchUpdateAdapter.java
@@ -0,0 +1,105 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, 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.api;
10
11import java.util.function.Consumer;
12
13/**
14 * A default implementation of {@link IMatchUpdateListener} that contains two match processors, one for appearance, one
15 * for disappearance. Any of the two can be null; in this case, corresponding notifications will be ignored.
16 *
17 * <p>
18 * Instantiate using either constructor.
19 *
20 * @author Bergmann Gabor
21 *
22 */
23public class MatchUpdateAdapter<Match extends IPatternMatch> implements IMatchUpdateListener<Match> {
24
25 Consumer<Match> appearCallback;
26 Consumer<Match> disappearCallback;
27
28 /**
29 * Constructs an instance without any match processors registered yet.
30 *
31 * Use {@link #setAppearCallback(Consumer)} and {@link #setDisappearCallback(Consumer)} to specify
32 * optional match processors for match appearance and disappearance, respectively.
33 */
34 public MatchUpdateAdapter() {
35 super();
36 }
37
38 /**
39 * Constructs an instance by specifying match processors.
40 *
41 * @param appearCallback
42 * a match processor that will be invoked on each new match that appears. If null, no callback will be
43 * executed on match appearance. See {@link Consumer} for details on how to implement.
44 * @param disappearCallback
45 * a match processor that will be invoked on each existing match that disappears. If null, no callback
46 * will be executed on match disappearance. See {@link Consumer} for details on how to implement.
47 * @since 2.0
48 */
49 public MatchUpdateAdapter(Consumer<Match> appearCallback, Consumer<Match> disappearCallback) {
50 super();
51 setAppearCallback(appearCallback);
52 setDisappearCallback(disappearCallback);
53 }
54
55 /**
56 * @return the match processor that will be invoked on each new match that appears. If null, no callback will be
57 * executed on match appearance.
58 * @since 2.0
59 */
60 public Consumer<Match> getAppearCallback() {
61 return appearCallback;
62 }
63
64 /**
65 * @param appearCallback
66 * a match processor that will be invoked on each new match that appears. If null, no callback will be
67 * executed on match appearance. See {@link Consumer} for details on how to implement.
68 * @since 2.0
69 */
70 public void setAppearCallback(Consumer<Match> appearCallback) {
71 this.appearCallback = appearCallback;
72 }
73
74 /**
75 * @return the match processor that will be invoked on each existing match that disappears. If null, no callback
76 * will be executed on match disappearance.
77 * @since 2.0
78 */
79 public Consumer<Match> getDisappearCallback() {
80 return disappearCallback;
81 }
82
83 /**
84 * @param disappearCallback
85 * a match processor that will be invoked on each existing match that disappears. If null, no callback
86 * will be executed on match disappearance. See {@link Consumer} for details on how to implement.
87 * @since 2.0
88 */
89 public void setDisappearCallback(Consumer<Match> disappearCallback) {
90 this.disappearCallback = disappearCallback;
91 }
92
93 @Override
94 public void notifyAppearance(Match match) {
95 if (appearCallback != null)
96 appearCallback.accept(match);
97 }
98
99 @Override
100 public void notifyDisappearance(Match match) {
101 if (disappearCallback != null)
102 disappearCallback.accept(match);
103 }
104
105}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngine.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngine.java
new file mode 100644
index 00000000..0f402b49
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngine.java
@@ -0,0 +1,153 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools>
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v. 2.0 which is available at
6 * http://www.eclipse.org/legal/epl-v20.html.
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *******************************************************************************/
10
11package tools.refinery.viatra.runtime.api;
12
13import tools.refinery.viatra.runtime.api.scope.IBaseIndex;
14import tools.refinery.viatra.runtime.api.scope.QueryScope;
15import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
16
17import java.util.Set;
18import java.util.function.Supplier;
19import java.util.stream.Collectors;
20
21/**
22 * A Viatra Query (incremental) evaluation engine, attached to a model such as an EMF resource. The engine hosts pattern matchers, and
23 * will listen on model update notifications stemming from the given model in order to maintain live results.
24 *
25 * <p>
26 * By default, ViatraQueryEngines do not need to be separately disposed; they will be garbage collected along with the model.
27 * Advanced users: see {@link AdvancedViatraQueryEngine} if you want fine control over the lifecycle of an engine.
28 *
29 * <p>
30 * Pattern matchers within this engine may be instantiated in the following ways:
31 * <ul>
32 * <li>Recommended: instantiate the specific matcher class generated for the pattern by e.g. MyPatternMatcher.on(engine).
33 * <li>Use {@link #getMatcher(IQuerySpecification)} if the pattern-specific generated matcher API is not available.
34 * <li>Advanced: use the query specification associated with the generated matcher class to achieve the same.
35 * </ul>
36 * Additionally, a group of patterns (see {@link IQueryGroup}) can be initialized together before usage; this may improve
37 * the performance of pattern matcher construction by trying to gather all necessary information from the model in one go.
38 * Note that no such improvement is to be expected if the engine is specifically constructed in wildcard mode,
39 * an option available in some scope implementations
40 * (see {@link EMFScope#EMFScope(Notifier, BaseIndexOptions)} and {@link BaseIndexOptions#withWildcardMode(boolean)}).
41 *
42 *
43 * @author Bergmann Gábor
44 * @noextend This class is not intended to be subclassed by clients.
45 */
46public abstract class ViatraQueryEngine {
47
48
49 /**
50 * Obtain a (managed) {@link ViatraQueryEngine} to evaluate queries over a given scope specified by an {@link QueryScope}.
51 *
52 * <p> For a given matcher scope, the same engine will be returned to any client.
53 * This facilitates the reuse of internal caches of the engine, greatly improving performance.
54 *
55 * <p> The lifecycle of this engine is centrally managed, and will not be disposed as long as the model is retained in memory.
56 * The engine will be garbage collected along with the model.
57 *
58 * <p>
59 * Advanced users: see {@link AdvancedViatraQueryEngine#createUnmanagedEngine(QueryScope)} to obtain a private,
60 * unmanaged engine that is not shared with other clients and allows tight control over its lifecycle.
61 *
62 * @param scope
63 * the scope of query evaluation; the definition of the set of model elements that this engine is operates on.
64 * Provide e.g. a {@link EMFScope} for evaluating queries on an EMF model.
65 * @return a (managed) {@link ViatraQueryEngine} instance
66 */
67 public static ViatraQueryEngine on(QueryScope scope) {
68 return ViatraQueryEngineManager.getInstance().getQueryEngine(scope);
69 }
70
71 /**
72 * Obtain a (managed) {@link ViatraQueryEngine} to evaluate queries over a given scope specified by an {@link QueryScope}.
73 *
74 * <p> For a given matcher scope, the same engine will be returned to any client.
75 * This facilitates the reuse of internal caches of the engine, greatly improving performance.
76 *
77 * <p> The lifecycle of this engine is centrally managed, and will not be disposed as long as the model is retained in memory.
78 * The engine will be garbage collected along with the model.
79 *
80 * <p>
81 * Advanced users: see {@link AdvancedViatraQueryEngine#createUnmanagedEngine(QueryScope)} to obtain a private,
82 * unmanaged engine that is not shared with other clients and allows tight control over its lifecycle.
83 *
84 * @param scope
85 * the scope of query evaluation; the definition of the set of model elements that this engine is operates on.
86 * Provide e.g. a {@link EMFScope} for evaluating queries on an EMF model.
87 * @return a (managed) {@link ViatraQueryEngine} instance
88 * @since 1.4
89 */
90 public static ViatraQueryEngine on(QueryScope scope, ViatraQueryEngineOptions options) {
91 return ViatraQueryEngineManager.getInstance().getQueryEngine(scope, options);
92 }
93
94 /**
95 * Provides access to the internal base index component of the engine, responsible for keeping track of basic
96 * contents of the model.
97 *
98 * <p>If using an {@link EMFScope},
99 * consider {@link EMFScope#extractUnderlyingEMFIndex(ViatraQueryEngine)} instead to access EMF-specific details.
100 *
101 * @return the baseIndex the NavigationHelper maintaining the base index
102 * @throws ViatraQueryRuntimeException
103 * if the base index could not be constructed
104 */
105 public abstract IBaseIndex getBaseIndex();
106
107 /**
108 * Access a pattern matcher based on a {@link IQuerySpecification}.
109 * Multiple calls will return the same matcher.
110 * @param querySpecification a {@link IQuerySpecification} that describes a VIATRA query specification
111 * @return a pattern matcher corresponding to the specification
112 * @throws ViatraQueryRuntimeException if the matcher could not be initialized
113 */
114 public abstract <Matcher extends ViatraQueryMatcher<? extends IPatternMatch>> Matcher getMatcher(IQuerySpecification<Matcher> querySpecification);
115
116 /**
117 * Access a pattern matcher for the graph pattern with the given fully qualified name.
118 * Will succeed only if a query specification for this fully qualified name has been generated and registered.
119 * Multiple calls will return the same matcher unless the registered specification changes.
120 *
121 * @param patternFQN the fully qualified name of a VIATRA query specification
122 * @return a pattern matcher corresponding to the specification
123 * @throws ViatraQueryRuntimeException if the matcher could not be initialized
124 */
125 public abstract ViatraQueryMatcher<? extends IPatternMatch> getMatcher(String patternFQN);
126
127 /**
128 * Access an existing pattern matcher based on a {@link IQuerySpecification}.
129 * @param querySpecification a {@link IQuerySpecification} that describes a VIATRA query specification
130 * @return a pattern matcher corresponding to the specification, <code>null</code> if a matcher does not exist yet.
131 */
132 public abstract <Matcher extends ViatraQueryMatcher<? extends IPatternMatch>> Matcher getExistingMatcher(IQuerySpecification<Matcher> querySpecification);
133
134
135 /**
136 * Access a copy of available {@link ViatraQueryMatcher} pattern matchers.
137 * @return a copy of the set of currently available pattern matchers registered on this engine instance
138 */
139 public abstract Set<? extends ViatraQueryMatcher<? extends IPatternMatch>> getCurrentMatchers();
140
141 public Set<IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>>> getRegisteredQuerySpecifications() {
142 return getCurrentMatchers().stream().map(ViatraQueryMatcher::getSpecification).collect(Collectors.toSet());
143 }
144
145 /**
146 * @return the scope of query evaluation; the definition of the set of model elements that this engine is operates on.
147 */
148 public abstract QueryScope getScope();
149
150 public abstract void flushChanges();
151
152 public abstract <T> T withFlushingChanges(Supplier<T> supplier);
153}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineInitializationListener.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineInitializationListener.java
new file mode 100644
index 00000000..02162a65
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineInitializationListener.java
@@ -0,0 +1,26 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Abel Hegedus, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.api;
10
11/**
12 * Listener interface to get notifications when a new managed engine is initialized.
13 *
14 * @author Abel Hegedus
15 *
16 */
17public interface ViatraQueryEngineInitializationListener {
18
19 /**
20 * Called when a managed engine is initialized in the EngineManager.
21 *
22 * @param engine the initialized engine
23 */
24 void engineInitialized(AdvancedViatraQueryEngine engine);
25
26}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineLifecycleListener.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineLifecycleListener.java
new file mode 100644
index 00000000..1c4dc264
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineLifecycleListener.java
@@ -0,0 +1,52 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Abel Hegedus, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.api;
10
11
12/**
13 * Listener interface for getting notification on changes in an {@link ViatraQueryEngine}.
14 *
15 * You can use it to remove any other listeners that you attached to matchers or the engine,
16 * or to handle matchers that are initialized after you started using the engine.
17 *
18 * @author Abel Hegedus
19 *
20 */
21public interface ViatraQueryEngineLifecycleListener {
22
23 // -------------------------------------------------------------------------------
24 // MATCHERS (methods notifying on changes in the matchers available in the engine)
25 // -------------------------------------------------------------------------------
26
27 /**
28 * Called after a matcher is instantiated in the engine
29 *
30 * @param matcher the new matcher
31 */
32 void matcherInstantiated(ViatraQueryMatcher<? extends IPatternMatch> matcher);
33
34 // -------------------------------------------------------------------------
35 // HEALTH (methods notifying on changes that affect the health of the engine
36 // -------------------------------------------------------------------------
37
38 /**
39 * Called after the engine has become tainted due to a fatal error
40 */
41 void engineBecameTainted(String message, Throwable t);
42
43 /**
44 * Called after the engine has been wiped
45 */
46 void engineWiped();
47
48 /**
49 * Called after the engine has been disposed
50 */
51 void engineDisposed();
52}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineManager.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineManager.java
new file mode 100644
index 00000000..4a256aea
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineManager.java
@@ -0,0 +1,191 @@
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.api;
11
12import tools.refinery.viatra.runtime.api.scope.QueryScope;
13import tools.refinery.viatra.runtime.internal.apiimpl.ViatraQueryEngineImpl;
14import tools.refinery.viatra.runtime.util.ViatraQueryLoggingUtil;
15
16import java.lang.ref.WeakReference;
17import java.util.*;
18
19import static tools.refinery.viatra.runtime.matchers.util.Preconditions.checkArgument;
20
21/**
22 * Global registry of active VIATRA Query Engines.
23 *
24 * <p>
25 * Manages an {@link ViatraQueryEngine} for each model (more precisely scope), that is created on demand. Managed engines are shared between
26 * clients querying the same model.
27 *
28 * <p>
29 * It is also possible to create private, unmanaged engines that are not shared between clients.
30 *
31 * <p>
32 * Only weak references are retained on the managed engines. So if there are no other references to the matchers or the
33 * engine, they can eventually be GC'ed, and they won't block the model from being GC'ed either.
34 *
35 *
36 * @author Bergmann Gabor
37 *
38 */
39public class ViatraQueryEngineManager {
40 private static ViatraQueryEngineManager instance = new ViatraQueryEngineManager();
41
42
43 /**
44 * @return the singleton instance
45 */
46 public static ViatraQueryEngineManager getInstance() {
47 return instance;
48 }
49
50 /**
51 * The engine manager keeps track of the managed engines via weak references only, so it will not keep unused
52 * managed engines from being garbage collected. Still, as long as the user keeps the model in memory, the
53 * associated managed engine will not be garbage collected, as it is expected to be strongly reachable from the
54 * model via the scope-specific base index or change notification listeners (see
55 * {@link BaseIndexListener#iqEngine}).
56 */
57 Map<QueryScope, WeakReference<ViatraQueryEngineImpl>> engines;
58
59 ViatraQueryEngineManager() {
60 super();
61 engines = new WeakHashMap<QueryScope, WeakReference<ViatraQueryEngineImpl>>();
62 initializationListeners = new HashSet<ViatraQueryEngineInitializationListener>();
63 }
64
65 /**
66 * Creates a managed VIATRA Query Engine at a given scope (e.g. an EMF Resource or ResourceSet, as in {@link EMFScope})
67 * or retrieves an already existing one. Repeated invocations for a single model root will return the same engine.
68 * Consequently, the engine will be reused between different clients querying the same model, providing performance benefits.
69 *
70 * <p>
71 * The match set of any patterns will be incrementally refreshed upon updates from this scope.
72 *
73 * @param scope
74 * the scope of query evaluation; the definition of the set of model elements that this engine is operates on.
75 * Provide e.g. a {@link EMFScope} for evaluating queries on an EMF model.
76 * @return a new or previously existing engine
77 */
78 public ViatraQueryEngine getQueryEngine(QueryScope scope) {
79 return getQueryEngine(scope, ViatraQueryEngineOptions.getDefault());
80 }
81
82 /**
83 * Creates a managed VIATRA Query Engine at a given scope (e.g. an EMF Resource or ResourceSet, as in {@link EMFScope})
84 * or retrieves an already existing one. Repeated invocations for a single model root will return the same engine.
85 * Consequently, the engine will be reused between different clients querying the same model, providing performance benefits.
86 *
87 * <p>
88 * The match set of any patterns will be incrementally refreshed upon updates from this scope.
89 *
90 * @param scope
91 * the scope of query evaluation; the definition of the set of model elements that this engine is operates on.
92 * Provide e.g. a {@link EMFScope} for evaluating queries on an EMF model.
93 * @return a new or previously existing engine
94 * @since 1.4
95 */
96 public ViatraQueryEngine getQueryEngine(QueryScope scope, ViatraQueryEngineOptions options) {
97 ViatraQueryEngineImpl engine = getEngineInternal(scope);
98 if (engine == null) {
99 engine = new ViatraQueryEngineImpl(this, scope, options);
100 engines.put(scope, new WeakReference<ViatraQueryEngineImpl>(engine));
101 notifyInitializationListeners(engine);
102 }
103 return engine;
104 }
105
106 /**
107 * Retrieves an already existing managed VIATRA Query Engine.
108 *
109 * @param scope
110 * the scope of query evaluation; the definition of the set of model elements that this engine is operates on.
111 * Provide e.g. a {@link EMFScope} for evaluating queries on an EMF model.
112 * @return a previously existing engine, or null if no engine is active for the given EMF model root
113 */
114 public ViatraQueryEngine getQueryEngineIfExists(QueryScope scope) {
115 return getEngineInternal(scope);
116 }
117
118 /**
119 * Collects all {@link ViatraQueryEngine} instances that still exist.
120 *
121 * @return set of engines if there is any, otherwise EMTPY_SET
122 */
123 public Set<ViatraQueryEngine> getExistingQueryEngines(){
124 Set<ViatraQueryEngine> existingEngines = null;
125 for (WeakReference<ViatraQueryEngineImpl> engineRef : engines.values()) {
126 AdvancedViatraQueryEngine engine = engineRef == null ? null : engineRef.get();
127 if(existingEngines == null) {
128 existingEngines = new HashSet<>();
129 }
130 existingEngines.add(engine);
131 }
132 if(existingEngines == null) {
133 existingEngines = Collections.emptySet();
134 }
135 return existingEngines;
136 }
137
138 private final Set<ViatraQueryEngineInitializationListener> initializationListeners;
139
140 /**
141 * Registers a listener for new engine initialization.
142 *
143 * <p/> For removal, use {@link #removeQueryEngineInitializationListener}
144 *
145 * @param listener the listener to register
146 */
147 public void addQueryEngineInitializationListener(ViatraQueryEngineInitializationListener listener) {
148 checkArgument(listener != null, "Cannot add null listener!");
149 initializationListeners.add(listener);
150 }
151
152 /**
153 * Removes a registered listener added with {@link #addQueryEngineInitializationListener}
154 *
155 * @param listener
156 */
157 public void removeQueryEngineInitializationListener(ViatraQueryEngineInitializationListener listener) {
158 checkArgument(listener != null, "Cannot remove null listener!");
159 initializationListeners.remove(listener);
160 }
161
162 /**
163 * Notifies listeners that a new engine has been initialized.
164 *
165 * @param engine the initialized engine
166 */
167 protected void notifyInitializationListeners(AdvancedViatraQueryEngine engine) {
168 try {
169 if (!initializationListeners.isEmpty()) {
170 for (ViatraQueryEngineInitializationListener listener : new HashSet<>(initializationListeners)) {
171 listener.engineInitialized(engine);
172 }
173 }
174 } catch (Exception ex) {
175 ViatraQueryLoggingUtil.getLogger(getClass()).fatal(
176 "VIATRA Query Engine Manager encountered an error in delivering notifications"
177 + " about engine initialization. ", ex);
178 }
179 }
180
181 /**
182 * @param emfRoot
183 * @return
184 */
185 private ViatraQueryEngineImpl getEngineInternal(QueryScope scope) {
186 final WeakReference<ViatraQueryEngineImpl> engineRef = engines.get(scope);
187 ViatraQueryEngineImpl engine = engineRef == null ? null : engineRef.get();
188 return engine;
189 }
190
191}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineOptions.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineOptions.java
new file mode 100644
index 00000000..15bf1f91
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryEngineOptions.java
@@ -0,0 +1,293 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Balázs Grill, 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.api;
10
11
12import java.util.Objects;
13import java.util.ServiceLoader;
14
15import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendFactory;
16import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendFactoryProvider;
17import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
18import tools.refinery.viatra.runtime.matchers.util.Preconditions;
19
20/**
21 * This class is intended to provide options to a created {@link ViatraQueryEngine} instance. The {@link #DEFAULT}
22 * instance represents the configuration that is selected when no explicit options are provided by the user. To create
23 * new configurations, use the static builder methods {@link #defineOptions()} (starts with empty options) or
24 * {@link #copyOptions(ViatraQueryEngineOptions)} (starts with all options from an existing configuration).
25 *
26 * @author Balázs Grill, Zoltan Ujhelyi
27 * @since 1.4
28 *
29 */
30public final class ViatraQueryEngineOptions {
31
32 private static boolean areSystemDefaultsCalculated = false;
33 private static IQueryBackendFactory systemDefaultBackendFactory;
34 private static IQueryBackendFactory systemDefaultCachingBackendFactory;
35 private static IQueryBackendFactory systemDefaultSearchBackendFactory;
36
37 /**
38 * @since 2.0
39 */
40 public static void setSystemDefaultBackends(IQueryBackendFactory systemDefaultBackendFactory,
41 IQueryBackendFactory systemDefaultCachingBackendFactory,
42 IQueryBackendFactory systemDefaultSearchBackendFactory) {
43 areSystemDefaultsCalculated = true;
44 ViatraQueryEngineOptions.systemDefaultBackendFactory = systemDefaultBackendFactory;
45 ViatraQueryEngineOptions.systemDefaultCachingBackendFactory = systemDefaultCachingBackendFactory;
46 ViatraQueryEngineOptions.systemDefaultSearchBackendFactory = systemDefaultSearchBackendFactory;
47 }
48
49 /**
50 * If {@link #setSystemDefaultBackends(IQueryBackendFactory, IQueryBackendFactory, IQueryBackendFactory)} is not
51 * called, this method is responsible of finding the corresponding backends on the classpath using Java Service
52 * loaders.
53 */
54 private static void calculateSystemDefaultBackends() {
55 for (IQueryBackendFactoryProvider provider : ServiceLoader.load(IQueryBackendFactoryProvider.class)) {
56 if (provider.isSystemDefaultEngine()) {
57 systemDefaultBackendFactory = provider.getFactory();
58 }
59 if (provider.isSystemDefaultCachingBackend()) {
60 systemDefaultCachingBackendFactory = provider.getFactory();
61 }
62 if (provider.isSystemDefaultSearchBackend()) {
63 systemDefaultSearchBackendFactory = provider.getFactory();
64 }
65 }
66 areSystemDefaultsCalculated = true;
67 }
68
69 private static IQueryBackendFactory getSystemDefaultBackend() {
70 if (!areSystemDefaultsCalculated) {
71 calculateSystemDefaultBackends();
72 }
73 return Objects.requireNonNull(systemDefaultBackendFactory, "System default backend not found");
74 }
75
76 private static IQueryBackendFactory getSystemDefaultCachingBackend() {
77 if (!areSystemDefaultsCalculated) {
78 calculateSystemDefaultBackends();
79 }
80 return Objects.requireNonNull(systemDefaultCachingBackendFactory, "System default caching backend not found");
81 }
82
83 private static IQueryBackendFactory getSystemDefaultSearchBackend() {
84 if (!areSystemDefaultsCalculated) {
85 calculateSystemDefaultBackends();
86 }
87 return Objects.requireNonNull(systemDefaultSearchBackendFactory, "System default search backend not found");
88 }
89
90 private final QueryEvaluationHint engineDefaultHints;
91
92 private final IQueryBackendFactory defaultCachingBackendFactory;
93 private final IQueryBackendFactory defaultSearchBackendFactory;
94
95 /** The default engine options; if options are not defined, this version will be used. */
96 private static ViatraQueryEngineOptions DEFAULT;
97
98 /**
99 * @since 2.0
100 */
101 public static final ViatraQueryEngineOptions getDefault() {
102 if (DEFAULT == null) {
103 DEFAULT = new Builder().build();
104 }
105 return DEFAULT;
106 }
107
108 public static final class Builder {
109 private QueryEvaluationHint engineDefaultHints;
110
111 private IQueryBackendFactory defaultBackendFactory;
112 private IQueryBackendFactory defaultCachingBackendFactory;
113 private IQueryBackendFactory defaultSearchBackendFactory;
114
115 public Builder() {
116
117 }
118
119 public Builder(ViatraQueryEngineOptions from) {
120 this.engineDefaultHints = from.engineDefaultHints;
121 this.defaultBackendFactory = engineDefaultHints.getQueryBackendFactory();
122 this.defaultCachingBackendFactory = from.defaultCachingBackendFactory;
123 this.defaultSearchBackendFactory = from.defaultSearchBackendFactory;
124 }
125
126 /**
127 * Note that the backend factory in the hint is overridden by a factory added with
128 * {@link #withDefaultBackend(IQueryBackendFactory)}.
129 */
130 public Builder withDefaultHint(QueryEvaluationHint engineDefaultHints) {
131 this.engineDefaultHints = engineDefaultHints;
132 return this;
133 }
134
135 /**
136 * Note that this backend factory overrides the factory defined by the hint added by
137 * {@link #withDefaultHint(QueryEvaluationHint)}.
138 */
139 public Builder withDefaultBackend(IQueryBackendFactory defaultBackendFactory) {
140 this.defaultBackendFactory = defaultBackendFactory;
141 return this;
142 }
143
144 /**
145 * @since 2.0
146 */
147 public Builder withDefaultSearchBackend(IQueryBackendFactory defaultSearchBackendFactory) {
148 Preconditions.checkArgument(!defaultSearchBackendFactory.isCaching(), "%s is not a search backend", defaultSearchBackendFactory.getClass());
149 this.defaultSearchBackendFactory = defaultSearchBackendFactory;
150 return this;
151 }
152
153 public Builder withDefaultCachingBackend(IQueryBackendFactory defaultCachingBackendFactory) {
154 Preconditions.checkArgument(defaultCachingBackendFactory.isCaching(), "%s is not a caching backend", defaultCachingBackendFactory.getClass());
155 this.defaultCachingBackendFactory = defaultCachingBackendFactory;
156 return this;
157 }
158
159 public ViatraQueryEngineOptions build() {
160 IQueryBackendFactory defaultFactory = getDefaultBackend();
161 QueryEvaluationHint hint = getEngineDefaultHints(defaultFactory);
162 return new ViatraQueryEngineOptions(hint, getDefaultCachingBackend(), getDefaultSearchBackend());
163 }
164
165 private IQueryBackendFactory getDefaultBackend() {
166 if (defaultBackendFactory != null){
167 return defaultBackendFactory;
168 } else if (engineDefaultHints != null) {
169 return engineDefaultHints.getQueryBackendFactory();
170 } else {
171 return getSystemDefaultBackend();
172 }
173 }
174
175 private IQueryBackendFactory getDefaultCachingBackend() {
176 if (defaultCachingBackendFactory != null) {
177 return defaultCachingBackendFactory;
178 } else if (defaultBackendFactory != null && defaultBackendFactory.isCaching()) {
179 return defaultBackendFactory;
180 } else {
181 return getSystemDefaultCachingBackend();
182 }
183 }
184
185 private IQueryBackendFactory getDefaultSearchBackend() {
186 if (defaultSearchBackendFactory != null) {
187 return defaultSearchBackendFactory;
188 } else if (defaultBackendFactory != null && !defaultBackendFactory.isCaching()) {
189 return defaultBackendFactory;
190 } else {
191 return getSystemDefaultSearchBackend();
192 }
193 }
194
195 private QueryEvaluationHint getEngineDefaultHints(IQueryBackendFactory defaultFactory) {
196 if (engineDefaultHints != null){
197 return engineDefaultHints.overrideBy(new QueryEvaluationHint(null, defaultFactory));
198 } else {
199 return new QueryEvaluationHint(null, defaultFactory);
200 }
201 }
202 }
203
204 /**
205 * Initializes an option builder with no previously set options.
206 */
207 public static Builder defineOptions() {
208 return new Builder();
209 }
210
211 /**
212 * Initializes an option builder with settings from an existing configuration.
213 */
214 public static Builder copyOptions(ViatraQueryEngineOptions options) {
215 return new Builder(options);
216 }
217
218 private ViatraQueryEngineOptions(QueryEvaluationHint engineDefaultHints,
219 IQueryBackendFactory defaultCachingBackendFactory, IQueryBackendFactory defaultSearchBackendFactory) {
220 this.engineDefaultHints = engineDefaultHints;
221 this.defaultCachingBackendFactory = defaultCachingBackendFactory;
222 this.defaultSearchBackendFactory = defaultSearchBackendFactory;
223 }
224
225 public QueryEvaluationHint getEngineDefaultHints() {
226 return engineDefaultHints;
227 }
228
229 /**
230 * Returns the configured default backend
231 *
232 * @return the defaultBackendFactory
233 */
234 public IQueryBackendFactory getDefaultBackendFactory() {
235 switch (engineDefaultHints.getQueryBackendRequirementType()) {
236 case DEFAULT_CACHING:
237 return ViatraQueryEngineOptions.getSystemDefaultCachingBackend();
238 case DEFAULT_SEARCH:
239 return ViatraQueryEngineOptions.getSystemDefaultCachingBackend();
240 case SPECIFIC:
241 return engineDefaultHints.getQueryBackendFactory();
242 case UNSPECIFIED:
243 default:
244 return ViatraQueryEngineOptions.getSystemDefaultBackend();
245 }
246 }
247
248 /**
249 * Returns the configured default caching backend. If the default backend caches matches, it is usually expected, but
250 * not mandatory for the two default backends to be the same.
251 */
252 public IQueryBackendFactory getDefaultCachingBackendFactory() {
253 return defaultCachingBackendFactory;
254 }
255
256 /**
257 * Returns the configured default search-based backend. If the default backend is search-based, it is usually expected, but
258 * not mandatory for the two default backends to be the same.
259 * @since 2.0
260 */
261 public IQueryBackendFactory getDefaultSearchBackendFactory() {
262 return defaultSearchBackendFactory;
263 }
264
265 @Override
266 public String toString() {
267 // TODO defaultCachingBackendFactory is ignored
268 if(Objects.equals(engineDefaultHints, DEFAULT.engineDefaultHints))
269 return "defaults";
270 else
271 return engineDefaultHints.toString();
272 }
273
274 /**
275 * @since 2.0
276 */
277 public IQueryBackendFactory getQueryBackendFactory(QueryEvaluationHint hint) {
278 if (hint == null) {
279 return getDefaultBackendFactory();
280 }
281
282 switch (hint.getQueryBackendRequirementType()) {
283 case DEFAULT_CACHING:
284 return getDefaultCachingBackendFactory();
285 case DEFAULT_SEARCH:
286 return getDefaultSearchBackendFactory();
287 case SPECIFIC:
288 return hint.getQueryBackendFactory();
289 default:
290 return getDefaultBackendFactory();
291 }
292 }
293}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryMatcher.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryMatcher.java
new file mode 100644
index 00000000..1ae0c96f
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryMatcher.java
@@ -0,0 +1,258 @@
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.api;
11
12import java.util.Collection;
13import java.util.List;
14import java.util.Optional;
15import java.util.Set;
16import java.util.function.Consumer;
17import java.util.stream.Stream;
18
19/**
20 * Interface for a VIATRA Query matcher associated with a graph pattern.
21 *
22 * @param <Match>
23 * the IPatternMatch type representing a single match of this pattern.
24 * @author Bergmann Gábor
25 * @noimplement This interface is not intended to be implemented by clients. Implement BaseMatcher instead.
26 */
27public interface ViatraQueryMatcher<Match extends IPatternMatch> {
28 // REFLECTION
29 /** The pattern that will be matched. */
30 IQuerySpecification<? extends ViatraQueryMatcher<Match>> getSpecification();
31
32 /** Fully qualified name of the pattern. */
33 String getPatternName();
34
35 /** Returns the index of the symbolic parameter with the given name. */
36 Integer getPositionOfParameter(String parameterName);
37
38 /** Returns the array of symbolic parameter names. */
39 List<String> getParameterNames();
40
41 // ALL MATCHES
42 /**
43 * Returns the set of all pattern matches.
44 *
45 * @return matches represented as a Match object.
46 */
47 Collection<Match> getAllMatches();
48
49 /**
50 * Returns the set of all matches of the pattern that conform to the given fixed values of some parameters.
51 *
52 * @param partialMatch
53 * a partial match of the pattern where each non-null field binds the corresponding pattern parameter to
54 * a fixed value.
55 * @return matches represented as a Match object.
56 */
57 Collection<Match> getAllMatches(Match partialMatch);
58
59 /**
60 * Returns a stream of all pattern matches.
61 * <p>
62 * <strong>WARNING</strong> If the result set changes while the stream is evaluated, the set of matches included in
63 * the stream are unspecified. In such cases, either rely on {@link #getAllMatches()} or collect the results of the
64 * stream in end-user code.
65 *
66 * @return matches represented as a Match object.
67 * @since 2.0
68 */
69 Stream<Match> streamAllMatches();
70
71 /**
72 * Returns a stream of all matches of the pattern that conform to the given fixed values of some parameters.
73 * <p>
74 * <strong>WARNING</strong> If the result set changes while the stream is evaluated, the set of matches included in
75 * the stream are unspecified. In such cases, either rely on {@link #getAllMatches()} or collect the results of the
76 * stream in end-user code.
77 *
78 * @param partialMatch
79 * a partial match of the pattern where each non-null field binds the corresponding pattern parameter to
80 * a fixed value.
81 * @return matches represented as a Match object.
82 * @since 2.0
83 */
84 Stream<Match> streamAllMatches(Match partialMatch);
85
86 // variant(s) with input binding as pattern-specific parameters: not declared in interface
87
88 // SINGLE MATCH
89 /**
90 * Returns an arbitrarily chosen pattern match. Neither determinism nor randomness of selection is guaranteed.
91 *
92 * @return a match represented as a Match object, or an empty Optional if no match is found.
93 * @since 2.0
94 */
95 Optional<Match> getOneArbitraryMatch();
96
97 /**
98 * Returns an arbitrarily chosen match of the pattern that conforms to the given fixed values of some parameters.
99 * Neither determinism nor randomness of selection is guaranteed.
100 *
101 * @param partialMatch
102 * a partial match of the pattern where each non-null field binds the corresponding pattern parameter to
103 * a fixed value.
104 * @return a match represented as a Match object, or an empty Optional if no match is found.
105 * @since 2.0
106 */
107 Optional<Match> getOneArbitraryMatch(Match partialMatch);
108
109 // variant(s) with input binding as pattern-specific parameters: not declared in interface
110
111 // MATCH CHECKING
112 /**
113 * Indicates whether the query has any kind of matches.
114 *
115 * @return true if there exists a valid match of the pattern.
116 * @since 1.7
117 */
118 boolean hasMatch();
119
120 /**
121 * Indicates whether the given combination of specified pattern parameters constitute a valid pattern match, under
122 * any possible substitution of the unspecified parameters (if any).
123 *
124 * @param partialMatch
125 * a (partial) match of the pattern where each non-null field binds the corresponding pattern parameter
126 * to a fixed value.
127 * @return true if the input is a valid (partial) match of the pattern.
128 */
129 boolean hasMatch(Match partialMatch);
130
131 // variant(s) with input binding as pattern-specific parameters: not declared in interface
132
133 // NUMBER OF MATCHES
134 /**
135 * Returns the number of all pattern matches.
136 *
137 * @return the number of pattern matches found.
138 */
139 int countMatches();
140
141 /**
142 * Returns the number of all matches of the pattern that conform to the given fixed values of some parameters.
143 *
144 * @param partialMatch
145 * a partial match of the pattern where each non-null field binds the corresponding pattern parameter to
146 * a fixed value.
147 * @return the number of pattern matches found.
148 */
149 int countMatches(Match partialMatch);
150
151 // variant(s) with input binding as pattern-specific parameters: not declared in interface
152
153 // FOR EACH MATCH
154 /**
155 * Executes the given processor on each match of the pattern.
156 *
157 * @param processor
158 * the action that will process each pattern match.
159 * @since 2.0
160 */
161 void forEachMatch(Consumer<? super Match> processor);
162
163 /**
164 * Executes the given processor on each match of the pattern that conforms to the given fixed values of some
165 * parameters.
166 *
167 * @param partialMatch
168 * array where each non-null element binds the corresponding pattern parameter to a fixed value.
169 * @param processor
170 * the action that will process each pattern match.
171 * @since 2.0
172 */
173 void forEachMatch(Match partialMatch, Consumer<? super Match> processor);
174
175 // variant(s) with input binding as pattern-specific parameters: not declared in interface
176
177 // FOR ONE ARBITRARY MATCH
178 /**
179 * Executes the given processor on an arbitrarily chosen match of the pattern. Neither determinism nor randomness of
180 * selection is guaranteed.
181 *
182 * @param processor
183 * the action that will process the selected match.
184 * @return true if the pattern has at least one match, false if the processor was not invoked
185 * @since 2.0
186 */
187 boolean forOneArbitraryMatch(Consumer<? super Match> processor);
188
189 /**
190 * Executes the given processor on an arbitrarily chosen match of the pattern that conforms to the given fixed
191 * values of some parameters. Neither determinism nor randomness of selection is guaranteed.
192 *
193 * @param partialMatch
194 * array where each non-null element binds the corresponding pattern parameter to a fixed value.
195 * @param processor
196 * the action that will process the selected match.
197 * @return true if the pattern has at least one match with the given parameter values, false if the processor was
198 * not invoked
199 * @since 2.0
200 */
201 boolean forOneArbitraryMatch(Match partialMatch, Consumer<? super Match> processor);
202
203 // variant(s) with input binding as pattern-specific parameters: not declared in interface
204
205 /**
206 * Returns an empty, mutable Match for the matcher.
207 * Fields of the mutable match can be filled to create a partial match, usable as matcher input.
208 * This can be used to call the matcher with a partial match
209 * even if the specific class of the matcher or the match is unknown.
210 *
211 * @return the empty match
212 */
213 Match newEmptyMatch();
214
215 /**
216 * Returns a new (partial) Match object for the matcher.
217 * This can be used e.g. to call the matcher with a partial
218 * match.
219 *
220 * <p>The returned match will be immutable. Use {@link #newEmptyMatch()} to obtain a mutable match object.
221 *
222 * @param parameters
223 * the fixed value of pattern parameters, or null if not bound.
224 * @return the (partial) match object.
225 */
226 Match newMatch(Object... parameters);
227
228 /**
229 * Retrieve the set of values that occur in matches for the given parameterName.
230 *
231 * @param parameterName
232 * name of the parameter for which values are returned
233 * @return the Set of all values for the given parameter, null if the parameter with the given name does not exists,
234 * empty set if there are no matches
235 */
236 Set<Object> getAllValues(final String parameterName);
237
238 /**
239 * Retrieve the set of values that occur in matches for the given parameterName, that conforms to the given fixed
240 * values of some parameters.
241 *
242 * @param parameterName
243 * name of the parameter for which values are returned
244 * @param partialMatch
245 * a partial match of the pattern where each non-null field binds the corresponding pattern parameter to
246 * a fixed value.
247 * @return the Set of all values for the given parameter, null if the parameter with the given name does not exists
248 * or if the parameter with the given name is set in partialMatch, empty set if there are no matches
249 */
250 Set<Object> getAllValues(final String parameterName, Match partialMatch);
251
252 /**
253 * Returns the engine that the matcher uses.
254 *
255 * @return the engine
256 */
257 ViatraQueryEngine getEngine();
258} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryModelUpdateListener.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryModelUpdateListener.java
new file mode 100644
index 00000000..da8bf87e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/ViatraQueryModelUpdateListener.java
@@ -0,0 +1,55 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Abel Hegedus, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.api;
10
11
12
13/**
14 * Listener interface for model changes affecting different levels of the VIATRA Query architecture.
15 *
16 * @author Abel Hegedus
17 *
18 */
19public interface ViatraQueryModelUpdateListener {
20
21 /**
22 * Possible notification levels for changes
23 *
24 * @author Abel Hegedus
25 *
26 */
27 enum ChangeLevel {
28 NO_CHANGE, MODEL, INDEX, MATCHSET;
29
30 public ChangeLevel changeOccured(ChangeLevel occuredLevel) {
31 if(this.compareTo(occuredLevel) < 0) {
32 return occuredLevel;
33 } else {
34 return this;
35 }
36 }
37 }
38 /**
39 * Called after each change with also sending the level of change.
40 * Only called if the change level is at least at the level returned by getLevel().
41 *
42 * @param changeLevel
43 */
44 void notifyChanged(ChangeLevel changeLevel);
45
46 /**
47 * This may be queried only ONCE (!!!) at the registration of the listener.
48 *
49 * NOTE: this allows us to only create engine level change providers if there is someone who needs it.
50 *
51 * @return the change level where you want notifications
52 */
53 ChangeLevel getLevel();
54
55}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseGeneratedPatternGroup.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseGeneratedPatternGroup.java
new file mode 100644
index 00000000..2e2a823b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseGeneratedPatternGroup.java
@@ -0,0 +1,31 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Mark Czotter, 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.api.impl;
10
11import java.util.HashSet;
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.api.IQuerySpecification;
15
16/**
17 * @author Mark Czotter
18 *
19 */
20public abstract class BaseGeneratedPatternGroup extends BaseQueryGroup {
21
22 @Override
23 public Set<IQuerySpecification<?>> getSpecifications() {
24 return querySpecifications;
25 }
26
27 /**
28 * Returns {@link IQuerySpecification} objects for handling them as a group. To be filled by constructors of subclasses.
29 */
30 protected Set<IQuerySpecification<?>> querySpecifications = new HashSet<IQuerySpecification<?>>();
31}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseMatcher.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseMatcher.java
new file mode 100644
index 00000000..ad79aafd
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseMatcher.java
@@ -0,0 +1,350 @@
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.api.impl;
11
12import java.util.Collection;
13import java.util.List;
14import java.util.Optional;
15import java.util.Set;
16import java.util.function.Consumer;
17import java.util.stream.Collectors;
18import java.util.stream.Stream;
19
20import tools.refinery.viatra.runtime.api.IPatternMatch;
21import tools.refinery.viatra.runtime.api.IQuerySpecification;
22import tools.refinery.viatra.runtime.api.ViatraQueryEngine;
23import tools.refinery.viatra.runtime.api.ViatraQueryMatcher;
24import tools.refinery.viatra.runtime.internal.apiimpl.QueryResultWrapper;
25import tools.refinery.viatra.runtime.matchers.backend.IMatcherCapability;
26import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
27import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
28import tools.refinery.viatra.runtime.matchers.util.Preconditions;
29
30/**
31 * Base implementation of ViatraQueryMatcher.
32 *
33 * @author Bergmann Gábor
34 *
35 * @param <Match>
36 */
37public abstract class BaseMatcher<Match extends IPatternMatch> extends QueryResultWrapper implements ViatraQueryMatcher<Match> {
38
39 // FIELDS AND CONSTRUCTOR
40
41 protected ViatraQueryEngine engine;
42 protected IQuerySpecification<? extends BaseMatcher<Match>> querySpecification;
43 private IMatcherCapability capabilities;
44
45 /**
46 * @since 1.4
47 */
48 public BaseMatcher(IQuerySpecification<? extends BaseMatcher<Match>> querySpecification) {
49 this.querySpecification = querySpecification;
50 this.querySpecification.getInternalQueryRepresentation().ensureInitialized();
51 }
52
53 /**
54 * @since 1.4
55 */
56 @Override
57 protected
58 void setBackend(ViatraQueryEngine engine, IQueryResultProvider resultProvider, IMatcherCapability capabilities){
59 this.backend = resultProvider;
60 this.engine = engine;
61 this.capabilities = capabilities;
62 }
63
64 // ARRAY-BASED INTERFACE
65
66 /** Converts the array representation of a pattern match to an immutable Match object. */
67 protected abstract Match arrayToMatch(Object[] parameters);
68 /** Converts the array representation of a pattern match to a mutable Match object. */
69 protected abstract Match arrayToMatchMutable(Object[] parameters);
70
71 /** Converts the Match object of a pattern match to the array representation. */
72 protected Object[] matchToArray(Match partialMatch) {
73 return partialMatch.toArray();
74 }
75 // TODO make me public for performance reasons
76 protected abstract Match tupleToMatch(Tuple t);
77
78 private Object[] fEmptyArray;
79
80 protected Object[] emptyArray() {
81 if (fEmptyArray == null)
82 fEmptyArray = new Object[getSpecification().getParameterNames().size()];
83 return fEmptyArray;
84 }
85
86 // REFLECTION
87
88 @Override
89 public Integer getPositionOfParameter(String parameterName) {
90 return getSpecification().getPositionOfParameter(parameterName);
91 }
92
93 @Override
94 public List<String> getParameterNames() {
95 return getSpecification().getParameterNames();
96 }
97
98 // BASE IMPLEMENTATION
99
100 @Override
101 public Collection<Match> getAllMatches() {
102 return rawStreamAllMatches(emptyArray()).collect(Collectors.toSet());
103 }
104
105 @Override
106 public Stream<Match> streamAllMatches() {
107 return rawStreamAllMatches(emptyArray());
108 }
109
110 /**
111 * Returns a stream of all matches of the pattern that conform to the given fixed values of some parameters.
112 *
113 * @param parameters
114 * array where each non-null element binds the corresponding pattern parameter to a fixed value.
115 * @pre size of input array must be equal to the number of parameters.
116 * @return matches represented as a Match object.
117 * @since 2.0
118 */
119 protected Stream<Match> rawStreamAllMatches(Object[] parameters) {
120 // clones the tuples into a match object to protect the Tuples from modifications outside of the ReteMatcher
121 return backend.getAllMatches(parameters).map(this::tupleToMatch);
122 }
123
124 @Override
125 public Collection<Match> getAllMatches(Match partialMatch) {
126 return rawStreamAllMatches(partialMatch.toArray()).collect(Collectors.toSet());
127 }
128
129 @Override
130 public Stream<Match> streamAllMatches(Match partialMatch) {
131 return rawStreamAllMatches(partialMatch.toArray());
132 }
133
134 // with input binding as pattern-specific parameters: not declared in interface
135
136 @Override
137 public Optional<Match> getOneArbitraryMatch() {
138 return rawGetOneArbitraryMatch(emptyArray());
139 }
140
141 /**
142 * Returns an arbitrarily chosen match of the pattern that conforms to the given fixed values of some parameters.
143 * Neither determinism nor randomness of selection is guaranteed.
144 *
145 * @param parameters
146 * array where each non-null element binds the corresponding pattern parameter to a fixed value.
147 * @pre size of input array must be equal to the number of parameters.
148 * @return a match represented as a Match object, or null if no match is found.
149 * @since 2.0
150 */
151 protected Optional<Match> rawGetOneArbitraryMatch(Object[] parameters) {
152 return backend.getOneArbitraryMatch(parameters).map(this::tupleToMatch);
153 }
154
155 @Override
156 public Optional<Match> getOneArbitraryMatch(Match partialMatch) {
157 return rawGetOneArbitraryMatch(partialMatch.toArray());
158 }
159
160 // with input binding as pattern-specific parameters: not declared in interface
161
162 /**
163 * Indicates whether the given combination of specified pattern parameters constitute a valid pattern match, under
164 * any possible substitution of the unspecified parameters.
165 *
166 * @param parameters
167 * array where each non-null element binds the corresponding pattern parameter to a fixed value.
168 * @return true if the input is a valid (partial) match of the pattern.
169 */
170 protected boolean rawHasMatch(Object[] parameters) {
171 return backend.hasMatch(parameters);
172 }
173
174 @Override
175 public boolean hasMatch() {
176 return rawHasMatch(emptyArray());
177 }
178
179 @Override
180 public boolean hasMatch(Match partialMatch) {
181 return rawHasMatch(partialMatch.toArray());
182 }
183
184 // with input binding as pattern-specific parameters: not declared in interface
185
186 @Override
187 public int countMatches() {
188 return rawCountMatches(emptyArray());
189 }
190
191 /**
192 * Returns the number of all matches of the pattern that conform to the given fixed values of some parameters.
193 *
194 * @param parameters
195 * array where each non-null element binds the corresponding pattern parameter to a fixed value.
196 * @pre size of input array must be equal to the number of parameters.
197 * @return the number of pattern matches found.
198 */
199 protected int rawCountMatches(Object[] parameters) {
200 return backend.countMatches(parameters);
201 }
202
203 @Override
204 public int countMatches(Match partialMatch) {
205 return rawCountMatches(partialMatch.toArray());
206 }
207
208 // with input binding as pattern-specific parameters: not declared in interface
209
210 /**
211 * Executes the given processor on each match of the pattern that conforms to the given fixed values of some
212 * parameters.
213 *
214 * @param parameters
215 * array where each non-null element binds the corresponding pattern parameter to a fixed value.
216 * @pre size of input array must be equal to the number of parameters.
217 * @param action
218 * the action that will process each pattern match.
219 * @since 2.0
220 */
221 protected void rawForEachMatch(Object[] parameters, Consumer<? super Match> processor) {
222 backend.getAllMatches(parameters).map(this::tupleToMatch).forEach(processor);
223 }
224
225 @Override
226 public void forEachMatch(Consumer<? super Match> processor) {
227 rawForEachMatch(emptyArray(), processor);
228 }
229
230 @Override
231 public void forEachMatch(Match match, Consumer<? super Match> processor) {
232 rawForEachMatch(match.toArray(), processor);
233 }
234
235 // with input binding as pattern-specific parameters: not declared in interface
236
237 @Override
238 public boolean forOneArbitraryMatch(Consumer<? super Match> processor) {
239 return rawForOneArbitraryMatch(emptyArray(), processor);
240 }
241
242 @Override
243 public boolean forOneArbitraryMatch(Match partialMatch, Consumer<? super Match> processor) {
244 return rawForOneArbitraryMatch(partialMatch.toArray(), processor);
245 }
246
247 /**
248 * Executes the given processor on an arbitrarily chosen match of the pattern that conforms to the given fixed
249 * values of some parameters. Neither determinism nor randomness of selection is guaranteed.
250 *
251 * @param parameters
252 * array where each non-null element binds the corresponding pattern parameter to a fixed value.
253 * @pre size of input array must be equal to the number of parameters.
254 * @param processor
255 * the action that will process the selected match.
256 * @return true if the pattern has at least one match with the given parameter values, false if the processor was
257 * not invoked
258 * @since 2.0
259 */
260 protected boolean rawForOneArbitraryMatch(Object[] parameters, Consumer<? super Match> processor) {
261 return backend.getOneArbitraryMatch(parameters).map(this::tupleToMatch).map(m -> {
262 processor.accept(m);
263 return true;
264 }).orElse(false);
265 }
266
267 // with input binding as pattern-specific parameters: not declared in interface
268
269
270 @Override
271 public Match newEmptyMatch() {
272 return arrayToMatchMutable(new Object[getParameterNames().size()]);
273 }
274
275 @Override
276 public Match newMatch(Object... parameters) {
277 return arrayToMatch(parameters);
278 }
279
280 @Override
281 public Set<Object> getAllValues(final String parameterName) {
282 return rawStreamAllValues(getPositionOfParameter(parameterName), emptyArray()).collect(Collectors.toSet());
283 }
284
285 @Override
286 public Set<Object> getAllValues(final String parameterName, Match partialMatch) {
287 return rawStreamAllValues(getPositionOfParameter(parameterName), partialMatch.toArray()).collect(Collectors.toSet());
288 }
289
290 /**
291 * Retrieve a stream of values that occur in matches for the given parameterName, that conforms to the given fixed
292 * values of some parameters.
293 *
294 * @param position
295 * position of the parameter for which values are returned
296 * @param parameters
297 * a parameter array corresponding to a partial match of the pattern where each non-null field binds the
298 * corresponding pattern parameter to a fixed value.
299 * @return the stream of all values in the given position
300 * @throws IllegalArgumentException
301 * if length of parameters array does not equal to number of parameters
302 * @throws IndexOutOfBoundsException
303 * if position is not appropriate for the current parameter size
304 * @since 2.0
305 */
306 protected Stream<Object> rawStreamAllValues(final int position, Object[] parameters) {
307 Preconditions.checkElementIndex(position, getParameterNames().size());
308 Preconditions.checkArgument(parameters.length == getParameterNames().size());
309 return rawStreamAllMatches(parameters).map(match -> match.get(position));
310 }
311
312 /**
313 * Uses an existing set to accumulate all values of the parameter with the given name. Since it is a protected
314 * method, no error checking or input validation is performed!
315 *
316 * @param position
317 * position of the parameter for which values are returned
318 * @param parameters
319 * a parameter array corresponding to a partial match of the pattern where each non-null field binds the
320 * corresponding pattern parameter to a fixed value.
321 * @param accumulator
322 * the existing set to fill with the values
323 */
324 @SuppressWarnings("unchecked")
325 protected <T> void rawAccumulateAllValues(final int position, Object[] parameters, final Set<T> accumulator) {
326 rawForEachMatch(parameters, match -> accumulator.add((T) match.get(position)));
327 }
328
329 @Override
330 public ViatraQueryEngine getEngine() {
331 return engine;
332 }
333
334 @Override
335 public IQuerySpecification<? extends BaseMatcher<Match>> getSpecification() {
336 return querySpecification;
337 }
338
339 @Override
340 public String getPatternName() {
341 return querySpecification.getFullyQualifiedName();
342 }
343
344 /**
345 * @since 1.4
346 */
347 public IMatcherCapability getCapabilities() {
348 return capabilities;
349 }
350}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BasePatternMatch.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BasePatternMatch.java
new file mode 100644
index 00000000..182bb466
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BasePatternMatch.java
@@ -0,0 +1,91 @@
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.api.impl;
11
12import tools.refinery.viatra.runtime.api.IPatternMatch;
13
14import java.util.Arrays;
15import java.util.Collections;
16import java.util.List;
17
18/**
19 * Base implementation of IPatternMatch.
20 *
21 * @author Bergmann Gábor
22 *
23 */
24public abstract class BasePatternMatch implements IPatternMatch {
25
26 @SafeVarargs
27 protected static <T> List<T> makeImmutableList(T... elements) {
28 return Collections.unmodifiableList(Arrays.asList(elements));
29 }
30
31 public static String prettyPrintValue(Object o) {
32 if (o == null) {
33 return "(null)";
34 }
35 return o.toString();
36 }
37
38 // TODO performance can be improved here somewhat
39
40 @Override
41 public Object get(int position) {
42 if (position >= 0 && position < parameterNames().size())
43 return get(parameterNames().get(position));
44 else
45 return null;
46 }
47
48 @Override
49 public boolean set(int position, Object newValue) {
50 if (!isMutable()) throw new UnsupportedOperationException();
51 if (position >= 0 && position < parameterNames().size()) {
52 return set(parameterNames().get(position), newValue);
53 } else {
54 return false;
55 }
56 }
57
58 @Override
59 public String toString() {
60 return "Match<" + patternName() + ">{" + prettyPrint() + "}";
61 }
62
63 @Override
64 public boolean isCompatibleWith(IPatternMatch other) {
65 if(other == null) {
66 return true;
67 }
68 // we assume that the pattern is set for this match!
69 if (!specification().equals(other.specification())) {
70 return false;
71 }
72 for (int i = 0; i < parameterNames().size(); i++) {
73 Object value = get(i);
74 Object otherValue = other.get(i);
75 if(value != null && otherValue != null && !value.equals(otherValue)) {
76 return false;
77 }
78 }
79 return true;
80 }
81
82 @Override
83 public String patternName() {
84 return specification().getFullyQualifiedName();
85 }
86
87 @Override
88 public List<String> parameterNames() {
89 return specification().getParameterNames();
90 }
91}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseQueryGroup.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseQueryGroup.java
new file mode 100644
index 00000000..b92727e7
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseQueryGroup.java
@@ -0,0 +1,33 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Mark Czotter, 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.api.impl;
10
11import tools.refinery.viatra.runtime.api.AdvancedViatraQueryEngine;
12import tools.refinery.viatra.runtime.api.IQueryGroup;
13import tools.refinery.viatra.runtime.api.ViatraQueryEngine;
14
15/**
16 * Base implementation of {@link IQueryGroup}.
17 *
18 * @author Mark Czotter
19 *
20 */
21public abstract class BaseQueryGroup implements IQueryGroup {
22
23 @Override
24 public void prepare(ViatraQueryEngine engine) {
25 prepare(AdvancedViatraQueryEngine.from(engine));
26 }
27
28 protected void prepare(AdvancedViatraQueryEngine engine) {
29 engine.prepareGroup(this, null /* default options */);
30 }
31
32
33}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseQuerySpecification.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseQuerySpecification.java
new file mode 100644
index 00000000..bee4b93d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/impl/BaseQuerySpecification.java
@@ -0,0 +1,147 @@
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.api.impl;
11
12import java.util.List;
13import java.util.Optional;
14import java.util.stream.Collectors;
15
16import tools.refinery.viatra.runtime.api.IPatternMatch;
17import tools.refinery.viatra.runtime.api.IQuerySpecification;
18import tools.refinery.viatra.runtime.api.ViatraQueryEngine;
19import tools.refinery.viatra.runtime.api.ViatraQueryMatcher;
20import tools.refinery.viatra.runtime.exception.ViatraQueryException;
21import tools.refinery.viatra.runtime.matchers.psystem.annotations.PAnnotation;
22import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
23import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
24import tools.refinery.viatra.runtime.matchers.psystem.queries.QueryInitializationException;
25import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery.PQueryStatus;
26import tools.refinery.viatra.runtime.matchers.psystem.queries.PVisibility;
27
28/**
29 * Base implementation of IQuerySpecification.
30 *
31 * @author Gabor Bergmann
32 *
33 */
34public abstract class BaseQuerySpecification<Matcher extends ViatraQueryMatcher<? extends IPatternMatch>> implements
35 IQuerySpecification<Matcher> {
36
37 /**
38 * @since 1.6
39 */
40 protected static ViatraQueryException processInitializerError(ExceptionInInitializerError err) {
41 Throwable cause1 = err.getCause();
42 if (cause1 instanceof RuntimeException) {
43 Throwable cause2 = ((RuntimeException) cause1).getCause();
44 if (cause2 instanceof ViatraQueryException) {
45 return (ViatraQueryException) cause2;
46 } else if (cause2 instanceof QueryInitializationException) {
47 return new ViatraQueryException((QueryInitializationException) cause2);
48 }
49 }
50 throw err;
51 }
52 protected final PQuery wrappedPQuery;
53
54 protected abstract Matcher instantiate(ViatraQueryEngine engine);
55
56 /**
57 * For backward compatibility of code generated with previous versions of viatra query, this method has a default
58 * implementation returning null, indicating that a matcher can only be created using the old method, which ignores
59 * the hints provided by the user.
60 *
61 * @since 1.4
62 */
63 @Override
64 public Matcher instantiate() {
65 return null;
66 }
67
68
69 /**
70 * Instantiates query specification for the given internal query representation.
71 */
72 public BaseQuerySpecification(PQuery wrappedPQuery) {
73 super();
74 this.wrappedPQuery = wrappedPQuery;
75 wrappedPQuery.publishedAs().add(this);
76 }
77
78
79 @Override
80 public PQuery getInternalQueryRepresentation() {
81 return wrappedPQuery;
82 }
83
84 @Override
85 public Matcher getMatcher(ViatraQueryEngine engine) {
86 ensureInitializedInternal();
87 if (wrappedPQuery.getStatus() == PQueryStatus.ERROR) {
88 String errorMessages = wrappedPQuery.getPProblems().stream()
89 .map(input -> (input == null) ? "" : input.getShortMessage()).collect(Collectors.joining("\n"));
90 throw new ViatraQueryException(String.format("Erroneous query specification: %s %n %s", getFullyQualifiedName(), errorMessages),
91 "Cannot initialize matchers on erroneous query specifications.");
92 } else if (!engine.getScope().isCompatibleWithQueryScope(this.getPreferredScopeClass())) {
93 throw new ViatraQueryException(
94 String.format(
95 "Scope class incompatibility: the query %s is formulated over query scopes of class %s, "
96 + " thus the query engine formulated over scope %s of class %s cannot evaluate it.",
97 this.getFullyQualifiedName(), this.getPreferredScopeClass().getCanonicalName(),
98 engine.getScope(), engine.getScope().getClass().getCanonicalName()),
99 "Incompatible scope classes of engine and query.");
100 }
101 return instantiate(engine);
102 }
103
104 protected void ensureInitializedInternal() {
105 wrappedPQuery.ensureInitialized();
106 }
107
108 // // DELEGATIONS
109
110 @Override
111 public List<PAnnotation> getAllAnnotations() {
112 return wrappedPQuery.getAllAnnotations();
113 }
114 @Override
115 public List<PAnnotation> getAnnotationsByName(String annotationName) {
116 return wrappedPQuery.getAnnotationsByName(annotationName);
117 }
118 @Override
119 public Optional<PAnnotation> getFirstAnnotationByName(String annotationName) {
120 return wrappedPQuery.getFirstAnnotationByName(annotationName);
121 }
122 @Override
123 public String getFullyQualifiedName() {
124 return wrappedPQuery.getFullyQualifiedName();
125 }
126 @Override
127 public List<String> getParameterNames() {
128 return wrappedPQuery.getParameterNames();
129 }
130 @Override
131 public List<PParameter> getParameters() {
132 return wrappedPQuery.getParameters();
133 }
134 @Override
135 public Integer getPositionOfParameter(String parameterName) {
136 return wrappedPQuery.getPositionOfParameter(parameterName);
137 }
138
139 /**
140 * @since 2.0
141 */
142 @Override
143 public PVisibility getVisibility() {
144 return wrappedPQuery.getVisibility();
145 }
146
147}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IBaseIndex.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IBaseIndex.java
new file mode 100644
index 00000000..1795a8ef
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IBaseIndex.java
@@ -0,0 +1,91 @@
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.api.scope;
10
11import java.lang.reflect.InvocationTargetException;
12import java.util.concurrent.Callable;
13
14/**
15 * Represents the index maintained on the model.
16 * @author Bergmann Gabor
17 * @since 0.9
18 *
19 */
20public interface IBaseIndex {
21 // TODO lightweightObserver?
22 // TODO ViatraBaseIndexChangeListener?
23
24 /**
25 * The given callback will be executed, and all model traversals and index registrations will be delayed until the
26 * execution is done. If there are any outstanding feature, class or datatype registrations, a single coalesced model
27 * traversal will initialize the caches and deliver the notifications.
28 *
29 * @param callable
30 */
31 public <V> V coalesceTraversals(Callable<V> callable) throws InvocationTargetException;
32
33 /**
34 * Adds a coarse-grained listener that will be invoked after the NavigationHelper index or the underlying model is changed. Can be used
35 * e.g. to check model contents. Not intended for general use.
36 *
37 * <p/> See {@link #removeBaseIndexChangeListener(ViatraBaseIndexChangeListener)}
38 * @param listener
39 */
40 public void addBaseIndexChangeListener(ViatraBaseIndexChangeListener listener);
41
42 /**
43 * Removes a registered listener.
44 *
45 * <p/> See {@link #addBaseIndexChangeListener(ViatraBaseIndexChangeListener)}
46 *
47 * @param listener
48 */
49 public void removeBaseIndexChangeListener(ViatraBaseIndexChangeListener listener);
50
51 /**
52 * Updates the value of indexed derived features that are not well-behaving.
53 */
54 void resampleDerivedFeatures();
55
56 /**
57 * Adds a listener for internal errors in the index. A listener can only be added once.
58 * @param listener
59 * @returns true if the listener was not already added
60 * @since 0.8.0
61 */
62 boolean addIndexingErrorListener(IIndexingErrorListener listener);
63 /**
64 * Removes a listener for internal errors in the index
65 * @param listener
66 * @returns true if the listener was successfully removed (e.g. it did exist)
67 * @since 0.8.0
68 */
69 boolean removeIndexingErrorListener(IIndexingErrorListener listener);
70
71 /**
72 * Register a lightweight observer that is notified if any edge starting at the given Object changes.
73 *
74 * @param observer the listener instance
75 * @param observedObject the observed instance object
76 * @return false if no observer can be registered for the given instance (e.g. it is a primitive),
77 * or observer was already registered (call has no effect)
78 */
79 public boolean addInstanceObserver(IInstanceObserver observer, Object observedObject);
80
81 /**
82 * Unregisters a lightweight observer for the given Object.
83 *
84 * @param observer the listener instance
85 * @param observedObject the observed instance object
86 * @return false if no observer can be registered for the given instance (e.g. it is a primitive),
87 * or no observer was registered previously (call has no effect)
88 */
89 public boolean removeInstanceObserver(IInstanceObserver observer, Object observedObject);
90
91}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IEngineContext.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IEngineContext.java
new file mode 100644
index 00000000..55060853
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IEngineContext.java
@@ -0,0 +1,49 @@
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.api.scope;
10
11import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
12import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
13
14/**
15 * The context of the engine is instantiated by the scope,
16 * and provides information and services regarding the model the towards the engine.
17 *
18 * @author Bergmann Gabor
19 *
20 */
21public interface IEngineContext {
22
23 /**
24 * Returns the base index.
25 * @throws ViatraQueryRuntimeException if the base index cannot be accessed
26 */
27 IBaseIndex getBaseIndex();
28
29 /**
30 * Disposes this context object. Resources in the index may now be freed up.
31 * No more methods should be called after this one.
32 *
33 * @throws IllegalStateException if there are any active listeners to the underlying index
34 */
35 void dispose();
36
37 /**
38 * Provides instance model information for pattern matching.
39 *
40 * <p> Implementors note: must be reentrant.
41 * If called while index loading is already in progress, must return the single runtime context instance that will eventually index the model.
42 * When the runtime query context is invoked in such a case, incomplete indexes are tolerable, but change notifications must be correctly provided as loading commences.
43 *
44 * @return a runtime context for pattern matching
45 * @since 1.2
46 * @throws ViatraQueryRuntimeException if the runtime context cannot be initialized
47 */
48 public IQueryRuntimeContext getQueryRuntimeContext();
49} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IIndexingErrorListener.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IIndexingErrorListener.java
new file mode 100644
index 00000000..f61a5edb
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IIndexingErrorListener.java
@@ -0,0 +1,23 @@
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.api.scope;
10
11/**
12 *
13 * This interface contains callbacks for various internal errors from the {@link NavigationHelper base index}.
14 *
15 * @author Zoltan Ujhelyi
16 * @since 0.9
17 *
18 */
19public interface IIndexingErrorListener {
20
21 void error(String description, Throwable t);
22 void fatal(String description, Throwable t);
23}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IInstanceObserver.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IInstanceObserver.java
new file mode 100644
index 00000000..8ef29cbe
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/IInstanceObserver.java
@@ -0,0 +1,21 @@
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.api.scope;
10
11
12/**
13 * Listener interface for lightweight observation of changes in edges leaving from given source instance elements.
14 * @author Bergmann Gabor
15 * @since 0.9
16 *
17 */
18public interface IInstanceObserver {
19 void notifyBinaryChanged(Object sourceElement, Object edgeType);
20 void notifyTernaryChanged(Object sourceElement, Object edgeType);
21}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/QueryScope.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/QueryScope.java
new file mode 100644
index 00000000..5456b9ea
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/QueryScope.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.api.scope;
10
11import tools.refinery.viatra.runtime.api.IQuerySpecification;
12import tools.refinery.viatra.runtime.api.ViatraQueryEngine;
13import tools.refinery.viatra.runtime.internal.apiimpl.EngineContextFactory;
14
15/**
16 * Defines a scope for a VIATRA Query engine, which determines the set of model elements that query evaluation operates on.
17 *
18 * @author Bergmann Gabor
19 *
20 */
21public abstract class QueryScope extends EngineContextFactory {
22
23 /**
24 * Determines whether a query engine initialized on this scope can evaluate queries formulated against the given scope type.
25 * <p> Every query scope class is compatible with a query engine initialized on a scope of the same class or a subclass.
26 * @param queryScopeClass the scope class returned by invoking {@link IQuerySpecification#getPreferredScopeClass()} on a query specification
27 * @return true if an {@link ViatraQueryEngine} initialized on this scope can consume an {@link IQuerySpecification}
28 */
29 public boolean isCompatibleWithQueryScope(Class<? extends QueryScope> queryScopeClass) {
30 return queryScopeClass.isAssignableFrom(this.getClass());
31 }
32
33}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/ViatraBaseIndexChangeListener.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/ViatraBaseIndexChangeListener.java
new file mode 100644
index 00000000..b746e637
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/api/scope/ViatraBaseIndexChangeListener.java
@@ -0,0 +1,34 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Abel Hegedus, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.api.scope;
10
11/**
12 * Listener interface for change notifications from the VIATRA Base index.
13 *
14 * @author Abel Hegedus
15 * @since 0.9
16 *
17 */
18public interface ViatraBaseIndexChangeListener {
19
20 /**
21 * NOTE: it is possible that this method is called only ONCE! Consider returning a constant value that is set in the constructor.
22 *
23 * @return true, if the listener should be notified only after index changes, false if notification is needed after each model change
24 */
25 public boolean onlyOnIndexChange();
26
27 /**
28 * Called after a model change is handled by the VIATRA Base index and if <code>indexChanged == onlyOnIndexChange()</code>.
29 *
30 * @param indexChanged true, if the model change also affected the contents of the base index
31 */
32 public void notifyChanged(boolean indexChanged);
33
34}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/exception/ViatraQueryException.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/exception/ViatraQueryException.java
new file mode 100644
index 00000000..fec547a6
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/exception/ViatraQueryException.java
@@ -0,0 +1,71 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Akos Horvath 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.exception;
10
11import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
12import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
13import tools.refinery.viatra.runtime.matchers.psystem.queries.QueryInitializationException;
14
15/**
16 * A general VIATRA Query-related problem during the operation of the VIATRA Query
17 * engine, or the loading, manipulation and evaluation of queries.
18 *
19 * @author Bergmann Gabor
20 * @since 0.9
21 *
22 */
23public class ViatraQueryException extends ViatraQueryRuntimeException {
24
25 private static final long serialVersionUID = -74252748358355750L;
26
27 public static final String PARAM_NOT_SUITABLE_WITH_NO = "The type of the parameters are not suitable for the operation. Parameter number: ";
28 public static final String CONVERSION_FAILED = "Could not convert the term to the designated type";
29 public static final String CONVERT_NULL_PARAMETER = "Could not convert null to the designated type";
30 public static final String RELATIONAL_PARAM_UNSUITABLE = "The parameters are not acceptable by the operation";
31 /**
32 * @since 0.9
33 */
34 public static final String PROCESSING_PROBLEM = "The following error occurred during the processing of a query (e.g. for the preparation of a VIATRA pattern matcher)";
35 /**
36 * @since 0.9
37 */
38 public static final String QUERY_INIT_PROBLEM = "The following error occurred during the initialization of a VIATRA query specification";
39 public static final String GETNAME_FAILED = "Could not get 'name' attribute of the result";
40
41 public static final String INVALID_EMFROOT = "Incremental EMF query engine can only be attached on the contents of an EMF EObject, Resource, ResourceSet or multiple ResourceSets. Received instead: ";
42 public static final String INVALID_EMFROOT_SHORT = "Invalid EMF model root";
43 // public static final String EMF_MODEL_PROCESSING_ERROR = "Error while processing the EMF model";
44
45 private final String shortMessage;
46
47 public ViatraQueryException(String s, String shortMessage) {
48 super(s);
49 this.shortMessage = shortMessage;
50 }
51
52 public ViatraQueryException(QueryProcessingException e) {
53 super(PROCESSING_PROBLEM + ": " + e.getMessage(), e);
54 this.shortMessage = e.getShortMessage();
55 }
56
57 public ViatraQueryException(QueryInitializationException e) {
58 super(QUERY_INIT_PROBLEM + ": " + e.getMessage(), e);
59 this.shortMessage = e.getShortMessage();
60 }
61
62 public ViatraQueryException(String s, String shortMessage, Throwable e) {
63 super(s + ": " + e.getMessage(), e);
64 this.shortMessage = shortMessage;
65 }
66
67 public String getShortMessage() {
68 return shortMessage;
69 }
70
71}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/EngineContextFactory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/EngineContextFactory.java
new file mode 100644
index 00000000..bed07ebf
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/EngineContextFactory.java
@@ -0,0 +1,24 @@
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.internal.apiimpl;
10
11import org.apache.log4j.Logger;
12import tools.refinery.viatra.runtime.api.ViatraQueryEngine;
13import tools.refinery.viatra.runtime.api.scope.IEngineContext;
14import tools.refinery.viatra.runtime.api.scope.IIndexingErrorListener;
15
16/**
17 * Internal interface for a Scope to reveal model contents to the engine.
18 *
19 * @author Bergmann Gabor
20 *
21 */
22public abstract class EngineContextFactory {
23 protected abstract IEngineContext createEngineContext(ViatraQueryEngine engine, IIndexingErrorListener errorListener, Logger logger);
24}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/QueryResultWrapper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/QueryResultWrapper.java
new file mode 100644
index 00000000..47f3268d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/QueryResultWrapper.java
@@ -0,0 +1,32 @@
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.internal.apiimpl;
10
11import tools.refinery.viatra.runtime.api.ViatraQueryEngine;
12import tools.refinery.viatra.runtime.matchers.backend.IMatcherCapability;
13import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
14
15/**
16 * Internal class for wrapping a query result providing backend. It's only supported usage is by the
17 * {@link ViatraQueryEngineImpl} class.
18 * </p>
19 *
20 * <strong>Important note</strong>: this class must not introduce any public method, as it will be visible through
21 * BaseMatcher as an API, although this class is not an API itself.
22 *
23 * @author Bergmann Gabor
24 *
25 */
26public abstract class QueryResultWrapper {
27
28 protected IQueryResultProvider backend;
29
30 protected abstract void setBackend(ViatraQueryEngine engine, IQueryResultProvider resultProvider, IMatcherCapability capabilities);
31
32}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/ViatraQueryEngineImpl.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/ViatraQueryEngineImpl.java
new file mode 100644
index 00000000..5317a79e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/apiimpl/ViatraQueryEngineImpl.java
@@ -0,0 +1,714 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools>
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v. 2.0 which is available at
6 * http://www.eclipse.org/legal/epl-v20.html.
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *******************************************************************************/
10
11package tools.refinery.viatra.runtime.internal.apiimpl;
12
13import org.apache.log4j.Logger;
14import tools.refinery.viatra.runtime.api.*;
15import tools.refinery.viatra.runtime.api.impl.BaseMatcher;
16import tools.refinery.viatra.runtime.api.scope.IBaseIndex;
17import tools.refinery.viatra.runtime.api.scope.IEngineContext;
18import tools.refinery.viatra.runtime.api.scope.IIndexingErrorListener;
19import tools.refinery.viatra.runtime.api.scope.QueryScope;
20import tools.refinery.viatra.runtime.exception.ViatraQueryException;
21import tools.refinery.viatra.runtime.internal.engine.LifecycleProvider;
22import tools.refinery.viatra.runtime.internal.engine.ModelUpdateProvider;
23import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
24import tools.refinery.viatra.runtime.matchers.backend.*;
25import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
26import tools.refinery.viatra.runtime.matchers.context.IQueryCacheContext;
27import tools.refinery.viatra.runtime.matchers.context.IQueryResultProviderAccess;
28import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
29import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
30import tools.refinery.viatra.runtime.matchers.psystem.analysis.QueryAnalyzer;
31import tools.refinery.viatra.runtime.matchers.psystem.queries.PQueries;
32import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
33import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery.PQueryStatus;
34import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
35import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
36import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
37import tools.refinery.viatra.runtime.matchers.util.Preconditions;
38import tools.refinery.viatra.runtime.util.ViatraQueryLoggingUtil;
39
40import java.lang.ref.WeakReference;
41import java.lang.reflect.InvocationTargetException;
42import java.util.*;
43import java.util.concurrent.Callable;
44import java.util.function.Supplier;
45import java.util.stream.Collectors;
46
47import static tools.refinery.viatra.runtime.matchers.util.Preconditions.checkArgument;
48
49/**
50 * A VIATRA Query engine back-end (implementation)
51 *
52 * @author Bergmann Gábor
53 */
54public final class ViatraQueryEngineImpl extends AdvancedViatraQueryEngine
55 implements IQueryBackendHintProvider, IQueryCacheContext, IQueryResultProviderAccess {
56
57 /**
58 *
59 */
60 private static final String ERROR_ACCESSING_BACKEND = "Error while accessing query evaluator backend";
61 /**
62 *
63 */
64 private static final String QUERY_ON_DISPOSED_ENGINE_MESSAGE = "Cannot evaluate query on disposed engine!";
65 /**
66 * The engine manager responsible for this engine. Null if this engine is unmanaged.
67 */
68 private final ViatraQueryEngineManager manager;
69 /**
70 * The model to which the engine is attached.
71 */
72 private final QueryScope scope;
73
74 /**
75 * The context of the engine, provided by the scope.
76 */
77 private IEngineContext engineContext;
78
79 /**
80 * Initialized matchers for each query
81 */
82 private final IMultiLookup<IQuerySpecification<? extends ViatraQueryMatcher<?>>, ViatraQueryMatcher<?>> matchers =
83 CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, Object.class);
84
85 /**
86 * The RETE and other pattern matcher implementations of the VIATRA Query Engine.
87 */
88 private volatile Map<IQueryBackendFactory, IQueryBackend> queryBackends = new HashMap<>();
89
90 /**
91 * The current engine default hints
92 */
93 private final ViatraQueryEngineOptions engineOptions;
94
95 /**
96 * Common query analysis provided to backends
97 */
98 private QueryAnalyzer queryAnalyzer;
99
100 /**
101 * true if message delivery is currently delayed, false otherwise
102 */
103 private boolean delayMessageDelivery = true;
104
105 private final LifecycleProvider lifecycleProvider;
106 private final ModelUpdateProvider modelUpdateProvider;
107 private Logger logger;
108 private boolean disposed = false;
109
110 /**
111 * @param manager
112 * null if unmanaged
113 * @param scope
114 * @param engineDefaultHint
115 * @since 1.4
116 */
117 public ViatraQueryEngineImpl(ViatraQueryEngineManager manager, QueryScope scope,
118 ViatraQueryEngineOptions engineOptions) {
119 super();
120 this.manager = manager;
121 this.scope = scope;
122 this.lifecycleProvider = new LifecycleProvider(this, getLogger());
123 this.modelUpdateProvider = new ModelUpdateProvider(this, getLogger());
124 this.engineContext = scope.createEngineContext(this, taintListener, getLogger());
125
126 if (engineOptions != null) {
127 this.engineOptions = engineOptions;
128 } else {
129 this.engineOptions = ViatraQueryEngineOptions.getDefault();
130 }
131
132 }
133
134 /**
135 * @param manager
136 * null if unmanaged
137 * @param scope
138 * @param engineDefaultHint
139 */
140 public ViatraQueryEngineImpl(ViatraQueryEngineManager manager, QueryScope scope) {
141 this(manager, scope, ViatraQueryEngineOptions.getDefault());
142 }
143
144 @Override
145 public boolean isUpdatePropagationDelayed() {
146 return this.delayMessageDelivery;
147 }
148
149 @Override
150 public <V> V delayUpdatePropagation(Callable<V> callable) throws InvocationTargetException {
151 if (!delayMessageDelivery) {
152 throw new IllegalStateException("Trying to delay propagation while changes are being flushed");
153 }
154 try {
155 return callable.call();
156 } catch (Exception e) {
157 throw new InvocationTargetException(e);
158 }
159 }
160
161 @Override
162 public void flushChanges() {
163 if (!delayMessageDelivery) {
164 throw new IllegalStateException("Trying to flush changes while changes are already being flushed");
165 }
166 delayMessageDelivery = false;
167 try {
168 flushAllBackends();
169 } finally {
170 delayMessageDelivery = true;
171 }
172 }
173
174 private void flushAllBackends() {
175 for (IQueryBackend backend : this.queryBackends.values()) {
176 backend.flushUpdates();
177 }
178 }
179
180 @Override
181 public <T> T withFlushingChanges(Supplier<T> callback) {
182 if (!delayMessageDelivery) {
183 return callback.get();
184 }
185 delayMessageDelivery = false;
186 try {
187 flushAllBackends();
188 return callback.get();
189 } finally {
190 delayMessageDelivery = true;
191 }
192 }
193
194 @Override
195 public Set<? extends ViatraQueryMatcher<? extends IPatternMatch>> getCurrentMatchers() {
196 return matchers.distinctValuesStream().collect(Collectors.toSet());
197 }
198
199 @Override
200 public <Matcher extends ViatraQueryMatcher<? extends IPatternMatch>> Matcher getMatcher(
201 IQuerySpecification<Matcher> querySpecification) {
202 return getMatcher(querySpecification, null);
203 }
204
205 @Override
206 public <Matcher extends ViatraQueryMatcher<? extends IPatternMatch>> Matcher getMatcher(
207 IQuerySpecification<Matcher> querySpecification, QueryEvaluationHint optionalEvaluationHints) {
208 return withFlushingChanges(() -> {
209 IMatcherCapability capability = getRequestedCapability(querySpecification, optionalEvaluationHints);
210 Matcher matcher = doGetExistingMatcher(querySpecification, capability);
211 if (matcher != null) {
212 return matcher;
213 }
214 matcher = querySpecification.instantiate();
215
216 BaseMatcher<?> baseMatcher = (BaseMatcher<?>) matcher;
217 ((QueryResultWrapper) baseMatcher).setBackend(this,
218 getResultProvider(querySpecification, optionalEvaluationHints), capability);
219 internalRegisterMatcher(querySpecification, baseMatcher);
220 return matcher;
221 });
222 }
223
224 @Override
225 public <Matcher extends ViatraQueryMatcher<? extends IPatternMatch>> Matcher getExistingMatcher(
226 IQuerySpecification<Matcher> querySpecification) {
227 return getExistingMatcher(querySpecification, null);
228 }
229
230 @Override
231 public <Matcher extends ViatraQueryMatcher<? extends IPatternMatch>> Matcher getExistingMatcher(
232 IQuerySpecification<Matcher> querySpecification, QueryEvaluationHint optionalOverrideHints) {
233 return doGetExistingMatcher(querySpecification, getRequestedCapability(querySpecification, optionalOverrideHints));
234 }
235
236 @SuppressWarnings("unchecked")
237 private <Matcher extends ViatraQueryMatcher<? extends IPatternMatch>> Matcher doGetExistingMatcher(
238 IQuerySpecification<Matcher> querySpecification, IMatcherCapability requestedCapability) {
239 for (ViatraQueryMatcher<?> matcher : matchers.lookupOrEmpty(querySpecification)) {
240 BaseMatcher<?> baseMatcher = (BaseMatcher<?>) matcher;
241 if (baseMatcher.getCapabilities().canBeSubstitute(requestedCapability))
242 return (Matcher) matcher;
243 }
244 return null;
245 }
246
247 @Override
248 public ViatraQueryMatcher<? extends IPatternMatch> getMatcher(String patternFQN) {
249 throw new UnsupportedOperationException("Query specification registry is not available");
250 }
251
252 @Override
253 public IBaseIndex getBaseIndex() {
254 return engineContext.getBaseIndex();
255 }
256
257 public final Logger getLogger() {
258 if (logger == null) {
259 final int hash = System.identityHashCode(this);
260 logger = Logger.getLogger(ViatraQueryLoggingUtil.getLogger(ViatraQueryEngine.class).getName() + "." + hash);
261 if (logger == null)
262 throw new AssertionError(
263 "Configuration error: unable to create VIATRA Query runtime logger for engine " + hash);
264 }
265 return logger;
266 }
267
268 ///////////////// internal stuff //////////////
269 private void internalRegisterMatcher(IQuerySpecification<?> querySpecification, ViatraQueryMatcher<?> matcher) {
270 matchers.addPair(querySpecification, matcher);
271 lifecycleProvider.matcherInstantiated(matcher);
272 }
273
274 /**
275 * Provides access to the selected query backend component of the VIATRA Query Engine.
276 */
277 @Override
278 public IQueryBackend getQueryBackend(IQueryBackendFactory iQueryBackendFactory) {
279 IQueryBackend iQueryBackend = queryBackends.get(iQueryBackendFactory);
280 if (iQueryBackend == null) {
281 // do this first, to make sure the runtime context exists
282 final IQueryRuntimeContext queryRuntimeContext = engineContext.getQueryRuntimeContext();
283
284 // maybe the backend has been created in the meantime when the indexer was initialized and queried for
285 // derived features
286 // no need to instantiate a new backend in that case
287 iQueryBackend = queryBackends.get(iQueryBackendFactory);
288 if (iQueryBackend == null) {
289
290 // need to instantiate the backend
291 iQueryBackend = iQueryBackendFactory.create(new IQueryBackendContext() {
292
293 @Override
294 public IQueryRuntimeContext getRuntimeContext() {
295 return queryRuntimeContext;
296 }
297
298 @Override
299 public IQueryCacheContext getQueryCacheContext() {
300 return ViatraQueryEngineImpl.this;
301 }
302
303 @Override
304 public Logger getLogger() {
305 return logger;
306 }
307
308 @Override
309 public IQueryBackendHintProvider getHintProvider() {
310 return ViatraQueryEngineImpl.this;
311 }
312
313 @Override
314 public IQueryResultProviderAccess getResultProviderAccess() {
315 return ViatraQueryEngineImpl.this;
316 }
317
318 @Override
319 public QueryAnalyzer getQueryAnalyzer() {
320 if (queryAnalyzer == null)
321 queryAnalyzer = new QueryAnalyzer(queryRuntimeContext.getMetaContext());
322 return queryAnalyzer;
323 }
324
325 @Override
326 public boolean areUpdatesDelayed() {
327 return ViatraQueryEngineImpl.this.delayMessageDelivery;
328 }
329
330 @Override
331 public IMatcherCapability getRequiredMatcherCapability(PQuery query,
332 QueryEvaluationHint hint) {
333 return engineOptions.getQueryBackendFactory(hint).calculateRequiredCapability(query, hint);
334 }
335
336
337
338 });
339 queryBackends.put(iQueryBackendFactory, iQueryBackend);
340 }
341 }
342 return iQueryBackend;
343 }
344
345 ///////////////// advanced stuff /////////////
346
347 @Override
348 public void dispose() {
349 if (manager != null) {
350 throw new UnsupportedOperationException(
351 String.format("Cannot dispose() managed VIATRA Query Engine. Attempted for scope %s.", scope));
352 }
353 wipe();
354
355 this.disposed = true;
356
357 // called before base index disposal to allow removal of base listeners
358 lifecycleProvider.engineDisposed();
359
360 try {
361 engineContext.dispose();
362 } catch (IllegalStateException ex) {
363 getLogger().warn(
364 "The base index could not be disposed along with the VIATRA Query engine, as there are still active listeners on it.");
365 }
366 }
367
368 @Override
369 public void wipe() {
370 if (manager != null) {
371 throw new UnsupportedOperationException(
372 String.format("Cannot wipe() managed VIATRA Query Engine. Attempted for scope %s.", scope));
373 }
374 if (queryBackends != null) {
375 for (IQueryBackend backend : queryBackends.values()) {
376 backend.dispose();
377 }
378 queryBackends.clear();
379 }
380 matchers.clear();
381 queryAnalyzer = null;
382 lifecycleProvider.engineWiped();
383 }
384
385 /**
386 * Indicates whether the engine is in a tainted, inconsistent state.
387 */
388 private boolean tainted = false;
389 private IIndexingErrorListener taintListener = new SelfTaintListener(this);
390
391 private static class SelfTaintListener implements IIndexingErrorListener {
392 WeakReference<ViatraQueryEngineImpl> queryEngineRef;
393
394 public SelfTaintListener(ViatraQueryEngineImpl queryEngine) {
395 this.queryEngineRef = new WeakReference<ViatraQueryEngineImpl>(queryEngine);
396 }
397
398 public void engineBecameTainted(String description, Throwable t) {
399 final ViatraQueryEngineImpl queryEngine = queryEngineRef.get();
400 if (queryEngine != null) {
401 queryEngine.tainted = true;
402 queryEngine.lifecycleProvider.engineBecameTainted(description, t);
403 }
404 }
405
406 private boolean noTaintDetectedYet = true;
407
408 protected void notifyTainted(String description, Throwable t) {
409 if (noTaintDetectedYet) {
410 noTaintDetectedYet = false;
411 engineBecameTainted(description, t);
412 }
413 }
414
415 @Override
416 public void error(String description, Throwable t) {
417 // Errors does not mean tainting
418 }
419
420 @Override
421 public void fatal(String description, Throwable t) {
422 notifyTainted(description, t);
423 }
424 }
425
426 @Override
427 public boolean isTainted() {
428 return tainted;
429 }
430
431 @Override
432 public boolean isManaged() {
433 return manager != null;
434 // return isAdvanced; ???
435 }
436
437 private <Match extends IPatternMatch> IQueryResultProvider getUnderlyingResultProvider(
438 final BaseMatcher<Match> matcher) {
439 // IQueryResultProvider resultProvider = reteEngine.accessMatcher(matcher.getSpecification());
440 return matcher.backend;
441 }
442
443 @Override
444 public <Match extends IPatternMatch> void addMatchUpdateListener(final ViatraQueryMatcher<Match> matcher,
445 final IMatchUpdateListener<? super Match> listener, boolean fireNow) {
446
447 checkArgument(listener != null, "Cannot add null listener!");
448 checkArgument(matcher.getEngine() == this, "Cannot register listener for matcher of different engine!");
449 checkArgument(!disposed, "Cannot register listener on matcher of disposed engine!");
450
451 final BaseMatcher<Match> bm = (BaseMatcher<Match>) matcher;
452
453 final IUpdateable updateDispatcher = (updateElement, isInsertion) -> {
454 Match match = null;
455 try {
456 match = bm.newMatch(updateElement.getElements());
457 if (isInsertion)
458 listener.notifyAppearance(match);
459 else
460 listener.notifyDisappearance(match);
461 } catch (Throwable e) { // NOPMD
462 if (e instanceof Error)
463 throw (Error) e;
464 logger.warn(
465 String.format(
466 "The incremental pattern matcher encountered an error during %s a callback on %s of match %s of pattern %s. Error message: %s. (Developer note: %s in %s callback)",
467 match == null ? "preparing" : "invoking", isInsertion ? "insertion" : "removal",
468 match == null ? updateElement.toString() : match.prettyPrint(),
469 matcher.getPatternName(), e.getMessage(), e.getClass().getSimpleName(), listener),
470 e);
471 }
472
473 };
474
475 IQueryResultProvider resultProvider = getUnderlyingResultProvider(bm);
476 resultProvider.addUpdateListener(updateDispatcher, listener, fireNow);
477 }
478
479 @Override
480 public <Match extends IPatternMatch> void removeMatchUpdateListener(ViatraQueryMatcher<Match> matcher,
481 IMatchUpdateListener<? super Match> listener) {
482 checkArgument(listener != null, "Cannot remove null listener!");
483 checkArgument(matcher.getEngine() == this, "Cannot remove listener from matcher of different engine!");
484 checkArgument(!disposed, "Cannot remove listener from matcher of disposed engine!");
485
486 final BaseMatcher<Match> bm = (BaseMatcher<Match>) matcher;
487
488 try {
489 IQueryResultProvider resultProvider = getUnderlyingResultProvider(bm);
490 resultProvider.removeUpdateListener(listener);
491 } catch (Exception e) {
492 logger.error(
493 "Error while removing listener " + listener + " from the matcher of " + matcher.getPatternName(),
494 e);
495 }
496 }
497
498 @Override
499 public void addModelUpdateListener(ViatraQueryModelUpdateListener listener) {
500 modelUpdateProvider.addListener(listener);
501 }
502
503 @Override
504 public void removeModelUpdateListener(ViatraQueryModelUpdateListener listener) {
505 modelUpdateProvider.removeListener(listener);
506 }
507
508 @Override
509 public void addLifecycleListener(ViatraQueryEngineLifecycleListener listener) {
510 lifecycleProvider.addListener(listener);
511 }
512
513 @Override
514 public void removeLifecycleListener(ViatraQueryEngineLifecycleListener listener) {
515 lifecycleProvider.removeListener(listener);
516 }
517
518 /**
519 * Returns an internal interface towards the query backend to feed the matcher with results.
520 *
521 * @param query
522 * the pattern for which the result provider should be delivered
523 *
524 * @throws ViatraQueryRuntimeException
525 */
526 public IQueryResultProvider getResultProvider(IQuerySpecification<?> query) {
527 Preconditions.checkState(!disposed, QUERY_ON_DISPOSED_ENGINE_MESSAGE);
528
529 return getResultProviderInternal(query, null);
530 }
531
532 /**
533 * Returns an internal interface towards the query backend to feed the matcher with results.
534 *
535 * @param query
536 * the pattern for which the result provider should be delivered
537 *
538 * @throws ViatraQueryRuntimeException
539 */
540 public IQueryResultProvider getResultProvider(IQuerySpecification<?> query, QueryEvaluationHint hint) {
541 Preconditions.checkState(!disposed, QUERY_ON_DISPOSED_ENGINE_MESSAGE);
542
543 return getResultProviderInternal(query, hint);
544 }
545
546 /**
547 * This method returns the result provider exactly as described by the passed hint. Query cannot be null! Use
548 * {@link #getQueryEvaluationHint(IQuerySpecification, QueryEvaluationHint)} before passing a hint to this method to
549 * make sure engine and query specific hints are correctly applied.
550 *
551 * @throws ViatraQueryRuntimeException
552 */
553 private IQueryResultProvider getResultProviderInternal(IQuerySpecification<?> query, QueryEvaluationHint hint) {
554 return getResultProviderInternal(query.getInternalQueryRepresentation(), hint);
555 }
556
557 /**
558 * This method returns the result provider exactly as described by the passed hint. Query cannot be null! Use
559 * {@link #getQueryEvaluationHint(IQuerySpecification, QueryEvaluationHint)} before passing a hint to this method to
560 * make sure engine and query specific hints are correctly applied.
561 *
562 * @throws ViatraQueryRuntimeException
563 */
564 private IQueryResultProvider getResultProviderInternal(PQuery query, QueryEvaluationHint hint) {
565 Preconditions.checkArgument(query != null, "Query cannot be null!");
566 Preconditions.checkArgument(query.getStatus() != PQueryStatus.ERROR, "Cannot initialize a result provider for the erronoues query `%s`.", query.getSimpleName());
567 final IQueryBackend backend = getQueryBackend(engineOptions.getQueryBackendFactory(getQueryEvaluationHint(query, hint)));
568 return backend.getResultProvider(query, hint);
569 }
570
571 /**
572 * Returns the query backend (influenced by the hint system), even if it is a non-caching backend.
573 *
574 * @throws ViatraQueryRuntimeException
575 */
576 private IQueryBackend getQueryBackend(PQuery query) {
577 final IQueryBackendFactory factory = engineOptions.getQueryBackendFactory(getQueryEvaluationHint(query));
578 return getQueryBackend(factory);
579 }
580
581 /**
582 * Returns a caching query backend (influenced by the hint system).
583 *
584 * @throws ViatraQueryRuntimeException
585 */
586 private IQueryBackend getCachingQueryBackend(PQuery query) {
587 IQueryBackend regularBackend = getQueryBackend(query);
588 if (regularBackend.isCaching())
589 return regularBackend;
590 else
591 return getQueryBackend(engineOptions.getDefaultCachingBackendFactory());
592 }
593
594 @Override
595 public boolean isResultCached(PQuery query) {
596 try {
597 return null != getCachingQueryBackend(query).peekExistingResultProvider(query);
598 } catch (ViatraQueryException iqe) {
599 getLogger().error(ERROR_ACCESSING_BACKEND, iqe);
600 return false;
601 }
602 }
603
604 @Override
605 public IQueryResultProvider getCachingResultProvider(PQuery query) {
606 try {
607 return getCachingQueryBackend(query).getResultProvider(query);
608 } catch (ViatraQueryException iqe) {
609 getLogger().error(ERROR_ACCESSING_BACKEND, iqe);
610 throw iqe;
611 }
612 }
613
614 private QueryEvaluationHint getEngineDefaultHint() {
615 return engineOptions.getEngineDefaultHints();
616 }
617
618 @Override
619 public QueryEvaluationHint getQueryEvaluationHint(PQuery query) {
620 return getEngineDefaultHint().overrideBy(query.getEvaluationHints());
621 }
622
623 private QueryEvaluationHint getQueryEvaluationHint(IQuerySpecification<?> querySpecification,
624 QueryEvaluationHint optionalOverrideHints) {
625 return getQueryEvaluationHint(querySpecification.getInternalQueryRepresentation())
626 .overrideBy(optionalOverrideHints);
627 }
628
629 private QueryEvaluationHint getQueryEvaluationHint(PQuery query, QueryEvaluationHint optionalOverrideHints) {
630 return getQueryEvaluationHint(query).overrideBy(optionalOverrideHints);
631 }
632
633 private IMatcherCapability getRequestedCapability(IQuerySpecification<?> querySpecification,
634 QueryEvaluationHint optionalOverrideHints) {
635 final QueryEvaluationHint hint = getQueryEvaluationHint(querySpecification, optionalOverrideHints);
636 return engineOptions.getQueryBackendFactory(hint)
637 .calculateRequiredCapability(querySpecification.getInternalQueryRepresentation(), hint);
638 }
639
640 @Override
641 public void prepareGroup(IQueryGroup queryGroup, final QueryEvaluationHint optionalEvaluationHints) {
642 try {
643 Preconditions.checkState(!disposed, QUERY_ON_DISPOSED_ENGINE_MESSAGE);
644
645 final Set<IQuerySpecification<?>> specifications = new HashSet<IQuerySpecification<?>>(
646 queryGroup.getSpecifications());
647 final Collection<PQuery> patterns = specifications.stream().map(
648 IQuerySpecification::getInternalQueryRepresentation).collect(Collectors.toList());
649 patterns.forEach(PQuery::ensureInitialized);
650
651 Collection<String> erroneousPatterns = patterns.stream().
652 filter(PQueries.queryStatusPredicate(PQueryStatus.ERROR)).
653 map(PQuery::getFullyQualifiedName).
654 collect(Collectors.toList());
655 Preconditions.checkState(erroneousPatterns.isEmpty(), "Erroneous query(s) found: %s",
656 erroneousPatterns.stream().collect(Collectors.joining(", ")));
657
658 // TODO maybe do some smarter preparation per backend?
659 try {
660 engineContext.getBaseIndex().coalesceTraversals(new Callable<Void>() {
661 @Override
662 public Void call() throws Exception {
663 for (IQuerySpecification<?> query : specifications) {
664 getResultProviderInternal(query, optionalEvaluationHints);
665 }
666 return null;
667 }
668 });
669 } catch (InvocationTargetException ex) {
670 final Throwable cause = ex.getCause();
671 if (cause instanceof QueryProcessingException)
672 throw (QueryProcessingException) cause;
673 if (cause instanceof ViatraQueryException)
674 throw (ViatraQueryException) cause;
675 if (cause instanceof RuntimeException)
676 throw (RuntimeException) cause;
677 assert (false);
678 }
679 } catch (QueryProcessingException e) {
680 throw new ViatraQueryException(e);
681 }
682 }
683
684 @Override
685 public QueryScope getScope() {
686 return scope;
687 }
688
689 @Override
690 public ViatraQueryEngineOptions getEngineOptions() {
691 return engineOptions;
692 }
693
694 @Override
695 public IQueryResultProvider getResultProviderOfMatcher(ViatraQueryMatcher<? extends IPatternMatch> matcher) {
696 return ((QueryResultWrapper) matcher).backend;
697 }
698
699 @Override
700 public IQueryResultProvider getResultProvider(PQuery query, QueryEvaluationHint overrideHints) {
701 try {
702 return getResultProviderInternal(query, overrideHints);
703 } catch (ViatraQueryException e) {
704 getLogger().error(ERROR_ACCESSING_BACKEND, e);
705 throw e;
706 }
707 }
708
709 @Override
710 public boolean isDisposed() {
711 return disposed;
712 }
713
714}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/engine/LifecycleProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/engine/LifecycleProvider.java
new file mode 100644
index 00000000..8bbf2a66
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/engine/LifecycleProvider.java
@@ -0,0 +1,138 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Abel Hegedus, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.internal.engine;
10
11import java.util.ArrayList;
12
13import org.apache.log4j.Logger;
14import tools.refinery.viatra.runtime.api.AdvancedViatraQueryEngine;
15import tools.refinery.viatra.runtime.api.IPatternMatch;
16import tools.refinery.viatra.runtime.api.ViatraQueryEngineLifecycleListener;
17import tools.refinery.viatra.runtime.api.ViatraQueryMatcher;
18
19public final class LifecycleProvider extends ListenerContainer<ViatraQueryEngineLifecycleListener> implements ViatraQueryEngineLifecycleListener{
20
21 private final Logger logger;
22
23 /**
24 * @param queryEngine
25 */
26 public LifecycleProvider(AdvancedViatraQueryEngine queryEngine, Logger logger) {
27 this.logger = logger;
28 }
29
30 @Override
31 protected void listenerAdded(ViatraQueryEngineLifecycleListener listener) {
32 logger.debug("Lifecycle listener " + listener + " added to engine.");
33 }
34
35 @Override
36 protected void listenerRemoved(ViatraQueryEngineLifecycleListener listener) {
37 logger.debug("Lifecycle listener " + listener + " removed from engine.");
38 }
39
40// public void propagateEventToListeners(Predicate<ViatraQueryEngineLifecycleListener> function) {
41// if (!listeners.isEmpty()) {
42// for (ViatraQueryEngineLifecycleListener listener : new ArrayList<ViatraQueryEngineLifecycleListener>(listeners)) {
43// try {
44// function.apply(listener);
45// } catch (Exception ex) {
46// logger.error(
47// "VIATRA Query encountered an error in delivering notification to listener "
48// + listener + ".", ex);
49// }
50// }
51// }
52// }
53
54 @Override
55 public void matcherInstantiated(final ViatraQueryMatcher<? extends IPatternMatch> matcher) {
56 if (!listeners.isEmpty()) {
57 for (ViatraQueryEngineLifecycleListener listener : new ArrayList<ViatraQueryEngineLifecycleListener>(listeners)) {
58 try {
59 listener.matcherInstantiated(matcher);
60 } catch (Exception ex) {
61 logger.error(
62 "VIATRA Query encountered an error in delivering matcher initialization notification to listener "
63 + listener + ".", ex);
64 }
65 }
66 }
67// propagateEventToListeners(new Predicate<ViatraQueryEngineLifecycleListener>() {
68// public boolean apply(ViatraQueryEngineLifecycleListener listener) {
69// listener.matcherInstantiated(matcher);
70// return true;
71// }
72// });
73 }
74
75 @Override
76 public void engineBecameTainted(String description, Throwable t) {
77 if (!listeners.isEmpty()) {
78 for (ViatraQueryEngineLifecycleListener listener : new ArrayList<ViatraQueryEngineLifecycleListener>(listeners)) {
79 try {
80 listener.engineBecameTainted(description, t);
81 } catch (Exception ex) {
82 logger.error(
83 "VIATRA Query encountered an error in delivering engine tainted notification to listener "
84 + listener + ".", ex);
85 }
86 }
87 }
88// propagateEventToListeners(new Predicate<ViatraQueryEngineLifecycleListener>() {
89// public boolean apply(ViatraQueryEngineLifecycleListener listener) {
90// listener.engineBecameTainted();
91// return true;
92// }
93// });
94 }
95
96 @Override
97 public void engineWiped() {
98 if (!listeners.isEmpty()) {
99 for (ViatraQueryEngineLifecycleListener listener : new ArrayList<ViatraQueryEngineLifecycleListener>(listeners)) {
100 try {
101 listener.engineWiped();
102 } catch (Exception ex) {
103 logger.error(
104 "VIATRA Query encountered an error in delivering engine wiped notification to listener "
105 + listener + ".", ex);
106 }
107 }
108 }
109// propagateEventToListeners(new Predicate<ViatraQueryEngineLifecycleListener>() {
110// public boolean apply(ViatraQueryEngineLifecycleListener listener) {
111// listener.engineWiped();
112// return true;
113// }
114// });
115 }
116
117 @Override
118 public void engineDisposed() {
119 if (!listeners.isEmpty()) {
120 for (ViatraQueryEngineLifecycleListener listener : new ArrayList<ViatraQueryEngineLifecycleListener>(listeners)) {
121 try {
122 listener.engineDisposed();
123 } catch (Exception ex) {
124 logger.error(
125 "VIATRA Query encountered an error in delivering engine disposed notification to listener "
126 + listener + ".", ex);
127 }
128 }
129 }
130// propagateEventToListeners(new Predicate<ViatraQueryEngineLifecycleListener>() {
131// public boolean apply(ViatraQueryEngineLifecycleListener listener) {
132// listener.engineDisposed();
133// return true;
134// }
135// });
136 }
137
138 } \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/engine/ListenerContainer.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/engine/ListenerContainer.java
new file mode 100644
index 00000000..34133bed
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/engine/ListenerContainer.java
@@ -0,0 +1,43 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Abel Hegedus, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.internal.engine;
10
11import static tools.refinery.viatra.runtime.matchers.util.Preconditions.checkArgument;
12
13import java.util.HashSet;
14import java.util.Set;
15
16public abstract class ListenerContainer<Listener> {
17
18 protected final Set<Listener> listeners;
19
20 public ListenerContainer() {
21 this.listeners = new HashSet<Listener>();
22 }
23
24 public synchronized void addListener(Listener listener) {
25 checkArgument(listener != null, "Cannot add null listener!");
26 boolean added = listeners.add(listener);
27 if(added) {
28 listenerAdded(listener);
29 }
30 }
31
32 public synchronized void removeListener(Listener listener) {
33 checkArgument(listener != null, "Cannot remove null listener!");
34 boolean removed = listeners.remove(listener);
35 if(removed) {
36 listenerRemoved(listener);
37 }
38 }
39
40 protected abstract void listenerAdded(Listener listener);
41
42 protected abstract void listenerRemoved(Listener listener);
43} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/engine/ModelUpdateProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/engine/ModelUpdateProvider.java
new file mode 100644
index 00000000..1f2c27e8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/internal/engine/ModelUpdateProvider.java
@@ -0,0 +1,214 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Abel Hegedus, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.internal.engine;
10
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.Collections;
14import java.util.EnumMap;
15import java.util.HashSet;
16import java.util.Map;
17import java.util.Map.Entry;
18
19import org.apache.log4j.Logger;
20import tools.refinery.viatra.runtime.api.AdvancedViatraQueryEngine;
21import tools.refinery.viatra.runtime.api.IMatchUpdateListener;
22import tools.refinery.viatra.runtime.api.IPatternMatch;
23import tools.refinery.viatra.runtime.api.ViatraQueryEngineLifecycleListener;
24import tools.refinery.viatra.runtime.api.ViatraQueryMatcher;
25import tools.refinery.viatra.runtime.api.ViatraQueryModelUpdateListener;
26import tools.refinery.viatra.runtime.api.ViatraQueryModelUpdateListener.ChangeLevel;
27import tools.refinery.viatra.runtime.api.scope.ViatraBaseIndexChangeListener;
28import tools.refinery.viatra.runtime.exception.ViatraQueryException;
29import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
30
31public final class ModelUpdateProvider extends ListenerContainer<ViatraQueryModelUpdateListener> {
32
33 private final AdvancedViatraQueryEngine queryEngine;
34 private ChangeLevel currentChange = ChangeLevel.NO_CHANGE;
35 private ChangeLevel maxLevel = ChangeLevel.NO_CHANGE;
36 private final Map<ChangeLevel, Collection<ViatraQueryModelUpdateListener>> listenerMap;
37 private final Logger logger;
38
39 public ModelUpdateProvider(AdvancedViatraQueryEngine queryEngine, Logger logger) {
40 super();
41 this.queryEngine = queryEngine;
42 this.logger = logger;
43 listenerMap = new EnumMap<>(ChangeLevel.class);
44 }
45
46 @Override
47 protected void listenerAdded(ViatraQueryModelUpdateListener listener) {
48 // check ChangeLevel
49 // create callback for given level if required
50 if(listenerMap.isEmpty()) {
51 try {
52 this.queryEngine.getBaseIndex().addBaseIndexChangeListener(indexListener);
53 // add listener to new matchers (use lifecycle listener)
54 this.queryEngine.addLifecycleListener(selfListener);
55 } catch (ViatraQueryException e) {
56 throw new IllegalStateException("Model update listener used on engine without base index", e);
57 }
58 }
59
60 ChangeLevel changeLevel = listener.getLevel();
61 listenerMap.computeIfAbsent(changeLevel, k -> CollectionsFactory.createSet()).add(listener);
62 // increase or keep max level of listeners
63 ChangeLevel oldMaxLevel = maxLevel;
64 maxLevel = maxLevel.changeOccured(changeLevel);
65 if(!maxLevel.equals(oldMaxLevel) && ChangeLevel.MATCHSET.compareTo(oldMaxLevel) > 0 && ChangeLevel.MATCHSET.compareTo(maxLevel) <= 0) {
66 // add matchUpdateListener to all matchers
67 for (ViatraQueryMatcher<?> matcher : this.queryEngine.getCurrentMatchers()) {
68 this.queryEngine.addMatchUpdateListener(matcher, matchSetListener, false);
69 }
70 }
71 }
72
73 @Override
74 protected void listenerRemoved(ViatraQueryModelUpdateListener listener) {
75 ChangeLevel changeLevel = listener.getLevel();
76 Collection<ViatraQueryModelUpdateListener> old = listenerMap.getOrDefault(changeLevel, Collections.emptySet());
77 boolean removed = old.remove(listener);
78 if(removed) {
79 if (old.isEmpty()) listenerMap.remove(changeLevel);
80 } else {
81 handleUnsuccesfulRemove(listener);
82 }
83
84 updateMaxLevel();
85
86 if(listenerMap.isEmpty()) {
87 this.queryEngine.removeLifecycleListener(selfListener);
88 removeBaseIndexChangeListener();
89 }
90 }
91
92 private void removeBaseIndexChangeListener() {
93 try {
94 this.queryEngine.getBaseIndex().removeBaseIndexChangeListener(indexListener);
95 } catch (ViatraQueryException e) {
96 throw new IllegalStateException("Model update listener used on engine without base index", e);
97 }
98 }
99
100 private void updateMaxLevel() {
101 if(!listenerMap.containsKey(maxLevel)) {
102 ChangeLevel newMaxLevel = ChangeLevel.NO_CHANGE;
103 for (ChangeLevel level : new HashSet<>(listenerMap.keySet())) {
104 newMaxLevel = newMaxLevel.changeOccured(level);
105 }
106 maxLevel = newMaxLevel;
107 }
108 if(maxLevel.compareTo(ChangeLevel.MATCHSET) < 0) {
109 // remove listener from matchers
110 for (ViatraQueryMatcher<?> matcher : this.queryEngine.getCurrentMatchers()) {
111 this.queryEngine.removeMatchUpdateListener(matcher, matchSetListener);
112 }
113 }
114 }
115
116 private void handleUnsuccesfulRemove(ViatraQueryModelUpdateListener listener) {
117 for (Entry<ChangeLevel, Collection<ViatraQueryModelUpdateListener>> entry : listenerMap.entrySet()) {
118 Collection<ViatraQueryModelUpdateListener> existingListeners = entry.getValue();
119 // if the listener is contained in some other bucket, remove it from there
120 if(existingListeners.remove(listener)) {
121 logger.error("Listener "+listener+" change level changed since initialization!");
122 if (existingListeners.isEmpty()) listenerMap.remove(entry.getKey());
123 return; // listener is contained only once
124 }
125 }
126 logger.error("Listener "+listener+" already removed from map (e.g. engine was already disposed)!");
127 }
128
129 private void notifyListeners() {
130
131 // any change that occurs after this point should be regarded as a new event
132 // FIXME what should happen when a listener creates new notifications?
133 // -> other listeners will get events in different order
134 ChangeLevel tempLevel = currentChange;
135 currentChange = ChangeLevel.NO_CHANGE;
136
137 if(!listenerMap.isEmpty()) {
138 for (ChangeLevel level : new HashSet<>(listenerMap.keySet())) {
139 if(tempLevel.compareTo(level) >= 0) {
140 for (ViatraQueryModelUpdateListener listener : new ArrayList<>(listenerMap.get(level))) {
141 try {
142 listener.notifyChanged(tempLevel);
143 } catch (Exception ex) {
144 logger.error(
145 "VIATRA Query encountered an error in delivering model update notification to listener "
146 + listener + ".", ex);
147 }
148 }
149 }
150 }
151 } else {
152 throw new IllegalStateException("Notify listeners must not be called without listeners! Maybe an update callback was not removed correctly.");
153 }
154
155 }
156
157 // model update "providers":
158 // - model: IQBase callback even if not dirty
159 // - index: IQBase dirty callback
160 private final ViatraBaseIndexChangeListener indexListener = new ViatraBaseIndexChangeListener() {
161
162 @Override
163 public boolean onlyOnIndexChange() {
164 return false;
165 }
166
167 @Override
168 public void notifyChanged(boolean indexChanged) {
169 if(indexChanged) {
170 currentChange = currentChange.changeOccured(ChangeLevel.INDEX);
171 } else {
172 currentChange = currentChange.changeOccured(ChangeLevel.MODEL);
173 }
174 notifyListeners();
175 }
176
177 };
178 // - matchset: add the same listener to each matcher and use a dirty flag. needs IQBase callback as well
179 private final IMatchUpdateListener<IPatternMatch> matchSetListener = new IMatchUpdateListener<IPatternMatch>() {
180
181 @Override
182 public void notifyDisappearance(IPatternMatch match) {
183 currentChange = currentChange.changeOccured(ChangeLevel.MATCHSET);
184 }
185
186 @Override
187 public void notifyAppearance(IPatternMatch match) {
188 currentChange = currentChange.changeOccured(ChangeLevel.MATCHSET);
189 }
190 };
191
192 private final ViatraQueryEngineLifecycleListener selfListener = new ViatraQueryEngineLifecycleListener() {
193
194 @Override
195 public void matcherInstantiated(ViatraQueryMatcher<? extends IPatternMatch> matcher) {
196 if (maxLevel.compareTo(ChangeLevel.MATCHSET) >= 0) {
197 ModelUpdateProvider.this.queryEngine.addMatchUpdateListener(matcher, matchSetListener, false);
198 }
199 }
200
201 @Override
202 public void engineWiped() {}
203
204 @Override
205 public void engineDisposed() {
206 removeBaseIndexChangeListener();
207 listenerMap.clear();
208 maxLevel = ChangeLevel.NO_CHANGE;
209 }
210
211 @Override
212 public void engineBecameTainted(String description, Throwable t) {}
213 };
214}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/ViatraQueryRuntimeException.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/ViatraQueryRuntimeException.java
new file mode 100644
index 00000000..83f6f766
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/ViatraQueryRuntimeException.java
@@ -0,0 +1,42 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers;
10
11/**
12 * A common base class for all exceptions thrown by various VIATRA Query Runtime APIs.
13 *
14 * @author Zoltan Ujhelyi
15 * @since 2.0
16 */
17public abstract class ViatraQueryRuntimeException extends RuntimeException {
18
19 private static final long serialVersionUID = -8505253058035069310L;
20
21 public ViatraQueryRuntimeException() {
22 super();
23 }
24
25 public ViatraQueryRuntimeException(String message) {
26 super(message);
27 }
28
29 public ViatraQueryRuntimeException(Throwable cause) {
30 super(cause);
31 }
32
33 public ViatraQueryRuntimeException(String message, Throwable cause) {
34 super(message, cause);
35 }
36
37 public ViatraQueryRuntimeException(String message, Throwable cause, boolean enableSuppression,
38 boolean writableStackTrace) {
39 super(message, cause, enableSuppression, writableStackTrace);
40 }
41
42}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/AverageAccumulator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/AverageAccumulator.java
new file mode 100644
index 00000000..2c09ede1
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/AverageAccumulator.java
@@ -0,0 +1,24 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11/**
12 * @since 2.0
13 */
14class AverageAccumulator<Domain> {
15 Domain value;
16 long count;
17
18 public AverageAccumulator(Domain value, long count) {
19 super();
20 this.value = value;
21 this.count = count;
22 }
23
24} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleAverageOperator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleAverageOperator.java
new file mode 100644
index 00000000..e8a26afd
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleAverageOperator.java
@@ -0,0 +1,82 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import java.util.OptionalDouble;
12import java.util.stream.Stream;
13
14import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator;
15
16/**
17 * @author Zoltan Ujhelyi
18 * @since 2.0
19 */
20public class DoubleAverageOperator implements IMultisetAggregationOperator<Double, AverageAccumulator<Double>, Double> {
21
22 public static final DoubleAverageOperator INSTANCE = new DoubleAverageOperator();
23
24 private DoubleAverageOperator() {
25 // Singleton, do not call.
26 }
27
28 @Override
29 public String getShortDescription() {
30 return "avg<Integer> incrementally computes the average of java.lang.Integer values";
31 }
32
33 @Override
34 public String getName() {
35 return "avg<Integer>";
36 }
37
38 @Override
39 public AverageAccumulator<Double> createNeutral() {
40 return new AverageAccumulator<Double>(0d, 0l);
41 }
42
43 @Override
44 public boolean isNeutral(AverageAccumulator<Double> result) {
45 return result.count == 0l;
46 }
47
48 @Override
49 public AverageAccumulator<Double> update(AverageAccumulator<Double> oldResult, Double updateValue,
50 boolean isInsertion) {
51 if (isInsertion) {
52 oldResult.value += updateValue;
53 oldResult.count++;
54 } else {
55 oldResult.value -= updateValue;
56 oldResult.count--;
57 }
58 return oldResult;
59 }
60
61 @Override
62 public Double getAggregate(AverageAccumulator<Double> result) {
63 return (result.count == 0)
64 ? null
65 : result.value/result.count;
66 }
67
68 @Override
69 public Double aggregateStream(Stream<Double> stream) {
70 final OptionalDouble averageOpt = stream.mapToDouble(Double::doubleValue).average();
71 return averageOpt.isPresent() ? averageOpt.getAsDouble() : null;
72 }
73
74 /**
75 * @since 2.4
76 */
77 @Override
78 public AverageAccumulator<Double> clone(AverageAccumulator<Double> original) {
79 return new AverageAccumulator<Double>(original.value, original.count);
80 }
81
82} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleSumOperator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleSumOperator.java
new file mode 100644
index 00000000..744b0cd1
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/DoubleSumOperator.java
@@ -0,0 +1,62 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import java.util.stream.Stream;
12
13import tools.refinery.viatra.runtime.matchers.psystem.aggregations.AbstractMemorylessAggregationOperator;
14
15/**
16 * Incrementally computes the sum of java.lang.Double values
17 * @author Gabor Bergmann
18 * @since 1.4
19 */
20public class DoubleSumOperator extends AbstractMemorylessAggregationOperator<Double, Double> {
21 public static final DoubleSumOperator INSTANCE = new DoubleSumOperator();
22
23 private DoubleSumOperator() {
24 // Singleton, do not call.
25 }
26
27 @Override
28 public String getShortDescription() {
29 return "sum<Double> incrementally computes the sum of java.lang.Double values";
30 }
31 @Override
32 public String getName() {
33 return "sum<Double>";
34 }
35
36 @Override
37 public Double createNeutral() {
38 return 0d;
39 }
40
41 @Override
42 public boolean isNeutral(Double result) {
43 return createNeutral().equals(result);
44 }
45
46 @Override
47 public Double update(Double oldResult, Double updateValue, boolean isInsertion) {
48 return isInsertion ?
49 oldResult + updateValue :
50 oldResult - updateValue;
51 }
52
53 /**
54 * @since 2.0
55 */
56 @Override
57 public Double aggregateStream(Stream<Double> stream) {
58 return stream.mapToDouble(Double::doubleValue).sum();
59 }
60
61
62}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/ExtremumOperator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/ExtremumOperator.java
new file mode 100644
index 00000000..ee4ceeb8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/ExtremumOperator.java
@@ -0,0 +1,135 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import java.util.Comparator;
12import java.util.SortedMap;
13import java.util.TreeMap;
14import java.util.stream.Stream;
15
16import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator;
17
18/**
19 * Incrementally computes the minimum or maximum of java.lang.Comparable values, using the default comparison
20 *
21 * @author Gabor Bergmann
22 * @since 1.4
23 */
24public class ExtremumOperator<T extends Comparable<T>>
25 implements IMultisetAggregationOperator<T, SortedMap<T, Integer>, T> {
26
27 public enum Extreme {
28 MIN, MAX;
29
30 /**
31 * @since 2.0
32 */
33 public <T> T pickFrom(SortedMap<T, Integer> nonEmptyMultiSet) {
34 switch(this) {
35 case MIN:
36 return nonEmptyMultiSet.firstKey();
37 case MAX:
38 return nonEmptyMultiSet.lastKey();
39 default:
40 return null;
41 }
42 }
43 }
44
45 private static final ExtremumOperator MIN_OP = new ExtremumOperator<>(Extreme.MIN);
46 private static final ExtremumOperator MAX_OP = new ExtremumOperator<>(Extreme.MAX);
47
48 public static <T extends Comparable<T>> ExtremumOperator<T> getMin() {
49 return MIN_OP;
50 }
51 public static <T extends Comparable<T>> ExtremumOperator<T> getMax() {
52 return MAX_OP;
53 }
54
55 Extreme extreme;
56 private ExtremumOperator(Extreme extreme) {
57 super();
58 this.extreme = extreme;
59 }
60
61 @Override
62 public String getShortDescription() {
63 String opName = getName();
64 return String.format(
65 "%s incrementally computes the %simum of java.lang.Comparable values, using the default comparison",
66 opName, opName);
67 }
68
69 @Override
70 public String getName() {
71 return extreme.name().toLowerCase();
72 }
73
74 /**
75 * @since 2.0
76 */
77 @Override
78 public SortedMap<T, Integer> createNeutral() {
79 return new TreeMap<>();
80 }
81
82 /**
83 * @since 2.0
84 */
85 @Override
86 public boolean isNeutral(SortedMap<T, Integer> result) {
87 return result.isEmpty();
88 }
89
90 /**
91 * @since 2.0
92 */
93 @Override
94 public SortedMap<T, Integer> update(SortedMap<T, Integer> oldResult, T updateValue, boolean isInsertion) {
95 oldResult.compute(updateValue, (value, c) -> {
96 int count = (c == null) ? 0 : c;
97 int result = (isInsertion) ? count+1 : count-1;
98 return (result == 0) ? null : result;
99 });
100 return oldResult;
101 }
102
103 /**
104 * @since 2.0
105 */
106 @Override
107 public T getAggregate(SortedMap<T, Integer> result) {
108 return result.isEmpty() ? null :
109 extreme.pickFrom(result);
110 }
111
112 /**
113 * @since 2.0
114 */
115 @Override
116 public T aggregateStream(Stream<T> stream) {
117 switch (extreme) {
118 case MIN:
119 return stream.min(Comparator.naturalOrder()).orElse(null);
120 case MAX:
121 return stream.max(Comparator.naturalOrder()).orElse(null);
122 default:
123 return null;
124 }
125 }
126
127 /**
128 * @since 2.4
129 */
130 @Override
131 public SortedMap<T, Integer> clone(SortedMap<T, Integer> original) {
132 return new TreeMap<T, Integer>(original);
133 }
134
135}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerAverageOperator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerAverageOperator.java
new file mode 100644
index 00000000..bf422476
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerAverageOperator.java
@@ -0,0 +1,82 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import java.util.OptionalDouble;
12import java.util.stream.Stream;
13
14import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator;
15
16/**
17 * @author Zoltan Ujhelyi
18 * @since 2.0
19 */
20public class IntegerAverageOperator implements IMultisetAggregationOperator<Integer, AverageAccumulator<Integer>, Double> {
21
22 public static final IntegerAverageOperator INSTANCE = new IntegerAverageOperator();
23
24 private IntegerAverageOperator() {
25 // Singleton, do not call.
26 }
27
28 @Override
29 public String getShortDescription() {
30 return "avg<Integer> incrementally computes the average of java.lang.Integer values";
31 }
32
33 @Override
34 public String getName() {
35 return "avg<Integer>";
36 }
37
38 @Override
39 public AverageAccumulator<Integer> createNeutral() {
40 return new AverageAccumulator<Integer>(0, 0l);
41 }
42
43 @Override
44 public boolean isNeutral(AverageAccumulator<Integer> result) {
45 return result.count == 0l;
46 }
47
48 @Override
49 public AverageAccumulator<Integer> update(AverageAccumulator<Integer> oldResult, Integer updateValue,
50 boolean isInsertion) {
51 if (isInsertion) {
52 oldResult.value += updateValue;
53 oldResult.count++;
54 } else {
55 oldResult.value -= updateValue;
56 oldResult.count--;
57 }
58 return oldResult;
59 }
60
61 @Override
62 public Double getAggregate(AverageAccumulator<Integer> result) {
63 return (result.count == 0)
64 ? null
65 : ((double)result.value)/result.count;
66 }
67
68 @Override
69 public Double aggregateStream(Stream<Integer> stream) {
70 final OptionalDouble averageOpt = stream.mapToInt(Integer::intValue).average();
71 return averageOpt.isPresent() ? averageOpt.getAsDouble() : null;
72 }
73
74 /**
75 * @since 2.4
76 */
77 @Override
78 public AverageAccumulator<Integer> clone(AverageAccumulator<Integer> original) {
79 return new AverageAccumulator<Integer>(original.value, original.count);
80 }
81
82} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerSumOperator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerSumOperator.java
new file mode 100644
index 00000000..18584256
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/IntegerSumOperator.java
@@ -0,0 +1,61 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import java.util.stream.Stream;
12
13import tools.refinery.viatra.runtime.matchers.psystem.aggregations.AbstractMemorylessAggregationOperator;
14
15/**
16 * Incrementally computes the sum of java.lang.Integer values
17 * @author Gabor Bergmann
18 * @since 1.4
19 */
20public class IntegerSumOperator extends AbstractMemorylessAggregationOperator<Integer, Integer> {
21 public static final IntegerSumOperator INSTANCE = new IntegerSumOperator();
22
23 private IntegerSumOperator() {
24 // Singleton, do not call.
25 }
26
27 @Override
28 public String getShortDescription() {
29 return "sum<Integer> incrementally computes the sum of java.lang.Integer values";
30 }
31 @Override
32 public String getName() {
33 return "sum<Integer>";
34 }
35
36 @Override
37 public Integer createNeutral() {
38 return 0;
39 }
40
41 @Override
42 public boolean isNeutral(Integer result) {
43 return createNeutral().equals(result);
44 }
45
46 @Override
47 public Integer update(Integer oldResult, Integer updateValue, boolean isInsertion) {
48 return isInsertion ?
49 oldResult + updateValue :
50 oldResult - updateValue;
51 }
52
53 /**
54 * @since 2.0
55 */
56 @Override
57 public Integer aggregateStream(Stream<Integer> stream) {
58 return stream.mapToInt(Integer::intValue).sum();
59 }
60
61}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongAverageOperator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongAverageOperator.java
new file mode 100644
index 00000000..d56c9507
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongAverageOperator.java
@@ -0,0 +1,82 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import java.util.OptionalDouble;
12import java.util.stream.Stream;
13
14import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator;
15
16/**
17 * @author Zoltan Ujhelyi
18 * @since 2.0
19 */
20public class LongAverageOperator implements IMultisetAggregationOperator<Long, AverageAccumulator<Long>, Double> {
21
22 public static final LongAverageOperator INSTANCE = new LongAverageOperator();
23
24 private LongAverageOperator() {
25 // Singleton, do not call.
26 }
27
28 @Override
29 public String getShortDescription() {
30 return "avg<Integer> incrementally computes the average of java.lang.Integer values";
31 }
32
33 @Override
34 public String getName() {
35 return "avg<Integer>";
36 }
37
38 @Override
39 public AverageAccumulator<Long> createNeutral() {
40 return new AverageAccumulator<Long>(0l, 0l);
41 }
42
43 @Override
44 public boolean isNeutral(AverageAccumulator<Long> result) {
45 return result.count == 0l;
46 }
47
48 @Override
49 public AverageAccumulator<Long> update(AverageAccumulator<Long> oldResult, Long updateValue,
50 boolean isInsertion) {
51 if (isInsertion) {
52 oldResult.value += updateValue;
53 oldResult.count++;
54 } else {
55 oldResult.value -= updateValue;
56 oldResult.count--;
57 }
58 return oldResult;
59 }
60
61 @Override
62 public Double getAggregate(AverageAccumulator<Long> result) {
63 return (result.count == 0)
64 ? null
65 : ((double)result.value)/result.count;
66 }
67
68 @Override
69 public Double aggregateStream(Stream<Long> stream) {
70 final OptionalDouble averageOpt = stream.mapToLong(Long::longValue).average();
71 return averageOpt.isPresent() ? averageOpt.getAsDouble() : null;
72 }
73
74 /**
75 * @since 2.4
76 */
77 @Override
78 public AverageAccumulator<Long> clone(AverageAccumulator<Long> original) {
79 return new AverageAccumulator<Long>(original.value, original.count);
80 }
81
82} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongSumOperator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongSumOperator.java
new file mode 100644
index 00000000..29ded090
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/LongSumOperator.java
@@ -0,0 +1,61 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import java.util.stream.Stream;
12
13import tools.refinery.viatra.runtime.matchers.psystem.aggregations.AbstractMemorylessAggregationOperator;
14
15/**
16 * Incrementally computes the sum of java.lang.Long values
17 * @author Gabor Bergmann
18 * @since 1.4
19 */
20public class LongSumOperator extends AbstractMemorylessAggregationOperator<Long, Long> {
21 public static final LongSumOperator INSTANCE = new LongSumOperator();
22
23 private LongSumOperator() {
24 // Singleton, do not call.
25 }
26
27 @Override
28 public String getShortDescription() {
29 return "sum<Long> incrementally computes the sum of java.lang.Long values";
30 }
31 @Override
32 public String getName() {
33 return "sum<Long>";
34 }
35
36 @Override
37 public Long createNeutral() {
38 return 0L;
39 }
40
41 @Override
42 public boolean isNeutral(Long result) {
43 return createNeutral().equals(result);
44 }
45
46 @Override
47 public Long update(Long oldResult, Long updateValue, boolean isInsertion) {
48 return isInsertion ?
49 oldResult + updateValue :
50 oldResult - updateValue;
51 }
52
53 /**
54 * @since 2.0
55 */
56 @Override
57 public Long aggregateStream(Stream<Long> stream) {
58 return stream.mapToLong(Long::longValue).sum();
59 }
60
61}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/avg.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/avg.java
new file mode 100644
index 00000000..c25678aa
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/avg.java
@@ -0,0 +1,39 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import tools.refinery.viatra.runtime.matchers.psystem.aggregations.AggregatorType;
12import tools.refinery.viatra.runtime.matchers.psystem.aggregations.BoundAggregator;
13import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IAggregatorFactory;
14
15/**
16 * This aggregator calculates the average of the values of a selected aggregate parameter of a called pattern. The aggregate
17 * parameter is selected with the '#' symbol; the aggregate parameter must not be used outside the aggregator call. The
18 * other parameters of the call might be bound or unbound; bound parameters limit the matches to consider for the
19 * summation.
20 *
21 * @since 2.0
22 *
23 */
24@AggregatorType(
25 parameterTypes = {Integer.class, Double.class, Long.class},
26 returnTypes = {Double.class, Double.class, Double.class})
27public final class avg implements IAggregatorFactory {
28
29 @Override
30 public BoundAggregator getAggregatorLogic(Class<?> domainClass) {
31 if (Integer.class.equals(domainClass))
32 return new BoundAggregator(IntegerAverageOperator.INSTANCE, Integer.class, Double.class);
33 if (Double.class.equals(domainClass))
34 return new BoundAggregator(DoubleAverageOperator.INSTANCE, Double.class, Double.class);
35 if (Long.class.equals(domainClass))
36 return new BoundAggregator(LongAverageOperator.INSTANCE, Long.class, Double.class);
37 else throw new IllegalArgumentException();
38 }
39}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/count.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/count.java
new file mode 100644
index 00000000..8310a0ce
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/count.java
@@ -0,0 +1,33 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import tools.refinery.viatra.runtime.matchers.psystem.aggregations.AggregatorType;
12import tools.refinery.viatra.runtime.matchers.psystem.aggregations.BoundAggregator;
13import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IAggregatorFactory;
14
15/**
16 * An aggregator to count the number of matches a pattern has. The return of the aggregator is an non-negative integer
17 * number.
18 *
19 * @since 1.4
20 *
21 */
22@AggregatorType(parameterTypes = {Void.class}, returnTypes = {Integer.class})
23public final class count implements IAggregatorFactory {
24
25 @Override
26 public BoundAggregator getAggregatorLogic(Class<?> domainClass) {
27 if (Void.class.equals(domainClass))
28 return new BoundAggregator(null, Void.class, Integer.class);
29 else throw new IllegalArgumentException();
30 }
31
32
33}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/max.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/max.java
new file mode 100644
index 00000000..e0236223
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/max.java
@@ -0,0 +1,44 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import java.math.BigDecimal;
12import java.math.BigInteger;
13import java.util.Calendar;
14import java.util.Date;
15
16import tools.refinery.viatra.runtime.matchers.psystem.aggregations.AggregatorType;
17import tools.refinery.viatra.runtime.matchers.psystem.aggregations.BoundAggregator;
18import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IAggregatorFactory;
19
20/**
21 * This aggregator calculates the maximum value of a selected aggregate parameter of a called pattern. The aggregate
22 * parameter is selected with the '#' symbol; the aggregate parameter must not be used outside the aggregator call. The
23 * other parameters of the call might be bound or unbound; bound parameters limit the matches to consider for the
24 * minimum calculation.
25 *
26 * @since 1.4
27 * @author Gabor Bergmann
28 */
29@AggregatorType(
30 // TODO T extends Comparable?
31 parameterTypes = {BigDecimal.class, BigInteger.class, Boolean.class, Byte.class, Calendar.class, Character.class,
32 Date.class, Double.class, Enum.class, Float.class, Integer.class, Long.class, Short.class, String.class},
33 returnTypes = {BigDecimal.class, BigInteger.class, Boolean.class, Byte.class, Calendar.class, Character.class,
34 Date.class, Double.class, Enum.class, Float.class, Integer.class, Long.class, Short.class, String.class})
35public final class max implements IAggregatorFactory {
36
37 @Override
38 public BoundAggregator getAggregatorLogic(Class<?> domainClass) {
39 if (Comparable.class.isAssignableFrom(domainClass))
40 return new BoundAggregator(ExtremumOperator.getMax(), domainClass, domainClass);
41 else throw new IllegalArgumentException();
42 }
43
44}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/min.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/min.java
new file mode 100644
index 00000000..6408c57b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/min.java
@@ -0,0 +1,44 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import java.math.BigDecimal;
12import java.math.BigInteger;
13import java.util.Calendar;
14import java.util.Date;
15
16import tools.refinery.viatra.runtime.matchers.psystem.aggregations.AggregatorType;
17import tools.refinery.viatra.runtime.matchers.psystem.aggregations.BoundAggregator;
18import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IAggregatorFactory;
19
20/**
21 * This aggregator calculates the minimum value of a selected aggregate parameter of a called pattern. The aggregate
22 * parameter is selected with the '#' symbol; the aggregate parameter must not be used outside the aggregator call. The
23 * other parameters of the call might be bound or unbound; bound parameters limit the matches to consider for the
24 * minimum calculation.
25 *
26 * @since 1.4
27 *
28 */
29@AggregatorType(
30 // TODO T extends Comparable?
31 parameterTypes = {BigDecimal.class, BigInteger.class, Boolean.class, Byte.class, Calendar.class, Character.class,
32 Date.class, Double.class, Enum.class, Float.class, Integer.class, Long.class, Short.class, String.class},
33 returnTypes = {BigDecimal.class, BigInteger.class, Boolean.class, Byte.class, Calendar.class, Character.class,
34 Date.class, Double.class, Enum.class, Float.class, Integer.class, Long.class, Short.class, String.class})
35public final class min implements IAggregatorFactory {
36
37 @Override
38 public BoundAggregator getAggregatorLogic(Class<?> domainClass) {
39 if (Comparable.class.isAssignableFrom(domainClass))
40 return new BoundAggregator(ExtremumOperator.getMin(), domainClass, domainClass);
41 else throw new IllegalArgumentException();
42 }
43
44}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/sum.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/sum.java
new file mode 100644
index 00000000..69ff2e75
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/aggregators/sum.java
@@ -0,0 +1,39 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.aggregators;
10
11import tools.refinery.viatra.runtime.matchers.psystem.aggregations.AggregatorType;
12import tools.refinery.viatra.runtime.matchers.psystem.aggregations.BoundAggregator;
13import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IAggregatorFactory;
14
15/**
16 * This aggregator calculates the sum of the values of a selected aggregate parameter of a called pattern. The aggregate
17 * parameter is selected with the '#' symbol; the aggregate parameter must not be used outside the aggregator call. The
18 * other parameters of the call might be bound or unbound; bound parameters limit the matches to consider for the
19 * summation.
20 *
21 * @since 1.4
22 *
23 */
24@AggregatorType(
25 parameterTypes = {Integer.class, Double.class, Long.class},
26 returnTypes = {Integer.class, Double.class, Long.class})
27public final class sum implements IAggregatorFactory {
28
29 @Override
30 public BoundAggregator getAggregatorLogic(Class<?> domainClass) {
31 if (Integer.class.equals(domainClass))
32 return new BoundAggregator(IntegerSumOperator.INSTANCE, Integer.class, Integer.class);
33 if (Double.class.equals(domainClass))
34 return new BoundAggregator(DoubleSumOperator.INSTANCE, Double.class, Double.class);
35 if (Long.class.equals(domainClass))
36 return new BoundAggregator(LongSumOperator.INSTANCE, Long.class, Long.class);
37 else throw new IllegalArgumentException();
38 }
39}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/OrderedIterableMerge.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/OrderedIterableMerge.java
new file mode 100644
index 00000000..1917e909
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/OrderedIterableMerge.java
@@ -0,0 +1,83 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.algorithms;
10
11import java.util.Comparator;
12import java.util.Iterator;
13import java.util.NoSuchElementException;
14
15/**
16 * @author Gabor Bergmann
17 * @since 2.1
18 *
19 */
20public class OrderedIterableMerge {
21
22 private OrderedIterableMerge() {
23 // Hidden utility class constructor
24 }
25
26 /**
27 * Lazily merges two iterables, each ordered according to a given comparator.
28 * Retains order in the result, and also eliminates any duplicates that appear in both arguments.
29 */
30 public static <T> Iterable<T> mergeUniques(Iterable<T> first, Iterable<T> second, Comparator<T> comparator) {
31 return () -> new Iterator<T>() {
32 Iterator<T> firstIterator = first.iterator();
33 Iterator<T> secondIterator = second.iterator();
34 T firstItem;
35 T secondItem;
36
37 {
38 fetchFirst();
39 fetchSecond();
40 }
41
42 private T fetchFirst() {
43 T previous = firstItem;
44 if (firstIterator.hasNext())
45 firstItem = firstIterator.next();
46 else
47 firstItem = null;
48 return previous;
49 }
50 private T fetchSecond() {
51 T previous = secondItem;
52 if (secondIterator.hasNext())
53 secondItem = secondIterator.next();
54 else
55 secondItem = null;
56 return previous;
57 }
58
59 @Override
60 public boolean hasNext() {
61 return firstItem != null || secondItem != null;
62 }
63 @Override
64 public T next() {
65 if (!hasNext()) throw new NoSuchElementException();
66 if (firstItem != null && secondItem != null) {
67 if (secondItem == firstItem) { // duplicates
68 fetchFirst();
69 return fetchSecond();
70 } else if (comparator.compare(firstItem, secondItem) < 0) {
71 return fetchFirst();
72 } else {
73 return fetchSecond();
74 }
75 } else if (firstItem != null) {
76 return fetchFirst();
77 } else { // secondItem must be non-null
78 return fetchSecond();
79 }
80 }
81 };
82 }
83}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFind.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFind.java
new file mode 100644
index 00000000..c69f08e5
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFind.java
@@ -0,0 +1,214 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.algorithms;
11
12import java.util.Collection;
13import java.util.HashSet;
14import java.util.Iterator;
15import java.util.Map;
16import java.util.Set;
17
18import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
19
20/**
21 * Union-find data structure implementation. Note that the implementation relies on the correct implementation of the
22 * equals method of the type parameter's class.
23 *
24 * @author Tamas Szabo
25 *
26 * @param <V>
27 * the type parameter of the element's stored in the union-find data structure
28 */
29public class UnionFind<V> {
30
31 private final Map<V, UnionFindNodeProperty<V>> nodeMap;
32 final Map<V, Set<V>> setMap;
33
34 /**
35 * Instantiate a new union-find data structure.
36 */
37 public UnionFind() {
38 nodeMap = CollectionsFactory.createMap();
39 setMap = CollectionsFactory.createMap();
40 }
41
42 /**
43 * Instantiate a new union-find data structure with the given elements as separate sets.
44 */
45 public UnionFind(Iterable<V> elements) {
46 this();
47 for (V element : elements) {
48 makeSet(element);
49 }
50 }
51
52 /**
53 * Creates a new union set from a collection of elements.
54 *
55 * @param nodes
56 * the collection of elements
57 * @return the root element
58 */
59 public V makeSet(Collection<V> nodes) {
60 if (!nodes.isEmpty()) {
61 Iterator<V> iterator = nodes.iterator();
62 V root = makeSet(iterator.next());
63 while (iterator.hasNext()) {
64 root = union(root, iterator.next());
65 }
66 return root;
67 } else {
68 return null;
69 }
70 }
71
72 /**
73 * This method creates a single set containing the given node.
74 *
75 * @param node
76 * the root node of the set
77 * @return the root element
78 */
79 public V makeSet(V node) {
80 if (!nodeMap.containsKey(node)) {
81 UnionFindNodeProperty<V> prop = new UnionFindNodeProperty<V>(0, node);
82 nodeMap.put(node, prop);
83 Set<V> set = new HashSet<V>();
84 set.add(node);
85 setMap.put(node, set);
86 }
87 return node;
88 }
89
90 /**
91 * Find method with path compression.
92 *
93 * @param node
94 * the node to find
95 * @return the root node of the set in which the given node can be found
96 */
97 public V find(V node) {
98 UnionFindNodeProperty<V> prop = nodeMap.get(node);
99
100 if (prop != null) {
101 if (prop.parent.equals(node)) {
102 return node;
103 } else {
104 prop.parent = find(prop.parent);
105 return prop.parent;
106 }
107 }
108 return null;
109 }
110
111 /**
112 * Union by rank implementation of the two sets which contain x and y; x and/or y can be a single element from the
113 * universe.
114 *
115 * @param x
116 * set or single element of the universe
117 * @param y
118 * set or single element of the universe
119 * @return the new root of the two sets
120 */
121 public V union(V x, V y) {
122 V xRoot = find(x);
123 V yRoot = find(y);
124
125 if ((xRoot == null) || (yRoot == null)) {
126 return union( (xRoot == null) ? makeSet(x) : xRoot, (yRoot == null) ? makeSet(y) : yRoot);
127 }
128 else if (!xRoot.equals(yRoot)) {
129 UnionFindNodeProperty<V> xRootProp = nodeMap.get(xRoot);
130 UnionFindNodeProperty<V> yRootProp = nodeMap.get(yRoot);
131
132 if (xRootProp.rank < yRootProp.rank) {
133 xRootProp.parent = yRoot;
134 setMap.get(yRoot).addAll(setMap.get(xRoot));
135 setMap.remove(xRoot);
136 return yRoot;
137 } else {// (xRootProp.rank >= yRootProp.rank)
138 yRootProp.parent = xRoot;
139 yRootProp.rank = (xRootProp.rank == yRootProp.rank) ? yRootProp.rank + 1 : yRootProp.rank;
140 setMap.get(xRoot).addAll(setMap.get(yRoot));
141 setMap.remove(yRoot);
142 return xRoot;
143 }
144 } else {
145 return xRoot;
146 }
147 }
148
149 /**
150 * Places the given elements in to the same partition.
151 */
152 public void unite(Set<V> elements) {
153 if (elements.size() > 1) {
154 V current = null;
155 for (V element : elements) {
156 if (current != null) {
157 if (getPartition(element) != null) {
158 union(current, element);
159 }
160 } else {
161 if (getPartition(element) != null) {
162 current = element;
163 }
164 }
165 }
166 }
167 }
168
169 /**
170 * Delete the set whose root is the given node.
171 *
172 * @param root
173 * the root node
174 */
175 public void deleteSet(V root) {
176 // if (setMap.containsKey(root))
177 for (V n : setMap.get(root)) {
178 nodeMap.remove(n);
179 }
180 setMap.remove(root);
181 }
182
183 /**
184 * Returns if all given elements are in the same partition.
185 */
186 public boolean isSameUnion(Set<V> elements) {
187 for (Set<V> partition : setMap.values()) {
188 if (partition.containsAll(elements)) {
189 return true;
190 }
191 }
192 return false;
193 }
194
195
196 /**
197 * Returns the partition in which the given element can be found, or null otherwise.
198 */
199 public Set<V> getPartition(V element) {
200 V root = find(element);
201 return setMap.get(root);
202 }
203
204 /**
205 * Returns all partitions.
206 */
207 public Collection<Set<V>> getPartitions() {
208 return setMap.values();
209 }
210
211 public Set<V> getPartitionHeads() {
212 return setMap.keySet();
213 }
214}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFindNodeProperty.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFindNodeProperty.java
new file mode 100644
index 00000000..82852f9c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/algorithms/UnionFindNodeProperty.java
@@ -0,0 +1,32 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2012, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.algorithms;
11
12public class UnionFindNodeProperty<V> {
13
14 public int rank;
15 public V parent;
16
17 public UnionFindNodeProperty() {
18 this.rank = 0;
19 this.parent = null;
20 }
21
22 public UnionFindNodeProperty(int rank, V parent) {
23 super();
24 this.rank = rank;
25 this.parent = parent;
26 }
27
28 @Override
29 public String toString() {
30 return "[rank:" + rank + ", parent:" + parent.toString() + "]";
31 }
32}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/CommonQueryHintOptions.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/CommonQueryHintOptions.java
new file mode 100644
index 00000000..317293bf
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/CommonQueryHintOptions.java
@@ -0,0 +1,36 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IRewriterTraceCollector;
12import tools.refinery.viatra.runtime.matchers.psystem.rewriters.NopTraceCollector;
13
14/**
15 * Query evaluation hints applicable to any engine
16 * @since 1.6
17 *
18 */
19public final class CommonQueryHintOptions {
20
21 private CommonQueryHintOptions() {
22 // Hiding constructor for utility class
23 }
24
25 /**
26 * This hint instructs the query backends to record trace information into the given trace collector
27 */
28 public static final QueryHintOption<IRewriterTraceCollector> normalizationTraceCollector =
29 hintOption("normalizationTraceCollector", NopTraceCollector.INSTANCE);
30
31 // internal helper for conciseness
32 private static <T> QueryHintOption<T> hintOption(String hintKeyLocalName, T defaultValue) {
33 return new QueryHintOption<>(CommonQueryHintOptions.class, hintKeyLocalName, defaultValue);
34 }
35
36}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ICallDelegationStrategy.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ICallDelegationStrategy.java
new file mode 100644
index 00000000..40853f46
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ICallDelegationStrategy.java
@@ -0,0 +1,89 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import tools.refinery.viatra.runtime.matchers.context.IQueryResultProviderAccess;
12import tools.refinery.viatra.runtime.matchers.psystem.IQueryReference;
13import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
14
15/**
16 * Function object that specifies how hints (including backend preferences) shall propagate through pattern calls.
17 *
18 * <p> A few useful default implementations are included as static fields.
19 *
20 * <p> As of 2.1, only suppported by the local search backend, and only if the pattern call is not flattened.
21 *
22 * @author Gabor Bergmann
23 * @since 2.1
24 */
25@FunctionalInterface
26public interface ICallDelegationStrategy {
27
28 /**
29 * Specifies how hints (including backend preferences) shall propagate through pattern calls.
30 *
31 * @param call a {@link PConstraint} in a query that calls another query.
32 * @param callerHint a hint under which the calling pattern is evaluated,
33 * @param callerBackend the actual backend evaluating the calling pattern.
34 * @param calleeHintProvider the provider of hints for the called pattern.
35 * @return the hints, including backend selection,
36 * that the backend responsible for the caller pattern must specify when
37 * requesting the {@link IQueryResultProvider} for the called pattern via {@link IQueryResultProviderAccess}.
38 */
39 public QueryEvaluationHint transformHints(IQueryReference call,
40 QueryEvaluationHint callerHint,
41 IQueryBackend callerBackend,
42 IQueryBackendHintProvider calleeHintProvider);
43
44
45 /**
46 * Options known for callee are used to override caller options, except the backend selection.
47 * Always use the same backend for the callee and the caller, regardless what is specified for the callee pattern.
48 * @author Gabor Bergmann
49 */
50 public static final ICallDelegationStrategy FULL_BACKEND_ADHESION = (call, callerHint, callerBackend, calleeHintProvider) -> {
51 QueryEvaluationHint calleeHint =
52 calleeHintProvider.getQueryEvaluationHint(call.getReferredQuery());
53 QueryEvaluationHint result =
54 callerHint == null ? calleeHint : callerHint.overrideBy(calleeHint);
55
56 QueryEvaluationHint backendAdhesion = new QueryEvaluationHint(
57 null /* settings-ignorant */, callerBackend.getFactory());
58 result = result.overrideBy(backendAdhesion);
59 return result;
60 };
61 /**
62 * Options known for callee are used to override caller options, including the backend selection.
63 * If callee does not specify a backend requirement, the backend of the caller is kept.
64 * @author Gabor Bergmann
65 */
66 public static final ICallDelegationStrategy PARTIAL_BACKEND_ADHESION = (call, callerHint, callerBackend, calleeHintProvider) -> {
67 QueryEvaluationHint backendAdhesion = new QueryEvaluationHint(
68 null /* settings-ignorant */, callerBackend.getFactory());
69
70 QueryEvaluationHint result =
71 callerHint == null ? backendAdhesion : callerHint.overrideBy(backendAdhesion);
72
73 QueryEvaluationHint calleeHint = calleeHintProvider.getQueryEvaluationHint(call.getReferredQuery());
74 result = result.overrideBy(calleeHint);
75
76 return result;
77 };
78 /**
79 * Options known for callee are used to override caller options, including the backend selection.
80 * Always use the backend specified for the callee (or the default if none), regardless of the backend of the caller.
81 * @author Gabor Bergmann
82 */
83 public static final ICallDelegationStrategy NO_BACKEND_ADHESION = (call, callerHint, callerBackend, calleeHintProvider) -> {
84 QueryEvaluationHint calleeHint = calleeHintProvider.getQueryEvaluationHint(call.getReferredQuery());
85 return callerHint == null ? calleeHint : callerHint.overrideBy(calleeHint);
86 };
87
88
89}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IMatcherCapability.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IMatcherCapability.java
new file mode 100644
index 00000000..104b68a8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IMatcherCapability.java
@@ -0,0 +1,26 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11/**
12 * Implementations of this interface can be used to decide whether a matcher created by an arbitrary backend can
13 * potentially be used as a substitute for another matcher.
14 *
15 * @author Grill Balázs
16 * @since 1.4
17 *
18 */
19public interface IMatcherCapability {
20
21 /**
22 * Returns true if matchers of this capability can be used as a substitute for a matcher implementing the given capability
23 */
24 public boolean canBeSubstitute(IMatcherCapability capability);
25
26}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackend.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackend.java
new file mode 100644
index 00000000..c85f10a4
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackend.java
@@ -0,0 +1,68 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
12import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
13
14/**
15 * Internal interface for a VIATRA query specification. Each query is associated with a pattern. Methods instantiate a matcher
16 * of the pattern with various parameters.
17 *
18 * @author Bergmann Gábor
19 * @since 0.9
20 * @noextend This interface is not intended to be extended by users of the VIATRA framework, and should only be used by the query engine
21 */
22public interface IQueryBackend {
23
24 /**
25 * @return true iff this backend is incremental, i.e. it caches the results of queries for quick retrieval,
26 * and can provide update notifications on result set changes.
27 */
28 public boolean isCaching();
29
30 /**
31 * Returns a result provider for a given query. Repeated calls may return the same instance.
32 * @throws ViatraQueryRuntimeException
33 */
34 public IQueryResultProvider getResultProvider(PQuery query);
35
36 /**
37 * Returns a result provider for a given query. Repeated calls may return the same instance.
38 * @param optional hints that may override engine and query defaults (as provided by {@link IQueryBackendHintProvider}). Can be null.
39 * @throws ViatraQueryRuntimeException
40 * @since 1.4
41 */
42 public IQueryResultProvider getResultProvider(PQuery query, QueryEvaluationHint hints);
43
44 /**
45 * Returns an existing result provider for a given query, if it was previously constructed, returns null otherwise.
46 * Will not construct and initialize new result providers.
47 */
48 public IQueryResultProvider peekExistingResultProvider(PQuery query);
49
50 /**
51 * Propagates all pending updates in this query backend. The implementation of this method is optional, and it
52 * can be ignored entirely if the backend does not delay updates.
53 * @since 1.6
54 */
55 public void flushUpdates();
56
57 /**
58 * Disposes the query backend.
59 */
60 public abstract void dispose();
61
62 /**
63 * @return the factory that created this backend, if this functionality is supported
64 * @since 2.1
65 */
66 public IQueryBackendFactory getFactory();
67
68}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactory.java
new file mode 100644
index 00000000..e264ab3f
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactory.java
@@ -0,0 +1,52 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
12import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
13
14/**
15 * A Query Backend Factory identifies a query evaluator implementation, and can create an evaluator instance (an {@link IQueryBackend}) tied to a specific VIATRA Query engine upon request.
16 *
17 * <p> The factory is used as a lookup key for the backend instance,
18 * therefore implementors should either be singletons, or implement equals() / hashCode() accordingly.
19 *
20 * @author Bergmann Gabor
21 *
22 */
23public interface IQueryBackendFactory {
24
25 /**
26 * Creates a new {@link IQueryBackend} instance tied to the given context elements.
27 *
28 * @return an instance of the class returned by {@link #getBackendClass()} that operates in the given context.
29 * @since 1.5
30 */
31 public IQueryBackend
32 create(IQueryBackendContext context);
33
34
35 /**
36 * The backend instances created by this factory are guaranteed to conform to the returned class.
37 */
38 public Class<? extends IQueryBackend> getBackendClass();
39
40 /**
41 * Calculate the required capabilities, which are needed to execute the given pattern
42 *
43 * @since 1.4
44 */
45 public IMatcherCapability calculateRequiredCapability(PQuery query, QueryEvaluationHint hint);
46
47 /**
48 * Returns whether the current backend is caching
49 * @since 2.0
50 */
51 public boolean isCaching();
52}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactoryProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactoryProvider.java
new file mode 100644
index 00000000..8787814e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendFactoryProvider.java
@@ -0,0 +1,46 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11/**
12 * A provider interface for {@link IQueryBackendFactory} instances.
13 * @since 2.0
14 */
15public interface IQueryBackendFactoryProvider {
16
17 /**
18 * Returns a query backend factory instance. The method should return the same instance in case of repeated calls.
19 */
20 IQueryBackendFactory getFactory();
21
22 /**
23 * Returns whether the given query backend should be considered as system default. If multiple backends are
24 * registered as system default, it is undefined which one will be chosen.
25 */
26 default boolean isSystemDefaultEngine() {
27 return false;
28 }
29
30 /**
31 * Returns whether the given query backend should be considered as system default search backend. If multiple
32 * backends are registered as system default, it is undefined which one will be chosen.
33 */
34 default boolean isSystemDefaultSearchBackend() {
35 return false;
36 }
37
38
39 /**
40 * Returns whether the given query backend should be considered as system default caching backend. If multiple
41 * backends are registered as system default, it is undefined which one will be chosen.
42 */
43 default boolean isSystemDefaultCachingBackend() {
44 return false;
45 }
46}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendHintProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendHintProvider.java
new file mode 100644
index 00000000..9bb76349
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryBackendHintProvider.java
@@ -0,0 +1,32 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
12
13/**
14 * Provides query evaluation hints consisting of the Engine default hints and
15 * the hints provided by the pattern itself.
16 *
17 * @author Bergmann Gabor
18 * @since 0.9
19 * @noimplement This interface is not intended to be implemented by clients, except in the tools.refinery.viatra.runtime plugin.
20 */
21public interface IQueryBackendHintProvider {
22
23 /**
24 * Suggests query evaluation hints regarding a query. The returned hints reflects the default hints of the
25 * query engine merged with the hints provided by the pattern itself. These can be overridden via specific
26 * advanced API of the engine.
27 *
28 * @since 1.4
29 */
30 QueryEvaluationHint getQueryEvaluationHint(PQuery query);
31
32}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryResultProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryResultProvider.java
new file mode 100644
index 00000000..cd7d050f
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IQueryResultProvider.java
@@ -0,0 +1,202 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import java.util.Optional;
12import java.util.stream.Stream;
13
14import tools.refinery.viatra.runtime.matchers.planning.helpers.StatisticsHelper;
15import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
16import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
17import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
18import tools.refinery.viatra.runtime.matchers.util.Accuracy;
19
20/**
21 * An internal interface of the query backend that provides results of a given query.
22 * @author Bergmann Gabor
23 * @noimplement This interface is not intended to be implemented by clients.
24 */
25public interface IQueryResultProvider {
26
27 /**
28 * Decides whether there are any matches of the pattern that conform to the given fixed values of some parameters.
29 *
30 * @param parameters
31 * array where each non-null element binds the corresponding pattern parameter to a fixed value.
32 * @pre size of input array must be equal to the number of parameters.
33 * @since 2.0
34 */
35 public boolean hasMatch(Object[] parameters);
36
37 /**
38 * Decides whether there are any matches of the pattern that conform to the given fixed values of some parameters.
39 *
40 * @param parameterSeedMask
41 * a mask that extracts those parameters of the query (from the entire parameter list) that should be
42 * bound to a fixed value
43 * @param parameters
44 * the tuple of fixed values restricting the match set to be considered, in the same order as given in
45 * parameterSeedMask, so that for each considered match tuple,
46 * projectedParameterSeed.equals(parameterSeedMask.transform(match)) should hold
47 * @since 2.0
48 */
49 public boolean hasMatch(TupleMask parameterSeedMask, ITuple projectedParameterSeed);
50
51 /**
52 * Returns the number of all matches of the pattern that conform to the given fixed values of some parameters.
53 *
54 * @param parameters
55 * array where each non-null element binds the corresponding pattern parameter to a fixed value.
56 * @pre size of input array must be equal to the number of parameters.
57 * @return the number of pattern matches found.
58 */
59 public int countMatches(Object[] parameters);
60
61 /**
62 * Returns the number of all matches of the pattern that conform to the given fixed values of some parameters.
63 *
64 * @param parameterSeedMask
65 * a mask that extracts those parameters of the query (from the entire parameter list) that should be
66 * bound to a fixed value
67 * @param parameters
68 * the tuple of fixed values restricting the match set to be considered, in the same order as given in
69 * parameterSeedMask, so that for each considered match tuple,
70 * projectedParameterSeed.equals(parameterSeedMask.transform(match)) should hold
71 * @return the number of pattern matches found.
72 * @since 1.7
73 */
74 public int countMatches(TupleMask parameterSeedMask, ITuple projectedParameterSeed);
75
76 /**
77 * Gives an estimate of the number of different groups the matches are projected into by the given mask
78 * (e.g. for an identity mask, this means the full match set size). The estimate must meet the required accuracy.
79 *
80 * <p> If there is insufficient information to provide an answer up to the required precision, {@link Optional#empty()} may be returned.
81 * In other words, query backends may deny an answer, or do their best to give an estimate without actually determining the match set of the query.
82 * However, caching backends are expected to simply return the indexed (projection) size, initialized on-demand if necessary.
83 *
84 * <p> PRE: {@link TupleMask#isNonrepeating()} must hold for the group mask.
85 *
86 * @return if available, an estimate of the cardinality of the projection of the match set, with the desired accuracy.
87 *
88 * @since 2.1
89 */
90 public Optional<Long> estimateCardinality(TupleMask groupMask, Accuracy requiredAccuracy);
91
92 /**
93 * Gives an estimate of the average size of different groups the matches are projected into by the given mask
94 * (e.g. for an identity mask, this means 1, while for an empty mask, the result is match set size).
95 * The estimate must meet the required accuracy.
96 *
97 * <p> If there is insufficient information to provide an answer up to the required precision, {@link Optional#empty()} may be returned.
98 * In other words, query backends may deny an answer, or do their best to give an estimate without actually determining the match set of the query.
99 * However, caching backends are expected to simply return the exact value from the index, initialized on-demand if necessary.
100 *
101 * <p> For an empty match set, zero is acceptable as an exact answer.
102 *
103 * <p> PRE: {@link TupleMask#isNonrepeating()} must hold for the group mask.
104 *
105 * @return if available, an estimate of the average size of each projection group of the match set, with the desired accuracy.
106 *
107 * @since 2.1
108 */
109 public default Optional<Double> estimateAverageBucketSize(TupleMask groupMask, Accuracy requiredAccuracy) {
110 return StatisticsHelper.estimateAverageBucketSize(groupMask, requiredAccuracy, this::estimateCardinality);
111 }
112
113 /**
114 * Returns an arbitrarily chosen match of the pattern that conforms to the given fixed values of some parameters.
115 * Neither determinism nor randomness of selection is guaranteed.
116 *
117 * @param parameters
118 * array where each non-null element binds the corresponding pattern parameter to a fixed value.
119 * @pre size of input array must be equal to the number of parameters.
120 * @return a match represented in the internal {@link Tuple} representation.
121 * @since 2.0
122 */
123 public Optional<Tuple> getOneArbitraryMatch(Object[] parameters);
124
125 /**
126 * Returns an arbitrarily chosen match of the pattern that conforms to the given fixed values of some parameters.
127 * Neither determinism nor randomness of selection is guaranteed.
128 *
129 * @param parameterSeedMask
130 * a mask that extracts those parameters of the query (from the entire parameter list) that should be
131 * bound to a fixed value
132 * @param parameters
133 * the tuple of fixed values restricting the match set to be considered, in the same order as given in
134 * parameterSeedMask, so that for each considered match tuple,
135 * projectedParameterSeed.equals(parameterSeedMask.transform(match)) should hold
136 * @return a match represented in the internal {@link Tuple} representation.
137 * @since 2.0
138 */
139 public Optional<Tuple> getOneArbitraryMatch(TupleMask parameterSeedMask, ITuple parameters);
140
141 /**
142 * Returns the set of all matches of the pattern that conform to the given fixed values of some parameters.
143 *
144 * @param parameters
145 * array where each non-null element binds the corresponding pattern parameter to a fixed value.
146 * @pre size of input array must be equal to the number of parameters.
147 * @return matches represented in the internal {@link Tuple} representation.
148 * @since 2.0
149 */
150 public Stream<Tuple> getAllMatches(Object[] parameters);
151
152 /**
153 * Returns the set of all matches of the pattern that conform to the given fixed values of some parameters.
154 *
155 * @param parameterSeedMask
156 * a mask that extracts those parameters of the query (from the entire parameter list) that should be
157 * bound to a fixed value
158 * @param parameters
159 * the tuple of fixed values restricting the match set to be considered, in the same order as given in
160 * parameterSeedMask, so that for each considered match tuple,
161 * projectedParameterSeed.equals(parameterSeedMask.transform(match)) should hold
162 * @return matches represented in the internal {@link Tuple} representation.
163 * @since 2.0
164 */
165 public Stream<Tuple> getAllMatches(TupleMask parameterSeedMask, ITuple parameters);
166
167 /**
168 * The underlying query evaluator backend.
169 */
170 public IQueryBackend getQueryBackend();
171
172 /**
173 * Internal method that registers low-level callbacks for match appearance and disappearance.
174 *
175 * <p>
176 * <b>Caution: </b> This is a low-level callback that is invoked when the pattern matcher is not necessarily in a
177 * consistent state yet. Importantly, no model modification permitted during the callback.
178 *
179 * <p>
180 * The callback can be unregistered via invoking {@link #removeUpdateListener(Object)} with the same tag.
181 *
182 * @param listener
183 * the listener that will be notified of each new match that appears or disappears, starting from now.
184 * @param listenerTag
185 * a tag by which to identify the listener for later removal by {@link #removeUpdateListener(Object)}.
186 * @param fireNow
187 * if true, the insertion update allback will be immediately invoked on all current matches as a one-time effect.
188 *
189 * @throws UnsupportedOperationException if this is a non-incremental backend
190 * (i.e. {@link IQueryBackend#isCaching()} on {@link #getQueryBackend()} returns false)
191 */
192 public void addUpdateListener(final IUpdateable listener, final Object listenerTag, boolean fireNow);
193
194 /**
195 * Removes an existing listener previously registered with the given tag.
196 *
197 * @throws UnsupportedOperationException if this is a non-incremental backend
198 * (i.e. {@link IQueryBackend#isCaching()} on {@link #getQueryBackend()} returns false)
199 */
200 public void removeUpdateListener(final Object listenerTag);
201
202}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IUpdateable.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IUpdateable.java
new file mode 100644
index 00000000..baf7144a
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/IUpdateable.java
@@ -0,0 +1,27 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
12
13/**
14 * Internal interface for the query backend to singal an update to a query result.
15 * @author Bergmann Gabor
16 * @since 0.9
17 *
18 */
19public interface IUpdateable {
20
21 /**
22 * This callback method must be free of exceptions, even {@link RuntimeException}s (though not {@link Error}s).
23 * @param updateElement the tuple that is changed
24 * @param isInsertion true if the tuple appeared in the result set, false if disappeared from the result set
25 */
26 public void update(Tuple updateElement, boolean isInsertion);
27}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryEvaluationHint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryEvaluationHint.java
new file mode 100644
index 00000000..eab92128
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryEvaluationHint.java
@@ -0,0 +1,241 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import java.util.AbstractMap;
12import java.util.Collections;
13import java.util.HashMap;
14import java.util.Map;
15import java.util.Objects;
16import java.util.stream.Collectors;
17
18import tools.refinery.viatra.runtime.matchers.util.Preconditions;
19
20/**
21 * Provides VIATRA Query with additional hints on how a query should be evaluated. The same hint can be provided to multiple queries.
22 *
23 * <p> This class is immutable. Overriding options will create a new instance.
24 *
25 * <p>
26 * Here be dragons: for advanced users only.
27 *
28 * @author Bergmann Gabor
29 *
30 */
31public class QueryEvaluationHint {
32
33 /**
34 * @since 2.0
35 *
36 */
37 public enum BackendRequirement {
38 /**
39 * The current hint does not specify any backend requirement
40 */
41 UNSPECIFIED,
42 /**
43 * The current hint specifies that the default search backend of the engine should be used
44 */
45 DEFAULT_SEARCH,
46 /**
47 * The current hint specifies that the default caching backend of the engine should be used
48 */
49 DEFAULT_CACHING,
50 /**
51 * The current hint specifies that a specific backend is to be used
52 */
53 SPECIFIC
54 }
55
56 final IQueryBackendFactory queryBackendFactory;
57 final Map<QueryHintOption<?>, Object> backendHintSettings;
58 final BackendRequirement requirement;
59
60 /**
61 * Specifies the suggested query backend requirements, and value settings for additional backend-specific options.
62 *
63 * <p>
64 * The backend requirement type must not be {@link BackendRequirement#SPECIFIC} - for that case, use the constructor
65 * {@link #QueryEvaluationHint(Map, IQueryBackendFactory)}.
66 *
67 * @param backendHintSettings
68 * if non-null, each entry in the map overrides backend-specific options regarding query evaluation
69 * (null-valued map entries permitted to erase hints); passing null means default options associated with
70 * the query
71 * @param backendRequirementType
72 * defines the kind of backend requirement
73 * @since 2.0
74 */
75 public QueryEvaluationHint(Map<QueryHintOption<?>, Object> backendHintSettings, BackendRequirement backendRequirementType) {
76 super();
77 Preconditions.checkArgument(backendRequirementType != null, "Specific requirement needs to be set");
78 Preconditions.checkArgument(backendRequirementType != BackendRequirement.SPECIFIC, "Specific backend requirement needs providing a corresponding backend type");
79 this.queryBackendFactory = null;
80 this.requirement = backendRequirementType;
81 this.backendHintSettings = (backendHintSettings == null)
82 ? Collections.<QueryHintOption<?>, Object> emptyMap()
83 : new HashMap<>(backendHintSettings);
84 }
85
86 /**
87 * Specifies the suggested query backend, and value settings for additional backend-specific options. The first
88 * parameter can be null; if the second parameter is null, it is expected that the other constructor is called
89 * instead with a {@link BackendRequirement#UNSPECIFIED} parameter.
90 *
91 * @param backendHintSettings
92 * if non-null, each entry in the map overrides backend-specific options regarding query evaluation
93 * (null-valued map entries permitted to erase hints); passing null means default options associated with
94 * the query
95 * @param queryBackendFactory
96 * overrides the query evaluator algorithm; passing null retains the default algorithm associated with
97 * the query
98 * @since 1.5
99 */
100 public QueryEvaluationHint(
101 Map<QueryHintOption<?>, Object> backendHintSettings,
102 IQueryBackendFactory queryBackendFactory) {
103 super();
104 this.queryBackendFactory = queryBackendFactory;
105 this.requirement = (queryBackendFactory == null) ? BackendRequirement.UNSPECIFIED : BackendRequirement.SPECIFIC;
106 this.backendHintSettings = (backendHintSettings == null)
107 ? Collections.<QueryHintOption<?>, Object> emptyMap()
108 : new HashMap<>(backendHintSettings);
109 }
110
111 /**
112 * Returns the backend requirement described by this hint. If a specific backend is required, that can be queried by {@link #getQueryBackendFactory()}.
113 * @since 2.0
114 */
115 public BackendRequirement getQueryBackendRequirementType() {
116 return requirement;
117 }
118
119 /**
120 * A suggestion for choosing the query evaluator algorithm.
121 *
122 * <p>
123 * Returns null iff {@link #getQueryBackendRequirementType()} does not return {@link BackendRequirement#SPECIFIC};
124 * in such cases a corresponding default backend is selected inside the engine
125 */
126 public IQueryBackendFactory getQueryBackendFactory() {
127 return queryBackendFactory;
128 }
129
130 /**
131 * Each entry in the immutable map overrides backend-specific options regarding query evaluation.
132 *
133 * <p>The map is non-null, even if empty.
134 * Null-valued map entries are also permitted to erase hints via {@link #overrideBy(QueryEvaluationHint)}.
135 *
136 * @since 1.5
137 */
138 public Map<QueryHintOption<?>, Object> getBackendHintSettings() {
139 return backendHintSettings;
140 }
141
142
143 /**
144 * Override values in this hint and return a consolidated instance.
145 *
146 * @since 1.4
147 */
148 public QueryEvaluationHint overrideBy(QueryEvaluationHint overridingHint){
149 if (overridingHint == null)
150 return this;
151
152 BackendRequirement overriddenRequirement = this.getQueryBackendRequirementType();
153 if (overridingHint.getQueryBackendRequirementType() != BackendRequirement.UNSPECIFIED) {
154 overriddenRequirement = overridingHint.getQueryBackendRequirementType();
155 }
156 Map<QueryHintOption<?>, Object> hints = new HashMap<>(this.getBackendHintSettings());
157 if (overridingHint.getBackendHintSettings() != null) {
158 hints.putAll(overridingHint.getBackendHintSettings());
159 }
160 if (overriddenRequirement == BackendRequirement.SPECIFIC) {
161 IQueryBackendFactory factory = this.getQueryBackendFactory();
162 if (overridingHint.getQueryBackendFactory() != null) {
163 factory = overridingHint.getQueryBackendFactory();
164 }
165 return new QueryEvaluationHint(hints, factory);
166 } else {
167 return new QueryEvaluationHint(hints, overriddenRequirement);
168 }
169 }
170
171 /**
172 * Returns whether the given hint option is overridden.
173 * @since 1.5
174 */
175 public boolean isOptionOverridden(QueryHintOption<?> option) {
176 return getBackendHintSettings().containsKey(option);
177 }
178
179 /**
180 * Returns the value of the given hint option from the given hint collection, or null if not defined.
181 * @since 1.5
182 */
183 @SuppressWarnings("unchecked")
184 public <HintValue> HintValue getValueOrNull(QueryHintOption<HintValue> option) {
185 return (HintValue) getBackendHintSettings().get(option);
186 }
187
188 /**
189 * Returns the value of the given hint option from the given hint collection, or the default value if not defined.
190 * Intended to be called by backends to find out the definitive value that should be considered.
191 * @since 1.5
192 */
193 public <HintValue> HintValue getValueOrDefault(QueryHintOption<HintValue> option) {
194 return option.getValueOrDefault(this);
195 }
196
197 @Override
198 public int hashCode() {
199 return Objects.hash(backendHintSettings, queryBackendFactory, requirement);
200 }
201
202 @Override
203 public boolean equals(Object obj) {
204 if (this == obj)
205 return true;
206 if (obj == null)
207 return false;
208 if (getClass() != obj.getClass())
209 return false;
210 QueryEvaluationHint other = (QueryEvaluationHint) obj;
211 return Objects.equals(backendHintSettings, other.backendHintSettings)
212 &&
213 Objects.equals(queryBackendFactory, other.queryBackendFactory)
214 &&
215 Objects.equals(requirement, other.requirement)
216 ;
217 }
218
219 @Override
220 public String toString() {
221 StringBuilder sb = new StringBuilder();
222
223 if (getQueryBackendFactory() != null)
224 sb.append("backend: ").append(getQueryBackendFactory().getBackendClass().getSimpleName());
225 if (! backendHintSettings.isEmpty()) {
226 sb.append("hints: ");
227 if(backendHintSettings instanceof AbstractMap){
228 sb.append(backendHintSettings.toString());
229 } else {
230 // we have to iterate on the contents
231
232 String joinedHintMap = backendHintSettings.entrySet().stream()
233 .map(setting -> setting.getKey() + "=" + setting.getValue()).collect(Collectors.joining(", "));
234 sb.append('{').append(joinedHintMap).append('}');
235 }
236 }
237
238 final String result = sb.toString();
239 return result.isEmpty() ? "defaults" : result;
240 }
241}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryHintOption.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryHintOption.java
new file mode 100644
index 00000000..2c6bb4de
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/QueryHintOption.java
@@ -0,0 +1,122 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import java.util.Map;
12import java.util.Objects;
13
14/**
15 * Each instance of this class corresponds to a given hint option.
16 *
17 * It is recommended to expose options to clients (and query backends) as public static fields.
18 *
19 * @author Gabor Bergmann
20 * @since 1.5
21 */
22public class QueryHintOption<HintValue> {
23
24 private String optionQualifiedName;
25 private HintValue defaultValue;
26
27 /**
28 * Instantiates an option object with the given name and default value.
29 */
30 public QueryHintOption(String optionQualifiedName, HintValue defaultValue) {
31 this.optionQualifiedName = optionQualifiedName;
32 this.defaultValue = defaultValue;
33 }
34
35 /**
36 * This is the recommended constructor for hint options defined as static fields within an enclosing class.
37 * Combines the qualified name of the hint from the (qualified) name of the enclosing class and a local name (unique within that class).
38 */
39 public <T extends HintValue> QueryHintOption(Class<?> optionNamespace, String optionLocalName, T defaultValue) {
40 this(String.format("%s@%s", optionLocalName, optionNamespace.getName()), defaultValue);
41 }
42
43 /**
44 * Returns the qualified name, a unique string identifier of the option.
45 */
46 public String getQualifiedName() {
47 return optionQualifiedName;
48 }
49
50 /**
51 * Returns the default value of this hint option, which is to be used by query backends in the case no overriding value is assigned.
52 */
53 public HintValue getDefaultValue() {
54 return defaultValue;
55 }
56
57 /**
58 * Returns the value of this hint option from the given hint collection, or the default value if not defined.
59 * Intended to be called by backends to find out the definitive value that should be considered.
60 */
61 @SuppressWarnings("unchecked")
62 public HintValue getValueOrDefault(QueryEvaluationHint hints) {
63 Object value = hints.getValueOrNull(this);
64 if (value == null)
65 return getDefaultValue();
66 else {
67 return (HintValue) value;
68 }
69 }
70
71
72 /**
73 * Returns the value of this hint option from the given hint collection, or null if not defined.
74 */
75 public HintValue getValueOrNull(QueryEvaluationHint hints) {
76 return hints.getValueOrNull(this);
77 }
78
79 /**
80 * Returns whether this hint option is defined in the given hint collection.
81 */
82 public boolean isOverriddenIn(QueryEvaluationHint hints) {
83 return hints.isOptionOverridden(this);
84 }
85
86 /**
87 * Puts a value of this hint option into an option-to-value map.
88 *
89 * <p> This method is offered in lieu of a builder API.
90 * Use this method on any number of hint options in order to populate an option-value map.
91 * Then instantiate the immutable {@link QueryEvaluationHint} using the map.
92 *
93 * @see #insertValueIfNondefault(Map, Object)
94 * @return the hint value that was previously present in the map under this hint option, carrying over the semantics of {@link Map#put(Object, Object)}.
95 */
96 @SuppressWarnings("unchecked")
97 public HintValue insertOverridingValue(Map<QueryHintOption<?>, Object> hints, HintValue overridingValue) {
98 return (HintValue) hints.put(this, overridingValue);
99 }
100
101 /**
102 * Puts a value of this hint option into an option-to-value map, if the given value differs from the default value of the option.
103 * If the default value is provided instead, then the map is not updated.
104 *
105 * <p> This method is offered in lieu of a builder API.
106 * Use this method on any number of hint options in order to populate an option-value map.
107 * Then instantiate the immutable {@link QueryEvaluationHint} using the map.
108 *
109 * @see #insertOverridingValue(Map, Object)
110 * @since 2.0
111 */
112 public void insertValueIfNondefault(Map<QueryHintOption<?>, Object> hints, HintValue overridingValue) {
113 if (!Objects.equals(defaultValue, overridingValue))
114 hints.put(this, overridingValue);
115 }
116
117 @Override
118 public String toString() {
119 return optionQualifiedName;
120 }
121
122}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ResultProviderRequestor.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ResultProviderRequestor.java
new file mode 100644
index 00000000..6ec6d53e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/backend/ResultProviderRequestor.java
@@ -0,0 +1,74 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.backend;
10
11import tools.refinery.viatra.runtime.matchers.context.IQueryResultProviderAccess;
12import tools.refinery.viatra.runtime.matchers.psystem.IQueryReference;
13import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
14
15/**
16 * Uniform way of requesting result providers for pattern calls within queries.
17 * Intended users are query backends, for calling other backends to deliver results of dependee queries.
18 *
19 * @author Gabor Bergmann
20 * @since 2.1
21 */
22public class ResultProviderRequestor {
23 IQueryBackend callerBackend;
24 IQueryResultProviderAccess resultProviderAccess;
25 IQueryBackendHintProvider hintProvider;
26 ICallDelegationStrategy delegationStrategy;
27 QueryEvaluationHint callerHint;
28 QueryEvaluationHint universalOverride;
29
30
31 /**
32 * @param callerBackend the actual backend evaluating the calling pattern.
33 * @param resultProviderAccess
34 * @param hintProvider
35 * @param delegationStrategy
36 * @param callerHint a hint under which the calling pattern is evaluated,
37 * @param universalOverride if non-null, overrides the hint with extra options <i>after</i> the {@link ICallDelegationStrategy}
38 */
39 public ResultProviderRequestor(IQueryBackend callerBackend, IQueryResultProviderAccess resultProviderAccess,
40 IQueryBackendHintProvider hintProvider, ICallDelegationStrategy delegationStrategy,
41 QueryEvaluationHint callerHint, QueryEvaluationHint universalOverride) {
42 super();
43 this.callerBackend = callerBackend;
44 this.resultProviderAccess = resultProviderAccess;
45 this.hintProvider = hintProvider;
46 this.delegationStrategy = delegationStrategy;
47 this.callerHint = callerHint;
48 this.universalOverride = universalOverride;
49 }
50
51
52
53
54 /**
55 *
56 * @param call a {@link PConstraint} in a query that calls another query.
57 * @param spotOverride if non-null, overrides the hint with extra options <i>after</i> the {@link ICallDelegationStrategy}
58 * and the universal override specified in the constructor
59 * @return the obtained result provider
60 */
61 public IQueryResultProvider requestResultProvider(IQueryReference call, QueryEvaluationHint spotOverride) {
62 QueryEvaluationHint hints =
63 delegationStrategy.transformHints(call, callerHint, callerBackend, hintProvider);
64
65 if (universalOverride != null)
66 hints = hints.overrideBy(universalOverride);
67
68 if (spotOverride != null)
69 hints = hints.overrideBy(spotOverride);
70
71 return resultProviderAccess.getResultProvider(call.getReferredQuery(), hints);
72 }
73
74}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryMetaContext.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryMetaContext.java
new file mode 100644
index 00000000..99611758
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryMetaContext.java
@@ -0,0 +1,69 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.Comparator;
14import java.util.HashMap;
15import java.util.Map;
16import java.util.Set;
17
18/**
19 * Common abstract class for implementers of {@link IQueryMetaContext}
20 *
21 * @author Grill Balázs
22 * @since 1.3
23 *
24 */
25public abstract class AbstractQueryMetaContext implements IQueryMetaContext {
26
27 /**
28 * @since 2.0
29 */
30 @Override
31 public Map<InputKeyImplication, Set<InputKeyImplication>> getConditionalImplications(IInputKey implyingKey) {
32 return new HashMap<>();
33 }
34
35 /**
36 * @since 1.6
37 */
38 @Override
39 public boolean canLeadOutOfScope(IInputKey key) {
40 return key.getArity() > 1;
41 }
42
43 /**
44 * @since 1.6
45 */
46 @Override
47 public Comparator<IInputKey> getSuggestedEliminationOrdering() {
48 return (o1, o2) -> 0;
49 }
50
51 /**
52 * @since 1.6
53 */
54 @Override
55 public Collection<InputKeyImplication> getWeakenedAlternatives(IInputKey implyingKey) {
56 return Collections.emptySet();
57 }
58
59 @Override
60 public boolean isPosetKey(IInputKey key) {
61 return false;
62 }
63
64 @Override
65 public IPosetComparator getPosetComparator(Iterable<IInputKey> key) {
66 return null;
67 }
68
69}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryRuntimeContext.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryRuntimeContext.java
new file mode 100644
index 00000000..c797eff9
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/AbstractQueryRuntimeContext.java
@@ -0,0 +1,21 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11/**
12 * This class is intended to be extended by implementors. The main purpose of this abstract implementation to protect
13 * implementors from future changes in the interface.
14 *
15 * @author Grill Balázs
16 * @since 1.4
17 *
18 */
19public abstract class AbstractQueryRuntimeContext implements IQueryRuntimeContext {
20
21}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IInputKey.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IInputKey.java
new file mode 100644
index 00000000..4dbcca88
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IInputKey.java
@@ -0,0 +1,45 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11/**
12 * An input key identifies an input (extensional) relation, such as the instance set of a given node or edge type, or the direct containment relation.
13 *
14 * <p> The input key, at the very minimum, is associated with an arity (number of columns), a user-friendly name, and a string identifier (for distributive purposes).
15 *
16 * <p> The input key itself must be an immutable data object that properly overrides equals() and hashCode().
17 * It must be instantiable without using the query context object, so that query specifications may construct the appropriate PQueries.
18 *
19 * @author Bergmann Gabor
20 *
21 */
22public interface IInputKey {
23
24 /**
25 * A user-friendly name that can be shown on screen for debug purposes, included in exceptions, etc.
26 */
27 public String getPrettyPrintableName();
28 /**
29 * An internal string identifier that can be used to uniquely identify to input key (relevant for distributed applications).
30 */
31 public String getStringID();
32
33 /**
34 * The width of tuples in this relation.
35 */
36 public int getArity();
37
38 /**
39 * Returns true iff instance tuples of the key can be enumerated.
40 * <p> If false, the runtime can only test tuple membership in the extensional relation identified by the key, but not enumerate member tuples in general.
41 */
42 boolean isEnumerable();
43
44
45}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IPosetComparator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IPosetComparator.java
new file mode 100644
index 00000000..e2d5bcee
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IPosetComparator.java
@@ -0,0 +1,35 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
12
13/**
14 * Implementations of this interface aid the query engine with the ordering of poset elements. This information is
15 * particularly important in the delete and re-derive evaluation mode because they let the engine identify monotone
16 * change pairs.
17 *
18 * @author Tamas Szabo
19 * @since 1.6
20 */
21public interface IPosetComparator {
22
23 /**
24 * Returns true if the 'left' tuple of poset elements is smaller or equal than the 'right' tuple of poset elements according to
25 * the partial order that this poset comparator employs.
26 *
27 * @param left
28 * the left tuple of poset elements
29 * @param right
30 * the right tuple of poset elements
31 * @return true if left is smaller or equal to right, false otherwise
32 */
33 public boolean isLessOrEqual(final Tuple left, final Tuple right);
34
35}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryBackendContext.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryBackendContext.java
new file mode 100644
index 00000000..04f00aaa
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryBackendContext.java
@@ -0,0 +1,49 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11import org.apache.log4j.Logger;
12import tools.refinery.viatra.runtime.matchers.backend.IMatcherCapability;
13import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendHintProvider;
14import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
15import tools.refinery.viatra.runtime.matchers.psystem.analysis.QueryAnalyzer;
16import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
17
18/**
19 * This interface is a collector which holds every API that is provided by the engine to control
20 * the operation of the backends.
21 *
22 * @since 1.5
23 * @noimplement This interface is not intended to be implemented by clients.
24 */
25public interface IQueryBackendContext {
26
27 Logger getLogger();
28
29 IQueryRuntimeContext getRuntimeContext();
30
31 IQueryCacheContext getQueryCacheContext();
32
33 IQueryBackendHintProvider getHintProvider();
34
35 IQueryResultProviderAccess getResultProviderAccess();
36
37 QueryAnalyzer getQueryAnalyzer();
38
39 /**
40 * @since 2.0
41 */
42 IMatcherCapability getRequiredMatcherCapability(PQuery query, QueryEvaluationHint overrideHints);
43
44 /**
45 * @since 1.6
46 */
47 boolean areUpdatesDelayed();
48
49}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryCacheContext.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryCacheContext.java
new file mode 100644
index 00000000..617207f6
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryCacheContext.java
@@ -0,0 +1,39 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
12import tools.refinery.viatra.runtime.matchers.backend.IQueryBackend;
13import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
14import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
15
16/**
17 * Provides information on already cached queries to query evaluator backends at runtime.
18 *
19 * @author Bergmann Gabor
20 *
21 */
22public interface IQueryCacheContext {
23
24 /**
25 * Checks if there already is a caching result provider for the given query.
26 * <p> Returns false if called while the caching result provider of the given query is being constructed in the first place.
27 */
28 public boolean isResultCached(PQuery query);
29
30 /**
31 * Returns a caching result provider for the given query; it must be constructed if it does not exist yet.
32 * <p> <b>Caution:</b> behavior undefined if called while the caching result provider of the given query is being constructed.
33 * Beware of infinite loops.
34 * <p> <b>Postcondition:</b> {@link IQueryBackend#isCaching()} returns true for the {@link #getQueryBackend()} of the returned provider
35 *
36 * @throws ViatraQueryRuntimeException
37 */
38 public IQueryResultProvider getCachingResultProvider(PQuery query);
39}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryMetaContext.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryMetaContext.java
new file mode 100644
index 00000000..4c22a3cb
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryMetaContext.java
@@ -0,0 +1,98 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11import java.util.Collection;
12import java.util.Comparator;
13import java.util.Map;
14import java.util.Set;
15
16/**
17 * Provides metamodel information (relationship of input keys) to query evaluator backends at runtime and at query planning time.
18 *
19 * @noimplement Implementors should extend {@link AbstractQueryMetaContext} instead of directly implementing this interface.
20 * @author Bergmann Gabor
21 */
22public interface IQueryMetaContext {
23
24 /**
25 * Returns true iff instance tuples of the given key can be enumerated.
26 * <p> If false, the runtime can only test tuple membership in the extensional relation identified by the key, but not enumerate member tuples in general.
27 * <p> Equivalent to {@link IInputKey#isEnumerable()}.
28 */
29 boolean isEnumerable(IInputKey key);
30
31 /**
32 * Returns true iff the set of instance tuples of the given key is immutable.
33 * <p> If false, the runtime provides notifications upon change.
34 */
35 boolean isStateless(IInputKey key);
36
37 /**
38 * Returns a set of implications (weakened alternatives),
39 * with a suggestion for the query planner that satisfying them first may help in satisfying the implying key.
40 * <p> Note that for the obvious reasons, enumerable keys can only be implied by enumerable keys.
41 * <p> Must follow directly or transitively from implications of {@link #getImplications(IInputKey)}.
42 * @since 1.6
43 */
44 Collection<InputKeyImplication> getWeakenedAlternatives(IInputKey implyingKey);
45
46 /**
47 * Returns known direct implications, e.g. edge supertypes, edge opposites, node type constraints, etc.
48 * <p> Note that for the obvious reasons, enumerable keys can only be implied by enumerable keys.
49 */
50 Collection<InputKeyImplication> getImplications(IInputKey implyingKey);
51
52 /**
53 * Returns known "double dispatch" implications, where the given implying key implies other input keys under certain additional conditions (themselves input keys).
54 * For example, a "type x, unscoped" input key may imply the "type x, in scope" input key under the condition of the input key "x is in scope"
55 *
56 * <p> Note that for the obvious reasons, enumerable keys can only be implied by enumerable keys (either as the implying key or as the additional condition).
57 * <p> Note that symmetry is not required, i.e. the additional conditions do not have to list the same conditional implication.
58 * @return multi-map, where the keys are additional conditions and the values are input key implications jointly implied by the condition and the given implying key.
59 * @since 2.0
60 */
61 Map<InputKeyImplication, Set<InputKeyImplication>> getConditionalImplications(IInputKey implyingKey);
62
63 /**
64 * Returns functional dependencies of the input key expressed in terms of column indices.
65 *
66 * <p> Each entry of the map is a functional dependency rule, where the entry key specifies source columns and the entry value specifies target columns.
67 */
68 Map<Set<Integer>, Set<Integer>> getFunctionalDependencies(IInputKey key);
69
70 /**
71 * For query normalizing, this is the order suggested for trying to eliminate input keys.
72 * @since 1.6
73 */
74 Comparator<IInputKey> getSuggestedEliminationOrdering();
75
76 /**
77 * Tells whether the given {@link IInputKey} is an edge and may lead out of scope.
78 *
79 * @since 1.6
80 */
81 boolean canLeadOutOfScope(IInputKey key);
82
83 /**
84 * Returns true if the given {@link IInputKey} represents a poset type.
85 * @since 1.6
86 */
87 boolean isPosetKey(IInputKey key);
88
89 /**
90 * Returns an {@link IPosetComparator} for the given set of {@link IInputKey}s.
91 *
92 * @param keys an iterable collection of input keys
93 * @return the poset comparator
94 * @since 1.6
95 */
96 IPosetComparator getPosetComparator(Iterable<IInputKey> keys);
97
98}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryResultProviderAccess.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryResultProviderAccess.java
new file mode 100644
index 00000000..7fecd01a
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryResultProviderAccess.java
@@ -0,0 +1,31 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
12import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
13import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
14
15/**
16 * This interface exposes API to request {@link IQueryResultProvider} for {@link PQuery} instances.
17 *
18 * @author Grill Balázs
19 * @since 1.5
20 * @noimplement This interface is not intended to be implemented by clients.
21 */
22public interface IQueryResultProviderAccess {
23
24 /**
25 * Get a result provider for the given {@link PQuery}, which conforms the capabilities requested by the
26 * given {@link QueryEvaluationHint} object.
27 * @throws ViatraQueryRuntimeException
28 */
29 public IQueryResultProvider getResultProvider(PQuery query, QueryEvaluationHint overrideHints);
30
31}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContext.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContext.java
new file mode 100644
index 00000000..61359c1b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContext.java
@@ -0,0 +1,287 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools>
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v. 2.0 which is available at
6 * http://www.eclipse.org/legal/epl-v20.html.
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *******************************************************************************/
10package tools.refinery.viatra.runtime.matchers.context;
11
12import tools.refinery.viatra.runtime.CancellationToken;
13import tools.refinery.viatra.runtime.matchers.planning.helpers.StatisticsHelper;
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.Accuracy;
18
19import java.lang.reflect.InvocationTargetException;
20import java.util.Optional;
21import java.util.concurrent.Callable;
22
23/**
24 * Provides instance model information (relations corresponding to input keys) to query evaluator backends at runtime.
25 * Implementors shall extend {@link AbstractQueryRuntimeContext} instead directly this interface.
26 *
27 * @author Bergmann Gabor
28 * @noimplement This interface is not intended to be implemented by clients. Extend {@link AbstractQueryRuntimeContext} instead.
29 */
30public interface IQueryRuntimeContext {
31 /**
32 * Provides metamodel-specific info independent of the runtime instance model.
33 */
34 public IQueryMetaContext getMetaContext();
35
36
37 /**
38 * The given callable will be executed, and all model traversals will be delayed until the execution is done. If
39 * there are any outstanding information to be read from the model, a single coalesced model traversal will
40 * initialize the caches and deliver the notifications.
41 *
42 * <p> Calls may be nested. A single coalesced traversal will happen at the end of the outermost call.
43 *
44 * <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.
45 * 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.
46 * Non-incremental query backends should therefore never enumerate input keys while coalesced (verify using {@link #isCoalescing()}).
47 *
48 * @param callable
49 */
50 public abstract <V> V coalesceTraversals(Callable<V> callable) throws InvocationTargetException;
51 /**
52 * @return true iff currently within a coalescing section (i.e. within the callable of a call to {@link #coalesceTraversals(Callable)}).
53 */
54 public boolean isCoalescing();
55
56 /**
57 * Returns true if index is available for the given key providing the given service.
58 * @throws IllegalArgumentException if key is not enumerable or an unknown type, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
59 * @since 1.4
60 */
61 public boolean isIndexed(IInputKey key, IndexingService service);
62
63 /**
64 * If the given (enumerable) input key is not yet indexed, the model will be traversed
65 * (after the end of the outermost coalescing block, see {@link IQueryRuntimeContext#coalesceTraversals(Callable)})
66 * so that the index can be built. It is possible that the base indexer will select a higher indexing level merging
67 * multiple indexing requests to an appropriate level.
68 *
69 * <p><b>Postcondition:</b> After invoking this method, {@link #getIndexed(IInputKey, IndexingService)} for the same key
70 * and service will be guaranteed to return the requested or a highing indexing level as soon as {@link #isCoalescing()} first returns false.
71 *
72 * <p><b>Precondition:</b> the given key is enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
73 * @throws IllegalArgumentException if key is not enumerable or an unknown type, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
74 * @since 1.4
75 */
76 public void ensureIndexed(IInputKey key, IndexingService service);
77
78 /**
79 * Returns the number of tuples in the extensional relation identified by the input key seeded with the given mask and tuple.
80 *
81 * @param key an input key
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 once in seedMask.
85 * @param seed
86 * the tuple of fixed values restricting the match set to be considered, in the same order as given in
87 * parameterSeedMask, so that for each considered match tuple,
88 * projectedParameterSeed.equals(parameterSeedMask.transform(match)) should hold. Must not be null.
89 *
90 * @return the number of tuples in the model for the given key and seed
91 *
92 * <p><b>Precondition:</b> the given key is enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
93 * @throws IllegalArgumentException if key is not enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
94 * @since 1.7
95 */
96 public int countTuples(IInputKey key, TupleMask seedMask, ITuple seed);
97
98
99 /**
100 * Gives an estimate of the number of different groups the tuples of the given relation are projected into by the given mask
101 * (e.g. for an identity mask, this means the full relation size). The estimate must meet the required accuracy.
102 *
103 * <p> Must accept any input key, even non-enumerables or those not recognized by this runtime context.
104 * If there is insufficient information to provide an answer up to the required precision, {@link Optional#empty()} is returned.
105 *
106 * <p> PRE: {@link TupleMask#isNonrepeating()} must hold for the group mask.
107 *
108 * @return if available, an estimate of the cardinality of the projection of the given extensional relation, with the desired accuracy.
109 *
110 * @since 2.1
111 */
112 public Optional<Long> estimateCardinality(IInputKey key, TupleMask groupMask, Accuracy requiredAccuracy);
113
114
115 /**
116 * Gives an estimate of the average size of different groups the tuples of the given relation are projected into by the given mask
117 * (e.g. for an identity mask, this means 1, while for an empty mask, the result is the full relation size).
118 * The estimate must meet the required accuracy.
119 *
120 * <p> Must accept any input key, even non-enumerables or those not recognized by this runtime context.
121 * If there is insufficient information to provide an answer up to the required precision, {@link Optional#empty()} may be returned.
122 *
123 * <p> For an empty relation, zero is acceptable as an exact answer.
124 *
125 * <p> PRE: {@link TupleMask#isNonrepeating()} must hold for the group mask.
126 *
127 * @return if available, an estimate of the average size of each projection group of the given extensional relation, with the desired accuracy.
128 *
129 * @since 2.1
130 */
131 public default Optional<Double> estimateAverageBucketSize(IInputKey key, TupleMask groupMask, Accuracy requiredAccuracy) {
132 if (key.isEnumerable()) {
133 return StatisticsHelper.estimateAverageBucketSize(groupMask, requiredAccuracy,
134 (mask, accuracy) -> this.estimateCardinality(key, mask, accuracy));
135 } else return groupMask.isIdentity() ? Optional.of(1.0) : Optional.empty();
136 }
137
138
139 /**
140 * Returns the tuples in the extensional relation identified by the input key, optionally seeded with the given tuple.
141 *
142 * @param key an input key
143 * @param seedMask
144 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
145 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most once in seedMask.
146 * @param seed
147 * the tuple of fixed values restricting the match set to be considered, in the same order as given in
148 * parameterSeedMask, so that for each considered match tuple,
149 * projectedParameterSeed.equals(parameterSeedMask.transform(match)) should hold. Must not be null.
150 * @return the tuples in the model for the given key and seed
151 *
152 * <p><b>Precondition:</b> the given key is enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
153 * @throws IllegalArgumentException if key is not enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
154 * @since 1.7
155 */
156 public Iterable<Tuple> enumerateTuples(IInputKey key, TupleMask seedMask, ITuple seed);
157
158 /**
159 * Simpler form of {@link #enumerateTuples(IInputKey, TupleMask, Tuple)} in the case where all values of the tuples
160 * are bound by the seed except for one.
161 *
162 * <p>
163 * Selects the tuples in the extensional relation identified by the input key, optionally seeded with the given
164 * tuple, and then returns the single value from each tuple which is not bound by the ssed mask.
165 *
166 * @param key
167 * an input key
168 * @param seedMask
169 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
170 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most
171 * once in seedMask, and seedMask must include all parameters in any arbitrary order except one.
172 * @param seed
173 * the tuple of fixed values restricting the match set to be considered, in the same order as given in
174 * parameterSeedMask, so that for each considered match tuple,
175 * projectedParameterSeed.equals(parameterSeedMask.transform(match)) should hold. Must not be null.
176 * @return the objects in the model for the given key and seed
177 *
178 * <p>
179 * <b>Precondition:</b> the given key is enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
180 * @throws IllegalArgumentException
181 * if key is not enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
182 * @since 1.7
183 */
184 public Iterable<? extends Object> enumerateValues(IInputKey key, TupleMask seedMask, ITuple seed);
185
186 /**
187 * Simpler form of {@link #enumerateTuples(IInputKey, TupleMask, Tuple)} in the case where all values of the tuples
188 * are bound by the seed.
189 *
190 * <p>
191 * Returns whether the given tuple is in the extensional relation identified by the input key.
192 *
193 * <p>
194 * Note: this call works for non-enumerable input keys as well.
195 *
196 * @param key
197 * an input key
198 * @param seed
199 * the tuple of fixed values restricting the match set to be considered, in the same order as given in
200 * parameterSeedMask, so that for each considered match tuple,
201 * projectedParameterSeed.equals(parameterSeedMask.transform(match)) should hold. Must not be null.
202 * @return true iff there is at least a single tuple contained in the relation that corresponds to the seed tuple
203 * @since 2.0
204 */
205 public boolean containsTuple(IInputKey key, ITuple seed);
206
207
208 /**
209 * Subscribes for updates in the extensional relation identified by the input key, optionally seeded with the given tuple.
210 * <p> This should be called after invoking
211 *
212 * @param key an input key
213 * @param seed can be null or a tuple with matching arity;
214 * if non-null, only those updates in the model are notified about
215 * that match the seed at positions where the seed is non-null.
216 * @param listener will be notified of future changes
217 *
218 * <p><b>Precondition:</b> the given key is enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
219 * @throws IllegalArgumentException if key is not enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
220 */
221 public void addUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener);
222
223 /**
224 * Unsubscribes from updates in the extensional relation identified by the input key, optionally seeded with the given tuple.
225 *
226 * @param key an input key
227 * @param seed can be null or a tuple with matching arity;
228 * if non-null, only those updates in the model are notified about
229 * that match the seed at positions where the seed is non-null.
230 * @param listener will no longer be notified of future changes
231 *
232 * <p><b>Precondition:</b> the given key is enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
233 * @throws IllegalArgumentException if key is not enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
234 */
235 public void removeUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener);
236 /*
237 TODO: uniqueness
238 */
239
240 /**
241 * Wraps the external element into the internal representation that is to be used by the query backend
242 * <p> model element -> internal object.
243 * <p> null must be mapped to null.
244 */
245 public Object wrapElement(Object externalElement);
246
247 /**
248 * Unwraps the internal representation of the element into its original form
249 * <p> internal object -> model element
250 * <p> null must be mapped to null.
251 */
252 public Object unwrapElement(Object internalElement);
253
254 /**
255 * Unwraps the tuple of elements into the internal representation that is to be used by the query backend
256 * <p> model elements -> internal objects
257 * <p> null must be mapped to null.
258 */
259 public Tuple wrapTuple(Tuple externalElements);
260
261 /**
262 * Unwraps the tuple of internal representations of elements into their original forms
263 * <p> internal objects -> model elements
264 * <p> null must be mapped to null.
265 */
266 public Tuple unwrapTuple(Tuple internalElements);
267
268 /**
269 * Starts wildcard indexing for the given service. After this call, no registration is required for this {@link IndexingService}.
270 * a previously set wildcard level cannot be lowered, only extended.
271 * @since 1.4
272 */
273 public void ensureWildcardIndexing(IndexingService service);
274
275 /**
276 * Execute the given runnable after traversal. It is guaranteed that the runnable is executed as soon as
277 * the indexing is finished. The callback is executed only once, then is removed from the callback queue.
278 * @param traversalCallback
279 * @throws InvocationTargetException
280 * @since 1.4
281 */
282 public void executeAfterTraversal(Runnable runnable) throws InvocationTargetException;
283
284 default CancellationToken getCancellationToken() {
285 return CancellationToken.NONE;
286 }
287}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContextListener.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContextListener.java
new file mode 100644
index 00000000..7be27d56
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IQueryRuntimeContextListener.java
@@ -0,0 +1,27 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
12
13/**
14 * Listens for changes in the runtime context.
15 * @author Bergmann Gabor
16 *
17 */
18public interface IQueryRuntimeContextListener {
19
20 /**
21 * The given tuple was inserted into or removed from the input relation indicated by the given key.
22 * @param key the key identifying the input relation that was updated
23 * @param updateTuple the tuple that was inserted or removed
24 * @param isInsertion true if it was an insertion, false otherwise.
25 */
26 public void update(IInputKey key, Tuple updateTuple, boolean isInsertion);
27}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IndexingService.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IndexingService.java
new file mode 100644
index 00000000..8210765d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/IndexingService.java
@@ -0,0 +1,36 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11/**
12 * These are the different services which can be provided by an {@link IQueryRuntimeContext} implementation.
13 *
14 * @author Grill Balázs
15 * @since 1.4
16 *
17 */
18public enum IndexingService {
19
20 /**
21 * Cardinality information is available. Makes possible to calculate
22 * unseeded calls of {@link IQueryRuntimeContext#countTuples(IInputKey, tools.refinery.viatra.runtime.matchers.tuple.Tuple)}
23 */
24 STATISTICS,
25
26 /**
27 * The indexer can provide notifications about changes in the model.
28 */
29 NOTIFICATIONS,
30
31 /**
32 * Enables enumeration of instances and reverse-navigation.
33 */
34 INSTANCES
35
36}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/InputKeyImplication.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/InputKeyImplication.java
new file mode 100644
index 00000000..2a403810
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/InputKeyImplication.java
@@ -0,0 +1,103 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context;
10
11import java.util.ArrayList;
12import java.util.Collections;
13import java.util.List;
14
15/**
16 * Data object representing the implication of an input key, in use cases including edge supertypes, edge opposites, node type constraints, etc.
17 *
18 * <p> Each instance tuple of the <i>implying input key</i> (if given) implies the presence of an instance tuple of the <i>implied input key</i> consisting of elements of the original tuple at given positions.
19 * When the input key is null, it is not an input constraint but some other source that implies input keys.
20 *
21 * <p> The implication is an immutable data object.
22 *
23 * @author Bergmann Gabor
24 *
25 */
26public final class InputKeyImplication {
27 private IInputKey implyingKey;
28 private IInputKey impliedKey;
29 private List<Integer> impliedIndices;
30
31 /**
32 * Optional. Instance tuples of this input key imply an instance tuple of another key.
33 * Sometimes it is not an input key that implies other input keys, so this attribute can be null.
34 */
35 public IInputKey getImplyingKey() {
36 return implyingKey;
37 }
38 /**
39 * An instance tuple of this input key is implied by another key.
40 */
41 public IInputKey getImpliedKey() {
42 return impliedKey;
43 }
44 /**
45 * The implied instance tuple consists of the values in the implying tuple at these indices.
46 */
47 public List<Integer> getImpliedIndices() {
48 return impliedIndices;
49 }
50 /**
51 * @param implyingKey instance tuples of this input key imply an instance tuple of the other key.
52 * @param impliedKey instance tuple of this input key is implied by the other key.
53 * @param implyingIndices the implied instance tuple consists of the values in the implying tuple at these indices.
54 */
55 public InputKeyImplication(IInputKey implyingKey, IInputKey impliedKey,
56 List<Integer> implyingIndices) {
57 super();
58 this.implyingKey = implyingKey;
59 this.impliedKey = impliedKey;
60 this.impliedIndices = Collections.unmodifiableList(new ArrayList<>(implyingIndices));
61 }
62
63 @Override
64 public int hashCode() {
65 final int prime = 31;
66 int result = 1;
67 result = prime * result
68 + ((impliedIndices == null) ? 0 : impliedIndices.hashCode());
69 result = prime * result
70 + ((impliedKey == null) ? 0 : impliedKey.hashCode());
71 result = prime * result
72 + ((implyingKey == null) ? 0 : implyingKey.hashCode());
73 return result;
74 }
75 @Override
76 public boolean equals(Object obj) {
77 if (this == obj)
78 return true;
79 if (obj == null)
80 return false;
81 if (!(obj instanceof InputKeyImplication))
82 return false;
83 InputKeyImplication other = (InputKeyImplication) obj;
84 if (impliedIndices == null) {
85 if (other.impliedIndices != null)
86 return false;
87 } else if (!impliedIndices.equals(other.impliedIndices))
88 return false;
89 if (impliedKey == null) {
90 if (other.impliedKey != null)
91 return false;
92 } else if (!impliedKey.equals(other.impliedKey))
93 return false;
94 if (implyingKey == null) {
95 if (other.implyingKey != null)
96 return false;
97 } else if (!implyingKey.equals(other.implyingKey))
98 return false;
99 return true;
100 }
101
102
103}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/BaseInputKeyWrapper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/BaseInputKeyWrapper.java
new file mode 100644
index 00000000..f9b05e5b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/BaseInputKeyWrapper.java
@@ -0,0 +1,55 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context.common;
10
11import tools.refinery.viatra.runtime.matchers.context.IInputKey;
12
13
14/**
15 * An input key that is identified by a single wrapped object and the class of the wrapper.
16 * @author Bergmann Gabor
17 *
18 */
19public abstract class BaseInputKeyWrapper<Wrapped> implements IInputKey {
20 protected Wrapped wrappedKey;
21
22 public BaseInputKeyWrapper(Wrapped wrappedKey) {
23 super();
24 this.wrappedKey = wrappedKey;
25 }
26
27 public Wrapped getWrappedKey() {
28 return wrappedKey;
29 }
30
31
32 @Override
33 public int hashCode() {
34 return ((wrappedKey == null) ? 0 : wrappedKey.hashCode());
35 }
36
37 @Override
38 public boolean equals(Object obj) {
39 if (this == obj)
40 return true;
41 if (obj == null)
42 return false;
43 if (!(this.getClass().equals(obj.getClass())))
44 return false;
45 BaseInputKeyWrapper other = (BaseInputKeyWrapper) obj;
46 if (wrappedKey == null) {
47 if (other.wrappedKey != null)
48 return false;
49 } else if (!wrappedKey.equals(other.wrappedKey))
50 return false;
51 return true;
52 }
53
54
55}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/JavaTransitiveInstancesKey.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/JavaTransitiveInstancesKey.java
new file mode 100644
index 00000000..eb972c2d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/common/JavaTransitiveInstancesKey.java
@@ -0,0 +1,165 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context.common;
10
11
12
13/**
14 * Instance tuples are of form (x), where object x is an instance of the given Java class or its subclasses.
15 * <p> Fine print 1: classes with the same name are considered equivalent.
16 * Can be instantiated with class name, even if the class itself is not loaded yet; but if the class is available, passing it in the constructor is beneficial to avoid classloading troubles.
17 * <p> Fine print 2: primitive types (char, etc.) are transparently treated as their wrapper class (Character, etc.).
18 * <p> Non-enumerable type, can only be checked.
19 * <p> Stateless type (objects can't change their type)
20 * @author Bergmann Gabor
21 *
22*/
23public class JavaTransitiveInstancesKey extends BaseInputKeyWrapper<String> {
24
25 /**
26 * The actual Class whose (transitive) instances this relation contains. Can be null at compile time, if only the name is available.
27 * Can be a primitive.
28 */
29 private Class<?> cachedOriginalInstanceClass;
30
31 /**
32 * Same as {@link #cachedOriginalInstanceClass}, but primitive classes are replaced with their wrapper classes (e.g. int --> java.lang.Integer).
33 */
34 private Class<?> cachedWrapperInstanceClass;
35
36 /**
37 * Preferred constructor.
38 */
39 public JavaTransitiveInstancesKey(Class<?> instanceClass) {
40 this(primitiveTypeToWrapperClass(instanceClass).getName());
41 this.cachedOriginalInstanceClass = instanceClass;
42 }
43
44 /**
45 * Call this constructor only in contexts where the class itself is not available for loading, e.g. it has not yet been compiled.
46 */
47 public JavaTransitiveInstancesKey(String className) {
48 super(className);
49 }
50
51
52 /**
53 * Returns null if class cannot be loaded.
54 */
55 private Class<?> getOriginalInstanceClass() {
56 if (cachedOriginalInstanceClass == null) {
57 try {
58 resolveClassInternal();
59 } catch (ClassNotFoundException e) {
60 // class not yet available at this point
61 }
62 }
63 return cachedOriginalInstanceClass;
64 }
65
66
67 /**
68 * @return non-null instance class
69 * @throws ClassNotFoundException
70 */
71 private Class<?> forceGetOriginalInstanceClass() throws ClassNotFoundException {
72 if (cachedOriginalInstanceClass == null) {
73 resolveClassInternal();
74 }
75 return cachedOriginalInstanceClass;
76 }
77
78 /**
79 * @return non-null instance class, wrapped if primitive class
80 * @throws ClassNotFoundException
81 */
82 public Class<?> forceGetWrapperInstanceClass() throws ClassNotFoundException {
83 forceGetOriginalInstanceClass();
84 return getWrapperInstanceClass();
85 }
86 /**
87 * @return non-null instance class, wrapped if primitive class
88 * @throws ClassNotFoundException
89 */
90 public Class<?> forceGetInstanceClass() throws ClassNotFoundException {
91 return forceGetWrapperInstanceClass();
92 }
93
94 /**
95 * @return instance class, wrapped if primitive class, null if class cannot be loaded
96 */
97 public Class<?> getWrapperInstanceClass() {
98 if (cachedWrapperInstanceClass == null) {
99 cachedWrapperInstanceClass = primitiveTypeToWrapperClass(getOriginalInstanceClass());
100 }
101 return cachedWrapperInstanceClass;
102 }
103 /**
104 * @return instance class, wrapped if primitive class, null if class cannot be loaded
105 */
106 public Class<?> getInstanceClass() {
107 return getWrapperInstanceClass();
108 }
109
110 private void resolveClassInternal() throws ClassNotFoundException {
111 cachedOriginalInstanceClass = Class.forName(wrappedKey);
112 }
113
114 @Override
115 public String getPrettyPrintableName() {
116 getWrapperInstanceClass();
117 return cachedWrapperInstanceClass == null ? wrappedKey == null ? "<null>" : wrappedKey : cachedWrapperInstanceClass.getName();
118 }
119
120 @Override
121 public String getStringID() {
122 return "javaClass#"+ getPrettyPrintableName();
123 }
124
125 @Override
126 public int getArity() {
127 return 1;
128 }
129
130 @Override
131 public boolean isEnumerable() {
132 return false;
133 }
134
135 @Override
136 public String toString() {
137 return this.getPrettyPrintableName();
138 }
139
140 private static Class<?> primitiveTypeToWrapperClass(Class<?> instanceClass) {
141 if (instanceClass != null && instanceClass.isPrimitive()) {
142 if (Void.TYPE.equals(instanceClass))
143 return Void.class;
144 if (Boolean.TYPE.equals(instanceClass))
145 return Boolean.class;
146 if (Character.TYPE.equals(instanceClass))
147 return Character.class;
148 if (Byte.TYPE.equals(instanceClass))
149 return Byte.class;
150 if (Short.TYPE.equals(instanceClass))
151 return Short.class;
152 if (Integer.TYPE.equals(instanceClass))
153 return Integer.class;
154 if (Long.TYPE.equals(instanceClass))
155 return Long.class;
156 if (Float.TYPE.equals(instanceClass))
157 return Float.class;
158 if (Double.TYPE.equals(instanceClass))
159 return Double.class;
160 }
161 return instanceClass;
162 }
163
164
165}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/surrogate/SurrogateQueryRegistry.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/surrogate/SurrogateQueryRegistry.java
new file mode 100644
index 00000000..bb24ec8c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/context/surrogate/SurrogateQueryRegistry.java
@@ -0,0 +1,153 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Abel Hegedus, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.context.surrogate;
10
11import java.util.Collections;
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.Map;
15import java.util.NoSuchElementException;
16import java.util.Set;
17
18import tools.refinery.viatra.runtime.matchers.context.IInputKey;
19import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
20import tools.refinery.viatra.runtime.matchers.util.IProvider;
21import tools.refinery.viatra.runtime.matchers.util.Preconditions;
22import tools.refinery.viatra.runtime.matchers.util.SingletonInstanceProvider;
23
24/**
25 * @author Abel Hegedus
26 *
27 */
28public class SurrogateQueryRegistry {
29
30 private Map<IInputKey, IProvider<PQuery>> registeredSurrogateQueryMap = new HashMap<>();
31 private Map<IInputKey, IProvider<PQuery>> dynamicSurrogateQueryMap = new HashMap<>();
32
33 /**
34 * Hidden constructor
35 */
36 private SurrogateQueryRegistry() {
37 }
38
39 private static final SurrogateQueryRegistry INSTANCE = new SurrogateQueryRegistry();
40
41 public static SurrogateQueryRegistry instance() {
42 return INSTANCE;
43 }
44
45 /**
46 *
47 * @param feature
48 * @param surrogateQuery
49 * @return the previous surrogate query associated with feature, or null if there was no such query FQN registered
50 * @throws IllegalArgumentException if feature or surrogateQuery is null
51 */
52 public IProvider<PQuery> registerSurrogateQueryForFeature(IInputKey feature, PQuery surrogateQuery) {
53 Preconditions.checkArgument(surrogateQuery != null, "Surrogate query must not be null!");
54 return registerSurrogateQueryForFeature(feature, new SingletonInstanceProvider<PQuery>(surrogateQuery));
55 }
56
57 /**
58 *
59 * @param feature
60 * @param surrogateQuery
61 * @return the previous surrogate query associated with feature, or null
62 * if there was no such query registered
63 * @throws IllegalArgumentException
64 * if feature or surrogateQuery is null
65 */
66 public IProvider<PQuery> registerSurrogateQueryForFeature(IInputKey feature, IProvider<PQuery> surrogateQueryProvider) {
67 Preconditions.checkArgument(feature != null, "Feature must not be null!");
68 Preconditions.checkArgument(surrogateQueryProvider != null, "Surrogate query must not be null!");
69 return registeredSurrogateQueryMap.put(feature, surrogateQueryProvider);
70 }
71
72 public IProvider<PQuery> addDynamicSurrogateQueryForFeature(IInputKey feature, PQuery surrogateQuery) {
73 Preconditions.checkArgument(surrogateQuery != null, "Surrogate query FQN must not be null!");
74 return addDynamicSurrogateQueryForFeature(feature, new SingletonInstanceProvider<PQuery>(surrogateQuery));
75 }
76
77 public IProvider<PQuery> addDynamicSurrogateQueryForFeature(IInputKey feature, IProvider<PQuery> surrogateQuery) {
78 Preconditions.checkArgument(feature != null, "Feature must not be null!");
79 Preconditions.checkArgument(surrogateQuery != null, "Surrogate query FQN must not be null!");
80 return dynamicSurrogateQueryMap.put(feature, surrogateQuery);
81 }
82
83 public IProvider<PQuery> removeDynamicSurrogateQueryForFeature(IInputKey feature) {
84 Preconditions.checkArgument(feature != null, "Feature must not be null!");
85 return dynamicSurrogateQueryMap.remove(feature);
86 }
87
88 /**
89 *
90 * @param feature that may have surrogate query defined, null not allowed
91 * @return true if the feature has a surrogate query defined
92 * @throws IllegalArgumentException if feature is null
93 */
94 public boolean hasSurrogateQueryFQN(IInputKey feature) {
95 Preconditions.checkArgument(feature != null, "Feature must not be null!");
96 boolean surrogateExists = dynamicSurrogateQueryMap.containsKey(feature);
97 if(!surrogateExists){
98 surrogateExists = registeredSurrogateQueryMap.containsKey(feature);
99 }
100 return surrogateExists;
101 }
102
103 /**
104 *
105 * @param feature for which the surrogate query FQN should be returned
106 * @return the surrogate query FQN defined for the feature
107 * @throws IllegalArgumentException if feature is null
108 * @throws NoSuchElementException if the feature has no surrogate query defined, use {@link #hasSurrogateQueryFQN} to check
109 */
110 public PQuery getSurrogateQuery(IInputKey feature) {
111 Preconditions.checkArgument(feature != null, "Feature must not be null!");
112 IProvider<PQuery> surrogate = dynamicSurrogateQueryMap.get(feature);
113 if(surrogate == null) {
114 surrogate = registeredSurrogateQueryMap.get(feature);
115 }
116 if(surrogate != null) {
117 return surrogate.get();
118 } else {
119 throw new NoSuchElementException(String.format("Feature %s has no surrogate query defined! Use #hasSurrogateQueryFQN to check existence.", feature));
120 }
121 }
122
123 /**
124 * @return an unmodifiable set of features with registered surrogate queries
125 */
126 public Set<IInputKey> getRegisteredSurrogateQueries() {
127 return Collections.unmodifiableSet(getRegisteredSurrogateQueriesInternal());
128 }
129
130 private Set<IInputKey> getRegisteredSurrogateQueriesInternal() {
131 return registeredSurrogateQueryMap.keySet();
132 }
133
134 /**
135 * @return an unmodifiable set of features with dynamically added surrogate queries
136 */
137 public Set<IInputKey> getDynamicSurrogateQueries() {
138 return Collections.unmodifiableSet(getDynamicSurrogateQueriesInternal());
139 }
140
141 private Set<IInputKey> getDynamicSurrogateQueriesInternal() {
142 return dynamicSurrogateQueryMap.keySet();
143 }
144
145 /**
146 * @return an unmodifiable set that contains all features with surrogate queries.
147 */
148 public Set<IInputKey> getAllSurrogateQueries() {
149 Set<IInputKey> results = new HashSet<>(getRegisteredSurrogateQueriesInternal());
150 results.addAll(getDynamicSurrogateQueriesInternal());
151 return results;
152 }
153}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/AbstractTrivialMaskedMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/AbstractTrivialMaskedMemory.java
new file mode 100644
index 00000000..66587f77
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/AbstractTrivialMaskedMemory.java
@@ -0,0 +1,58 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories;
10
11import java.util.Iterator;
12import java.util.Map;
13
14import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
15import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
16import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
17import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
18import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
19import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
20import tools.refinery.viatra.runtime.matchers.util.IMemory;
21
22/**
23 * Common parts of nullary and identity specializations.
24 *
25 * @noextend This class is not intended to be subclassed by clients.
26 * @author Gabor Bergmann
27 * @since 2.0
28 */
29abstract class AbstractTrivialMaskedMemory<Timestamp extends Comparable<Timestamp>> extends MaskedTupleMemory<Timestamp> {
30
31 protected IMemory<Tuple> tuples;
32
33 protected AbstractTrivialMaskedMemory(TupleMask mask, MemoryType bucketType, Object owner) {
34 super(mask, owner);
35 tuples = CollectionsFactory.createMemory(Object.class, bucketType);
36 }
37
38 @Override
39 public Map<Tuple, Timeline<Timestamp>> getWithTimeline(ITuple signature) {
40 throw new UnsupportedOperationException("Timeless memories do not support timestamp-based lookup!");
41 }
42
43 @Override
44 public void clear() {
45 tuples.clear();
46 }
47
48 @Override
49 public int getTotalSize() {
50 return tuples.size();
51 }
52
53 @Override
54 public Iterator<Tuple> iterator() {
55 return tuples.iterator();
56 }
57
58}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/DefaultMaskedTupleMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/DefaultMaskedTupleMemory.java
new file mode 100644
index 00000000..92081409
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/DefaultMaskedTupleMemory.java
@@ -0,0 +1,127 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.memories;
11
12import java.util.Collection;
13import java.util.Iterator;
14import java.util.Map;
15
16import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
17import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
18import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
19import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
20import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
21import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
22import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
23import tools.refinery.viatra.runtime.matchers.util.IMultiLookup.ChangeGranularity;
24import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
25
26/**
27 * @author Gabor Bergmann
28 *
29 * Default implementation that covers all cases.
30 *
31 * @since 2.0
32 */
33public final class DefaultMaskedTupleMemory<Timestamp extends Comparable<Timestamp>>
34 extends MaskedTupleMemory<Timestamp> {
35 /**
36 * Maps a signature tuple to the bucket of tuples with the given signature.
37 *
38 * @since 2.0
39 */
40 protected IMultiLookup<Tuple, Tuple> signatureToTuples;
41
42 /**
43 * @param mask
44 * The mask used to index the matchings
45 * @param owner
46 * the object "owning" this memory
47 * @param bucketType
48 * the kind of tuple collection maintained for each indexer bucket
49 * @since 2.0
50 */
51 public DefaultMaskedTupleMemory(TupleMask mask, MemoryType bucketType, Object owner) {
52 super(mask, owner);
53 signatureToTuples = CollectionsFactory.<Tuple, Tuple> createMultiLookup(Object.class, bucketType, Object.class);
54 }
55
56 @Override
57 public boolean add(Tuple tuple) {
58 Tuple signature = mask.transform(tuple);
59 return add(tuple, signature);
60 }
61
62 @Override
63 public boolean add(Tuple tuple, Tuple signature) {
64 try {
65 return signatureToTuples.addPair(signature, tuple) == ChangeGranularity.KEY;
66 } catch (IllegalStateException ex) { // ignore worthless internal exception details
67 throw raiseDuplicateInsertion(tuple);
68 }
69
70 }
71
72 @Override
73 public boolean remove(Tuple tuple) {
74 Tuple signature = mask.transform(tuple);
75 return remove(tuple, signature);
76 }
77
78 @Override
79 public boolean remove(Tuple tuple, Tuple signature) {
80 try {
81 return signatureToTuples.removePair(signature, tuple) == ChangeGranularity.KEY;
82 } catch (IllegalStateException ex) { // ignore worthless internal exception details
83 throw raiseDuplicateDeletion(tuple);
84 }
85 }
86
87 @Override
88 public Map<Tuple, Timeline<Timestamp>> getWithTimeline(ITuple signature) {
89 throw new UnsupportedOperationException("Timeless memories do not support timestamp-based lookup!");
90 }
91
92 @Override
93 public Collection<Tuple> get(ITuple signature) {
94 IMemoryView<Tuple> bucket = signatureToTuples.lookupUnsafe(signature);
95 return bucket == null ? null : bucket.distinctValues();
96 }
97
98 @Override
99 public void clear() {
100 signatureToTuples.clear();
101 }
102
103 @Override
104 public Iterable<Tuple> getSignatures() {
105 return signatureToTuples.distinctKeys();
106 }
107
108 @Override
109 public Iterator<Tuple> iterator() {
110 return signatureToTuples.distinctValues().iterator();
111 }
112
113 @Override
114 public int getTotalSize() {
115 int i = 0;
116 for (Tuple key : signatureToTuples.distinctKeys()) {
117 i += signatureToTuples.lookup(key).size();
118 }
119 return i;
120 }
121
122 @Override
123 public int getKeysetSize() {
124 return signatureToTuples.countKeys();
125 }
126
127}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/IdentityMaskedTupleMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/IdentityMaskedTupleMemory.java
new file mode 100644
index 00000000..dc59daf5
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/IdentityMaskedTupleMemory.java
@@ -0,0 +1,77 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories;
10
11import java.util.Collection;
12import java.util.Collections;
13
14import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
15import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
16import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
17import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
18
19/**
20 * Specialized for identity mask; tuples are stored as a simple set/multiset memory.
21 *
22 * @author Gabor Bergmann
23 * @since 2.0
24 */
25public final class IdentityMaskedTupleMemory<Timestamp extends Comparable<Timestamp>> extends AbstractTrivialMaskedMemory<Timestamp> {
26
27 /**
28 * @param mask
29 * The mask used to index the matchings
30 * @param owner the object "owning" this memory
31 * @param bucketType the kind of tuple collection maintained for each indexer bucket
32 * @since 2.0
33 */
34 public IdentityMaskedTupleMemory(TupleMask mask, MemoryType bucketType, Object owner) {
35 super(mask, bucketType, owner);
36 if (!mask.isIdentity()) throw new IllegalArgumentException(mask.toString());
37 }
38
39 @Override
40 public int getKeysetSize() {
41 return tuples.size();
42 }
43
44 @Override
45 public Iterable<Tuple> getSignatures() {
46 return tuples;
47 }
48
49 @Override
50 public Collection<Tuple> get(ITuple signature) {
51 Tuple contained = tuples.theContainedVersionOfUnsafe(signature);
52 return contained != null ?
53 Collections.singleton(contained) :
54 null;
55 }
56
57 @Override
58 public boolean remove(Tuple tuple, Tuple signature) {
59 return tuples.removeOne(tuple);
60 }
61
62 @Override
63 public boolean remove(Tuple tuple) {
64 return tuples.removeOne(tuple);
65 }
66
67 @Override
68 public boolean add(Tuple tuple, Tuple signature) {
69 return tuples.addOne(tuple);
70 }
71
72 @Override
73 public boolean add(Tuple tuple) {
74 return tuples.addOne(tuple);
75 }
76
77}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/MaskedTupleMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/MaskedTupleMemory.java
new file mode 100644
index 00000000..62377624
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/MaskedTupleMemory.java
@@ -0,0 +1,385 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.Iterator;
14import java.util.Map;
15
16import tools.refinery.viatra.runtime.matchers.memories.timely.TimelyDefaultMaskedTupleMemory;
17import tools.refinery.viatra.runtime.matchers.memories.timely.TimelyIdentityMaskedTupleMemory;
18import tools.refinery.viatra.runtime.matchers.memories.timely.TimelyNullaryMaskedTupleMemory;
19import tools.refinery.viatra.runtime.matchers.memories.timely.TimelyUnaryMaskedTupleMemory;
20import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
21import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
22import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
23import tools.refinery.viatra.runtime.matchers.util.Clearable;
24import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
25import tools.refinery.viatra.runtime.matchers.util.resumable.MaskedResumable;
26import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
27import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
28
29/**
30 * Indexes a collection of tuples by their signature (i.e. footprint, projection) obtained according to a mask. May
31 * belong to an "owner" (for documentation / traceability purposes).
32 * <p>
33 * There are timeless and timely versions of the different memories. Timely versions associate {@link Timeline}s with
34 * the stored tuples.
35 *
36 * @noextend This class is not intended to be subclassed by clients.
37 * @author Gabor Bergmann
38 * @author Tamas Szabo
39 * @since 2.0
40 */
41public abstract class MaskedTupleMemory<Timestamp extends Comparable<Timestamp>>
42 implements Clearable, MaskedResumable<Timestamp> {
43
44 /**
45 * Creates a new memory for the given owner that indexes tuples according to the given mask.
46 */
47 public static <T extends Comparable<T>> MaskedTupleMemory<T> create(final TupleMask mask,
48 final MemoryType bucketType, final Object owner) {
49 return create(mask, bucketType, owner, false);
50 }
51
52 /**
53 * Creates a new memory for the given owner that indexes tuples according to the given mask. Clients can specify if
54 * the created memory should be timely or not. <br>
55 * <br>
56 * Timely means that tuples are associated with a timeline.
57 *
58 * @since 2.3
59 */
60 public static <T extends Comparable<T>> MaskedTupleMemory<T> create(final TupleMask mask,
61 final MemoryType bucketType, final Object owner, final boolean isTimely) {
62 return create(mask, bucketType, owner, isTimely, false);
63 }
64
65 /**
66 * Creates a new memory for the given owner that indexes tuples according to the given mask. Clients can specify if
67 * the created memory should be timely or not. In case of timely memory, clients can also specify if the memory is
68 * lazy or not. <br>
69 * <br>
70 * Timely means that tuples are associated with a timeline. <br>
71 * <br>
72 * Lazyness can only be used together with timely memories. It means that the maintenance of the timelines is lazy,
73 * that is, the memory only updates its internal data structures at the timestamp affected by an update, and can be
74 * instructed later to resume the maintenance at higher timestamps, as well.
75 *
76 * @since 2.4
77 */
78 public static <T extends Comparable<T>> MaskedTupleMemory<T> create(final TupleMask mask,
79 final MemoryType bucketType, final Object owner, final boolean isTimely, final boolean isLazy) {
80 if (isTimely) {
81 if (bucketType != MemoryType.SETS) {
82 throw new IllegalArgumentException("Timely memories only support SETS as the bucket type!");
83 }
84 if (mask.isIdentity()) {
85 return new TimelyIdentityMaskedTupleMemory<T>(mask, owner, isLazy);
86 } else if (0 == mask.getSize()) {
87 return new TimelyNullaryMaskedTupleMemory<T>(mask, owner, isLazy);
88 } else if (1 == mask.getSize()) {
89 return new TimelyUnaryMaskedTupleMemory<T>(mask, owner, isLazy);
90 } else {
91 return new TimelyDefaultMaskedTupleMemory<T>(mask, owner, isLazy);
92 }
93 } else {
94 if (isLazy) {
95 throw new IllegalArgumentException("Lazy maintenance is only supported by timely memories!");
96 }
97 if (mask.isIdentity()) {
98 return new IdentityMaskedTupleMemory<T>(mask, bucketType, owner);
99 } else if (0 == mask.getSize()) {
100 return new NullaryMaskedTupleMemory<T>(mask, bucketType, owner);
101 } else if (1 == mask.getSize()) {
102 return new UnaryMaskedTupleMemory<T>(mask, bucketType, owner);
103 } else {
104 return new DefaultMaskedTupleMemory<T>(mask, bucketType, owner);
105 }
106 }
107 }
108
109 @Override
110 public Map<Tuple, Map<Tuple, Diff<Timestamp>>> resumeAt(final Timestamp timestamp) {
111 throw new UnsupportedOperationException("This is only supported by lazy timely memory implementations!");
112 }
113
114 @Override
115 public Iterable<Tuple> getResumableSignatures() {
116 throw new UnsupportedOperationException("This is only supported by lazy timely memory implementations!");
117 }
118
119 @Override
120 public Timestamp getResumableTimestamp() {
121 return null;
122 }
123
124 /**
125 * Initializes the contents of this memory based on the contents of another memory. The default value is associated
126 * with each tuple in the timely memories.
127 *
128 * @since 2.3
129 */
130 public void initializeWith(final MaskedTupleMemory<Timestamp> other, final Timestamp defaultValue) {
131 throw new UnsupportedOperationException("This is only supported by timely memory implementations!");
132 }
133
134 /**
135 * Returns true if there is any tuple with the given signature that is present at the timestamp +inf, false
136 * otherwise.
137 * @since 2.4
138 */
139 public boolean isPresentAtInfinity(final ITuple signature) {
140 return get(signature) != null;
141 }
142
143 /**
144 * Returns true of this memory is timely, false otherwise.
145 *
146 * @since 2.3
147 */
148 public boolean isTimely() {
149 return false;
150 }
151
152 /**
153 * The mask by which the tuples are indexed.
154 */
155 protected final TupleMask mask;
156
157 /**
158 * The object "owning" this memory. May be null.
159 *
160 * @since 1.7
161 */
162 protected final Object owner;
163
164 /**
165 * The node owning this memory. May be null.
166 *
167 * @since 2.0
168 */
169 public Object getOwner() {
170 return owner;
171 }
172
173 /**
174 * The mask according to which tuples are projected and indexed.
175 *
176 * @since 2.0
177 */
178 public TupleMask getMask() {
179 return mask;
180 }
181
182 /**
183 * @return the number of distinct signatures of all stored tuples.
184 */
185 public abstract int getKeysetSize();
186
187 /**
188 * @return the total number of distinct tuples stored. Multiple copies of the same tuple, if allowed, are counted as
189 * one.
190 *
191 * <p>
192 * This is currently not cached but computed on demand. It is therefore not efficient, and shall only be
193 * used for debug / profiling purposes.
194 */
195 public abstract int getTotalSize();
196
197 /**
198 * Iterates over distinct tuples stored in the memory, regardless of their signatures.
199 */
200 public abstract Iterator<Tuple> iterator();
201
202 /**
203 * Retrieves a read-only view of exactly those signatures for which at least one tuple is stored
204 *
205 * @since 2.0
206 */
207 public abstract Iterable<Tuple> getSignatures();
208
209 /**
210 * Retrieves tuples that have the specified signature
211 *
212 * @return collection of tuples found, null if none
213 */
214 public abstract Collection<Tuple> get(final ITuple signature);
215
216 /**
217 * Retrieves the tuples and their associated timelines that have the specified signature.
218 *
219 * @return the mappings from tuples to timelines, null if there is no mapping for the signature
220 * @since 2.4
221 */
222 public abstract Map<Tuple, Timeline<Timestamp>> getWithTimeline(final ITuple signature);
223
224 /**
225 * Retrieves tuples that have the specified signature.
226 *
227 * @return collection of tuples found, never null
228 * @since 2.1
229 */
230 public Collection<Tuple> getOrEmpty(final ITuple signature) {
231 final Collection<Tuple> result = get(signature);
232 return result == null ? Collections.emptySet() : result;
233 }
234
235 /**
236 * Retrieves tuples with their associated timelines that have the specified signature.
237 *
238 * @return map of tuples and timelines found, never null
239 * @since 2.4
240 */
241 public Map<Tuple, Timeline<Timestamp>> getOrEmptyWithTimeline(final ITuple signature) {
242 final Map<Tuple, Timeline<Timestamp>> result = getWithTimeline(signature);
243 return result == null ? Collections.emptyMap() : result;
244 }
245
246 /**
247 * Removes a tuple occurrence from the memory with the given signature.
248 *
249 * @param tuple
250 * the tuple to be removed from the memory
251 * @param signature
252 * precomputed footprint of the tuple according to the mask
253 *
254 * @return true if this was the the last occurrence of the signature (according to the mask)
255 */
256 public boolean remove(final Tuple tuple, final Tuple signature) {
257 throw new UnsupportedOperationException("This is only supported by timeless memory implementations!");
258 }
259
260 /**
261 * Removes a tuple occurrence from the memory with the given signature and timestamp.
262 *
263 * @param tuple
264 * the tuple to be removed from the memory
265 * @param signature
266 * precomputed footprint of the tuple according to the mask
267 * @param timestamp
268 * the timestamp associated with the tuple
269 *
270 * @return A {@link Diff} describing how the timeline of the given tuple changed.
271 *
272 * @since 2.4
273 */
274 public Diff<Timestamp> removeWithTimestamp(final Tuple tuple, final Tuple signature, final Timestamp timestamp) {
275 throw new UnsupportedOperationException("This is only supported by timely memory implementations!");
276 }
277
278 /**
279 * Removes a tuple occurrence from the memory.
280 *
281 * @param tuple
282 * the tuple to be removed from the memory
283 *
284 * @return true if this was the the last occurrence of the signature (according to the mask)
285 */
286 public boolean remove(final Tuple tuple) {
287 throw new UnsupportedOperationException("This is only supported by timeless memory implementations!");
288 }
289
290 /**
291 * Removes a tuple occurrence from the memory with the given timestamp.
292 *
293 * @param tuple
294 * the tuple to be removed from the memory
295 * @param timestamp
296 * the timestamp associated with the tuple
297 *
298 * @return A {@link Diff} describing how the timeline of the given tuple changed.
299 *
300 * @since 2.4
301 */
302 public Diff<Timestamp> removeWithTimestamp(final Tuple tuple, final Timestamp timestamp) {
303 throw new UnsupportedOperationException("This is only supported by timely memory implementations!");
304 }
305
306 /**
307 * Adds a tuple occurrence to the memory with the given signature.
308 *
309 * @param tuple
310 * the tuple to be added to the memory
311 * @param signature
312 * precomputed footprint of the tuple according to the mask
313 *
314 * @return true if new signature encountered (according to the mask)
315 */
316 public boolean add(final Tuple tuple, final Tuple signature) {
317 throw new UnsupportedOperationException("This is only supported by timeless memory implementations!");
318 }
319
320 /**
321 * Adds a tuple occurrence to the memory with the given signature and timestamp.
322 *
323 * @param tuple
324 * the tuple to be added to the memory
325 * @param signature
326 * precomputed footprint of the tuple according to the mask
327 * @param timestamp
328 * the timestamp associated with the tuple
329 *
330 * @return A {@link Diff} describing how the timeline of the given tuple changed.
331 *
332 * @since 2.4
333 */
334 public Diff<Timestamp> addWithTimestamp(final Tuple tuple, final Tuple signature, final Timestamp timestamp) {
335 throw new UnsupportedOperationException("This is only supported by timely memory implementations!");
336 }
337
338 /**
339 * Adds a tuple occurrence to the memory.
340 *
341 * @param tuple
342 * the tuple to be added to the memory
343 *
344 * @return true if new signature encountered (according to the mask)
345 */
346 public boolean add(final Tuple tuple) {
347 throw new UnsupportedOperationException("This is only supported by timeless memory implementations!");
348 }
349
350 /**
351 * Adds a tuple occurrence to the memory with the given timestamp.
352 *
353 * @param tuple
354 * the tuple to be added to the memory
355 * @param timestamp
356 * the timestamp associated with the tuple
357 *
358 * @return A {@link Diff} describing how the timeline of the given tuple changed.
359 *
360 * @since 2.4
361 */
362 public Diff<Timestamp> addWithTimestamp(final Tuple tuple, final Timestamp timestamp) {
363 throw new UnsupportedOperationException("This is only supported by timely memory implementations!");
364 }
365
366 protected MaskedTupleMemory(final TupleMask mask, final Object owner) {
367 super();
368 this.mask = mask;
369 this.owner = owner;
370 }
371
372 protected IllegalStateException raiseDuplicateInsertion(final Tuple tuple) {
373 return new IllegalStateException(String.format("Duplicate insertion of tuple %s into %s", tuple, owner));
374 }
375
376 protected IllegalStateException raiseDuplicateDeletion(final Tuple tuple) {
377 return new IllegalStateException(String.format("Duplicate deletion of tuple %s from %s", tuple, owner));
378 }
379
380 @Override
381 public String toString() {
382 return getClass().getSimpleName() + "<" + mask + ">@" + owner;
383 }
384
385} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/NullaryMaskedTupleMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/NullaryMaskedTupleMemory.java
new file mode 100644
index 00000000..7fa9e053
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/NullaryMaskedTupleMemory.java
@@ -0,0 +1,85 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.Set;
14
15import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
16import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
17import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
19import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
20
21/**
22 * Specialized for nullary mask; tuples are stored as a simple set/multiset memory.
23 *
24 * @author Gabor Bergmann
25 * @since 2.0
26 */
27public final class NullaryMaskedTupleMemory<Timestamp extends Comparable<Timestamp>> extends AbstractTrivialMaskedMemory<Timestamp> {
28
29 protected static final Set<Tuple> UNIT_RELATION =
30 Collections.singleton(Tuples.staticArityFlatTupleOf());
31 protected static final Set<Tuple> EMPTY_RELATION =
32 Collections.emptySet();
33 /**
34 * @param mask
35 * The mask used to index the matchings
36 * @param owner the object "owning" this memory
37 * @param bucketType the kind of tuple collection maintained for each indexer bucket
38 * @since 2.0
39 */
40 public NullaryMaskedTupleMemory(TupleMask mask, MemoryType bucketType, Object owner) {
41 super(mask, bucketType, owner);
42 if (0 != mask.getSize()) throw new IllegalArgumentException(mask.toString());
43 }
44
45 @Override
46 public int getKeysetSize() {
47 return tuples.isEmpty() ? 0 : 1;
48 }
49
50 @Override
51 public Iterable<Tuple> getSignatures() {
52 return tuples.isEmpty() ? EMPTY_RELATION : UNIT_RELATION;
53 }
54
55 @Override
56 public Collection<Tuple> get(ITuple signature) {
57 if (0 == signature.getSize())
58 return tuples.distinctValues();
59 else return null;
60 }
61
62 @Override
63 public boolean remove(Tuple tuple, Tuple signature) {
64 tuples.removeOne(tuple);
65 return tuples.isEmpty();
66 }
67
68 @Override
69 public boolean remove(Tuple tuple) {
70 return remove(tuple, null);
71 }
72
73 @Override
74 public boolean add(Tuple tuple, Tuple signature) {
75 boolean wasEmpty = tuples.isEmpty();
76 tuples.addOne(tuple);
77 return wasEmpty;
78 }
79
80 @Override
81 public boolean add(Tuple tuple) {
82 return add(tuple, null);
83 }
84
85}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/UnaryMaskedTupleMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/UnaryMaskedTupleMemory.java
new file mode 100644
index 00000000..f34cc9e3
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/UnaryMaskedTupleMemory.java
@@ -0,0 +1,143 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories;
10
11import java.util.Collection;
12import java.util.Iterator;
13import java.util.Map;
14
15import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
16import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
17import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
19import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
20import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
21import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
22import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
23import tools.refinery.viatra.runtime.matchers.util.IMultiLookup.ChangeGranularity;
24import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
25
26/**
27 * Specialized for unary mask; tuples are indexed by a single column as opposed to a projection (signature) tuple.
28 *
29 * @author Gabor Bergmann
30 * @since 2.0
31 */
32public final class UnaryMaskedTupleMemory<Timestamp extends Comparable<Timestamp>> extends MaskedTupleMemory<Timestamp> {
33
34 protected IMultiLookup<Object, Tuple> columnToTuples;
35 protected final int keyPosition;
36
37 /**
38 * @param mask
39 * The mask used to index the matchings
40 * @param owner the object "owning" this memory
41 * @param bucketType the kind of tuple collection maintained for each indexer bucket
42 * @since 2.0
43 */
44 public UnaryMaskedTupleMemory(TupleMask mask, MemoryType bucketType, Object owner) {
45 super(mask, owner);
46 if (1 != mask.getSize()) throw new IllegalArgumentException(mask.toString());
47
48 columnToTuples = CollectionsFactory.<Object, Tuple>createMultiLookup(
49 Object.class, bucketType, Object.class);
50 keyPosition = mask.indices[0];
51 }
52
53 @Override
54 public void clear() {
55 columnToTuples.clear();
56 }
57
58 @Override
59 public int getKeysetSize() {
60 return columnToTuples.countKeys();
61 }
62
63 @Override
64 public int getTotalSize() {
65 int i = 0;
66 for (Object key : columnToTuples.distinctKeys()) {
67 i += columnToTuples.lookup(key).size();
68 }
69 return i;
70 }
71
72 @Override
73 public Iterator<Tuple> iterator() {
74 return columnToTuples.distinctValues().iterator();
75 }
76
77 @Override
78 public Iterable<Tuple> getSignatures() {
79 return () -> {
80 Iterator<Object> wrapped = columnToTuples.distinctKeys().iterator();
81 return new Iterator<Tuple>() {
82 @Override
83 public boolean hasNext() {
84 return wrapped.hasNext();
85 }
86 @Override
87 public Tuple next() {
88 Object key = wrapped.next();
89 return Tuples.staticArityFlatTupleOf(key);
90 }
91 };
92 };
93 }
94
95 @Override
96 public Collection<Tuple> get(ITuple signature) {
97 Object key = signature.get(0);
98 IMemoryView<Tuple> bucket = columnToTuples.lookup(key);
99 return bucket == null ? null : bucket.distinctValues();
100 }
101
102 @Override
103 public Map<Tuple, Timeline<Timestamp>> getWithTimeline(ITuple signature) {
104 throw new UnsupportedOperationException("Timeless memories do not support timestamp-based lookup!");
105 }
106
107 @Override
108 public boolean remove(Tuple tuple, Tuple signature) {
109 return removeInternal(tuple, tuple.get(keyPosition));
110 }
111
112 @Override
113 public boolean remove(Tuple tuple) {
114 return removeInternal(tuple, tuple.get(keyPosition));
115 }
116
117 @Override
118 public boolean add(Tuple tuple, Tuple signature) {
119 return addInternal(tuple, tuple.get(keyPosition));
120 }
121
122 @Override
123 public boolean add(Tuple tuple) {
124 return addInternal(tuple, tuple.get(keyPosition));
125 }
126
127 protected boolean addInternal(Tuple tuple, Object key) {
128 try {
129 return columnToTuples.addPair(key, tuple) == ChangeGranularity.KEY;
130 } catch (IllegalStateException ex) { // ignore worthless internal exception details
131 throw raiseDuplicateInsertion(tuple);
132 }
133 }
134
135 protected boolean removeInternal(Tuple tuple, Object key) {
136 try {
137 return columnToTuples.removePair(key, tuple) == ChangeGranularity.KEY;
138 } catch (IllegalStateException ex) { // ignore worthless internal exception details
139 throw raiseDuplicateDeletion(tuple);
140 }
141 }
142
143}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyMaskedMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyMaskedMemory.java
new file mode 100644
index 00000000..45ce3a4e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyMaskedMemory.java
@@ -0,0 +1,228 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories.timely;
10
11import java.util.Collection;
12import java.util.Iterator;
13import java.util.Map;
14import java.util.Map.Entry;
15import java.util.Objects;
16import java.util.Set;
17import java.util.TreeMap;
18
19import tools.refinery.viatra.runtime.matchers.memories.MaskedTupleMemory;
20import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
21import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
22import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
23import tools.refinery.viatra.runtime.matchers.util.Direction;
24import tools.refinery.viatra.runtime.matchers.util.Signed;
25import tools.refinery.viatra.runtime.matchers.util.TimelyMemory;
26import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
27import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
28
29/**
30 * Common parts of timely default and timely unary implementations.
31 *
32 * @noextend This class is not intended to be subclassed by clients.
33 * @author Tamas Szabo
34 * @since 2.3
35 */
36abstract class AbstractTimelyMaskedMemory<Timestamp extends Comparable<Timestamp>, KeyType>
37 extends MaskedTupleMemory<Timestamp> {
38
39 protected final TreeMap<Timestamp, Set<KeyType>> foldingStates;
40 protected final Map<KeyType, TimelyMemory<Timestamp>> memoryMap;
41 protected final boolean isLazy;
42
43 public AbstractTimelyMaskedMemory(final TupleMask mask, final Object owner, final boolean isLazy) {
44 super(mask, owner);
45 this.isLazy = isLazy;
46 this.memoryMap = CollectionsFactory.createMap();
47 this.foldingStates = this.isLazy ? CollectionsFactory.createTreeMap() : null;
48 }
49
50 @Override
51 public void initializeWith(final MaskedTupleMemory<Timestamp> other, final Timestamp defaultValue) {
52 final Iterable<Tuple> signatures = other.getSignatures();
53 for (final Tuple signature : signatures) {
54 if (other.isTimely()) {
55 final Map<Tuple, Timeline<Timestamp>> tupleMap = other.getWithTimeline(signature);
56 for (final Entry<Tuple, Timeline<Timestamp>> entry : tupleMap.entrySet()) {
57 for (final Signed<Timestamp> signed : entry.getValue().asChangeSequence()) {
58 if (signed.getDirection() == Direction.DELETE) {
59 this.removeWithTimestamp(entry.getKey(), signed.getPayload());
60 } else {
61 this.addWithTimestamp(entry.getKey(), signed.getPayload());
62 }
63 }
64 }
65 } else {
66 final Collection<Tuple> tuples = other.get(signature);
67 for (final Tuple tuple : tuples) {
68 this.addWithTimestamp(tuple, defaultValue);
69 }
70 }
71 }
72 }
73
74 public boolean isPresentAtInfinityInteral(KeyType key) {
75 final TimelyMemory<Timestamp> values = this.memoryMap.get(key);
76 if (values == null) {
77 return false;
78 } else {
79 return values.getCountAtInfinity() != 0;
80 }
81 }
82
83 @Override
84 public void clear() {
85 this.memoryMap.clear();
86 }
87
88 @Override
89 public int getKeysetSize() {
90 return this.memoryMap.keySet().size();
91 }
92
93 @Override
94 public int getTotalSize() {
95 int i = 0;
96 for (final Entry<KeyType, TimelyMemory<Timestamp>> entry : this.memoryMap.entrySet()) {
97 i += entry.getValue().size();
98 }
99 return i;
100 }
101
102 @Override
103 public Iterator<Tuple> iterator() {
104 return this.memoryMap.values().stream().flatMap(e -> e.keySet().stream()).iterator();
105 }
106
107 protected Collection<Tuple> getInternal(final KeyType key) {
108 final TimelyMemory<Timestamp> memory = this.memoryMap.get(key);
109 if (memory == null) {
110 return null;
111 } else {
112 return memory.getTuplesAtInfinity();
113 }
114 }
115
116 public Map<Tuple, Timeline<Timestamp>> getWithTimestampInternal(final KeyType key) {
117 final TimelyMemory<Timestamp> memory = this.memoryMap.get(key);
118 if (memory == null) {
119 return null;
120 } else {
121 return memory.asMap();
122 }
123 }
124
125 protected Diff<Timestamp> removeInternal(final KeyType key, final Tuple tuple, final Timestamp timestamp) {
126 Timestamp oldResumableTimestamp = null;
127 Timestamp newResumableTimestamp = null;
128
129 final TimelyMemory<Timestamp> keyMemory = this.memoryMap.get(key);
130 if (keyMemory == null) {
131 throw raiseDuplicateDeletion(tuple);
132 }
133
134 if (this.isLazy) {
135 oldResumableTimestamp = keyMemory.getResumableTimestamp();
136 }
137
138 Diff<Timestamp> diff = null;
139 try {
140 diff = keyMemory.remove(tuple, timestamp);
141 } catch (final IllegalStateException e) {
142 throw raiseDuplicateDeletion(tuple);
143 }
144 if (keyMemory.isEmpty()) {
145 this.memoryMap.remove(key);
146 }
147
148 if (this.isLazy) {
149 newResumableTimestamp = keyMemory.getResumableTimestamp();
150 if (!Objects.equals(oldResumableTimestamp, newResumableTimestamp)) {
151 unregisterFoldingState(oldResumableTimestamp, key);
152 registerFoldingState(newResumableTimestamp, key);
153 }
154 }
155
156 return diff;
157 }
158
159 protected Diff<Timestamp> addInternal(final KeyType key, final Tuple tuple, final Timestamp timestamp) {
160 Timestamp oldResumableTimestamp = null;
161 Timestamp newResumableTimestamp = null;
162
163 final TimelyMemory<Timestamp> keyMemory = this.memoryMap.computeIfAbsent(key,
164 k -> new TimelyMemory<Timestamp>(this.isLazy));
165
166 if (this.isLazy) {
167 oldResumableTimestamp = keyMemory.getResumableTimestamp();
168 }
169
170 final Diff<Timestamp> diff = keyMemory.put(tuple, timestamp);
171
172 if (this.isLazy) {
173 newResumableTimestamp = keyMemory.getResumableTimestamp();
174 if (!Objects.equals(oldResumableTimestamp, newResumableTimestamp)) {
175 unregisterFoldingState(oldResumableTimestamp, key);
176 registerFoldingState(newResumableTimestamp, key);
177 }
178 }
179
180 return diff;
181 }
182
183 @Override
184 public Diff<Timestamp> removeWithTimestamp(final Tuple tuple, final Timestamp timestamp) {
185 return removeWithTimestamp(tuple, null, timestamp);
186 }
187
188 @Override
189 public Diff<Timestamp> addWithTimestamp(final Tuple tuple, final Timestamp timestamp) {
190 return addWithTimestamp(tuple, null, timestamp);
191 }
192
193 @Override
194 public boolean isTimely() {
195 return true;
196 }
197
198 protected void registerFoldingState(final Timestamp timestamp, final KeyType key) {
199 if (timestamp != null) {
200 this.foldingStates.compute(timestamp, (k, v) -> {
201 if (v == null) {
202 v = CollectionsFactory.createSet();
203 }
204 v.add(key);
205 return v;
206 });
207 }
208 }
209
210 protected void unregisterFoldingState(final Timestamp timestamp, final KeyType key) {
211 if (timestamp != null) {
212 this.foldingStates.compute(timestamp, (k, v) -> {
213 v.remove(key);
214 return v.isEmpty() ? null : v;
215 });
216 }
217 }
218
219 @Override
220 public Timestamp getResumableTimestamp() {
221 if (this.foldingStates == null || this.foldingStates.isEmpty()) {
222 return null;
223 } else {
224 return this.foldingStates.firstKey();
225 }
226 }
227
228}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyTrivialMaskedMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyTrivialMaskedMemory.java
new file mode 100644
index 00000000..ca06685a
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/AbstractTimelyTrivialMaskedMemory.java
@@ -0,0 +1,100 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories.timely;
10
11import java.util.Collection;
12import java.util.Iterator;
13import java.util.Map;
14import java.util.Map.Entry;
15
16import tools.refinery.viatra.runtime.matchers.memories.MaskedTupleMemory;
17import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
18import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
19import tools.refinery.viatra.runtime.matchers.util.Direction;
20import tools.refinery.viatra.runtime.matchers.util.Signed;
21import tools.refinery.viatra.runtime.matchers.util.TimelyMemory;
22import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
23import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
24
25/**
26 * Common parts of timely nullary and timely identity implementations.
27 *
28 * @noextend This class is not intended to be subclassed by clients.
29 * @author Tamas Szabo
30 * @since 2.3
31 */
32abstract class AbstractTimelyTrivialMaskedMemory<Timestamp extends Comparable<Timestamp>> extends MaskedTupleMemory<Timestamp> {
33
34 protected final TimelyMemory<Timestamp> memory;
35
36 protected AbstractTimelyTrivialMaskedMemory(final TupleMask mask, final Object owner, final boolean isLazy) {
37 super(mask, owner);
38 this.memory = new TimelyMemory<Timestamp>(isLazy);
39 }
40
41 @Override
42 public void initializeWith(final MaskedTupleMemory<Timestamp> other, final Timestamp defaultValue) {
43 final Iterable<Tuple> signatures = other.getSignatures();
44 for (final Tuple signature : signatures) {
45 if (other.isTimely()) {
46 final Map<Tuple, Timeline<Timestamp>> tupleMap = other.getWithTimeline(signature);
47 for (final Entry<Tuple, Timeline<Timestamp>> entry : tupleMap.entrySet()) {
48 for (final Signed<Timestamp> signed : entry.getValue().asChangeSequence()) {
49 if (signed.getDirection() == Direction.DELETE) {
50 this.removeWithTimestamp(entry.getKey(), signed.getPayload());
51 } else {
52 this.addWithTimestamp(entry.getKey(), signed.getPayload());
53 }
54 }
55 }
56 } else {
57 final Collection<Tuple> tuples = other.get(signature);
58 for (final Tuple tuple : tuples) {
59 this.removeWithTimestamp(tuple, defaultValue);
60 }
61 }
62 }
63 }
64
65 @Override
66 public void clear() {
67 this.memory.clear();
68 }
69
70 @Override
71 public int getTotalSize() {
72 return this.memory.size();
73 }
74
75 @Override
76 public Iterator<Tuple> iterator() {
77 return this.memory.keySet().iterator();
78 }
79
80 @Override
81 public Diff<Timestamp> removeWithTimestamp(final Tuple tuple, final Timestamp timestamp) {
82 return removeWithTimestamp(tuple, null, timestamp);
83 }
84
85 @Override
86 public Diff<Timestamp> addWithTimestamp(final Tuple tuple, final Timestamp timestamp) {
87 return addWithTimestamp(tuple, null, timestamp);
88 }
89
90 @Override
91 public boolean isTimely() {
92 return true;
93 }
94
95 @Override
96 public Timestamp getResumableTimestamp() {
97 return this.memory.getResumableTimestamp();
98 }
99
100}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyDefaultMaskedTupleMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyDefaultMaskedTupleMemory.java
new file mode 100644
index 00000000..623d7399
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyDefaultMaskedTupleMemory.java
@@ -0,0 +1,98 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.memories.timely;
11
12import java.util.Collection;
13import java.util.Collections;
14import java.util.Map;
15import java.util.Set;
16
17import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
19import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
20import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
21import tools.refinery.viatra.runtime.matchers.util.TimelyMemory;
22import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
23import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
24
25/**
26 * Default timely implementation that covers all cases.
27 *
28 * @author Tamas Szabo
29 * @since 2.3
30 */
31public final class TimelyDefaultMaskedTupleMemory<Timestamp extends Comparable<Timestamp>>
32 extends AbstractTimelyMaskedMemory<Timestamp, Tuple> {
33
34 public TimelyDefaultMaskedTupleMemory(final TupleMask mask, final Object owner, final boolean isLazy) {
35 super(mask, owner, isLazy);
36 }
37
38 @Override
39 public Iterable<Tuple> getSignatures() {
40 return this.memoryMap.keySet();
41 }
42
43 @Override
44 public Diff<Timestamp> removeWithTimestamp(final Tuple tuple, final Tuple signature,
45 final Timestamp timestamp) {
46 final Tuple key = mask.transform(tuple);
47 return removeInternal(key, tuple, timestamp);
48 }
49
50 @Override
51 public Diff<Timestamp> addWithTimestamp(final Tuple tuple, final Tuple signature,
52 final Timestamp timestamp) {
53 final Tuple key = this.mask.transform(tuple);
54 return addInternal(key, tuple, timestamp);
55 }
56
57 @Override
58 public Collection<Tuple> get(final ITuple signature) {
59 return getInternal(signature.toImmutable());
60 }
61
62 @Override
63 public Map<Tuple, Timeline<Timestamp>> getWithTimeline(final ITuple signature) {
64 return getWithTimestampInternal(signature.toImmutable());
65 }
66
67 @Override
68 public boolean isPresentAtInfinity(final ITuple signature) {
69 return isPresentAtInfinityInteral(signature.toImmutable());
70 }
71
72 @Override
73 public Set<Tuple> getResumableSignatures() {
74 if (this.foldingStates == null || this.foldingStates.isEmpty()) {
75 return Collections.emptySet();
76 } else {
77 return this.foldingStates.firstEntry().getValue();
78 }
79 }
80
81 @Override
82 public Map<Tuple, Map<Tuple, Diff<Timestamp>>> resumeAt(final Timestamp timestamp) {
83 final Map<Tuple, Map<Tuple, Diff<Timestamp>>> result = CollectionsFactory.createMap();
84 final Timestamp resumableTimestamp = this.getResumableTimestamp();
85 if (resumableTimestamp == null || resumableTimestamp.compareTo(timestamp) != 0) {
86 throw new IllegalStateException("Expected to continue folding at " + resumableTimestamp + "!");
87 }
88 final Set<Tuple> signatures = this.foldingStates.remove(timestamp);
89 for (final Tuple signature : signatures) {
90 final TimelyMemory<Timestamp> memory = this.memoryMap.get(signature);
91 final Map<Tuple, Diff<Timestamp>> diffMap = memory.resumeAt(resumableTimestamp);
92 result.put(signature, diffMap);
93 registerFoldingState(memory.getResumableTimestamp(), signature);
94 }
95 return result;
96 }
97
98}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyIdentityMaskedTupleMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyIdentityMaskedTupleMemory.java
new file mode 100644
index 00000000..568f274d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyIdentityMaskedTupleMemory.java
@@ -0,0 +1,106 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories.timely;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.Map;
14import java.util.Map.Entry;
15import java.util.Set;
16
17import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
19import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
20import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
21import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
22import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
23
24/**
25 * Timely specialization for identity mask.
26 *
27 * @author Tamas Szabo
28 * @since 2.3
29 */
30public final class TimelyIdentityMaskedTupleMemory<Timestamp extends Comparable<Timestamp>>
31 extends AbstractTimelyTrivialMaskedMemory<Timestamp> {
32
33 public TimelyIdentityMaskedTupleMemory(final TupleMask mask, final Object owner, final boolean isLazy) {
34 super(mask, owner, isLazy);
35 if (!mask.isIdentity())
36 throw new IllegalArgumentException(mask.toString());
37 }
38
39 @Override
40 public int getKeysetSize() {
41 return this.memory.size();
42 }
43
44 @Override
45 public Iterable<Tuple> getSignatures() {
46 return this.memory.keySet();
47 }
48
49 @Override
50 public Collection<Tuple> get(final ITuple signature) {
51 if (this.memory.getTuplesAtInfinity().contains(signature)) {
52 return Collections.singleton(signature.toImmutable());
53 } else {
54 return null;
55 }
56 }
57
58 @Override
59 public Map<Tuple, Timeline<Timestamp>> getWithTimeline(final ITuple signature) {
60 final Timeline<Timestamp> value = this.memory.get(signature);
61 if (value != null) {
62 return Collections.singletonMap(signature.toImmutable(), value);
63 } else {
64 return null;
65 }
66 }
67
68 @Override
69 public Diff<Timestamp> removeWithTimestamp(final Tuple tuple, final Tuple signature, final Timestamp timestamp) {
70 try {
71 return this.memory.remove(tuple, timestamp);
72 } catch (final IllegalStateException e) {
73 throw raiseDuplicateDeletion(tuple);
74 }
75 }
76
77 @Override
78 public Diff<Timestamp> addWithTimestamp(final Tuple tuple, final Tuple signature, final Timestamp timestamp) {
79 return this.memory.put(tuple, timestamp);
80 }
81
82 @Override
83 public boolean isPresentAtInfinity(final ITuple signature) {
84 return this.memory.isPresentAtInfinity(signature.toImmutable());
85 }
86
87 @Override
88 public Set<Tuple> getResumableSignatures() {
89 if (this.memory.getResumableTimestamp() != null) {
90 return this.memory.getResumableTuples();
91 } else {
92 return Collections.emptySet();
93 }
94 }
95
96 @Override
97 public Map<Tuple, Map<Tuple, Diff<Timestamp>>> resumeAt(final Timestamp timestamp) {
98 final Map<Tuple, Diff<Timestamp>> diffMap = this.memory.resumeAt(timestamp);
99 final Map<Tuple, Map<Tuple, Diff<Timestamp>>> result = CollectionsFactory.createMap();
100 for (final Entry<Tuple, Diff<Timestamp>> entry : diffMap.entrySet()) {
101 result.put(entry.getKey(), Collections.singletonMap(entry.getKey(), entry.getValue()));
102 }
103 return result;
104 }
105
106}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyNullaryMaskedTupleMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyNullaryMaskedTupleMemory.java
new file mode 100644
index 00000000..75987a89
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyNullaryMaskedTupleMemory.java
@@ -0,0 +1,108 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories.timely;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.Map;
14import java.util.Set;
15
16import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
17import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
18import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
19import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
20import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
21import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
22
23/**
24 * Timely specialization for nullary mask.
25 *
26 * @author Tamas Szabo
27 * @since 2.3
28 */
29public final class TimelyNullaryMaskedTupleMemory<Timestamp extends Comparable<Timestamp>>
30 extends AbstractTimelyTrivialMaskedMemory<Timestamp> {
31
32 protected static final Tuple EMPTY_TUPLE = Tuples.staticArityFlatTupleOf();
33 protected static final Set<Tuple> UNIT_RELATION = Collections.singleton(EMPTY_TUPLE);
34 protected static final Set<Tuple> EMPTY_RELATION = Collections.emptySet();
35
36 public TimelyNullaryMaskedTupleMemory(final TupleMask mask, final Object owner, final boolean isLazy) {
37 super(mask, owner, isLazy);
38 if (0 != mask.getSize()) {
39 throw new IllegalArgumentException(mask.toString());
40 }
41 }
42
43 @Override
44 public int getKeysetSize() {
45 return this.memory.isEmpty() ? 0 : 1;
46 }
47
48 @Override
49 public Iterable<Tuple> getSignatures() {
50 return this.memory.isEmpty() ? EMPTY_RELATION : UNIT_RELATION;
51 }
52
53 @Override
54 public Collection<Tuple> get(final ITuple signature) {
55 if (0 == signature.getSize()) {
56 return this.memory.getTuplesAtInfinity();
57 } else {
58 return null;
59 }
60 }
61
62 @Override
63 public Map<Tuple, Timeline<Timestamp>> getWithTimeline(final ITuple signature) {
64 if (0 == signature.getSize()) {
65 return this.memory.asMap();
66 } else {
67 return null;
68 }
69 }
70
71 @Override
72 public Diff<Timestamp> removeWithTimestamp(final Tuple tuple, final Tuple signature, final Timestamp timestamp) {
73 try {
74 return this.memory.remove(tuple, timestamp);
75 } catch (final IllegalStateException e) {
76 throw raiseDuplicateDeletion(tuple);
77 }
78 }
79
80 @Override
81 public Diff<Timestamp> addWithTimestamp(final Tuple tuple, final Tuple signature, final Timestamp timestamp) {
82 return this.memory.put(tuple, timestamp);
83 }
84
85 @Override
86 public boolean isPresentAtInfinity(final ITuple signature) {
87 if (0 == signature.getSize()) {
88 return this.memory.getCountAtInfinity() > 0;
89 } else {
90 return false;
91 }
92 }
93
94 @Override
95 public Set<Tuple> getResumableSignatures() {
96 if (this.memory.getResumableTimestamp() != null) {
97 return UNIT_RELATION;
98 } else {
99 return EMPTY_RELATION;
100 }
101 }
102
103 @Override
104 public Map<Tuple, Map<Tuple, Diff<Timestamp>>> resumeAt(final Timestamp timestamp) {
105 return Collections.singletonMap(EMPTY_TUPLE, this.memory.resumeAt(timestamp));
106 }
107
108}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyUnaryMaskedTupleMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyUnaryMaskedTupleMemory.java
new file mode 100644
index 00000000..178193af
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/memories/timely/TimelyUnaryMaskedTupleMemory.java
@@ -0,0 +1,133 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.memories.timely;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.Iterator;
14import java.util.Map;
15import java.util.Set;
16
17import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
19import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
20import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
21import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
22import tools.refinery.viatra.runtime.matchers.util.TimelyMemory;
23import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
24import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
25
26/**
27 * Timely specialization for unary mask.
28 *
29 * @author Tamas Szabo
30 * @since 2.3
31 */
32public final class TimelyUnaryMaskedTupleMemory<Timestamp extends Comparable<Timestamp>>
33 extends AbstractTimelyMaskedMemory<Timestamp, Object> {
34
35 protected final int keyPosition;
36
37 public TimelyUnaryMaskedTupleMemory(final TupleMask mask, final Object owner, final boolean isLazy) {
38 super(mask, owner, isLazy);
39 if (1 != mask.getSize())
40 throw new IllegalArgumentException(mask.toString());
41 this.keyPosition = mask.indices[0];
42 }
43
44 @Override
45 public Iterable<Tuple> getSignatures() {
46 return () -> {
47 final Iterator<Object> wrapped = this.memoryMap.keySet().iterator();
48 return new Iterator<Tuple>() {
49 @Override
50 public boolean hasNext() {
51 return wrapped.hasNext();
52 }
53
54 @Override
55 public Tuple next() {
56 final Object key = wrapped.next();
57 return Tuples.staticArityFlatTupleOf(key);
58 }
59 };
60 };
61 }
62
63 @Override
64 public Diff<Timestamp> removeWithTimestamp(final Tuple tuple, final Tuple signature, final Timestamp timestamp) {
65 final Object key = tuple.get(keyPosition);
66 return removeInternal(key, tuple, timestamp);
67 }
68
69 @Override
70 public Diff<Timestamp> addWithTimestamp(final Tuple tuple, final Tuple signature, final Timestamp timestamp) {
71 final Object key = tuple.get(keyPosition);
72 return addInternal(key, tuple, timestamp);
73 }
74
75 @Override
76 public Collection<Tuple> get(final ITuple signature) {
77 return getInternal(signature.get(0));
78 }
79
80 @Override
81 public Map<Tuple, Timeline<Timestamp>> getWithTimeline(final ITuple signature) {
82 return getWithTimestampInternal(signature.get(0));
83 }
84
85 @Override
86 public boolean isPresentAtInfinity(ITuple signature) {
87 return isPresentAtInfinityInteral(signature.get(0));
88 }
89
90 @Override
91 public Iterable<Tuple> getResumableSignatures() {
92 if (this.foldingStates == null || this.foldingStates.isEmpty()) {
93 return Collections.emptySet();
94 } else {
95 return () -> {
96 final Iterator<Object> wrapped = this.foldingStates.firstEntry().getValue().iterator();
97 return new Iterator<Tuple>() {
98 @Override
99 public boolean hasNext() {
100 return wrapped.hasNext();
101 }
102
103 @Override
104 public Tuple next() {
105 final Object key = wrapped.next();
106 return Tuples.staticArityFlatTupleOf(key);
107 }
108 };
109 };
110 }
111 }
112
113 @Override
114 public Map<Tuple, Map<Tuple, Diff<Timestamp>>> resumeAt(final Timestamp timestamp) {
115 final Map<Tuple, Map<Tuple, Diff<Timestamp>>> result = CollectionsFactory.createMap();
116 final Timestamp resumableTimestamp = this.getResumableTimestamp();
117 if (resumableTimestamp == null) {
118 throw new IllegalStateException("There is nothing to fold!");
119 } else if (resumableTimestamp.compareTo(timestamp) != 0) {
120 throw new IllegalStateException("Expected to continue folding at " + resumableTimestamp + "!");
121 }
122
123 final Set<Object> signatures = this.foldingStates.remove(timestamp);
124 for (final Object signature : signatures) {
125 final TimelyMemory<Timestamp> memory = this.memoryMap.get(signature);
126 final Map<Tuple, Diff<Timestamp>> diffMap = memory.resumeAt(resumableTimestamp);
127 result.put(Tuples.staticArityFlatTupleOf(signature), diffMap);
128 registerFoldingState(memory.getResumableTimestamp(), signature);
129 }
130 return result;
131 }
132
133}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IOperationCompiler.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IOperationCompiler.java
new file mode 100644
index 00000000..c9f4b305
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IOperationCompiler.java
@@ -0,0 +1,108 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.planning;
11
12import java.util.Map;
13
14import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
15import tools.refinery.viatra.runtime.matchers.psystem.IExpressionEvaluator;
16import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
17import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
18import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
19
20/**
21 *
22 * An implicit common parameter is the "effort" PatternDescription. This
23 * indicates that the build request is part of an effort to build the matcher of
24 * the given pattern; it it important to record this during code generation so
25 * that the generated code can be separated according to patterns.
26 *
27 * @param <Collector>
28 * the handle of a receiver-like RETE ending to which plans can be
29 * connected
30 * @author Gabor Bergmann
31 * @noimplement This interface is not intended to be implemented by clients.
32 */
33public interface IOperationCompiler<Collector> {
34
35 /**
36 * @throws ViatraQueryRuntimeException
37 */
38 public Collector patternCollector(PQuery pattern);
39
40 public void buildConnection(SubPlan parentPlan, Collector collector);
41
42 /**
43 * @since 0.9
44 */
45 public void patternFinished(PQuery pattern, Collector collector);
46
47 /**
48 * @throws ViatraQueryRuntimeException
49 */
50 public SubPlan patternCallPlan(Tuple nodes, PQuery supplierKey);
51
52 public SubPlan transitiveInstantiationPlan(Tuple nodes);
53
54 public SubPlan directInstantiationPlan(Tuple nodes);
55
56 public SubPlan transitiveGeneralizationPlan(Tuple nodes);
57
58 public SubPlan directGeneralizationPlan(Tuple nodes);
59
60 public SubPlan transitiveContainmentPlan(Tuple nodes);
61
62 public SubPlan directContainmentPlan(Tuple nodes);
63
64 public SubPlan binaryEdgeTypePlan(Tuple nodes, Object supplierKey);
65
66 public SubPlan ternaryEdgeTypePlan(Tuple nodes, Object supplierKey);
67
68 public SubPlan unaryTypePlan(Tuple nodes, Object supplierKey);
69
70 public SubPlan buildStartingPlan(Object[] constantValues, Object[] constantNames);
71
72 public SubPlan buildEqualityChecker(SubPlan parentPlan, int[] indices);
73
74 public SubPlan buildInjectivityChecker(SubPlan parentPlan, int subject, int[] inequalIndices);
75
76 public SubPlan buildTransitiveClosure(SubPlan parentPlan);
77
78 public SubPlan buildTrimmer(SubPlan parentPlan, TupleMask trimMask, boolean enforceUniqueness);
79
80 public SubPlan buildBetaNode(SubPlan primaryPlan, SubPlan sidePlan,
81 TupleMask primaryMask, TupleMask sideMask, TupleMask complementer, boolean negative);
82
83 public SubPlan buildCounterBetaNode(SubPlan primaryPlan, SubPlan sidePlan,
84 TupleMask primaryMask, TupleMask originalSideMask, TupleMask complementer,
85 Object aggregateResultCalibrationElement);
86
87 public SubPlan buildCountCheckBetaNode(SubPlan primaryPlan, SubPlan sidePlan,
88 TupleMask primaryMask, TupleMask originalSideMask, int resultPositionInSignature);
89
90 public SubPlan buildPredicateChecker(IExpressionEvaluator evaluator, Map<String, Integer> tupleNameMap,
91 SubPlan parentPlan);
92 public SubPlan buildFunctionEvaluator(IExpressionEvaluator evaluator, Map<String, Integer> tupleNameMap,
93 SubPlan parentPlan, Object computedResultCalibrationElement);
94
95 /**
96 * @return an operation compiler that potentially acts on a separate container
97 */
98 public IOperationCompiler<Collector> getNextContainer();
99
100 /**
101 * @return an operation compiler that puts build actions on the tab of the given pattern
102 * @since 0.9
103 */
104 public IOperationCompiler<Collector> putOnTab(PQuery effort /*, IPatternMatcherContext context*/);
105
106 public void reinitialize();
107
108} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IQueryPlannerStrategy.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IQueryPlannerStrategy.java
new file mode 100644
index 00000000..6ce9d91b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/IQueryPlannerStrategy.java
@@ -0,0 +1,29 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.planning;
11
12import org.apache.log4j.Logger;
13import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
14import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
15import tools.refinery.viatra.runtime.matchers.psystem.PBody;
16
17/**
18 * An algorithm that builds a query plan based on a PSystem representation of a body of constraints. This interface is
19 * for internal use of the various query backends.
20 *
21 * @author Gabor Bergmann
22 */
23public interface IQueryPlannerStrategy {
24
25 /**
26 * @throws ViatraQueryRuntimeException
27 */
28 public SubPlan plan(PBody pSystem, Logger logger, IQueryMetaContext context);
29}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/QueryProcessingException.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/QueryProcessingException.java
new file mode 100644
index 00000000..501ddf73
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/QueryProcessingException.java
@@ -0,0 +1,102 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning;
10
11import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
12
13/**
14 * @author Zoltan Ujhelyi
15 * @since 0.9
16 */
17public class QueryProcessingException extends ViatraQueryRuntimeException {
18
19 private static final long serialVersionUID = -8272290113656867086L;
20 /**
21 * Binding the '{n}' (n = 1..N) strings to contextual conditions in 'context'
22 *
23 * @param context
24 * : array of context-sensitive Strings
25 */
26 protected static String bind(String message, String[] context) {
27 if (context == null)
28 return message;
29
30 String internal = message;
31 for (int i = 0; i < context.length; i++) {
32 internal = internal.replace("{" + (i + 1) + "}", context[i] != null ? context[i] : "<<null>>");
33 }
34 return internal;
35 }
36
37 private Object patternDescription;
38 private String shortMessage;
39
40 /**
41 * @param message
42 * The template of the exception message
43 * @param context
44 * The data elements to be used to instantiate the template. Can be null if no context parameter is
45 * defined
46 * @param patternDescription
47 * the PatternDescription where the exception occurred
48 * @since 2.0
49 */
50 public QueryProcessingException(String message, Object patternDescription) {
51 super(message);
52 initializeFields(message, patternDescription);
53 }
54
55 /**
56 * @param message
57 * The template of the exception message
58 * @param context
59 * The data elements to be used to instantiate the template. Can be null if no context parameter is
60 * defined
61 * @param patternDescription
62 * the PatternDescription where the exception occurred
63 */
64 public QueryProcessingException(String message, String[] context, String shortMessage, Object patternDescription) {
65 super(bind(message, context));
66 initializeFields(shortMessage, patternDescription);
67 }
68
69 /**
70 * @param message
71 * The template of the exception message
72 * @param context
73 * The data elements to be used to instantiate the template. Can be null if no context parameter is
74 * defined
75 * @param patternDescription
76 * the PatternDescription where the exception occurred
77 */
78 public QueryProcessingException(String message, String[] context, String shortMessage, Object patternDescription,
79 Throwable cause) {
80 super(bind(message, context), cause);
81 initializeFields(shortMessage, patternDescription);
82 }
83
84 public Object getPatternDescription() {
85 return patternDescription;
86 }
87
88 public String getShortMessage() {
89 return shortMessage;
90 }
91
92 private void initializeFields(String shortMessage, Object patternDescription) {
93 this.patternDescription = patternDescription;
94 this.shortMessage = shortMessage;
95 }
96
97
98 public void setPatternDescription(Object patternDescription) {
99 this.patternDescription = patternDescription;
100 }
101
102} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlan.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlan.java
new file mode 100644
index 00000000..1998df9d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlan.java
@@ -0,0 +1,240 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.planning;
11
12import java.util.Arrays;
13import java.util.HashSet;
14import java.util.List;
15import java.util.Set;
16import java.util.WeakHashMap;
17import java.util.stream.Collectors;
18
19import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
20import tools.refinery.viatra.runtime.matchers.planning.helpers.TypeHelper;
21import tools.refinery.viatra.runtime.matchers.planning.operations.POperation;
22import tools.refinery.viatra.runtime.matchers.planning.operations.PProject;
23import tools.refinery.viatra.runtime.matchers.planning.operations.PStart;
24import tools.refinery.viatra.runtime.matchers.psystem.PBody;
25import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
26import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
27import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
28
29/**
30 * A plan representing a subset of (or possibly all the) constraints evaluated. A SubPlan instance is responsible for
31 * representing a state of the plan; but after it is initialized it is expected be immutable
32 * (exception: inferred constraints, see {@link #inferConstraint(PConstraint)}).
33 *
34 * <p> A SubPlan is constructed by applying a {@link POperation} on zero or more parent SubPlans.
35 * Important maintained information: <ul>
36 * <li>set of <b>variables</b> whose values are known when the runtime evaluation is at this stage,
37 * <li>set of <b>constraints</b> that are known to hold true at this point.
38 * </ul>
39 *
40 * <p> Recommended to instantiate via a {@link SubPlanFactory} or subclasses,
41 * so that query planners can subclass SubPlan if needed.
42 *
43 * @author Gabor Bergmann
44 *
45 */
46public class SubPlan {
47 private PBody body;
48 private List<? extends SubPlan> parentPlans;
49 private POperation operation;
50
51 private final Set<PVariable> visibleVariables;
52 private final Set<PVariable> allVariables;
53 private final Set<PVariable> introducedVariables; // delta compared to first parent
54 private Set<PConstraint> allConstraints;
55 private Set<PConstraint> deltaConstraints; // delta compared to all parents
56 private Set<PConstraint> externallyInferredConstraints; // inferred in addition to direct consequences of the operation and parents
57
58
59
60
61
62 /**
63 * A SubPlan is constructed by applying a {@link POperation} on zero or more parent SubPlans.
64 */
65 public SubPlan(PBody body, POperation operation, SubPlan... parentPlans) {
66 this(body, operation, Arrays.asList(parentPlans));
67 }
68 /**
69 * A SubPlan is constructed by applying a {@link POperation} on zero or more parent SubPlans.
70 */
71 public SubPlan(PBody body, POperation operation, List<? extends SubPlan> parentPlans) {
72 super();
73 this.body = body;
74 this.parentPlans = parentPlans;
75 this.operation = operation;
76
77 this.externallyInferredConstraints = new HashSet<PConstraint>();
78 this.deltaConstraints = new HashSet<PConstraint>(operation.getDeltaConstraints());
79
80 this.allVariables = new HashSet<PVariable>();
81 for (PConstraint constraint: deltaConstraints) {
82 this.allVariables.addAll(constraint.getDeducedVariables());
83 }
84 this.allConstraints = new HashSet<PConstraint>(deltaConstraints);
85 for (SubPlan parentPlan: parentPlans) {
86 this.allConstraints.addAll(parentPlan.getAllEnforcedConstraints());
87 this.allVariables.addAll(parentPlan.getAllDeducedVariables());
88 }
89
90 // TODO this is ugly a bit
91 if (operation instanceof PStart) {
92 this.visibleVariables = new HashSet<PVariable>(((PStart) operation).getAPrioriVariables());
93 this.allVariables.addAll(visibleVariables);
94 } else if (operation instanceof PProject) {
95 this.visibleVariables = new HashSet<PVariable>(((PProject) operation).getToVariables());
96 } else {
97 this.visibleVariables = new HashSet<PVariable>();
98 for (SubPlan parentPlan: parentPlans)
99 this.visibleVariables.addAll(parentPlan.getVisibleVariables());
100 for (PConstraint constraint: deltaConstraints)
101 this.visibleVariables.addAll(constraint.getDeducedVariables());
102 }
103
104 this.introducedVariables = new HashSet<PVariable>(this.visibleVariables);
105 if (!parentPlans.isEmpty())
106 introducedVariables.removeAll(parentPlans.get(0).getVisibleVariables());
107
108 operation.checkConsistency(this);
109 }
110
111
112 @Override
113 public String toString() {
114 return toLongString();
115 }
116 public String toShortString() {
117 return String.format("Plan{%s}:%s",
118 visibleVariables.stream().map(PVariable::getName).collect(Collectors.joining(",")),
119 operation.getShortName());
120 }
121 public String toLongString() {
122 return String.format("%s<%s>",
123 toShortString(),
124 parentPlans.stream().map(Object::toString).collect(Collectors.joining("; ")));
125 }
126
127
128 /**
129 * All constraints that are known to hold at this point
130 */
131 public Set<PConstraint> getAllEnforcedConstraints() {
132 return allConstraints;
133 }
134
135 /**
136 * The new constraints enforced at this stage of plan, that aren't yet enforced at parents
137 * (results are also included in {@link SubPlan#getAllEnforcedConstraints()})
138 */
139 public Set<PConstraint> getDeltaEnforcedConstraints() {
140 return deltaConstraints;
141 }
142
143 /**
144 * Indicate that a given constraint was found to be automatically satisfied at this point
145 * without additional operations.
146 * (results are also included in {@link SubPlan#getDeltaEnforcedConstraints()})
147 *
148 * <p>Warning: not propagated automatically to child plans,
149 * so best to invoke before constructing further SubPlans. </p>
150 */
151 public void inferConstraint(PConstraint constraint) {
152 externallyInferredConstraints.add(constraint);
153 deltaConstraints.add(constraint);
154 allConstraints.add(constraint);
155 }
156
157 public PBody getBody() {
158 return body;
159 }
160
161 /**
162 * Variables which are assigned a value at this point
163 * (results are also included in {@link SubPlan#getAllDeducedVariables()})
164 */
165 public Set<PVariable> getVisibleVariables() {
166 return visibleVariables;
167 }
168 /**
169 * Variables which have been assigned a value;
170 * includes visible variables (see {@link #getVisibleVariables()})
171 * and additionally any variables hidden by a projection (see {@link PProject}).
172 */
173 public Set<PVariable> getAllDeducedVariables() {
174 return allVariables;
175 }
176 /**
177 * Delta compared to first parent: variables that are visible here but were not visible at the first parent.
178 */
179 public Set<PVariable> getIntroducedVariables() {
180 return introducedVariables;
181 }
182 public List<? extends SubPlan> getParentPlans() {
183 return parentPlans;
184 }
185 public POperation getOperation() {
186 return operation;
187 }
188
189
190 /**
191 * The closure of all type judgments of enforced constraints at this point.
192 * <p> No subsumption applied.
193 */
194 public Set<TypeJudgement> getAllImpliedTypeJudgements(IQueryMetaContext context) {
195 Set<TypeJudgement> impliedJudgements = allImpliedTypeJudgements.get(context);
196 if (impliedJudgements == null) {
197 Set<TypeJudgement> equivalentJudgements = TypeHelper.getDirectJudgements(getAllEnforcedConstraints(), context);
198 impliedJudgements = TypeHelper.typeClosure(equivalentJudgements, context);
199
200 allImpliedTypeJudgements.put(context, impliedJudgements);
201 }
202 return impliedJudgements;
203 }
204 private WeakHashMap<IQueryMetaContext, Set<TypeJudgement>> allImpliedTypeJudgements = new WeakHashMap<IQueryMetaContext, Set<TypeJudgement>>();
205
206
207 @Override
208 public int hashCode() {
209 final int prime = 31;
210 int result = 1;
211 result = prime * result
212 + ((operation == null) ? 0 : operation.hashCode());
213 result = prime * result
214 + ((parentPlans == null) ? 0 : parentPlans.hashCode());
215 return result;
216 }
217 @Override
218 public boolean equals(Object obj) {
219 if (this == obj)
220 return true;
221 if (obj == null)
222 return false;
223 if (!(obj instanceof SubPlan))
224 return false;
225 SubPlan other = (SubPlan) obj;
226 if (operation == null) {
227 if (other.operation != null)
228 return false;
229 } else if (!operation.equals(other.operation))
230 return false;
231 if (parentPlans == null) {
232 if (other.parentPlans != null)
233 return false;
234 } else if (!parentPlans.equals(other.parentPlans))
235 return false;
236 return true;
237 }
238
239
240}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlanFactory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlanFactory.java
new file mode 100644
index 00000000..d0df5fac
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlanFactory.java
@@ -0,0 +1,33 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning;
10
11import tools.refinery.viatra.runtime.matchers.planning.operations.POperation;
12import tools.refinery.viatra.runtime.matchers.psystem.PBody;
13
14/**
15 * Single entry point for creating subplans.
16 * Can be subclassed by query planner to provide specialized SubPlans.
17 * @author Bergmann Gabor
18 *
19 */
20public class SubPlanFactory {
21
22 protected PBody body;
23
24 public SubPlanFactory(PBody body) {
25 super();
26 this.body = body;
27 }
28
29 public SubPlan createSubPlan(POperation operation, SubPlan... parentPlans) {
30 return new SubPlan(body, operation, parentPlans);
31 }
32
33}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/BuildHelper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/BuildHelper.java
new file mode 100644
index 00000000..ed5d1cbb
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/BuildHelper.java
@@ -0,0 +1,165 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.planning.helpers;
11
12import java.util.Collection;
13import java.util.HashSet;
14import java.util.Map;
15import java.util.Set;
16
17import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
18import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
19import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
20import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
21import tools.refinery.viatra.runtime.matchers.planning.SubPlanFactory;
22import tools.refinery.viatra.runtime.matchers.planning.operations.PProject;
23import tools.refinery.viatra.runtime.matchers.psystem.PBody;
24import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
25import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
26import tools.refinery.viatra.runtime.matchers.psystem.analysis.QueryAnalyzer;
27import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExportedParameter;
28
29/**
30 * @author Gabor Bergmann
31 *
32 */
33public class BuildHelper {
34
35 private BuildHelper() {
36 // Hiding constructor for utility class
37 }
38
39// public static SubPlan naturalJoin(IOperationCompiler buildable,
40// SubPlan primaryPlan, SubPlan secondaryPlan) {
41// JoinHelper joinHelper = new JoinHelper(primaryPlan, secondaryPlan);
42// return buildable.buildBetaNode(primaryPlan, secondaryPlan, joinHelper.getPrimaryMask(),
43// joinHelper.getSecondaryMask(), joinHelper.getComplementerMask(), false);
44// }
45
46
47 /**
48 * Reduces the number of tuples by trimming (existentially quantifying) the set of variables that <ul>
49 * <li> are visible in the subplan,
50 * <li> are not exported parameters,
51 * <li> have all their constraints already enforced in the subplan,
52 * </ul> and thus will not be needed anymore.
53 *
54 * @param onlyIfNotDetermined if true, no trimming performed unless there is at least one variable that is not functionally determined
55 * @return the plan after the trimming (possibly the original)
56 * @since 1.5
57 */
58 public static SubPlan trimUnneccessaryVariables(SubPlanFactory planFactory, /*IOperationCompiler buildable,*/
59 SubPlan plan, boolean onlyIfNotDetermined, QueryAnalyzer analyzer) {
60 Set<PVariable> canBeTrimmed = new HashSet<PVariable>();
61 Set<PVariable> variablesInPlan = plan.getVisibleVariables();
62 for (PVariable trimCandidate : variablesInPlan) {
63 if (trimCandidate.getReferringConstraintsOfType(ExportedParameter.class).isEmpty()) {
64 if (plan.getAllEnforcedConstraints().containsAll(trimCandidate.getReferringConstraints()))
65 canBeTrimmed.add(trimCandidate);
66 }
67 }
68 final Set<PVariable> retainedVars = setMinus(variablesInPlan, canBeTrimmed);
69 if (!canBeTrimmed.isEmpty() && !(onlyIfNotDetermined && areVariablesDetermined(plan, retainedVars, canBeTrimmed, analyzer, false))) {
70 // TODO add smart ordering?
71 plan = planFactory.createSubPlan(new PProject(retainedVars), plan);
72 }
73 return plan;
74 }
75
76 /**
77 * @return true iff a set of given variables functionally determine all visible variables in the subplan according to the subplan's constraints
78 * @param strict if true, only "hard" dependencies are taken into account that are strictly enforced by the model representation;
79 * if false, user-provided soft dependencies are included as well, that are anticipated but not guaranteed by the storage mechanism;
80 * use true if superfluous dependencies may taint the correctness of a computation, false if they would merely impact performance
81 * @since 1.5
82 */
83 public static boolean areAllVariablesDetermined(SubPlan plan, Collection<PVariable> determining, QueryAnalyzer analyzer, boolean strict) {
84 return areVariablesDetermined(plan, determining, plan.getVisibleVariables(), analyzer, strict);
85 }
86
87 /**
88 * @return true iff one set of given variables functionally determine the other set according to the subplan's constraints
89 * @param strict if true, only "hard" dependencies are taken into account that are strictly enforced by the model representation;
90 * if false, user-provided soft dependencies are included as well, that are anticipated but not guaranteed by the storage mechanism;
91 * use true if superfluous dependencies may taint the correctness of a computation, false if they would merely impact performance
92 * @since 1.5
93 */
94 public static boolean areVariablesDetermined(SubPlan plan, Collection<PVariable> determining, Collection<PVariable> determined,
95 QueryAnalyzer analyzer, boolean strict) {
96 Map<Set<PVariable>, Set<PVariable>> dependencies = analyzer.getFunctionalDependencies(plan.getAllEnforcedConstraints(), strict);
97 final Set<PVariable> closure = FunctionalDependencyHelper.closureOf(determining, dependencies);
98 final boolean isDetermined = closure.containsAll(determined);
99 return isDetermined;
100 }
101
102 private static <T> Set<T> setMinus(Set<T> a, Set<T> b) {
103 Set<T> difference = new HashSet<T>(a);
104 difference.removeAll(b);
105 return difference;
106 }
107
108 /**
109 * Finds an arbitrary constraint that is not enforced at the given plan.
110 *
111 * @param pSystem
112 * @param plan
113 * @return a PConstraint that is not enforced, if any, or null if all are enforced
114 */
115 public static PConstraint getAnyUnenforcedConstraint(PBody pSystem,
116 SubPlan plan) {
117 Set<PConstraint> allEnforcedConstraints = plan.getAllEnforcedConstraints();
118 Set<PConstraint> constraints = pSystem.getConstraints();
119 for (PConstraint pConstraint : constraints) {
120 if (!allEnforcedConstraints.contains(pConstraint))
121 return pConstraint;
122 }
123 return null;
124 }
125
126 /**
127 * Skips the last few steps, if any, that are projections, so that a custom projection can be added instead.
128 * Useful for connecting body final plans into the production node.
129 *
130 * @since 2.1
131 */
132 public static SubPlan eliminateTrailingProjections(SubPlan plan) {
133 while (plan.getOperation() instanceof PProject)
134 plan = plan.getParentPlans().get(0);
135 return plan;
136 }
137
138 /**
139 * Verifies whether all constraints are enforced and exported parameters are present.
140 *
141 * @param pSystem
142 * @param plan
143 * @throws ViatraQueryRuntimeException
144 */
145 public static void finalCheck(final PBody pSystem, SubPlan plan, IQueryMetaContext context) {
146 PConstraint unenforcedConstraint = getAnyUnenforcedConstraint(pSystem, plan);
147 if (unenforcedConstraint != null) {
148 throw new QueryProcessingException(
149 "Pattern matcher construction terminated without successfully enforcing constraint {1}."
150 + " Could be caused if the value of some variables can not be deduced, e.g. by circularity of pattern constraints.",
151 new String[] { unenforcedConstraint.toString() }, "Could not enforce a pattern constraint", null);
152 }
153 for (ExportedParameter export : pSystem
154 .getConstraintsOfType(ExportedParameter.class)) {
155 if (!export.isReadyAt(plan, context)) {
156 throw new QueryProcessingException(
157 "Exported pattern parameter {1} could not be deduced during pattern matcher construction."
158 + " A pattern constraint is required to positively deduce its value.",
159 new String[] { export.getParameterName() }, "Could not calculate pattern parameter",
160 null);
161 }
162 }
163 }
164
165}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/FunctionalDependencyHelper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/FunctionalDependencyHelper.java
new file mode 100644
index 00000000..40835f52
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/FunctionalDependencyHelper.java
@@ -0,0 +1,143 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Adam Dudas, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning.helpers;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.HashMap;
14import java.util.HashSet;
15import java.util.Map;
16import java.util.Map.Entry;
17import java.util.Set;
18
19import tools.refinery.viatra.runtime.matchers.util.Sets;
20
21/**
22 * Helper utility class for functional dependency analysis.
23 *
24 * Throughout this class attribute sets are represented as generic sets and functional dependencies as maps from
25 * attribute set (generic sets) to attribute set (generic sets)
26 *
27 * @author Adam Dudas
28 *
29 */
30public class FunctionalDependencyHelper {
31
32 private FunctionalDependencyHelper() {
33 // Hiding constructor for utility class
34 }
35
36 /**
37 * Get the closure of the specified attribute set relative to the specified functional dependencies.
38 *
39 * @param attributes
40 * The attributes to get the closure of.
41 * @param dependencies
42 * The functional dependencies of which the closure operation is relative to.
43 * @return The closure of the specified attribute set relative to the specified functional dependencies.
44 */
45 public static <A> Set<A> closureOf(Collection<A> attributes, Map<Set<A>, Set<A>> dependencies) {
46 Set<A> closureSet = new HashSet<A>();
47
48 for (Set<A> closureSet1 = new HashSet<A>(attributes); closureSet.addAll(closureSet1);) {
49 closureSet1 = new HashSet<A>();
50 for (Entry<Set<A>, Set<A>> dependency : dependencies.entrySet()) {
51 if (closureSet.containsAll(dependency.getKey()))
52 closureSet1.addAll(dependency.getValue());
53 }
54 }
55
56 return closureSet;
57 }
58
59 /**
60 * @return true if the dependency from the left set to the right set is trivial
61 * @since 1.5
62 */
63 public static <A> boolean isTrivial(Set<A> left, Set<A> right) {
64 return left.containsAll(right);
65 }
66
67 /***
68 * Returns the dependency set over attributes in {@link targetAttributes} that are implied by a given source dependency set.
69 * <p> Note: exponential in the size of the target attribute set.
70 * <p> Note: minimality of the returned dependency set is currently not guaranteed.
71 * @param originalDependencies all dependencies that are known to hold on a wider set of attributes
72 * @param targetAttributes the set of attributes we are interested in
73 * @since 1.5
74 */
75 public static <A> Map<Set<A>, Set<A>> projectDependencies(Map<Set<A>, Set<A>> originalDependencies, Set<A> targetAttributes) {
76 // only those attributes are considered as left-hand-side candidates that occur at least once in dependencies
77 Set<A> leftCandidates = new HashSet<A>();
78 for (Entry<Set<A>, Set<A>> dependency : originalDependencies.entrySet()) {
79 if (!isTrivial(dependency.getKey(), dependency.getValue())) // only if non-trivial
80 leftCandidates.addAll(Sets.intersection(dependency.getKey(), targetAttributes));
81 }
82
83 // Compute an initial list of nontrivial projected dependencies - it does not have to be minimal yet
84 Map<Set<A>, Set<A>> initialDependencies = new HashMap<Set<A>, Set<A>>();
85 for (Set<A> leftSet : Sets.powerSet(leftCandidates)) {
86 Set<A> rightSet = Sets.intersection(closureOf(leftSet, originalDependencies), targetAttributes);
87 if (!isTrivial(leftSet, rightSet)) {
88 initialDependencies.put(leftSet, rightSet);
89 }
90 }
91 // Don't forget to include constants!
92 Set<A> constants = Sets.intersection(closureOf(Collections.<A>emptySet(), originalDependencies), targetAttributes);
93 if (! constants.isEmpty()) {
94 initialDependencies.put(Collections.<A>emptySet(), constants);
95 }
96
97 // Omit those dependencies where the LHS has superfluous attributes
98 Map<Set<A>, Set<A>> solidDependencies = new HashMap<Set<A>, Set<A>>();
99 for (Entry<Set<A>, Set<A>> dependency : initialDependencies.entrySet()) {
100 Set<A> leftSet = dependency.getKey();
101 Set<A> rightSet = dependency.getValue();
102 boolean solid = true;
103 for (A skipped : leftSet) { // what if we skip one attribute from the left set?
104 Set<A> singleton = Collections.singleton(skipped);
105 Set<A> candidate = Sets.difference(leftSet, singleton);
106 Set<A> rightCandidate = initialDependencies.get(candidate);
107 if (rightCandidate != null) {
108 if (Sets.union(rightCandidate, singleton).containsAll(rightSet)) {
109 solid = false;
110 break;
111 }
112 }
113 }
114 if (solid) {
115 solidDependencies.put(leftSet, rightSet);
116 }
117 }
118
119 // TODO perform proper minimization,
120 // see e.g. page 45 in http://www.cs.ubc.ca/~hkhosrav/db/slides/03.design%20theory.pdf
121
122 return Collections.unmodifiableMap(solidDependencies);
123 }
124
125 /**
126 * Adds a given dependency to a mutable accumulator.
127 * @since 1.5
128 */
129 public static <A> void includeDependency(Map<Set<A>, Set<A>> accumulator, Set<A> left, Set<A> right) {
130 Set<A> accumulatorRights = accumulator.computeIfAbsent(left, l -> new HashSet<>());
131 accumulatorRights.addAll(right);
132 }
133
134 /**
135 * Adds all given dependencies to a mutable accumulator.
136 * @since 1.5
137 */
138 public static <A> void includeDependencies(Map<Set<A>, Set<A>> accumulator, Map<Set<A>, Set<A>> additionalDependencies) {
139 for (Entry<Set<A>, Set<A>> entry : additionalDependencies.entrySet()) {
140 includeDependency(accumulator, entry.getKey(), entry.getValue());
141 }
142 }
143}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/StatisticsHelper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/StatisticsHelper.java
new file mode 100644
index 00000000..b4f848a7
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/StatisticsHelper.java
@@ -0,0 +1,62 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning.helpers;
10
11import java.util.Optional;
12import java.util.function.BiFunction;
13
14import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
15import tools.refinery.viatra.runtime.matchers.util.Accuracy;
16
17/**
18 * Helpers dealing with optionally present statistics information
19 *
20 * @author Gabor Bergmann
21 * @since 2.1
22 *
23 */
24public class StatisticsHelper {
25
26 private StatisticsHelper() {
27 // Hidden utility class constructor
28 }
29
30 public static Optional<Double> estimateAverageBucketSize(TupleMask groupMask, Accuracy requiredAccuracy,
31 BiFunction<TupleMask, Accuracy, Optional<Long>> estimateCardinality)
32 {
33 if (groupMask.isIdentity()) return Optional.of(1.0);
34
35 Accuracy numeratorAccuracy = requiredAccuracy;
36 Accuracy denominatorAccuracy = requiredAccuracy.reciprocal();
37 TupleMask identityMask = TupleMask.identity(groupMask.sourceWidth);
38
39 Optional<Long> totalCountEstimate = estimateCardinality.apply(identityMask, numeratorAccuracy);
40 Optional<Long> bucketCountEstimate = estimateCardinality.apply(groupMask, denominatorAccuracy);
41
42 return totalCountEstimate.flatMap(matchCount ->
43 bucketCountEstimate.map(bucketCount ->
44 bucketCount == 0L ? 0L : ((double) matchCount) / bucketCount
45 ));
46 }
47
48 public static Optional<Double> min(Optional<Double> a, Optional<Double> b) {
49 if (b.isPresent()) {
50 if (a.isPresent()) {
51 return Optional.of(Math.min(a.get(), b.get()));
52 } else return b;
53 } else return a;
54 }
55 public static Optional<Double> min(Optional<Double> a, double b) {
56 if (a.isPresent()) {
57 return Optional.of(Math.min(a.get(), b));
58 } else return Optional.of(b);
59 }
60
61
62}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/TypeHelper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/TypeHelper.java
new file mode 100644
index 00000000..926a591f
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/helpers/TypeHelper.java
@@ -0,0 +1,217 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.planning.helpers;
11
12import java.util.Collections;
13import java.util.HashMap;
14import java.util.HashSet;
15import java.util.LinkedList;
16import java.util.Map;
17import java.util.Map.Entry;
18import java.util.Queue;
19import java.util.Set;
20import java.util.stream.Collectors;
21
22import tools.refinery.viatra.runtime.matchers.context.IInputKey;
23import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
24import tools.refinery.viatra.runtime.matchers.psystem.ITypeInfoProviderConstraint;
25import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
26import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
27import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
28
29/**
30 * @author Gabor Bergmann
31 * @author Tamas Szabo
32 */
33public class TypeHelper {
34
35 private TypeHelper() {
36 // Hiding constructor for utility class
37 }
38
39 /**
40 * Collects the type constraints for the specified collection of variables. The type constraints consist of the
41 * constraints directly enforced on the variable itself, plus all of those that the given variable is unified with
42 * through equalities.
43 *
44 * @param variables
45 * the variables in question
46 * @param constraints
47 * the constraints in the pattern body
48 * @param context
49 * the query meta context
50 * @return the mapping from variable to set of type constraints
51 * @since 1.6
52 */
53 public static Map<PVariable, Set<IInputKey>> inferUnaryTypesFor(Iterable<PVariable> variables,
54 Set<PConstraint> constraints, IQueryMetaContext context) {
55 Map<PVariable, Set<TypeJudgement>> typeMap = TypeHelper.inferUnaryTypes(constraints, context);
56 return inferUnaryTypesFor(variables, typeMap);
57 }
58
59 /**
60 * Collects the type constraints for the specified collection of variables. The type constraints consist of the
61 * constraints directly enforced on the variable itself, plus all of those that the given variable is unified with
62 * through equalities.
63 *
64 * The method accepts a type map which is the result of the basic type inference from the
65 * {@link TypeHelper.inferUnaryTypes} method. The purpose of this method is that the type map can be reused across
66 * several calls to this method.
67 *
68 * @param variables
69 * the variables in question
70 * @param typeMap
71 * the type map of inference results
72 * @return the mapping from variable to set of type constraints
73 * @since 1.6
74 */
75 public static Map<PVariable, Set<IInputKey>> inferUnaryTypesFor(Iterable<PVariable> variables,
76 Map<PVariable, Set<TypeJudgement>> typeMap) {
77 Map<PVariable, Set<IInputKey>> result = new HashMap<PVariable, Set<IInputKey>>();
78
79 for (PVariable original : variables) {
80 // it can happen that the variable was unified into an other one due to equalities
81 Set<IInputKey> keys = new HashSet<IInputKey>();
82 PVariable current = original;
83
84 while (current != null) {
85 Set<TypeJudgement> judgements = typeMap.get(current);
86 if (judgements != null) {
87 for (TypeJudgement judgement : judgements) {
88 keys.add(judgement.getInputKey());
89 }
90 }
91 current = current.getDirectUnifiedInto();
92 }
93
94 result.put(original, keys);
95 }
96
97 return result;
98 }
99
100 /**
101 * Infers unary type information for variables, based on the given constraints.
102 *
103 * Subsumptions are not taken into account.
104 *
105 * @param constraints
106 * the set of constraints to extract type info from
107 */
108 public static Map<PVariable, Set<TypeJudgement>> inferUnaryTypes(Set<PConstraint> constraints,
109 IQueryMetaContext context) {
110 Set<TypeJudgement> equivalentJudgements = getDirectJudgements(constraints, context);
111 Set<TypeJudgement> impliedJudgements = typeClosure(equivalentJudgements, context);
112
113 Map<PVariable, Set<TypeJudgement>> results = new HashMap<PVariable, Set<TypeJudgement>>();
114 for (TypeJudgement typeJudgement : impliedJudgements) {
115 final IInputKey inputKey = typeJudgement.getInputKey();
116 if (inputKey.getArity() == 1) {
117 PVariable variable = (PVariable) typeJudgement.getVariablesTuple().get(0);
118 Set<TypeJudgement> inferredTypes = results.computeIfAbsent(variable, v -> new HashSet<>());
119 inferredTypes.add(typeJudgement);
120 }
121 }
122 return results;
123 }
124
125 /**
126 * Gets direct judgements reported by constraints. No closure is applied yet.
127 */
128 public static Set<TypeJudgement> getDirectJudgements(Set<PConstraint> constraints, IQueryMetaContext context) {
129 Set<TypeJudgement> equivalentJudgements = new HashSet<TypeJudgement>();
130 for (PConstraint pConstraint : constraints) {
131 if (pConstraint instanceof ITypeInfoProviderConstraint) {
132 equivalentJudgements.addAll(((ITypeInfoProviderConstraint) pConstraint).getImpliedJudgements(context));
133 }
134 }
135 return equivalentJudgements;
136 }
137
138 /**
139 * Calculates the closure of a set of type judgements, with respect to supertyping.
140 *
141 * @return the set of all type judgements in typesToClose and all their direct and indirect supertypes
142 */
143 public static Set<TypeJudgement> typeClosure(Set<TypeJudgement> typesToClose, IQueryMetaContext context) {
144 return typeClosure(Collections.<TypeJudgement> emptySet(), typesToClose, context);
145 }
146
147 /**
148 * Calculates the closure of a set of type judgements (with respect to supertyping), where the closure has been
149 * calculated before for a given base set, but not for a separate delta set.
150 * <p>
151 * Precondition: the set (typesToClose MINUS delta) is already closed w.r.t. supertyping.
152 *
153 * @return the set of all type judgements in typesToClose and all their direct and indirect supertypes
154 * @since 1.6
155 */
156 public static Set<TypeJudgement> typeClosure(Set<TypeJudgement> preclosedBaseSet, Set<TypeJudgement> delta,
157 IQueryMetaContext context) {
158 Queue<TypeJudgement> queue = delta.stream().filter(input -> !preclosedBaseSet.contains(input)).collect(Collectors.toCollection(LinkedList::new));
159 if (queue.isEmpty())
160 return preclosedBaseSet;
161
162 Set<TypeJudgement> closure = new HashSet<TypeJudgement>(preclosedBaseSet);
163
164 Map<TypeJudgement, Set<TypeJudgement>> conditionalImplications = new HashMap<>();
165 for (TypeJudgement typeJudgement : closure) {
166 conditionalImplications.putAll(typeJudgement.getConditionalImpliedJudgements(context));
167 }
168
169 do {
170 TypeJudgement deltaType = queue.poll();
171 if (closure.add(deltaType)) {
172 // direct implications
173 queue.addAll(deltaType.getDirectlyImpliedJudgements(context));
174
175 // conditional implications, source key processed before, this is the condition key
176 final Set<TypeJudgement> implicationSet = conditionalImplications.get(deltaType);
177 if (implicationSet != null) {
178 queue.addAll(implicationSet);
179 }
180
181 // conditional implications, this is the source key
182 Map<TypeJudgement, Set<TypeJudgement>> deltaConditionalImplications = deltaType
183 .getConditionalImpliedJudgements(context);
184 for (Entry<TypeJudgement, Set<TypeJudgement>> entry : deltaConditionalImplications.entrySet()) {
185 if (closure.contains(entry.getKey())) {
186 // condition processed before
187 queue.addAll(entry.getValue());
188 } else {
189 // condition not processed yet
190 conditionalImplications.computeIfAbsent(entry.getKey(), key -> new HashSet<>())
191 .addAll(entry.getValue());
192 }
193 }
194 }
195 } while (!queue.isEmpty());
196
197 return closure;
198 }
199
200 /**
201 * Calculates a remainder set of types from a larger set, that are not subsumed by a given set of subsuming types.
202 *
203 * @param subsumableTypes
204 * a set of types from which some may be implied by the subsuming types
205 * @param subsumingTypes
206 * a set of types that may imply some of the subsuming types
207 * @return the collection of types in subsumableTypes that are NOT identical to or supertypes of any type in
208 * subsumingTypes.
209 */
210 public static Set<TypeJudgement> subsumeTypes(Set<TypeJudgement> subsumableTypes, Set<TypeJudgement> subsumingTypes,
211 IQueryMetaContext context) {
212 Set<TypeJudgement> closure = typeClosure(subsumingTypes, context);
213 Set<TypeJudgement> subsumed = new HashSet<TypeJudgement>(subsumableTypes);
214 subsumed.removeAll(closure);
215 return subsumed;
216 }
217}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PApply.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PApply.java
new file mode 100644
index 00000000..2c285b54
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PApply.java
@@ -0,0 +1,94 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning.operations;
10
11import java.util.Collections;
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
15import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
16import tools.refinery.viatra.runtime.matchers.util.Preconditions;
17
18/**
19 * Represents a constraint application on a single parent SubPlan.
20 * <p> Either a "selection" filter operation according to a deferred PConstraint (or transform in case of eval/aggregate), or
21 * alternatively a shorthand for PJoin + a PEnumerate on the right input for an enumerable PConstraint.
22 *
23 * <p> <b>WARNING</b>: if there are coinciding variables in the variable tuple of the enumerable constraint,
24 * it is the responsibility of the compiler to check them for equality.
25 *
26 * @author Bergmann Gabor
27 *
28 */
29public class PApply extends POperation {
30
31 private PConstraint pConstraint;
32
33 public PApply(PConstraint pConstraint) {
34 super();
35 this.pConstraint = pConstraint;
36 }
37 public PConstraint getPConstraint() {
38 return pConstraint;
39 }
40
41 @Override
42 public String getShortName() {
43 return String.format("APPLY_%s", pConstraint.toString());
44 }
45
46 @Override
47 public Set<? extends PConstraint> getDeltaConstraints() {
48 return Collections.singleton(pConstraint);
49 }
50
51 @Override
52 public int numParentSubPlans() {
53 return 1;
54 }
55
56 @Override
57 public void checkConsistency(SubPlan subPlan) {
58 super.checkConsistency(subPlan);
59 for (SubPlan parentPlan : subPlan.getParentPlans())
60 Preconditions.checkArgument(!parentPlan.getAllEnforcedConstraints().contains(pConstraint),
61 "Double-checking constraint %s", pConstraint);
62 // TODO obtain context?
63 //if (pConstraint instanceof DeferredPConstraint)
64 // Preconditions.checkArgument(((DeferredPConstraint) pConstraint).isReadyAt(subPlan, context))
65 }
66
67 @Override
68 public int hashCode() {
69 final int prime = 31;
70 int result = 1;
71 result = prime
72 * result
73 + ((pConstraint == null) ? 0 : pConstraint
74 .hashCode());
75 return result;
76 }
77 @Override
78 public boolean equals(Object obj) {
79 if (this == obj)
80 return true;
81 if (obj == null)
82 return false;
83 if (!(obj instanceof PApply))
84 return false;
85 PApply other = (PApply) obj;
86 if (pConstraint == null) {
87 if (other.pConstraint != null)
88 return false;
89 } else if (!pConstraint.equals(other.pConstraint))
90 return false;
91 return true;
92 }
93
94}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PEnumerate.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PEnumerate.java
new file mode 100644
index 00000000..a975d50c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PEnumerate.java
@@ -0,0 +1,76 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning.operations;
10
11import java.util.Collections;
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.psystem.EnumerablePConstraint;
15import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
16
17/**
18 * Represents a base relation defined by the instance set of an enumerable PConstraint; there are no parent SubPlans.
19 *
20 * <p> <b>WARNING</b>: if there are coinciding variables in the variable tuple of the enumerable constraint,
21 * it is the responsibility of the compiler to check them for equality.
22 * @author Bergmann Gabor
23 *
24 */
25public class PEnumerate extends POperation {
26
27 EnumerablePConstraint enumerablePConstraint;
28
29 public PEnumerate(EnumerablePConstraint enumerablePConstraint) {
30 super();
31 this.enumerablePConstraint = enumerablePConstraint;
32 }
33 public EnumerablePConstraint getEnumerablePConstraint() {
34 return enumerablePConstraint;
35 }
36
37 @Override
38 public Set<? extends PConstraint> getDeltaConstraints() {
39 return Collections.singleton(enumerablePConstraint);
40 }
41 @Override
42 public int numParentSubPlans() {
43 return 0;
44 }
45 @Override
46 public String getShortName() {
47 return enumerablePConstraint.toString();
48 }
49 @Override
50 public int hashCode() {
51 final int prime = 31;
52 int result = 1;
53 result = prime
54 * result
55 + ((enumerablePConstraint == null) ? 0 : enumerablePConstraint
56 .hashCode());
57 return result;
58 }
59 @Override
60 public boolean equals(Object obj) {
61 if (this == obj)
62 return true;
63 if (obj == null)
64 return false;
65 if (!(obj instanceof PEnumerate))
66 return false;
67 PEnumerate other = (PEnumerate) obj;
68 if (enumerablePConstraint == null) {
69 if (other.enumerablePConstraint != null)
70 return false;
71 } else if (!enumerablePConstraint.equals(other.enumerablePConstraint))
72 return false;
73 return true;
74 }
75
76}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PJoin.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PJoin.java
new file mode 100644
index 00000000..10e0a85a
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PJoin.java
@@ -0,0 +1,64 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning.operations;
10
11import java.util.Collections;
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
15
16/**
17 * Represents a natural join of two parent SubPlans.
18 * @author Bergmann Gabor
19 *
20 */
21public class PJoin extends POperation {
22
23// // TODO leave here? is this a problem in equivalnece checking?
24// private Set<PVariable> onVariables;
25
26 public PJoin(/*Set<PVariable> onVariables*/) {
27 super();
28 //this.onVariables = new HashSet<PVariable>(onVariables);
29 }
30// public Set<PVariable> getOnVariables() {
31// return onVariables;
32// }
33
34 @Override
35 public Set<? extends PConstraint> getDeltaConstraints() {
36 return Collections.emptySet();
37 }
38 @Override
39 public int numParentSubPlans() {
40 return 2;
41 }
42
43 @Override
44 public String getShortName() {
45 return "JOIN"; //String.format("JOIN_{%s}", Joiner.on(",").join(onVariables));
46 }
47
48 @Override
49 public int hashCode() {
50 return getClass().hashCode();
51 }
52 @Override
53 public boolean equals(Object obj) {
54 if (this == obj)
55 return true;
56 if (obj == null)
57 return false;
58 if (!(obj instanceof PJoin))
59 return false;
60 return true;
61 }
62
63
64}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/POperation.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/POperation.java
new file mode 100644
index 00000000..e71cf217
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/POperation.java
@@ -0,0 +1,52 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning.operations;
10
11import java.util.Set;
12
13import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
14import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
15import tools.refinery.viatra.runtime.matchers.util.Preconditions;
16
17/**
18 * Abstract superclass for representing a high-level query evaluation operation.
19 *
20 * <p> Subclasses correspond to various POperations modeled after relational algebra.
21 *
22 * @author Bergmann Gabor
23 *
24 */
25public abstract class POperation {
26
27 /**
28 * Newly enforced constraints
29 */
30 public abstract Set<? extends PConstraint> getDeltaConstraints();
31
32 public abstract String getShortName();
33
34 /**
35 * @return the number of SubPlans that must be specified as parents
36 */
37 public abstract int numParentSubPlans();
38
39 /**
40 * Checks whether this constraint can be properly applied at the given SubPlan.
41 */
42 public void checkConsistency(SubPlan subPlan) {
43 Preconditions.checkArgument(this == subPlan.getOperation(), "POperation misalignment");
44 Preconditions.checkArgument(subPlan.getParentPlans().size() == numParentSubPlans(), "Incorrect number of parent SubPlans");
45 }
46
47 @Override
48 public String toString() {
49 return getShortName();
50 }
51
52}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PProject.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PProject.java
new file mode 100644
index 00000000..d0539b2c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PProject.java
@@ -0,0 +1,109 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning.operations;
10
11import java.util.Collection;
12import java.util.Collections;
13import java.util.List;
14import java.util.Set;
15import java.util.stream.Collectors;
16
17import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
18import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
19import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
20import tools.refinery.viatra.runtime.matchers.util.Preconditions;
21
22/**
23 * Represents a projection of a single parent SubPlan onto a limited set of variables.
24 * <p> May optionally prescribe an ordering of variables (List, as opposed to Set).
25 *
26 * @author Bergmann Gabor
27 *
28 */
29public class PProject extends POperation {
30
31 private Collection<PVariable> toVariables;
32 private boolean ordered;
33
34
35 public PProject(Set<PVariable> toVariables) {
36 super();
37 this.toVariables = toVariables;
38 this.ordered = false;
39 }
40 public PProject(List<PVariable> toVariables) {
41 super();
42 this.toVariables = toVariables;
43 this.ordered = true;
44 }
45
46 public Collection<PVariable> getToVariables() {
47 return toVariables;
48 }
49 public boolean isOrdered() {
50 return ordered;
51 }
52
53 @Override
54 public Set<? extends PConstraint> getDeltaConstraints() {
55 return Collections.emptySet();
56 }
57 @Override
58 public int numParentSubPlans() {
59 return 1;
60 }
61 @Override
62 public void checkConsistency(SubPlan subPlan) {
63 super.checkConsistency(subPlan);
64 final SubPlan parentPlan = subPlan.getParentPlans().get(0);
65
66 Preconditions.checkArgument(parentPlan.getVisibleVariables().containsAll(toVariables),
67 () -> toVariables.stream()
68 .filter(input -> !parentPlan.getVisibleVariables().contains(input)).map(PVariable::getName)
69 .collect(Collectors.joining(",", "Variables missing from project: ", "")));
70 }
71
72 @Override
73 public String getShortName() {
74 return String.format("PROJECT%s_{%s}", ordered? "!" : "",
75 toVariables.stream().map(PVariable::getName).collect(Collectors.joining(",")));
76 }
77
78 @Override
79 public int hashCode() {
80 final int prime = 31;
81 int result = 1;
82 result = prime * result + (ordered ? 1231 : 1237);
83 result = prime * result
84 + ((toVariables == null) ? 0 : toVariables.hashCode());
85 return result;
86 }
87 @Override
88 public boolean equals(Object obj) {
89 if (this == obj)
90 return true;
91 if (obj == null)
92 return false;
93 if (!(obj instanceof PProject))
94 return false;
95 PProject other = (PProject) obj;
96 if (ordered != other.ordered)
97 return false;
98 if (toVariables == null) {
99 if (other.toVariables != null)
100 return false;
101 } else if (!toVariables.equals(other.toVariables))
102 return false;
103 return true;
104 }
105
106
107
108
109}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PStart.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PStart.java
new file mode 100644
index 00000000..9e6ea10e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/operations/PStart.java
@@ -0,0 +1,90 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.planning.operations;
10
11import java.util.Arrays;
12import java.util.Collections;
13import java.util.HashSet;
14import java.util.Set;
15import java.util.stream.Collectors;
16
17import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
18import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
19
20/**
21 * No constraints, and no parent SubPlan, just a (possibly empty) set of a priori known (input) variables. Satisfied by a single tuple.
22 *
23 * <p> Can also be used without a priori variables,
24 * e.g. as a "virtual parent" in extreme cases,
25 * such as <code>pattern foo(Bar) = {Bar = eval (3*4)} </code>
26 *
27 * @author Bergmann Gabor
28 *
29 */
30public class PStart extends POperation {
31
32 private Set<PVariable> aPrioriVariables;
33
34
35 public PStart(Set<PVariable> aPrioriVariables) {
36 super();
37 this.aPrioriVariables = aPrioriVariables;
38 }
39 public PStart(PVariable... aPrioriVariables) {
40 this(new HashSet<PVariable>(Arrays.asList(aPrioriVariables)));
41 }
42 public Set<PVariable> getAPrioriVariables() {
43 return aPrioriVariables;
44 }
45
46 @Override
47 public String getShortName() {
48 return aPrioriVariables.stream().map(PVariable::getName).collect(Collectors.joining(",", "START_{", "}"));
49 }
50 @Override
51 public int numParentSubPlans() {
52 return 0;
53 }
54
55 @Override
56 public Set<? extends PConstraint> getDeltaConstraints() {
57 return Collections.emptySet();
58 }
59
60 @Override
61 public int hashCode() {
62 final int prime = 31;
63 int result = 1;
64 result = prime
65 * result
66 + ((aPrioriVariables == null) ? 0 : aPrioriVariables.hashCode());
67 return result;
68 }
69
70 @Override
71 public boolean equals(Object obj) {
72 if (this == obj)
73 return true;
74 if (obj == null)
75 return false;
76 if (!(obj instanceof PStart))
77 return false;
78 PStart other = (PStart) obj;
79 if (aPrioriVariables == null) {
80 if (other.aPrioriVariables != null)
81 return false;
82 } else if (!aPrioriVariables.equals(other.aPrioriVariables))
83 return false;
84 return true;
85 }
86
87
88
89
90}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/BasePConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/BasePConstraint.java
new file mode 100644
index 00000000..eda4aa25
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/BasePConstraint.java
@@ -0,0 +1,108 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem;
11
12import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
13
14import java.util.Collections;
15import java.util.HashSet;
16import java.util.Map;
17import java.util.Set;
18import java.util.concurrent.atomic.AtomicInteger;
19
20/**
21 * @author Gabor Bergmann
22 *
23 */
24public abstract class BasePConstraint implements PConstraint {
25
26
27 protected PBody pBody;
28 private final Set<PVariable> affectedVariables;
29
30
31 private final int sequentialID = nextID.getAndIncrement();
32
33 // Use a static atomic integer to avoid race conditions when creating new constraints.
34 private static AtomicInteger nextID = new AtomicInteger(0);
35
36 public BasePConstraint(PBody pBody, Set<PVariable> affectedVariables) {
37 super();
38 this.pBody = pBody;
39 this.affectedVariables = new HashSet<PVariable>(affectedVariables);
40
41 for (PVariable pVariable : affectedVariables) {
42 pVariable.refer(this);
43 }
44 pBody.registerConstraint(this);
45 }
46
47 @Override
48 public String toString() {
49 return "PC[" + getClass().getSimpleName() + ":" + toStringRest() + "]";
50 }
51
52 protected abstract String toStringRest();
53
54 @Override
55 public Set<PVariable> getAffectedVariables() {
56 return affectedVariables;
57 }
58
59 @Override
60 public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context) {
61 return Collections.emptyMap();
62 }
63
64 @Override
65 public void replaceVariable(PVariable obsolete, PVariable replacement) {
66 pBody.checkMutability();
67 if (affectedVariables.remove(obsolete)) {
68 affectedVariables.add(replacement);
69 obsolete.unrefer(this);
70 replacement.refer(this);
71 doReplaceVariable(obsolete, replacement);
72 }
73 }
74
75 protected abstract void doReplaceVariable(PVariable obsolete, PVariable replacement);
76
77 @Override
78 public void delete() {
79 pBody.checkMutability();
80 for (PVariable pVariable : affectedVariables) {
81 pVariable.unrefer(this);
82 }
83 pBody.unregisterConstraint(this);
84 }
85
86 @Override
87 public void checkSanity() {
88 }
89
90 /**
91 * For backwards compatibility. Equivalent to {@link #getBody()}
92 */
93 public PBody getPSystem() {
94 return pBody;
95 }
96 /**
97 * @since 2.1
98 */
99 @Override
100 public PBody getBody() {
101 return pBody;
102 }
103
104 @Override
105 public int getMonotonousID() {
106 return sequentialID;
107 }
108}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/DeferredPConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/DeferredPConstraint.java
new file mode 100644
index 00000000..d2bf088c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/DeferredPConstraint.java
@@ -0,0 +1,31 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem;
11
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
15import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
16
17/**
18 * Any constraint that can only be checked on certain SubPlans (e.g. those plans that already contain some variables).
19 *
20 * @author Gabor Bergmann
21 *
22 */
23public abstract class DeferredPConstraint extends BasePConstraint {
24
25 public DeferredPConstraint(PBody pBody, Set<PVariable> affectedVariables) {
26 super(pBody, affectedVariables);
27 }
28
29 public abstract boolean isReadyAt(SubPlan plan, IQueryMetaContext context);
30
31}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/EnumerablePConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/EnumerablePConstraint.java
new file mode 100644
index 00000000..9129aa47
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/EnumerablePConstraint.java
@@ -0,0 +1,59 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem;
11
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
15
16/**
17 * A constraint for which all satisfying tuples of variable values can be enumerated at any point during run-time.
18 *
19 * @author Gabor Bergmann
20 *
21 */
22public abstract class EnumerablePConstraint extends BasePConstraint {
23 protected Tuple variablesTuple;
24
25 protected EnumerablePConstraint(PBody pBody, Tuple variablesTuple) {
26 super(pBody, variablesTuple.<PVariable> getDistinctElements());
27 this.variablesTuple = variablesTuple;
28 }
29
30 @Override
31 public void doReplaceVariable(PVariable obsolete, PVariable replacement) {
32 variablesTuple = variablesTuple.replaceAll(obsolete, replacement);
33 }
34
35 @Override
36 protected String toStringRest() {
37 String stringRestRest = toStringRestRest();
38 String tupleString = "@" + variablesTuple.toString();
39 return stringRestRest == null ? tupleString : ":" + stringRestRest + tupleString;
40 }
41
42 protected String toStringRestRest() {
43 return null;
44 }
45
46 public Tuple getVariablesTuple() {
47 return variablesTuple;
48 }
49
50 @Override
51 public Set<PVariable> getDeducedVariables() {
52 return getAffectedVariables();
53 }
54
55 public PVariable getVariableInTuple(int index) {
56 return (PVariable) this.variablesTuple.get(index);
57 }
58
59}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IExpressionEvaluator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IExpressionEvaluator.java
new file mode 100644
index 00000000..686999f7
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IExpressionEvaluator.java
@@ -0,0 +1,42 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem;
10
11/**
12 * An expression evaluator is used to execute arbitrary Java code during pattern matching. In order to include the
13 * evaluation in the planning seemlessly it is expected from the evaluator implementors to report all used PVariables by
14 * name.
15 *
16 * @author Zoltan Ujhelyi
17 *
18 */
19public interface IExpressionEvaluator {
20
21 /**
22 * A textual description of the expression. Used only for debug purposes, but must not be null.
23 */
24 String getShortDescription();
25
26 /**
27 * All input parameter names should be reported correctly.
28 */
29 Iterable<String> getInputParameterNames();
30
31 /**
32 * The expression evaluator code
33 *
34 * @param provider
35 * the value provider is an engine-specific way of reading internal variable tuples to evaluate the
36 * expression with
37 * @return the result of the expression: in case of predicate evaluation the return value must be true or false;
38 * otherwise the result can be an arbitrary object. No null values should be returned.
39 * @throws Exception
40 */
41 Object evaluateExpression(IValueProvider provider) throws Exception;
42}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IMultiQueryReference.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IMultiQueryReference.java
new file mode 100644
index 00000000..8f647c64
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IMultiQueryReference.java
@@ -0,0 +1,26 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2022, Tamas Szabo, GitHub
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem;
10
11import java.util.Collection;
12
13import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
14
15/**
16 * A {@link PConstraint} that implements this interface refers to a list of PQueries.
17 *
18 * @author Tamas Szabo
19 * @since 2.8
20 *
21 */
22public interface IMultiQueryReference {
23
24 Collection<PQuery> getReferredQueries();
25
26}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IQueryReference.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IQueryReference.java
new file mode 100644
index 00000000..9ee05b39
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IQueryReference.java
@@ -0,0 +1,33 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem;
10
11import java.util.Collections;
12import java.util.List;
13
14import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
15
16/**
17 * A {@link PConstraint} that implements this interface refers to a {@link PQuery}.
18 *
19 * @author Zoltan Ujhelyi
20 *
21 */
22public interface IQueryReference extends IMultiQueryReference {
23
24 PQuery getReferredQuery();
25
26 /**
27 * @since 2.8
28 */
29 @Override
30 default List<PQuery> getReferredQueries() {
31 return Collections.singletonList(getReferredQuery());
32 }
33}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IRelationEvaluator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IRelationEvaluator.java
new file mode 100644
index 00000000..e4c396d8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IRelationEvaluator.java
@@ -0,0 +1,47 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2022, Tamas Szabo, GitHub
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem;
10
11import java.util.List;
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
15
16/**
17 * Implementations of this interface take an arbitrary number of input relations with their contents and compute the
18 * tuples of a single output relation.
19 *
20 * @author Tamas Szabo
21 * @since 2.8
22 *
23 */
24public interface IRelationEvaluator {
25
26 /**
27 * A textual description of the evaluator. Used only for debug purposes, but must not be null.
28 */
29 String getShortDescription();
30
31 /**
32 * The relation evaluator code. For performance reasons, it is expected that the returned set is a mutable
33 * collection, and the caller must be allowed to actually perform mutations!
34 */
35 Set<Tuple> evaluateRelation(List<Set<Tuple>> inputs) throws Exception;
36
37 /**
38 * For each input relation that this evaluator requires, this method returns the expected arities of the relations in order.
39 */
40 List<Integer> getInputArities();
41
42 /**
43 * Returns the arity of the output relation that this evaluator computes.
44 */
45 int getOutputArity();
46
47}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeConstraint.java
new file mode 100644
index 00000000..b72035a8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeConstraint.java
@@ -0,0 +1,65 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem;
10
11import java.util.HashMap;
12import java.util.HashSet;
13import java.util.Map;
14import java.util.Map.Entry;
15
16import tools.refinery.viatra.runtime.matchers.context.IInputKey;
17import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
19
20import java.util.Set;
21
22/**
23 * Common superinterface of enumerable and deferred type constraints.
24 * @author Bergmann Gabor
25 *
26 */
27public interface ITypeConstraint extends ITypeInfoProviderConstraint {
28
29 public abstract TypeJudgement getEquivalentJudgement();
30
31 /**
32 * Static internal utility class for implementations of {@link ITypeConstraint}s.
33 * @author Bergmann Gabor
34 */
35 public static class TypeConstraintUtil {
36
37 private TypeConstraintUtil() {
38 // Hiding constructor for utility class
39 }
40
41 public static Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context, IInputKey inputKey, Tuple variablesTuple) {
42 final Map<Set<PVariable>, Set<PVariable>> result = new HashMap<Set<PVariable>, Set<PVariable>>();
43
44 Set<Entry<Set<Integer>, Set<Integer>>> dependencies = context.getFunctionalDependencies(inputKey).entrySet();
45 for (Entry<Set<Integer>, Set<Integer>> dependency : dependencies) {
46 result.put(
47 transcribeVariables(dependency.getKey(), variablesTuple),
48 transcribeVariables(dependency.getValue(), variablesTuple)
49 );
50 }
51
52 return result;
53 }
54
55 private static Set<PVariable> transcribeVariables(Set<Integer> indices, Tuple variablesTuple) {
56 Set<PVariable> result = new HashSet<PVariable>();
57 for (Integer index : indices) {
58 result.add((PVariable) variablesTuple.get(index));
59 }
60 return result;
61 }
62
63 }
64
65}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeInfoProviderConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeInfoProviderConstraint.java
new file mode 100644
index 00000000..ff127d38
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/ITypeInfoProviderConstraint.java
@@ -0,0 +1,28 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem;
11
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
15
16/**
17 * @author Gabor Bergmann
18 *
19 */
20public interface ITypeInfoProviderConstraint extends PConstraint {
21
22 /**
23 * Returns type information implied by this constraint.
24 *
25 */
26 public Set<TypeJudgement> getImpliedJudgements(IQueryMetaContext context);
27
28}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IValueProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IValueProvider.java
new file mode 100644
index 00000000..d959adc4
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/IValueProvider.java
@@ -0,0 +1,27 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem;
10
11/**
12 * Helper interface to get values from a tuple of variables. All pattern matching engines are expected to implement this
13 * to handle their internal structures.
14 *
15 * @author Zoltan Ujhelyi
16 *
17 */
18public interface IValueProvider {
19
20 /**
21 * Returns the value of the selected variable
22 * @param variableName
23 * @return the value of the variable; never null
24 * @throws IllegalArgumentException if the variable is not defined
25 */
26 Object getValue(String variableName);
27}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/InitializablePQuery.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/InitializablePQuery.java
new file mode 100644
index 00000000..a82d12ec
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/InitializablePQuery.java
@@ -0,0 +1,56 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem;
10
11import java.util.Set;
12
13import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
14import tools.refinery.viatra.runtime.matchers.psystem.annotations.PAnnotation;
15import tools.refinery.viatra.runtime.matchers.psystem.queries.PProblem;
16import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
17
18/**
19 * Adds extra methods to the PQuery interface to initialize its contents.
20 *
21 * @author Zoltan Ujhelyi
22 *
23 */
24public interface InitializablePQuery extends PQuery {
25
26 /**
27 * Sets the query status. Only applicable if the pattern is still {@link PQueryStatus#UNINITIALIZED uninitialized}.
28 *
29 * @param status the new status
30 */
31 void setStatus(PQueryStatus status);
32
33 /**
34 * Adds a detected error. Only applicable if the pattern is still {@link PQueryStatus#UNINITIALIZED uninitialized}.
35 *
36 * @param problem the new problem
37 */
38 void addError(PProblem problem);
39
40 /**
41 * Sets up the bodies of the pattern. Only applicable if the pattern is still {@link PQueryStatus#UNINITIALIZED
42 * uninitialized}.
43 *
44 * @param bodies
45 * @throws ViatraQueryRuntimeException
46 */
47 void initializeBodies(Set<PBody> bodies);
48
49 /**
50 * Adds an annotation to the specification. Only applicable if the pattern is still
51 * {@link PQueryStatus#UNINITIALIZED uninitialized}.
52 *
53 * @param annotation
54 */
55 void addAnnotation(PAnnotation annotation);
56}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/KeyedEnumerablePConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/KeyedEnumerablePConstraint.java
new file mode 100644
index 00000000..91eea817
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/KeyedEnumerablePConstraint.java
@@ -0,0 +1,39 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem;
11
12import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
13
14/**
15 * @author Gabor Bergmann
16 *
17 */
18public abstract class KeyedEnumerablePConstraint<KeyType> extends EnumerablePConstraint {
19
20 protected KeyType supplierKey;
21
22 public KeyedEnumerablePConstraint(PBody pBody, Tuple variablesTuple,
23 KeyType supplierKey) {
24 super(pBody, variablesTuple);
25 this.supplierKey = supplierKey;
26 }
27
28 @Override
29 protected String toStringRestRest() {
30 return supplierKey == null ? "$any(null)" : keyToString();
31 }
32
33 protected abstract String keyToString();
34
35 public KeyType getSupplierKey() {
36 return supplierKey;
37 }
38
39}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PBody.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PBody.java
new file mode 100644
index 00000000..c38dc23a
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PBody.java
@@ -0,0 +1,289 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem;
11
12import java.util.ArrayList;
13import java.util.HashMap;
14import java.util.HashSet;
15import java.util.LinkedHashSet;
16import java.util.List;
17import java.util.Map;
18import java.util.Set;
19import java.util.WeakHashMap;
20import java.util.stream.Collectors;
21
22import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
23import tools.refinery.viatra.runtime.matchers.planning.helpers.TypeHelper;
24import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExportedParameter;
25import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.ConstantValue;
26import tools.refinery.viatra.runtime.matchers.psystem.queries.PDisjunction;
27import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
28import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery.PQueryStatus;
29import tools.refinery.viatra.runtime.matchers.util.Preconditions;
30
31/**
32 * A set of constraints representing a pattern body
33 *
34 * @author Gabor Bergmann
35 *
36 */
37public class PBody implements PTraceable {
38
39 public static final String VIRTUAL_VARIABLE_PREFIX = ".virtual";
40 private static final String VIRTUAL_VARIABLE_PATTERN = VIRTUAL_VARIABLE_PREFIX + "{%d}";
41
42 private PQuery query;
43
44 /**
45 * If null, then parent query status is reused
46 */
47 private PQueryStatus status = PQueryStatus.UNINITIALIZED;
48
49 private Set<PVariable> allVariables;
50 private Set<PVariable> uniqueVariables;
51 private List<ExportedParameter> symbolicParameters;
52 private Map<Object, PVariable> variablesByName;
53 private Set<PConstraint> constraints;
54 private int nextVirtualNodeID;
55 private PDisjunction containerDisjunction;
56
57 public PBody(PQuery query) {
58 super();
59 this.query = query;
60 allVariables = new LinkedHashSet<>();
61 uniqueVariables = new LinkedHashSet<>();
62 variablesByName = new HashMap<>();
63 constraints = new LinkedHashSet<>();
64 }
65
66 /**
67 * @return whether the submission of the new variable was successful
68 */
69 private boolean addVariable(PVariable var) {
70 checkMutability();
71 Object name = var.getName();
72 if (!variablesByName.containsKey(name)) {
73 allVariables.add(var);
74 if (var.isUnique())
75 uniqueVariables.add(var);
76 variablesByName.put(name, var);
77 return true;
78 } else {
79 return false;
80 }
81 }
82
83 /**
84 * Use this method to add a newly created constraint to the pSystem.
85 *
86 * @return whether the submission of the new constraint was successful
87 */
88 boolean registerConstraint(PConstraint constraint) {
89 checkMutability();
90 return constraints.add(constraint);
91 }
92
93 /**
94 * Use this method to remove an obsolete constraint from the pSystem.
95 *
96 * @return whether the removal of the constraint was successful
97 */
98 boolean unregisterConstraint(PConstraint constraint) {
99 checkMutability();
100 return constraints.remove(constraint);
101 }
102
103 @SuppressWarnings("unchecked")
104 public <ConstraintType> Set<ConstraintType> getConstraintsOfType(Class<ConstraintType> constraintClass) {
105 Set<ConstraintType> result = new HashSet<ConstraintType>();
106 for (PConstraint pConstraint : constraints) {
107 if (constraintClass.isInstance(pConstraint))
108 result.add((ConstraintType) pConstraint);
109 }
110 return result;
111 }
112
113 public PVariable newVirtualVariable() {
114 checkMutability();
115 String name;
116 do {
117
118 name = String.format(VIRTUAL_VARIABLE_PATTERN, nextVirtualNodeID++);
119 } while (variablesByName.containsKey(name));
120 PVariable var = new PVariable(this, name, true);
121 addVariable(var);
122 return var;
123 }
124
125 public PVariable newVirtualVariable(String name) {
126 checkMutability();
127 Preconditions.checkArgument(!variablesByName.containsKey(name), "ID %s already used for a virtual variable", name);
128 PVariable var = new PVariable(this, name, true);
129 addVariable(var);
130 return var;
131 }
132
133 public PVariable newConstantVariable(Object value) {
134 checkMutability();
135 PVariable virtual = newVirtualVariable();
136 new ConstantValue(this, virtual, value);
137 return virtual;
138 }
139
140 public Set<PVariable> getAllVariables() {
141 return allVariables;
142 }
143
144 public Set<PVariable> getUniqueVariables() {
145 return uniqueVariables;
146 }
147
148 private PVariable getVariableByName(Object name) {
149 return variablesByName.get(name).getUnifiedIntoRoot();
150 }
151
152 /**
153 * Find a PVariable by name
154 *
155 * @param name
156 * @return the found variable
157 * @throws IllegalArgumentException
158 * if no PVariable is found with the selected name
159 */
160 public PVariable getVariableByNameChecked(Object name) {
161 if (!variablesByName.containsKey(name))
162 throw new IllegalArgumentException(String.format("Cannot find PVariable %s", name));
163 return getVariableByName(name);
164 }
165
166 /**
167 * Finds and returns a PVariable by name. If no PVariable exists with the name in the body, a new one is created. If
168 * the name of the variable starts with {@value #VIRTUAL_VARIABLE_PREFIX}, the created variable will be considered
169 * virtual.
170 *
171 * @param name
172 * @return a PVariable with the selected name; never null
173 */
174 public PVariable getOrCreateVariableByName(String name) {
175 checkMutability();
176 if (!variablesByName.containsKey(name)) {
177 addVariable(new PVariable(this, name, name.startsWith(VIRTUAL_VARIABLE_PREFIX)));
178 }
179 return getVariableByName(name);
180 }
181
182 public Set<PConstraint> getConstraints() {
183 return constraints;
184 }
185
186 public PQuery getPattern() {
187 return query;
188 }
189
190 void noLongerUnique(PVariable pVariable) {
191 assert (!pVariable.isUnique());
192 uniqueVariables.remove(pVariable);
193 }
194
195 /**
196 * Returns the symbolic parameters of the body. </p>
197 *
198 * <p>
199 * <strong>Warning</strong>: if two PVariables are unified, the returned list changes. If you want to have a stable
200 * version, consider using {@link #getSymbolicParameters()}.
201 *
202 * @return a non-null, but possibly empty list
203 */
204 public List<PVariable> getSymbolicParameterVariables() {
205 return getSymbolicParameters().stream().map(ExportedParameter::getParameterVariable)
206 .collect(Collectors.toList());
207 }
208
209 /**
210 * Returns the exported parameter constraints of the body.
211 *
212 * @return a non-null, but possibly empty list
213 */
214 public List<ExportedParameter> getSymbolicParameters() {
215 if (symbolicParameters == null)
216 symbolicParameters = new ArrayList<>();
217 return symbolicParameters;
218 }
219
220 /**
221 * Sets the exported parameter constraints of the body, if this instance is mutable.
222 * @param symbolicParameters the new value
223 */
224 public void setSymbolicParameters(List<ExportedParameter> symbolicParameters) {
225 checkMutability();
226 this.symbolicParameters = new ArrayList<>(symbolicParameters);
227 }
228
229 /**
230 * Sets a specific status for the body. If set, the parent PQuery status will not be checked; if set to null, its corresponding PQuery
231 * status is checked for mutability.
232 *
233 * @param status
234 * the status to set
235 */
236 public void setStatus(PQueryStatus status) {
237 this.status = status;
238 }
239
240 public boolean isMutable() {
241 if (status == null) {
242 return query.isMutable();
243 } else {
244 return status.equals(PQueryStatus.UNINITIALIZED);
245 }
246 }
247
248 void checkMutability() {
249 if (status == null) {
250 query.checkMutability();
251 } else {
252 Preconditions.checkState(status.equals(PQueryStatus.UNINITIALIZED), "Initialized queries are not mutable");
253 }
254 }
255
256 /**
257 * Returns the disjunction the body is contained with. This disjunction may either be the
258 * {@link PQuery#getDisjunctBodies() canonical disjunction of the corresponding query} or something equivalent.
259 *
260 * @return the container disjunction of the body. Can be null if body is not in a disjunction yet.
261 */
262 public PDisjunction getContainerDisjunction() {
263 return containerDisjunction;
264 }
265
266 /**
267 * @param containerDisjunction the containerDisjunction to set
268 */
269 public void setContainerDisjunction(PDisjunction containerDisjunction) {
270 Preconditions.checkArgument(query.equals(containerDisjunction.getQuery()), "Disjunction of pattern %s incompatible with body %s", containerDisjunction.getQuery().getFullyQualifiedName(), query.getFullyQualifiedName());
271 Preconditions.checkState(this.containerDisjunction == null, "Disjunction is already set.");
272 this.containerDisjunction = containerDisjunction;
273 }
274
275 /**
276 * All unary input keys directly prescribed by constraints, grouped by variable.
277 * <p> to supertype inference or subsumption applied at this point.
278 */
279 public Map<PVariable, Set<TypeJudgement>> getAllUnaryTypeRestrictions(IQueryMetaContext context) {
280 Map<PVariable, Set<TypeJudgement>> currentRestrictions = allUnaryTypeRestrictions.get(context);
281 if (currentRestrictions == null) {
282 currentRestrictions = TypeHelper.inferUnaryTypes(getConstraints(), context);
283 allUnaryTypeRestrictions.put(context, currentRestrictions);
284 }
285 return currentRestrictions;
286 }
287 private WeakHashMap<IQueryMetaContext, Map<PVariable, Set<TypeJudgement>>> allUnaryTypeRestrictions = new WeakHashMap<IQueryMetaContext, Map<PVariable,Set<TypeJudgement>>>();
288
289}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PConstraint.java
new file mode 100644
index 00000000..ae2c4632
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PConstraint.java
@@ -0,0 +1,70 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem;
11
12import java.util.Comparator;
13import java.util.Map;
14import java.util.Set;
15
16import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
17import tools.refinery.viatra.runtime.matchers.psystem.analysis.QueryAnalyzer;
18
19/**
20 * @author Gabor Bergmann
21 *
22 */
23public interface PConstraint extends PTraceable {
24
25 /**
26 * @since 2.1
27 * @return the query body this constraint belongs to
28 */
29 public PBody getBody();
30
31 /**
32 * All variables affected by this constraint.
33 */
34 public Set<PVariable> getAffectedVariables();
35
36 /**
37 * The set of variables whose potential values can be enumerated (once all non-deduced variables have known values).
38 */
39 public Set<PVariable> getDeducedVariables();
40
41 /**
42 * A (preferably minimal) cover of known functional dependencies between variables.
43 * @noreference Use {@link QueryAnalyzer} instead to properly handle dependencies of pattern calls.
44 * @return non-trivial functional dependencies in the form of {variables} --> {variables}, where dependencies with the same lhs are unified.
45 */
46 public Map<Set<PVariable>,Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context);
47
48 public void replaceVariable(PVariable obsolete, PVariable replacement);
49
50 public void delete();
51
52 public void checkSanity();
53
54 /**
55 * Returns an integer ID that is guaranteed to increase strictly monotonously for constraints within a pBody.
56 */
57 public abstract int getMonotonousID();
58
59
60 /**
61 * A comparator that orders constraints by their {@link #getMonotonousID() monotonous identifiers}. Should only used
62 * for tiebreaking in other comparators.
63 *
64 * @since 2.0
65 */
66 public static final Comparator<PConstraint> COMPARE_BY_MONOTONOUS_ID = (arg0, arg1) -> arg0.getMonotonousID() - arg1.getMonotonousID();
67
68
69
70}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PTraceable.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PTraceable.java
new file mode 100644
index 00000000..f0241a9c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PTraceable.java
@@ -0,0 +1,16 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Dénes Harmath, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem;
10
11/**
12 * Marker interface for PSystem elements that can be traced.
13 * @since 1.6
14 */
15public interface PTraceable {
16}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PVariable.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PVariable.java
new file mode 100644
index 00000000..b6ea4861
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/PVariable.java
@@ -0,0 +1,203 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem;
11
12import java.util.HashSet;
13import java.util.Set;
14
15/**
16 * @author Gabor Bergmann
17 *
18 */
19public class PVariable {
20 private PBody pBody;
21 /**
22 * The name of the pattern variable. This is the unique key of the pattern node.
23 */
24 private String name;
25 /**
26 * virtual pVariables are nodes that do not correspond to actual pattern variables; they represent constants or Term
27 * substitutes
28 */
29 private boolean virtual;
30
31 /**
32 * Set of constraints that mention this variable
33 */
34 private Set<PConstraint> referringConstraints;
35
36 /**
37 * Determines whether there are any constraints that can deduce this variable
38 */
39 private Boolean deducable;
40
41 /**
42 * Another PVariable this variable has been unified into. Please use the other variable instead of this. Null iff
43 * this is still a first-class variable.
44 */
45 private PVariable unifiedInto;
46
47 PVariable(PBody pBody, String name) {
48 this(pBody, name, false);
49 }
50
51 PVariable(PBody pBody, String name, boolean virtual) {
52 super();
53 this.pBody = pBody;
54 this.name = name;
55 this.virtual = virtual;
56 // this.exportedParameter = false;
57 this.referringConstraints = new HashSet<PConstraint>();
58 this.unifiedInto = null;
59 this.deducable = false;
60 }
61
62 /**
63 * Replaces this variable with a given other, resulting in their unification. This variable will no longer be
64 * unique.
65 *
66 * @param replacement
67 */
68 public void unifyInto(PVariable replacement) {
69 pBody.checkMutability();
70 replacementCheck();
71 replacement = replacement.getUnifiedIntoRoot();
72
73 if (this.equals(replacement))
74 return;
75
76 if (!this.isVirtual() && replacement.isVirtual()) {
77 replacement.unifyInto(this);
78 } else {
79 // replacement.referringConstraints.addAll(this.referringConstraints);
80 // replacement.exportedParameter |= this.exportedParameter;
81 replacement.virtual &= this.virtual;
82 if (replacement.deducable != null && this.deducable != null)
83 replacement.deducable |= this.deducable;
84 else
85 replacement.deducable = null;
86 Set<PConstraint> snapshotConstraints = // avoid ConcurrentModificationX
87 new HashSet<PConstraint>(this.referringConstraints);
88 for (PConstraint constraint : snapshotConstraints) {
89 constraint.replaceVariable(this, replacement);
90 }
91 // replacementCheck() will fail from this point
92 this.unifiedInto = replacement;
93 pBody.noLongerUnique(this);
94 }
95 }
96
97 /**
98 * Determines whether there are any constraints that can deduce this variable
99 */
100 public boolean isDeducable() {
101 replacementCheck();
102 if (deducable == null) {
103 deducable = false;
104 for (PConstraint pConstraint : getReferringConstraints()) {
105 if (pConstraint.getDeducedVariables().contains(this)) {
106 deducable = true;
107 break;
108 }
109 }
110 }
111 return deducable;
112 }
113
114 /**
115 * Register that this variable is referred by the given constraint.
116 *
117 * @param constraint
118 */
119 public void refer(PConstraint constraint) {
120 pBody.checkMutability();
121 replacementCheck();
122 deducable = null;
123 referringConstraints.add(constraint);
124 }
125
126 /**
127 * Register that this variable is no longer referred by the given constraint.
128 *
129 * @param constraint
130 */
131 public void unrefer(PConstraint constraint) {
132 pBody.checkMutability();
133 replacementCheck();
134 deducable = null;
135 referringConstraints.remove(constraint);
136 }
137
138 /**
139 * @return the name of the pattern variable. This is the unique key of the pattern node.
140 */
141 public String getName() {
142 replacementCheck();
143 return name;
144 }
145
146 /**
147 * @return the virtual
148 */
149 public boolean isVirtual() {
150 replacementCheck();
151 return virtual;
152 }
153
154 /**
155 * @return the referringConstraints
156 */
157 public Set<PConstraint> getReferringConstraints() {
158 replacementCheck();
159 return referringConstraints;
160 }
161
162 @SuppressWarnings("unchecked")
163 public <ConstraintType> Set<ConstraintType> getReferringConstraintsOfType(Class<ConstraintType> constraintClass) {
164 replacementCheck();
165 Set<ConstraintType> result = new HashSet<ConstraintType>();
166 for (PConstraint pConstraint : referringConstraints) {
167 if (constraintClass.isInstance(pConstraint))
168 result.add((ConstraintType) pConstraint);
169 }
170 return result;
171 }
172
173 @Override
174 public String toString() {
175 // replacementCheck();
176 return name;// + ":PatternNode";
177 }
178
179 public PVariable getDirectUnifiedInto() {
180 return unifiedInto;
181 }
182
183 public PVariable getUnifiedIntoRoot() {
184 PVariable nextUnified = unifiedInto;
185 PVariable oldUnifiedInto = this;
186 while (nextUnified != null) {
187 oldUnifiedInto = nextUnified;
188 nextUnified = oldUnifiedInto.getDirectUnifiedInto();
189 }
190 return oldUnifiedInto; // unifiedInto;
191 }
192
193 public boolean isUnique() {
194 return unifiedInto == null;
195 }
196
197 private void replacementCheck() {
198 if (unifiedInto != null)
199 throw new IllegalStateException("Illegal usage of variable " + name + " which has been replaced with "
200 + unifiedInto.name);
201 }
202
203}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/TypeJudgement.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/TypeJudgement.java
new file mode 100644
index 00000000..4447b225
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/TypeJudgement.java
@@ -0,0 +1,153 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem;
10
11import java.util.Collection;
12import java.util.HashSet;
13import java.util.List;
14import java.util.Map;
15import java.util.stream.Collectors;
16import java.util.Set;
17
18import tools.refinery.viatra.runtime.matchers.context.IInputKey;
19import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
20import tools.refinery.viatra.runtime.matchers.context.InputKeyImplication;
21import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.TypeFilterConstraint;
22import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.TypeConstraint;
23import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
24import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
25
26/**
27 * A judgement that means that the given tuple of variables will represent a tuple of values that is a member of the extensional relation identified by the given input key.
28 * @author Bergmann Gabor
29 *
30 */
31public class TypeJudgement {
32
33 private IInputKey inputKey;
34 private Tuple variablesTuple;
35 /**
36 * @param inputKey
37 * @param variablesTuple
38 */
39 public TypeJudgement(IInputKey inputKey, Tuple variablesTuple) {
40 super();
41 this.inputKey = inputKey;
42 this.variablesTuple = variablesTuple;
43 }
44 public IInputKey getInputKey() {
45 return inputKey;
46 }
47 public Tuple getVariablesTuple() {
48 return variablesTuple;
49 }
50 @Override
51 public int hashCode() {
52 final int prime = 31;
53 int result = 1;
54 result = prime * result
55 + ((inputKey == null) ? 0 : inputKey.hashCode());
56 result = prime * result
57 + ((variablesTuple == null) ? 0 : variablesTuple.hashCode());
58 return result;
59 }
60 @Override
61 public boolean equals(Object obj) {
62 if (this == obj)
63 return true;
64 if (obj == null)
65 return false;
66 if (!(obj instanceof TypeJudgement))
67 return false;
68 TypeJudgement other = (TypeJudgement) obj;
69 if (inputKey == null) {
70 if (other.inputKey != null)
71 return false;
72 } else if (!inputKey.equals(other.inputKey))
73 return false;
74 if (variablesTuple == null) {
75 if (other.variablesTuple != null)
76 return false;
77 } else if (!variablesTuple.equals(other.variablesTuple))
78 return false;
79 return true;
80 }
81
82 public Set<TypeJudgement> getDirectlyImpliedJudgements(IQueryMetaContext context) {
83 Set<TypeJudgement> results = new HashSet<TypeJudgement>();
84 results.add(this);
85
86 Collection<InputKeyImplication> implications = context.getImplications(this.inputKey);
87 for (InputKeyImplication inputKeyImplication : implications) {
88 results.add(
89 transcribeImplication(inputKeyImplication)
90 );
91 }
92
93 return results;
94 }
95
96 /**
97 * @since 1.6
98 */
99 public Set<TypeJudgement> getWeakenedAlternativeJudgements(IQueryMetaContext context) {
100 Set<TypeJudgement> results = new HashSet<TypeJudgement>();
101
102 Collection<InputKeyImplication> implications = context.getWeakenedAlternatives(this.inputKey);
103 for (InputKeyImplication inputKeyImplication : implications) {
104 results.add(
105 transcribeImplication(inputKeyImplication)
106 );
107 }
108
109 return results;
110 }
111
112 /**
113 * @since 2.0
114 */
115 public Map<TypeJudgement, Set<TypeJudgement>> getConditionalImpliedJudgements(IQueryMetaContext context) {
116 return context.getConditionalImplications(this.inputKey).entrySet().stream().collect(Collectors.toMap(
117 entry -> transcribeImplication(entry.getKey()),
118 entry -> entry.getValue().stream().map(this::transcribeImplication).collect(Collectors.toSet())));
119 }
120
121
122
123 private TypeJudgement transcribeImplication(InputKeyImplication inputKeyImplication) {
124 return new TypeJudgement(
125 inputKeyImplication.getImpliedKey(),
126 transcribeVariablesToTuple(inputKeyImplication.getImpliedIndices())
127 );
128 }
129 private Tuple transcribeVariablesToTuple(List<Integer> indices) {
130 Object[] elements = new Object[indices.size()];
131 for (int i = 0; i < indices.size(); ++i)
132 elements[i] = variablesTuple.get(indices.get(i));
133 return Tuples.flatTupleOf(elements);
134 }
135
136 @Override
137 public String toString() {
138 return "TypeJudgement:" + inputKey.getPrettyPrintableName() + "@" + variablesTuple.toString();
139 }
140
141 /**
142 * Creates this judgement as a direct type constraint in the given PBody under construction.
143 * <p> pre: the variables tuple must be formed of variables of that PBody.
144 * @since 1.6
145 */
146 public PConstraint createConstraintFor(PBody pBody) {
147 if (inputKey.isEnumerable()) {
148 return new TypeConstraint(pBody, variablesTuple, inputKey);
149 } else {
150 return new TypeFilterConstraint(pBody, variablesTuple, inputKey);
151 }
152 }
153}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/VariableDeferredPConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/VariableDeferredPConstraint.java
new file mode 100644
index 00000000..8ea6bb93
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/VariableDeferredPConstraint.java
@@ -0,0 +1,40 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem;
11
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
15import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
16
17/**
18 * A kind of deferred constraint that can only be checked when a set of deferring variables are all present in a plan.
19 *
20 * @author Gabor Bergmann
21 *
22 */
23public abstract class VariableDeferredPConstraint extends DeferredPConstraint {
24
25 public VariableDeferredPConstraint(PBody pBody,
26 Set<PVariable> affectedVariables) {
27 super(pBody, affectedVariables);
28 }
29
30 public abstract Set<PVariable> getDeferringVariables();
31
32 /**
33 * Refine further if needed
34 */
35 @Override
36 public boolean isReadyAt(SubPlan plan, IQueryMetaContext context) {
37 return plan.getVisibleVariables().containsAll(getDeferringVariables());
38 }
39
40}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AbstractMemorylessAggregationOperator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AbstractMemorylessAggregationOperator.java
new file mode 100644
index 00000000..63a37bbe
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AbstractMemorylessAggregationOperator.java
@@ -0,0 +1,31 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.aggregations;
10
11/**
12 *
13 * An aggregation operator that does not store interim results beyond the final aggregated value.
14 * @author Gabor Bergmann
15 * @since 1.4
16 */
17public abstract class AbstractMemorylessAggregationOperator<Domain, AggregateResult>
18 implements IMultisetAggregationOperator<Domain, AggregateResult, AggregateResult>
19{
20
21 @Override
22 public AggregateResult getAggregate(AggregateResult result) {
23 return result;
24 }
25
26 @Override
27 public AggregateResult clone(AggregateResult original) {
28 return original;
29 }
30
31}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AggregatorType.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AggregatorType.java
new file mode 100644
index 00000000..4cc40a2b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/AggregatorType.java
@@ -0,0 +1,49 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.aggregations;
10
11import java.lang.annotation.ElementType;
12import java.lang.annotation.Inherited;
13import java.lang.annotation.Retention;
14import java.lang.annotation.RetentionPolicy;
15import java.lang.annotation.Target;
16
17import tools.refinery.viatra.runtime.matchers.aggregators.count;
18
19/**
20 * The aggregator type annotation describes the type constraints for the selected aggregator. In version 1.4, two kinds of
21 * aggregators are supported:
22 *
23 * <ol>
24 * <li>An aggregator that does not consider any parameter value from the call ({@link count}), just calculates the
25 * number of matches. This is represented by a single {@link Void} and a single corresponding return type.</li>
26 * <li>An aggregator that considers a single parameter from the call, and executes some aggregate operations over it.
27 * Such an aggregate operation can be defined over multiple types, where each possible parameter type has a corresponding return type declared.</li>
28 * </ol>
29 *
30 * <strong>Important!</strong> The parameterTypes and returnTypes arrays must have
31 * <ul>
32 * <li>The same number of classes defined each.</li>
33 * <li>Items are corresponded by index.</li>
34 * <li>Items should represent data types</li>
35 * </ul>
36 *
37 * @author Zoltan Ujhelyi
38 * @since 1.4
39 *
40 */
41@Target({ ElementType.TYPE })
42@Retention(RetentionPolicy.RUNTIME)
43@Inherited
44public @interface AggregatorType {
45
46 Class<?>[] parameterTypes();
47
48 Class<?>[] returnTypes();
49}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/BoundAggregator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/BoundAggregator.java
new file mode 100644
index 00000000..e6972544
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/BoundAggregator.java
@@ -0,0 +1,61 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.aggregations;
10
11import tools.refinery.viatra.runtime.matchers.context.IInputKey;
12import tools.refinery.viatra.runtime.matchers.context.common.JavaTransitiveInstancesKey;
13
14/**
15 * Augments an aggregator operator with type bindings for the type of values being aggregated and the aggregate result.
16 * <p> In case of <em>count</em>, the operator should be null.
17 * @author Gabor Bergmann
18 * @since 1.4
19 */
20public class BoundAggregator {
21 private final IMultisetAggregationOperator<?, ?, ?> operator;
22 private final Class<?> domainType;
23 private final Class<?> aggregateResultType;
24
25 public BoundAggregator(IMultisetAggregationOperator<?, ?, ?> operator,
26 Class<?> domainType,
27 Class<?> aggregateResultType) {
28 super();
29 this.operator = operator;
30 this.domainType = domainType;
31 this.aggregateResultType = aggregateResultType;
32 }
33
34 public IMultisetAggregationOperator<?, ?, ?> getOperator() {
35 return operator;
36 }
37
38 public Class<?> getDomainType() {
39 return domainType;
40 }
41
42 public Class<?> getAggregateResultType() {
43 return aggregateResultType;
44 }
45
46 public IInputKey getDomainTypeAsInputKey() {
47 return toJavaInputKey(domainType);
48 }
49
50 public IInputKey getAggregateResultTypeAsInputKey() {
51 return toJavaInputKey(aggregateResultType);
52 }
53
54 private static IInputKey toJavaInputKey(Class<?> type) {
55 if (type==null) {
56 return null;
57 } else {
58 return new JavaTransitiveInstancesKey(type);
59 }
60 }
61}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IAggregatorFactory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IAggregatorFactory.java
new file mode 100644
index 00000000..c970bd6a
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IAggregatorFactory.java
@@ -0,0 +1,40 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Zoltan Ujhelyi, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.aggregations;
10
11/**
12 *
13 * Describes an aggregation operator keyword, potentially with type polymorphism. The actual runtime
14 * {@link IMultisetAggregationOperator} that implements the aggregation logic may depend on the type context.
15 *
16 * <p>
17 * Implementors are suggested to use lower-case classnames (as it will end up in the language) and are required use the
18 * annotation {@link AggregatorType} to indicate type inference rules.
19 *
20 * <p>
21 * <strong>Important!</strong> Implemented aggregators must be (1) deterministic (2) pure and (3)support incremental
22 * value updates in the internal operation.
23 *
24 * @author Zoltan Ujhelyi
25 * @since 1.4
26 */
27
28public interface IAggregatorFactory {
29
30 /**
31 * Given type parameters selected from {@link AggregatorType} annotations, returns a run-time aggregator operator
32 * that is bound to the actual types.
33 *
34 * @param domainClass
35 * Java type of the values that are being aggregated
36 * @return the actual run-time aggregator logic, with type bindings
37 */
38 public BoundAggregator getAggregatorLogic(Class<?> domainClass);
39
40}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IMultisetAggregationOperator.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IMultisetAggregationOperator.java
new file mode 100644
index 00000000..3bc22274
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/aggregations/IMultisetAggregationOperator.java
@@ -0,0 +1,106 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.aggregations;
10
11import java.util.Collection;
12import java.util.stream.Stream;
13
14import tools.refinery.viatra.runtime.matchers.aggregators.ExtremumOperator;
15
16/**
17 * A single column aggregator is used to incrementally compute the aggregate of a multiset of values according to an aggregator operator.
18 *
19 * <p> The operator provides two methods of computation: <ul>
20 * <li>Stateless aggregation of an explicit multiset, provided by {@link #aggregateStatelessly(Collection)}.</li>
21 * <li>Incremental aggregation, provided by {@link #createNeutral()}, {@link #update(Object, Object, boolean)}, {@link #isNeutral(Object)}, {@link #getAggregate(Object)}.
22 * </ul>
23 *
24 * <p> In case of incremental computation, the aggregable multiset is conceptual; it is not represented by an explicit Collection<Domain> object, but its update operations are tracked.
25 *
26 * <p> In case of incremental computation, internal results, potentially distinct from the final aggregate result, may be stored in a helper data structure called <b>accumulator</b>.
27 * The goal of this distinction is that the final result may not be sufficient for incremental updates (see e.g. {@link ExtremumOperator}).
28 *
29 * @author Gabor Bergmann
30 *
31 * @param <Domain> the type of elements to be aggregated.
32 * @param <Accumulator> the type used to store the interim results of the aggregate computation,
33 * that may be incrementally refreshed upon updates to the multiset, and that can easily yield the final result.
34 * @param <AggregateResult> the type of the final result of the aggregation to be output.
35 *
36 * @since 1.4
37 */
38public interface IMultisetAggregationOperator<Domain, Accumulator, AggregateResult> {
39
40 /**
41 * A textual description of the operator.
42 */
43 String getShortDescription();
44
45 /**
46 * A name or identifier of the operator.
47 */
48 String getName();
49
50 /**
51 * @return the neutral element, i.e. the interim result of aggregating an empty multiset.
52 */
53 Accumulator createNeutral();
54
55 /**
56 * @return true if the interim result is equivalent to the neutral element, as if there are no values in the multiset.
57 * Must return true if the multiset is empty.
58 */
59 boolean isNeutral(Accumulator result);
60
61 /**
62 * @return an updated intermediate result,
63 * changed to reflect that a given object was added to / removed from the multiset
64 * (as indicated by the parameter isInsertion)
65 */
66 Accumulator update(Accumulator oldResult, Domain updateValue, boolean isInsertion);
67
68 /**
69 * @return the aggregate result obtained from the given intermediate result.
70 * May be null to indicate that the current multiset cannot be aggregated (e.g. 0 elements have no minimum).
71 */
72 AggregateResult getAggregate(Accumulator result);
73
74 /**
75 * Calculates the aggregate results from a given stream of values; all values are considered as inserted
76 * @return the aggregate result, or null if no result can be calculated (e.g. because of an empty stream)
77 * @since 2.0
78 */
79 AggregateResult aggregateStream(Stream<Domain> stream);
80
81 /**
82 * Clones the given accumulator (with all its internal contents).
83 */
84 default Accumulator clone(Accumulator original) {
85 throw new UnsupportedOperationException();
86 }
87
88 /**
89 * Combines the given aggregate result and accumulator into a single aggregate result.
90 */
91 default AggregateResult combine(AggregateResult left, Accumulator right) {
92 throw new UnsupportedOperationException();
93 }
94
95 default boolean contains(Domain value, Accumulator accumulator) {
96 throw new UnsupportedOperationException();
97 }
98
99 /**
100 * Pretty prints the contents of the given accumulator.
101 */
102 default String prettyPrint(final Accumulator accumulator) {
103 return accumulator.toString();
104 }
105
106}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/analysis/QueryAnalyzer.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/analysis/QueryAnalyzer.java
new file mode 100644
index 00000000..e3f28cff
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/analysis/QueryAnalyzer.java
@@ -0,0 +1,194 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.analysis;
10
11import java.util.HashMap;
12import java.util.HashSet;
13import java.util.Map;
14import java.util.Map.Entry;
15import java.util.Set;
16import java.util.stream.Collectors;
17
18import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
19import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
20import tools.refinery.viatra.runtime.matchers.planning.helpers.FunctionalDependencyHelper;
21import tools.refinery.viatra.runtime.matchers.psystem.PBody;
22import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
23import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
24import tools.refinery.viatra.runtime.matchers.psystem.annotations.PAnnotation;
25import tools.refinery.viatra.runtime.matchers.psystem.annotations.ParameterReference;
26import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExportedParameter;
27import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
28import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
29import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
30
31/**
32 * Object responsible for computing and caching static query analysis results.
33 * <p> Any client can instantiate this to statically analyze queries.
34 * Query backends should share an instance obtained via {@link IQueryBackendContext} to save resources.
35 * <p> Precondition: all involved queries must be initialized.
36 * @noinstantiate Considered unstable API; subject to change in future versions.
37 * Either use the analyzer provided by {@link IQueryBackendContext}, or anticipate
38 * potential future breakage when instantiating your own analyzer.
39 * @author Gabor Bergmann
40 * @since 1.5
41 */
42public final class QueryAnalyzer {
43
44 private IQueryMetaContext metaContext;
45
46 public QueryAnalyzer(IQueryMetaContext metaContext) {
47 this.metaContext = metaContext;
48 }
49
50 // Functional dependencies
51
52 /**
53 * Maps query and strictness to functional dependencies
54 */
55 private Map<PQuery, Map<Set<Integer>, Set<Integer>>> strictFunctionalDependencyGuarantees =
56 new HashMap<>();
57 private Map<PQuery, Map<Set<Integer>, Set<Integer>>> softFunctionalDependencyGuarantees =
58 new HashMap<>();
59
60 /**
61 * Functional dependency information, expressed on query parameters, that the match set of the query is guaranteed to respect.
62 * <p> The type dependencies shall be expressed on the <i>parameter index</i> integers, NOT the {@link PParameter} object.
63 * @return a non-null map of functional dependencies on parameters that can be processed by {@link FunctionalDependencyHelper}
64 * @param strict if true, only "hard" dependencies are taken into account that are strictly enforced by the model representation;
65 * if false, user-provided soft dependencies (@FunctionalDependency) are included as well, that are anticipated but not guaranteed by the storage mechanism;
66 * use true if superfluous dependencies may taint the correctness of a computation, false if they would merely impact performance
67 * @since 1.5
68 */
69 public Map<Set<Integer>, Set<Integer>> getProjectedFunctionalDependencies(PQuery query, boolean strict) {
70 Map<PQuery, Map<Set<Integer>, Set<Integer>>> guaranteeStore = strict ? strictFunctionalDependencyGuarantees : softFunctionalDependencyGuarantees;
71 Map<Set<Integer>, Set<Integer>> dependencies = guaranteeStore.get(query);
72 // Why not computeIfAbsent? See Bug 532507
73 // Invoked method #computeFunctionalDependencies may trigger functional dependency computation for called queries;
74 // and may thus recurs back into #getProjectedFunctionalDependencies, causing a ConcurrentModificationException
75 // if the called query has not been previously analyzed.
76 //
77 // Note: if patterns are recursive, the empty accumulator will be found in the store
78 // (this yields a safe lower estimate and guarantees termination for #getProjectedFunctionalDependencies)
79 // But this case probably will not occur due to recursive queries having a disjunction at some point,
80 // and thus ignored by #computeFunctionalDependencies
81 if (dependencies == null) {
82 dependencies = new HashMap<>(); // accumulator
83 guaranteeStore.put(query, dependencies);
84 computeFunctionalDependencies(dependencies, query, strict);
85 }
86 return dependencies;
87 }
88
89 private void computeFunctionalDependencies(Map<Set<Integer>, Set<Integer>> accumulator, PQuery query, boolean strict) {
90 Set<PBody> bodies = query.getDisjunctBodies().getBodies();
91 if (bodies.size() == 1) { // no support for recursion or disjunction
92
93 PBody body = bodies.iterator().next();
94
95 // collect parameter variables
96 Map<PVariable, Integer> parameters = body.getSymbolicParameters().stream()
97 .collect(Collectors.toMap(ExportedParameter::getParameterVariable,
98 param -> query.getParameters().indexOf(param.getPatternParameter())));
99
100 // collect all internal dependencies
101 Map<Set<PVariable>, Set<PVariable>> internalDependencies =
102 getFunctionalDependencies(body.getConstraints(), strict);
103
104 // project onto parameter variables
105 Map<Set<PVariable>, Set<PVariable>> projectedDeps =
106 FunctionalDependencyHelper.projectDependencies(internalDependencies, parameters.keySet());
107
108 // translate into indices
109 for (Entry<Set<PVariable>, Set<PVariable>> entry : projectedDeps.entrySet()) {
110 Set<Integer> left = new HashSet<Integer>();
111 Set<Integer> right = new HashSet<Integer>();
112 for (PVariable pVariable : entry.getKey()) {
113 left.add(parameters.get(pVariable));
114 }
115 for (PVariable pVariable : entry.getValue()) {
116 right.add(parameters.get(pVariable));
117 }
118 accumulator.put(left, right);
119 }
120
121 } else {
122 // Disjunctive case, no dependencies are inferred
123 // TODO: we can still salvage the intersection of dependencies IF
124 // - all bodies have disjoint match sets
125 // - and we avoid recursion
126 }
127
128 // add annotation-based soft dependencies (regardless of number of bodies)
129 if (!strict) {
130 outer:
131 for (PAnnotation annotation : query.getAnnotationsByName("FunctionalDependency")) {
132 Set<Integer> lefts = new HashSet<Integer>();
133 Set<Integer> rights = new HashSet<Integer>();
134
135 for (Object object : annotation.getAllValues("forEach")) {
136 ParameterReference parameter = (ParameterReference) object;
137 Integer position = query.getPositionOfParameter(parameter.getName());
138 if (position == null) continue outer;
139 lefts.add(position);
140 }
141 for (Object object : annotation.getAllValues("unique")) {
142 ParameterReference parameter = (ParameterReference) object;
143 Integer position = query.getPositionOfParameter(parameter.getName());
144 if (position == null) continue outer;
145 rights.add(position);
146 }
147
148 FunctionalDependencyHelper.includeDependency(accumulator, lefts, rights);
149 }
150 }
151 }
152
153 /**
154 * Functional dependency information, expressed on PVariables within a body, that the selected constraints imply.
155 * @return a non-null map of functional dependencies on PVariables that can be processed by {@link FunctionalDependencyHelper}
156 * @param constraints the set of constraints whose consequences will be analyzed
157 * @param strict if true, only "hard" dependencies are taken into account that are strictly enforced by the model representation;
158 * if false, user-provided soft dependencies (@FunctionalDependency) are included as well, that are anticipated but not guaranteed by the storage mechanism;
159 * use true if superfluous dependencies may taint the correctness of a computation, false if they would merely impact performance
160 * @since 1.5
161 */
162 public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(Set<? extends PConstraint> constraints, boolean strict) {
163 Map<Set<PVariable>, Set<PVariable>> accumulator = new HashMap<Set<PVariable>, Set<PVariable>>();
164 for (PConstraint pConstraint : constraints){
165 if (pConstraint instanceof PositivePatternCall) {
166 // use query analysis results instead
167 PositivePatternCall call = (PositivePatternCall) pConstraint;
168 PQuery query = call.getSupplierKey();
169 Map<Set<Integer>, Set<Integer>> paramDependencies = getProjectedFunctionalDependencies(query, strict);
170 for (Entry<Set<Integer>, Set<Integer>> entry : paramDependencies.entrySet()) {
171 Set<PVariable> lefts = new HashSet<PVariable>();
172 Set<PVariable> rights = new HashSet<PVariable>();
173
174 for (Integer index : entry.getKey()) {
175 lefts.add(call.getVariableInTuple(index));
176 }
177 for (Integer index : entry.getValue()) {
178 rights.add(call.getVariableInTuple(index));
179 }
180
181 FunctionalDependencyHelper.includeDependency(accumulator,
182 lefts, rights);
183 }
184 } else {
185 // delegate to PConstraint
186 FunctionalDependencyHelper.includeDependencies(accumulator,
187 pConstraint.getFunctionalDependencies(metaContext));
188 }
189 }
190 return accumulator;
191 }
192
193
194}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/PAnnotation.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/PAnnotation.java
new file mode 100644
index 00000000..c4fbe0e9
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/PAnnotation.java
@@ -0,0 +1,94 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.annotations;
10
11import java.util.List;
12import java.util.Optional;
13import java.util.Set;
14import java.util.function.BiConsumer;
15
16import org.eclipse.collections.api.multimap.MutableMultimap;
17import org.eclipse.collections.impl.multimap.list.FastListMultimap;
18
19/**
20 * A container describing query annotations
21 * @author Zoltan Ujhelyi
22 *
23 */
24public class PAnnotation {
25
26 private final String name;
27 private MutableMultimap<String, Object> attributes = FastListMultimap.newMultimap();
28
29 public PAnnotation(String name) {
30 this.name = name;
31
32 }
33
34 /**
35 * Adds an attribute to the annotation
36 * @param attributeName
37 * @param value
38 */
39 public void addAttribute(String attributeName, Object value) {
40 attributes.put(attributeName, value);
41 }
42
43 /**
44 * Return the name of the annotation
45 */
46 public String getName() {
47 return name;
48 }
49
50 /**
51 * Returns the value of the first occurrence of an attribute
52 * @param attributeName
53 * @return the attribute value, or null, if attribute is not available
54 * @since 2.0
55 */
56 public Optional<Object> getFirstValue(String attributeName) {
57 return getAllValues(attributeName).stream().findFirst();
58 }
59
60 /**
61 * Returns the value of the first occurrence of an attribute
62 * @param attributeName
63 * @return the attribute value, or null, if attribute is not available
64 * @since 2.0
65 */
66 public <T> Optional<T> getFirstValue(String attributeName, Class<T> clazz) {
67 return getAllValues(attributeName).stream().filter(clazz::isInstance).map(clazz::cast).findFirst();
68 }
69
70 /**
71 * Returns all values of a selected attribute
72 * @param attributeName
73 * @return a non-null, but possibly empty list of attributes
74 */
75 public List<Object> getAllValues(String attributeName) {
76 return attributes.get(attributeName).toList();
77 }
78
79 /**
80 * Executes a consumer over all attributes. A selected attribute name (key) can appear (and thus consumed) multiple times.
81 * @since 2.0
82 */
83 public void forEachValue(BiConsumer<String, Object> consumer) {
84 attributes.forEachKeyValue(consumer::accept);
85 }
86
87 /**
88 * Returns a set of all attribute names used in this annotation
89 * @since 2.1
90 */
91 public Set<String> getAllAttributeNames() {
92 return attributes.keySet().toSet();
93 }
94}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/ParameterReference.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/ParameterReference.java
new file mode 100644
index 00000000..c67e9046
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/annotations/ParameterReference.java
@@ -0,0 +1,30 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.annotations;
10
11/**
12 * An annotation parameter referencing a query parameter by name. Does not check whether the parameter exists.
13 *
14 * @author Zoltan Ujhelyi
15 *
16 */
17public class ParameterReference {
18
19 final String name;
20
21 public ParameterReference(String name) {
22 super();
23 this.name = name;
24 }
25
26 public String getName() {
27 return name;
28 }
29
30}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/AggregatorConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/AggregatorConstraint.java
new file mode 100644
index 00000000..56f86e89
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/AggregatorConstraint.java
@@ -0,0 +1,98 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
10
11import java.util.Collections;
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.Map;
15import java.util.Set;
16
17import tools.refinery.viatra.runtime.matchers.context.IInputKey;
18import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
19import tools.refinery.viatra.runtime.matchers.psystem.ITypeInfoProviderConstraint;
20import tools.refinery.viatra.runtime.matchers.psystem.PBody;
21import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
22import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
23import tools.refinery.viatra.runtime.matchers.psystem.aggregations.BoundAggregator;
24import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
25import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
26import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
27
28/**
29 * The PSystem representation of an aggregation.
30 *
31 * @author Tamas Szabo
32 * @since 1.4
33 */
34public class AggregatorConstraint extends PatternCallBasedDeferred implements ITypeInfoProviderConstraint {
35
36 protected PVariable resultVariable;
37 private BoundAggregator aggregator;
38 protected int aggregatedColumn;
39
40 public AggregatorConstraint(BoundAggregator aggregator, PBody pBody, Tuple actualParametersTuple, PQuery query,
41 PVariable resultVariable, int aggregatedColumn) {
42 super(pBody, actualParametersTuple, query, Collections.singleton(resultVariable));
43 this.resultVariable = resultVariable;
44 this.aggregatedColumn = aggregatedColumn;
45 this.aggregator = aggregator;
46 }
47
48 public int getAggregatedColumn() {
49 return this.aggregatedColumn;
50 }
51
52 public BoundAggregator getAggregator() {
53 return this.aggregator;
54 }
55
56 @Override
57 public Set<PVariable> getDeducedVariables() {
58 return Collections.singleton(resultVariable);
59 }
60
61 @Override
62 public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context) {
63 final Map<Set<PVariable>, Set<PVariable>> result = new HashMap<Set<PVariable>, Set<PVariable>>();
64 result.put(getDeferringVariables(), getDeducedVariables());
65 return result;
66 }
67
68 @Override
69 protected void doDoReplaceVariables(PVariable obsolete, PVariable replacement) {
70 if (resultVariable.equals(obsolete))
71 resultVariable = replacement;
72 }
73
74 @Override
75 protected Set<PVariable> getCandidateQuantifiedVariables() {
76 return actualParametersTuple.<PVariable> getDistinctElements();
77 }
78
79 @Override
80 protected String toStringRest() {
81 return query.getFullyQualifiedName() + "@" + actualParametersTuple.toString() + "->"
82 + resultVariable.toString();
83 }
84
85 public PVariable getResultVariable() {
86 return resultVariable;
87 }
88
89 @Override
90 public Set<TypeJudgement> getImpliedJudgements(IQueryMetaContext context) {
91 Set<TypeJudgement> result = new HashSet<TypeJudgement>();
92 IInputKey aggregateResultType = aggregator.getAggregateResultTypeAsInputKey();
93 if (aggregateResultType != null) {
94 result.add(new TypeJudgement(aggregateResultType, Tuples.staticArityFlatTupleOf(resultVariable)));
95 }
96 return result;
97 }
98}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/BaseTypeSafeConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/BaseTypeSafeConstraint.java
new file mode 100644
index 00000000..7bc949a8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/BaseTypeSafeConstraint.java
@@ -0,0 +1,99 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
11
12import java.util.Collections;
13import java.util.Set;
14import java.util.stream.Collectors;
15import java.util.stream.Stream;
16
17import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
18import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
19import tools.refinery.viatra.runtime.matchers.psystem.PBody;
20import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
21import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
22import tools.refinery.viatra.runtime.matchers.psystem.VariableDeferredPConstraint;
23
24/**
25 * @author Gabor Bergmann
26 *
27 */
28public abstract class BaseTypeSafeConstraint extends
29 VariableDeferredPConstraint {
30
31 protected Set<PVariable> inputVariables;
32 protected PVariable outputVariable;
33
34 public PVariable getOutputVariable() {
35 return outputVariable;
36 }
37
38 /**
39 * @param pBody
40 * @param inputVariables
41 * @param outputVariable null iff no output (check-only)
42 */
43 public BaseTypeSafeConstraint(PBody pBody,
44 Set<PVariable> inputVariables, final PVariable outputVariable) {
45 super(pBody,
46 (outputVariable == null) ?
47 inputVariables :
48 Stream.concat(inputVariables.stream(), Stream.of(outputVariable)).collect(Collectors.toSet())
49 );
50 this.inputVariables = inputVariables;
51 this.outputVariable = outputVariable;
52 }
53
54 @Override
55 public Set<PVariable> getDeducedVariables() {
56 if (outputVariable == null)
57 return Collections.emptySet();
58 else
59 return Collections.singleton(outputVariable);
60 }
61
62 @Override
63 public Set<PVariable> getDeferringVariables() {
64 return inputVariables;
65 }
66
67 @Override
68 public boolean isReadyAt(SubPlan plan, IQueryMetaContext context) {
69 if (super.isReadyAt(plan, context)) {
70 return checkTypeSafety(plan, context) == null;
71 }
72 return false;
73 }
74
75 /**
76 * Checks whether all type restrictions are already enforced on affected variables.
77 *
78 * @param plan
79 * @return a variable whose type safety is not enforced yet, or null if the plan is typesafe
80 */
81 public PVariable checkTypeSafety(SubPlan plan, IQueryMetaContext context) {
82 Set<TypeJudgement> impliedJudgements = plan.getAllImpliedTypeJudgements(context);
83
84 for (PVariable pVariable : inputVariables) {
85 Set<TypeJudgement> allTypeRestrictionsForVariable = pBody.getAllUnaryTypeRestrictions(context).get(pVariable);
86 if (allTypeRestrictionsForVariable != null && !impliedJudgements.containsAll(allTypeRestrictionsForVariable))
87 return pVariable;
88 }
89 return null;
90 }
91
92 @Override
93 protected void doReplaceVariable(PVariable obsolete, PVariable replacement) {
94 if (inputVariables.remove(obsolete))
95 inputVariables.add(replacement);
96 if (outputVariable == obsolete)
97 outputVariable = replacement;
98 }
99}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Equality.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Equality.java
new file mode 100644
index 00000000..b978b62c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Equality.java
@@ -0,0 +1,96 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
11
12import java.util.Collections;
13import java.util.HashMap;
14import java.util.HashSet;
15import java.util.Map;
16import java.util.Set;
17
18import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
19import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
20import tools.refinery.viatra.runtime.matchers.psystem.DeferredPConstraint;
21import tools.refinery.viatra.runtime.matchers.psystem.PBody;
22import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
23
24/**
25 * @author Gabor Bergmann
26 *
27 */
28public class Equality extends DeferredPConstraint {
29
30 private PVariable who;
31 private PVariable withWhom;
32
33 public Equality(PBody pBody, PVariable who, PVariable withWhom) {
34 super(pBody, buildSet(who, withWhom));
35 this.who = who;
36 this.withWhom = withWhom;
37 }
38
39 private static Set<PVariable> buildSet(PVariable who, PVariable withWhom) {
40 Set<PVariable> set = new HashSet<PVariable>();
41 set.add(who);
42 set.add(withWhom);
43 return set;
44 }
45
46 /**
47 * An equality is moot if it compares the a variable with itself.
48 *
49 * @return true, if the equality is moot
50 */
51 public boolean isMoot() {
52 return who.equals(withWhom);
53 }
54
55 @Override
56 public void doReplaceVariable(PVariable obsolete, PVariable replacement) {
57 if (obsolete.equals(who))
58 who = replacement;
59 if (obsolete.equals(withWhom))
60 withWhom = replacement;
61 }
62
63 @Override
64 protected String toStringRest() {
65 return who.getName() + "=" + withWhom.getName();
66 }
67
68 public PVariable getWho() {
69 return who;
70 }
71
72 public PVariable getWithWhom() {
73 return withWhom;
74 }
75
76 @Override
77 public Set<PVariable> getDeducedVariables() {
78 return Collections.emptySet();
79 }
80
81 @Override
82 public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context) {
83 final Map<Set<PVariable>, Set<PVariable>> result = new HashMap<Set<PVariable>, Set<PVariable>>();
84 result.put(Collections.singleton(who), Collections.singleton(withWhom));
85 result.put(Collections.singleton(withWhom), Collections.singleton(who));
86 return result;
87 }
88
89 @Override
90 public boolean isReadyAt(SubPlan plan, IQueryMetaContext context) {
91 return plan.getVisibleVariables().contains(who) && plan.getVisibleVariables().contains(withWhom);
92 // will be replaced by || if copierNode is available;
93 // until then, LayoutHelper.unifyVariablesAlongEqualities(PSystem<PatternDescription, StubHandle, Collector>) is
94 // recommended.
95 }
96}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExportedParameter.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExportedParameter.java
new file mode 100644
index 00000000..80706792
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExportedParameter.java
@@ -0,0 +1,108 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
11
12import java.util.Collections;
13import java.util.Set;
14
15import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
16import tools.refinery.viatra.runtime.matchers.psystem.PBody;
17import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
18import tools.refinery.viatra.runtime.matchers.psystem.VariableDeferredPConstraint;
19import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
20import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
21
22/**
23 * @author Gabor Bergmann
24 *
25 */
26public class ExportedParameter extends VariableDeferredPConstraint {
27 PVariable parameterVariable;
28 final String parameterName;
29 final PParameter patternParameter;
30
31 /**
32 * @since 1.4
33 */
34 public ExportedParameter(PBody pBody, PVariable parameterVariable, PParameter patternParameter) {
35 super(pBody, Collections.singleton(parameterVariable));
36 this.parameterVariable = parameterVariable;
37 this.patternParameter = patternParameter;
38 parameterName = patternParameter.getName();
39 }
40
41 @Override
42 public void doReplaceVariable(PVariable obsolete, PVariable replacement) {
43 if (obsolete.equals(parameterVariable))
44 parameterVariable = replacement;
45 }
46
47 @Override
48 protected String toStringRest() {
49 Object varName = parameterVariable.getName();
50 return parameterName.equals(varName) ? parameterName : parameterName + "(" + varName + ")";
51 }
52
53 @Override
54 public Set<PVariable> getDeducedVariables() {
55 return Collections.emptySet();
56 }
57
58 /**
59 * The name of the parameter; usually, it is expected that {@link #getParameterVariable()} is more useful, except
60 * maybe for debugging purposes.
61 *
62 * @return a non-null name of the parameter
63 */
64 public String getParameterName() {
65 return parameterName;
66 }
67
68 public PVariable getParameterVariable() {
69 return parameterVariable;
70 }
71
72 /**
73 * @since 1.4
74 */
75 public PParameter getPatternParameter() {
76 if (patternParameter == null) {
77 PQuery query = pBody.getPattern();
78 Integer index = query.getPositionOfParameter(parameterName);
79 if (index == null) {
80 throw new IllegalStateException(String.format("Pattern %s does not have a parameter named %s",
81 query.getFullyQualifiedName(), parameterName));
82 }
83 return query.getParameters().get(index);
84 } else {
85 return patternParameter;
86 }
87 }
88
89 @Override
90 public Set<PVariable> getDeferringVariables() {
91 return Collections.singleton(parameterVariable);
92 }
93
94 @Override
95 public void checkSanity() {
96 super.checkSanity();
97 if (!parameterVariable.isDeducable()) {
98 String[] args = { parameterName };
99 String msg = "Impossible to match pattern: "
100 + "exported pattern variable {1} can not be determined based on the pattern constraints. "
101 + "HINT: certain constructs (e.g. negative patterns or check expressions) cannot output symbolic parameters.";
102 String shortMsg = "Could not deduce value of parameter";
103 throw new QueryProcessingException(msg, args, shortMsg, null);
104 }
105
106 }
107
108}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExpressionEvaluation.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExpressionEvaluation.java
new file mode 100644
index 00000000..06688c36
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/ExpressionEvaluation.java
@@ -0,0 +1,80 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
10
11import java.util.ArrayList;
12import java.util.Collections;
13import java.util.LinkedHashSet;
14import java.util.Map;
15import java.util.Set;
16
17import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
18import tools.refinery.viatra.runtime.matchers.psystem.IExpressionEvaluator;
19import tools.refinery.viatra.runtime.matchers.psystem.PBody;
20import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
21import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
22
23/**
24 * @author Zoltan Ujhelyi
25 *
26 */
27public class ExpressionEvaluation extends BaseTypeSafeConstraint {
28
29 private IExpressionEvaluator evaluator;
30 private boolean isUnwinding;
31
32 public ExpressionEvaluation(PBody pBody, IExpressionEvaluator evaluator, PVariable outputVariable) {
33 this(pBody, evaluator, outputVariable, false);
34 }
35
36 /**
37 * @since 2.4
38 */
39 public ExpressionEvaluation(PBody pBody, IExpressionEvaluator evaluator, PVariable outputVariable,
40 boolean isUnwinding) {
41 super(pBody, getPVariablesOfExpression(pBody, evaluator), outputVariable);
42 this.evaluator = evaluator;
43 this.isUnwinding = isUnwinding;
44 }
45
46 /**
47 * @since 2.4
48 */
49 public boolean isUnwinding() {
50 return isUnwinding;
51 }
52
53 public IExpressionEvaluator getEvaluator() {
54 return evaluator;
55 }
56
57 @Override
58 protected String toStringRest() {
59 return Tuples.flatTupleOf(new ArrayList<PVariable>(inputVariables).toArray()).toString() + "|="
60 + evaluator.getShortDescription();
61 }
62
63 @Override
64 public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context) {
65 if (outputVariable == null)
66 return Collections.emptyMap();
67 else
68 return Collections.singletonMap(inputVariables, Collections.singleton(outputVariable));
69 }
70
71 private static Set<PVariable> getPVariablesOfExpression(PBody pBody, IExpressionEvaluator evaluator) {
72 // use a linked set, so that the variables will come in the order of the parameters
73 Set<PVariable> result = new LinkedHashSet<PVariable>();
74 for (String name : evaluator.getInputParameterNames()) {
75 PVariable variable = pBody.getOrCreateVariableByName(name);
76 result.add(variable);
77 }
78 return result;
79 }
80}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Inequality.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Inequality.java
new file mode 100644
index 00000000..5cac33dc
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/Inequality.java
@@ -0,0 +1,151 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
11
12import java.util.Arrays;
13import java.util.Collections;
14import java.util.HashSet;
15import java.util.Set;
16
17import tools.refinery.viatra.runtime.matchers.psystem.PBody;
18import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
19import tools.refinery.viatra.runtime.matchers.psystem.VariableDeferredPConstraint;
20
21/**
22 * @author Gabor Bergmann
23 *
24 */
25public class Inequality extends VariableDeferredPConstraint {
26
27 private PVariable who;
28 private PVariable withWhom;
29
30 /**
31 * The inequality constraint is weak if it can be ignored when who is the same as withWhom, or if any if them is
32 * undeducible.
33 */
34 private boolean weak;
35
36 public Inequality(PBody pBody, PVariable who, PVariable withWhom) {
37 this(pBody, who, withWhom, false);
38 }
39
40 public Inequality(PBody pBody, PVariable who, PVariable withWhom,
41 boolean weak) {
42 super(pBody, new HashSet<>(Arrays.asList(who, withWhom) ));
43 this.who = who;
44 this.withWhom = withWhom;
45 this.weak = weak;
46 }
47
48 // private Inequality(
49 // PSystem<PatternDescription, StubHandle, ?> pSystem,
50 // PVariable subject, Set<PVariable> inequals)
51 // {
52 // super(pSystem, include(inequals, subject));
53 // this.subject = subject;
54 // this.inequals = inequals;
55 // }
56
57 // private static HashSet<PVariable> include(Set<PVariable> inequals, PVariable subject) {
58 // HashSet<PVariable> hashSet = new HashSet<PVariable>(inequals);
59 // hashSet.add(subject);
60 // return hashSet;
61 // }
62
63 @Override
64 public Set<PVariable> getDeferringVariables() {
65 return getAffectedVariables();
66 }
67
68 // private static int[] mapIndices(Map<Object, Integer> variablesIndex, Set<PVariable> keys) {
69 // int[] result = new int[keys.size()];
70 // int k = 0;
71 // for (PVariable key : keys) {
72 // result[k++] = variablesIndex.get(key);
73 // }
74 // return result;
75 // }
76
77 // @Override
78 // public IFoldablePConstraint getIncorporator() {
79 // return incorporator;
80 // }
81 //
82 // @Override
83 // public void registerIncorporatationInto(IFoldablePConstraint incorporator) {
84 // this.incorporator = incorporator;
85 // }
86 //
87 // @Override
88 // public boolean incorporate(IFoldablePConstraint other) {
89 // if (other instanceof Inequality<?, ?>) {
90 // Inequality other2 = (Inequality) other;
91 // if (subject.equals(other2.subject)) {
92 // Set<PVariable> newInequals = new HashSet<PVariable>(inequals);
93 // newInequals.addAll(other2.inequals);
94 // return new Inequality<PatternDescription, StubHandle>(buildable, subject, newInequals);
95 // }
96 // } else return false;
97 // }
98
99 @Override
100 protected String toStringRest() {
101 return who.toString() + (isWeak() ? "!=?" : "!=") + withWhom.toString();
102 }
103
104 @Override
105 public void doReplaceVariable(PVariable obsolete, PVariable replacement) {
106 if (obsolete.equals(who))
107 who = replacement;
108 if (obsolete.equals(withWhom))
109 withWhom = replacement;
110 }
111
112 @Override
113 public Set<PVariable> getDeducedVariables() {
114 return Collections.emptySet();
115 }
116
117 /**
118 * The inequality constraint is weak if it can be ignored when who is the same as withWhom, or if any if them is
119 * undeducible.
120 *
121 * @return the weak
122 */
123 public boolean isWeak() {
124 return weak;
125 }
126
127 /**
128 * A weak inequality constraint is eliminable if who is the same as withWhom, or if any if them is undeducible.
129 */
130 public boolean isEliminable() {
131 return isWeak() && (who.equals(withWhom) || !who.isDeducable() || !withWhom.isDeducable());
132 }
133
134 /**
135 * Eliminates a weak inequality constraint if it can be ignored when who is the same as withWhom, or if any if them
136 * is undeducible.
137 */
138 public void eliminateWeak() {
139 if (isEliminable())
140 delete();
141 }
142
143 public PVariable getWho() {
144 return who;
145 }
146
147 public PVariable getWithWhom() {
148 return withWhom;
149 }
150
151}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/NegativePatternCall.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/NegativePatternCall.java
new file mode 100644
index 00000000..87d9d9fc
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/NegativePatternCall.java
@@ -0,0 +1,52 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
11
12import java.util.Collections;
13import java.util.Set;
14
15import tools.refinery.viatra.runtime.matchers.psystem.PBody;
16import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
17import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
19
20/**
21 * @author Gabor Bergmann
22 *
23 */
24public class NegativePatternCall extends PatternCallBasedDeferred {
25
26 public NegativePatternCall(PBody pBody, Tuple actualParametersTuple, PQuery query) {
27 super(pBody, actualParametersTuple, query);
28 }
29
30 @Override
31 public Set<PVariable> getDeducedVariables() {
32 return Collections.emptySet();
33 }
34
35 /**
36 * @return all variables that may potentially be quantified they are not used anywhere else
37 */
38 @Override
39 protected Set<PVariable> getCandidateQuantifiedVariables() {
40 return getAffectedVariables();
41 }
42
43 @Override
44 protected void doDoReplaceVariables(PVariable obsolete, PVariable replacement) {
45 }
46
47 @Override
48 protected String toStringRest() {
49 return "!" + query.getFullyQualifiedName() + "@" + actualParametersTuple.toString();
50 }
51
52}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternCallBasedDeferred.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternCallBasedDeferred.java
new file mode 100644
index 00000000..93eeffec
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternCallBasedDeferred.java
@@ -0,0 +1,118 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
11
12import java.util.Collections;
13import java.util.HashSet;
14import java.util.Set;
15
16import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
17import tools.refinery.viatra.runtime.matchers.psystem.IQueryReference;
18import tools.refinery.viatra.runtime.matchers.psystem.PBody;
19import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
20import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
21import tools.refinery.viatra.runtime.matchers.psystem.VariableDeferredPConstraint;
22import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
23import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
24
25/**
26 * @author Gabor Bergmann
27 *
28 */
29public abstract class PatternCallBasedDeferred extends VariableDeferredPConstraint implements IQueryReference {
30
31 protected Tuple actualParametersTuple;
32
33 protected abstract void doDoReplaceVariables(PVariable obsolete, PVariable replacement);
34
35 protected abstract Set<PVariable> getCandidateQuantifiedVariables();
36
37 protected PQuery query;
38 private Set<PVariable> deferringVariables;
39
40 public PatternCallBasedDeferred(PBody pBody, Tuple actualParametersTuple,
41 PQuery pattern, Set<PVariable> additionalAffectedVariables) {
42 super(pBody, union(actualParametersTuple.<PVariable> getDistinctElements(), additionalAffectedVariables));
43 this.actualParametersTuple = actualParametersTuple;
44 this.query = pattern;
45 }
46
47 public PatternCallBasedDeferred(PBody pBody, Tuple actualParametersTuple,
48 PQuery pattern) {
49 this(pBody, actualParametersTuple, pattern, Collections.<PVariable> emptySet());
50 }
51
52 private static Set<PVariable> union(Set<PVariable> a, Set<PVariable> b) {
53 Set<PVariable> result = new HashSet<PVariable>();
54 result.addAll(a);
55 result.addAll(b);
56 return result;
57 }
58
59 @Override
60 public Set<PVariable> getDeferringVariables() {
61 if (deferringVariables == null) {
62 deferringVariables = new HashSet<PVariable>();
63 for (PVariable var : getCandidateQuantifiedVariables()) {
64 if (var.isDeducable())
65 deferringVariables.add(var);
66 }
67 }
68 return deferringVariables;
69 }
70
71 @Override
72 public void checkSanity() {
73 super.checkSanity();
74 for (Object obj : this.actualParametersTuple.getDistinctElements()) {
75 PVariable var = (PVariable) obj;
76 if (!getDeferringVariables().contains(var)) {
77 // so this is a free variable of the NAC / aggregation?
78 for (PConstraint pConstraint : var.getReferringConstraints()) {
79 if (pConstraint != this
80 && !(pConstraint instanceof Equality && ((Equality) pConstraint).isMoot()))
81 throw new QueryProcessingException (
82 "Variable {1} of constraint {2} is not a positively determined part of the pattern, yet it is also affected by {3}.",
83 new String[] { var.toString(), this.toString(), pConstraint.toString() },
84 "Read-only variable can not be deduced", null);
85 }
86 }
87 }
88
89 }
90
91// public SubPlan getSidePlan(IOperationCompiler compiler) throws QueryPlannerException {
92// SubPlan sidePlan = compiler.patternCallPlan(actualParametersTuple, query);
93// sidePlan = BuildHelper.enforceVariableCoincidences(compiler, sidePlan);
94// return sidePlan;
95// }
96
97 @Override
98 protected void doReplaceVariable(PVariable obsolete, PVariable replacement) {
99 if (deferringVariables != null) {
100 // FAIL instead of hopeless attempt to fix
101 // if (deferringVariables.remove(obsolete)) deferringVariables.add(replacement);
102 throw new IllegalStateException("Cannot replace variables on " + this
103 + " when deferring variables have already been identified.");
104 }
105 actualParametersTuple = actualParametersTuple.replaceAll(obsolete, replacement);
106 doDoReplaceVariables(obsolete, replacement);
107 }
108
109 public Tuple getActualParametersTuple() {
110 return actualParametersTuple;
111 }
112
113 @Override
114 public PQuery getReferredQuery() {
115 return query;
116 }
117
118}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternMatchCounter.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternMatchCounter.java
new file mode 100644
index 00000000..0c40d91e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/PatternMatchCounter.java
@@ -0,0 +1,70 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
11
12import java.util.Collections;
13import java.util.HashMap;
14import java.util.Map;
15import java.util.Set;
16
17import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
18import tools.refinery.viatra.runtime.matchers.psystem.PBody;
19import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
20import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
21import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
22
23/**
24 * @author Gabor Bergmann
25 */
26public class PatternMatchCounter extends PatternCallBasedDeferred {
27
28 private PVariable resultVariable;
29
30 public PatternMatchCounter(PBody pBody, Tuple actualParametersTuple,
31 PQuery query, PVariable resultVariable) {
32 super(pBody, actualParametersTuple, query, Collections.singleton(resultVariable));
33 this.resultVariable = resultVariable;
34 }
35
36 @Override
37 public Set<PVariable> getDeducedVariables() {
38 return Collections.singleton(resultVariable);
39 }
40
41 @Override
42 public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context) {
43 final Map<Set<PVariable>, Set<PVariable>> result = new HashMap<Set<PVariable>, Set<PVariable>>();
44 result.put(getDeferringVariables(), getDeducedVariables());
45 return result;
46 }
47
48 @Override
49 protected void doDoReplaceVariables(PVariable obsolete, PVariable replacement) {
50 if (resultVariable.equals(obsolete))
51 resultVariable = replacement;
52 }
53
54 @Override
55 protected Set<PVariable> getCandidateQuantifiedVariables() {
56 return actualParametersTuple.<PVariable> getDistinctElements();
57 }
58
59
60 @Override
61 protected String toStringRest() {
62 return query.getFullyQualifiedName() + "@" + actualParametersTuple.toString() + "->"
63 + resultVariable.toString();
64 }
65
66 public PVariable getResultVariable() {
67 return resultVariable;
68 }
69
70} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/RelationEvaluation.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/RelationEvaluation.java
new file mode 100644
index 00000000..336a83fb
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/RelationEvaluation.java
@@ -0,0 +1,57 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2022, Tamas Szabo, GitHub
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
10
11import java.util.List;
12
13import tools.refinery.viatra.runtime.matchers.psystem.EnumerablePConstraint;
14import tools.refinery.viatra.runtime.matchers.psystem.IMultiQueryReference;
15import tools.refinery.viatra.runtime.matchers.psystem.IRelationEvaluator;
16import tools.refinery.viatra.runtime.matchers.psystem.PBody;
17import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
19
20/**
21 * A constraint which prescribes the evaluation of custom Java logic that takes an arbitrary number of input relations
22 * and produces one output relation. Contrast this to {@link ExpressionEvaluation}, which produces a single output value
23 * given an input tuple.
24 *
25 * The assumption is that the relation evaluation logic is not incremental, that is, it can only perform from-scratch
26 * computation of the output relation given the complete input relations. To this end, the relation evaluator always
27 * receives the complete input relations with all their contents as input. However, the evaluator engine makes sure that
28 * the output of the relation evaluation is at least "seemingly" incremental. This means that the underlying computation
29 * network computes the delta on the output compared to the previous output and only propagates the delta further.
30 *
31 * @author Tamas Szabo
32 *
33 * @since 2.8
34 *
35 */
36public class RelationEvaluation extends EnumerablePConstraint implements IMultiQueryReference {
37
38 private final IRelationEvaluator evaluator;
39 private final List<PQuery> inputQueries;
40
41 public RelationEvaluation(final PBody body, final Tuple variablesTuple, final List<PQuery> inputQueries,
42 final IRelationEvaluator evaluator) {
43 super(body, variablesTuple);
44 this.evaluator = evaluator;
45 this.inputQueries = inputQueries;
46 }
47
48 public IRelationEvaluator getEvaluator() {
49 return this.evaluator;
50 }
51
52 @Override
53 public List<PQuery> getReferredQueries() {
54 return this.inputQueries;
55 }
56
57}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/TypeFilterConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/TypeFilterConstraint.java
new file mode 100644
index 00000000..8b6e29ef
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicdeferred/TypeFilterConstraint.java
@@ -0,0 +1,105 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.basicdeferred;
10
11import java.util.Collections;
12import java.util.Map;
13import java.util.Set;
14
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
16import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
17import tools.refinery.viatra.runtime.matchers.psystem.ITypeConstraint;
18import tools.refinery.viatra.runtime.matchers.psystem.PBody;
19import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
20import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
21import tools.refinery.viatra.runtime.matchers.psystem.VariableDeferredPConstraint;
22import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.TypeConstraint;
23import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
24
25/**
26 * Represents a non-enumerable type constraint that asserts that values substituted for the given tuple of variables
27 * form a tuple that belongs to a (typically non-enumerable) extensional relation identified by an {@link IInputKey}.
28 *
29 * <p> The InputKey is typically not enumerable. If it is enumerable, use {@link TypeConstraint} instead, so that the PConstraint carries over the property of enumerability.
30 *
31 * @author Bergmann Gabor
32 *
33 */
34public class TypeFilterConstraint extends VariableDeferredPConstraint implements
35 ITypeConstraint {
36
37 private Tuple variablesTuple;
38 private IInputKey inputKey;
39
40 private TypeJudgement equivalentJudgement;
41
42
43 public TypeFilterConstraint(PBody pBody, Tuple variablesTuple, IInputKey inputKey) {
44 super(pBody, variablesTuple.<PVariable> getDistinctElements());
45 this.equivalentJudgement = new TypeJudgement(inputKey, variablesTuple);
46
47 this.variablesTuple = variablesTuple;
48 this.inputKey = inputKey;
49
50 if (variablesTuple.getSize() != inputKey.getArity())
51 throw new IllegalArgumentException(
52 this.getClass().getSimpleName() +
53 " applied for variable tuple " + variablesTuple + " having wrong arity for input key " +
54 inputKey);
55 }
56
57
58
59 public Tuple getVariablesTuple() {
60 return variablesTuple;
61 }
62
63 public IInputKey getInputKey() {
64 return inputKey;
65 }
66
67 @Override
68 public TypeJudgement getEquivalentJudgement() {
69 return equivalentJudgement;
70 }
71
72 @Override
73 protected void doReplaceVariable(PVariable obsolete, PVariable replacement) {
74 variablesTuple = variablesTuple.replaceAll(obsolete, replacement);
75 this.equivalentJudgement = new TypeJudgement(inputKey, variablesTuple);
76 }
77
78 @Override
79 public Set<TypeJudgement> getImpliedJudgements(IQueryMetaContext context) {
80 return Collections.singleton(equivalentJudgement);
81 }
82
83 @Override
84 public Set<PVariable> getDeducedVariables() {
85 return Collections.emptySet();
86 }
87
88 @Override
89 public Set<PVariable> getDeferringVariables() {
90 return getAffectedVariables();
91 }
92
93 @Override
94 protected String toStringRest() {
95 return inputKey.getPrettyPrintableName() + "@" + variablesTuple;
96 }
97
98 @Override
99 public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context) {
100 return TypeConstraintUtil.getFunctionalDependencies(context, inputKey, variablesTuple);
101 }
102
103
104
105}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/AbstractTransitiveClosure.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/AbstractTransitiveClosure.java
new file mode 100644
index 00000000..7bbf7118
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/AbstractTransitiveClosure.java
@@ -0,0 +1,44 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.basicenumerables;
10
11import java.util.Set;
12
13import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
14import tools.refinery.viatra.runtime.matchers.psystem.IQueryReference;
15import tools.refinery.viatra.runtime.matchers.psystem.ITypeInfoProviderConstraint;
16import tools.refinery.viatra.runtime.matchers.psystem.KeyedEnumerablePConstraint;
17import tools.refinery.viatra.runtime.matchers.psystem.PBody;
18import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
19import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
20import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
21
22/**
23 * @since 2.0
24 */
25public abstract class AbstractTransitiveClosure extends KeyedEnumerablePConstraint<PQuery> implements IQueryReference, ITypeInfoProviderConstraint {
26
27 public AbstractTransitiveClosure(PBody pBody, Tuple variablesTuple, PQuery supplierKey) {
28 super(pBody, variablesTuple, supplierKey);
29 }
30
31 @Override
32 public PQuery getReferredQuery() {
33 return supplierKey;
34 }
35
36 /**
37 * @since 1.3
38 */
39 @Override
40 public Set<TypeJudgement> getImpliedJudgements(IQueryMetaContext context) {
41 return PositivePatternCall.getTypesImpliedByCall(supplierKey, variablesTuple);
42 }
43
44} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryReflexiveTransitiveClosure.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryReflexiveTransitiveClosure.java
new file mode 100644
index 00000000..e3dae240
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryReflexiveTransitiveClosure.java
@@ -0,0 +1,57 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Zoltan Ujhelyi, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicenumerables;
11
12import tools.refinery.viatra.runtime.matchers.context.IInputKey;
13import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
14import tools.refinery.viatra.runtime.matchers.psystem.PBody;
15import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
16import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
17
18/**
19 * For a binary base pattern over an enumerable universe type, computes the reflexive transitive closure (base)*
20 *
21 * @author Gabor Bergmann, Zoltan Ujhelyi
22 * @since 2.0
23 */
24public class BinaryReflexiveTransitiveClosure extends AbstractTransitiveClosure {
25
26 private final IInputKey universeType;
27
28 public BinaryReflexiveTransitiveClosure(PBody pBody, Tuple variablesTuple,
29 PQuery pattern, IInputKey universeType) {
30 super(pBody, variablesTuple, pattern);
31 this.universeType = universeType;
32 }
33
34 @Override
35 protected String keyToString() {
36 return supplierKey.getFullyQualifiedName() + "*";
37 }
38
39 /**
40 * Returns the type whose instances should be returned as 0-long paths.
41 * @since 2.0
42 */
43 public IInputKey getUniverseType() {
44 return universeType;
45 }
46
47 @Override
48 public void checkSanity() {
49 if (!universeType.isEnumerable() || universeType.getArity() != 1) {
50 throw new QueryProcessingException(
51 String.format("Invalid universe type %s - it should be enumerable and must have an arity of 1.",
52 universeType.getPrettyPrintableName()),
53 pBody.getPattern());
54 }
55 }
56
57}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryTransitiveClosure.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryTransitiveClosure.java
new file mode 100644
index 00000000..716d043b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/BinaryTransitiveClosure.java
@@ -0,0 +1,33 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicenumerables;
11
12import tools.refinery.viatra.runtime.matchers.psystem.PBody;
13import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
14import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
15
16/**
17 * For a binary base pattern, computes the irreflexive transitive closure (base)+
18 *
19 * @author Gabor Bergmann
20 *
21 */
22public class BinaryTransitiveClosure extends AbstractTransitiveClosure {
23
24 public BinaryTransitiveClosure(PBody pBody, Tuple variablesTuple,
25 PQuery pattern) {
26 super(pBody, variablesTuple, pattern);
27 }
28
29 @Override
30 protected String keyToString() {
31 return supplierKey.getFullyQualifiedName() + "+";
32 }
33}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/Connectivity.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/Connectivity.java
new file mode 100644
index 00000000..10da2e21
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/Connectivity.java
@@ -0,0 +1,11 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.viatra.runtime.matchers.psystem.basicenumerables;
7
8public enum Connectivity {
9 WEAK,
10 STRONG;
11}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/ConstantValue.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/ConstantValue.java
new file mode 100644
index 00000000..251146c8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/ConstantValue.java
@@ -0,0 +1,57 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicenumerables;
11
12import java.util.Collections;
13import java.util.HashMap;
14import java.util.Map;
15import java.util.Set;
16
17import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
18import tools.refinery.viatra.runtime.matchers.psystem.KeyedEnumerablePConstraint;
19import tools.refinery.viatra.runtime.matchers.psystem.PBody;
20import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
21import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
22
23/**
24 * @author Gabor Bergmann
25 *
26 */
27public class ConstantValue extends KeyedEnumerablePConstraint<Object> {
28
29 private PVariable variable;
30
31 public ConstantValue(PBody pBody, PVariable variable, Object value) {
32 super(pBody, Tuples.staticArityFlatTupleOf(variable), value);
33 this.variable = variable;
34 }
35
36 @Override
37 protected String keyToString() {
38 return supplierKey.toString();
39 }
40
41 /**
42 * @since 1.7
43 */
44 public PVariable getVariable() {
45 return variable;
46 }
47
48 @Override
49 public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context) {
50 final Map<Set<PVariable>, Set<PVariable>> result = new HashMap<Set<PVariable>, Set<PVariable>>();
51 final Set<PVariable> emptySet = Collections.emptySet(); // a constant value is functionally determined by everything
52 result.put(emptySet, Collections.singleton(getVariableInTuple(0)));
53 return result;
54 }
55
56
57}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/PositivePatternCall.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/PositivePatternCall.java
new file mode 100644
index 00000000..25ab34b4
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/PositivePatternCall.java
@@ -0,0 +1,76 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.basicenumerables;
11
12import java.util.HashSet;
13import java.util.Set;
14
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
16import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
17import tools.refinery.viatra.runtime.matchers.psystem.IQueryReference;
18import tools.refinery.viatra.runtime.matchers.psystem.ITypeInfoProviderConstraint;
19import tools.refinery.viatra.runtime.matchers.psystem.KeyedEnumerablePConstraint;
20import tools.refinery.viatra.runtime.matchers.psystem.PBody;
21import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
22import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
23import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
24import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
25
26/**
27 * @author Gabor Bergmann
28 *
29 */
30public class PositivePatternCall extends KeyedEnumerablePConstraint<PQuery> implements IQueryReference, ITypeInfoProviderConstraint {
31
32 public PositivePatternCall(PBody pBody, Tuple variablesTuple,
33 PQuery pattern) {
34 super(pBody, variablesTuple, pattern);
35 }
36
37 @Override
38 protected String keyToString() {
39 return supplierKey.getFullyQualifiedName();
40 }
41
42 // Note: #getFunctionalDependencies is intentionally not implemented - use QueryAnalyzer instead!
43// @Override
44// public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context) {
45// return super.getFunctionalDependencies(context);
46// }
47
48 @Override
49 public PQuery getReferredQuery() {
50 return supplierKey;
51 }
52
53 @Override
54 public Set<TypeJudgement> getImpliedJudgements(IQueryMetaContext context) {
55 return getTypesImpliedByCall(supplierKey, variablesTuple);
56 }
57
58 /**
59 * @since 1.3
60 */
61 public static Set<TypeJudgement> getTypesImpliedByCall(PQuery calledQuery, Tuple actualParametersTuple) {
62 Set<TypeJudgement> result = new HashSet<TypeJudgement>();
63 for (TypeJudgement parameterJudgement : calledQuery.getTypeGuarantees()) {
64 IInputKey inputKey = parameterJudgement.getInputKey();
65 Tuple judgementIndexTuple = parameterJudgement.getVariablesTuple();
66
67 Object[] judgementVariables = new Object[judgementIndexTuple.getSize()];
68 for (int i=0; i<judgementVariables.length; ++i)
69 judgementVariables[i] = actualParametersTuple.get((int) judgementIndexTuple.get(i));
70
71 result.add(new TypeJudgement(inputKey, Tuples.flatTupleOf(judgementVariables)));
72 }
73 return result;
74 }
75
76}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/RepresentativeElectionConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/RepresentativeElectionConstraint.java
new file mode 100644
index 00000000..b97ff55f
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/RepresentativeElectionConstraint.java
@@ -0,0 +1,43 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.viatra.runtime.matchers.psystem.basicenumerables;
7
8import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
9import tools.refinery.viatra.runtime.matchers.psystem.*;
10import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
11import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
12
13import java.util.Set;
14
15public class RepresentativeElectionConstraint extends KeyedEnumerablePConstraint<PQuery>
16 implements IQueryReference, ITypeInfoProviderConstraint {
17 private final Connectivity connectivity;
18
19 public RepresentativeElectionConstraint(PBody pBody, Tuple variablesTuple, PQuery supplierKey,
20 Connectivity connectivity) {
21 super(pBody, variablesTuple, supplierKey);
22 this.connectivity = connectivity;
23 }
24
25 public Connectivity getConnectivity() {
26 return connectivity;
27 }
28
29 @Override
30 public PQuery getReferredQuery() {
31 return supplierKey;
32 }
33
34 @Override
35 public Set<TypeJudgement> getImpliedJudgements(IQueryMetaContext context) {
36 return PositivePatternCall.getTypesImpliedByCall(supplierKey, variablesTuple);
37 }
38
39 @Override
40 protected String keyToString() {
41 return supplierKey.getFullyQualifiedName() + "#" + connectivity + "#representative";
42 }
43}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/TypeConstraint.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/TypeConstraint.java
new file mode 100644
index 00000000..2ca54cc0
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/basicenumerables/TypeConstraint.java
@@ -0,0 +1,79 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.basicenumerables;
10
11import java.util.Collections;
12import java.util.Map;
13import java.util.Set;
14
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
16import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
17import tools.refinery.viatra.runtime.matchers.psystem.ITypeConstraint;
18import tools.refinery.viatra.runtime.matchers.psystem.KeyedEnumerablePConstraint;
19import tools.refinery.viatra.runtime.matchers.psystem.PBody;
20import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
21import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
22import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
23
24/**
25 * Represents an enumerable type constraint that asserts that values substituted for the given tuple of variables
26 * form a tuple that belongs to an enumerable extensional relation identified by an {@link IInputKey}.
27 *
28 * <p> The InputKey must be enumerable!
29 *
30 * @author Zoltan Ujhelyi
31 *
32 */
33public class TypeConstraint extends KeyedEnumerablePConstraint<IInputKey> implements ITypeConstraint {
34
35 private TypeJudgement equivalentJudgement;
36
37 public TypeConstraint(PBody pBody, Tuple variablesTuple, IInputKey inputKey) {
38 super(pBody, variablesTuple, inputKey);
39 this.equivalentJudgement = new TypeJudgement(inputKey, variablesTuple);
40
41 if (! inputKey.isEnumerable())
42 throw new IllegalArgumentException(
43 this.getClass().getSimpleName() +
44 " applicable for enumerable input keys only; received instead " +
45 inputKey);
46 if (variablesTuple.getSize() != inputKey.getArity())
47 throw new IllegalArgumentException(
48 this.getClass().getSimpleName() +
49 " applied for variable tuple " + variablesTuple + " having wrong arity for input key " +
50 inputKey);
51 }
52
53 @Override
54 protected String keyToString() {
55 return supplierKey.getPrettyPrintableName();
56 }
57
58 @Override
59 public TypeJudgement getEquivalentJudgement() {
60 return equivalentJudgement;
61 }
62
63 @Override
64 public Set<TypeJudgement> getImpliedJudgements(IQueryMetaContext context) {
65 return Collections.singleton(equivalentJudgement);
66 //return equivalentJudgement.getDirectlyImpliedJudgements(context);
67 }
68
69 @Override
70 public Map<Set<PVariable>, Set<PVariable>> getFunctionalDependencies(IQueryMetaContext context) {
71 return TypeConstraintUtil.getFunctionalDependencies(context, supplierKey, variablesTuple);
72 }
73
74 @Override
75 public void doReplaceVariable(PVariable obsolete, PVariable replacement) {
76 super.doReplaceVariable(obsolete, replacement);
77 this.equivalentJudgement = new TypeJudgement(getSupplierKey(), variablesTuple);
78 }
79} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/BasePQuery.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/BasePQuery.java
new file mode 100644
index 00000000..2c03a894
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/BasePQuery.java
@@ -0,0 +1,231 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11import java.util.ArrayList;
12import java.util.Collections;
13import java.util.HashSet;
14import java.util.List;
15import java.util.Objects;
16import java.util.Optional;
17import java.util.Set;
18import java.util.stream.Collectors;
19import java.util.stream.Stream;
20
21import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
22import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendFactory;
23import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
24import tools.refinery.viatra.runtime.matchers.context.IInputKey;
25import tools.refinery.viatra.runtime.matchers.psystem.PBody;
26import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
27import tools.refinery.viatra.runtime.matchers.psystem.annotations.PAnnotation;
28import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
29import tools.refinery.viatra.runtime.matchers.util.Preconditions;
30
31/**
32 * Default implementation of PQuery.
33 *
34 * @author Bergmann Gabor
35 */
36public abstract class BasePQuery implements PQuery {
37
38 protected PQueryStatus status = PQueryStatus.UNINITIALIZED;
39 /**
40 * @since 2.0
41 */
42 protected final PVisibility visibility;
43 protected List<PProblem> pProblems = new ArrayList<PProblem>();
44 private List<PAnnotation> annotations = new ArrayList<PAnnotation>();
45 private QueryEvaluationHint evaluationHints = new QueryEvaluationHint(null, (IQueryBackendFactory)null);
46 PDisjunction canonicalDisjunction;
47 private List<String> parameterNames = null; // Lazy initialization
48
49 /** For traceability only. */
50 private List<Object> wrappingQuerySpecifications = new ArrayList<Object>(1);
51
52 @Override
53 public Integer getPositionOfParameter(String parameterName) {
54 ensureInitialized();
55 int index = getParameterNames().indexOf(parameterName);
56 return index != -1 ? index : null;
57 }
58
59 protected void setStatus(PQueryStatus newStatus) {
60 this.status = newStatus;
61 }
62
63 protected void addError(PProblem problem) {
64 status = PQueryStatus.ERROR;
65 pProblems.add(problem);
66 }
67
68 @Override
69 public PQueryStatus getStatus() {
70 return status;
71 }
72
73 @Override
74 public List<PProblem> getPProblems() {
75 return Collections.unmodifiableList(pProblems);
76 }
77
78 @Override
79 public boolean isMutable() {
80 return status.equals(PQueryStatus.UNINITIALIZED) || status.equals(PQueryStatus.INITIALIZING);
81 }
82
83 @Override
84 public void checkMutability() {
85 Preconditions.checkState(isMutable(), "Cannot edit query definition %s", getFullyQualifiedName());
86 }
87
88 /**
89 * @since 1.5
90 */
91 public void setEvaluationHints(QueryEvaluationHint hints) {
92 checkMutability();
93 this.evaluationHints = hints;
94 }
95
96 @Override
97 public QueryEvaluationHint getEvaluationHints() {
98 ensureInitialized();
99 return evaluationHints;
100 // TODO instead of field, compute something from annotations?
101 }
102
103 protected void addAnnotation(PAnnotation annotation) {
104 checkMutability();
105 annotations.add(annotation);
106 }
107
108 @Override
109 public List<PAnnotation> getAllAnnotations() {
110 ensureInitialized();
111 return new ArrayList<>(annotations);
112 }
113
114 private Stream<PAnnotation> getAnnotationStreamByName(final String name) {
115 ensureInitialized();
116 return annotations.stream().filter(Objects::nonNull).filter(annotation -> Objects.equals(name, annotation.getName()));
117 }
118
119 @Override
120 public List<PAnnotation> getAnnotationsByName(final String annotationName) {
121 return getAnnotationStreamByName(annotationName).collect(Collectors.toList());
122 }
123
124 @Override
125 public Optional<PAnnotation> getFirstAnnotationByName(String annotationName) {
126 return getAnnotationStreamByName(annotationName).findFirst();
127 }
128
129 @Override
130 public List<String> getParameterNames() {
131 ensureInitialized();
132 if (parameterNames == null) {
133 parameterNames = getParameters().stream().map(PParameter::getName).collect(Collectors.toList());
134 }
135 return parameterNames;
136 }
137
138 @Override
139 public Set<PQuery> getDirectReferredQueries() {
140 ensureInitialized();
141 return canonicalDisjunction.getDirectReferredQueries();
142 }
143
144 @Override
145 public Set<PQuery> getAllReferredQueries() {
146 ensureInitialized();
147 return canonicalDisjunction.getAllReferredQueries();
148 }
149
150
151 @Override
152 public List<Object> publishedAs() {
153 return wrappingQuerySpecifications;
154 }
155
156 @Override
157 public Set<TypeJudgement> getTypeGuarantees() {
158 ensureInitialized();
159 Set<TypeJudgement> result = new HashSet<TypeJudgement>();
160
161 List<PParameter> parameters = getParameters();
162 for (int i=0; i<parameters.size(); ++i) {
163 PParameter parameter = parameters.get(i);
164 IInputKey declaredUnaryType = parameter.getDeclaredUnaryType();
165 if (declaredUnaryType != null) {
166 result.add(new TypeJudgement(declaredUnaryType, Tuples.staticArityFlatTupleOf(i)));
167 }
168 }
169
170 return result;
171 }
172
173 /**
174 * @since 2.0
175 */
176 public BasePQuery(PVisibility visibility) {
177 super();
178 this.visibility = visibility;
179 }
180
181 @Override
182 public PDisjunction getDisjunctBodies() {
183 ensureInitialized();
184 Preconditions.checkState(!status.equals(PQueryStatus.ERROR), "Query %s contains errors.", getFullyQualifiedName());
185 return canonicalDisjunction;
186 }
187
188 @Override
189 public final void ensureInitialized() {
190 try {
191 if (status.equals(PQueryStatus.UNINITIALIZED)) {
192 setStatus(PQueryStatus.INITIALIZING);
193 setBodies(doGetContainedBodies());
194 setStatus(PQueryStatus.OK);
195 }
196 } catch (QueryInitializationException e) {
197 addError(new PProblem(e, e.getShortMessage()));
198 throw e;
199 }
200 }
201
202 protected final void setBodies(Set<PBody> bodies) {
203 canonicalDisjunction = new PDisjunction(this, bodies);
204 for (PBody body : canonicalDisjunction.getBodies()) {
205 body.setStatus(null);
206 }
207 setStatus(PQueryStatus.OK);
208 }
209
210 /**
211 * Creates and returns the bodies of the query. If recalled again, a new instance is created.
212 *
213 * @return
214 * @throws ViatraQueryRuntimeException
215 */
216 protected abstract Set<PBody> doGetContainedBodies();
217
218 @Override
219 public String toString() {
220 return String.format("PQuery<%s>=%s", getFullyQualifiedName(), super.toString());
221 }
222
223 /**
224 * @since 2.0
225 */
226 @Override
227 public PVisibility getVisibility() {
228 return visibility;
229 }
230
231} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PDisjunction.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PDisjunction.java
new file mode 100644
index 00000000..eae4eacf
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PDisjunction.java
@@ -0,0 +1,104 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11import java.util.Collections;
12import java.util.LinkedHashSet;
13import java.util.Set;
14import java.util.stream.Collectors;
15
16import tools.refinery.viatra.runtime.matchers.psystem.PBody;
17
18/**
19 *
20 * A disjunction is a set of bodies representing separate conditions. A {@link PQuery} has a single, canonical
21 * PDisjunction, that can be replaced using rewriter
22 *
23 * @author Zoltan Ujhelyi
24 *
25 */
26public class PDisjunction {
27
28 private Set<PBody> bodies;
29 private PQuery query;
30
31 public PDisjunction(Set<PBody> bodies) {
32 this(bodies.iterator().next().getPattern(), bodies);
33 }
34
35 public PDisjunction(PQuery query, Set<PBody> bodies) {
36 super();
37 this.query = query;
38 this.bodies = Collections.unmodifiableSet(new LinkedHashSet<>(bodies));
39 this.bodies.forEach(body -> body.setContainerDisjunction(this));
40 }
41
42 /**
43 * Returns an immutable set of bodies that consists of this disjunction
44 *
45 * @return the bodies
46 */
47 public Set<PBody> getBodies() {
48 return bodies;
49 }
50
51 /**
52 * Returns the corresponding query specification. May be null if not set.
53 */
54 public PQuery getQuery() {
55 return query;
56 }
57
58 /**
59 * Returns all queries directly referred in the constraints. They are all required to evaluate this query
60 *
61 * @return a non-null, but possibly empty list of query definitions
62 */
63 public Set<PQuery> getDirectReferredQueries() {
64 return this.getBodies().stream().
65 flatMap(PQueries.directlyReferencedQueriesFunction()). // flatten stream of streams
66 collect(Collectors.toCollection(LinkedHashSet::new));
67 }
68
69 /**
70 * Returns all queries required to evaluate this query (transitively).
71 *
72 * @return a non-null, but possibly empty list of query definitions
73 */
74 public Set<PQuery> getAllReferredQueries() {
75 Set<PQuery> processedQueries = new LinkedHashSet<>();
76 processedQueries.add(this.getQuery());
77 Set<PQuery> foundQueries = getDirectReferredQueries();
78 Set<PQuery> newQueries = new LinkedHashSet<>(foundQueries);
79
80 while(!processedQueries.containsAll(newQueries)) {
81 PQuery query = newQueries.iterator().next();
82 processedQueries.add(query);
83 newQueries.remove(query);
84 Set<PQuery> referred = query.getDirectReferredQueries();
85 referred.removeAll(processedQueries);
86 foundQueries.addAll(referred);
87 newQueries.addAll(referred);
88 }
89 return foundQueries;
90 }
91
92 /**
93 * Decides whether a disjunction is mutable. A disjunction is mutable if all its contained bodies are mutable.
94 *
95 */
96 public boolean isMutable() {
97 for (PBody body : bodies) {
98 if (!body.isMutable()) {
99 return false;
100 }
101 }
102 return true;
103 }
104}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameter.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameter.java
new file mode 100644
index 00000000..07165aa2
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameter.java
@@ -0,0 +1,105 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11import java.util.Objects;
12
13import tools.refinery.viatra.runtime.matchers.context.IInputKey;
14
15/**
16 * A descriptor for declared PQuery parameters. A parameter has a name, a declared type and a direction constraint
17 *
18 * @author Zoltan Ujhelyi
19 *
20 */
21public class PParameter {
22
23 private final String name;
24 private final String typeName;
25 private final IInputKey declaredUnaryType;
26 private final PParameterDirection direction;
27
28 public PParameter(String name) {
29 this(name, (String) null);
30 }
31
32 public PParameter(String name, String typeName) {
33 this(name, typeName, (IInputKey) null);
34 }
35
36 public PParameter(String name, String typeName, IInputKey declaredUnaryType) {
37 this(name, typeName, declaredUnaryType, PParameterDirection.INOUT);
38 }
39
40 /**
41 * @since 1.4
42 */
43 public PParameter(String name, String typeName, IInputKey declaredUnaryType, PParameterDirection direction) {
44 super();
45 this.name = name;
46 this.typeName = typeName;
47 this.declaredUnaryType = declaredUnaryType;
48 this.direction = direction;
49
50 if (declaredUnaryType != null && declaredUnaryType.getArity() != 1) {
51 throw new IllegalArgumentException(
52 "PParameter declared type must be unary instead of " + declaredUnaryType.getPrettyPrintableName());
53 }
54 }
55
56 /**
57 * @return the direction
58 * @since 1.4
59 */
60 public PParameterDirection getDirection() {
61 return direction;
62 }
63
64 /**
65 * @return the name of the parameter
66 */
67 public String getName() {
68 return name;
69 }
70
71 /**
72 * Returns a textual representation of the declared type of the parameter
73 *
74 * @return the type description, or null if not available
75 */
76 public String getTypeName() {
77 return typeName;
78 }
79
80 /**
81 * Yield an {@link IInputKey} representation of the type declared for this parameter.
82 *
83 * @return the unary type that was declared on this parameter in the query header, or null if not available
84 */
85 public IInputKey getDeclaredUnaryType() {
86 return declaredUnaryType;
87 }
88
89 @Override
90 public boolean equals(Object obj) {
91 if (obj instanceof PParameter) {
92 return Objects.equals(name, ((PParameter) obj).name)
93 && Objects.equals(typeName, ((PParameter) obj).typeName)
94 && Objects.equals(declaredUnaryType, ((PParameter) obj).declaredUnaryType)
95 && Objects.equals(direction, ((PParameter) obj).direction);
96 }
97 return false;
98 }
99
100 @Override
101 public int hashCode() {
102 return Objects.hash(name, typeName, declaredUnaryType);
103 }
104
105}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameterDirection.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameterDirection.java
new file mode 100644
index 00000000..c94d4797
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PParameterDirection.java
@@ -0,0 +1,35 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11/**
12 * Values of this enum describe a constraint to the calling of patterns regarding its parameters.
13 *
14 * @author Grill Balázs
15 * @since 1.4
16 *
17 */
18public enum PParameterDirection {
19
20 /**
21 * Default value, no additional constraint is applied
22 */
23 INOUT,
24
25 /**
26 * The parameters marked with this constraints shall be set to a value before calling the pattern
27 */
28 IN,
29
30 /**
31 * The parameters marked with this constraints shall not be set to a value before calling the pattern
32 */
33 OUT
34
35}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PProblem.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PProblem.java
new file mode 100644
index 00000000..1fe4f541
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PProblem.java
@@ -0,0 +1,68 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
12
13/**
14 * Represents an error that was detected while the {@link PQuery} object was built from a source.
15 * @author Bergmann Gabor
16 *
17 */
18public class PProblem {
19
20 private final String shortMessage;
21 private final String location;
22 private final Exception exception;
23
24 public PProblem(String shortMessage) {
25 this(null, shortMessage, null, null);
26 }
27 /**
28 * @since 2.0
29 */
30 public PProblem(String shortMessage, Integer line, Integer column) {
31 this(null, shortMessage, line, column);
32 }
33 public PProblem(QueryProcessingException exception) {
34 this(exception, exception.getShortMessage(), null, null);
35 }
36 public PProblem(Exception exception, String shortMessage) {
37 this(exception, shortMessage, null, null);
38 }
39
40 /**
41 * @since 2.0
42 */
43 public PProblem(Exception exception, String shortMessage, Integer line, Integer column) {
44 this.shortMessage = shortMessage;
45 this.exception = exception;
46 if (line == null) {
47 location = "Unspecified location";
48 } else if (column == null) {
49 location = String.format("Line %d", line);
50 } else {
51 location = String.format("Line %d Column %d", line, column);
52 }
53 }
54
55 public String getShortMessage() {
56 return shortMessage;
57 }
58 public Exception getException() {
59 return exception;
60 }
61 /**
62 * @since 2.0
63 */
64 public String getLocation() {
65 return location;
66 }
67
68}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueries.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueries.java
new file mode 100644
index 00000000..56f8ca76
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueries.java
@@ -0,0 +1,110 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11import java.util.HashSet;
12import java.util.Set;
13import java.util.function.Function;
14import java.util.function.Predicate;
15import java.util.stream.Stream;
16
17import tools.refinery.viatra.runtime.matchers.context.IInputKey;
18import tools.refinery.viatra.runtime.matchers.psystem.IMultiQueryReference;
19import tools.refinery.viatra.runtime.matchers.psystem.ITypeConstraint;
20import tools.refinery.viatra.runtime.matchers.psystem.PBody;
21import tools.refinery.viatra.runtime.matchers.psystem.PTraceable;
22import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.TypeConstraint;
23import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery.PQueryStatus;
24
25/**
26 * Utility class for using PQueries in functional/streaming collection operations effectively
27 *
28 * @author Zoltan Ujhelyi
29 *
30 */
31public final class PQueries {
32
33 /**
34 * Hidden constructor for utility class
35 */
36 private PQueries() {
37 }
38
39 /**
40 * Predicate checking for the status of selected queries
41 *
42 */
43 public static Predicate<PQuery> queryStatusPredicate(final PQueryStatus status) {
44 return query -> query.getStatus().equals(status);
45 }
46
47 /**
48 * Enumerates referred queries (without duplicates) for the given body
49 */
50 public static Function<PBody, Stream<PQuery>> directlyReferencedQueriesFunction() {
51 return body -> (body.getConstraintsOfType(IMultiQueryReference.class).stream()
52 .flatMap(e -> e.getReferredQueries().stream()).distinct());
53 }
54
55 /**
56 * Enumerates directly referred extensional relations (without duplicates) in the canonical form of the given query
57 *
58 * @param enumerablesOnly
59 * only enumerable type constraints are considered
60 * @since 2.0
61 */
62 public static Stream<IInputKey> directlyRequiredTypesOfQuery(PQuery query, boolean enumerablesOnly) {
63 return directlyRequiredTypesOfDisjunction(query.getDisjunctBodies(), enumerablesOnly);
64 }
65
66 /**
67 * Enumerates directly referred extensional relations (without duplicates) for the given formulation of a query.
68 *
69 * @param enumerablesOnly
70 * only enumerable type constraints are considered
71 * @since 2.0
72 */
73 public static Stream<IInputKey> directlyRequiredTypesOfDisjunction(PDisjunction disjunctBodies,
74 boolean enumerablesOnly) {
75 Class<? extends ITypeConstraint> filterClass = enumerablesOnly ? TypeConstraint.class : ITypeConstraint.class;
76 return disjunctBodies.getBodies().stream().flatMap(body -> body.getConstraintsOfType(filterClass).stream())
77 .map(constraint -> constraint.getEquivalentJudgement().getInputKey()).distinct();
78 }
79
80 /**
81 * @since 1.4
82 */
83 public static Predicate<PParameter> parameterDirectionPredicate(final PParameterDirection direction) {
84 return input -> input.getDirection() == direction;
85 }
86
87 /**
88 * Returns all {@link PTraceable}s contained in the given {@link PQuery}: itself, its bodies and their constraints.
89 *
90 * @since 1.6
91 */
92 public static Set<PTraceable> getTraceables(PQuery query) {
93 final Set<PTraceable> traceables = new HashSet<>();
94 traceables.add(query);
95 query.getDisjunctBodies().getBodies().forEach(body -> {
96 traceables.add(body);
97 body.getConstraints().forEach(traceables::add);
98 });
99 return traceables;
100 }
101
102 /**
103 * Calculates the simple name related from a given qualified name by finding the part after the last '.' character.
104 *
105 * @since 2.0
106 */
107 public static String calculateSimpleName(String qualifiedName) {
108 return qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1);
109 }
110}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQuery.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQuery.java
new file mode 100644
index 00000000..a909c650
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQuery.java
@@ -0,0 +1,154 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11import java.util.List;
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.ViatraQueryRuntimeException;
15import tools.refinery.viatra.runtime.matchers.backend.IQueryBackend;
16import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendHintProvider;
17import tools.refinery.viatra.runtime.matchers.backend.QueryEvaluationHint;
18import tools.refinery.viatra.runtime.matchers.psystem.PBody;
19import tools.refinery.viatra.runtime.matchers.psystem.PTraceable;
20import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
21
22/**
23 * Internal representation of a query / graph pattern (using a constraint system formalism),
24 * to be interpreted by a query evaluator ({@link IQueryBackend}).
25 * End-users of VIATRA Query should access a query as an IQuerySpecification instead.
26 *
27 * <p>
28 * PQuerys are definitions of queries usable inside pattern descriptions. Such description always has (a non-null) name. The query
29 * itself is defined as a (non-empty) set of {@link PBody} instances, the result is the disjunction of the single
30 * {@link PBody} instances. </p>
31 * <p>
32 * A PQuery might be constructed from erroneous patterns or might be uninitialized - this is represented by its status.
33 *
34 * @author Zoltan Ujhelyi
35 * @since 0.8.0
36 * @noimplement This interface is not intended to be implemented by clients. Use {@link BasePQuery} as a base class instead.
37 */
38public interface PQuery extends PQueryHeader, PTraceable {
39
40 // TODO rewritten as / rewritten from traceability to PDisjunction?
41
42 /**
43 * @author Zoltan Ujhelyi
44 *
45 */
46 public enum PQueryStatus {
47 /**
48 * Marks that the query definition is not initialized
49 */
50 UNINITIALIZED,
51 /**
52 * Marks that the query definition is being initialized
53 * @since 1.4
54 */
55 INITIALIZING,
56 /**
57 * The query definition was successfully initialized
58 */
59 OK,
60 /**
61 * The query definition was initialized, but some issues were present
62 */
63 WARNING,
64 /**
65 * The query definition was not successfully initialized because of an error
66 */
67 ERROR
68 }
69
70 /**
71 * Returns all bodies associated with the query in their canonical form. If called multiple times, the same set with
72 * the same contents will be returned.
73 *
74 */
75 PDisjunction getDisjunctBodies();
76
77 /**
78 * Returns all queries directly referred in the constraints. They are all required to evaluate this query
79 *
80 * @return a non-null, but possibly empty list of query definitions
81 */
82 Set<PQuery> getDirectReferredQueries();
83
84 /**
85 * Returns all queries required to evaluate this query (transitively).
86 *
87 * @return a non-null, but possibly empty list of query definitions
88 */
89 Set<PQuery> getAllReferredQueries();
90
91 /**
92 * Returns the initialization status of the definition
93 *
94 */
95 PQueryStatus getStatus();
96
97 /**
98 * Returns a list describing the problems that were found in this query.
99 *
100 * <p> TODO: formulate invariant connecting {@link #getPProblems()} and {@link #getStatus()}.
101 *
102 * @return a non-null, but possibly empty list of problems
103 */
104 List<PProblem> getPProblems();
105
106 /**
107 * Before a modification operation is executed, a mutability check is performed (via the {@link #getStatus()}
108 * implementation, and in case of problems an {@link IllegalStateException} is thrown.
109 */
110 void checkMutability();
111
112 /**
113 * An option to check mutability of the query. It can be used to avoid getting an {@link IllegalStateException} by
114 * the execution of {@link #checkMutability()}.
115 *
116 * @return true if the query specification is still editable
117 */
118 boolean isMutable();
119
120 /**
121 * Optional hints regarding the query evaluation strategy, to be interpreted by the query engine.
122 * <p> To ensure the possibility of external overrides,
123 * the evaluation engine should not directly consult this field,
124 * but use an {@link IQueryBackendHintProvider} instead.
125 */
126 public QueryEvaluationHint getEvaluationHints();
127
128
129 /**
130 * Type information, expressed on query parameters, that all matches of the query are guaranteed to respect.
131 * <p> At the very minimum, this should include the declared types of the parameters.
132 * <p> The type judgement tuples shall contain the <i>parameter index</i>, NOT the {@link PParameter} object.
133 *
134 * @return a non-null set of type judgements that the query guarantees for its matches
135 */
136 public Set<TypeJudgement> getTypeGuarantees();
137
138 /**
139 * If the query definition is uninitialized, initializes it.
140 * @throws ViatraQueryRuntimeException if initialization of query specification fails
141 */
142 public abstract void ensureInitialized();
143
144 /**
145 * Returns the end-user query specification API objects that wrap this query.
146 *
147 * <p> Intended for traceability and debug purposes, not part of normal operation.
148 * Returned list is intended to be appended during query specification construction time.
149 *
150 * @return a non-null, but possibly empty list of query specification objects;
151 */
152 List<Object> publishedAs();
153
154} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueryHeader.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueryHeader.java
new file mode 100644
index 00000000..f3671934
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PQueryHeader.java
@@ -0,0 +1,101 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11import java.util.List;
12import java.util.Optional;
13
14import tools.refinery.viatra.runtime.matchers.psystem.annotations.PAnnotation;
15
16/**
17 * Represents header information (metainfo) about a query.
18 * <p> To be implemented both by IQuerySpecifications intended for end users,
19 * and the internal query representation {@link PQuery}.
20 *
21 *
22 * @author Bergmann Gabor
23 * @since 0.9
24 */
25public interface PQueryHeader {
26
27 /**
28 * Identifies the pattern for which matchers can be instantiated.
29 */
30 public String getFullyQualifiedName();
31
32 /**
33 * Return the list of parameter names
34 *
35 * @return a non-null, but possibly empty list of parameter names
36 */
37 public List<String> getParameterNames();
38
39 /**
40 * Returns a list of parameter descriptions
41 *
42 * @return a non-null, but possibly empty list of parameter descriptions
43 */
44 public List<PParameter> getParameters();
45
46 /**
47 * Returns the index of a named parameter
48 *
49 * @param parameterName
50 * @return the index, or null of no such parameter is available
51 */
52 public Integer getPositionOfParameter(String parameterName);
53
54 /**
55 * Returns a parameter by name if exists
56 * @since 2.1
57 */
58 default Optional<PParameter> getParameter(String parameterName) {
59 return Optional.ofNullable(getPositionOfParameter(parameterName))
60 .map(getParameters()::get);
61 }
62
63 /**
64 * Returns the list of annotations specified for this query
65 *
66 * @return a non-null, but possibly empty list of annotations
67 */
68 public List<PAnnotation> getAllAnnotations();
69
70 /**
71 * Returns the list of annotations with a specified name
72 *
73 * @param annotationName
74 * @return a non-null, but possibly empty list of annotations
75 */
76 public List<PAnnotation> getAnnotationsByName(String annotationName);
77
78 /**
79 * Returns the first annotation with a specified name
80 *
81 * @since 2.0
82 */
83 public Optional<PAnnotation> getFirstAnnotationByName(String annotationName);
84
85 /**
86 * Returns the visibility information about the query.
87 * @since 2.0
88 */
89 public PVisibility getVisibility();
90
91 /**
92 * Returns the non-qualified name of the query. By default this means returning the qualified name after the last
93 * '.' character.
94 *
95 * @since 2.0
96 */
97 public default String getSimpleName() {
98 return PQueries.calculateSimpleName(getFullyQualifiedName());
99 }
100
101} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PVisibility.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PVisibility.java
new file mode 100644
index 00000000..7cb312bd
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/PVisibility.java
@@ -0,0 +1,37 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11/**
12 * @author Zoltan Ujhelyi
13 * @since 2.0
14 *
15 */
16public enum PVisibility {
17
18 /**
19 * A public (default) visibility means a pattern can be called at any time.
20 */
21 PUBLIC,
22 /**
23 * A private query is not expected to be called directly, only by a different query matcher.
24 */
25 PRIVATE,
26 /**
27 * A query that is only used inside a single caller query and is not visible outside its container query. Such
28 * patterns must also fulfill the following additional constraints:
29 *
30 * <ul>
31 * <li>An embedded query must have only a single body.</li>
32 * <li>An embedded query must not be recursice.</li>
33 * </ul>
34 */
35 EMBEDDED
36
37}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/QueryInitializationException.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/QueryInitializationException.java
new file mode 100644
index 00000000..470d7287
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/queries/QueryInitializationException.java
@@ -0,0 +1,35 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.queries;
10
11import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
12
13/**
14 * Represent an exception that occurred while initializing the specification of a query.
15 * @author Bergmann Gabor
16 * @since 0.9
17 *
18 */
19public class QueryInitializationException extends QueryProcessingException {
20
21 public QueryInitializationException(String message, String[] context, String shortMessage, Object patternDescription,
22 Throwable cause) {
23 super(message, context, shortMessage, patternDescription, cause);
24 }
25
26 public QueryInitializationException(String message, String[] context, String shortMessage, Object patternDescription) {
27 super(message, context, shortMessage, patternDescription);
28 }
29
30 private static final long serialVersionUID = 9106033062252951489L;
31
32
33
34
35}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/AbstractRewriterTraceSource.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/AbstractRewriterTraceSource.java
new file mode 100644
index 00000000..276b2b42
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/AbstractRewriterTraceSource.java
@@ -0,0 +1,53 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import java.util.Objects;
12
13import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
14import tools.refinery.viatra.runtime.matchers.psystem.PTraceable;
15
16/**
17 * @since 1.6
18 *
19 */
20public class AbstractRewriterTraceSource {
21
22 private IRewriterTraceCollector traceCollector = NopTraceCollector.INSTANCE;
23
24 public void setTraceCollector(IRewriterTraceCollector traceCollector) {
25 this.traceCollector = Objects.requireNonNull(traceCollector);
26 }
27
28 public IPTraceableTraceProvider getTraces() {
29 return traceCollector;
30 }
31
32 protected IRewriterTraceCollector getTraceCollector() {
33 return traceCollector;
34 }
35
36 /**
37 * Mark the given derivative to be originated from the given original constraint.
38 * @since 1.6
39 */
40 protected void addTrace(PTraceable original, PTraceable derivative){
41 traceCollector.addTrace(original, derivative);
42 }
43
44 /**
45 * Indicate that the given derivative is removed from the resulting query, thus its trace
46 * information should be removed also.
47 * @since 1.6
48 */
49 protected void derivativeRemoved(PConstraint derivative, IDerivativeModificationReason reason){
50 traceCollector.derivativeRemoved(derivative, reason);
51 }
52
53}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/ConstraintRemovalReason.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/ConstraintRemovalReason.java
new file mode 100644
index 00000000..237a762d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/ConstraintRemovalReason.java
@@ -0,0 +1,23 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11/**
12 * Common reasons for removing constraint through rewriters
13 *
14 * @noreference This enum is not intended to be referenced by clients.
15 */
16public enum ConstraintRemovalReason implements IDerivativeModificationReason {
17
18 MOOT_EQUALITY,
19 WEAK_INEQUALITY_SELF_LOOP,
20 TYPE_SUBSUMED,
21 DUPLICATE
22
23}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/DefaultFlattenCallPredicate.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/DefaultFlattenCallPredicate.java
new file mode 100644
index 00000000..3b5d7390
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/DefaultFlattenCallPredicate.java
@@ -0,0 +1,23 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Marton Bur, Zoltan Ujhelyi, Akos Horvath, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
11
12/**
13 * @author Marton Bur
14 *
15 */
16public class DefaultFlattenCallPredicate implements IFlattenCallPredicate {
17
18 @Override
19 public boolean shouldFlatten(PositivePatternCall positivePatternCall) {
20 return true;
21 }
22
23}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/FlattenerCopier.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/FlattenerCopier.java
new file mode 100644
index 00000000..06b8d372
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/FlattenerCopier.java
@@ -0,0 +1,129 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Marton Bur, Akos Horvath, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import java.util.HashMap;
12import java.util.List;
13import java.util.Map;
14import java.util.Map.Entry;
15import java.util.Objects;
16import java.util.Set;
17import java.util.stream.Collectors;
18
19import tools.refinery.viatra.runtime.matchers.psystem.PBody;
20import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
21import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
22import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.Equality;
23import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExportedParameter;
24import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExpressionEvaluation;
25import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
26import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
27import tools.refinery.viatra.runtime.matchers.util.Preconditions;
28
29/**
30 * This rewriter class can add new equality constraints to the copied body
31 *
32 * @author Marton Bur
33 *
34 */
35class FlattenerCopier extends PBodyCopier {
36
37 private final Map<PositivePatternCall, CallInformation> calls;
38
39 private static class CallInformation {
40 final PBody body;
41 final Map<PVariable, PVariable> variableMapping;
42
43 private CallInformation(PBody body) {
44 this.body = body;
45 this.variableMapping = new HashMap<>();
46 }
47 }
48
49 public FlattenerCopier(PQuery query, Map<PositivePatternCall, PBody> callsToFlatten) {
50 super(query);
51 this.calls = callsToFlatten.entrySet().stream().collect(Collectors.toMap(Entry::getKey, entry -> new CallInformation(entry.getValue())));
52 }
53
54 protected void copyVariable(PositivePatternCall contextPatternCall, PVariable variable, String newName) {
55 PVariable newPVariable = body.getOrCreateVariableByName(newName);
56 calls.get(contextPatternCall).variableMapping.put(variable, newPVariable);
57 variableMapping.put(variable, newPVariable);
58 }
59
60 /**
61 * Merge all variables and constraints from the body called through the given pattern call to a target body. If
62 * multiple bodies are merged into a single one, use the renamer and filter options to avoid collisions.
63 *
64 * @param sourceBody
65 * @param namingTool
66 * @param filter
67 */
68 public void mergeBody(PositivePatternCall contextPatternCall, IVariableRenamer namingTool,
69 IConstraintFilter filter) {
70
71 PBody sourceBody = calls.get(contextPatternCall).body;
72
73 // Copy variables
74 Set<PVariable> allVariables = sourceBody.getAllVariables();
75 for (PVariable pVariable : allVariables) {
76 if (pVariable.isUnique()) {
77 copyVariable(contextPatternCall, pVariable,
78 namingTool.createVariableName(pVariable, sourceBody.getPattern()));
79 }
80 }
81
82 // Copy constraints which are not filtered
83 Set<PConstraint> constraints = sourceBody.getConstraints();
84 for (PConstraint pConstraint : constraints) {
85 if (!(pConstraint instanceof ExportedParameter) && !filter.filter(pConstraint)) {
86 copyConstraint(pConstraint);
87 }
88 }
89 }
90
91 @Override
92 protected void copyPositivePatternCallConstraint(PositivePatternCall positivePatternCall) {
93
94 if (!calls.containsKey(positivePatternCall)) {
95 // If the call was not flattened, copy the constraint
96 super.copyPositivePatternCallConstraint(positivePatternCall);
97 } else {
98 PBody calledBody = Objects.requireNonNull(calls.get(positivePatternCall).body);
99 Preconditions.checkArgument(positivePatternCall.getReferredQuery().equals(calledBody.getPattern()));
100
101 List<PVariable> symbolicParameters = calledBody.getSymbolicParameterVariables();
102 Object[] elements = positivePatternCall.getVariablesTuple().getElements();
103 for (int i = 0; i < elements.length; i++) {
104 // Create equality constraints between the caller PositivePatternCall and the corresponding body
105 // parameter variables
106 createEqualityConstraint((PVariable) elements[i], symbolicParameters.get(i), positivePatternCall);
107 }
108
109 }
110 }
111
112 private void createEqualityConstraint(PVariable pVariable1, PVariable pVariable2,
113 PositivePatternCall contextPatternCall) {
114 PVariable who = variableMapping.get(pVariable1);
115 PVariable withWhom = calls.get(contextPatternCall).variableMapping.get(pVariable2);
116 addTrace(contextPatternCall, new Equality(body, who, withWhom));
117 }
118
119 @Override
120 protected void copyExpressionEvaluationConstraint(final ExpressionEvaluation expressionEvaluation) {
121 Map<PVariable, PVariable> variableMapping = this.variableMapping.entrySet().stream()
122 .filter(input -> expressionEvaluation.getPSystem().getAllVariables().contains(input.getKey()))
123 .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
124
125 PVariable mappedOutputVariable = variableMapping.get(expressionEvaluation.getOutputVariable());
126 addTrace(expressionEvaluation, new ExpressionEvaluation(body, new VariableMappingExpressionEvaluatorWrapper(expressionEvaluation.getEvaluator(), variableMapping), mappedOutputVariable, expressionEvaluation.isUnwinding()));
127 }
128
129}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IConstraintFilter.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IConstraintFilter.java
new file mode 100644
index 00000000..518b9c64
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IConstraintFilter.java
@@ -0,0 +1,48 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Zoltan Ujhelyi, Marton Bur, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
12import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExportedParameter;
13
14/**
15 * Helper interface to exclude constraints from PBody copy processes
16 *
17 * @author Marton Bur
18 *
19 */
20public interface IConstraintFilter {
21 /**
22 * Returns true, if the given constraint should be filtered (thus should not be copied)
23 *
24 * @param constraint
25 * to check
26 * @return true, if the constraint should be filtered
27 */
28 boolean filter(PConstraint constraint);
29
30 public static class ExportedParameterFilter implements IConstraintFilter {
31
32 @Override
33 public boolean filter(PConstraint constraint) {
34 return constraint instanceof ExportedParameter;
35 }
36
37 }
38
39 public static class AllowAllFilter implements IConstraintFilter {
40
41 @Override
42 public boolean filter(PConstraint constraint) {
43 // Nothing is filtered
44 return false;
45 }
46
47 }
48} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IDerivativeModificationReason.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IDerivativeModificationReason.java
new file mode 100644
index 00000000..dbd6a78d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IDerivativeModificationReason.java
@@ -0,0 +1,19 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11/**
12 * This is a role indication interface, implementations may provide a reason about
13 * why a modification is made during PQuery normalization.
14 * @since 1.6
15 *
16 */
17public interface IDerivativeModificationReason {
18
19}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IFlattenCallPredicate.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IFlattenCallPredicate.java
new file mode 100644
index 00000000..7e224e98
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IFlattenCallPredicate.java
@@ -0,0 +1,50 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Marton Bur, Zoltan Ujhelyi, Akos Horvath, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
12
13
14/**
15 * Interface used by the PQueryFlattener to decide which positive pattern calls to flatten
16 *
17 * @author Marton Bur
18 *
19 */
20public interface IFlattenCallPredicate {
21
22 /**
23 * Decides whether the called query by the pattern call should be flattened into the caller or not.
24 *
25 * @param positivePatternCall
26 * the pattern call
27 * @return true if the call should be flattened
28 */
29 boolean shouldFlatten(PositivePatternCall positivePatternCall);
30
31 /**
32 * Flattens only if all operand predicates vote for flattening.
33 * @author Gabor Bergmann
34 * @since 2.1
35 */
36 public static class And implements IFlattenCallPredicate {
37 private IFlattenCallPredicate[] operands;
38 public And(IFlattenCallPredicate... operands) {
39 this.operands = operands;
40 }
41
42 @Override
43 public boolean shouldFlatten(PositivePatternCall positivePatternCall) {
44 for (IFlattenCallPredicate operand : operands) {
45 if (!operand.shouldFlatten(positivePatternCall)) return false;
46 }
47 return true;
48 }
49 }
50}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IPTraceableTraceProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IPTraceableTraceProvider.java
new file mode 100644
index 00000000..84da4d1b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IPTraceableTraceProvider.java
@@ -0,0 +1,55 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import java.util.stream.Stream;
12
13import tools.refinery.viatra.runtime.matchers.psystem.PTraceable;
14import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
15
16/**
17 * This interface provides methods to trace the {@link PTraceable}s of a transformed {@link PQuery} produced by
18 * a {@link PDisjunctionRewriter}. In case the associated rewriter is a composite (a.k.a. {@link PDisjunctionRewriterCacher}),
19 * this trace provider handles traces end-to-end, hiding all the intermediate transformation steps.
20 *
21 * @since 1.6
22 * @noimplement This interface is not intended to be implemented by clients.
23 */
24public interface IPTraceableTraceProvider {
25
26 /**
27 * Find and return the canonical {@link PTraceable}s in the original query which are the sources of the given derivative
28 * {@link PTraceable} according to the transformation.
29 *
30 * @param derivative a {@link PTraceable} which is contained by the {@link PQuery} produced by the associated rewriter
31 * @since 2.0
32 */
33 public Stream<PTraceable> getCanonicalTraceables(PTraceable derivative);
34
35 /**
36 * Find and return the {@link PTraceable}s in the rewritten query which are the destinations of the given source
37 * {@link PTraceable} according to the transformation.
38 *
39 * @param source a {@link PTraceable} which is contained by a {@link PQuery} before rewriting
40 * @since 2.0
41 */
42 public Stream<PTraceable> getRewrittenTraceables(PTraceable source);
43
44 /**
45 * Returns whether the given traceable element has been removed by every rewriter for a reason.
46 */
47 public boolean isRemoved(PTraceable traceable);
48
49 /**
50 * Returns the reasons for which the traceable element has been removed by the rewriters.
51 * @return the reasons of removal during rewriting
52 * @since 2.0
53 */
54 public Stream<IDerivativeModificationReason> getRemovalReasons(PTraceable traceable);
55}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IRewriterTraceCollector.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IRewriterTraceCollector.java
new file mode 100644
index 00000000..70771ea7
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IRewriterTraceCollector.java
@@ -0,0 +1,33 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import tools.refinery.viatra.runtime.matchers.psystem.PTraceable;
12
13/**
14 * This is the internal API of {@link IPTraceableTraceProvider} expected to be used by
15 * copier and rewriter implementations.
16 *
17 * @since 1.6
18 * @noreference This interface is not intended to be referenced by clients.
19 */
20public interface IRewriterTraceCollector extends IPTraceableTraceProvider {
21
22 /**
23 * Mark the given derivative to be originated from the given original constraint.
24 */
25 public void addTrace(PTraceable origin, PTraceable derivative);
26
27 /**
28 * Indicate that the given derivative is removed from the resulting query, thus its trace
29 * information should be removed also.
30 */
31 public void derivativeRemoved(PTraceable derivative, IDerivativeModificationReason reason);
32
33}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IVariableRenamer.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IVariableRenamer.java
new file mode 100644
index 00000000..ce446e0d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/IVariableRenamer.java
@@ -0,0 +1,59 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Zoltan Ujhelyi, Marton Bur, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
12import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
13
14/**
15 * Helper interface to ease the naming of the new variables during flattening
16 *
17 * @author Marton Bur
18 *
19 */
20public interface IVariableRenamer {
21 /**
22 * Creates a variable name based on a given variable and a given query. It only creates a String, doesn't set
23 * anything.
24 *
25 * @param pVariable
26 * @param query
27 * @return the new variable name as a String
28 */
29 String createVariableName(PVariable pVariable, PQuery query);
30
31 public class SameName implements IVariableRenamer {
32 @Override
33 public String createVariableName(PVariable pVariable, PQuery query) {
34 return pVariable.getName();
35 }
36 }
37
38 public class HierarchicalName implements IVariableRenamer {
39
40 private int callCount;
41
42 public void setCallCount(int callCount) {
43 this.callCount = callCount;
44 }
45
46 @Override
47 public String createVariableName(PVariable pVariable, PQuery query) {
48 // make sure to keep the "_" prefix before anonymous variables
49 String newVarName = getShortName(query) + "<" + callCount + ">" + "_" + pVariable.getName();
50 return pVariable.getName().startsWith("_") ? "_" + newVarName : newVarName ;
51 }
52
53 private String getShortName(PQuery query) {
54 String fullyQualifiedName = query.getFullyQualifiedName();
55 int beginIndex = fullyQualifiedName.lastIndexOf('.') + 1;
56 return fullyQualifiedName.substring(beginIndex);
57 }
58 }
59} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/MappingTraceCollector.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/MappingTraceCollector.java
new file mode 100644
index 00000000..7429fc60
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/MappingTraceCollector.java
@@ -0,0 +1,135 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import java.util.Collections;
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.LinkedList;
15import java.util.Map;
16import java.util.Queue;
17import java.util.Set;
18import java.util.function.Predicate;
19import java.util.stream.Stream;
20
21import tools.refinery.viatra.runtime.matchers.psystem.PTraceable;
22import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
23import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
24import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
25import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
26import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
27import tools.refinery.viatra.runtime.matchers.util.Preconditions;
28
29/**
30 * Multimap-based implementation to contain and query traces
31 *
32 * @since 1.6
33 *
34 */
35public class MappingTraceCollector implements IRewriterTraceCollector {
36
37 /**
38 * Traces from derivative to original
39 */
40 private final IMultiLookup<PTraceable, PTraceable> traces = CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, Object.class);
41
42 /**
43 * Traces from original to derivative
44 */
45 private final IMultiLookup<PTraceable, PTraceable> inverseTraces = CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, Object.class);
46
47 /**
48 * Reasons for removing {@link PTraceable}s
49 */
50 private final Map<PTraceable, IDerivativeModificationReason> removals = new HashMap<>();
51
52 /**
53 * Decides whether {@link PTraceable} is removed
54 */
55 private final Predicate<PTraceable> removed = removals::containsKey;
56
57 /**
58 * @since 2.0
59 */
60 @Override
61 public Stream<PTraceable> getCanonicalTraceables(PTraceable derivative) {
62 return findTraceEnds(derivative, traces).stream();
63 }
64
65 /**
66 * @since 2.0
67 */
68 @Override
69 public Stream<PTraceable> getRewrittenTraceables(PTraceable source) {
70 return findTraceEnds(source, inverseTraces).stream();
71 }
72
73 /**
74 * Returns the end of trace chains starting from the given {@link PTraceable} along the given trace edges.
75 */
76 private Set<PTraceable> findTraceEnds(PTraceable traceable, IMultiLookup<PTraceable, PTraceable> traceRecords) {
77 if (traceable instanceof PQuery) { // PQueries are preserved
78 return Collections.singleton(traceable);
79 }
80 Set<PTraceable> visited = new HashSet<>();
81 Set<PTraceable> result = new HashSet<>();
82 Queue<PTraceable> queue = new LinkedList<>();
83 queue.add(traceable);
84 while(!queue.isEmpty()){
85 PTraceable aDerivative = queue.poll();
86 // Track visited elements to avoid infinite loop via directed cycles in traces
87 visited.add(aDerivative);
88 IMemoryView<PTraceable> nextOrigins = traceRecords.lookup(aDerivative);
89 if (nextOrigins == null){
90 // End of trace chain
91 result.add(aDerivative);
92 } else {
93 // Follow traces
94 for(PTraceable nextOrigin : nextOrigins){
95 if (!visited.contains(nextOrigin)){
96 queue.add(nextOrigin);
97 }
98 }
99 }
100 }
101 return result;
102 }
103
104 @Override
105 public void addTrace(PTraceable original, PTraceable derivative){
106 traces.addPairOrNop(derivative, original);
107 inverseTraces.addPairOrNop(original, derivative);
108 // Even if this element was marked as removed earlier, now we replace it with another constraint!
109 removals.remove(original);
110 }
111
112 @Override
113 public void derivativeRemoved(PTraceable derivative, IDerivativeModificationReason reason){
114 Preconditions.checkState(!removals.containsKey(derivative), "Traceable %s removed multiple times", derivative);
115 // XXX the derivative must not be removed from the trace chain, as some rewriters, e.g. the normalizer keeps trace links to deleted elements
116 if (!inverseTraces.lookupExists(derivative)) {
117 // If there already exists a trace link, this removal means an update
118 removals.put(derivative, reason);
119 }
120 }
121
122 @Override
123 public boolean isRemoved(PTraceable traceable) {
124 return getRewrittenTraceables(traceable).allMatch(removed);
125 }
126
127 /**
128 * @since 2.0
129 */
130 @Override
131 public Stream<IDerivativeModificationReason> getRemovalReasons(PTraceable traceable) {
132 return getRewrittenTraceables(traceable).filter(removed).map(removals::get);
133 }
134
135}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NeverFlattenCallPredicate.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NeverFlattenCallPredicate.java
new file mode 100644
index 00000000..96c0b205
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NeverFlattenCallPredicate.java
@@ -0,0 +1,26 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
12
13/**
14 * @author Grill Balázs
15 * @since 1.4
16 *
17 */
18public class NeverFlattenCallPredicate implements IFlattenCallPredicate {
19
20
21 @Override
22 public boolean shouldFlatten(PositivePatternCall positivePatternCall) {
23 return false;
24 }
25
26}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NopTraceCollector.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NopTraceCollector.java
new file mode 100644
index 00000000..15cf577e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/NopTraceCollector.java
@@ -0,0 +1,68 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Grill Balázs, IncQueryLabs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import java.util.stream.Stream;
12
13import tools.refinery.viatra.runtime.matchers.psystem.PTraceable;
14
15/**
16 * This implementation does not store any traces and scales to NOP for every traceability feature.
17 * @since 1.6
18 *
19 */
20public class NopTraceCollector implements IRewriterTraceCollector {
21
22 public static final IRewriterTraceCollector INSTANCE = new NopTraceCollector();
23
24 private NopTraceCollector() {
25 // Private constructor to force using the common instance
26 }
27
28 /**
29 * @since 2.0
30 */
31 @Override
32 public Stream<PTraceable> getCanonicalTraceables(PTraceable derivative) {
33 return Stream.empty();
34 }
35
36 /**
37 * @since 2.0
38 */
39 @Override
40 public Stream<PTraceable> getRewrittenTraceables(PTraceable source) {
41 return Stream.empty();
42 }
43
44
45 @Override
46 public void addTrace(PTraceable origin, PTraceable derivative) {
47 // ignored
48 }
49
50 @Override
51 public void derivativeRemoved(PTraceable derivative, IDerivativeModificationReason reason) {
52 // ignored
53 }
54
55 @Override
56 public boolean isRemoved(PTraceable traceable) {
57 return false;
58 }
59
60 /**
61 * @since 2.0
62 */
63 @Override
64 public Stream<IDerivativeModificationReason> getRemovalReasons(PTraceable traceable) {
65 return Stream.empty();
66 }
67
68}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyCopier.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyCopier.java
new file mode 100644
index 00000000..10ab19c8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyCopier.java
@@ -0,0 +1,307 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Marton Bur, Akos Horvath, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools>
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v. 2.0 which is available at
6 * http://www.eclipse.org/legal/epl-v20.html.
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *******************************************************************************/
10package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
11
12import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
13import tools.refinery.viatra.runtime.matchers.psystem.EnumerablePConstraint;
14import tools.refinery.viatra.runtime.matchers.psystem.PBody;
15import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
16import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
17import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.*;
18import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.*;
19import tools.refinery.viatra.runtime.matchers.psystem.queries.PParameter;
20import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
21import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IConstraintFilter.AllowAllFilter;
22import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IVariableRenamer.SameName;
23import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
24import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
25
26import java.util.*;
27import java.util.stream.Collectors;
28
29/**
30 * This class can create a new PBody for a PQuery. The result body contains a copy of given variables and constraints.
31 *
32 * @author Marton Bur
33 *
34 */
35public class PBodyCopier extends AbstractRewriterTraceSource {
36
37 /**
38 * The created body
39 */
40 protected PBody body;
41 /**
42 * Mapping between the original and the copied variables
43 */
44 protected Map<PVariable, PVariable> variableMapping = new HashMap<>();
45
46 public Map<PVariable, PVariable> getVariableMapping() {
47 return variableMapping;
48 }
49
50 /**
51 * @since 1.6
52 */
53 public PBodyCopier(PBody body, IRewriterTraceCollector traceCollector) {
54 this.body = new PBody(body.getPattern());
55 setTraceCollector(traceCollector);
56
57 // do the actual copying
58 mergeBody(body);
59 }
60
61 /**
62 * @since 1.6
63 */
64 public PBodyCopier(PQuery query) {
65 this.body = new PBody(query);
66 }
67
68 public void mergeBody(PBody sourceBody) {
69 mergeBody(sourceBody, new SameName(), new AllowAllFilter());
70 }
71
72 /**
73 * Merge all variables and constraints from a source body to a target body. If multiple bodies are merged into a
74 * single one, use the renamer and filter options to avoid collisions.
75 */
76 public void mergeBody(PBody sourceBody, IVariableRenamer namingTool, IConstraintFilter filter) {
77
78 // Copy variables
79 Set<PVariable> allVariables = sourceBody.getAllVariables();
80 for (PVariable pVariable : allVariables) {
81 if (pVariable.isUnique()) {
82 copyVariable(pVariable, namingTool.createVariableName(pVariable, sourceBody.getPattern()));
83 }
84 }
85
86 // Copy exported parameters
87 this.body.setSymbolicParameters(sourceBody.getSymbolicParameters().stream()
88 .map(this::copyExportedParameterConstraint).collect(Collectors.toList()));
89
90 // Copy constraints which are not filtered
91 Set<PConstraint> constraints = sourceBody.getConstraints();
92 for (PConstraint pConstraint : constraints) {
93 if (!(pConstraint instanceof ExportedParameter) && !filter.filter(pConstraint)) {
94 copyConstraint(pConstraint);
95 }
96 }
97
98 // Add trace between original and copied body
99 addTrace(sourceBody, body);
100 }
101
102 protected void copyVariable(PVariable variable, String newName) {
103 PVariable newPVariable = body.getOrCreateVariableByName(newName);
104 variableMapping.put(variable, newPVariable);
105 }
106
107 /**
108 * Returns the body with the copied variables and constraints. The returned body is still uninitialized.
109 */
110 public PBody getCopiedBody() {
111 return body;
112 }
113
114 protected void copyConstraint(PConstraint constraint) {
115 if (constraint instanceof ExportedParameter) {
116 copyExportedParameterConstraint((ExportedParameter) constraint);
117 } else if (constraint instanceof Equality) {
118 copyEqualityConstraint((Equality) constraint);
119 } else if (constraint instanceof Inequality) {
120 copyInequalityConstraint((Inequality) constraint);
121 } else if (constraint instanceof TypeConstraint) {
122 copyTypeConstraint((TypeConstraint) constraint);
123 } else if (constraint instanceof TypeFilterConstraint) {
124 copyTypeFilterConstraint((TypeFilterConstraint) constraint);
125 } else if (constraint instanceof ConstantValue) {
126 copyConstantValueConstraint((ConstantValue) constraint);
127 } else if (constraint instanceof PositivePatternCall) {
128 copyPositivePatternCallConstraint((PositivePatternCall) constraint);
129 } else if (constraint instanceof NegativePatternCall) {
130 copyNegativePatternCallConstraint((NegativePatternCall) constraint);
131 } else if (constraint instanceof BinaryTransitiveClosure) {
132 copyBinaryTransitiveClosureConstraint((BinaryTransitiveClosure) constraint);
133 } else if (constraint instanceof RepresentativeElectionConstraint) {
134 copyRepresentativeElectionConstraint((RepresentativeElectionConstraint) constraint);
135 } else if (constraint instanceof RelationEvaluation) {
136 copyRelationEvaluationConstraint((RelationEvaluation) constraint);
137 } else if (constraint instanceof BinaryReflexiveTransitiveClosure) {
138 copyBinaryReflexiveTransitiveClosureConstraint((BinaryReflexiveTransitiveClosure) constraint);
139 } else if (constraint instanceof PatternMatchCounter) {
140 copyPatternMatchCounterConstraint((PatternMatchCounter) constraint);
141 } else if (constraint instanceof AggregatorConstraint) {
142 copyAggregatorConstraint((AggregatorConstraint) constraint);
143 } else if (constraint instanceof ExpressionEvaluation) {
144 copyExpressionEvaluationConstraint((ExpressionEvaluation) constraint);
145 } else {
146 throw new QueryProcessingException("Unknown PConstraint {0} encountered while copying PBody",
147 new String[] { constraint.getClass().getName() }, "Unknown PConstraint", body.getPattern());
148 }
149 }
150
151 protected ExportedParameter copyExportedParameterConstraint(ExportedParameter exportedParameter) {
152 PVariable mappedPVariable = variableMapping.get(exportedParameter.getParameterVariable());
153 PParameter parameter = exportedParameter.getPatternParameter();
154 ExportedParameter newExportedParameter;
155 newExportedParameter = new ExportedParameter(body, mappedPVariable, parameter);
156 body.getSymbolicParameters().add(newExportedParameter);
157 addTrace(exportedParameter, newExportedParameter);
158 return newExportedParameter;
159 }
160
161 protected void copyEqualityConstraint(Equality equality) {
162 PVariable who = equality.getWho();
163 PVariable withWhom = equality.getWithWhom();
164 addTrace(equality, new Equality(body, variableMapping.get(who), variableMapping.get(withWhom)));
165 }
166
167 protected void copyInequalityConstraint(Inequality inequality) {
168 PVariable who = inequality.getWho();
169 PVariable withWhom = inequality.getWithWhom();
170 addTrace(inequality, new Inequality(body, variableMapping.get(who), variableMapping.get(withWhom)));
171 }
172
173 protected void copyTypeConstraint(TypeConstraint typeConstraint) {
174 PVariable[] mappedVariables = extractMappedVariables(typeConstraint);
175 Tuple variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
176 addTrace(typeConstraint, new TypeConstraint(body, variablesTuple, typeConstraint.getSupplierKey()));
177 }
178
179 protected void copyTypeFilterConstraint(TypeFilterConstraint typeConstraint) {
180 PVariable[] mappedVariables = extractMappedVariables(typeConstraint);
181 Tuple variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
182 addTrace(typeConstraint, new TypeFilterConstraint(body, variablesTuple, typeConstraint.getInputKey()));
183 }
184
185 protected void copyConstantValueConstraint(ConstantValue constantValue) {
186 PVariable pVariable = (PVariable) constantValue.getVariablesTuple().getElements()[0];
187 addTrace(constantValue,
188 new ConstantValue(body, variableMapping.get(pVariable), constantValue.getSupplierKey()));
189 }
190
191 protected void copyPositivePatternCallConstraint(PositivePatternCall positivePatternCall) {
192 PVariable[] mappedVariables = extractMappedVariables(positivePatternCall);
193 Tuple variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
194 addTrace(positivePatternCall,
195 new PositivePatternCall(body, variablesTuple, positivePatternCall.getReferredQuery()));
196 }
197
198 protected void copyNegativePatternCallConstraint(NegativePatternCall negativePatternCall) {
199 PVariable[] mappedVariables = extractMappedVariables(negativePatternCall);
200 Tuple variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
201 addTrace(negativePatternCall,
202 new NegativePatternCall(body, variablesTuple, negativePatternCall.getReferredQuery()));
203 }
204
205 protected void copyBinaryTransitiveClosureConstraint(BinaryTransitiveClosure binaryTransitiveClosure) {
206 PVariable[] mappedVariables = extractMappedVariables(binaryTransitiveClosure);
207 Tuple variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
208 addTrace(binaryTransitiveClosure,
209 new BinaryTransitiveClosure(body, variablesTuple, binaryTransitiveClosure.getReferredQuery()));
210 }
211
212 protected void copyRepresentativeElectionConstraint(RepresentativeElectionConstraint constraint) {
213 var mappedVariables = extractMappedVariables(constraint);
214 var variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
215 addTrace(constraint, new RepresentativeElectionConstraint(body, variablesTuple, constraint.getReferredQuery(),
216 constraint.getConnectivity()));
217 }
218
219 /**
220 * @since 2.8
221 */
222 protected void copyRelationEvaluationConstraint(RelationEvaluation relationEvaluation) {
223 PVariable[] mappedVariables = extractMappedVariables(relationEvaluation);
224 Tuple variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
225 addTrace(relationEvaluation, new RelationEvaluation(body, variablesTuple, relationEvaluation.getReferredQueries(),
226 relationEvaluation.getEvaluator()));
227 }
228
229 /**
230 * @since 2.0
231 */
232 protected void copyBinaryReflexiveTransitiveClosureConstraint(
233 BinaryReflexiveTransitiveClosure binaryReflexiveTransitiveClosure) {
234 PVariable[] mappedVariables = extractMappedVariables(binaryReflexiveTransitiveClosure);
235 Tuple variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
236 addTrace(binaryReflexiveTransitiveClosure,
237 new BinaryReflexiveTransitiveClosure(body, variablesTuple,
238 binaryReflexiveTransitiveClosure.getReferredQuery(),
239 binaryReflexiveTransitiveClosure.getUniverseType()));
240 }
241
242 protected void copyPatternMatchCounterConstraint(PatternMatchCounter patternMatchCounter) {
243 PVariable[] mappedVariables = extractMappedVariables(patternMatchCounter);
244 PVariable mappedResultVariable = variableMapping.get(patternMatchCounter.getResultVariable());
245 Tuple variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
246 addTrace(patternMatchCounter, new PatternMatchCounter(body, variablesTuple,
247 patternMatchCounter.getReferredQuery(), mappedResultVariable));
248 }
249
250 /**
251 * @since 1.4
252 */
253 protected void copyAggregatorConstraint(AggregatorConstraint constraint) {
254 PVariable[] mappedVariables = extractMappedVariables(constraint);
255 PVariable mappedResultVariable = variableMapping.get(constraint.getResultVariable());
256 Tuple variablesTuple = Tuples.flatTupleOf((Object[]) mappedVariables);
257 addTrace(constraint, new AggregatorConstraint(constraint.getAggregator(), body, variablesTuple,
258 constraint.getReferredQuery(), mappedResultVariable, constraint.getAggregatedColumn()));
259 }
260
261 protected void copyExpressionEvaluationConstraint(ExpressionEvaluation expressionEvaluation) {
262 PVariable mappedOutputVariable = variableMapping.get(expressionEvaluation.getOutputVariable());
263 addTrace(expressionEvaluation, new ExpressionEvaluation(body,
264 new VariableMappingExpressionEvaluatorWrapper(expressionEvaluation.getEvaluator(), variableMapping),
265 mappedOutputVariable, expressionEvaluation.isUnwinding()));
266 }
267
268 /**
269 * For positive pattern calls
270 *
271 * @param positivePatternCall
272 * @return the mapped variables to the pattern's parameters
273 */
274 protected PVariable[] extractMappedVariables(EnumerablePConstraint enumerablePConstraint) {
275 Object[] pVariables = enumerablePConstraint.getVariablesTuple().getElements();
276 return mapVariableList(pVariables);
277 }
278
279 /**
280 * For negative and count pattern calls.
281 *
282 * @param patternMatchCounter
283 * @return the mapped variables to the pattern's parameters
284 */
285 private PVariable[] extractMappedVariables(PatternCallBasedDeferred patternCallBasedDeferred) {
286 Object[] pVariables = patternCallBasedDeferred.getActualParametersTuple().getElements();
287 return mapVariableList(pVariables);
288 }
289
290 /**
291 * For type filters.
292 */
293 private PVariable[] extractMappedVariables(TypeFilterConstraint typeFilterConstraint) {
294 Object[] pVariables = typeFilterConstraint.getVariablesTuple().getElements();
295 return mapVariableList(pVariables);
296 }
297
298 private PVariable[] mapVariableList(Object[] pVariables) {
299 List<PVariable> list = new ArrayList<PVariable>();
300 for (int i = 0; i < pVariables.length; i++) {
301 PVariable mappedVariable = variableMapping.get(pVariables[i]);
302 list.add(mappedVariable);
303 }
304 return list.toArray(new PVariable[0]);
305 }
306
307}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyNormalizer.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyNormalizer.java
new file mode 100644
index 00000000..90943129
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PBodyNormalizer.java
@@ -0,0 +1,310 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2010 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
11
12import java.util.ArrayList;
13import java.util.Collection;
14import java.util.Collections;
15import java.util.Comparator;
16import java.util.HashMap;
17import java.util.HashSet;
18import java.util.Iterator;
19import java.util.LinkedHashSet;
20import java.util.LinkedList;
21import java.util.List;
22import java.util.Map;
23import java.util.Queue;
24import java.util.Set;
25
26import tools.refinery.viatra.runtime.matchers.context.IInputKey;
27import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
28import tools.refinery.viatra.runtime.matchers.planning.QueryProcessingException;
29import tools.refinery.viatra.runtime.matchers.planning.helpers.TypeHelper;
30import tools.refinery.viatra.runtime.matchers.psystem.ITypeConstraint;
31import tools.refinery.viatra.runtime.matchers.psystem.ITypeInfoProviderConstraint;
32import tools.refinery.viatra.runtime.matchers.psystem.PBody;
33import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
34import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;
35import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.Equality;
36import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.Inequality;
37import tools.refinery.viatra.runtime.matchers.psystem.queries.PDisjunction;
38import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
39import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery.PQueryStatus;
40import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
41
42/**
43 * A disjunction rewriter for creating a normalized form of specification, unifying variables and running basic sanity
44 * checks. This rewriter does not copy but modifies directly the original specification, requiring a mutable
45 * disjunction.
46 *
47 * @author Gabor Bergmann
48 *
49 */
50public class PBodyNormalizer extends PDisjunctionRewriter {
51
52 private IQueryMetaContext context;
53
54 public PBodyNormalizer(IQueryMetaContext context) {
55 this.context = context;
56 }
57
58 /**
59 * Returns whether unary constraint elimination is enabled. This behavior can be customized by creating a subclass
60 * with a custom implementation.
61 *
62 * @since 1.6
63 */
64 protected boolean shouldCalculateImpliedTypes(PQuery query) {
65 return true;
66 }
67
68 /**
69 * Returns whether 'weakened alternative' suggestions of the context shall be expanded as additional PConstraints.
70 * This behavior can be customized by creating a subclass
71 * with a custom implementation.
72 *
73 * @since 1.6
74 */
75 protected boolean shouldExpandWeakenedAlternatives(PQuery query) {
76 return false;
77 }
78
79 @Override
80 public PDisjunction rewrite(PDisjunction disjunction) {
81 Set<PBody> normalizedBodies = new LinkedHashSet<>();
82 for (PBody body : disjunction.getBodies()) {
83 PBodyCopier copier = new PBodyCopier(body, getTraceCollector());
84 PBody modifiedBody = copier.getCopiedBody();
85 normalizeBody(modifiedBody);
86 normalizedBodies.add(modifiedBody);
87 modifiedBody.setStatus(PQueryStatus.OK);
88 }
89 return new PDisjunction(normalizedBodies);
90 }
91
92 public void setContext(IQueryMetaContext context) {
93 this.context = context;
94 }
95
96 /**
97 * Provides a normalized version of the pattern body. May return a different version than the original version if
98 * needed.
99 *
100 * @param body
101 */
102 public PBody normalizeBody(PBody body) {
103 try {
104 return normalizeBodyInternal(body);
105 } catch (QueryProcessingException e) {
106 throw new RewriterException("Error during rewriting: {1}", new String[] { e.getMessage() },
107 e.getShortMessage(), body.getPattern(), e);
108 }
109 }
110
111 PBody normalizeBodyInternal(PBody body) {
112 // UNIFICATION AND WEAK INEQUALITY ELIMINATION
113 unifyVariablesAlongEqualities(body);
114 eliminateWeakInequalities(body);
115 removeMootEqualities(body);
116
117 // ADDING WEAKENED ALTERNATIVES
118 if (shouldExpandWeakenedAlternatives(body.getPattern())) {
119 expandWeakenedAlternativeConstraints(body);
120 }
121
122 // CONSTRAINT ELIMINATION WITH TYPE INFERENCE
123 if (shouldCalculateImpliedTypes(body.getPattern())) {
124 eliminateInferrableTypes(body, context);
125 } else {
126 // ELIMINATE DUPLICATE TYPE CONSTRAINTS
127 eliminateDuplicateTypeConstraints(body);
128 }
129
130
131 // PREVENTIVE CHECKS
132 checkSanity(body);
133 return body;
134 }
135
136 private void removeMootEqualities(PBody body) {
137 Set<Equality> equals = body.getConstraintsOfType(Equality.class);
138 for (Equality equality : equals) {
139 if (equality.isMoot()) {
140 equality.delete();
141 derivativeRemoved(equality, ConstraintRemovalReason.MOOT_EQUALITY);
142 }
143 }
144 }
145
146 /**
147 * Unifies allVariables along equalities so that they can be handled as one.
148 *
149 * @param body
150 */
151 void unifyVariablesAlongEqualities(PBody body) {
152 Set<Equality> equals = body.getConstraintsOfType(Equality.class);
153 for (Equality equality : equals) {
154 if (!equality.isMoot()) {
155 equality.getWho().unifyInto(equality.getWithWhom());
156 }
157 }
158 }
159
160 /**
161 * Eliminates weak inequalities if they are not substantiated.
162 *
163 * @param body
164 */
165 void eliminateWeakInequalities(PBody body) {
166 for (Inequality inequality : body.getConstraintsOfType(Inequality.class)){
167 if (inequality.isEliminable()){
168 inequality.eliminateWeak();
169 derivativeRemoved(inequality, ConstraintRemovalReason.WEAK_INEQUALITY_SELF_LOOP);
170 }
171 }
172 }
173
174 /**
175 * Eliminates all type constraints that are inferrable from other constraints.
176 */
177 void eliminateInferrableTypes(final PBody body, IQueryMetaContext context) {
178 Set<TypeJudgement> subsumedByRetainedConstraints = new HashSet<TypeJudgement>();
179 LinkedList<ITypeConstraint> allTypeConstraints = new LinkedList<ITypeConstraint>();
180 for (PConstraint pConstraint : body.getConstraints()) {
181 if (pConstraint instanceof ITypeConstraint) {
182 allTypeConstraints.add((ITypeConstraint) pConstraint);
183 } else if (pConstraint instanceof ITypeInfoProviderConstraint) {
184 // non-type constraints are all retained
185 final Set<TypeJudgement> directJudgements = ((ITypeInfoProviderConstraint) pConstraint)
186 .getImpliedJudgements(context);
187 subsumedByRetainedConstraints = TypeHelper.typeClosure(subsumedByRetainedConstraints, directJudgements,
188 context);
189 }
190 }
191 Comparator<ITypeConstraint> eliminationOrder = (o1, o2) -> {
192 IInputKey type1 = o1.getEquivalentJudgement().getInputKey();
193 IInputKey type2 = o2.getEquivalentJudgement().getInputKey();
194
195 int result = context.getSuggestedEliminationOrdering().compare(type1, type2);
196 return (result == 0)
197 ? PConstraint.COMPARE_BY_MONOTONOUS_ID.compare(o1, o2)
198 : result;
199 };
200
201 Collections.sort(allTypeConstraints, eliminationOrder);
202 Queue<ITypeConstraint> potentialConstraints = allTypeConstraints; // rename for better comprehension
203
204 while (!potentialConstraints.isEmpty()) {
205 ITypeConstraint candidate = potentialConstraints.poll();
206
207 boolean isSubsumed = subsumedByRetainedConstraints.contains(candidate.getEquivalentJudgement());
208 if (!isSubsumed) {
209 Set<TypeJudgement> typeClosure = subsumedByRetainedConstraints;
210 for (ITypeConstraint subsuming : potentialConstraints) { // the remaining ones
211 final Set<TypeJudgement> directJudgements = subsuming.getImpliedJudgements(context);
212 typeClosure = TypeHelper.typeClosure(typeClosure, directJudgements, context);
213
214 if (typeClosure.contains(candidate.getEquivalentJudgement())) {
215 isSubsumed = true;
216 break;
217 }
218 }
219 }
220 if (isSubsumed) { // eliminated
221 candidate.delete();
222 derivativeRemoved(candidate, ConstraintRemovalReason.TYPE_SUBSUMED);
223 } else { // retained
224 subsumedByRetainedConstraints = TypeHelper.typeClosure(subsumedByRetainedConstraints,
225 candidate.getImpliedJudgements(context), context);
226 }
227 }
228 }
229
230 /**
231 * Inserts "weakened alternative" constraints suggested by the meta context that aid in coming up with a query plan.
232 */
233 void expandWeakenedAlternativeConstraints(PBody body) {
234 Set<TypeJudgement> allJudgements = new HashSet<TypeJudgement>();
235 Set<TypeJudgement> newJudgementsToAdd = new HashSet<TypeJudgement>();
236 Queue<TypeJudgement> judgementsToProcess = new LinkedList<TypeJudgement>();
237 Map<TypeJudgement, List<PConstraint>> traceability = CollectionsFactory.createMap();
238
239 for (ITypeConstraint typeConstraint : body.getConstraintsOfType(ITypeConstraint.class)) {
240 TypeJudgement equivalentJudgement = typeConstraint.getEquivalentJudgement();
241 judgementsToProcess.add(equivalentJudgement);
242 allJudgements.add(equivalentJudgement);
243 traceability.computeIfAbsent(equivalentJudgement, k-> new ArrayList<>()).add(typeConstraint);
244 }
245
246 while (!judgementsToProcess.isEmpty()) {
247 TypeJudgement judgement = judgementsToProcess.poll();
248 for (TypeJudgement alternativeJudgement : judgement.getWeakenedAlternativeJudgements(context)) {
249 if (allJudgements.add(alternativeJudgement)) {
250 newJudgementsToAdd.add(alternativeJudgement);
251 judgementsToProcess.add(alternativeJudgement);
252 traceability.merge(
253 alternativeJudgement,
254 traceability.getOrDefault(judgement, new ArrayList<>()),
255 (old,further) -> {old.addAll(further); return old;}
256 );
257 }
258 }
259 }
260
261 for (TypeJudgement typeJudgement : newJudgementsToAdd) {
262 PConstraint newConstraint = typeJudgement.createConstraintFor(body);
263 for (PConstraint source : traceability.getOrDefault(typeJudgement, Collections.emptyList())) {
264 addTrace(source, newConstraint);
265 }
266 }
267 }
268
269 private Object getConstraintKey(PConstraint constraint) {
270 if (constraint instanceof ITypeConstraint) {
271 return ((ITypeConstraint) constraint).getEquivalentJudgement();
272 }
273 // Do not check duplication for any other types
274 return constraint;
275 }
276
277 void eliminateDuplicateTypeConstraints(PBody body) {
278 Map<Object, PConstraint> constraints = new HashMap<>();
279 for (PConstraint constraint : body.getConstraints()) {
280 Object key = getConstraintKey(constraint);
281 // Retain first found instance of a constraint
282 if (!constraints.containsKey(key)) {
283 constraints.put(key, constraint);
284 }
285 }
286
287 // Retain collected constraints, remove everything else
288 Iterator<PConstraint> iterator = body.getConstraints().iterator();
289 Collection<PConstraint> toRetain = constraints.values();
290 while(iterator.hasNext()){
291 PConstraint next = iterator.next();
292 if (!toRetain.contains(next)){
293 derivativeRemoved(next, ConstraintRemovalReason.DUPLICATE);
294 iterator.remove();
295 }
296 }
297 }
298
299 /**
300 * Verifies the sanity of all constraints. Should be issued as a preventive check before layouting.
301 *
302 * @param body
303 * @throws RetePatternBuildException
304 */
305 void checkSanity(PBody body) {
306 for (PConstraint pConstraint : body.getConstraints())
307 pConstraint.checkSanity();
308 }
309
310}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriter.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriter.java
new file mode 100644
index 00000000..c844ccf7
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriter.java
@@ -0,0 +1,27 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import tools.refinery.viatra.runtime.matchers.psystem.queries.PDisjunction;
12import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
13
14/**
15 * An abstract base class for creating alternative representations for PDisjunctions.
16 * @author Zoltan Ujhelyi
17 *
18 */
19public abstract class PDisjunctionRewriter extends AbstractRewriterTraceSource{
20
21 public abstract PDisjunction rewrite(PDisjunction disjunction);
22
23 public PDisjunction rewrite(PQuery query) {
24 return rewrite(query.getDisjunctBodies());
25 }
26
27}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriterCacher.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriterCacher.java
new file mode 100644
index 00000000..eb5422ca
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PDisjunctionRewriterCacher.java
@@ -0,0 +1,64 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import java.util.ArrayList;
12import java.util.Arrays;
13import java.util.Collections;
14import java.util.List;
15import java.util.WeakHashMap;
16
17import tools.refinery.viatra.runtime.matchers.psystem.queries.PDisjunction;
18
19/**
20 * A rewriter that stores the previously computed results of a rewriter or a rewriter chain.
21 *
22 * @author Zoltan Ujhelyi
23 * @since 1.0
24 */
25public class PDisjunctionRewriterCacher extends PDisjunctionRewriter {
26
27 private final List<PDisjunctionRewriter> rewriterChain;
28 private WeakHashMap<PDisjunction, PDisjunction> cachedResults =
29 new WeakHashMap<PDisjunction, PDisjunction>();
30
31 private void setupTraceCollectorInChain(){
32 IRewriterTraceCollector collector = getTraceCollector();
33 for(PDisjunctionRewriter rewriter: rewriterChain){
34 rewriter.setTraceCollector(collector);
35 }
36 }
37
38 public PDisjunctionRewriterCacher(PDisjunctionRewriter rewriter) {
39 rewriterChain = Collections.singletonList(rewriter);
40 }
41
42 public PDisjunctionRewriterCacher(PDisjunctionRewriter... rewriters) {
43 rewriterChain = new ArrayList<>(Arrays.asList(rewriters));
44 }
45
46 public PDisjunctionRewriterCacher(List<PDisjunctionRewriter> rewriterChain) {
47 this.rewriterChain = new ArrayList<>(rewriterChain);
48 }
49
50 @Override
51 public PDisjunction rewrite(PDisjunction disjunction) {
52 if (!cachedResults.containsKey(disjunction)) {
53 PDisjunction rewritten = disjunction;
54 setupTraceCollectorInChain();
55 for (PDisjunctionRewriter rewriter : rewriterChain) {
56 rewritten = rewriter.rewrite(rewritten);
57 }
58
59 cachedResults.put(disjunction, rewritten);
60 }
61 return cachedResults.get(disjunction);
62 }
63
64}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PQueryFlattener.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PQueryFlattener.java
new file mode 100644
index 00000000..76311d8f
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/PQueryFlattener.java
@@ -0,0 +1,253 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Marton Bur, Akos Horvath, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import java.util.ArrayDeque;
12import java.util.ArrayList;
13import java.util.Collections;
14import java.util.Deque;
15import java.util.HashMap;
16import java.util.HashSet;
17import java.util.LinkedHashSet;
18import java.util.LinkedList;
19import java.util.List;
20import java.util.Map;
21import java.util.Set;
22
23import tools.refinery.viatra.runtime.matchers.psystem.PBody;
24import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
25import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
26import tools.refinery.viatra.runtime.matchers.psystem.queries.PDisjunction;
27import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
28import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery.PQueryStatus;
29import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IConstraintFilter.AllowAllFilter;
30import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IConstraintFilter.ExportedParameterFilter;
31import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IVariableRenamer.HierarchicalName;
32import tools.refinery.viatra.runtime.matchers.psystem.rewriters.IVariableRenamer.SameName;
33import tools.refinery.viatra.runtime.matchers.util.Preconditions;
34import tools.refinery.viatra.runtime.matchers.util.Sets;
35
36/**
37 * This rewriter class holds the query flattening logic
38 *
39 * @author Marton Bur
40 *
41 */
42public class PQueryFlattener extends PDisjunctionRewriter {
43
44 /**
45 * Utility function to produce the permutation of every possible mapping of values.
46 *
47 * @param values
48 * @return
49 */
50 private static <K, V> Set<Map<K, V>> permutation(Map<K, Set<V>> values) {
51 // An ordering of keys is defined here which will help restoring the appropriate values after the execution of
52 // the cartesian product
53 List<K> keyList = new ArrayList<>(values.keySet());
54
55 // Produce list of value sets with the ordering defined by keyList
56 List<Set<V>> valuesList = new ArrayList<Set<V>>(keyList.size());
57 for (K key : keyList) {
58 valuesList.add(values.get(key));
59 }
60
61 // Cartesian product will obey ordering of the list
62 Set<List<V>> valueMappings = Sets.cartesianProduct(valuesList);
63
64 // Build result
65 Set<Map<K, V>> result = new LinkedHashSet<>();
66 for (List<V> valueList : valueMappings) {
67 Map<K, V> map = new HashMap<>();
68 for (int i = 0; i < keyList.size(); i++) {
69 map.put(keyList.get(i), valueList.get(i));
70 }
71 result.add(map);
72 }
73
74 return result;
75 }
76
77 private IFlattenCallPredicate flattenCallPredicate;
78
79 public PQueryFlattener(IFlattenCallPredicate flattenCallPredicate) {
80 this.flattenCallPredicate = flattenCallPredicate;
81 }
82
83 @Override
84 public PDisjunction rewrite(PDisjunction disjunction) {
85 PQuery query = disjunction.getQuery();
86
87 // Check for recursion
88 Set<PQuery> allReferredQueries = disjunction.getAllReferredQueries();
89 for (PQuery referredQuery : allReferredQueries) {
90 if (referredQuery.getAllReferredQueries().contains(referredQuery)) {
91 throw new RewriterException("Recursive queries are not supported, can't flatten query named \"{1}\"",
92 new String[] { query.getFullyQualifiedName() }, "Unsupported recursive query", query);
93 }
94 }
95
96 return this.doFlatten(disjunction);
97 }
98
99 /**
100 * Return the list of dependencies (including the root) in chronological order
101 *
102 * @param rootDisjunction
103 * @return
104 */
105 private List<PDisjunction> disjunctionDependencies(PDisjunction rootDisjunction) {
106 // Disjunctions are first collected into a list usign a depth-first approach,
107 // which can be iterated backwards while removing duplicates
108 Deque<PDisjunction> stack = new ArrayDeque<>();
109 LinkedList<PDisjunction> list = new LinkedList<>();
110 stack.push(rootDisjunction);
111 list.add(rootDisjunction);
112
113 while (!stack.isEmpty()) {
114 PDisjunction disjunction = stack.pop();
115 // Collect dependencies
116 for (PBody pBody : disjunction.getBodies()) {
117 for (PConstraint constraint : pBody.getConstraints()) {
118 if (constraint instanceof PositivePatternCall) {
119 PositivePatternCall positivePatternCall = (PositivePatternCall) constraint;
120 if (flattenCallPredicate.shouldFlatten(positivePatternCall)) {
121 // If the above preconditions meet, the call should be flattened
122 PDisjunction calledDisjunction = positivePatternCall.getReferredQuery().getDisjunctBodies();
123 stack.push(calledDisjunction);
124 list.add(calledDisjunction);
125 }
126 }
127 }
128 }
129 }
130
131 // Remove duplicates (keeping the last instance) and reverse order
132 Set<PDisjunction> visited = new HashSet<PDisjunction>();
133 List<PDisjunction> result = new ArrayList<PDisjunction>(list.size());
134
135 list.descendingIterator().forEachRemaining(item -> {
136 if (!visited.contains(item)) {
137 result.add(item);
138 visited.add(item);
139 }
140
141 });
142
143 return result;
144 }
145
146 /**
147 * This function holds the actual flattening logic for a PQuery
148 *
149 * @param rootDisjunction
150 * to be flattened
151 * @return the flattened bodies of the pQuery
152 */
153 private PDisjunction doFlatten(PDisjunction rootDisjunction) {
154
155 Map<PDisjunction, Set<PBody>> flatBodyMapping = new HashMap<>();
156
157 List<PDisjunction> dependencies = disjunctionDependencies(rootDisjunction);
158
159 for (PDisjunction disjunction : dependencies) {
160 Set<PBody> flatBodies = new LinkedHashSet<>();
161 for (PBody body : disjunction.getBodies()) {
162 if (isFlatteningNeeded(body)) {
163 Map<PositivePatternCall, Set<PBody>> flattenedBodies = new HashMap<>();
164 for (PConstraint pConstraint : body.getConstraints()) {
165
166 if (pConstraint instanceof PositivePatternCall) {
167 PositivePatternCall positivePatternCall = (PositivePatternCall) pConstraint;
168 if (flattenCallPredicate.shouldFlatten(positivePatternCall)) {
169 // If the above preconditions meet, do the flattening and return the disjoint bodies
170 PDisjunction calledDisjunction = positivePatternCall.getReferredQuery()
171 .getDisjunctBodies();
172
173 Set<PBody> flattenedBodySet = flatBodyMapping.get(calledDisjunction);
174 Preconditions.checkArgument(!flattenedBodySet.isEmpty());
175 flattenedBodies.put(positivePatternCall, flattenedBodySet);
176 }
177 }
178 }
179 flatBodies.addAll(createSetOfFlatPBodies(body, flattenedBodies));
180 } else {
181 flatBodies.add(prepareFlatPBody(body));
182 }
183 }
184 flatBodyMapping.put(disjunction, flatBodies);
185 }
186
187 return new PDisjunction(rootDisjunction.getQuery(), flatBodyMapping.get(rootDisjunction));
188 }
189
190 /**
191 * Creates the flattened bodies based on the caller body and the called (and already flattened) disjunctions
192 *
193 * @param pBody
194 * the body to flatten
195 * @param flattenedDisjunctions
196 * the
197 * @param flattenedCalls
198 * @return
199 */
200 private Set<PBody> createSetOfFlatPBodies(PBody pBody, Map<PositivePatternCall, Set<PBody>> flattenedCalls) {
201 PQuery pQuery = pBody.getPattern();
202
203 Set<Map<PositivePatternCall, PBody>> conjunctedCalls = permutation(flattenedCalls);
204
205 // The result set containing the merged conjuncted bodies
206 Set<PBody> conjunctedBodies = new HashSet<>();
207
208 for (Map<PositivePatternCall, PBody> calledBodies : conjunctedCalls) {
209 FlattenerCopier copier = createBodyCopier(pQuery, calledBodies);
210
211 int i = 0;
212 HierarchicalName hierarchicalNamingTool = new HierarchicalName();
213 for (PositivePatternCall patternCall : calledBodies.keySet()) {
214 // Merge each called body
215 hierarchicalNamingTool.setCallCount(i++);
216 copier.mergeBody(patternCall, hierarchicalNamingTool, new ExportedParameterFilter());
217 }
218
219 // Merge the caller's constraints to the conjunct body
220 copier.mergeBody(pBody);
221
222 PBody copiedBody = copier.getCopiedBody();
223 copiedBody.setStatus(PQueryStatus.OK);
224 conjunctedBodies.add(copiedBody);
225 }
226
227 return conjunctedBodies;
228 }
229
230 private FlattenerCopier createBodyCopier(PQuery query, Map<PositivePatternCall, PBody> calledBodies) {
231 FlattenerCopier flattenerCopier = new FlattenerCopier(query, calledBodies);
232 flattenerCopier.setTraceCollector(getTraceCollector());
233 return flattenerCopier;
234 }
235
236 private PBody prepareFlatPBody(PBody pBody) {
237 PBodyCopier copier = createBodyCopier(pBody.getPattern(), Collections.<PositivePatternCall, PBody> emptyMap());
238 copier.mergeBody(pBody, new SameName(), new AllowAllFilter());
239 // the copying of the body here is necessary for only one containing PDisjunction can be assigned to a PBody
240 return copier.getCopiedBody();
241 }
242
243 private boolean isFlatteningNeeded(PBody pBody) {
244 // Check if the body contains positive pattern call AND if it should be flattened
245 for (PConstraint pConstraint : pBody.getConstraints()) {
246 if (pConstraint instanceof PositivePatternCall) {
247 return flattenCallPredicate.shouldFlatten((PositivePatternCall) pConstraint);
248 }
249 }
250 return false;
251 }
252
253}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/RewriterException.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/RewriterException.java
new file mode 100644
index 00000000..d0fc286b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/RewriterException.java
@@ -0,0 +1,31 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import tools.refinery.viatra.runtime.matchers.psystem.queries.QueryInitializationException;
12
13/**
14 * An exception to wrap various issues during PDisjunction rewriting.
15 * @author Zoltan Ujhelyi
16 *
17 */
18public class RewriterException extends QueryInitializationException {
19
20 private static final long serialVersionUID = -4703825954995497932L;
21
22 public RewriterException(String message, String[] context, String shortMessage, Object patternDescription,
23 Throwable cause) {
24 super(message, context, shortMessage, patternDescription, cause);
25 }
26
27 public RewriterException(String message, String[] context, String shortMessage, Object patternDescription) {
28 super(message, context, shortMessage, patternDescription);
29 }
30
31}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/SurrogateQueryRewriter.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/SurrogateQueryRewriter.java
new file mode 100644
index 00000000..71459558
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/SurrogateQueryRewriter.java
@@ -0,0 +1,63 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import java.util.LinkedHashSet;
12import java.util.Set;
13
14import tools.refinery.viatra.runtime.matchers.context.IInputKey;
15import tools.refinery.viatra.runtime.matchers.context.surrogate.SurrogateQueryRegistry;
16import tools.refinery.viatra.runtime.matchers.psystem.PBody;
17import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
18import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
19import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.TypeConstraint;
20import tools.refinery.viatra.runtime.matchers.psystem.queries.PDisjunction;
21import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
22import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery.PQueryStatus;
23import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
24import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
25
26/**
27 * @author Zoltan Ujhelyi
28 *
29 */
30public class SurrogateQueryRewriter extends PDisjunctionRewriter {
31
32 @Override
33 public PDisjunction rewrite(PDisjunction disjunction) {
34 Set<PBody> replacedBodies = new LinkedHashSet<>();
35 for (PBody body : disjunction.getBodies()) {
36 PBodyCopier copier = new PBodyCopier(body, getTraceCollector()) {
37
38 @Override
39 protected void copyTypeConstraint(TypeConstraint typeConstraint) {
40 PVariable[] mappedVariables = extractMappedVariables(typeConstraint);
41 Tuple variablesTuple = Tuples.flatTupleOf((Object[])mappedVariables);
42 final IInputKey supplierKey = typeConstraint.getSupplierKey();
43 if(SurrogateQueryRegistry.instance().hasSurrogateQueryFQN(supplierKey)) {
44 PQuery surrogateQuery = SurrogateQueryRegistry.instance().getSurrogateQuery(supplierKey);
45 if (surrogateQuery == null) {
46 throw new IllegalStateException(
47 String.format("Surrogate query for feature %s not found",
48 supplierKey.getPrettyPrintableName()));
49 }
50 addTrace(typeConstraint, new PositivePatternCall(getCopiedBody(), variablesTuple, surrogateQuery));
51 } else {
52 addTrace(typeConstraint, new TypeConstraint(getCopiedBody(), variablesTuple, supplierKey));
53 }
54 }
55 };
56 PBody modifiedBody = copier.getCopiedBody();
57 replacedBodies.add(modifiedBody);
58 modifiedBody.setStatus(PQueryStatus.OK);
59 }
60 return new PDisjunction(replacedBodies);
61 }
62
63}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/VariableMappingExpressionEvaluatorWrapper.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/VariableMappingExpressionEvaluatorWrapper.java
new file mode 100644
index 00000000..10337979
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/psystem/rewriters/VariableMappingExpressionEvaluatorWrapper.java
@@ -0,0 +1,88 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.psystem.rewriters;
10
11import java.util.HashMap;
12import java.util.LinkedHashMap;
13import java.util.Map;
14
15import tools.refinery.viatra.runtime.matchers.psystem.IExpressionEvaluator;
16import tools.refinery.viatra.runtime.matchers.psystem.IValueProvider;
17import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
18import tools.refinery.viatra.runtime.matchers.util.Preconditions;
19
20/**
21 * A wrapper for {@link IExpressionEvaluator} which is capable of correctly mapping variable names used by the
22 * expression.
23 *
24 * @author Grill Balázs
25 *
26 */
27class VariableMappingExpressionEvaluatorWrapper implements IExpressionEvaluator {
28
29 private final IExpressionEvaluator wrapped;
30 private final Map<String, String> variableMapping;
31
32 public VariableMappingExpressionEvaluatorWrapper(IExpressionEvaluator wrapped,
33 Map<PVariable, PVariable> variableMapping) {
34
35 // Support to rewrap an already wrapped expression.
36 boolean rewrap = wrapped instanceof VariableMappingExpressionEvaluatorWrapper;
37 this.wrapped = rewrap ? ((VariableMappingExpressionEvaluatorWrapper)wrapped).wrapped : wrapped;
38
39 // Instead of just saving the reference of the mapping, save the actual (trimmed) state of the mapping as it
40 // may change during copying (especially during flattening). A LinkedHashMap is used to retain ordering of
41 // original parameter names iterator.
42 this.variableMapping = new LinkedHashMap<>();
43
44 // Index map by variable names
45 Map<String, PVariable> names = new HashMap<>();
46 for (PVariable originalVar : variableMapping.keySet()) {
47 names.put(originalVar.getName(), originalVar);
48 }
49
50 // In case of rewrapping, current names are contained by the previous mapping
51 Map<String, String> previousMapping = null;
52 if (rewrap){
53 previousMapping = ((VariableMappingExpressionEvaluatorWrapper)wrapped).variableMapping;
54 }
55
56 // Populate mapping
57 for (String inputParameterName : this.wrapped.getInputParameterNames()) {
58 String parameterName = rewrap ? previousMapping.get(inputParameterName) : inputParameterName;
59 Preconditions.checkArgument(parameterName != null);
60 PVariable original = names.get(parameterName);
61 Preconditions.checkArgument(original != null);
62 PVariable mapped = variableMapping.get(original);
63 if (mapped != null){
64 this.variableMapping.put(inputParameterName, mapped.getName());
65 }
66 }
67 }
68
69 @Override
70 public String getShortDescription() {
71 return wrapped.getShortDescription();
72 }
73
74 @Override
75 public Iterable<String> getInputParameterNames() {
76 return variableMapping.values();
77 }
78
79 @Override
80 public Object evaluateExpression(final IValueProvider provider) throws Exception {
81 return wrapped.evaluateExpression(variableName -> {
82 String mappedVariableName = variableMapping.get(variableName);
83 Preconditions.checkArgument(mappedVariableName != null, "Could not find variable %s", variableName);
84 return provider.getValue(mappedVariableName);
85 });
86 }
87
88}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/AbstractTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/AbstractTuple.java
new file mode 100644
index 00000000..a26d9193
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/AbstractTuple.java
@@ -0,0 +1,136 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.ArrayList;
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.List;
15import java.util.Map;
16import java.util.Objects;
17import java.util.Set;
18
19/**
20 * Common implementation methods for immutable and volatile tuples. The class should not be used directly in client
21 * code, except for the definition of new tuple implementations.
22 *
23 * @author Zoltan Ujhelyi
24 * @since 1.7
25 */
26public abstract class AbstractTuple implements ITuple {
27
28 /**
29 * As the tuple is supposed to be immutable, do not modify the returned array.
30 *
31 * @return the array containing all elements of this Tuple
32 */
33 @Override
34 public Object[] getElements() {
35 Object[] allElements = new Object[getSize()];
36 for (int i = 0; i < allElements.length; ++i)
37 allElements[i] = get(i);
38 return allElements;
39 }
40
41 /**
42 * @return the set containing all distinct elements of this Tuple, cast as type T
43 */
44 @Override
45 @SuppressWarnings("unchecked")
46 public <T> Set<T> getDistinctElements() {
47 Set<T> result = new HashSet<T>();
48 Object[] elements = getElements();
49 for (Object object : elements) {
50 result.add((T) object);
51 }
52 return result;
53 }
54
55 /**
56 * Calculates an inverted index of the elements of this pattern. For each element, the index of the (last)
57 * occurrence is calculated.
58 *
59 * @return the inverted index mapping each element of this pattern to its index in the array
60 */
61 @Override
62 public Map<Object, Integer> invertIndex() {
63 Map<Object, Integer> result = new HashMap<Object, Integer>();
64 for (int i = 0; i < getSize(); i++)
65 result.put(get(i), i);
66 return result;
67 }
68
69 /**
70 * Calculates an inverted index of the elements of this pattern. For each element, the index of all of its
71 * occurrences is calculated.
72 *
73 * @return the inverted index mapping each element of this pattern to its index in the array
74 */
75 @Override
76 public Map<Object, List<Integer>> invertIndexWithMupliplicity() {
77 Map<Object, List<Integer>> result = new HashMap<Object, List<Integer>>();
78 for (int i = 0; i < getSize(); i++) {
79 Object value = get(i);
80 List<Integer> indices = result.computeIfAbsent(value, v -> new ArrayList<>());
81 indices.add(i);
82 }
83 return result;
84 }
85
86 /**
87 * @since 1.7
88 */
89 protected IndexOutOfBoundsException raiseIndexingError(int index) {
90 return new IndexOutOfBoundsException(
91 String.format("No value at position %d for %s instance %s", index, getClass().getSimpleName(), this));
92 }
93
94 /**
95 * Compares the elements stored in this tuple to another tuple
96 */
97 protected boolean internalEquals(ITuple other) {
98 if (getSize() != other.getSize())
99 return false;
100 boolean result = true;
101 for (int i = 0; result && i < getSize(); ++i) {
102 Object ours = get(i);
103 Object theirs = other.get(i);
104 result = result && Objects.equals(ours, theirs);
105 }
106 return result;
107 }
108
109 @Override
110 public String toString() {
111 StringBuilder s = new StringBuilder();
112 s.append("T(");
113 for (Object o : getElements()) {
114 s.append(o == null ? "null" : o.toString());
115 s.append(';');
116 }
117 s.append(')');
118 return s.toString();
119 }
120
121 /**
122 * @since 1.7
123 */
124 protected int doCalcHash() {
125 final int PRIME = 31;
126 int hash = 1;
127 for (int i = 0; i < getSize(); i++) {
128 hash = PRIME * hash;
129 Object element = get(i);
130 if (element != null)
131 hash += element.hashCode();
132 }
133 return hash;
134 }
135
136} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseFlatTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseFlatTuple.java
new file mode 100644
index 00000000..6f46b763
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseFlatTuple.java
@@ -0,0 +1,20 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11/**
12 * Base class for all flat tuple implementations.
13 * Flat tuples store all elements locally (do not reference other tuples).
14 *
15 * @author Gabor Bergmann
16 * @since 1.7
17 */
18public abstract class BaseFlatTuple extends Tuple {
19
20}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseLeftInheritanceTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseLeftInheritanceTuple.java
new file mode 100644
index 00000000..03f9ea89
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/BaseLeftInheritanceTuple.java
@@ -0,0 +1,65 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11/**
12 * Common functionality of left inheritance tuple implementations.
13 *
14 * <p>Left inheritance tuples inherit their first few elements from another tuple,
15 * and extend it with additional "local" elements.
16 *
17 * @author Gabor Bergmann
18 * @since 1.7
19 */
20public abstract class BaseLeftInheritanceTuple extends Tuple {
21
22 /**
23 * The number of elements that aren't stored locally, but inherited from an ancestor Tuple instead.
24 */
25 protected final int inheritedIndex;
26 /**
27 * This object contains the same elements as the ancestor on the first inheritedIndex positions
28 */
29 protected final Tuple ancestor;
30
31 /**
32 * @param ancestor
33 */
34 public BaseLeftInheritanceTuple(Tuple ancestor) {
35 super();
36 this.ancestor = ancestor;
37 this.inheritedIndex = ancestor.getSize();
38 }
39
40 /**
41 * @return the number of local (non-inherited) elements
42 */
43 public abstract int getLocalSize();
44
45 /**
46 * Optimized equals calculation (prediction: true, since hash values match)
47 */
48 @Override
49 protected boolean internalEquals(ITuple other) {
50 if (other instanceof BaseLeftInheritanceTuple) {
51 BaseLeftInheritanceTuple blit = (BaseLeftInheritanceTuple) other;
52 if (blit.inheritedIndex == this.inheritedIndex) {
53 if (this.ancestor.equals(blit.ancestor)) {
54 return localEquals(blit);
55 } else return false;
56 }
57 }
58 return super.internalEquals(other);
59 }
60
61 /**
62 * Checks the equivalence of local elements only, after ancestor tuple has been determined to be equal.
63 */
64 protected abstract boolean localEquals(BaseLeftInheritanceTuple other);
65}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple.java
new file mode 100644
index 00000000..8bbb0ac2
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple.java
@@ -0,0 +1,60 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.tuple;
11
12import java.util.Arrays;
13
14/**
15 * Default Tuple implementation, with statically unknown arity.
16 * @author Gabor Bergmann
17 */
18public final class FlatTuple extends BaseFlatTuple {
19
20 /**
21 * Array of substituted values. DO NOT MODIFY! Use Constructor to build a new instance instead.
22 */
23 private final Object[] elements;
24
25 /**
26 * Creates a FlatTuple instance, fills it with the given array.
27 * <p> Users should consider calling {@link Tuples#flatTupleOf(Object...)} instead to save memory on low-arity tuples.
28 *
29 * @param elements
30 * array of substitution values
31 */
32 protected FlatTuple(Object... elements) {
33 this.elements = Arrays.copyOf(elements, elements.length);
34 calcHash();
35 }
36
37 @Override
38 public Object get(int index) {
39 return elements[index];
40 }
41
42 @Override
43 public int getSize() {
44 return elements.length;
45 }
46
47 @Override
48 public Object[] getElements() {
49 return elements;
50 }
51
52 @Override
53 protected boolean internalEquals(ITuple other) {
54 if (other instanceof FlatTuple) {
55 return Arrays.equals(elements, ((FlatTuple) other).elements);
56 } else
57 return super.internalEquals(other);
58 }
59
60}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple0.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple0.java
new file mode 100644
index 00000000..93f412b7
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple0.java
@@ -0,0 +1,46 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11/**
12 * Flat tuple with statically known arity of 0.
13 *
14 * @author Gabor Bergmann
15 * @since 1.7
16 *
17 */
18public final class FlatTuple0 extends BaseFlatTuple {
19 protected static final FlatTuple0 INSTANCE = new FlatTuple0();
20
21 private FlatTuple0() {
22 calcHash();
23 }
24
25 @Override
26 public int getSize() {
27 return 0;
28 }
29
30 @Override
31 public Object get(int index) {
32 throw raiseIndexingError(index);
33 }
34
35 private static final Object[] NULLARY_ARRAY = new Object[0];
36
37 @Override
38 public Object[] getElements() {
39 return NULLARY_ARRAY;
40 }
41
42 @Override
43 protected boolean internalEquals(ITuple other) {
44 return 0 == other.getSize();
45 }
46}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple1.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple1.java
new file mode 100644
index 00000000..b3b1c312
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple1.java
@@ -0,0 +1,44 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Objects;
12
13/**
14 * Flat tuple with statically known arity of 1.
15 *
16 * @author Gabor Bergmann
17 * @since 1.7
18 *
19 */
20public final class FlatTuple1 extends BaseFlatTuple {
21 private final Object element0;
22
23 protected FlatTuple1(Object element0) {
24 this.element0 = element0;
25 calcHash();
26 }
27
28 @Override
29 public int getSize() {
30 return 1;
31 }
32
33 @Override
34 public Object get(int index) {
35 if (index == 0) return element0;
36 else throw raiseIndexingError(index);
37 }
38
39 @Override
40 protected boolean internalEquals(ITuple other) {
41 return 1 == other.getSize() &&
42 Objects.equals(element0, other.get(0));
43 }
44}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple2.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple2.java
new file mode 100644
index 00000000..2dcfd718
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple2.java
@@ -0,0 +1,51 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Objects;
12
13/**
14 * Flat tuple with statically known arity of 2.
15 *
16 * @author Gabor Bergmann
17 * @since 1.7
18 *
19 */
20public final class FlatTuple2 extends BaseFlatTuple {
21 private final Object element0;
22 private final Object element1;
23
24 protected FlatTuple2(Object element0, Object element1) {
25 this.element0 = element0;
26 this.element1 = element1;
27 calcHash();
28 }
29
30 @Override
31 public int getSize() {
32 return 2;
33 }
34
35 @Override
36 public Object get(int index) {
37 switch(index) {
38 case 0 : return element0;
39 case 1 : return element1;
40 default: throw raiseIndexingError(index);
41 }
42 }
43
44 @Override
45 protected boolean internalEquals(ITuple other) {
46 return 2 == other.getSize() &&
47 Objects.equals(element0, other.get(0)) &&
48 Objects.equals(element1, other.get(1));
49 }
50
51}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple3.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple3.java
new file mode 100644
index 00000000..50cee57e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple3.java
@@ -0,0 +1,55 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Objects;
12
13/**
14 * Flat tuple with statically known arity of 3.
15 *
16 * @author Gabor Bergmann
17 * @since 1.7
18 *
19 */
20public final class FlatTuple3 extends BaseFlatTuple {
21 private final Object element0;
22 private final Object element1;
23 private final Object element2;
24
25 protected FlatTuple3(Object element0, Object element1, Object element2) {
26 this.element0 = element0;
27 this.element1 = element1;
28 this.element2 = element2;
29 calcHash();
30 }
31
32 @Override
33 public int getSize() {
34 return 3;
35 }
36
37 @Override
38 public Object get(int index) {
39 switch (index) {
40 case 0: return element0;
41 case 1: return element1;
42 case 2: return element2;
43 default: throw raiseIndexingError(index);
44 }
45 }
46
47 @Override
48 protected boolean internalEquals(ITuple other) {
49 return 3 == other.getSize() &&
50 Objects.equals(element0, other.get(0)) &&
51 Objects.equals(element1, other.get(1)) &&
52 Objects.equals(element2, other.get(2));
53 }
54
55}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple4.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple4.java
new file mode 100644
index 00000000..024c94f4
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/FlatTuple4.java
@@ -0,0 +1,59 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Objects;
12
13/**
14 * Flat tuple with statically known arity of 4.
15 *
16 * @author Gabor Bergmann
17 * @since 1.7
18 *
19 */
20public final class FlatTuple4 extends BaseFlatTuple {
21 private final Object element0;
22 private final Object element1;
23 private final Object element2;
24 private final Object element3;
25
26 protected FlatTuple4(Object element0, Object element1, Object element2, Object element3) {
27 this.element0 = element0;
28 this.element1 = element1;
29 this.element2 = element2;
30 this.element3 = element3;
31 calcHash();
32 }
33
34 @Override
35 public int getSize() {
36 return 4;
37 }
38
39 @Override
40 public Object get(int index) {
41 switch(index) {
42 case 0: return element0;
43 case 1: return element1;
44 case 2: return element2;
45 case 3: return element3;
46 default: throw raiseIndexingError(index);
47 }
48 }
49
50 @Override
51 protected boolean internalEquals(ITuple other) {
52 return 4 == other.getSize() &&
53 Objects.equals(element0, other.get(0)) &&
54 Objects.equals(element1, other.get(1)) &&
55 Objects.equals(element2, other.get(2)) &&
56 Objects.equals(element3, other.get(3));
57 }
58
59}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/IModifiableTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/IModifiableTuple.java
new file mode 100644
index 00000000..f5dab2a5
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/IModifiableTuple.java
@@ -0,0 +1,27 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11/**
12 * A tuple that allows modifying the underlying value. Should not be used for non-volatile tuples.
13 *
14 * @author Zoltan Ujhelyi
15 * @since 1.7
16 */
17public interface IModifiableTuple extends ITuple {
18
19 /**
20 * Sets the selected value for a tuple
21 *
22 * @pre: 0 <= index < getSize()
23 *
24 */
25 void set(int index, Object value);
26
27}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/ITuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/ITuple.java
new file mode 100644
index 00000000..92014781
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/ITuple.java
@@ -0,0 +1,64 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.List;
12import java.util.Map;
13import java.util.Set;
14
15/**
16 * Represents both mutable and immutable tuples
17 *
18 * @author Zoltan Ujhelyi
19 * @since 1.7
20 *
21 */
22public interface ITuple {
23
24 /**
25 * @pre: 0 <= index < getSize()
26 *
27 * @return the element at the specified index
28 */
29 Object get(int index);
30
31 /**
32 * As the tuple is supposed to be immutable, do not modify the returned array.
33 * @return the array containing all elements of this Tuple
34 */
35 Object[] getElements();
36
37 /**
38 * @return the set containing all distinct elements of this Tuple, cast as type T
39 */
40 <T> Set<T> getDistinctElements();
41
42 /**
43 * @return number of elements
44 */
45 int getSize();
46
47 /**
48 * Calculates an inverted index of the elements of this pattern. For each element, the index of the (last)
49 * occurrence is calculated.
50 *
51 * @return the inverted index mapping each element of this pattern to its index in the array
52 */
53 Map<Object, Integer> invertIndex();
54
55 /**
56 * Calculates an inverted index of the elements of this pattern. For each element, the index of all of its
57 * occurrences is calculated.
58 *
59 * @return the inverted index mapping each element of this pattern to its index in the array
60 */
61 Map<Object, List<Integer>> invertIndexWithMupliplicity();
62
63 Tuple toImmutable();
64} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple.java
new file mode 100644
index 00000000..dcdfc376
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple.java
@@ -0,0 +1,172 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.tuple;
11
12import java.util.Arrays;
13import java.util.Objects;
14
15/**
16 *
17 * Tuple that inherits another tuple on the left.
18 *
19 * @author Gabor Bergmann
20 *
21 */
22public final class LeftInheritanceTuple extends BaseLeftInheritanceTuple {
23 /**
24 * Array of substituted values above inheritedIndex. DO NOT MODIFY! Use Constructor to build a new instance instead.
25 */
26 private final Object[] localElements;
27
28 //
29 // /**
30 // * Creates a Tuple instance, fills it with the given array.
31 // * @pre: no elements are null
32 // * @param elements array of substitution values
33 // */
34 // public Tuple(Object[] elements)
35 // {
36 // this.localElements = elements;
37 // this.ancestor=null;
38 // this.inheritedIndex = 0;
39 // calcHash();
40 // }
41
42
43
44 /**
45 * Creates a Tuple instance, lets it inherit from an ancestor, extends it with a given array. @pre: no elements are
46 * null
47 *
48 * @param localElements
49 * array of substitution values
50 */
51 LeftInheritanceTuple(Tuple ancestor, Object[] localElements) {
52 super(ancestor);
53 this.localElements = localElements;
54 calcHash();
55 }
56
57 //
58 // /**
59 // * Creates a Tuple instance of size one, fills it with the given object.
60 // * @pre: o!=null
61 // * @param o the single substitution
62 // */
63 // public Tuple(Object o)
64 // {
65 // localElements = new Object [1];
66 // localElements[0] = o;
67 // this.ancestor=null;
68 // this.inheritedIndex = 0;
69 // calcHash();
70 // }
71 //
72 // /**
73 // * Creates a Tuple instance of size two, fills it with the given objects.
74 // * @pre: o1!=null, o2!=null
75 // */
76 // public Tuple(Object o1, Object o2)
77 // {
78 // localElements = new Object [2];
79 // localElements[0] = o1;
80 // localElements[1] = o2;
81 // this.ancestor=null;
82 // this.inheritedIndex = 0;
83 // calcHash();
84 // }
85 //
86 // /**
87 // * Creates a Tuple instance of size three, fills it with the given
88 // objects.
89 // * @pre: o1!=null, o2!=null, o3!=null
90 // */
91 // public Tuple(Object o1, Object o2, Object o3)
92 // {
93 // localElements = new Object [3];
94 // localElements[0] = o1;
95 // localElements[1] = o2;
96 // localElements[2] = o3;
97 // this.ancestor=null;
98 // this.inheritedIndex = 0;
99 // calcHash();
100 // }
101
102 /**
103 * @return number of elements
104 */
105 public int getSize() {
106 return inheritedIndex + localElements.length;
107 }
108
109 @Override
110 public int getLocalSize() {
111 return localElements.length;
112 }
113
114 /**
115 * @pre: 0 <= index < getSize()
116 *
117 * @return the element at the specified index
118 */
119 public Object get(int index) {
120 return (index < inheritedIndex) ? ancestor.get(index) : localElements[index - inheritedIndex];
121 }
122
123 /**
124 * Optimized hash calculation
125 */
126 @Override
127 void calcHash() {
128 final int PRIME = 31;
129 cachedHash = ancestor.hashCode();
130 for (int i = 0; i < localElements.length; i++) {
131 cachedHash = PRIME * cachedHash;
132 Object element = localElements[i];
133 if (element != null)
134 cachedHash += element.hashCode();
135 }
136 }
137
138 /**
139 * Optimized equals calculation (prediction: true, since hash values match)
140 */
141 @Override
142 protected boolean localEquals(BaseLeftInheritanceTuple other) {
143 if (other instanceof LeftInheritanceTuple) {
144 LeftInheritanceTuple lit = (LeftInheritanceTuple)other;
145 return Arrays.equals(this.localElements, lit.localElements);
146 } else {
147 if (localElements.length != other.getLocalSize())
148 return false;
149 int index = inheritedIndex;
150 for (int i = 0; i<localElements.length; ++i) {
151 if (! Objects.equals(localElements[i], other.get(index++)))
152 return false;
153 }
154 return true;
155 }
156 }
157
158 // public int compareTo(Object arg0) {
159 // Tuple other = (Tuple) arg0;
160 //
161 // int retVal = cachedHash - other.cachedHash;
162 // if (retVal==0) retVal = elements.length - other.elements.length;
163 // for (int i=0; retVal==0 && i<elements.length; ++i)
164 // {
165 // if (elements[i] == null && other.elements[i] != null) retVal = -1;
166 // else if (other.elements[i] == null) retVal = 1;
167 // else retVal = elements[i].compareTo(other.elements[i]);
168 // }
169 // return retVal;
170 // }
171
172}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple1.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple1.java
new file mode 100644
index 00000000..61123176
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple1.java
@@ -0,0 +1,83 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Objects;
12
13/**
14 * @author Gabor Bergmann
15 * @since 1.7
16 */
17public final class LeftInheritanceTuple1 extends BaseLeftInheritanceTuple {
18 /**
19 * A single substituted value after inheritedIndex.
20 */
21 private final Object localElement;
22
23 /**
24 * @param ancestor
25 * @param localElement
26 */
27 protected LeftInheritanceTuple1(Tuple ancestor, Object localElement) {
28 super(ancestor);
29 this.localElement = localElement;
30 calcHash();
31 }
32
33 /**
34 * @return number of elements
35 */
36 public int getSize() {
37 return inheritedIndex + 1;
38 }
39
40 @Override
41 public int getLocalSize() {
42 return 1;
43 }
44
45 /**
46 * @pre: 0 <= index < getSize()
47 *
48 * @return the element at the specified index
49 */
50 public Object get(int index) {
51 int local = index - inheritedIndex;
52 if (local < 0)
53 return ancestor.get(index);
54 else if (local == 0) return localElement;
55 else throw raiseIndexingError(index);
56 }
57
58 /**
59 * Optimized hash calculation
60 */
61 @Override
62 void calcHash() {
63 final int PRIME = 31;
64 cachedHash = ancestor.hashCode();
65 cachedHash = PRIME * cachedHash;
66 if (localElement != null) cachedHash += localElement.hashCode();
67 }
68
69 /**
70 * Optimized equals calculation (prediction: true, since hash values match)
71 */
72 @Override
73 protected boolean localEquals(BaseLeftInheritanceTuple other) {
74 if (other instanceof LeftInheritanceTuple1) {
75 LeftInheritanceTuple1 lit = (LeftInheritanceTuple1)other;
76 return Objects.equals(this.localElement, lit.localElement);
77 } else {
78 return (1 == other.getLocalSize()) &&
79 Objects.equals(localElement, other.get(inheritedIndex));
80 }
81 }
82
83}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple2.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple2.java
new file mode 100644
index 00000000..e9fb98e8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple2.java
@@ -0,0 +1,73 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Objects;
12
13/**
14 * @author Gabor Bergmann
15 * @since 1.7
16 */
17public final class LeftInheritanceTuple2 extends BaseLeftInheritanceTuple {
18 private final Object localElement0;
19 private final Object localElement1;
20
21 protected LeftInheritanceTuple2(Tuple ancestor, Object localElement0, Object localElement1) {
22 super(ancestor);
23 this.localElement0 = localElement0;
24 this.localElement1 = localElement1;
25 calcHash();
26 }
27
28 @Override
29 public int getLocalSize() {
30 return 2;
31 }
32
33 @Override
34 public int getSize() {
35 return inheritedIndex + 2;
36 }
37
38 @Override
39 public Object get(int index) {
40 int local = index - inheritedIndex;
41 if (local < 0)
42 return ancestor.get(index);
43 else if (local == 0) return localElement0;
44 else if (local == 1) return localElement1;
45 else throw raiseIndexingError(index);
46 }
47
48 /**
49 * Optimized hash calculation
50 */
51 @Override
52 void calcHash() {
53 final int PRIME = 31;
54 cachedHash = ancestor.hashCode();
55 cachedHash = PRIME * cachedHash;
56 if (localElement0 != null) cachedHash += localElement0.hashCode();
57 cachedHash = PRIME * cachedHash;
58 if (localElement1 != null) cachedHash += localElement1.hashCode();
59 }
60
61 @Override
62 protected boolean localEquals(BaseLeftInheritanceTuple other) {
63 if (other instanceof LeftInheritanceTuple2) {
64 LeftInheritanceTuple2 lit = (LeftInheritanceTuple2)other;
65 return Objects.equals(this.localElement0, lit.localElement0) &&
66 Objects.equals(this.localElement1, lit.localElement1);
67 } else {
68 return (2 == other.getLocalSize()) &&
69 Objects.equals(localElement0, other.get(inheritedIndex)) &&
70 Objects.equals(localElement1, other.get(inheritedIndex + 1));
71 }
72 }
73}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple3.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple3.java
new file mode 100644
index 00000000..e61d196f
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple3.java
@@ -0,0 +1,81 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Objects;
12
13/**
14 * @author Gabor Bergmann
15 * @since 1.7
16 */
17public final class LeftInheritanceTuple3 extends BaseLeftInheritanceTuple {
18 private final Object localElement0;
19 private final Object localElement1;
20 private final Object localElement2;
21
22 protected LeftInheritanceTuple3(Tuple ancestor, Object localElement0, Object localElement1, Object localElement2) {
23 super(ancestor);
24 this.localElement0 = localElement0;
25 this.localElement1 = localElement1;
26 this.localElement2 = localElement2;
27 calcHash();
28 }
29
30 @Override
31 public int getLocalSize() {
32 return 3;
33 }
34
35 @Override
36 public int getSize() {
37 return inheritedIndex + 3;
38 }
39
40 @Override
41 public Object get(int index) {
42 int local = index - inheritedIndex;
43 if (local < 0)
44 return ancestor.get(index);
45 else if (local == 0) return localElement0;
46 else if (local == 1) return localElement1;
47 else if (local == 2) return localElement2;
48 else throw raiseIndexingError(index);
49 }
50
51 /**
52 * Optimized hash calculation
53 */
54 @Override
55 void calcHash() {
56 final int PRIME = 31;
57 cachedHash = ancestor.hashCode();
58 cachedHash = PRIME * cachedHash;
59 if (localElement0 != null) cachedHash += localElement0.hashCode();
60 cachedHash = PRIME * cachedHash;
61 if (localElement1 != null) cachedHash += localElement1.hashCode();
62 cachedHash = PRIME * cachedHash;
63 if (localElement2 != null) cachedHash += localElement2.hashCode();
64 }
65
66 @Override
67 protected boolean localEquals(BaseLeftInheritanceTuple other) {
68 if (other instanceof LeftInheritanceTuple3) {
69 LeftInheritanceTuple3 lit = (LeftInheritanceTuple3)other;
70 return Objects.equals(this.localElement0, lit.localElement0) &&
71 Objects.equals(this.localElement1, lit.localElement1) &&
72 Objects.equals(this.localElement2, lit.localElement2);
73 } else {
74 return (3 == other.getLocalSize()) &&
75 Objects.equals(localElement0, other.get(inheritedIndex)) &&
76 Objects.equals(localElement1, other.get(inheritedIndex + 1)) &&
77 Objects.equals(localElement2, other.get(inheritedIndex + 2));
78 }
79 }
80
81}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple4.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple4.java
new file mode 100644
index 00000000..4e50f1e1
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/LeftInheritanceTuple4.java
@@ -0,0 +1,88 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Objects;
12
13/**
14 * @author Gabor Bergmann
15 * @since 1.7
16 */
17public final class LeftInheritanceTuple4 extends BaseLeftInheritanceTuple {
18 private final Object localElement0;
19 private final Object localElement1;
20 private final Object localElement2;
21 private final Object localElement3;
22
23 protected LeftInheritanceTuple4(Tuple ancestor, Object localElement0, Object localElement1, Object localElement2,
24 Object localElement3) {
25 super(ancestor);
26 this.localElement0 = localElement0;
27 this.localElement1 = localElement1;
28 this.localElement2 = localElement2;
29 this.localElement3 = localElement3;
30 calcHash();
31 }
32
33 @Override
34 public int getLocalSize() {
35 return 4;
36 }
37
38 @Override
39 public int getSize() {
40 return inheritedIndex + 4;
41 }
42
43 @Override
44 public Object get(int index) {
45 int local = index - inheritedIndex;
46 if (local < 0)
47 return ancestor.get(index);
48 else if (local == 0) return localElement0;
49 else if (local == 1) return localElement1;
50 else if (local == 2) return localElement2;
51 else if (local == 3) return localElement3;
52 else throw raiseIndexingError(index);
53 }
54
55 /**
56 * Optimized hash calculation
57 */
58 @Override
59 void calcHash() {
60 final int PRIME = 31;
61 cachedHash = ancestor.hashCode();
62 cachedHash = PRIME * cachedHash;
63 if (localElement0 != null) cachedHash += localElement0.hashCode();
64 cachedHash = PRIME * cachedHash;
65 if (localElement1 != null) cachedHash += localElement1.hashCode();
66 cachedHash = PRIME * cachedHash;
67 if (localElement2 != null) cachedHash += localElement2.hashCode();
68 cachedHash = PRIME * cachedHash;
69 if (localElement3 != null) cachedHash += localElement3.hashCode();
70 }
71
72 @Override
73 protected boolean localEquals(BaseLeftInheritanceTuple other) {
74 if (other instanceof LeftInheritanceTuple4) {
75 LeftInheritanceTuple4 lit = (LeftInheritanceTuple4)other;
76 return Objects.equals(this.localElement0, lit.localElement0) &&
77 Objects.equals(this.localElement1, lit.localElement1) &&
78 Objects.equals(this.localElement2, lit.localElement2) &&
79 Objects.equals(this.localElement3, lit.localElement3);
80 } else {
81 return (4 == other.getLocalSize()) &&
82 Objects.equals(localElement0, other.get(inheritedIndex)) &&
83 Objects.equals(localElement1, other.get(inheritedIndex + 1)) &&
84 Objects.equals(localElement2, other.get(inheritedIndex + 2)) &&
85 Objects.equals(localElement3, other.get(inheritedIndex + 3));
86 }
87 }
88}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/MaskedTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/MaskedTuple.java
new file mode 100644
index 00000000..a5d1991c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/MaskedTuple.java
@@ -0,0 +1,48 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2009 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.tuple;
11
12/**
13 * A tuple that transparently provides a masked (transformed) view of another tuple.
14 *
15 * @author Gabor Bergmann
16 * @since 2.0
17 *
18 */
19public class MaskedTuple extends Tuple {
20
21 Tuple wrapped;
22 TupleMask mask;
23
24 public MaskedTuple(Tuple wrapped, TupleMask mask) {
25 super();
26 // if (wrapped instanceof MaskedTuple) {
27 // MaskedTuple parent = (MaskedTuple)wrapped;
28 // this.wrapped = parent.wrapped;
29 // this.mask = mask.transform(parent.mask);
30 // }
31 // else
32 //{
33 this.wrapped = wrapped;
34 this.mask = mask;
35 //}
36 }
37
38 @Override
39 public Object get(int index) {
40 return wrapped.get(mask.indices[index]);
41 }
42
43 @Override
44 public int getSize() {
45 return mask.indices.length;
46 }
47
48}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuple.java
new file mode 100644
index 00000000..d94f545f
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuple.java
@@ -0,0 +1,69 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.tuple;
11
12/**
13 * Immutable tuple. Obtain instances via utility class {@link Tuples}.
14 * @author Gabor Bergmann
15 *
16 */
17public abstract class Tuple extends AbstractTuple {
18
19 /**
20 * Caches precalculated hash value
21 */
22 protected int cachedHash;
23
24 /**
25 * Creates a Tuple instance Derivatives should call calcHash()
26 */
27 protected Tuple() {
28 // calcHash();
29 }
30
31 /**
32 * Hash calculation. Overrides should keep semantics.
33 */
34 void calcHash() {
35 cachedHash = doCalcHash();
36 }
37
38 @Override
39 public boolean equals(Object obj) {
40 if (this == obj)
41 return true;
42 if (obj instanceof ITuple) {
43 final ITuple other = (ITuple) obj;
44 return cachedHash == other.hashCode() && internalEquals(other);
45 }
46 return false;
47 }
48
49 @Override
50 public int hashCode() {
51 // Calculated by #calcHash
52 return cachedHash;
53 }
54
55 public Tuple replaceAll(Object obsolete, Object replacement) {
56 Object[] oldElements = getElements();
57 Object[] newElements = new Object[oldElements.length];
58 for (int i = 0; i < oldElements.length; ++i) {
59 newElements[i] = obsolete.equals(oldElements[i]) ? replacement : oldElements[i];
60 }
61 return Tuples.flatTupleOf(newElements);
62 }
63
64 @Override
65 public Tuple toImmutable() {
66 return this;
67 }
68
69}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask.java
new file mode 100644
index 00000000..49c55fef
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask.java
@@ -0,0 +1,560 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.tuple;
11
12import java.util.ArrayList;
13import java.util.Arrays;
14import java.util.Collection;
15import java.util.HashSet;
16import java.util.LinkedList;
17import java.util.List;
18import java.util.OptionalInt;
19import java.util.Set;
20
21/**
22 *
23 * Specifies select indices of a tuple. If viewed through this mask (see {@link #transform(ITuple)}), the signature of the pattern will consist of its
24 * individual substitutions at the given positions, in the exact same order as they appear in indices[].
25 *
26 * @author Gabor Bergmann
27 */
28public class TupleMask {
29 /**
30 * indices[i] specifies the index of the substitution in the original tuple that occupies the i-th place in the
31 * masked signature.
32 */
33 public final int[] indices;
34 /**
35 * the size of the tuple this mask is applied to
36 */
37 public int sourceWidth;
38 /**
39 * indicesSorted is indices, sorted in ascending order.
40 * null by default, call {@link #ensureIndicesSorted()} before using
41 */
42 int[] indicesSorted;
43
44 /**
45 * true if no index occurs twice; computed on demand by {@link #isNonrepeating()}
46 */
47 Boolean isNonrepeating;
48
49 /**
50 * Creates a TupleMask instance with the given indices array
51 * <p> indicesSorted and isNonrepeating may be OPTIONALLY given if known.
52 * @since 2.0
53 */
54 protected TupleMask(int[] indices, int sourceWidth, int[] indicesSorted, Boolean isNonrepeating) {
55 this.indices = indices;
56 this.sourceWidth = sourceWidth;
57 this.indicesSorted = indicesSorted;
58 this.isNonrepeating = isNonrepeating;
59 }
60
61 /**
62 * Creates a TupleMask instance that selects given positions.
63 * The mask takes ownership of the array selectedIndices, the client must not modify it afterwards.
64 *
65 * <p> indicesSorted and isNonrepeating may be OPTIONALLY given if known.
66 * @since 2.0
67 */
68 protected static TupleMask fromSelectedIndicesInternal(
69 int[] selectedIndices, int sourceArity,
70 int[] indicesSorted, Boolean isNonrepeating)
71 {
72 if (selectedIndices.length == 0) // is it nullary?
73 return new TupleMask0(sourceArity);
74
75 // is it identity?
76 boolean identity = sourceArity == selectedIndices.length;
77 if (identity) {
78 for (int k=0; k < sourceArity; ++k) {
79 if (selectedIndices[k] != k) {
80 identity = false;
81 break;
82 }
83 }
84 }
85 if (identity)
86 return new TupleMaskIdentity(selectedIndices, sourceArity);
87
88 // generic case
89 return new TupleMask(selectedIndices, sourceArity, indicesSorted, isNonrepeating);
90 }
91
92 /**
93 * Creates a TupleMask instance that selects given positions in monotonically increasing order.
94 * The mask takes ownership of the array selectedIndices, the client must not modify it afterwards.
95 * @since 2.0
96 */
97 protected static TupleMask fromSelectedMonotonicIndicesInternal(int[] selectedIndices, int sourceArity)
98 {
99 return fromSelectedIndicesInternal(selectedIndices, sourceArity, selectedIndices /* also sorted */, true);
100 }
101
102 /**
103 * Creates a TupleMask instance of the given size that maps the first 'size' elements intact
104 */
105 public static TupleMask linear(int size, int sourceWidth) {
106 if (size == sourceWidth) return new TupleMaskIdentity(sourceWidth);
107 int[] indices = constructLinearSequence(size);
108 return fromSelectedMonotonicIndicesInternal(indices, sourceWidth);
109 }
110
111 /**
112 * An array containing the first {@link size} nonnegative integers in order
113 * @since 2.0
114 */
115 protected static int[] constructLinearSequence(int size) {
116 int[] indices = new int[size];
117 for (int i = 0; i < size; i++)
118 indices[i] = i;
119 return indices;
120 }
121
122 /**
123 * Creates a TupleMask instance of the given size that maps every single element intact
124 */
125 public static TupleMask identity(int size) {
126 return new TupleMaskIdentity(size);
127 }
128
129 /**
130 * Creates a TupleMask instance of the given size that does not emit output.
131 */
132 public static TupleMask empty(int sourceWidth) {
133 return linear(0, sourceWidth);
134 }
135
136 /**
137 * Creates a TupleMask instance that maps the tuple intact save for a single element at the specified index which is
138 * omitted
139 */
140 public static TupleMask omit(int omission, int sourceWidth) {
141 int size = sourceWidth - 1;
142 int[] indices = new int[size];
143 for (int i = 0; i < omission; i++)
144 indices[i] = i;
145 for (int i = omission; i < size; i++)
146 indices[i] = i + 1;
147 return fromSelectedMonotonicIndicesInternal(indices, sourceWidth);
148 }
149
150
151 /**
152 * Creates a TupleMask instance that selects positions where keep is true
153 * @since 1.7
154 */
155 public static TupleMask fromKeepIndicators(boolean[] keep) {
156 int size = 0;
157 for (int k = 0; k < keep.length; ++k)
158 if (keep[k])
159 size++;
160 if (size == keep.length) return new TupleMaskIdentity(size);
161 int[] indices = new int[size];
162 int l = 0;
163 for (int k = 0; k < keep.length; ++k)
164 if (keep[k])
165 indices[l++] = k;
166 return fromSelectedMonotonicIndicesInternal(indices, keep.length);
167 }
168
169 /**
170 * Creates a TupleMask instance that selects given positions.
171 * @since 1.7
172 */
173 public static TupleMask fromSelectedIndices(int sourceArity, Collection<Integer> selectedIndices) {
174 int[] selected = integersToIntArray(selectedIndices);
175 return fromSelectedIndicesInternal(selected, sourceArity, null, null);
176 }
177 /**
178 * Creates a TupleMask instance that selects given positions.
179 * @since 1.7
180 */
181 public static TupleMask fromSelectedIndices(int sourceArity, int[] selectedIndices) {
182 return fromSelectedIndicesInternal(Arrays.copyOf(selectedIndices, selectedIndices.length), sourceArity, null, null);
183 }
184 /**
185 * Creates a TupleMask instance that selects non-null positions of a given tuple
186 * @since 1.7
187 */
188 public static TupleMask fromNonNullIndices(ITuple tuple) {
189 List<Integer> indices = new ArrayList<>();
190 for (int i=0; i < tuple.getSize(); i++) {
191 if (tuple.get(i) != null) {
192 indices.add(i);
193 }
194 }
195 if (indices.size() == tuple.getSize()) return new TupleMaskIdentity(indices.size());
196 return fromSelectedMonotonicIndicesInternal(integersToIntArray(indices), tuple.getSize());
197 }
198 /**
199 * @since 1.7
200 */
201 public static int[] integersToIntArray(Collection<Integer> selectedIndices) {
202 int[] selected = new int[selectedIndices.size()];
203 int k=0;
204 for (Integer integer : selectedIndices) {
205 selected[k++] = integer;
206 }
207 return selected;
208 }
209
210
211 /**
212 * Creates a TupleMask instance that moves an element from one index to other, shifting the others if neccessary.
213 */
214 public static TupleMask displace(int from, int to, int sourceWidth) {
215 if (from == to) return new TupleMaskIdentity(sourceWidth);
216 int[] indices = new int[sourceWidth];
217 for (int i = 0; i < sourceWidth; i++)
218 if (i == to)
219 indices[i] = from;
220 else if (i >= from && i < to)
221 indices[i] = i + 1;
222 else if (i > to && i <= from)
223 indices[i] = i - 1;
224 else
225 indices[i] = i;
226 return fromSelectedIndicesInternal(indices, sourceWidth, null, true);
227 }
228
229 /**
230 * Creates a TupleMask instance that selects a single element of the tuple.
231 */
232 public static TupleMask selectSingle(int selected, int sourceWidth) {
233 int[] indices = { selected };
234 return fromSelectedMonotonicIndicesInternal(indices, sourceWidth);
235 }
236
237 /**
238 * Creates a TupleMask instance that selects whatever is selected by left, and appends whatever is selected by
239 * right. PRE: left and right have the same sourcewidth
240 */
241 public static TupleMask append(TupleMask left, TupleMask right) {
242 int leftLength = left.indices.length;
243 int rightLength = right.indices.length;
244 int[] indices = new int[leftLength + rightLength];
245 for (int i = 0; i < leftLength; ++i)
246 indices[i] = left.indices[i];
247 for (int i = 0; i < rightLength; ++i)
248 indices[i + leftLength] = right.indices[i];
249 return fromSelectedIndicesInternal(indices, left.sourceWidth, null, null);
250 }
251
252 /**
253 * Generates indicesSorted from indices on demand
254 */
255 void ensureIndicesSorted() {
256 if (indicesSorted == null) {
257 indicesSorted = new int[indices.length];
258 List<Integer> list = new LinkedList<Integer>();
259 for (int i = 0; i < indices.length; ++i)
260 list.add(indices[i]);
261 java.util.Collections.sort(list);
262 int i = 0;
263 for (Integer a : list)
264 indicesSorted[i++] = a;
265 }
266 }
267
268
269
270 /**
271 * Returns the first index of the source that is not selected by the mask, or empty if all indices are selected.
272 * <p> PRE: mask indices are all different
273 * @since 2.0
274 */
275 public OptionalInt getFirstOmittedIndex() {
276 ensureIndicesSorted();
277 int column = 0;
278 while (column < getSize() && indicesSorted[column] == column) column++;
279 if (column < getSourceWidth()) return OptionalInt.of(column);
280 else return OptionalInt.empty();
281 }
282
283
284 /**
285 * Returns a selected masked value from the selected tuple.
286 * @pre: 0 <= index < getSize()
287 * @since 1.7
288 */
289 public Object getValue(ITuple original, int index) {
290 return original.get(indices[index]);
291 }
292
293 /**
294 * Sets the selected value in the original tuple based on the mask definition
295 *
296 * @pre: 0 <= index < getSize()
297 * @since 1.7
298 */
299 public void set(IModifiableTuple tuple, int index, Object value) {
300 tuple.set(indices[index], value);
301 }
302
303 /**
304 * Generates an immutable, masked view of the original tuple.
305 * <p> The new tuple will have arity {@link #getSize()},
306 * and will consist of the elements of the original tuple, at positions indicated by this mask.
307 * @since 1.7
308 */
309 public Tuple transform(ITuple original) {
310 switch (indices.length) {
311 case 0:
312 return FlatTuple0.INSTANCE;
313 case 1:
314 return new FlatTuple1(original.get(indices[0]));
315 case 2:
316 return new FlatTuple2(original.get(indices[0]), original.get(indices[1]));
317 case 3:
318 return new FlatTuple3(original.get(indices[0]), original.get(indices[1]), original.get(indices[2]));
319 case 4:
320 return new FlatTuple4(original.get(indices[0]), original.get(indices[1]), original.get(indices[2]), original.get(indices[3]));
321 default:
322 Object signature[] = new Object[indices.length];
323 for (int i = 0; i < indices.length; ++i)
324 signature[i] = original.get(indices[i]);
325 return new FlatTuple(signature);
326 }
327 }
328
329 /**
330 * @return true iff no two selected indices are the same
331 * @since 2.0
332 */
333 public boolean isNonrepeating() {
334 if (isNonrepeating == null) {
335 ensureIndicesSorted();
336 int previous = -1;
337 int i;
338 for (i = 0; i < sourceWidth && previous != indicesSorted[i]; ++i) {
339 previous = indicesSorted[i];
340 }
341 isNonrepeating = (i == sourceWidth); // if not, stopped due to detected repetition
342 }
343 return isNonrepeating;
344 }
345
346 /**
347 * Returns a tuple `result` that satisfies `this.transform(result).equals(masked)`. Positions of the result tuple
348 * that are not determined this way will be filled with null.
349 *
350 * @pre: all indices of the mask must be different, i.e {@link #isNonrepeating()} must return true
351 * @since 1.7
352 */
353 public Tuple revertFrom(ITuple masked) {
354 Object[] signature = new Object[sourceWidth];
355 for (int i = 0; i < indices.length; ++i)
356 signature[indices[i]] = masked.get(i);
357 return Tuples.flatTupleOf(signature);
358 }
359
360 /**
361 * Returns a tuple `result`, same arity as the original tuple, that satisfies
362 * `this.transform(result).equals(this.transform(tuple))`.
363 * Positions of the result tuple that are not determined this way will be filled with null.
364 * <p> In other words, a copy of the original tuple is returned,
365 * with null substituted at each position that is <em>not</em> selected by this mask.
366 *
367 * @pre: all indices of the mask must be different, i.e {@link #isNonrepeating()} must return true
368 * @since 2.1
369 */
370 public Tuple keepSelectedIndices(ITuple original) {
371 Object[] signature = new Object[sourceWidth];
372 for (int i = 0; i < indices.length; ++i)
373 signature[indices[i]] = original.get(indices[i]);
374 return Tuples.flatTupleOf(signature);
375 }
376
377 /**
378 * Generates an immutable, masked view of the original tuple.
379 * <p> The list will have arity {@link #getSize()},
380 * and will consist of the elements of the original tuple, at positions indicated by this mask.
381 */
382 public <T> List<T> transform(List<T> original) {
383 List<T> signature = new ArrayList<T>(indices.length);
384 for (int i = 0; i < indices.length; ++i)
385 signature.add(original.get(indices[i]));
386 return signature;
387 }
388
389 /**
390 * Transforms a given mask directly, instead of transforming tuples that were transformed by the other mask.
391 *
392 * @return a mask that cascades the effects this mask after the mask provided as parameter.
393 */
394 public TupleMask transform(TupleMask mask) {
395 int[] cascadeIndices = new int[indices.length];
396 for (int i = 0; i < indices.length; ++i)
397 cascadeIndices[i] = mask.indices[indices[i]];
398 return fromSelectedIndicesInternal(cascadeIndices, mask.sourceWidth, null, null);
399 }
400
401 // /**
402 // * Generates a complementer mask that maps those elements that were
403 // untouched by the original mask.
404 // * Ordering is left intact.
405 // * A Tuple is used for reference concerning possible equalities among
406 // elements.
407 // */
408 // public TupleMask complementer(Tuple reference)
409 // {
410 // HashSet<Object> touched = new HashSet<Object>();
411 // LinkedList<Integer> untouched = new LinkedList<Integer>();
412 //
413 // for (int index : indices) touched.add(reference.get(index));
414 // for (int index=0; index<reference.getSize(); ++index)
415 // {
416 // if (touched.add(reference.get(index))) untouched.addLast(index);
417 // }
418 //
419 // int[] complementer = new int[untouched.size()];
420 // int k = 0;
421 // for (Integer integer : untouched) complementer[k++] = integer;
422 // return new TupleMask(complementer, reference.getSize());
423 // }
424
425 /**
426 * Combines two substitutions. The new pattern will contain all substitutions of masked and unmasked, assuming that
427 * the elements of masked indicated by this mask are already matched against unmasked.
428 *
429 * POST: the result will start with an exact copy of unmasked
430 *
431 * @param unmasked
432 * primary pattern substitution that is left intact.
433 * @param masked
434 * secondary pattern substitution that is transformed to the end of the result.
435 * @param useInheritance
436 * whether to use inheritance or copy umasked into result instead.
437 * @param asComplementer
438 * whether this mask maps from the masked Tuple to the tail of the result or to the unmasked one.
439 * @return new pattern that is a combination of unmasked and masked.
440 */
441 public Tuple combine(Tuple unmasked, Tuple masked, boolean useInheritance, boolean asComplementer) {
442
443 int combinedLength = asComplementer ? indices.length : masked.getSize() - indices.length;
444 if (!useInheritance)
445 combinedLength += unmasked.getSize();
446 Object combined[] = new Object[combinedLength];
447
448 int cPos = 0;
449 if (!useInheritance) {
450 for (int i = 0; i < unmasked.getSize(); ++i)
451 combined[cPos++] = unmasked.get(i);
452 }
453
454 if (asComplementer) {
455 for (int i = 0; i < indices.length; ++i)
456 combined[cPos++] = masked.get(indices[i]);
457 } else {
458 ensureIndicesSorted();
459 int mPos = 0;
460 for (int i = 0; i < masked.getSize(); ++i)
461 if (mPos < indicesSorted.length && i == indicesSorted[mPos])
462 mPos++;
463 else
464 combined[cPos++] = masked.get(i);
465 }
466
467 return useInheritance ? Tuples.leftInheritanceTupleOf(unmasked, combined) : Tuples.flatTupleOf(combined);
468 }
469
470 @Override
471 public int hashCode() {
472 final int PRIME = 31;
473 int result = sourceWidth;
474 for (int i : indices)
475 result = PRIME * result + i;
476 return result;
477 }
478
479 @Override
480 public boolean equals(Object obj) {
481 if (this == obj)
482 return true;
483 if (obj == null)
484 return false;
485 if (getClass() != obj.getClass())
486 return false;
487 final TupleMask other = (TupleMask) obj;
488 if (sourceWidth != other.sourceWidth)
489 return false;
490 if (indices.length != other.indices.length)
491 return false;
492 for (int k = 0; k < indices.length; k++)
493 if (indices[k] != other.indices[k])
494 return false;
495 return true;
496 }
497
498 @Override
499 public String toString() {
500 StringBuilder s = new StringBuilder();
501 s.append("M(" + sourceWidth + "->");
502 for (int i : indices) {
503 s.append(i);
504 s.append(',');
505 }
506 s.append(')');
507 return s.toString();
508 }
509
510 /**
511 * Returns the size of the masked tuples described by this mask
512 * @since 1.7
513 */
514 public int getSize() {
515 return indices.length;
516 }
517
518 /**
519 * Returns the size of the original tuples handled by this mask
520 * @since 1.7
521 */
522 public int getSourceWidth() {
523 return sourceWidth;
524 }
525
526
527 /**
528 * @return true iff this mask is a no-op
529 * @since 2.0
530 */
531 public boolean isIdentity() {
532 // Contract: if identity mask, a specialized subclass is constructed instead
533 return false;
534 }
535
536 /**
537 * Transforms the given list by applying the mask and putting all results into a set; keeping only a single element
538 * in case of the mapping result in duplicate values.
539 *
540 * @since 1.7
541 */
542 public <T> Set<T> transformUnique(List<T> original) {
543 Set<T> signature = new HashSet<>();
544 for (int i = 0; i < indices.length; ++i)
545 signature.add(original.get(indices[i]));
546 return signature;
547 }
548
549 /**
550 * @return the list of selected indices
551 * @since 2.1
552 */
553 public List<Integer> getIndicesAsList() {
554 List<Integer> result = new ArrayList<Integer>(indices.length);
555 for (int i = 0; i < indices.length; ++i)
556 result.add(indices[i]);
557 return result;
558 }
559
560}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask0.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask0.java
new file mode 100644
index 00000000..5a0c79ff
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMask0.java
@@ -0,0 +1,56 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Collections;
12import java.util.List;
13
14/**
15 * @author Gabor Bergmann
16 * @since 1.7
17 */
18public final class TupleMask0 extends TupleMask {
19
20 private final static int[] EMPTY_ARRAY = {};
21
22 /**
23 * PRE: indices.length == 0
24 */
25 TupleMask0(int sourceWidth) {
26 super(EMPTY_ARRAY, sourceWidth, EMPTY_ARRAY, true);
27 }
28
29 @Override
30 public <T> List<T> transform(List<T> original) {
31 return Collections.emptyList();
32 }
33
34 @Override
35 public Tuple transform(ITuple original) {
36 return Tuples.staticArityFlatTupleOf();
37 }
38
39 @Override
40 public TupleMask transform(TupleMask mask) {
41 return new TupleMask0(mask.sourceWidth);
42 }
43
44 @Override
45 public Tuple combine(Tuple unmasked, Tuple masked, boolean useInheritance, boolean asComplementer) {
46 if (asComplementer)
47 return unmasked;
48 else
49 return super.combine(unmasked, masked, useInheritance, asComplementer);
50 }
51
52 @Override
53 public boolean isIdentity() {
54 return 0 == sourceWidth;
55 }
56}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMaskIdentity.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMaskIdentity.java
new file mode 100644
index 00000000..62746587
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleMaskIdentity.java
@@ -0,0 +1,51 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.List;
12
13/**
14 * @author Gabor Bergmann
15 * @since 1.7
16 */
17public final class TupleMaskIdentity extends TupleMask {
18
19 TupleMaskIdentity(int sourceWidth) {
20 this(constructLinearSequence(sourceWidth), sourceWidth);
21 }
22 TupleMaskIdentity(int[] indices, int sourceWidth) {
23 super(indices, sourceWidth, indices, true);
24 }
25
26 @Override
27 public <T> List<T> transform(List<T> original) {
28 return original;
29 }
30
31 @Override
32 public Tuple transform(ITuple original) {
33 return original.toImmutable();
34 }
35
36 @Override
37 public TupleMask transform(TupleMask mask) {
38 return mask;
39 }
40
41 @Override
42 public Tuple revertFrom(ITuple masked) {
43 return masked.toImmutable();
44 }
45
46 @Override
47 public boolean isIdentity() {
48 return true;
49 }
50
51}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleValueProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleValueProvider.java
new file mode 100644
index 00000000..79193516
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/TupleValueProvider.java
@@ -0,0 +1,48 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import java.util.Map;
12
13import tools.refinery.viatra.runtime.matchers.psystem.IValueProvider;
14
15/**
16 * @author Zoltan Ujhelyi
17 * @since 1.7
18 */
19public class TupleValueProvider implements IValueProvider {
20
21 final ITuple tuple;
22 final Map<String, Integer> indexMapping;
23
24 /**
25 * Wraps a tuple with an index mapping
26 * @param tuple
27 * @param indexMapping
28 */
29 public TupleValueProvider(ITuple tuple, Map<String, Integer> indexMapping) {
30 super();
31 this.tuple = tuple;
32 this.indexMapping = indexMapping;
33 }
34
35 @Override
36 public Object getValue(String variableName) {
37 Integer index = indexMapping.get(variableName);
38 if (index == null) {
39 throw new IllegalArgumentException(String.format("Variable %s is not present in mapping.", variableName));
40 }
41 Object value = tuple.get(index);
42 if (value == null) {
43 throw new IllegalArgumentException(String.format("Variable %s is not found using index %d.", variableName, index));
44 }
45 return value;
46 }
47
48}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuples.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuples.java
new file mode 100644
index 00000000..5e41d7d8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/Tuples.java
@@ -0,0 +1,157 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11/**
12 * Common static factory utilities for tuples.
13 *
14 * @author Gabor Bergmann
15 * @since 1.7
16 */
17public class Tuples {
18
19 private Tuples() {
20 // Empty utility class constructor
21 }
22
23 /**
24 * Creates a flat tuple consisting of the given elements.
25 * For low-arity tuples, specialized implementations
26 * (such as {@link FlatTuple2}) will be instantiated.
27 *
28 * <p> In case the exact arity is <i>statically</i> known,
29 * it may be more efficient for the client to instantiate
30 * the appropriate specialized implementation
31 * (via {@link #staticArityFlatTupleOf(Object, Object)} etc.
32 * or {@link #wideFlatTupleOf(Object...)}),
33 * instead of invoking this method.
34 * This method does a runtime arity check, and therefore
35 * also appropriate if the arity is determined at runtime.
36 */
37 public static Tuple flatTupleOf(Object... elements) {
38 switch (elements.length) {
39 case 0:
40 return FlatTuple0.INSTANCE;
41 case 1:
42 return new FlatTuple1(elements[0]);
43 case 2:
44 return new FlatTuple2(elements[0], elements[1]);
45 case 3:
46 return new FlatTuple3(elements[0], elements[1], elements[2]);
47 case 4:
48 return new FlatTuple4(elements[0], elements[1], elements[2], elements[3]);
49 default:
50 return new FlatTuple(elements);
51 }
52 }
53 /**
54 * Creates a left inheritance tuple that extends an ancestor tuple
55 * by the given "local" elements.
56 * For locally low-arity tuples, specialized implementations
57 * (such as {@link LeftInheritanceTuple2}) will be instantiated.
58 *
59 * <p> In case the exact arity is <i>statically</i> known,
60 * it may be more efficient for the client to instantiate
61 * the appropriate specialized implementation
62 * (via {@link #staticArityLeftInheritanceTupleOf(Object, Object)} etc.
63 * or {@link #wideLeftInheritanceTupleOf(Object...)}),
64 * instead of invoking this method.
65 * This method does a runtime arity check, and therefore
66 * also appropriate if the arity is determined at runtime.
67 */
68 public static Tuple leftInheritanceTupleOf(Tuple ancestor, Object... localElements) {
69 switch (localElements.length) {
70 case 0:
71 return ancestor;
72 case 1:
73 return new LeftInheritanceTuple1(ancestor, localElements[0]);
74 case 2:
75 return new LeftInheritanceTuple2(ancestor, localElements[0], localElements[1]);
76 case 3:
77 return new LeftInheritanceTuple3(ancestor, localElements[0], localElements[1], localElements[2]);
78 case 4:
79 return new LeftInheritanceTuple4(ancestor, localElements[0], localElements[1], localElements[2], localElements[3]);
80 default:
81 return new LeftInheritanceTuple(ancestor, localElements);
82 }
83 }
84
85 /**
86 * Creates a flat tuple consisting of no elements.
87 */
88 public static Tuple staticArityFlatTupleOf() {
89 return FlatTuple0.INSTANCE;
90 }
91 /**
92 * Creates a flat tuple consisting of the given single element.
93 */
94 public static Tuple staticArityFlatTupleOf(Object element) {
95 return new FlatTuple1(element);
96 }
97 /**
98 * Creates a flat tuple consisting of the given elements.
99 */
100 public static Tuple staticArityFlatTupleOf(Object element0, Object element1) {
101 return new FlatTuple2(element0, element1);
102 }
103 /**
104 * Creates a flat tuple consisting of the given elements.
105 */
106 public static Tuple staticArityFlatTupleOf(Object element0, Object element1, Object element2) {
107 return new FlatTuple3(element0, element1, element2);
108 }
109 /**
110 * Creates a flat tuple consisting of the given elements.
111 */
112 public static Tuple staticArityFlatTupleOf(Object element0, Object element1, Object element2, Object element3) {
113 return new FlatTuple4(element0, element1, element2, element3);
114 }
115 /**
116 * Creates a flat tuple consisting of the given elements.
117 * <p> Invoke this only if it is statically known that the tuple will be wide.
118 * Otherwise, use {@link #flatTupleOf(Object...)}.
119 */
120 public static Tuple wideFlatTupleOf(Object... elements) {
121 return new FlatTuple(elements);
122 }
123
124 /**
125 * Creates a left inheritance tuple consisting of the given single local element.
126 */
127 public static Tuple staticArityLeftInheritanceTupleOf(Tuple ancestor, Object element) {
128 return new LeftInheritanceTuple1(ancestor, element);
129 }
130 /**
131 * Creates a left inheritance tuple consisting of the given local elements.
132 */
133 public static Tuple staticArityLeftInheritanceTupleOf(Tuple ancestor, Object element0, Object element1) {
134 return new LeftInheritanceTuple2(ancestor, element0, element1);
135 }
136 /**
137 * Creates a left inheritance tuple consisting of the given local elements.
138 */
139 public static Tuple staticArityLeftInheritanceTupleOf(Tuple ancestor, Object element0, Object element1, Object element2) {
140 return new LeftInheritanceTuple3(ancestor, element0, element1, element2);
141 }
142 /**
143 * Creates a left inheritance tuple consisting of the given local elements.
144 */
145 public static Tuple staticArityLeftInheritanceTupleOf(Tuple ancestor, Object element0, Object element1, Object element2, Object element3) {
146 return new LeftInheritanceTuple4(ancestor, element0, element1, element2, element3);
147 }
148 /**
149 * Creates a left inheritance tuple consisting of the given local elements.
150 * <p> Invoke this only if it is statically known that the tuple will be wide.
151 * Otherwise, use {@link #leftInheritanceTupleOf(Tuple, Object...)}.
152 */
153 public static Tuple wideLeftInheritanceTupleOf(Tuple ancestor, Object... elements) {
154 return new LeftInheritanceTuple(ancestor, elements);
155 }
156
157}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileMaskedTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileMaskedTuple.java
new file mode 100644
index 00000000..f683d544
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileMaskedTuple.java
@@ -0,0 +1,50 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import tools.refinery.viatra.runtime.matchers.util.Preconditions;
12
13/**
14 * This class provides a volatile tuple view with a given mask of a given tuple instance. If the masked tuple changes,
15 * the view updates as well.
16 *
17 * @author Zoltan Ujhelyi
18 * @since 1.7
19 *
20 */
21public class VolatileMaskedTuple extends VolatileTuple {
22
23 protected final TupleMask mask;
24 protected ITuple source;
25
26 public VolatileMaskedTuple(ITuple source, TupleMask mask) {
27 this.source = source;
28 this.mask = mask;
29 }
30
31 public VolatileMaskedTuple(TupleMask mask) {
32 this(null, mask);
33 }
34
35 public void updateTuple(ITuple newSource) {
36 source = newSource;
37 }
38
39 @Override
40 public Object get(int index) {
41 Preconditions.checkState(source != null, "Source tuple is not set.");
42 return mask.getValue(source, index);
43 }
44
45 @Override
46 public int getSize() {
47 return mask.getSize();
48 }
49
50}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileModifiableMaskedTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileModifiableMaskedTuple.java
new file mode 100644
index 00000000..92306c6e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileModifiableMaskedTuple.java
@@ -0,0 +1,47 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.tuple;
10
11import tools.refinery.viatra.runtime.matchers.util.Preconditions;
12
13/**
14 * A masked tuple implementation that allows modifying the backing tuple.
15 * @author Zoltan Ujhelyi
16 * @since 1.7
17 *
18 */
19public class VolatileModifiableMaskedTuple extends VolatileMaskedTuple implements IModifiableTuple {
20
21 private IModifiableTuple modifiableTuple;
22
23 public VolatileModifiableMaskedTuple(IModifiableTuple source, TupleMask mask) {
24 super(source, mask);
25 modifiableTuple = source;
26 }
27
28 public VolatileModifiableMaskedTuple(TupleMask mask) {
29 this(null, mask);
30 }
31
32 @Override
33 public void updateTuple(ITuple newSource) {
34 Preconditions.checkArgument(newSource instanceof IModifiableTuple, "Provided tuple does not support updates");
35 this.updateTuple((IModifiableTuple)newSource);
36 }
37
38 public void updateTuple(IModifiableTuple newSource) {
39 super.updateTuple(newSource);
40 modifiableTuple = newSource;
41 }
42
43 @Override
44 public void set(int index, Object value) {
45 mask.set(modifiableTuple, index, value);
46 }
47}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileTuple.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileTuple.java
new file mode 100644
index 00000000..699105a5
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/VolatileTuple.java
@@ -0,0 +1,47 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017 Zoltan Ujhelyi, IncQuery Labs
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.tuple;
11
12/**
13 * Mutable tuple without explicit modification commands. In practical terms, the values stored in a volatile tuple can
14 * be changed without any notification.
15 *
16 * @author Zoltan Ujhelyi
17 * @since 1.7
18 *
19 */
20public abstract class VolatileTuple extends AbstractTuple {
21
22 @Override
23 public boolean equals(Object obj) {
24 if (this == obj)
25 return true;
26 if (obj == null)
27 return false;
28 if (!(obj instanceof ITuple))
29 return false;
30 final ITuple other = (ITuple) obj;
31 return internalEquals(other);
32 }
33
34 @Override
35 public int hashCode() {
36 return doCalcHash();
37 }
38
39 /**
40 * Creates an immutable tuple from the values stored in the tuple. The created tuple will not be updated when the
41 * current tuple changes.
42 */
43 @Override
44 public Tuple toImmutable() {
45 return Tuples.flatTupleOf(getElements());
46 }
47}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Accuracy.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Accuracy.java
new file mode 100644
index 00000000..338990ab
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Accuracy.java
@@ -0,0 +1,48 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11/**
12 * The degree of accuracy of a cardinality estimate
13 * @author Gabor Bergmann
14 * @since 2.1
15 */
16public enum Accuracy {
17 EXACT_COUNT,
18 BEST_UPPER_BOUND,
19 BEST_LOWER_BOUND,
20 APPROXIMATION;
21
22 /**
23 * Partial order comparison.
24 */
25 public boolean atLeastAsPreciseAs(Accuracy other) {
26 switch (this) {
27 case EXACT_COUNT: return true;
28 case APPROXIMATION: return APPROXIMATION == other;
29 case BEST_UPPER_BOUND: return BEST_UPPER_BOUND == other || APPROXIMATION == other;
30 case BEST_LOWER_BOUND: return BEST_LOWER_BOUND == other || APPROXIMATION == other;
31 default: throw new IllegalArgumentException();
32 }
33 }
34
35 /**
36 * @return another accuracy value that is anti-monotonic to this one,
37 * i.e. an accuracy that should be used in the denominator to obtain a fraction with this accuracy
38 */
39 public Accuracy reciprocal() {
40 switch(this) {
41 case APPROXIMATION: return APPROXIMATION;
42 case BEST_UPPER_BOUND: return BEST_LOWER_BOUND;
43 case BEST_LOWER_BOUND: return BEST_UPPER_BOUND;
44 case EXACT_COUNT: return EXACT_COUNT;
45 default: throw new IllegalArgumentException();
46 }
47 }
48}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Clearable.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Clearable.java
new file mode 100644
index 00000000..1b09aec6
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Clearable.java
@@ -0,0 +1,23 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.util;
11
12/**
13 * @author Gabor Bergmann
14 * @since 1.7
15 * An instance of clearable pattern memory.
16 */
17public interface Clearable {
18 /**
19 * Clear all partial matchings stored in memory
20 *
21 */
22 void clear();
23}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/CollectionsFactory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/CollectionsFactory.java
new file mode 100644
index 00000000..590a1ec3
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/CollectionsFactory.java
@@ -0,0 +1,188 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Collection;
12import java.util.List;
13import java.util.Map;
14import java.util.Set;
15import java.util.TreeMap;
16import java.util.function.Function;
17
18/**
19 * Factory class used as an accessor to Collections implementations.
20 * @author istvanrath
21 */
22public final class CollectionsFactory
23{
24
25 /**
26 * Instantiates a new empty map.
27 * @since 1.7
28 */
29 public static <K, V> Map<K, V> createMap() {
30 return FRAMEWORK.createMap();
31 }
32
33 /**
34 * Instantiates a new map with the given initial contents.
35 * @since 1.7
36 */
37 public static <K, V> Map<K, V> createMap(Map<K, V> initial) {
38 return FRAMEWORK.createMap(initial);
39 }
40
41 /**
42 * Instantiates a new tree map.
43 * @since 2.3
44 */
45 public static <K, V> TreeMap<K, V> createTreeMap() {
46 return FRAMEWORK.createTreeMap();
47 }
48
49 /**
50 * Instantiates a new empty set.
51 * @since 1.7
52 */
53 public static <E> Set<E> createSet() {
54 return FRAMEWORK.createSet();
55 }
56
57 /**
58 * Instantiates a new set with the given initial contents.
59 * @since 1.7
60 */
61 public static <E> Set<E> createSet(Collection<E> initial) {
62 return FRAMEWORK.createSet(initial);
63 }
64
65 /**
66 * Instantiates an empty set; the key parameter is used to allow using this as a method reference as a
67 * {@link Function}, e.g. in {@link Map#computeIfAbsent(Object, Function)}.
68 *
69 * @param key
70 * the value of this parameter is ignored
71 * @since 2.0
72 */
73 public static <T> Set<T> emptySet(Object key) {
74 return FRAMEWORK.createSet();
75 }
76
77 /**
78 * Instantiates a new empty multiset.
79 * @since 1.7
80 */
81 public static <T> IMultiset<T> createMultiset() {
82 return FRAMEWORK.createMultiset();
83 }
84
85 /**
86 * Instantiates an empty multiset; the key parameter is used to allow using this as a method reference as a
87 * {@link Function}, e.g. in {@link Map#computeIfAbsent(Object, Function)}.
88 *
89 * @param key
90 * the value of this parameter is ignored
91 * @since 2.0
92 */
93 public static <T> IMultiset<T> emptyMultiset(Object key) {
94 return FRAMEWORK.createMultiset();
95 }
96
97 /**
98 * Instantiates a new empty delta bag.
99 * @since 1.7
100 */
101 public static <T> IDeltaBag<T> createDeltaBag() {
102 return FRAMEWORK.createDeltaBag();
103 }
104
105 /**
106 * Instantiates a new list that is optimized for registering observers / callbacks.
107 * @since 1.7
108 */
109 public static <O> List<O> createObserverList() {
110 return FRAMEWORK.createObserverList();
111 }
112
113 /**
114 * Instantiates a size-optimized multimap from keys to sets of values.
115 * <p>For a single key, many values can be associated according to the given bucket semantics.
116 * <p>The keys and values are stored as type fromKeys resp. ofValues;
117 * currently Object.class and Long.class are supported.
118 * @since 2.0
119 */
120 public static <K, V> IMultiLookup<K, V> createMultiLookup(
121 Class<? super K> fromKeys, MemoryType toBuckets, Class<? super V> ofValues) {
122 return FRAMEWORK.createMultiLookup(fromKeys, toBuckets, ofValues);
123 }
124
125 /**
126 * Instantiates a memory storing values.
127 * <p>For a single key, many values can be associated according to the given memory semantics.
128 * <p>The values are stored as type 'values';
129 * currently Object.class and Long.class are supported.
130 * @since 2.0
131 */
132 public static <T> IMemory<T> createMemory(
133 Class<? super T> values, MemoryType memoryType) {
134 return FRAMEWORK.createMemory(values, memoryType);
135 }
136
137 /**
138 * The type of {@link IMemory}
139 * @since 2.0
140 * TODO add delta as type
141 */
142 public enum MemoryType {
143 /**
144 * A single key-value pair is stored at most once
145 */
146 SETS,
147 /**
148 * Duplicate key-value pairs allowed
149 */
150 MULTISETS
151 }
152
153 /**
154 * The collections framework of the current configuration.
155 * @since 1.7
156 */
157 private static final ICollectionsFramework FRAMEWORK = new EclipseCollectionsFactory();
158
159 /**
160 * Interface abstracting over a collections technology that provides custom collection implementations.
161 * @since 1.7
162 */
163 public static interface ICollectionsFramework {
164
165 public abstract <K,V> Map<K,V> createMap();
166 public abstract <K,V> Map<K,V> createMap(Map<K,V> initial);
167 /**
168 * @since 2.3
169 */
170 public abstract <K, V> TreeMap<K, V> createTreeMap();
171 public abstract <E> Set<E> createSet();
172 public abstract <E> Set<E> createSet(Collection<E> initial);
173 public abstract <T> IMultiset<T> createMultiset();
174 public abstract <T> IDeltaBag<T> createDeltaBag();
175 public abstract <O> List<O> createObserverList();
176
177 /**
178 * @since 2.0
179 */
180 public abstract <K, V> IMultiLookup<K, V> createMultiLookup(
181 Class<? super K> fromKeys, MemoryType toBuckets, Class<? super V> ofValues);
182 /**
183 * @since 2.0
184 */
185 public abstract <T> IMemory<T> createMemory(Class<? super T> values, MemoryType memoryType);
186 }
187
188} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Direction.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Direction.java
new file mode 100644
index 00000000..88f7ec00
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Direction.java
@@ -0,0 +1,61 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, itemis AG, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11/**
12 * Indicates whether a propagated update event signals the insertion or deletion of an element
13 *
14 * @author Gabor Bergmann
15 */
16public enum Direction {
17 INSERT, DELETE;
18
19 /**
20 * @since 2.4
21 */
22 public Direction opposite() {
23 switch (this) {
24 case INSERT:
25 return DELETE;
26 default:
27 return INSERT;
28 }
29 }
30
31 /**
32 * @since 2.4
33 */
34 public char asSign() {
35 switch (this) {
36 case INSERT:
37 return '+';
38 default:
39 return '-';
40 }
41 }
42
43 /**
44 * Returns the direction that is the product of this direction and the other direction.
45 *
46 * DELETE x DELETE = INSERT
47 * DELETE x INSERT = DELETE
48 * INSERT x DELETE = DELETE
49 * INSERT x INSERT = INSERT
50 * @since 2.4
51 */
52 public Direction multiply(final Direction other) {
53 switch (this) {
54 case DELETE:
55 return other.opposite();
56 default:
57 return other;
58 }
59 }
60
61}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsBagMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsBagMemory.java
new file mode 100644
index 00000000..e24b2448
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsBagMemory.java
@@ -0,0 +1,86 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2008 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.util;
11
12import java.util.Iterator;
13import java.util.Set;
14import java.util.function.BiConsumer;
15
16import org.eclipse.collections.impl.map.mutable.primitive.ObjectIntHashMap;
17
18/**
19 * Eclipse Collections-based multiset for tuples. Can contain duplicate occurrences of the same matching.
20 *
21 * <p>Inherits Eclipse Collections' Object-to-Int primitive hashmap and counts the number of occurrences of each value.
22 * Element is deleted if # of occurences drops to 0.
23 *
24 * @author Gabor Bergmann.
25 * @since 1.7
26 * @noreference
27 */
28public abstract class EclipseCollectionsBagMemory<T> extends ObjectIntHashMap<T> implements IMemory<T> {
29
30 public EclipseCollectionsBagMemory() {
31 super();
32 }
33
34 @Override
35 public int getCount(T value) {
36 return super.getIfAbsent(value, 0);
37 }
38 @Override
39 public int getCountUnsafe(Object value) {
40 return super.getIfAbsent(value, 0);
41 }
42 @Override
43 public boolean containsNonZero(T value) {
44 return super.containsKey(value);
45 }
46 @Override
47 public boolean containsNonZeroUnsafe(Object value) {
48 return super.containsKey(value);
49 }
50
51 @Override
52 public void clearAllOf(T value) {
53 super.remove(value);
54 }
55
56
57 @Override
58 public Iterator<T> iterator() {
59 return super.keySet().iterator();
60 }
61
62 @Override
63 public String toString() {
64 return "TM" + super.toString();
65 }
66
67 @Override
68 public Set<T> distinctValues() {
69 return super.keySet();
70 }
71
72 @Override
73 public void forEachEntryWithMultiplicities(BiConsumer<T, Integer> entryConsumer) {
74 super.forEachKeyValue(entryConsumer::accept);
75 }
76
77 @Override
78 public int hashCode() {
79 return IMemoryView.hashCode(this);
80 }
81 @Override
82 public boolean equals(Object obj) {
83 return IMemoryView.equals(this, obj);
84 }
85
86}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsDeltaBag.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsDeltaBag.java
new file mode 100644
index 00000000..94ec33cd
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsDeltaBag.java
@@ -0,0 +1,41 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11/**
12 * @author Gabor Bergmann
13 * @since 1.7
14 */
15public class EclipseCollectionsDeltaBag<T> extends EclipseCollectionsBagMemory<T> implements IDeltaBag<T> {
16
17 @Override
18 public boolean addOne(T value) {
19 return addSigned(value, +1);
20 }
21
22 @Override
23 public boolean addSigned(T value, int count) {
24 int oldCount = super.getIfAbsent(value, 0);
25 int newCount = oldCount + count;
26
27 boolean becomesZero = newCount == 0;
28 if (becomesZero)
29 super.removeKey(value);
30 else
31 super.put(value, newCount);
32
33 return becomesZero || oldCount == 0;
34 }
35
36
37 @Override
38 public boolean removeOne(T value) {
39 return addSigned(value, -1);
40 }
41}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsFactory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsFactory.java
new file mode 100644
index 00000000..5a623c9b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsFactory.java
@@ -0,0 +1,159 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.List;
14import java.util.Map;
15import java.util.Set;
16import java.util.TreeMap;
17
18import org.eclipse.collections.api.map.MutableMap;
19import org.eclipse.collections.impl.factory.Maps;
20import org.eclipse.collections.impl.factory.Sets;
21import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.ICollectionsFramework;
22import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
23
24/**
25 * @author Gabor Bergmann
26 * @since 1.7
27 * @noreference This class is not intended to be referenced by clients.
28 */
29public class EclipseCollectionsFactory implements ICollectionsFramework {
30
31 @Override
32 public <K, V> Map<K, V> createMap() {
33 return Maps.mutable.empty();
34 }
35
36 @Override
37 public <K, V> Map<K, V> createMap(Map<K, V> initial) {
38 MutableMap<K, V> result = Maps.mutable.ofInitialCapacity(initial.size());
39 result.putAll(initial);
40 return result;
41 }
42
43 @Override
44 public <K, V> TreeMap<K, V> createTreeMap() {
45 // eclipse collections is doing the same
46 return new TreeMap<>();
47 }
48
49 @Override
50 public <E> Set<E> createSet() {
51 return Sets.mutable.empty();
52 }
53
54 @Override
55 public <E> Set<E> createSet(Collection<E> initial) {
56 return Sets.mutable.ofAll(initial);
57 }
58
59 @Override
60 public <T> IMultiset<T> createMultiset() {
61 return new EclipseCollectionsMultiset<T>();
62 }
63
64 @Override
65 public <T> IDeltaBag<T> createDeltaBag() {
66 return new EclipseCollectionsDeltaBag<T>();
67 }
68
69 @Override
70 public <O> List<O> createObserverList() {
71 return new ArrayList<O>(1); // keep concurrent modification exceptions for error detection
72 // Lists.mutable.empty
73
74 }
75
76 @Override
77 @SuppressWarnings({ "unchecked", "rawtypes" })
78 public <K, V> IMultiLookup<K, V> createMultiLookup(
79 Class<? super K> fromKeys,
80 MemoryType toBuckets,
81 Class<? super V> ofValues)
82 {
83 boolean longKeys = Long.class.equals(fromKeys);
84 boolean objectKeys = Object.class.equals(fromKeys);
85 if (! (longKeys || objectKeys)) throw new IllegalArgumentException(fromKeys.getName());
86 boolean longValues = Long.class.equals(ofValues);
87 boolean objectValues = Object.class.equals(ofValues);
88 if (! (longValues || objectValues)) throw new IllegalArgumentException(ofValues.getName());
89
90 if (longKeys) { // K == java.lang.Long
91 if (longValues) { // V == java.lang.Long
92 switch(toBuckets) {
93 case MULTISETS:
94 return (IMultiLookup<K, V>) new EclipseCollectionsMultiLookup.FromLongs.ToMultisets.OfLongs();
95 case SETS:
96 return (IMultiLookup<K, V>) new EclipseCollectionsMultiLookup.FromLongs.ToSets.OfLongs();
97 default:
98 throw new IllegalArgumentException(toBuckets.toString());
99 }
100 } else { // objectValues
101 switch(toBuckets) {
102 case MULTISETS:
103 return new EclipseCollectionsMultiLookup.FromLongs.ToMultisets.OfObjects();
104 case SETS:
105 return new EclipseCollectionsMultiLookup.FromLongs.ToSets.OfObjects();
106 default:
107 throw new IllegalArgumentException(toBuckets.toString());
108 }
109 }
110 } else { // objectKeys
111 if (longValues) { // V == java.lang.Long
112 switch(toBuckets) {
113 case MULTISETS:
114 return new EclipseCollectionsMultiLookup.FromObjects.ToMultisets.OfLongs();
115 case SETS:
116 return new EclipseCollectionsMultiLookup.FromObjects.ToSets.OfLongs();
117 default:
118 throw new IllegalArgumentException(toBuckets.toString());
119 }
120 } else { // objectValues
121 switch(toBuckets) {
122 case MULTISETS:
123 return new EclipseCollectionsMultiLookup.FromObjects.ToMultisets.OfObjects();
124 case SETS:
125 return new EclipseCollectionsMultiLookup.FromObjects.ToSets.OfObjects();
126 default:
127 throw new IllegalArgumentException(toBuckets.toString());
128 }
129 }
130 }
131 }
132
133 @Override
134 @SuppressWarnings("unchecked")
135 public <T> IMemory<T> createMemory(Class<? super T> values, MemoryType memoryType) {
136 if (Long.class.equals(values)) { // T == java.lang.Long
137 switch(memoryType) {
138 case MULTISETS:
139 return (IMemory<T>) new EclipseCollectionsLongMultiset();
140 case SETS:
141 return (IMemory<T>) new EclipseCollectionsLongSetMemory();
142 default:
143 throw new IllegalArgumentException(memoryType.toString());
144 }
145 } else { // objectValues
146 switch(memoryType) {
147 case MULTISETS:
148 return new EclipseCollectionsMultiset<>();
149 case SETS:
150 return new EclipseCollectionsSetMemory<>();
151 default:
152 throw new IllegalArgumentException(memoryType.toString());
153 }
154 }
155 }
156
157
158
159}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongMultiset.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongMultiset.java
new file mode 100644
index 00000000..88773c5d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongMultiset.java
@@ -0,0 +1,150 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Iterator;
12import java.util.Set;
13import java.util.function.BiConsumer;
14
15import org.eclipse.collections.impl.map.mutable.primitive.LongIntHashMap;
16
17/**
18 * @author Gabor Bergmann
19 * @since 2.0
20 * <p> TODO refactor common methods with {@link EclipseCollectionsMultiset}
21 * <p> TODO refactor into LongBagMemory etc.
22 */
23public class EclipseCollectionsLongMultiset extends LongIntHashMap implements IMultiset<Long> {
24
25 @Override
26 public boolean addOne(Long value) {
27 int oldCount = super.getIfAbsent(value, 0);
28
29 super.put(value, oldCount + 1);
30
31 return oldCount == 0;
32 }
33
34 @Override
35 public boolean addSigned(Long value, int count) {
36 int oldCount = super.getIfAbsent(value, 0);
37 int newCount = oldCount + count;
38
39 boolean becomesZero = newCount == 0;
40 if (newCount < 0)
41 throw new IllegalStateException(String.format(
42 "Cannot remove %d occurrences of value '%s' as only %d would remain in %s",
43 count, value, newCount, this));
44 else if (becomesZero)
45 super.removeKey(value);
46 else // (newCount > 0)
47 super.put(value, newCount);
48
49 return becomesZero || oldCount == 0;
50 }
51
52 @Override
53 public boolean removeOne(Long value) {
54 return removeOneInternal(value, true);
55 }
56 /**
57 * @since 2.3
58 */
59 @Override
60 public boolean removeOneOrNop(Long value) {
61 return removeOneInternal(value, false);
62 }
63
64
65 /**
66 * @since 2.3
67 */
68 protected boolean removeOneInternal(Long value, boolean throwIfImpossible) {
69 int oldCount = super.getIfAbsent(value, 0);
70 if (oldCount == 0) {
71 if (throwIfImpossible) throw new IllegalStateException(String.format(
72 "Cannot remove value '%s' that is not contained in %s",
73 value, this));
74 else return false;
75 }
76
77 int rest = oldCount - 1;
78 boolean empty = rest == 0;
79
80 if (!empty) {
81 super.put(value, rest);
82 } else {
83 super.remove(value);
84 }
85
86 return empty;
87 }
88
89 @Override
90 public void clearAllOf(Long value) {
91 super.remove(value);
92 }
93
94 @Override
95 public int getCount(Long value) {
96 return super.getIfAbsent(value, 0);
97 }
98 @Override
99 public int getCountUnsafe(Object value) {
100 return value instanceof Long ? getCount((Long) value) : 0;
101 }
102
103 @Override
104 public boolean containsNonZero(Long value) {
105 return super.containsKey(value);
106 }
107
108 @Override
109 public boolean containsNonZeroUnsafe(Object value) {
110 return value instanceof Long && containsNonZero((Long) value);
111 }
112
113 @Override
114 public Iterator<Long> iterator() {
115 return EclipseCollectionsLongSetMemory.iteratorOf(super.keySet());
116 }
117
118 @Override
119 public boolean addPositive(Long value, int count) {
120 if (count < 0) {
121 throw new IllegalArgumentException("The count value must be positive!");
122 }
123
124 int oldCount = super.getIfAbsent(value, 0);
125
126 super.put(value, oldCount + count);
127
128 return oldCount == 0;
129 }
130
131 @Override
132 public Set<Long> distinctValues() {
133 return new EclipseCollectionsLongSetMemory.SetWrapper(super.keySet());
134 }
135
136 @Override
137 public void forEachEntryWithMultiplicities(BiConsumer<Long, Integer> entryConsumer) {
138 super.forEachKeyValue(entryConsumer::accept);
139 }
140
141 @Override
142 public int hashCode() {
143 return IMemoryView.hashCode(this);
144 }
145 @Override
146 public boolean equals(Object obj) {
147 return IMemoryView.equals(this, obj);
148 }
149
150}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongSetMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongSetMemory.java
new file mode 100644
index 00000000..fceb54fc
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsLongSetMemory.java
@@ -0,0 +1,212 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Collection;
12import java.util.Iterator;
13import java.util.Set;
14
15import org.eclipse.collections.api.LongIterable;
16import org.eclipse.collections.api.iterator.LongIterator;
17import org.eclipse.collections.api.set.primitive.LongSet;
18import org.eclipse.collections.impl.set.mutable.primitive.LongHashSet;
19
20/**
21 * @author Gabor Bergmann
22 * @since 2.0
23 */
24public class EclipseCollectionsLongSetMemory extends LongHashSet implements ISetMemory<Long> {
25
26 @Override
27 public boolean addOne(Long value) {
28 return super.add(value);
29 }
30
31 @Override
32 public boolean addSigned(Long value, int count) {
33 if (count == 1) return addOne(value);
34 else if (count == -1) return removeOne(value);
35 else throw new IllegalStateException();
36 }
37
38 @Override
39 public boolean removeOne(Long value) {
40 // Kept for binary compatibility
41 return ISetMemory.super.removeOne(value);
42 }
43
44 /**
45 * @since 2.3
46 */
47 @Override
48 public boolean removeOneOrNop(Long value) {
49 return super.remove(value);
50 }
51
52 @Override
53 public void clearAllOf(Long value) {
54 super.remove(value);
55 }
56
57 @Override
58 public int getCount(Long value) {
59 return super.contains(value) ? 1 : 0;
60 }
61
62 @Override
63 public int getCountUnsafe(Object value) {
64 return value instanceof Long ? getCount((Long) value) : 0;
65 }
66
67 @Override
68 public boolean containsNonZero(Long value) {
69 return super.contains(value);
70 }
71
72 @Override
73 public boolean containsNonZeroUnsafe(Object value) {
74 return value instanceof Long && containsNonZero((Long) value);
75 }
76
77 @Override
78 public Iterator<Long> iterator() {
79 return iteratorOf(this);
80 }
81
82 @Override
83 public Set<Long> distinctValues() {
84 return new SetWrapper(this);
85 }
86
87 @Override
88 public boolean isEmpty() {
89 return super.isEmpty();
90 }
91
92 /**
93 * Helper for iterating a LongIterable
94 */
95 public static Iterator<Long> iteratorOf(LongIterable wrapped) {
96 return new Iterator<Long>() {
97 LongIterator longIterator = wrapped.longIterator();
98
99 @Override
100 public boolean hasNext() {
101 return longIterator.hasNext();
102 }
103
104 @Override
105 public Long next() {
106 return longIterator.next();
107 }
108 };
109 }
110
111 @Override
112 public int hashCode() {
113 return IMemoryView.hashCode(this);
114 }
115 @Override
116 public boolean equals(Object obj) {
117 return IMemoryView.equals(this, obj);
118 }
119
120
121 /**
122 * Helper that presents a primitive collection as a Set view
123 * @author Gabor Bergmann
124 */
125 public static final class SetWrapper implements Set<Long> {
126 private LongSet wrapped;
127
128 /**
129 * @param wrapped
130 */
131 public SetWrapper(LongSet wrapped) {
132 this.wrapped = wrapped;
133 }
134
135 @Override
136 public int size() {
137 return wrapped.size();
138 }
139
140 @Override
141 public boolean isEmpty() {
142 return wrapped.isEmpty();
143 }
144
145 @Override
146 public boolean contains(Object o) {
147 return o instanceof Long && wrapped.contains((Long)o);
148 }
149
150 @Override
151 public Iterator<Long> iterator() {
152 return iteratorOf(wrapped);
153 }
154
155 @Override
156 public boolean containsAll(Collection<?> c) {
157 for (Object object : c) {
158 if (contains(object))
159 return true;
160 }
161 return false;
162 }
163
164 @Override
165 public Object[] toArray() {
166 return toArray(new Long[wrapped.size()]);
167 }
168
169 @Override
170 @SuppressWarnings("unchecked")
171 public <T> T[] toArray(T[] a) {
172 int k = 0;
173 LongIterator iterator = wrapped.longIterator();
174 while (iterator.hasNext())
175 a[k++] = (T) Long.valueOf(iterator.next());
176 return a;
177 }
178
179 @Override
180 public boolean add(Long e) {
181 throw new UnsupportedOperationException();
182 }
183
184 @Override
185 public boolean remove(Object o) {
186 throw new UnsupportedOperationException();
187 }
188
189 @Override
190 public boolean addAll(Collection<? extends Long> c) {
191 throw new UnsupportedOperationException();
192 }
193
194 @Override
195 public boolean retainAll(Collection<?> c) {
196 throw new UnsupportedOperationException();
197 }
198
199 @Override
200 public boolean removeAll(Collection<?> c) {
201 throw new UnsupportedOperationException();
202 }
203
204 @Override
205 public void clear() {
206 throw new UnsupportedOperationException();
207 }
208
209
210 }
211
212}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiLookup.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiLookup.java
new file mode 100644
index 00000000..394135c9
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiLookup.java
@@ -0,0 +1,226 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import org.eclipse.collections.impl.map.mutable.UnifiedMap;
12import org.eclipse.collections.impl.map.mutable.primitive.LongObjectHashMap;
13import tools.refinery.viatra.runtime.matchers.util.MarkedMemory.MarkedMultiset;
14import tools.refinery.viatra.runtime.matchers.util.MarkedMemory.MarkedSet;
15
16import java.util.Set;
17import java.util.stream.Stream;
18
19
20
21/**
22 * Eclipse Collections-based realizations of {@link IMultiLookup}
23 *
24 * @author Gabor Bergmann
25 * @since 2.0
26 */
27class EclipseCollectionsMultiLookup {
28
29 private EclipseCollectionsMultiLookup() {/* Hidden utility class constructor */}
30
31 private static class MarkedSetImpl<Value> extends EclipseCollectionsSetMemory<Value> implements MarkedMemory.MarkedSet<Value> {}
32 private static class MarkedMultisetImpl<Value> extends EclipseCollectionsMultiset<Value> implements MarkedMemory.MarkedMultiset<Value> {}
33 private static class MarkedLongSetImpl extends EclipseCollectionsLongSetMemory implements MarkedMemory.MarkedSet<Long> {}
34 private static class MarkedLongMultisetImpl extends EclipseCollectionsLongMultiset implements MarkedMemory.MarkedMultiset<Long> {}
35
36 public abstract static class FromObjects<Key, Value, Bucket extends MarkedMemory<Value>>
37 extends UnifiedMap<Key, Object> implements IMultiLookupAbstract<Key, Value, Bucket> {
38
39 @Override
40 public boolean equals(Object obj) {
41 return IMultiLookup.equals(this, obj);
42 }
43 @Override
44 public int hashCode() {
45 return IMultiLookup.hashCode(this);
46 }
47
48
49 @Override
50 public Object lowLevelPutIfAbsent(Key key, Value value) {
51 return super.putIfAbsent(key, value);
52 }
53
54 @Override
55 public Object lowLevelGet(Key key) {
56 return super.get(key);
57 }
58
59 @Override
60 public Object lowLevelGetUnsafe(Object key) {
61 return super.get(key);
62 }
63
64 @Override
65 public Object lowLevelRemove(Key key) {
66 return super.remove(key);
67 }
68
69 @Override
70 public void lowLevelPut(Key key, Object valueOrBucket) {
71 super.put(key, valueOrBucket);
72 }
73 @Override
74 public Iterable<Object> lowLevelValues() {
75 return super.values();
76 }
77 @Override
78 public Set<Key> lowLevelKeySet() {
79 return super.keySet();
80 }
81 @Override
82 public int lowLevelSize() {
83 return super.size();
84 }
85
86 @Override
87 public Stream<Key> distinctKeysStream() {
88 // may be more efficient than the default spliterator
89 return super.keySet().stream();
90 }
91
92 public abstract static class ToSets<Key, Value> extends FromObjects<Key, Value, MarkedSet<Value>>
93 implements IMultiLookupAbstract.ToSetsAbstract<Key, Value>
94 {
95 public static class OfObjects<Key, Value> extends ToSets<Key, Value> {
96 @Override
97 public MarkedSet<Value> createMarkedSet() {
98 return new MarkedSetImpl<Value>();
99 }
100 }
101
102 public static class OfLongs<Key> extends ToSets<Key, Long> {
103 @Override
104 public MarkedSet<Long> createMarkedSet() {
105 return new MarkedLongSetImpl();
106 }
107 }
108
109 }
110
111 public abstract static class ToMultisets<Key, Value> extends FromObjects<Key, Value, MarkedMultiset<Value>>
112 implements IMultiLookupAbstract.ToMultisetsAbstract<Key, Value>
113 {
114 public static class OfObjects<Key, Value> extends ToMultisets<Key, Value> {
115 @Override
116 public MarkedMultiset<Value> createMarkedMultiset() {
117 return new MarkedMultisetImpl<Value>();
118 }
119 }
120
121 public static class OfLongs<Key> extends ToMultisets<Key, Long> {
122 @Override
123 public MarkedMultiset<Long> createMarkedMultiset() {
124 return new MarkedLongMultisetImpl();
125 }
126 }
127
128 }
129
130 }
131
132 public abstract static class FromLongs<Value, Bucket extends MarkedMemory<Value>>
133 extends LongObjectHashMap<Object> implements IMultiLookupAbstract<Long, Value, Bucket> {
134
135 @Override
136 public boolean equals(Object obj) {
137 return IMultiLookup.equals(this, obj);
138 }
139 @Override
140 public int hashCode() {
141 return IMultiLookup.hashCode(this);
142 }
143
144 @Override
145 public Object lowLevelPutIfAbsent(Long key, Value value) {
146 Object old = super.get(key);
147 if (old == null) super.put(key, value);
148 return old;
149 }
150
151 @Override
152 public Object lowLevelGet(Long key) {
153 return super.get(key);
154 }
155
156 @Override
157 public Object lowLevelGetUnsafe(Object key) {
158 return key instanceof Long ? super.get((Long)key) : null;
159 }
160
161 @Override
162 public Object lowLevelRemove(Long key) {
163 return super.remove(key);
164 }
165
166 @Override
167 public void lowLevelPut(Long key, Object valueOrBucket) {
168 super.put(key, valueOrBucket);
169 }
170 @Override
171 public Iterable<Object> lowLevelValues() {
172 return super.values();
173 }
174 @Override
175 public int lowLevelSize() {
176 return super.size();
177 }
178 @Override
179 public Iterable<Long> lowLevelKeySet() {
180 return () -> EclipseCollectionsLongSetMemory.iteratorOf(FromLongs.super.keysView());
181 }
182
183 public abstract static class ToSets<Value> extends FromLongs<Value, MarkedSet<Value>>
184 implements IMultiLookupAbstract.ToSetsAbstract<Long, Value>
185 {
186 public static class OfObjects<Value> extends ToSets<Value> {
187 @Override
188 public MarkedSet<Value> createMarkedSet() {
189 return new MarkedSetImpl<Value>();
190 }
191 }
192
193 public static class OfLongs extends ToSets<Long> {
194 @Override
195 public MarkedSet<Long> createMarkedSet() {
196 return new MarkedLongSetImpl();
197 }
198 }
199
200 }
201
202 public abstract static class ToMultisets<Value> extends FromLongs<Value, MarkedMultiset<Value>>
203 implements IMultiLookupAbstract.ToMultisetsAbstract<Long, Value>
204 {
205 public static class OfObjects<Value> extends ToMultisets<Value> {
206 @Override
207 public MarkedMultiset<Value> createMarkedMultiset() {
208 return new MarkedMultisetImpl<Value>();
209 }
210 }
211
212 public static class OfLongs extends ToMultisets<Long> {
213 @Override
214 public MarkedMultiset<Long> createMarkedMultiset() {
215 return new MarkedLongMultisetImpl();
216 }
217 }
218
219 }
220
221 }
222
223
224}
225
226
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiset.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiset.java
new file mode 100644
index 00000000..46977c8b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsMultiset.java
@@ -0,0 +1,93 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11/**
12 * @author Gabor Bergmann
13 * @since 1.7
14 */
15public class EclipseCollectionsMultiset<T> extends EclipseCollectionsBagMemory<T> implements IMultiset<T> {
16
17 @Override
18 public boolean addOne(T value) {
19 int oldCount = super.getIfAbsent(value, 0);
20
21 super.put(value, oldCount + 1);
22
23 return oldCount == 0;
24 }
25
26 @Override
27 public boolean addPositive(T value, int count) {
28 if (count < 0) {
29 throw new IllegalArgumentException("The count value must be positive!");
30 }
31
32 int oldCount = super.getIfAbsent(value, 0);
33
34 super.put(value, oldCount + count);
35
36 return oldCount == 0;
37 }
38
39 @Override
40 public boolean addSigned(T value, int count) {
41 int oldCount = super.getIfAbsent(value, 0);
42 int newCount = oldCount + count;
43
44 boolean becomesZero = newCount == 0;
45 if (newCount < 0)
46 throw new IllegalStateException(String.format(
47 "Cannot remove %d occurrences of value '%s' as only %d would remain in %s",
48 count, value, newCount, this));
49 else if (becomesZero)
50 super.removeKey(value);
51 else // (newCount > 0)
52 super.put(value, newCount);
53
54 return becomesZero || oldCount == 0;
55 }
56
57
58 @Override
59 public boolean removeOne(T value) {
60 return removeOneInternal(value, true);
61 }
62
63 @Override
64 public boolean removeOneOrNop(T value) {
65 return removeOneInternal(value, false);
66 }
67
68 /**
69 * @since 2.3
70 */
71 protected boolean removeOneInternal(T value, boolean throwIfImpossible) {
72 int oldCount = super.getIfAbsent(value, 0);
73 if (oldCount == 0) {
74 if (throwIfImpossible) throw new IllegalStateException(String.format(
75 "Cannot remove value '%s' that is not contained in %s",
76 value, this));
77 else return false;
78 }
79
80 int rest = oldCount - 1;
81 boolean empty = rest == 0;
82
83 if (!empty) {
84 super.put(value, rest);
85 } else {
86 super.remove(value);
87 }
88
89 return empty;
90 }
91
92
93}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsSetMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsSetMemory.java
new file mode 100644
index 00000000..92f65246
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EclipseCollectionsSetMemory.java
@@ -0,0 +1,94 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Set;
12
13import org.eclipse.collections.impl.set.mutable.UnifiedSet;
14
15/**
16 * @author Gabor Bergmann
17 * @since 2.0
18 */
19public class EclipseCollectionsSetMemory<Value> extends UnifiedSet<Value> implements ISetMemory<Value> {
20 @Override
21 public int getCount(Value value) {
22 return super.contains(value) ? 1 : 0;
23 }
24 @Override
25 public int getCountUnsafe(Object value) {
26 return super.contains(value) ? 1 : 0;
27 }
28 @Override
29 public boolean containsNonZero(Value value) {
30 return super.contains(value);
31 }
32
33 @Override
34 public boolean containsNonZeroUnsafe(Object value) {
35 return super.contains(value);
36 }
37
38 @Override
39 public boolean addOne(Value value) {
40 return super.add(value);
41 }
42
43 @Override
44 public boolean addSigned(Value value, int count) {
45 if (count == 1) return addOne(value);
46 else if (count == -1) return removeOne(value);
47 else throw new IllegalStateException();
48 }
49
50 @Override
51 public boolean removeOne(Value value) {
52 // Kept for binary compatibility
53 return ISetMemory.super.removeOne(value);
54 }
55
56 @Override
57 public boolean removeOneOrNop(Value value) {
58 return super.remove(value);
59 }
60
61 @Override
62 public void clearAllOf(Value value) {
63 super.remove(value);
64 }
65
66 @Override
67 public Set<Value> distinctValues() {
68 return this;
69 }
70
71 @Override
72 public Value theContainedVersionOf(Value value) {
73 return super.get(value);
74 }
75
76 @Override
77 @SuppressWarnings("unchecked")
78 public Value theContainedVersionOfUnsafe(Object value) {
79 if (super.contains(value))
80 return super.get((Value)value);
81 else return null;
82 }
83
84 @Override
85 public int hashCode() {
86 return IMemoryView.hashCode(this);
87 }
88 @Override
89 public boolean equals(Object obj) {
90 return IMemoryView.equals(this, obj);
91 }
92
93
94}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EmptyMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EmptyMemory.java
new file mode 100644
index 00000000..a17b3a3f
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/EmptyMemory.java
@@ -0,0 +1,93 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Collections;
12import java.util.Iterator;
13import java.util.Set;
14
15/**
16 * A singleton immutable empty memory.
17 * @author Gabor Bergmann
18 * @since 2.0
19 *
20 */
21public class EmptyMemory<T> implements IMemoryView<T> {
22
23 @SuppressWarnings("rawtypes")
24 private static final EmptyMemory INSTANCE = new EmptyMemory();
25
26 @SuppressWarnings("unchecked")
27 public static <T> EmptyMemory<T> instance() {
28 return INSTANCE;
29 }
30
31
32
33 /**
34 * Singleton; hidden constructor
35 */
36 private EmptyMemory() {
37 super();
38 }
39
40 @Override
41 public Iterator<T> iterator() {
42 return Collections.<T>emptySet().iterator();
43 }
44
45 @Override
46 public int getCount(T value) {
47 return 0;
48 }
49
50 @Override
51 public int getCountUnsafe(Object value) {
52 return 0;
53 }
54
55 @Override
56 public boolean containsNonZero(T value) {
57 return false;
58 }
59
60 @Override
61 public boolean containsNonZeroUnsafe(Object value) {
62 return false;
63 }
64
65 @Override
66 public int size() {
67 return 0;
68 }
69
70 @Override
71 public boolean isEmpty() {
72 return true;
73 }
74
75 @Override
76 public Set<T> distinctValues() {
77 return Collections.emptySet();
78 }
79
80 @Override
81 public int hashCode() {
82 return IMemoryView.hashCode(this);
83 }
84 @Override
85 public boolean equals(Object obj) {
86 return IMemoryView.equals(this, obj);
87 }
88
89 @Override
90 public String toString() {
91 return "{}";
92 }
93}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/ICache.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/ICache.java
new file mode 100644
index 00000000..8c2e54ad
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/ICache.java
@@ -0,0 +1,32 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.function.Supplier;
12
13/**
14 * A cache is a simple key-value pair that stores calculated values for specific key objects
15 *
16 * <p>
17 * <b>NOTE</b> These caches are not expected to be used outside query backend implementations
18 *
19 * @author Zoltan Ujhelyi
20 * @since 1.7
21 * @noreference This interface is not intended to be referenced by clients.
22 */
23public interface ICache {
24
25 /**
26 * Return a selected value for the key object. If the value is not available in the cache yet, the given provider is
27 * called once
28 * @since 2.0
29 */
30 <T> T getValue(Object key, Class<? extends T> clazz, Supplier<T> valueProvider);
31
32} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IDeltaBag.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IDeltaBag.java
new file mode 100644
index 00000000..99a4cb3b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IDeltaBag.java
@@ -0,0 +1,26 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11/**
12 * An {@link IMemory} that represents the difference between two states of a set or {@link IMultiset}, and therefore
13 * may contain values with a negative multiplicity.
14 *
15 * @author Gabor Bergmann
16 * @since 1.7
17 */
18public interface IDeltaBag<T> extends IMemory<T> {
19
20 @Override
21 default boolean removeOneOrNop(T value) {
22 // makes no difference for delta bags
23 return removeOne(value);
24 }
25
26}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemory.java
new file mode 100644
index 00000000..ea788e53
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemory.java
@@ -0,0 +1,81 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11/**
12 * A memory containing a positive or negative number of equal() copies for some values.
13 * During iterations, each distinct value is iterated only once.
14 *
15 * <p> Refined by: <ul>
16 * <li>{@link IMultiset}, which always contains values with a nonnegative multiplicity. </li>
17 * <li>{@link IDeltaBag}, which may contain values with negative multiplicity. </li>
18 * <li>{@link ISetMemory}, which is just a set (allowed multiplicities: 0 and 1). </li>
19 * </ul>
20 *
21 * @author Gabor Bergmann
22 * @since 1.7
23 * @noimplement This interface is not intended to be implemented by clients.
24 */
25public interface IMemory<T> extends IMemoryView<T>, Clearable {
26
27 /**
28 * Adds one value occurrence to the memory.
29 *
30 * @return true if the tuple was not present before in the memory, or
31 * (in case of {@link IDeltaBag}) is no longer present in the memory
32 */
33 boolean addOne(T value);
34
35 /**
36 * Adds the given number of occurrences to the memory. The count value may or may not be negative.
37 * <p> Precondition if {@link IMultiset}: at least the given amount of occurrences exist, if count is negative.
38 * <p> Precondition if {@link ISetMemory}: count is +1 or -1, the latter is only allowed if the set contains the value.
39 *
40 * @param count
41 * the number of occurrences
42 * @return true if the tuple was not present before in the memory, or is no longer present in the memory
43 * @throws IllegalStateException if {@link IMultiset} or {@link ISetMemory} and the number of occurrences in the memory would underflow to negative
44 */
45 boolean addSigned(T value, int count);
46
47 /**
48 * Removes one occurrence of the given value from the memory.
49 * <p> Precondition if {@link IMultiset} or {@link ISetMemory}: the value must have a positive amount of occurrences in the memory.
50 *
51 * @return true if this was the the last occurrence of the value, or
52 * (in case of {@link IDeltaBag}) is the first negative occurrence of the value
53 * @throws IllegalStateException if {@link IMultiset} or {@link ISetMemory} and value had no occurrences in the memory
54 */
55 boolean removeOne(T value);
56
57 /**
58 * Removes one occurrence of the given value from the memory, if possible.
59 *
60 * <p> Memory is unchanged and false is returned if
61 * {@link IMultiset} or {@link ISetMemory} and value had no occurrences in the memory
62 *
63 * @return true if this was the the last occurrence of the value, or
64 * (in case of {@link IDeltaBag}) is the first negative occurrence of the value
65 *
66 * @since 2.3
67 */
68 boolean removeOneOrNop(T value);
69
70 /**
71 * Removes all occurrences of the given value from the memory.
72 */
73 void clearAllOf(T value);
74
75 /**
76 * Empties out the memory.
77 */
78 @Override
79 void clear();
80
81} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemoryView.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemoryView.java
new file mode 100644
index 00000000..add575c6
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMemoryView.java
@@ -0,0 +1,205 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Iterator;
12import java.util.Map;
13import java.util.Map.Entry;
14import java.util.Set;
15import java.util.function.BiConsumer;
16import java.util.stream.Stream;
17import java.util.stream.StreamSupport;
18
19/**
20 * A read-only view on a memory containing a positive or negative number of equal() copies for some values.
21 * During iterations, each distinct value is iterated only once.
22 *
23 * <p> See {@link IMemory}.
24 *
25 * <p> Implementors must provide semantic (not identity-based) hashCode() and equals() using the static helpers {@link #hashCode(IMemoryView)} and {@link #equals(IMemoryView, Object)} here.
26 *
27 * @author Gabor Bergmann
28 *
29 * @since 2.0
30 */
31public interface IMemoryView<T> extends Iterable<T> {
32
33 /**
34 * Returns the number of occurrences of the given value.
35 *
36 * @return the number of occurrences
37 */
38 int getCount(T value);
39
40 /**
41 * Returns the number of occurrences of the given value (which may be of any type).
42 *
43 * @return the number of occurrences
44 */
45 int getCountUnsafe(Object value);
46
47 /**
48 * @return true if the given value is contained with a nonzero multiplicity
49 */
50 boolean containsNonZero(T value);
51
52 /**
53 * @return true if the given value (which may be of any type) is contained with a nonzero multiplicity
54 */
55 boolean containsNonZeroUnsafe(Object value);
56
57 /**
58 * @return the number of distinct values
59 */
60 int size();
61
62 /**
63 *
64 * @return iff contains at least one value with non-zero occurrences
65 */
66 boolean isEmpty();
67
68 /**
69 * The set of distinct values
70 */
71 Set<T> distinctValues();
72
73
74 /**
75 * Where supported, returns the stored element that is equal to the given value, or null if none.
76 * Useful for canonicalization in case of non-identity equals().
77 *
78 * <p> For collections that do not support canonicalization, simply returns the argument if contained, null if none.
79 *
80 * @return a value equal to the argument if such a value is stored, or null if none
81 */
82 default T theContainedVersionOf(T value) {
83 if (containsNonZero(value)) return value; else return null;
84 }
85
86 /**
87 * Where supported, returns the stored element that is equal to the given value (of any type),
88 * or null if none.
89 * Useful for canonicalization in case of non-identity equals().
90 *
91 * <p> For collections that do not support canonicalization, simply returns the argument if contained, null if none.
92 *
93 * @return a value equal to the argument if such a value is stored, or null if none
94 */
95 @SuppressWarnings("unchecked")
96 default T theContainedVersionOfUnsafe(Object value) {
97 if (containsNonZeroUnsafe(value)) return (T) value; else return null;
98 }
99
100
101 /**
102 * @return an unmodifiable view of contained values with their multiplicities
103 */
104 default Iterable<Map.Entry<T, Integer>> entriesWithMultiplicities() {
105 return () -> {
106 Iterator<T> wrapped = distinctValues().iterator();
107 return new Iterator<Map.Entry<T, Integer>> () {
108 @Override
109 public boolean hasNext() {
110 return wrapped.hasNext();
111 }
112
113 @Override
114 public Map.Entry<T, Integer> next() {
115 T key = wrapped.next();
116 int count = getCount(key);
117 return new Map.Entry<T, Integer>(){
118 @Override
119 public T getKey() {
120 return key;
121 }
122
123 @Override
124 public Integer getValue() {
125 return count;
126 }
127
128 @Override
129 public Integer setValue(Integer value) {
130 throw new UnsupportedOperationException();
131 }
132
133 @Override
134 public String toString() {
135 return String.format("%d of %s", count, key);
136 }
137
138 };
139 }
140
141 };
142 };
143 }
144
145 /**
146 * Process contained values with their multiplicities
147 */
148 default void forEachEntryWithMultiplicities(BiConsumer<T, Integer> entryConsumer) {
149 for (T value : distinctValues()) {
150 entryConsumer.accept(value, getCount(value));
151 }
152 }
153
154
155 /**
156 * For compatibility with legacy code relying on element-to-integer maps.
157 * @return an unmodifiable view of contained values with their multiplicities
158 */
159 public default Map<T, Integer> asMap() {
160 return new MemoryViewBackedMapView<>(this);
161 }
162
163 /**
164 * For compatibility with legacy code relying on element-to-integer maps.
165 * @return an unmodifiable view of contained values with their multiplicities
166 */
167 public static <T> IMemoryView<T> fromMap(Map<T, Integer> wrapped) {
168 return new MapBackedMemoryView<>(wrapped);
169 }
170
171 /**
172 * @return a stream of values, iterable once
173 * @since 2.1
174 */
175 public default Stream<T> asStream() {
176 return StreamSupport.stream(spliterator(), false);
177 }
178
179 /**
180 * Provides semantic equality comparison.
181 */
182 public static <T> boolean equals(IMemoryView<T> self, Object obj) {
183 if (obj instanceof IMemoryView<?>) {
184 IMemoryView<?> other = (IMemoryView<?>) obj;
185 if (other.size() != self.size()) return false;
186 for (Entry<?, Integer> entry : other.entriesWithMultiplicities()) {
187 if ( !entry.getValue().equals(self.getCountUnsafe(entry.getKey())))
188 return false;
189 }
190 return true;
191 }
192 return false;
193 }
194
195 /**
196 * Provides semantic hashCode() comparison.
197 */
198 public static <T> int hashCode(IMemoryView<T> memory) {
199 int hashCode = 0;
200 for (T value : memory.distinctValues()) {
201 hashCode += value.hashCode() ^ Integer.hashCode(memory.getCount(value));
202 }
203 return hashCode;
204 }
205} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookup.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookup.java
new file mode 100644
index 00000000..1ce1d2c9
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookup.java
@@ -0,0 +1,216 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.stream.Stream;
12
13import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
14
15/**
16 * A multi-map that associates sets / multisets / delta sets of values to each key.
17 *
18 * <p> Implementors must provide semantic (not identity-based) hashCode() and equals() using the static helpers {@link #hashCode(IMultiLookup)} and {@link #equals(IMultiLookup, Object)} here.
19 *
20 * @author Gabor Bergmann
21 * @since 2.0
22 * @noimplement This interface is not intended to be implemented by clients.
23 */
24public interface IMultiLookup<Key, Value> {
25
26 /**
27 * Returns true if this collection is empty, false otherwise.
28 * @since 2.2
29 */
30 boolean isEmpty();
31
32
33 /**
34 * Returns true if there are any values associated with the given key.
35 * @param key a key for which associated values are sought
36 * @since 2.3
37 */
38 boolean lookupExists(Key key);
39
40 /**
41 * Returns a (read-only) bucket of values associated with the given key.
42 * Clients must not modify the returned bucket.
43 * @param key a key for which associated values are sought
44 * @return null if key not found, a bucket of values otherwise
45 */
46 IMemoryView<Value> lookup(Key key);
47
48 /**
49 * Returns a (read-only) bucket of values associated with the given key.
50 * Clients must not modify the returned bucket.
51 * @param key a key for which associated values are sought
52 * @return a bucket of values, never null
53 */
54 default IMemoryView<Value> lookupOrEmpty(Key key) {
55 IMemoryView<Value> bucket = lookup(key);
56 return bucket == null ? EmptyMemory.instance() : bucket;
57 }
58
59 /**
60 * Returns a (read-only) bucket of values associated with the given key, while simultaneously removing them.
61 * Clients must not modify the returned bucket.
62 * @param key a key for which associated values are sought
63 * @return a bucket of values, never null
64 * @since 2.3
65 */
66 IMemoryView<Value> lookupAndRemoveAll(Key key);
67
68 /**
69 * Returns a (read-only) bucket of values associated with the given key, which can be of any type.
70 * Clients must not modify the returned bucket.
71 * @param key a key for which associated values are sought (may or may not be of Key type)
72 * @return null if key not found, a bucket of values otherwise
73 */
74 IMemoryView<Value> lookupUnsafe(Object key);
75
76 /**
77 * Returns a (read-only) bucket of values associated with the given key.
78 * Clients must not modify the returned bucket.
79 * @param key a key for which associated values are sought (may or may not be of Key type)
80 * @return a bucket of values, never null
81 */
82 default IMemoryView<Value> lookupUnsafeOrEmpty(Object key) {
83 IMemoryView<Value> bucket = lookupUnsafe(key);
84 return bucket == null ? EmptyMemory.instance() : bucket;
85 }
86
87
88
89 /**
90 * @return the set of distinct keys that have values associated.
91 */
92 Iterable<Key> distinctKeys();
93
94 /**
95 * @return the set of distinct keys that have values associated.
96 * @since 2.3
97 */
98 Stream<Key> distinctKeysStream();
99
100 /**
101 * @return the number of distinct keys that have values associated.
102 */
103 int countKeys();
104
105 /**
106 * Iterates once over each distinct value.
107 */
108 Iterable<Value> distinctValues();
109
110 /**
111 * Iterates once over each distinct value.
112 * @since 2.3
113 */
114 Stream<Value> distinctValuesStream();
115
116
117
118 /**
119 * How significant was the change? *
120 * @author Gabor Bergmann
121 */
122 public enum ChangeGranularity {
123 /**
124 * First key-value pair with given key inserted, or last pair with given key deleted.
125 * (In case of delta maps, also if last negative key-value pair with given key neutralized.)
126 */
127 KEY,
128 /**
129 * First occurrence of given key-value pair inserted, or last occurrence of the pair deleted, while key still has values associated.
130 * (In case of delta maps, also if last negative occurrence of key-value pair neutralized.)
131 */
132 VALUE,
133 /**
134 * Duplicate key-value pair inserted or deleted.
135 */
136 DUPLICATE
137 }
138
139 /**
140 * Adds key-value pair to the lookup structure, or fails if not possible.
141 * <p> If the addition would cause duplicates but the bucket type does not allow it ({@link MemoryType#SETS}),
142 * the operation throws an {@link IllegalStateException}.
143 * @return the granularity of the change
144 * @throws IllegalStateException if addition would cause duplication that is not permitted
145 */
146 public ChangeGranularity addPair(Key key, Value value);
147 /**
148 * Adds key-value pair to the lookup structure.
149 * <p> If the addition would cause duplicates but the bucket type does not allow it ({@link MemoryType#SETS}),
150 * the operation is silently ignored and {@link ChangeGranularity#DUPLICATE} is returned.
151 * @return the granularity of the change, or {@link ChangeGranularity#DUPLICATE} if addition would result in a duplicate and therefore ignored
152 * @since 2.3
153 */
154 public ChangeGranularity addPairOrNop(Key key, Value value);
155 /**
156 * Removes key-value pair from the lookup structure, or fails if not possible.
157 * <p> When attempting to remove a key-value pair with zero multiplicity from a non-delta bucket type
158 * ({@link MemoryType#SETS} or {@link MemoryType#MULTISETS}}), an {@link IllegalStateException} is thrown.
159 * @return the granularity of the change
160 * @throws IllegalStateException if removing non-existing element that is not permitted
161 */
162 public ChangeGranularity removePair(Key key, Value value);
163 /**
164 * Removes key-value pair from the lookup structure.
165 * <p> When attempting to remove a key-value pair with zero multiplicity from a non-delta bucket type
166 * ({@link MemoryType#SETS} or {@link MemoryType#MULTISETS}}),
167 * the operation is silently ignored and {@link ChangeGranularity#DUPLICATE} is returned.
168 * @return the granularity of the change
169 * @throws IllegalStateException if removing non-existing element that is not permitted
170 * @since 2.3
171 */
172 public ChangeGranularity removePairOrNop(Key key, Value value);
173
174 /**
175 * Updates multiplicity of key-value pair by a positive amount.
176 *
177 * <p> PRE: count > 0
178 *
179 * @return the granularity of the change
180 * @throws IllegalStateException if addition would cause duplication that is not permitted
181 */
182 public ChangeGranularity addPairPositiveMultiplicity(Key key, Value value, int count);
183
184 /**
185 * Empties out the lookup structure.
186 */
187 public void clear();
188
189 /**
190 * Provides semantic equality comparison.
191 */
192 public static <Key, Value> boolean equals(IMultiLookup<Key, Value> self, Object obj) {
193 if (obj instanceof IMultiLookup<?, ?>) {
194 IMultiLookup<?, ?> other = (IMultiLookup<?, ?>) obj;
195 if (other.countKeys() != self.countKeys()) return false;
196 for (Object key : other.distinctKeys()) {
197 if (! other.lookupUnsafe(key).equals(self.lookupUnsafe(key)))
198 return false;
199 }
200 return true;
201 }
202 return false;
203 }
204
205 /**
206 * Provides semantic hashCode() comparison.
207 */
208 public static <Key, Value> int hashCode(IMultiLookup<Key, Value> memory) {
209 int hashCode = 0;
210 for (Key key : memory.distinctKeys()) {
211 hashCode += key.hashCode() ^ memory.lookup(key).hashCode();
212 }
213 return hashCode;
214 }
215
216}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookupAbstract.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookupAbstract.java
new file mode 100644
index 00000000..8b1944c1
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiLookupAbstract.java
@@ -0,0 +1,485 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Collections;
12import java.util.Iterator;
13import java.util.NoSuchElementException;
14import java.util.Objects;
15import java.util.stream.Stream;
16import java.util.stream.StreamSupport;
17
18import tools.refinery.viatra.runtime.matchers.util.MarkedMemory.MarkedSet;
19
20/**
21 * Specialized multimap implementation that saves memory
22 * by storing singleton value objects (multiplicity 1) instead of multiset buckets
23 * whenever there is only one value associated with a key.
24 *
25 * <p> See specialized {@link ToSetsAbstract}, {@link ToMultisetsAbstract} for various bucket types.
26 *
27 * <p> Implemented as a Key->Object map with invariant: <ul>
28 * <li> key maps to null if associated with no values;
29 * <li> key maps to a single Value iff it is associated with a single value of multiplicity +1;
30 * <li> key maps to Bucket otherwise
31 * </ul>
32 *
33 * Note that due to the above invariant, handling +1 and -1 are asymmetric in case of delta maps.
34 *
35 * <p> Not intended as an API, but rather as a 'base class' for implementors.
36 * Realized as an interface with default implementations, instead of an abstract class,
37 * to ensure that implementors can easily choose a base class such as UnifiedMap to augment.
38 *
39 * <p> Implementor should inherit from a Map<Key, Object>-like class (primitive map possible)
40 * and bind the lowLevel* methods accordingly.
41 *
42 * @noreference This interface is not intended to be referenced by clients.
43 * @noimplement This interface is not intended to be implemented by clients.
44 *
45 * @author Gabor Bergmann
46 * @since 2.0
47 *
48 *
49 */
50public interface IMultiLookupAbstract<Key, Value, Bucket extends MarkedMemory<Value>> extends IMultiLookup<Key, Value> {
51
52 // the following methods must be bound to a concrete Map<Key,Object>-like structure (primitive implementation allowed)
53
54 /**
55 * Implementor shall bind to the low-level get() or equivalent of the underlying Key-to-Object map
56 */
57 abstract Object lowLevelGet(Key key);
58
59 /**
60 * Implementor shall bind to the low-level get() or equivalent of the underlying Key-to-Object map
61 */
62 abstract Object lowLevelGetUnsafe(Object key);
63
64 /**
65 * Implementor shall bind to the low-level remove() or equivalent of the underlying Key-to-Object map
66 */
67 abstract Object lowLevelRemove(Key key);
68
69 /**
70 * Implementor shall bind to the low-level putIfAbsent() or equivalent of the underlying Key-to-Object map
71 */
72 abstract Object lowLevelPutIfAbsent(Key key, Value value);
73
74 /**
75 * Implementor shall bind to the low-level put() or equivalent of the underlying Key-to-Object map
76 */
77 abstract void lowLevelPut(Key key, Object valueOrBucket);
78
79 /**
80 * Implementor shall bind to the low-level values() or equivalent of the underlying Key-to-Object map
81 */
82 abstract Iterable<Object> lowLevelValues();
83
84 /**
85 * Implementor shall bind to the low-level keySet() or equivalent of the underlying Key-to-Object map
86 */
87 abstract Iterable<Key> lowLevelKeySet();
88
89 /**
90 * Implementor shall bind to the low-level size() or equivalent of the underlying Key-to-Object map
91 */
92 abstract int lowLevelSize();
93
94
95 // generic multi-lookup logic
96
97 @Override
98 default boolean lookupExists(Key key) {
99 Object object = lowLevelGet(key);
100 return null != object;
101 }
102
103 @Override
104 public default IMemoryView<Value> lookup(Key key) {
105 Object object = lowLevelGet(key);
106 if (object == null) return null;
107 if (object instanceof MarkedMemory) return (Bucket) object;
108 return yieldSingleton((Value)object);
109 }
110
111 @Override
112 default IMemoryView<Value> lookupAndRemoveAll(Key key) {
113 Object object = lowLevelRemove(key);
114 if (object == null) return EmptyMemory.instance();
115 if (object instanceof MarkedMemory) return (Bucket) object;
116 return yieldSingleton((Value)object);
117 }
118
119 @Override
120 public default IMemoryView<Value> lookupUnsafe(Object key) {
121 Object object = lowLevelGetUnsafe(key);
122 if (object == null) return null;
123 if (object instanceof MarkedMemory) return (Bucket) object;
124 return yieldSingleton((Value)object);
125 }
126
127 @Override
128 public default ChangeGranularity addPair(Key key, Value value) {
129 return addPairInternal(key, value, true);
130 }
131
132 @Override
133 default ChangeGranularity addPairOrNop(Key key, Value value) {
134 return addPairInternal(key, value, false);
135 }
136
137 public default ChangeGranularity addPairInternal(Key key, Value value, boolean throwIfImpossible) {
138 Object old = lowLevelPutIfAbsent(key, value);
139 boolean keyChange = (old == null);
140
141 if (keyChange) { // key was not present
142 return ChangeGranularity.KEY;
143 } else { // key was already present
144 Bucket bucket;
145 if (old instanceof MarkedMemory) { // ... as collection
146 bucket = (Bucket) old;
147 } else { // ... as singleton
148 if (!this.duplicatesAllowed() && Objects.equals(value, old)) {
149 if (throwIfImpossible)
150 throw new IllegalStateException();
151 else
152 return ChangeGranularity.DUPLICATE;
153 }
154 bucket = createSingletonBucket((Value) old);
155 lowLevelPut(key, bucket);
156 }
157 // will throw if forbidden duplicate, return false if allowed duplicate
158 if (addToBucket(bucket, value, throwIfImpossible)) {
159 // deltas may become empty or a singleton after addition!
160 if (negativesAllowed()) {
161 if (bucket.isEmpty()) {
162 lowLevelRemove(key);
163 return ChangeGranularity.KEY;
164 } else {
165 handleSingleton(key, bucket);
166 return ChangeGranularity.VALUE;
167 }
168 } else return ChangeGranularity.VALUE;
169 } else return ChangeGranularity.DUPLICATE;
170 }
171 }
172
173 @Override
174 // TODO deltas not supproted yet
175 default ChangeGranularity addPairPositiveMultiplicity(Key key, Value value, int count) {
176 if (count == 1) return addPair(key, value);
177 // count > 1, always end up with non-singleton bucket
178
179 Object old = lowLevelGet(key);
180 boolean keyChange = (old == null);
181
182 Bucket bucket;
183 if (keyChange) { // ... nothing associated to key yet
184 bucket = createSingletonBucket(value);
185 lowLevelPut(key, bucket);
186 --count; // one less to increment later
187 } else if (old instanceof MarkedMemory) { // ... as collection
188 bucket = (Bucket) old;
189 } else { // ... as singleton
190 bucket = createSingletonBucket((Value) old);
191 lowLevelPut(key, bucket);
192 }
193
194 boolean newValue = bucket.addSigned(value, count);
195
196 if (keyChange) return ChangeGranularity.KEY;
197 else if (newValue) return ChangeGranularity.VALUE;
198 else return ChangeGranularity.DUPLICATE;
199 }
200
201 @Override
202 public default ChangeGranularity removePair(Key key, Value value) {
203 return removePairInternal(key, value, true);
204 }
205
206 @Override
207 default ChangeGranularity removePairOrNop(Key key, Value value) {
208 return removePairInternal(key, value, false);
209 }
210
211 public default ChangeGranularity removePairInternal(Key key, Value value, boolean throwIfImpossible) {
212 Object old = lowLevelGet(key);
213 if (old instanceof MarkedMemory) { // ... as collection
214 @SuppressWarnings("unchecked")
215 Bucket bucket = (Bucket) old;
216 // will throw if removing non-existent, return false if removing duplicate
217 boolean valueChange = removeFromBucket(bucket, value, throwIfImpossible);
218 handleSingleton(key, bucket);
219 if (valueChange)
220 return ChangeGranularity.VALUE;
221 else
222 return ChangeGranularity.DUPLICATE;
223 } else if (value.equals(old)) { // matching singleton
224 lowLevelRemove(key);
225 return ChangeGranularity.KEY;
226 } else { // different singleton, will produce a delta if possible
227 if (negativesAllowed()) {
228 Bucket deltaBucket = createDeltaBucket((Value) old, value); // will throw if no deltas supported
229 lowLevelPut(key, deltaBucket);
230 return ChangeGranularity.VALUE; // no key change
231 } else {
232 if (throwIfImpossible)
233 throw new IllegalStateException();
234 else
235 return ChangeGranularity.DUPLICATE;
236 }
237 }
238 }
239
240 public default void handleSingleton(Key key, Bucket bucket) {
241 Value remainingSingleton = asSingleton(bucket);
242 if (remainingSingleton != null) { // only one remains
243 lowLevelPut(key, remainingSingleton);
244 }
245 }
246
247 @Override
248 public default Iterable<Value> distinctValues() {
249 return new Iterable<Value>() {
250 private final Iterator<Value> EMPTY_ITERATOR = Collections.<Value>emptySet().iterator();
251 @Override
252 public Iterator<Value> iterator() {
253 return new Iterator<Value>() {
254 Iterator<Object> bucketIterator = lowLevelValues().iterator();
255 Iterator<Value> elementIterator = EMPTY_ITERATOR;
256
257 @Override
258 public boolean hasNext() {
259 return (elementIterator.hasNext() || bucketIterator.hasNext());
260 }
261
262 @Override
263 public Value next() {
264 if (elementIterator.hasNext())
265 return elementIterator.next();
266 else if (bucketIterator.hasNext()) {
267 Object bucket = bucketIterator.next();
268 if (bucket instanceof MarkedMemory) {
269 elementIterator =
270 ((MarkedMemory) bucket).distinctValues().iterator();
271 return elementIterator.next();
272 } else {
273 elementIterator = EMPTY_ITERATOR;
274 return (Value) bucket;
275 }
276 } else
277 throw new NoSuchElementException();
278 }
279
280 /**
281 * Not implemented
282 */
283 @Override
284 public void remove() {
285 throw new UnsupportedOperationException();
286 }
287
288 };
289 }
290 };
291 }
292
293 @Override
294 default Stream<Value> distinctValuesStream() {
295 return StreamSupport.stream(distinctValues().spliterator(), false);
296 }
297
298 @Override
299 default Iterable<Key> distinctKeys() {
300 return lowLevelKeySet();
301 }
302
303 @Override
304 default Stream<Key> distinctKeysStream() {
305 return StreamSupport.stream(distinctKeys().spliterator(), false);
306 }
307
308 @Override
309 default int countKeys() {
310 return lowLevelSize();
311 }
312
313 // the following methods are customized for bucket type
314
315 /**
316 * @return iff negative multiplicites are allowed
317 */
318 abstract boolean negativesAllowed();
319
320 /**
321 * @return iff larger-than-1 multiplicites are allowed
322 * @since 2.3
323 */
324 abstract boolean duplicatesAllowed();
325
326 /**
327 * Increases the multiplicity of the value in the bucket.
328 * @return true iff non-duplicate
329 * @throws IllegalStateException if disallowed duplication and throwIfImpossible is specified
330 */
331 abstract boolean addToBucket(Bucket bucket, Value value, boolean throwIfImpossible);
332
333 /**
334 * Decreases the multiplicity of the value in the bucket.
335 * @return false if removing duplicate value
336 * @throws IllegalStateException if removing non-existing value (unless delta map) and throwIfImpossible is specified
337 */
338 abstract boolean removeFromBucket(Bucket bucket, Value value, boolean throwIfImpossible);
339
340 /**
341 * Checks whether the bucket is a singleton, i.e. it contains a single value with multiplicity +1
342 * @return the singleton value, or null if the bucket is not singleton
343 */
344 abstract Value asSingleton(Bucket bucket);
345
346 /**
347 * @return a new bucket consisting of a sole value
348 */
349 abstract Bucket createSingletonBucket(Value value);
350 /**
351 * @return a read-only bucket consisting of a sole value, to be returned to the user
352 */
353 default IMemoryView<Value> yieldSingleton(Value value) {
354 return new SingletonMemoryView<>(value);
355 }
356
357 /**
358 * @param positive the previously existing value, or null if the delta is to contain a single negative tuple
359 * @return a new bucket consisting of a delta of two values
360 * @throws IllegalStateException if deltas not supported
361 */
362 abstract Bucket createDeltaBucket(Value positive, Value negative);
363
364 /**
365 * A multi-lookup whose buckets are sets.
366 *
367 * <p> Not intended as an API, but rather as a 'base class' for implementors.
368 * Realized as an interface with default implementations, instead of an abstract class,
369 * to ensure that implementors can easily choose a base class such as UnifiedMap to augment.
370 *
371 * <p> Implementor should inherit from a Map<Key, Object>-like class (primitive map possible)
372 * and bind the lowLevel* methods accordingly.
373 *
374 * @noreference This interface is not intended to be referenced by clients.
375 * @noimplement This interface is not intended to be implemented by clients.
376 * @author Gabor Bergmann
377 */
378 public static interface ToSetsAbstract<Key, Value> extends IMultiLookupAbstract<Key, Value, MarkedMemory.MarkedSet<Value>> {
379 /**
380 * @return a fresh, empty marked set
381 */
382 public MarkedSet<Value> createMarkedSet();
383
384 @Override
385 public default boolean negativesAllowed() {
386 return false;
387 }
388 @Override
389 default boolean duplicatesAllowed() {
390 return false;
391 }
392
393 @Override
394 public default boolean addToBucket(MarkedSet<Value> bucket, Value value, boolean throwIfImpossible) {
395 if (bucket.addOne(value)) return true;
396 else if (throwIfImpossible) throw new IllegalStateException();
397 else return false;
398 }
399
400 @Override
401 public default boolean removeFromBucket(MarkedSet<Value> bucket, Value value, boolean throwIfImpossible) {
402 return throwIfImpossible ? bucket.removeOne(value) : bucket.removeOneOrNop(value);
403 }
404
405 @Override
406 public default Value asSingleton(MarkedSet<Value> bucket) {
407 return bucket.size() == 1 ? bucket.iterator().next() : null;
408 }
409
410 @Override
411 public default MarkedSet<Value> createSingletonBucket(Value value) {
412 MarkedSet<Value> result = createMarkedSet();
413 result.addOne(value);
414 return result;
415 }
416
417 @Override
418 public default MarkedSet<Value> createDeltaBucket(Value positive, Value negative) {
419 throw new IllegalStateException();
420 }
421 }
422
423 /**
424 * A multi-lookup whose buckets are multisets.
425 *
426 * <p> Not intended as an API, but rather as a 'base class' for implementors.
427 * Realized as an interface with default implementations, instead of an abstract class,
428 * to ensure that implementors can easily choose a base class such as UnifiedMap to augment.
429 *
430 * <p> Implementor should inherit from a Map<Key, Object>-like class (primitive map possible)
431 * and bind the lowLevel* methods accordingly.
432 *
433 * @noreference This interface is not intended to be referenced by clients.
434 * @noimplement This interface is not intended to be implemented by clients.
435 * @author Gabor Bergmann
436 */
437 public static interface ToMultisetsAbstract<Key, Value> extends IMultiLookupAbstract<Key, Value, MarkedMemory.MarkedMultiset<Value>> {
438 /**
439 * @return a fresh, empty marked multiset
440 */
441 public MarkedMemory.MarkedMultiset<Value> createMarkedMultiset();
442
443 @Override
444 public default boolean negativesAllowed() {
445 return false;
446 }
447 @Override
448 default boolean duplicatesAllowed() {
449 return true;
450 }
451
452 @Override
453 public default boolean addToBucket(MarkedMemory.MarkedMultiset<Value> bucket, Value value, boolean throwIfImpossible) {
454 return bucket.addOne(value);
455 }
456
457 @Override
458 public default boolean removeFromBucket(MarkedMemory.MarkedMultiset<Value> bucket, Value value, boolean throwIfImpossible) {
459 return throwIfImpossible ? bucket.removeOne(value) : bucket.removeOneOrNop(value);
460 }
461
462 @Override
463 public default Value asSingleton(MarkedMemory.MarkedMultiset<Value> bucket) {
464 if (bucket.size() != 1) return null;
465 Value candidate = bucket.iterator().next();
466 return bucket.getCount(candidate) == 1 ? candidate : null;
467 }
468
469 @Override
470 public default MarkedMemory.MarkedMultiset<Value> createSingletonBucket(Value value) {
471 MarkedMemory.MarkedMultiset<Value> result = createMarkedMultiset();
472 result.addOne(value);
473 return result;
474 }
475
476 @Override
477 public default MarkedMemory.MarkedMultiset<Value> createDeltaBucket(Value positive, Value negative) {
478 throw new IllegalStateException();
479 }
480 }
481
482
483 // TODO add ToDeltaBagsAbstract
484
485} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiset.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiset.java
new file mode 100644
index 00000000..bdd5d597
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IMultiset.java
@@ -0,0 +1,30 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11/**
12 * An {@link IMemory} that always contains values with a nonnegative multiplicity.
13 *
14 * <p> In case a write operation caused underflow, an {@link IllegalStateException} is thrown.
15 *
16 * @author Gabor Bergmann
17 * @since 1.7
18 */
19public interface IMultiset<T> extends IMemory<T> {
20
21 /**
22 * Adds the given number of occurrences to the memory. The count value must be a positive number.
23 *
24 * @param count
25 * the number of occurrences
26 * @return true if the tuple was not present before in the memory
27 */
28 boolean addPositive(T value, int count);
29
30} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IProvider.java
new file mode 100644
index 00000000..cd25dc95
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/IProvider.java
@@ -0,0 +1,30 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.function.Function;
12import java.util.function.Supplier;
13
14import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
15
16/**
17 * A provider interface useful in various registry instances.
18 *
19 * @author Zoltan Ujhelyi
20 *
21 */
22public interface IProvider<T> extends Supplier<T>{
23
24 public final class ProvidedValueFunction implements Function<IProvider<PQuery>, PQuery> {
25 @Override
26 public PQuery apply(IProvider<PQuery> input) {
27 return (input == null) ? null : input.get();
28 }
29 }
30}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/ISetMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/ISetMemory.java
new file mode 100644
index 00000000..0c03da48
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/ISetMemory.java
@@ -0,0 +1,37 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.function.BiConsumer;
12
13/**
14 * An {@link IMemory} that always contains values with a 0 or +1 multiplicity.
15 *
16 * <p> In case a write operation causes underflow or overflow, an {@link IllegalStateException} is thrown.
17 *
18 * @author Gabor Bergmann
19 * @since 2.0
20 */
21public interface ISetMemory<T> extends IMemory<T> {
22
23 @Override
24 default void forEachEntryWithMultiplicities(BiConsumer<T, Integer> entryConsumer) {
25 for (T t : this.distinctValues()) entryConsumer.accept(t, 1);
26 }
27
28
29 @Override
30 default boolean removeOne(T value) {
31 if (!removeOneOrNop(value))
32 throw new IllegalStateException();
33 return true;
34 }
35
36
37}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MapBackedMemoryView.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MapBackedMemoryView.java
new file mode 100644
index 00000000..3be078bd
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MapBackedMemoryView.java
@@ -0,0 +1,102 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Iterator;
12import java.util.Map;
13import java.util.Map.Entry;
14import java.util.Set;
15import java.util.function.BiConsumer;
16
17/**
18 * Wraps a Map<T, Integer> (mapping elements to non-zero multiplicities) into an {@link IMemoryView}.
19 *
20 * @author Gabor Bergmann
21 * @since 2.0
22 */
23public class MapBackedMemoryView<T> implements IMemoryView<T> {
24
25 private Map<T, Integer> wrapped;
26
27 /**
28 * @param wrapped an equivalent map from contained objects to multiplicities
29 */
30 protected MapBackedMemoryView(Map<T, Integer> wrapped) {
31 super();
32 this.wrapped = wrapped;
33 }
34
35 @Override
36 public Iterator<T> iterator() {
37 return wrapped.keySet().iterator();
38 }
39
40 @Override
41 public int getCount(T value) {
42 return getCountUnsafe(value);
43 }
44
45 @Override
46 public int getCountUnsafe(Object value) {
47 Integer count = wrapped.get(value);
48 return count == null ? 0 : count;
49 }
50
51 @Override
52 public boolean containsNonZero(T value) {
53 return wrapped.containsKey(value);
54 }
55
56 @Override
57 public boolean containsNonZeroUnsafe(Object value) {
58 return wrapped.containsKey(value);
59 }
60
61 @Override
62 public int size() {
63 return wrapped.size();
64 }
65
66 @Override
67 public boolean isEmpty() {
68 return wrapped.isEmpty();
69 }
70
71 @Override
72 public Set<T> distinctValues() {
73 return wrapped.keySet();
74 }
75
76
77 @Override
78 public void forEachEntryWithMultiplicities(BiConsumer<T, Integer> entryConsumer) {
79 for (Entry<T, Integer> entry : wrapped.entrySet()) {
80 entryConsumer.accept(entry.getKey(), entry.getValue());
81 }
82 }
83
84 @Override
85 public Iterable<Entry<T, Integer>> entriesWithMultiplicities() {
86 return wrapped.entrySet();
87 }
88
89 @Override
90 public int hashCode() {
91 return IMemoryView.hashCode(this);
92 }
93 @Override
94 public boolean equals(Object obj) {
95 return IMemoryView.equals(this, obj);
96 }
97
98 @Override
99 public String toString() {
100 return wrapped.toString();
101 }
102}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MarkedMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MarkedMemory.java
new file mode 100644
index 00000000..d22dcbe7
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MarkedMemory.java
@@ -0,0 +1,21 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQueryLabs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11/**
12 * Internal marker type, must only be instantiated inside implementors of IMultiLookupImpl
13 * @noimplement This interface is not intended to be implemented by clients.
14 * @since 2.0
15 */
16public interface MarkedMemory<Value> extends IMemory<Value> {
17
18 static interface MarkedSet<Value> extends MarkedMemory<Value> {}
19 static interface MarkedMultiset<Value> extends MarkedMemory<Value> {}
20 static interface MarkedDeltaBag<Value> extends MarkedMemory<Value> {}
21} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MemoryViewBackedMapView.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MemoryViewBackedMapView.java
new file mode 100644
index 00000000..49711a89
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/MemoryViewBackedMapView.java
@@ -0,0 +1,117 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.HashSet;
14import java.util.Map;
15import java.util.Set;
16
17/**
18 * A partial and read-only Map implementation, mapping elements to multiplicities backed by an {@link IMemoryView}.
19 *
20 * <p> Not implemented: write methods.
21 *
22 * <p> Inefficiently implemented: {@link #containsValue(Object)}, {@link #values()}, {@link #entrySet()}.
23 *
24 * @author Gabor Bergmann
25 * @since 2.0
26 */
27public class MemoryViewBackedMapView<T> implements Map<T, Integer> {
28
29 private static final String READ_ONLY = "Read only";
30 private final IMemoryView<T> wrapped;
31
32 /**
33 * @param wrapped a memory view whose contents are to be exposed as an element-to-integer map.
34 */
35 protected MemoryViewBackedMapView(IMemoryView<T> wrapped) {
36 super();
37 this.wrapped = wrapped;
38 }
39
40 @Override
41 public int size() {
42 return wrapped.size();
43 }
44
45 @Override
46 public boolean isEmpty() {
47 return wrapped.isEmpty();
48 }
49
50 @Override
51 public boolean containsKey(Object key) {
52 return wrapped.containsNonZeroUnsafe(key);
53 }
54
55 @Override
56 public boolean containsValue(Object value) {
57 if (value instanceof Integer) {
58 for (Entry<T, Integer> entry : wrapped.entriesWithMultiplicities()) {
59 if (entry.getValue().equals(value)) return true;
60 }
61 }
62 return false;
63 }
64
65 @Override
66 public Integer put(T key, Integer value) {
67 throw new UnsupportedOperationException(READ_ONLY);
68 }
69
70 @Override
71 public Integer get(Object key) {
72 int count = wrapped.getCountUnsafe(key);
73 if (count == 0) return null; else return count;
74 }
75
76 @Override
77 public Integer remove(Object key) {
78 throw new UnsupportedOperationException(READ_ONLY);
79 }
80
81 @Override
82 public void putAll(Map<? extends T, ? extends Integer> m) {
83 throw new UnsupportedOperationException(READ_ONLY);
84 }
85
86 @Override
87 public void clear() {
88 throw new UnsupportedOperationException(READ_ONLY);
89 }
90
91 @Override
92 public Set<T> keySet() {
93 return wrapped.distinctValues();
94 }
95
96 @Override
97 public Collection<Integer> values() {
98 Collection<Integer> result = new ArrayList<>();
99 wrapped.forEachEntryWithMultiplicities((value, count) -> result.add(count));
100 return result;
101 }
102
103 @Override
104 public Set<Entry<T, Integer>> entrySet() {
105 Set<Entry<T, Integer>> result = new HashSet<>();
106 for (Entry<T, Integer> entry : wrapped.entriesWithMultiplicities()) {
107 result.add(entry);
108 }
109 return result;
110 }
111
112
113 @Override
114 public String toString() {
115 return wrapped.toString();
116 }
117}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Preconditions.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Preconditions.java
new file mode 100644
index 00000000..e9e5e3a0
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Preconditions.java
@@ -0,0 +1,208 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.function.Supplier;
12
13/**
14 * This class was motivated by the similar Preconditions class from Guava to provide simple precondition checking
15 * functionality. However, as starting with version 2.0 the runtime of VIATRA Query should not depend on Guava, the
16 * relevant functionality of the Preconditions checking functionality will be implemented here.
17 *
18 * @author Zoltan Ujhelyi
19 * @since 2.0
20 *
21 */
22public final class Preconditions {
23
24 private Preconditions() {
25 /* Utility class constructor */ }
26
27 /**
28 * Ensures the truth of an expression involving one or more parameters to the calling method.
29 *
30 * @param expression
31 * a boolean expression
32 * @throws IllegalArgumentException
33 * if {@code expression} is false
34 */
35 public static void checkArgument(boolean expression) {
36 if (!expression) {
37 throw new IllegalArgumentException();
38 }
39 }
40
41 /**
42 * Ensures the truth of an expression involving one or more parameters to the calling method.
43 *
44 * @param expression
45 * a boolean expression
46 * @param errorMessage
47 * the exception message to use if the check fails
48 * @throws IllegalArgumentException
49 * if {@code expression} is false
50 */
51 public static void checkArgument(boolean expression, String errorMessage) {
52 if (!expression) {
53 throw new IllegalArgumentException(errorMessage);
54 }
55 }
56
57 /**
58 * Ensures the truth of an expression involving one or more parameters to the calling method.
59 *
60 * @param expression
61 * a boolean expression
62 * @param errorMessageTemplate
63 * a template for the exception message should the check fail using the Java Formatter syntax; the same
64 * as used by {@link String#format(String, Object...)}.
65 * @param errorMessageArgs
66 * the arguments to be substituted into the message template.
67 * @throws IllegalArgumentException
68 * if {@code expression} is false
69 * @throws NullPointerException
70 * if the check fails and either {@code errorMessageTemplate} or {@code errorMessageArgs} is null (don't
71 * let this happen)
72 */
73 public static void checkArgument(boolean expression, String errorMessageTemplate, Object... errorMessageArgs) {
74 if (!expression) {
75 throw new IllegalArgumentException(String.format(errorMessageTemplate, errorMessageArgs));
76 }
77 }
78
79 /**
80 * Ensures the truth of an expression involving one or more parameters to the calling method.
81 *
82 * @param expression
83 * a boolean expression
84 * @param messageSupplier a supplier that is called to calculate the error message if necessary
85 * @throws IllegalArgumentException
86 * if {@code expression} is false
87 */
88 public static void checkArgument(boolean expression, Supplier<String> messageSupplier) {
89 if (!expression) {
90 throw new IllegalArgumentException(messageSupplier.get());
91 }
92 }
93
94 /**
95 * Ensures the truth of an expression involving one or more fields of a class.
96 *
97 * @param expression
98 * a boolean expression
99 * @throws IllegalStateException
100 * if {@code expression} is false
101 */
102 public static void checkState(boolean expression) {
103 if (!expression) {
104 throw new IllegalStateException();
105 }
106 }
107
108 /**
109 * Ensures the truth of an expression involving one or more fields of a class.
110 *
111 * @param expression
112 * a boolean expression
113 * @param errorMessage
114 * the exception message to use if the check fails
115 * @throws IllegalStateException
116 * if {@code expression} is false
117 */
118 public static void checkState(boolean expression, String errorMessage) {
119 if (!expression) {
120 throw new IllegalStateException(errorMessage);
121 }
122 }
123
124 /**
125 * Ensures the truth of an expression involving one or more fields of a class.
126 *
127 * @param expression
128 * a boolean expression
129 * @param errorMessageTemplate
130 * a template for the exception message should the check fail using the Java Formatter syntax; the same
131 * as used by {@link String#format(String, Object...)}.
132 * @param errorMessageArgs
133 * the arguments to be substituted into the message template.
134 * @throws IllegalStateException
135 * if {@code expression} is false
136 * @throws NullPointerException
137 * if the check fails and either {@code errorMessageTemplate} or {@code errorMessageArgs} is null (don't
138 * let this happen)
139 */
140 public static void checkState(boolean expression, String errorMessageTemplate, Object... errorMessageArgs) {
141 if (!expression) {
142 throw new IllegalStateException(String.format(errorMessageTemplate, errorMessageArgs));
143 }
144 }
145
146 /**
147 * Ensures the truth of an expression involving one or more fields of a class.
148 *
149 * @param expression
150 * a boolean expression
151 * @param messageSupplier a supplier that is called to calculate the error message if necessary
152 * @throws IllegalStateException
153 * if {@code expression} is false
154 */
155 public static void checkState(boolean expression, Supplier<String> messageSupplier) {
156 if (!expression) {
157 throw new IllegalStateException(messageSupplier.get());
158 }
159 }
160
161 /**
162 * Ensures that an index is appropriate for a list or array of given size.
163 *
164 * @param index
165 * @param size
166 * @throws IndexOutOfBoundsException
167 * if index is negative or is greater or equal to size
168 */
169 public static void checkElementIndex(int index, int size) {
170 if (index < 0 || index >= size) {
171 throw new IndexOutOfBoundsException();
172 }
173 }
174
175 /**
176 * Ensures that an index is appropriate for a list or array of given size.
177 *
178 * @param index
179 * @param size
180 * @param errorMessageTemplate
181 * a template for the exception message should the check fail using the Java Formatter syntax; the same
182 * as used by {@link String#format(String, Object...)}.
183 * @param errorMessageArgs
184 * the arguments to be substituted into the message template.
185 * @throws IndexOutOfBoundsException
186 * if index is negative or is greater or equal to size
187 */
188 public static void checkElementIndex(int index, int size, String errorMessageTemplate, Object... errorMessageArgs) {
189 if (index < 0 || index >= size) {
190 throw new IndexOutOfBoundsException(String.format(errorMessageTemplate, errorMessageArgs));
191 }
192 }
193
194 /**
195 * Ensures that an index is appropriate for a list or array of given size.
196 *
197 * @param index
198 * @param size
199 * @param messageSupplier a supplier that is called to calculate the error message if necessary
200 * @throws IndexOutOfBoundsException
201 * if index is negative or is greater or equal to size
202 */
203 public static void checkElementIndex(int index, int size, Supplier<String> messageSupplier) {
204 if (index < 0 || index >= size) {
205 throw new IndexOutOfBoundsException(messageSupplier.get());
206 }
207 }
208}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/PurgableCache.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/PurgableCache.java
new file mode 100644
index 00000000..c4e6b5af
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/PurgableCache.java
@@ -0,0 +1,44 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.HashMap;
12import java.util.Map;
13import java.util.function.Supplier;
14
15/**
16 * @author Zoltan Ujhelyi
17 * @since 1.7
18 * @noreference This class is not intended to be referenced by clients.
19 */
20public class PurgableCache implements ICache {
21
22 Map<Object, Object> storage = new HashMap<>();
23
24 @Override
25 @SuppressWarnings("unchecked")
26 public <T> T getValue(Object key, Class<? extends T> clazz, Supplier<T> valueProvider) {
27 if (storage.containsKey(key)) {
28 Object value = storage.get(key);
29 Preconditions.checkState(clazz.isInstance(value), "Cache stores for key %s a value of %s that is incompatible with the requested type %s", key, value, clazz);
30 return (T) value;
31 } else {
32 T value = valueProvider.get();
33 storage.put(key, value);
34 return value;
35 }
36 }
37
38 /**
39 * Removes all values stored in the cache
40 */
41 public void purge() {
42 storage.clear();
43 }
44}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Sets.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Sets.java
new file mode 100644
index 00000000..3749fe06
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Sets.java
@@ -0,0 +1,90 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *
9 * Contributors:
10 * Gabor Bergmann - initial API and implementation
11 *******************************************************************************/
12package tools.refinery.viatra.runtime.matchers.util;
13
14import java.util.ArrayList;
15import java.util.List;
16import java.util.Set;
17import java.util.stream.Collectors;
18import java.util.stream.Stream;
19
20/**
21 * This class was motivated by the similar Sets class from Guava to provide simple set manipulation
22 * functionality. However, as starting with version 2.3 the runtime of VIATRA Query should not depend on Guava,
23 * not even internally, the relevant subset of Sets methods will be reimplemented here.
24 *
25 * <p> The current approach is to delegate to Eclipse Collections wherever possible.
26 * Such glue methods are useful so that downstream clients can avoid directly depending on Eclipse Collections.
27 *
28 * <p> Without an equivalent from Eclipse Collections, {@link #cartesianProduct(List)} is implemented here from scratch.
29 *
30 * @author Gabor Bergmann
31 * @since 2.3
32 */
33public final class Sets {
34
35 /**
36 * @since 2.4
37 */
38 public static <A> Set<A> newSet(Iterable<A> elements) {
39 return org.eclipse.collections.impl.factory.Sets.mutable.ofAll(elements);
40 }
41
42 public static <A> Set<A> intersection(Set<A> left, Set<A> right) {
43 return org.eclipse.collections.impl.factory.Sets.intersect(left, right);
44 }
45
46 public static <A> Set<A> difference(Set<A> left, Set<A> right) {
47 return org.eclipse.collections.impl.factory.Sets.difference(left, right);
48 }
49
50 public static <A> Set<A> union(Set<A> left, Set<A> right) {
51 return org.eclipse.collections.impl.factory.Sets.union(left, right);
52 }
53
54 public static <A> Set<? extends Set<A>> powerSet(Set<A> set) {
55 return org.eclipse.collections.impl.factory.Sets.powerSet(set);
56 }
57
58 public static <A> Set<List<A>> cartesianProduct(List<? extends Set<? extends A>> setsList) {
59
60 class Suffix { // simple immutable linked list
61 private A head;
62 private Suffix next;
63
64 public Suffix(A head, Suffix next) {
65 super();
66 this.head = head;
67 this.next = next;
68 }
69
70 public List<A> toList() {
71 ArrayList<A> result = new ArrayList<>();
72 for (Suffix cursor = this; cursor!=null; cursor = cursor.next)
73 result.add(cursor.head);
74 return result;
75 }
76 }
77
78 // build result lists from end to start, in the form of suffixes
79 Stream<Suffix> suffixes = Stream.of((Suffix) null /* empty suffix*/);
80 for (int i = setsList.size()-1; i>=0; --i) { // iterate sets in reverse order
81 Set<? extends A> set = setsList.get(i);
82 suffixes = suffixes.flatMap(suffix -> set.stream().map(newElement -> new Suffix(newElement, suffix)));
83 }
84
85
86 return suffixes.map(Suffix::toList).collect(Collectors.toSet());
87 }
88
89
90}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Signed.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Signed.java
new file mode 100644
index 00000000..8f8bc228
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/Signed.java
@@ -0,0 +1,60 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, itemis AG, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Objects;
12
13/**
14 * A piece of data associated with a direction.
15 *
16 * @author Tamas Szabo
17 * @since 2.4
18 */
19public class Signed<Payload extends Comparable<Payload>> {
20
21 private final Payload payload;
22 private final Direction direction;
23
24 public Signed(final Direction direction, final Payload payload) {
25 this.payload = payload;
26 this.direction = direction;
27 }
28
29 public Payload getPayload() {
30 return payload;
31 }
32
33 public Direction getDirection() {
34 return direction;
35 }
36
37 @Override
38 public int hashCode() {
39 return Objects.hash(direction, payload);
40 }
41
42 @Override
43 public boolean equals(final Object obj) {
44 if (this == obj) {
45 return true;
46 } else if (obj == null || this.getClass() != obj.getClass()) {
47 return false;
48 } else {
49 @SuppressWarnings("rawtypes")
50 final Signed other = (Signed) obj;
51 return direction == other.direction && Objects.equals(payload, other.payload);
52 }
53 }
54
55 @Override
56 public String toString() {
57 return this.direction.asSign() + this.payload.toString();
58 }
59
60} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonInstanceProvider.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonInstanceProvider.java
new file mode 100644
index 00000000..cc5963f7
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonInstanceProvider.java
@@ -0,0 +1,29 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Zoltan Ujhelyi, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11/**
12 * A provider implementation that always returns the same object instance.
13 * @author Zoltan Ujhelyi
14 */
15public class SingletonInstanceProvider<T> implements IProvider<T>{
16
17 private T instance;
18
19 public SingletonInstanceProvider(T instance) {
20 Preconditions.checkArgument(instance != null, "Instance parameter must not be null.");
21 this.instance = instance;
22 }
23
24 @Override
25 public T get() {
26 return instance;
27 }
28
29} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonMemoryView.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonMemoryView.java
new file mode 100644
index 00000000..b303f9ad
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/SingletonMemoryView.java
@@ -0,0 +1,105 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Collections;
12import java.util.Iterator;
13import java.util.NoSuchElementException;
14import java.util.Set;
15
16/**
17 * An immutable memory view that consists of a single non-null element with multiplicity 1.
18 * @author Gabor Bergmann
19 * @since 2.0
20 */
21public final class SingletonMemoryView<Value> implements IMemoryView<Value> {
22
23 private Value wrapped;
24 private static final int ONE_HASH = Integer.valueOf(1).hashCode();
25
26 public SingletonMemoryView(Value value) {
27 this.wrapped = value;
28 }
29
30 @Override
31 public Iterator<Value> iterator() {
32 return new Iterator<Value>() {
33 boolean hasNext = true;
34
35 @Override
36 public boolean hasNext() {
37 return hasNext;
38 }
39
40 @Override
41 public Value next() {
42 if (hasNext) {
43 hasNext = false;
44 return wrapped;
45 } else throw new NoSuchElementException();
46 }
47 };
48 }
49
50 @Override
51 public int getCount(Value value) {
52 return wrapped.equals(value) ? 1 : 0;
53 }
54
55 @Override
56 public int getCountUnsafe(Object value) {
57 return wrapped.equals(value) ? 1 : 0;
58 }
59
60 @Override
61 public boolean containsNonZero(Value value) {
62 return wrapped.equals(value);
63 }
64
65 @Override
66 public boolean containsNonZeroUnsafe(Object value) {
67 return wrapped.equals(value);
68 }
69
70 @Override
71 public int size() {
72 return 1;
73 }
74
75 @Override
76 public boolean isEmpty() {
77 return false;
78 }
79
80 @Override
81 public Set<Value> distinctValues() {
82 return Collections.singleton(wrapped);
83 }
84
85 @Override
86 public boolean equals(Object obj) {
87 if (obj instanceof IMemoryView<?>) {
88 IMemoryView<?> other = (IMemoryView<?>) obj;
89 if (1 != other.size()) return false;
90 if (1 != other.getCountUnsafe(wrapped)) return false;
91 return true;
92 }
93 return false;
94 }
95
96 @Override
97 public int hashCode() {
98 return wrapped.hashCode() ^ ONE_HASH;
99 }
100
101 @Override
102 public String toString() {
103 return "{" + wrapped + "}";
104 }
105}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/TimelyMemory.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/TimelyMemory.java
new file mode 100644
index 00000000..90fcad4d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/TimelyMemory.java
@@ -0,0 +1,517 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, itemis AG, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util;
10
11import java.util.Collections;
12import java.util.Map;
13import java.util.Map.Entry;
14import java.util.NavigableMap;
15import java.util.Set;
16import java.util.TreeMap;
17
18import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
19import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
20import tools.refinery.viatra.runtime.matchers.util.resumable.Resumable;
21import tools.refinery.viatra.runtime.matchers.util.resumable.UnmaskedResumable;
22import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
23import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
24import tools.refinery.viatra.runtime.matchers.util.timeline.Timelines;
25
26/**
27 * A timely memory implementation that incrementally maintains the {@link Timeline}s of tuples. The memory is capable of
28 * lazy folding (see {@link Resumable}).
29 *
30 * @author Tamas Szabo
31 * @since 2.3
32 */
33public class TimelyMemory<Timestamp extends Comparable<Timestamp>> implements Clearable, UnmaskedResumable<Timestamp> {
34
35 protected final Map<Tuple, TreeMap<Timestamp, CumulativeCounter>> counters;
36 protected final Map<Tuple, Timeline<Timestamp>> timelines;
37 public final TreeMap<Timestamp, Map<Tuple, FoldingState>> foldingState;
38 protected final Set<Tuple> presentAtInfinity;
39 protected final boolean isLazy;
40 protected final Diff<Timestamp> EMPTY_DIFF = new Diff<Timestamp>();
41
42 public TimelyMemory() {
43 this(false);
44 }
45
46 public TimelyMemory(final boolean isLazy) {
47 this.counters = CollectionsFactory.createMap();
48 this.timelines = CollectionsFactory.createMap();
49 this.presentAtInfinity = CollectionsFactory.createSet();
50 this.isLazy = isLazy;
51 if (isLazy) {
52 this.foldingState = CollectionsFactory.createTreeMap();
53 } else {
54 this.foldingState = null;
55 }
56 }
57
58 @Override
59 public Set<Tuple> getResumableTuples() {
60 if (this.foldingState == null || this.foldingState.isEmpty()) {
61 return Collections.emptySet();
62 } else {
63 return this.foldingState.firstEntry().getValue().keySet();
64 }
65 }
66
67 @Override
68 public Timestamp getResumableTimestamp() {
69 if (this.foldingState == null || this.foldingState.isEmpty()) {
70 return null;
71 } else {
72 return this.foldingState.firstKey();
73 }
74 }
75
76 /**
77 * Registers the given folding state for the specified timestamp and tuple. If there is already a state stored, the
78 * two states will be merged together.
79 */
80 protected void addFoldingState(final Tuple tuple, final FoldingState state, final Timestamp timestamp) {
81 assert state.diff != 0;
82 final Map<Tuple, FoldingState> tupleMap = this.foldingState.computeIfAbsent(timestamp,
83 k -> CollectionsFactory.createMap());
84 tupleMap.compute(tuple, (k, v) -> {
85 return v == null ? state : v.merge(state);
86 });
87 }
88
89 @Override
90 public Map<Tuple, Diff<Timestamp>> resumeAt(final Timestamp timestamp) {
91 Timestamp current = this.getResumableTimestamp();
92 if (current == null) {
93 throw new IllegalStateException("There is othing to fold!");
94 } else if (current.compareTo(timestamp) != 0) {
95 // It can happen that already registered folding states end up having zero diffs,
96 // and we are instructed to continue folding at a timestamp that is higher
97 // than the lowest timestamp with a folding state.
98 // However, we only do garbage collection in doFoldingState, so now it is time to
99 // first clean up those states with zero diffs.
100 while (current != null && current.compareTo(timestamp) < 0) {
101 final Map<Tuple, FoldingState> tupleMap = this.foldingState.remove(current);
102 for (final Entry<Tuple, FoldingState> entry : tupleMap.entrySet()) {
103 final Tuple key = entry.getKey();
104 final FoldingState value = entry.getValue();
105 if (value.diff != 0) {
106 throw new IllegalStateException("Expected zero diff during garbage collection at " + current
107 + ", but the diff was " + value.diff + "!");
108 }
109 doFoldingStep(key, value, current);
110 }
111 current = this.getResumableTimestamp();
112 }
113 if (current == null || current.compareTo(timestamp) != 0) {
114 throw new IllegalStateException("Expected to continue folding at " + timestamp + "!");
115 }
116 }
117
118 final Map<Tuple, Diff<Timestamp>> diffMap = CollectionsFactory.createMap();
119 final Map<Tuple, FoldingState> tupleMap = this.foldingState.remove(timestamp);
120 for (final Entry<Tuple, FoldingState> entry : tupleMap.entrySet()) {
121 final Tuple key = entry.getKey();
122 final FoldingState value = entry.getValue();
123 diffMap.put(key, doFoldingStep(key, value, timestamp));
124 }
125
126 if (this.foldingState.get(timestamp) != null) {
127 throw new IllegalStateException(
128 "Folding at " + timestamp + " produced more folding work at the same timestamp!");
129 }
130
131 return diffMap;
132 }
133
134 protected Diff<Timestamp> doFoldingStep(final Tuple tuple, final FoldingState state, final Timestamp timestamp) {
135 final CumulativeCounter counter = getCounter(tuple, timestamp);
136 if (state.diff == 0) {
137 gcCounters(counter, tuple, timestamp);
138 return EMPTY_DIFF;
139 } else {
140 final Diff<Timestamp> resultDiff = new Diff<>();
141 final Timestamp nextTimestamp = this.counters.get(tuple).higherKey(timestamp);
142
143 final int oldCumulative = counter.cumulative;
144
145 counter.cumulative += state.diff;
146
147 computeDiffsLazy(state.diff < 0 ? Direction.DELETE : Direction.INSERT, oldCumulative, counter.cumulative,
148 timestamp, nextTimestamp, resultDiff);
149
150 gcCounters(counter, tuple, timestamp);
151 updateTimeline(tuple, resultDiff);
152
153 // prepare folding state for next timestamp
154 if (nextTimestamp != null) {
155 // propagate the incoming diff, not the diff stored in counter
156 addFoldingState(tuple, new FoldingState(state.diff), nextTimestamp);
157 }
158
159 return resultDiff;
160 }
161 }
162
163 /**
164 * On-demand initializes and returns the counter for the given tuple and timestamp.
165 */
166 protected CumulativeCounter getCounter(final Tuple tuple, final Timestamp timestamp) {
167 final TreeMap<Timestamp, CumulativeCounter> counterTimeline = this.counters.computeIfAbsent(tuple,
168 k -> CollectionsFactory.createTreeMap());
169
170 final CumulativeCounter counter = counterTimeline.computeIfAbsent(timestamp, k -> {
171 final Entry<Timestamp, CumulativeCounter> previousCounter = counterTimeline.lowerEntry(k);
172 final int previousCumulative = previousCounter == null ? 0 : previousCounter.getValue().cumulative;
173 return new CumulativeCounter(0, previousCumulative);
174 });
175
176 return counter;
177 }
178
179 /**
180 * Garbage collects the counter of the given tuple and timestamp if the new diff is zero.
181 */
182 protected void gcCounters(final CumulativeCounter counter, final Tuple tuple, final Timestamp timestamp) {
183 if (counter.diff == 0) {
184 final TreeMap<Timestamp, CumulativeCounter> counterMap = this.counters.get(tuple);
185 counterMap.remove(timestamp);
186 if (counterMap.isEmpty()) {
187 this.counters.remove(tuple);
188 }
189 }
190 }
191
192 /**
193 * Utility method that computes the timeline diffs in case of lazy memories. The diffs will be inserted into the
194 * input parameter. This method computes diffs for entire plateaus that spans from timestamp to nextTimestamp.
195 *
196 * Compared to the eager version of this method, the lazy version makes use of both the old and the new cumulative
197 * values because it can happen that the cumulative is incremented by a value that is larger than 1 (as folding
198 * states are merged together). This means that we cant decide whether the cumulative became positive by comparing
199 * the new value to 1.
200 */
201 protected void computeDiffsLazy(final Direction direction, final int oldCumulative, final int newCumulative,
202 final Timestamp timestamp, final Timestamp nextTimestamp, final Diff<Timestamp> diffs) {
203 if (direction == Direction.INSERT) {
204 if (newCumulative == 0) {
205 throw new IllegalStateException("Cumulative count can never be negative!");
206 } else {
207 if (oldCumulative == 0 /* current became positive */) {
208 // (1) either we sent out a DELETE before and now we need to cancel it,
209 // (2) or we just INSERT this for the first time
210 diffs.add(new Signed<>(Direction.INSERT, timestamp));
211 if (nextTimestamp != null) {
212 diffs.add(new Signed<>(Direction.DELETE, nextTimestamp));
213 }
214 } else /* current stays positive */ {
215 // nothing to do
216 }
217 }
218 } else {
219 if (newCumulative < 0) {
220 throw new IllegalStateException("Cumulative count can never be negative!");
221 } else {
222 if (newCumulative == 0 /* current became zero */) {
223 diffs.add(new Signed<>(Direction.DELETE, timestamp));
224 if (nextTimestamp != null) {
225 diffs.add(new Signed<>(Direction.INSERT, nextTimestamp));
226 }
227 } else /* current stays positive */ {
228 // nothing to do
229 }
230 }
231 }
232 }
233
234 /**
235 * Utility method that computes the timeline diffs in case of eager memories. The diffs will be inserted into the
236 * input parameter. This method computes diffs that describe momentary changes instead of plateaus. Returns a
237 * {@link SignChange} that describes how the sign has changed at the given timestamp.
238 */
239 protected SignChange computeDiffsEager(final Direction direction, final CumulativeCounter counter,
240 final SignChange signChangeAtPrevious, final Timestamp timestamp, final Diff<Timestamp> diffs) {
241 if (direction == Direction.INSERT) {
242 if (counter.cumulative == 0) {
243 throw new IllegalStateException("Cumulative count can never be negative!");
244 } else {
245 if (counter.cumulative == 1 /* current became positive */) {
246 if (signChangeAtPrevious != SignChange.BECAME_POSITIVE) {
247 // (1) either we sent out a DELETE before and now we need to cancel it,
248 // (2) or we just INSERT this for the first time
249 diffs.add(new Signed<>(Direction.INSERT, timestamp));
250 } else {
251 // we have already emitted this at the previous timestamp
252 // both previous and current became positive
253 throw new IllegalStateException(
254 "This would mean that the diff at current is 0 " + counter.diff);
255 }
256
257 // remember for next timestamp
258 return SignChange.BECAME_POSITIVE;
259 } else /* current stays positive */ {
260 if (signChangeAtPrevious == SignChange.BECAME_POSITIVE) {
261 // we sent out an INSERT before and now the timeline is positive already starting at previous
262 // we need to cancel the effect of this with a DELETE
263 diffs.add(new Signed<>(Direction.DELETE, timestamp));
264 } else {
265 // this is normal, both previous and current was positive and stays positive
266 }
267
268 // remember for next timestamp
269 return SignChange.IRRELEVANT;
270 }
271 }
272 } else {
273 if (counter.cumulative < 0) {
274 throw new IllegalStateException("Cumulative count can never be negative!");
275 } else {
276 if (counter.cumulative == 0 /* current became zero */) {
277 if (signChangeAtPrevious != SignChange.BECAME_ZERO) {
278 // (1) either we sent out a INSERT before and now we need to cancel it,
279 // (2) or we just DELETE this for the first time
280 diffs.add(new Signed<>(Direction.DELETE, timestamp));
281 } else {
282 // we have already emitted this at the previous timestamp
283 // both previous and current became zero
284 throw new IllegalStateException(
285 "This would mean that the diff at current is 0 " + counter.diff);
286 }
287
288 // remember for next timestamp
289 return SignChange.BECAME_ZERO;
290 } else /* current stays positive */ {
291 if (signChangeAtPrevious == SignChange.BECAME_ZERO) {
292 // we sent out a DELETE before and now the timeline is zero already starting at previous
293 // we need to cancel the effect of this with a INSERT
294 diffs.add(new Signed<>(Direction.INSERT, timestamp));
295 } else {
296 // this is normal, both previous and current was positive and stays positive
297 }
298
299 // remember for next timestamp
300 return SignChange.IRRELEVANT;
301 }
302 }
303 }
304 }
305
306 public Diff<Timestamp> put(final Tuple tuple, final Timestamp timestamp) {
307 if (this.isLazy) {
308 return putLazy(tuple, timestamp);
309 } else {
310 return putEager(tuple, timestamp);
311 }
312 }
313
314 public Diff<Timestamp> remove(final Tuple tuple, final Timestamp timestamp) {
315 if (this.isLazy) {
316 return removeLazy(tuple, timestamp);
317 } else {
318 return removeEager(tuple, timestamp);
319 }
320 }
321
322 protected Diff<Timestamp> putEager(final Tuple tuple, final Timestamp timestamp) {
323 final Diff<Timestamp> resultDiff = new Diff<>();
324 final CumulativeCounter counter = getCounter(tuple, timestamp);
325 ++counter.diff;
326
327 // before the INSERT timestamp, no change at all
328 // it cannot happen that those became positive in this round
329 SignChange signChangeAtPrevious = SignChange.IRRELEVANT;
330
331 final NavigableMap<Timestamp, CumulativeCounter> nextCounters = this.counters.get(tuple).tailMap(timestamp,
332 true);
333 for (final Entry<Timestamp, CumulativeCounter> currentEntry : nextCounters.entrySet()) {
334 final Timestamp currentTimestamp = currentEntry.getKey();
335 final CumulativeCounter currentCounter = currentEntry.getValue();
336 ++currentCounter.cumulative;
337 signChangeAtPrevious = computeDiffsEager(Direction.INSERT, currentCounter, signChangeAtPrevious,
338 currentTimestamp, resultDiff);
339 }
340
341 gcCounters(counter, tuple, timestamp);
342 updateTimeline(tuple, resultDiff);
343
344 return resultDiff;
345 }
346
347 protected Diff<Timestamp> putLazy(final Tuple tuple, final Timestamp timestamp) {
348 final CumulativeCounter counter = getCounter(tuple, timestamp);
349 counter.diff += 1;
350 // before the INSERT timestamp, no change at all
351 // it cannot happen that those became positive in this round
352 addFoldingState(tuple, new FoldingState(+1), timestamp);
353 return EMPTY_DIFF;
354 }
355
356 protected Diff<Timestamp> removeEager(final Tuple tuple, final Timestamp timestamp) {
357 final Diff<Timestamp> resultDiff = new Diff<>();
358 final CumulativeCounter counter = getCounter(tuple, timestamp);
359 --counter.diff;
360
361 // before the DELETE timestamp, no change at all
362 // it cannot happen that those became zero in this round
363 SignChange signChangeAtPrevious = SignChange.IRRELEVANT;
364
365 final NavigableMap<Timestamp, CumulativeCounter> nextCounters = this.counters.get(tuple).tailMap(timestamp,
366 true);
367 for (final Entry<Timestamp, CumulativeCounter> currentEntry : nextCounters.entrySet()) {
368 final Timestamp currentTimestamp = currentEntry.getKey();
369 final CumulativeCounter currentCounter = currentEntry.getValue();
370 --currentCounter.cumulative;
371 signChangeAtPrevious = computeDiffsEager(Direction.DELETE, currentCounter, signChangeAtPrevious,
372 currentTimestamp, resultDiff);
373 }
374
375 gcCounters(counter, tuple, timestamp);
376 updateTimeline(tuple, resultDiff);
377
378 return resultDiff;
379 }
380
381 protected Diff<Timestamp> removeLazy(final Tuple tuple, final Timestamp timestamp) {
382 final CumulativeCounter counter = getCounter(tuple, timestamp);
383 counter.diff -= 1;
384 // before the DELETE timestamp, no change at all
385 // it cannot happen that those became zero in this round
386 addFoldingState(tuple, new FoldingState(-1), timestamp);
387 return EMPTY_DIFF;
388 }
389
390 /**
391 * Updates and garbage collects the timeline of the given tuple based on the given timeline diff.
392 */
393 protected void updateTimeline(final Tuple tuple, final Diff<Timestamp> diff) {
394 if (!diff.isEmpty()) {
395 this.timelines.compute(tuple, (k, oldTimeline) -> {
396 this.presentAtInfinity.remove(tuple);
397 final Timeline<Timestamp> timeline = oldTimeline == null ? Timelines.createFrom(diff)
398 : oldTimeline.mergeAdditive(diff);
399 if (timeline.isPresentAtInfinity()) {
400 this.presentAtInfinity.add(tuple);
401 }
402 if (timeline.isEmpty()) {
403 return null;
404 } else {
405 return timeline;
406 }
407 });
408 }
409 }
410
411 /**
412 * @since 2.8
413 */
414 public Set<Tuple> getTuplesAtInfinity() {
415 return this.presentAtInfinity;
416 }
417
418 /**
419 * Returns the number of tuples that are present at the moment 'infinity'.
420 */
421 public int getCountAtInfinity() {
422 return this.presentAtInfinity.size();
423 }
424
425 /**
426 * Returns true if the given tuple is present at the moment 'infinity'.
427 */
428 public boolean isPresentAtInfinity(final Tuple tuple) {
429 final Timeline<Timestamp> timeline = this.timelines.get(tuple);
430 if (timeline == null) {
431 return false;
432 } else {
433 return timeline.isPresentAtInfinity();
434 }
435 }
436
437 public boolean isEmpty() {
438 return this.counters.isEmpty();
439 }
440
441 public int size() {
442 return this.counters.size();
443 }
444
445 public Set<Tuple> keySet() {
446 return this.counters.keySet();
447 }
448
449 public Map<Tuple, Timeline<Timestamp>> asMap() {
450 return this.timelines;
451 }
452
453 public Timeline<Timestamp> get(final ITuple tuple) {
454 return this.timelines.get(tuple);
455 }
456
457 @Override
458 public void clear() {
459 this.counters.clear();
460 this.timelines.clear();
461 if (this.foldingState != null) {
462 this.foldingState.clear();
463 }
464 }
465
466 public boolean containsKey(final ITuple tuple) {
467 return this.counters.containsKey(tuple);
468 }
469
470 @Override
471 public String toString() {
472 return this.counters + "\n" + this.timelines + "\n" + this.foldingState + "\n";
473 }
474
475 protected static final class CumulativeCounter {
476 protected int diff;
477 protected int cumulative;
478
479 protected CumulativeCounter(final int diff, final int cumulative) {
480 this.diff = diff;
481 this.cumulative = cumulative;
482 }
483
484 @Override
485 public String toString() {
486 return "{diff=" + this.diff + ", cumulative=" + this.cumulative + "}";
487 }
488
489 }
490
491 protected static final class FoldingState {
492 protected final int diff;
493
494 protected FoldingState(final int diff) {
495 this.diff = diff;
496 }
497
498 @Override
499 public String toString() {
500 return "{diff=" + this.diff + "}";
501 }
502
503 /**
504 * The returned result will never be null, even if the resulting diff is zero.
505 */
506 public FoldingState merge(final FoldingState that) {
507 Preconditions.checkArgument(that != null);
508 return new FoldingState(this.diff + that.diff);
509 }
510
511 }
512
513 protected enum SignChange {
514 BECAME_POSITIVE, BECAME_ZERO, IRRELEVANT;
515 }
516
517}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/MaskedResumable.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/MaskedResumable.java
new file mode 100644
index 00000000..ea70e61d
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/MaskedResumable.java
@@ -0,0 +1,36 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util.resumable;
10
11import java.util.Map;
12
13import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
14import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
15
16/**
17 * A masked {@link Resumable} implementation, which maintains lazy folding per tuple signature.
18 *
19 * @author Tamas Szabo
20 * @since 2.4
21 */
22public interface MaskedResumable<Timestamp extends Comparable<Timestamp>> extends Resumable<Timestamp> {
23
24 /**
25 * When called, the folding of the state shall be resumed at the given timestamp. The resumable is expected to
26 * do a folding step at the given timestamp only. Afterwards, folding shall be interrupted, even if there is more
27 * folding to do towards higher timestamps.
28 */
29 public Map<Tuple, Map<Tuple, Diff<Timestamp>>> resumeAt(final Timestamp timestamp);
30
31 /**
32 * Returns the set of signatures for which lazy folding shall be resumed at the next timestamp.
33 */
34 public Iterable<Tuple> getResumableSignatures();
35
36}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/Resumable.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/Resumable.java
new file mode 100644
index 00000000..2861df20
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/Resumable.java
@@ -0,0 +1,27 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util.resumable;
10
11/**
12 * A resumable lazily folds its state towards higher timestamps. Folding shall be done in the increasing order of
13 * timestamps, and it shall be interrupted after each step. The resumable can then be instructed to resume the folding,
14 * one step at a time.
15 *
16 * @author Tamas Szabo
17 * @since 2.4
18 */
19public interface Resumable<Timestamp extends Comparable<Timestamp>> {
20
21 /**
22 * Returns the smallest timestamp where lazy folding shall be resumed, or null if there is no more folding to do in this
23 * resumable.
24 */
25 public Timestamp getResumableTimestamp();
26
27}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/UnmaskedResumable.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/UnmaskedResumable.java
new file mode 100644
index 00000000..1671940b
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/resumable/UnmaskedResumable.java
@@ -0,0 +1,36 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Tamas Szabo, Istvan Rath and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util.resumable;
10
11import java.util.Map;
12
13import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
14import tools.refinery.viatra.runtime.matchers.util.timeline.Diff;
15
16/**
17 * A unmasked {@link Resumable} implementation, which maintains lazy folding without caring about tuple signatures.
18 *
19 * @author Tamas Szabo
20 * @since 2.4
21 */
22public interface UnmaskedResumable<Timestamp extends Comparable<Timestamp>> extends Resumable<Timestamp> {
23
24 /**
25 * When called, the folding of the state shall be resumed at the given timestamp. The resumable is expected to
26 * do a folding step at the given timestamp only. Afterwards, folding shall be interrupted, even if there is more
27 * folding to do towards higher timestamps.
28 */
29 public Map<Tuple, Diff<Timestamp>> resumeAt(final Timestamp timestamp);
30
31 /**
32 * Returns the set of tuples for which lazy folding shall be resumed at the next timestamp.
33 */
34 public Iterable<Tuple> getResumableTuples();
35
36}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/CompactTimeline.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/CompactTimeline.java
new file mode 100644
index 00000000..0532d094
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/CompactTimeline.java
@@ -0,0 +1,111 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, itemis AG, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util.timeline;
10
11import java.util.ArrayList;
12import java.util.Iterator;
13import java.util.List;
14
15import tools.refinery.viatra.runtime.matchers.util.Direction;
16import tools.refinery.viatra.runtime.matchers.util.Signed;
17
18/**
19 * A compact timeline may cosist of an arbitrary amount of moments.
20 * It is backed by an {@link ArrayList}.
21 *
22 * @author Tamas Szabo
23 * @since 2.4
24 */
25public class CompactTimeline<Timestamp extends Comparable<Timestamp>> extends Timeline<Timestamp> {
26
27 protected final List<Timestamp> elements;
28
29 CompactTimeline() {
30 this.elements = new ArrayList<>();
31 }
32
33 CompactTimeline(final Timestamp timestamp) {
34 this();
35 this.elements.add(timestamp);
36 }
37
38 CompactTimeline(final List<Timestamp> timestamps) {
39 this.elements = new ArrayList<>(timestamps.size());
40 this.elements.addAll(timestamps);
41 }
42
43 CompactTimeline(final Diff<Timestamp> diff) {
44 this.elements = new ArrayList<>(diff.size());
45 Direction expected = Direction.INSERT;
46 for (Signed<Timestamp> signed : diff) {
47 if (!expected.equals(signed.getDirection())) {
48 throw new IllegalStateException(String.format("Expected direction (%s) constraint violated! %s @%s",
49 expected, diff, signed.getPayload()));
50 }
51 this.elements.add(signed.getPayload());
52 expected = expected.opposite();
53 }
54 }
55
56 @Override
57 public Signed<Timestamp> getSigned(final int index) {
58 final Direction direction = index % 2 == 0 ? Direction.INSERT : Direction.DELETE;
59 return new Signed<>(direction, this.getUnsigned(index));
60 }
61
62 @Override
63 public Timestamp getUnsigned(final int index) {
64 if (this.elements.size() <= index) {
65 throw new IllegalArgumentException(
66 "Timeline size (" + this.size() + ") is smaller than requested index " + index + "!");
67 } else {
68 return this.elements.get(index);
69 }
70 }
71
72 @Override
73 public int size() {
74 return this.elements.size();
75 }
76
77 @Override
78 public boolean isPresentAtInfinity() {
79 // if it has an odd length, then it ends with "INSERT"
80 return this.size() % 2 == 1;
81 }
82
83 @Override
84 public Iterable<Signed<Timestamp>> asChangeSequence() {
85 Iterable<Timestamp> outer = this.elements;
86 return () -> {
87 final Iterator<Timestamp> itr = outer.iterator();
88 return new Iterator<Signed<Timestamp>>() {
89 Direction direction = Direction.INSERT;
90
91 @Override
92 public boolean hasNext() {
93 return itr.hasNext();
94 }
95
96 @Override
97 public Signed<Timestamp> next() {
98 final Signed<Timestamp> result = new Signed<Timestamp>(direction, itr.next());
99 direction = direction.opposite();
100 return result;
101 }
102 };
103 };
104 }
105
106 @Override
107 public boolean isEmpty() {
108 return this.elements.isEmpty();
109 }
110
111}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Diff.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Diff.java
new file mode 100644
index 00000000..cec6049e
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Diff.java
@@ -0,0 +1,55 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, itemis AG, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util.timeline;
10
11import java.util.ArrayList;
12
13import tools.refinery.viatra.runtime.matchers.util.Signed;
14
15/**
16 * The description of a delta that specifies how a {@link Timeline} changes. It consists of {@link Signed} timestamps that
17 * depict the moments of insertions and deletions on the timeline.
18 *
19 * @author Tamas Szabo
20 * @since 2.4
21 * @param <Timestamp>
22 * the type representing the timestamps
23 */
24public class Diff<Timestamp extends Comparable<Timestamp>> extends ArrayList<Signed<Timestamp>> {
25
26 private static final long serialVersionUID = 3853460426655994160L;
27
28 public Diff() {
29
30 }
31
32 public void appendWithCancellation(Signed<Timestamp> item) {
33 if (this.isEmpty()) {
34 this.add(item);
35 } else {
36 final Signed<Timestamp> last = this.get(this.size() - 1);
37 final int lastMinusItem = last.getPayload().compareTo(item.getPayload());
38 if (lastMinusItem == 0) {
39 if (last.getDirection() != item.getDirection()) {
40 // cancellation
41 this.remove(this.size() - 1);
42 } else {
43 throw new IllegalStateException(
44 "Trying to insert or delete for the second time at the same timestamp! " + item);
45 }
46 } else if (lastMinusItem > 0) {
47 throw new IllegalStateException(
48 "Trying to append a timestamp that is smaller than the last one! " + last + " " + item);
49 } else {
50 this.add(item);
51 }
52 }
53 }
54
55} \ No newline at end of file
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/SingletonTimeline.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/SingletonTimeline.java
new file mode 100644
index 00000000..526a95f5
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/SingletonTimeline.java
@@ -0,0 +1,73 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, itemis AG, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util.timeline;
10
11import java.util.Collections;
12
13import tools.refinery.viatra.runtime.matchers.util.Direction;
14import tools.refinery.viatra.runtime.matchers.util.Signed;
15
16/**
17 * A timeline which solely consists of one timestamp value, representing a single insertion. Intuitively, a singleton
18 * timeline always represents a bump which starts at the given timestamp and lasts till plus infinity.
19 *
20 * @author Tamas Szabo
21 * @since 2.4
22 */
23public class SingletonTimeline<Timestamp extends Comparable<Timestamp>> extends Timeline<Timestamp> {
24
25 protected final Timestamp start;
26
27 SingletonTimeline(final Timestamp timestamp) {
28 this.start = timestamp;
29 }
30
31 SingletonTimeline(final Diff<Timestamp> diff) {
32 if (diff.size() != 1 || diff.get(0).getDirection() == Direction.DELETE) {
33 throw new IllegalArgumentException("There is only a single (insert) timestamp in the singleton timestamp!");
34 } else {
35 this.start = diff.get(0).getPayload();
36 }
37 }
38
39 @Override
40 public Signed<Timestamp> getSigned(final int index) {
41 return new Signed<>(Direction.INSERT, this.getUnsigned(index));
42 }
43
44 @Override
45 public Timestamp getUnsigned(final int index) {
46 if (index != 0) {
47 throw new IllegalArgumentException("There is only a single (insert) timestamp in the singleton timestamp!");
48 } else {
49 return this.start;
50 }
51 }
52
53 @Override
54 public int size() {
55 return 1;
56 }
57
58 @Override
59 public boolean isPresentAtInfinity() {
60 return true;
61 }
62
63 @Override
64 public Iterable<Signed<Timestamp>> asChangeSequence() {
65 return Collections.singletonList(this.getSigned(0));
66 }
67
68 @Override
69 public boolean isEmpty() {
70 return false;
71 }
72
73}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timeline.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timeline.java
new file mode 100644
index 00000000..9214536c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timeline.java
@@ -0,0 +1,146 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, itemis AG, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util.timeline;
10
11import java.util.ArrayList;
12import java.util.Iterator;
13import java.util.List;
14
15import tools.refinery.viatra.runtime.matchers.util.Direction;
16import tools.refinery.viatra.runtime.matchers.util.Signed;
17
18/**
19 * A timeline describes the life cycle of a piece of data (typically a tuple in a relation) as a sequence of moments.
20 * Even moments represent appearances, odd moments represent disappearances. A timeline is immutable, once created, it
21 * is not possible to extend it with further moments.
22 *
23 * @author Tamas Szabo
24 * @since 2.4
25 */
26public abstract class Timeline<Timestamp extends Comparable<Timestamp>> {
27
28 public abstract Iterable<Signed<Timestamp>> asChangeSequence();
29
30 public abstract boolean isPresentAtInfinity();
31
32 public abstract boolean isEmpty();
33
34 public abstract int size();
35
36 public abstract Signed<Timestamp> getSigned(final int index);
37
38 public abstract Timestamp getUnsigned(final int index);
39
40 public Timeline<Timestamp> mergeMultiplicative(final Timeline<Timestamp> that) {
41 final List<Timestamp> result = new ArrayList<>();
42 int thisIdx = 0, thatIdx = 0;
43 Timestamp thisNext = thisIdx < this.size() ? this.getUnsigned(thisIdx) : null;
44 Timestamp thatNext = thatIdx < that.size() ? that.getUnsigned(thatIdx) : null;
45
46 while (thisNext != null || thatNext != null) {
47 int thisMinusThat = 0;
48 if (thisNext != null && thatNext != null) {
49 thisMinusThat = thisNext.compareTo(thatNext);
50 }
51 if (thisNext == null || thisMinusThat > 0) {
52 if (thisIdx % 2 == 1) {
53 result.add(thatNext);
54 }
55 thatIdx++;
56 thatNext = thatIdx < that.size() ? that.getUnsigned(thatIdx) : null;
57 } else if (thatNext == null || thisMinusThat < 0) {
58 if (thatIdx % 2 == 1) {
59 result.add(thisNext);
60 }
61 thisIdx++;
62 thisNext = thisIdx < this.size() ? this.getUnsigned(thisIdx) : null;
63 } else {
64 if (thisIdx % 2 == thatIdx % 2) {
65 result.add(thisNext);
66 }
67 thisIdx++;
68 thatIdx++;
69 thatNext = thatIdx < that.size() ? that.getUnsigned(thatIdx) : null;
70 thisNext = thisIdx < this.size() ? this.getUnsigned(thisIdx) : null;
71 }
72 }
73
74 return Timelines.createFrom(result);
75 }
76
77 /**
78 * Merges this timeline with the given timestamp diff. The expectation is that the resulting timeline starts with an
79 * insertion. The logic is similar to a merge sort; we iterate side-by-side over the timeline and the diff. During
80 * the merge, cancellation can happen if at the same timestamp we observe different signs at the corresponding
81 * timeline and diff elements.
82 */
83 public Timeline<Timestamp> mergeAdditive(final Diff<Timestamp> diff) {
84 final Iterator<Signed<Timestamp>> thisItr = this.asChangeSequence().iterator();
85 final Iterator<Signed<Timestamp>> diffItr = diff.iterator();
86 final List<Timestamp> result = new ArrayList<>();
87 Direction expected = Direction.INSERT;
88 Signed<Timestamp> thisNext = thisItr.hasNext() ? thisItr.next() : null;
89 Signed<Timestamp> diffNext = diffItr.hasNext() ? diffItr.next() : null;
90
91 while (thisNext != null || diffNext != null) {
92 int thisMinusDiff = 0;
93 if (thisNext != null && diffNext != null) {
94 thisMinusDiff = thisNext.getPayload().compareTo(diffNext.getPayload());
95 }
96
97 if (thisNext == null || thisMinusDiff > 0) {
98 if (!expected.equals(diffNext.getDirection())) {
99 throw new IllegalStateException(
100 String.format("Expected direction (%s) constraint violated! %s %s @%s", expected, this,
101 diff, diffNext.getPayload()));
102 }
103 result.add(diffNext.getPayload());
104 diffNext = diffItr.hasNext() ? diffItr.next() : null;
105 expected = expected.opposite();
106 } else if (diffNext == null || thisMinusDiff < 0) {
107 if (!expected.equals(thisNext.getDirection())) {
108 throw new IllegalStateException(
109 String.format("Expected direction (%s) constraint violated! %s %s @%s", expected, this,
110 diff, thisNext.getPayload()));
111 }
112 result.add(thisNext.getPayload());
113 thisNext = thisItr.hasNext() ? thisItr.next() : null;
114 expected = expected.opposite();
115 } else {
116 // they cancel out each other
117 if (diffNext.getDirection().equals(thisNext.getDirection())) {
118 throw new IllegalStateException(String.format("Changes do not cancel out each other! %s %s @%s",
119 this, diff, thisNext.getPayload()));
120 }
121 diffNext = diffItr.hasNext() ? diffItr.next() : null;
122 thisNext = thisItr.hasNext() ? thisItr.next() : null;
123 }
124 }
125
126 return Timelines.createFrom(result);
127 }
128
129 @Override
130 public String toString() {
131 final StringBuilder builder = new StringBuilder();
132 builder.append("[");
133 boolean first = true;
134 for (final Signed<Timestamp> element : this.asChangeSequence()) {
135 if (first) {
136 first = false;
137 } else {
138 builder.append(", ");
139 }
140 builder.append(element.toString());
141 }
142 builder.append("]");
143 return builder.toString();
144 }
145
146}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timelines.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timelines.java
new file mode 100644
index 00000000..747fda15
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timelines.java
@@ -0,0 +1,46 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, itemis AG, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.util.timeline;
10
11import java.util.List;
12
13/**
14 * Utility class for creating {@link Timeline}s.
15 * @author Tamas Szabo
16 * @since 2.4
17 */
18public final class Timelines<Timestamp extends Comparable<Timestamp>> {
19
20 public static <Timestamp extends Comparable<Timestamp>> Timeline<Timestamp> createEmpty() {
21 return new CompactTimeline<Timestamp>();
22 }
23
24 public static <Timestamp extends Comparable<Timestamp>> Timeline<Timestamp> createFrom(
25 final Diff<Timestamp> diffs) {
26 if (diffs.size() == 1) {
27 return new SingletonTimeline<Timestamp>(diffs);
28 } else {
29 return new CompactTimeline<Timestamp>(diffs);
30 }
31 }
32
33 public static <Timestamp extends Comparable<Timestamp>> Timeline<Timestamp> createFrom(
34 final List<Timestamp> timestamps) {
35 if (timestamps.size() == 1) {
36 return new SingletonTimeline<Timestamp>(timestamps.get(0));
37 } else {
38 return new CompactTimeline<Timestamp>(timestamps);
39 }
40 }
41
42 public static <Timestamp extends Comparable<Timestamp>> Timeline<Timestamp> createFrom(final Timestamp timestamp) {
43 return new SingletonTimeline<Timestamp>(timestamp);
44 }
45
46}
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/util/ViatraQueryLoggingUtil.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/util/ViatraQueryLoggingUtil.java
new file mode 100644
index 00000000..229801f8
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/util/ViatraQueryLoggingUtil.java
@@ -0,0 +1,72 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2013, 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.util;
10
11import org.apache.log4j.Logger;
12import tools.refinery.viatra.runtime.matchers.util.Preconditions;
13
14/**
15 * Centralized logger of the VIATRA Query runtime.
16 * @author Bergmann Gabor
17 *
18 */
19public class ViatraQueryLoggingUtil {
20
21 private ViatraQueryLoggingUtil() {/*Utility class constructor*/}
22
23 private static Logger externalLogger;
24
25 public static void setExternalLogger(Logger externalLogger) {
26 Preconditions.checkArgument(externalLogger != null, "Must not set up null logger");
27 ViatraQueryLoggingUtil.externalLogger = externalLogger;
28 }
29 /**
30 * Provides a static default logger.
31 */
32 public static Logger getDefaultLogger() {
33 if (defaultRuntimeLogger == null) {
34 Logger parentLogger = externalLogger;
35 if (parentLogger == null) {
36 defaultRuntimeLogger = Logger.getLogger("org.eclipse.viatra");
37 } else {
38 defaultRuntimeLogger = Logger.getLogger(parentLogger.getName() + ".runtime");
39 }
40 if (defaultRuntimeLogger == null)
41 throw new AssertionError("Configuration error: unable to create default VIATRA Query runtime logger.");
42 }
43
44 return defaultRuntimeLogger;
45 }
46
47 private static String getLoggerClassname(Class<?> clazz) {
48 return clazz.getName().startsWith(getDefaultLogger().getName())
49 ? clazz.getName()
50 : getDefaultLogger().getName() + "." + clazz.getName();
51 }
52
53 /**
54 * Provides a class-specific logger that also stores the global logger settings of the VIATRA Query runtime
55 * @param clazz
56 */
57 public static Logger getLogger(Class<?> clazz) {
58 return Logger.getLogger(getLoggerClassname(clazz));
59 }
60
61 /**
62 * Provides a named logger that also stores the global logger settings of the VIATRA Query runtime
63 * @param clazz
64 * @param name a non-empty name to append to the class names
65 * @since 2.5
66 */
67 public static Logger getLogger(Class<?> clazz, String name) {
68 return Logger.getLogger(getLoggerClassname(clazz) + '.' + name);
69 }
70
71 private static Logger defaultRuntimeLogger;
72}