From 8d2d6359f3b47b36075ea5aad8b522c094f5a71c Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Thu, 9 Feb 2023 16:52:43 +0100 Subject: refactor: Atom -> Literal naming convention --- .../query/viatra/ViatraModelQueryBuilder.java | 14 +- .../internal/ViatraModelQueryAdapterImpl.java | 6 +- .../internal/ViatraModelQueryBuilderImpl.java | 16 +- .../internal/ViatraModelQueryStoreAdapterImpl.java | 10 +- .../query/viatra/internal/pquery/DNF2PQuery.java | 223 --------------------- .../query/viatra/internal/pquery/Dnf2PQuery.java | 223 +++++++++++++++++++++ .../refinery/store/query/viatra/QueryTest.java | 155 +++++++------- .../store/query/viatra/QueryTransactionTest.java | 8 +- .../main/java/tools/refinery/store/query/DNF.java | 169 ---------------- .../java/tools/refinery/store/query/DNFAnd.java | 9 - .../java/tools/refinery/store/query/DNFUtils.java | 19 -- .../main/java/tools/refinery/store/query/Dnf.java | 169 ++++++++++++++++ .../java/tools/refinery/store/query/DnfClause.java | 9 + .../java/tools/refinery/store/query/DnfUtils.java | 19 ++ .../refinery/store/query/ModelQueryAdapter.java | 2 +- .../refinery/store/query/ModelQueryBuilder.java | 6 +- .../store/query/ModelQueryStoreAdapter.java | 2 +- .../java/tools/refinery/store/query/Variable.java | 2 +- .../tools/refinery/store/query/atom/CallAtom.java | 80 -------- .../refinery/store/query/atom/CallPolarity.java | 28 --- .../refinery/store/query/atom/ConstantAtom.java | 12 -- .../tools/refinery/store/query/atom/DNFAtom.java | 9 - .../refinery/store/query/atom/DNFCallAtom.java | 32 --- .../refinery/store/query/atom/EquivalenceAtom.java | 17 -- .../tools/refinery/store/query/atom/Modality.java | 22 -- .../store/query/atom/RelationViewAtom.java | 32 --- .../refinery/store/query/literal/CallLiteral.java | 60 ++++++ .../refinery/store/query/literal/CallPolarity.java | 28 +++ .../store/query/literal/ConstantLiteral.java | 12 ++ .../store/query/literal/DnfCallLiteral.java | 32 +++ .../store/query/literal/EquivalenceLiteral.java | 17 ++ .../refinery/store/query/literal/Literal.java | 9 + .../refinery/store/query/literal/Modality.java | 22 ++ .../store/query/literal/RelationViewLiteral.java | 32 +++ .../refinery/store/representation/Symbol.java | 6 - .../refinery/store/model/tests/ModelTest.java | 2 +- 36 files changed, 745 insertions(+), 768 deletions(-) delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/DNF2PQuery.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/Dnf2PQuery.java delete mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/DNF.java delete mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/DNFAnd.java delete mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/DNFUtils.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/Dnf.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/DnfClause.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/DnfUtils.java delete mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/atom/CallAtom.java delete mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/atom/CallPolarity.java delete mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/atom/ConstantAtom.java delete mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/atom/DNFAtom.java delete mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/atom/DNFCallAtom.java delete mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/atom/EquivalenceAtom.java delete mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/atom/Modality.java delete mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/atom/RelationViewAtom.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/literal/CallLiteral.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/literal/CallPolarity.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/literal/DnfCallLiteral.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/literal/Literal.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/literal/Modality.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/query/literal/RelationViewLiteral.java diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java index efc6146c..24aa52e2 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java @@ -4,7 +4,7 @@ import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions; import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory; import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; import tools.refinery.store.model.ModelStore; -import tools.refinery.store.query.DNF; +import tools.refinery.store.query.Dnf; import tools.refinery.store.query.ModelQueryBuilder; import java.util.Collection; @@ -23,25 +23,25 @@ public interface ViatraModelQueryBuilder extends ModelQueryBuilder { ViatraModelQueryBuilder searchBackend(IQueryBackendFactory queryBackendFactory); @Override - default ViatraModelQueryBuilder queries(DNF... queries) { + default ViatraModelQueryBuilder queries(Dnf... queries) { ModelQueryBuilder.super.queries(queries); return this; } @Override - default ViatraModelQueryBuilder queries(Collection queries) { + default ViatraModelQueryBuilder queries(Collection queries) { ModelQueryBuilder.super.queries(queries); return this; } @Override - ViatraModelQueryBuilder query(DNF query); + ViatraModelQueryBuilder query(Dnf query); - ViatraModelQueryBuilder query(DNF query, QueryEvaluationHint queryEvaluationHint); + ViatraModelQueryBuilder query(Dnf query, QueryEvaluationHint queryEvaluationHint); - ViatraModelQueryBuilder computeHint(Function computeHint); + ViatraModelQueryBuilder computeHint(Function computeHint); - ViatraModelQueryBuilder hint(DNF dnf, QueryEvaluationHint queryEvaluationHint); + ViatraModelQueryBuilder hint(Dnf dnf, QueryEvaluationHint queryEvaluationHint); @Override ViatraModelQueryStoreAdapter createStoreAdapter(ModelStore store); diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java index 039f46fa..e5d8e2f6 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java @@ -7,7 +7,7 @@ import org.eclipse.viatra.query.runtime.internal.apiimpl.ViatraQueryEngineImpl; import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackend; import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory; import tools.refinery.store.model.Model; -import tools.refinery.store.query.DNF; +import tools.refinery.store.query.Dnf; import tools.refinery.store.query.ResultSet; import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; @@ -27,7 +27,7 @@ public class ViatraModelQueryAdapterImpl implements ViatraModelQueryAdapter { private final ViatraQueryEngineImpl queryEngine; private final MethodHandle setUpdatePropagationDelayedHandle; private final MethodHandle getQueryBackendsHandle; - private final Map resultSets; + private final Map resultSets; private boolean pendingChanges; ViatraModelQueryAdapterImpl(Model model, ViatraModelQueryStoreAdapterImpl storeAdapter) { @@ -95,7 +95,7 @@ public class ViatraModelQueryAdapterImpl implements ViatraModelQueryAdapter { } @Override - public ResultSet getResultSet(DNF query) { + public ResultSet getResultSet(Dnf query) { var resultSet = resultSets.get(query); if (resultSet == null) { throw new IllegalArgumentException("No matcher for query %s in model".formatted(query.name())); diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java index 9f1e55b1..af20033a 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java @@ -9,9 +9,9 @@ import org.eclipse.viatra.query.runtime.rete.matcher.ReteBackendFactory; import tools.refinery.store.adapter.AbstractModelAdapterBuilder; import tools.refinery.store.model.ModelStore; import tools.refinery.store.model.ModelStoreBuilder; -import tools.refinery.store.query.DNF; +import tools.refinery.store.query.Dnf; import tools.refinery.store.query.viatra.ViatraModelQueryBuilder; -import tools.refinery.store.query.viatra.internal.pquery.DNF2PQuery; +import tools.refinery.store.query.viatra.internal.pquery.Dnf2PQuery; import tools.refinery.store.query.viatra.internal.pquery.RawPatternMatcher; import java.util.Collections; @@ -21,8 +21,8 @@ import java.util.function.Function; public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder implements ViatraModelQueryBuilder { private ViatraQueryEngineOptions.Builder engineOptionsBuilder; - private final DNF2PQuery dnf2PQuery = new DNF2PQuery(); - private final Map> querySpecifications = new LinkedHashMap<>(); + private final Dnf2PQuery dnf2PQuery = new Dnf2PQuery(); + private final Map> querySpecifications = new LinkedHashMap<>(); public ViatraModelQueryBuilderImpl(ModelStoreBuilder storeBuilder) { super(storeBuilder); @@ -63,7 +63,7 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp } @Override - public ViatraModelQueryBuilder query(DNF query) { + public ViatraModelQueryBuilder query(Dnf query) { if (querySpecifications.containsKey(query)) { throw new IllegalArgumentException("%s was already added to the query engine".formatted(query.name())); } @@ -73,20 +73,20 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp } @Override - public ViatraModelQueryBuilder query(DNF query, QueryEvaluationHint queryEvaluationHint) { + public ViatraModelQueryBuilder query(Dnf query, QueryEvaluationHint queryEvaluationHint) { query(query); hint(query, queryEvaluationHint); return this; } @Override - public ViatraModelQueryBuilder computeHint(Function computeHint) { + public ViatraModelQueryBuilder computeHint(Function computeHint) { dnf2PQuery.setComputeHint(computeHint); return this; } @Override - public ViatraModelQueryBuilder hint(DNF dnf, QueryEvaluationHint queryEvaluationHint) { + public ViatraModelQueryBuilder hint(Dnf dnf, QueryEvaluationHint queryEvaluationHint) { var pQuery = dnf2PQuery.getAlreadyTranslated(dnf); if (pQuery == null) { throw new IllegalArgumentException( diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java index 394e407e..8323118b 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java @@ -5,7 +5,7 @@ import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions; import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; import tools.refinery.store.model.Model; import tools.refinery.store.model.ModelStore; -import tools.refinery.store.query.DNF; +import tools.refinery.store.query.Dnf; import tools.refinery.store.query.viatra.ViatraModelQueryStoreAdapter; import tools.refinery.store.query.viatra.internal.pquery.RawPatternMatcher; import tools.refinery.store.query.view.AnyRelationView; @@ -17,11 +17,11 @@ public class ViatraModelQueryStoreAdapterImpl implements ViatraModelQueryStoreAd private final ModelStore store; private final ViatraQueryEngineOptions engineOptions; private final Map inputKeys; - private final Map> querySpecifications; + private final Map> querySpecifications; ViatraModelQueryStoreAdapterImpl(ModelStore store, ViatraQueryEngineOptions engineOptions, Map inputKeys, - Map> querySpecifications) { + Map> querySpecifications) { this.store = store; this.engineOptions = engineOptions; this.inputKeys = inputKeys; @@ -42,11 +42,11 @@ public class ViatraModelQueryStoreAdapterImpl implements ViatraModelQueryStoreAd } @Override - public Collection getQueries() { + public Collection getQueries() { return querySpecifications.keySet(); } - Map> getQuerySpecifications() { + Map> getQuerySpecifications() { return querySpecifications; } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/DNF2PQuery.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/DNF2PQuery.java deleted file mode 100644 index 60f1bcae..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/DNF2PQuery.java +++ /dev/null @@ -1,223 +0,0 @@ -package tools.refinery.store.query.viatra.internal.pquery; - -import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; -import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; -import org.eclipse.viatra.query.runtime.matchers.psystem.PBody; -import org.eclipse.viatra.query.runtime.matchers.psystem.PVariable; -import org.eclipse.viatra.query.runtime.matchers.psystem.annotations.PAnnotation; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Equality; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.ExportedParameter; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Inequality; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.NegativePatternCall; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.BinaryTransitiveClosure; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.ConstantValue; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.PositivePatternCall; -import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.TypeConstraint; -import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; -import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PVisibility; -import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; -import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; -import tools.refinery.store.query.DNF; -import tools.refinery.store.query.DNFAnd; -import tools.refinery.store.query.DNFUtils; -import tools.refinery.store.query.Variable; -import tools.refinery.store.query.atom.*; -import tools.refinery.store.query.view.AnyRelationView; - -import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; - -public class DNF2PQuery { - private static final Object P_CONSTRAINT_LOCK = new Object(); - - private final Set translating = new LinkedHashSet<>(); - - private final Map dnf2PQueryMap = new HashMap<>(); - - private final Map view2WrapperMap = new LinkedHashMap<>(); - - private final Map view2EmbeddedMap = new HashMap<>(); - - private Function computeHint = dnf -> new QueryEvaluationHint(null, - QueryEvaluationHint.BackendRequirement.UNSPECIFIED); - - public void setComputeHint(Function computeHint) { - this.computeHint = computeHint; - } - - public RawPQuery translate(DNF dnfQuery) { - if (translating.contains(dnfQuery)) { - var path = translating.stream().map(DNF::name).collect(Collectors.joining(" -> ")); - throw new IllegalStateException("Circular reference %s -> %s detected".formatted(path, - dnfQuery.name())); - } - // We can't use computeIfAbsent here, because translating referenced queries calls this method in a reentrant - // way, which would cause a ConcurrentModificationException with computeIfAbsent. - var pQuery = dnf2PQueryMap.get(dnfQuery); - if (pQuery == null) { - translating.add(dnfQuery); - try { - pQuery = doTranslate(dnfQuery); - dnf2PQueryMap.put(dnfQuery, pQuery); - } finally { - translating.remove(dnfQuery); - } - } - return pQuery; - } - - public Map getRelationViews() { - return Collections.unmodifiableMap(view2WrapperMap); - } - - public RawPQuery getAlreadyTranslated(DNF dnfQuery) { - return dnf2PQueryMap.get(dnfQuery); - } - - private RawPQuery doTranslate(DNF dnfQuery) { - var pQuery = new RawPQuery(dnfQuery.getUniqueName()); - pQuery.setEvaluationHints(computeHint.apply(dnfQuery)); - - Map parameters = new HashMap<>(); - for (Variable variable : dnfQuery.getParameters()) { - parameters.put(variable, new PParameter(variable.getUniqueName())); - } - - List parameterList = new ArrayList<>(); - for (var param : dnfQuery.getParameters()) { - parameterList.add(parameters.get(param)); - } - pQuery.setParameters(parameterList); - - for (var functionalDependency : dnfQuery.getFunctionalDependencies()) { - var functionalDependencyAnnotation = new PAnnotation("FunctionalDependency"); - for (var forEachVariable : functionalDependency.forEach()) { - functionalDependencyAnnotation.addAttribute("forEach", forEachVariable.getUniqueName()); - } - for (var uniqueVariable : functionalDependency.unique()) { - functionalDependencyAnnotation.addAttribute("unique", uniqueVariable.getUniqueName()); - } - pQuery.addAnnotation(functionalDependencyAnnotation); - } - - // The constructor of {@link org.eclipse.viatra.query.runtime.matchers.psystem.BasePConstraint} mutates - // global static state (nextID) without locking. Therefore, we need to synchronize before creating - // any query constraints to avoid a data race. - synchronized (P_CONSTRAINT_LOCK) { - for (DNFAnd clause : dnfQuery.getClauses()) { - PBody body = new PBody(pQuery); - List symbolicParameters = new ArrayList<>(); - for (var param : dnfQuery.getParameters()) { - PVariable pVar = body.getOrCreateVariableByName(param.getUniqueName()); - symbolicParameters.add(new ExportedParameter(body, pVar, parameters.get(param))); - } - body.setSymbolicParameters(symbolicParameters); - pQuery.addBody(body); - for (DNFAtom constraint : clause.constraints()) { - translateDNFAtom(constraint, body); - } - } - } - - return pQuery; - } - - private void translateDNFAtom(DNFAtom constraint, PBody body) { - if (constraint instanceof EquivalenceAtom equivalenceAtom) { - translateEquivalenceAtom(equivalenceAtom, body); - } else if (constraint instanceof RelationViewAtom relationViewAtom) { - translateRelationViewAtom(relationViewAtom, body); - } else if (constraint instanceof DNFCallAtom callAtom) { - translateCallAtom(callAtom, body); - } else if (constraint instanceof ConstantAtom constantAtom) { - translateConstantAtom(constantAtom, body); - } else { - throw new IllegalArgumentException("Unknown constraint: " + constraint.toString()); - } - } - - private void translateEquivalenceAtom(EquivalenceAtom equivalence, PBody body) { - PVariable varSource = body.getOrCreateVariableByName(equivalence.left().getUniqueName()); - PVariable varTarget = body.getOrCreateVariableByName(equivalence.right().getUniqueName()); - if (equivalence.positive()) { - new Equality(body, varSource, varTarget); - } else { - new Inequality(body, varSource, varTarget); - } - } - - private void translateRelationViewAtom(RelationViewAtom relationViewAtom, PBody body) { - var substitution = translateSubstitution(relationViewAtom.getSubstitution(), body); - var polarity = relationViewAtom.getPolarity(); - var relationView = relationViewAtom.getTarget(); - if (polarity == CallPolarity.POSITIVE) { - new TypeConstraint(body, substitution, wrapView(relationView)); - } else { - var embeddedPQuery = translateEmbeddedRelationViewPQuery(relationView); - switch (polarity) { - case TRANSITIVE -> new BinaryTransitiveClosure(body, substitution, embeddedPQuery); - case NEGATIVE -> new NegativePatternCall(body, substitution, embeddedPQuery); - default -> throw new IllegalArgumentException("Unknown polarity: " + polarity); - } - } - } - - private static Tuple translateSubstitution(List substitution, PBody body) { - int arity = substitution.size(); - Object[] variables = new Object[arity]; - for (int i = 0; i < arity; i++) { - var variable = substitution.get(i); - variables[i] = body.getOrCreateVariableByName(variable.getUniqueName()); - } - return Tuples.flatTupleOf(variables); - } - - private RawPQuery translateEmbeddedRelationViewPQuery(AnyRelationView relationView) { - return view2EmbeddedMap.computeIfAbsent(relationView, this::doTranslateEmbeddedRelationViewPQuery); - } - - private RawPQuery doTranslateEmbeddedRelationViewPQuery(AnyRelationView relationView) { - var embeddedPQuery = new RawPQuery(DNFUtils.generateUniqueName(relationView.name()), PVisibility.EMBEDDED); - var body = new PBody(embeddedPQuery); - int arity = relationView.arity(); - var parameters = new ArrayList(arity); - var arguments = new Object[arity]; - var symbolicParameters = new ArrayList(arity); - for (int i = 0; i < arity; i++) { - var parameterName = "p" + i; - var parameter = new PParameter(parameterName); - parameters.add(parameter); - var variable = body.getOrCreateVariableByName(parameterName); - arguments[i] = variable; - symbolicParameters.add(new ExportedParameter(body, variable, parameter)); - } - embeddedPQuery.setParameters(parameters); - body.setSymbolicParameters(symbolicParameters); - var argumentTuple = Tuples.flatTupleOf(arguments); - new TypeConstraint(body, argumentTuple, wrapView(relationView)); - embeddedPQuery.addBody(body); - return embeddedPQuery; - } - - private RelationViewWrapper wrapView(AnyRelationView relationView) { - return view2WrapperMap.computeIfAbsent(relationView, RelationViewWrapper::new); - } - - private void translateCallAtom(DNFCallAtom callAtom, PBody body) { - var variablesTuple = translateSubstitution(callAtom.getSubstitution(), body); - var translatedReferred = translate(callAtom.getTarget()); - var polarity = callAtom.getPolarity(); - switch (polarity) { - case POSITIVE -> new PositivePatternCall(body, variablesTuple, translatedReferred); - case TRANSITIVE -> new BinaryTransitiveClosure(body, variablesTuple, translatedReferred); - case NEGATIVE -> new NegativePatternCall(body, variablesTuple, translatedReferred); - default -> throw new IllegalArgumentException("Unknown polarity: " + polarity); - } - } - - private void translateConstantAtom(ConstantAtom constantAtom, PBody body) { - var variable = body.getOrCreateVariableByName(constantAtom.variable().getUniqueName()); - new ConstantValue(body, variable, constantAtom.nodeId()); - } -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/Dnf2PQuery.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/Dnf2PQuery.java new file mode 100644 index 00000000..02e26bde --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/Dnf2PQuery.java @@ -0,0 +1,223 @@ +package tools.refinery.store.query.viatra.internal.pquery; + +import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; +import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; +import org.eclipse.viatra.query.runtime.matchers.psystem.PBody; +import org.eclipse.viatra.query.runtime.matchers.psystem.PVariable; +import org.eclipse.viatra.query.runtime.matchers.psystem.annotations.PAnnotation; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Equality; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.ExportedParameter; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Inequality; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.NegativePatternCall; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.BinaryTransitiveClosure; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.ConstantValue; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.PositivePatternCall; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.TypeConstraint; +import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; +import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PVisibility; +import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; +import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; +import tools.refinery.store.query.Dnf; +import tools.refinery.store.query.DnfClause; +import tools.refinery.store.query.DnfUtils; +import tools.refinery.store.query.Variable; +import tools.refinery.store.query.literal.*; +import tools.refinery.store.query.view.AnyRelationView; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class Dnf2PQuery { + private static final Object P_CONSTRAINT_LOCK = new Object(); + + private final Set translating = new LinkedHashSet<>(); + + private final Map dnf2PQueryMap = new HashMap<>(); + + private final Map view2WrapperMap = new LinkedHashMap<>(); + + private final Map view2EmbeddedMap = new HashMap<>(); + + private Function computeHint = dnf -> new QueryEvaluationHint(null, + QueryEvaluationHint.BackendRequirement.UNSPECIFIED); + + public void setComputeHint(Function computeHint) { + this.computeHint = computeHint; + } + + public RawPQuery translate(Dnf dnfQuery) { + if (translating.contains(dnfQuery)) { + var path = translating.stream().map(Dnf::name).collect(Collectors.joining(" -> ")); + throw new IllegalStateException("Circular reference %s -> %s detected".formatted(path, + dnfQuery.name())); + } + // We can't use computeIfAbsent here, because translating referenced queries calls this method in a reentrant + // way, which would cause a ConcurrentModificationException with computeIfAbsent. + var pQuery = dnf2PQueryMap.get(dnfQuery); + if (pQuery == null) { + translating.add(dnfQuery); + try { + pQuery = doTranslate(dnfQuery); + dnf2PQueryMap.put(dnfQuery, pQuery); + } finally { + translating.remove(dnfQuery); + } + } + return pQuery; + } + + public Map getRelationViews() { + return Collections.unmodifiableMap(view2WrapperMap); + } + + public RawPQuery getAlreadyTranslated(Dnf dnfQuery) { + return dnf2PQueryMap.get(dnfQuery); + } + + private RawPQuery doTranslate(Dnf dnfQuery) { + var pQuery = new RawPQuery(dnfQuery.getUniqueName()); + pQuery.setEvaluationHints(computeHint.apply(dnfQuery)); + + Map parameters = new HashMap<>(); + for (Variable variable : dnfQuery.getParameters()) { + parameters.put(variable, new PParameter(variable.getUniqueName())); + } + + List parameterList = new ArrayList<>(); + for (var param : dnfQuery.getParameters()) { + parameterList.add(parameters.get(param)); + } + pQuery.setParameters(parameterList); + + for (var functionalDependency : dnfQuery.getFunctionalDependencies()) { + var functionalDependencyAnnotation = new PAnnotation("FunctionalDependency"); + for (var forEachVariable : functionalDependency.forEach()) { + functionalDependencyAnnotation.addAttribute("forEach", forEachVariable.getUniqueName()); + } + for (var uniqueVariable : functionalDependency.unique()) { + functionalDependencyAnnotation.addAttribute("unique", uniqueVariable.getUniqueName()); + } + pQuery.addAnnotation(functionalDependencyAnnotation); + } + + // The constructor of {@link org.eclipse.viatra.query.runtime.matchers.psystem.BasePConstraint} mutates + // global static state (nextID) without locking. Therefore, we need to synchronize before creating + // any query literals to avoid a data race. + synchronized (P_CONSTRAINT_LOCK) { + for (DnfClause clause : dnfQuery.getClauses()) { + PBody body = new PBody(pQuery); + List symbolicParameters = new ArrayList<>(); + for (var param : dnfQuery.getParameters()) { + PVariable pVar = body.getOrCreateVariableByName(param.getUniqueName()); + symbolicParameters.add(new ExportedParameter(body, pVar, parameters.get(param))); + } + body.setSymbolicParameters(symbolicParameters); + pQuery.addBody(body); + for (Literal literal : clause.literals()) { + translateLiteral(literal, body); + } + } + } + + return pQuery; + } + + private void translateLiteral(Literal literal, PBody body) { + if (literal instanceof EquivalenceLiteral equivalenceLiteral) { + translateEquivalenceLiteral(equivalenceLiteral, body); + } else if (literal instanceof RelationViewLiteral relationViewLiteral) { + translateRelationViewLiteral(relationViewLiteral, body); + } else if (literal instanceof DnfCallLiteral dnfCallLiteral) { + translateDnfCallLiteral(dnfCallLiteral, body); + } else if (literal instanceof ConstantLiteral constantLiteral) { + translateConstantLiteral(constantLiteral, body); + } else { + throw new IllegalArgumentException("Unknown literal: " + literal.toString()); + } + } + + private void translateEquivalenceLiteral(EquivalenceLiteral equivalenceLiteral, PBody body) { + PVariable varSource = body.getOrCreateVariableByName(equivalenceLiteral.left().getUniqueName()); + PVariable varTarget = body.getOrCreateVariableByName(equivalenceLiteral.right().getUniqueName()); + if (equivalenceLiteral.positive()) { + new Equality(body, varSource, varTarget); + } else { + new Inequality(body, varSource, varTarget); + } + } + + private void translateRelationViewLiteral(RelationViewLiteral relationViewLiteral, PBody body) { + var substitution = translateSubstitution(relationViewLiteral.getSubstitution(), body); + var polarity = relationViewLiteral.getPolarity(); + var relationView = relationViewLiteral.getTarget(); + if (polarity == CallPolarity.POSITIVE) { + new TypeConstraint(body, substitution, wrapView(relationView)); + } else { + var embeddedPQuery = translateEmbeddedRelationViewPQuery(relationView); + switch (polarity) { + case TRANSITIVE -> new BinaryTransitiveClosure(body, substitution, embeddedPQuery); + case NEGATIVE -> new NegativePatternCall(body, substitution, embeddedPQuery); + default -> throw new IllegalArgumentException("Unknown polarity: " + polarity); + } + } + } + + private static Tuple translateSubstitution(List substitution, PBody body) { + int arity = substitution.size(); + Object[] variables = new Object[arity]; + for (int i = 0; i < arity; i++) { + var variable = substitution.get(i); + variables[i] = body.getOrCreateVariableByName(variable.getUniqueName()); + } + return Tuples.flatTupleOf(variables); + } + + private RawPQuery translateEmbeddedRelationViewPQuery(AnyRelationView relationView) { + return view2EmbeddedMap.computeIfAbsent(relationView, this::doTranslateEmbeddedRelationViewPQuery); + } + + private RawPQuery doTranslateEmbeddedRelationViewPQuery(AnyRelationView relationView) { + var embeddedPQuery = new RawPQuery(DnfUtils.generateUniqueName(relationView.name()), PVisibility.EMBEDDED); + var body = new PBody(embeddedPQuery); + int arity = relationView.arity(); + var parameters = new ArrayList(arity); + var arguments = new Object[arity]; + var symbolicParameters = new ArrayList(arity); + for (int i = 0; i < arity; i++) { + var parameterName = "p" + i; + var parameter = new PParameter(parameterName); + parameters.add(parameter); + var variable = body.getOrCreateVariableByName(parameterName); + arguments[i] = variable; + symbolicParameters.add(new ExportedParameter(body, variable, parameter)); + } + embeddedPQuery.setParameters(parameters); + body.setSymbolicParameters(symbolicParameters); + var argumentTuple = Tuples.flatTupleOf(arguments); + new TypeConstraint(body, argumentTuple, wrapView(relationView)); + embeddedPQuery.addBody(body); + return embeddedPQuery; + } + + private RelationViewWrapper wrapView(AnyRelationView relationView) { + return view2WrapperMap.computeIfAbsent(relationView, RelationViewWrapper::new); + } + + private void translateDnfCallLiteral(DnfCallLiteral dnfCallLiteral, PBody body) { + var variablesTuple = translateSubstitution(dnfCallLiteral.getSubstitution(), body); + var translatedReferred = translate(dnfCallLiteral.getTarget()); + var polarity = dnfCallLiteral.getPolarity(); + switch (polarity) { + case POSITIVE -> new PositivePatternCall(body, variablesTuple, translatedReferred); + case TRANSITIVE -> new BinaryTransitiveClosure(body, variablesTuple, translatedReferred); + case NEGATIVE -> new NegativePatternCall(body, variablesTuple, translatedReferred); + default -> throw new IllegalArgumentException("Unknown polarity: " + polarity); + } + } + + private void translateConstantLiteral(ConstantLiteral constantLiteral, PBody body) { + var variable = body.getOrCreateVariableByName(constantLiteral.variable().getUniqueName()); + new ConstantValue(body, variable, constantLiteral.nodeId()); + } +} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java index 6a37b54a..471fdfc9 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java @@ -2,10 +2,13 @@ package tools.refinery.store.query.viatra; import org.junit.jupiter.api.Test; import tools.refinery.store.model.ModelStore; -import tools.refinery.store.query.DNF; +import tools.refinery.store.query.Dnf; import tools.refinery.store.query.ModelQuery; import tools.refinery.store.query.Variable; -import tools.refinery.store.query.atom.*; +import tools.refinery.store.query.literal.CallPolarity; +import tools.refinery.store.query.literal.DnfCallLiteral; +import tools.refinery.store.query.literal.EquivalenceLiteral; +import tools.refinery.store.query.literal.RelationViewLiteral; import tools.refinery.store.query.view.FilteredRelationView; import tools.refinery.store.query.view.KeyOnlyRelationView; import tools.refinery.store.representation.Symbol; @@ -27,9 +30,9 @@ class QueryTest { var personView = new KeyOnlyRelationView<>(person); var p1 = new Variable("p1"); - var predicate = DNF.builder("TypeConstraint") + var predicate = Dnf.builder("TypeConstraint") .parameters(p1) - .clause(new RelationViewAtom(personView, p1)) + .clause(new RelationViewLiteral(personView, p1)) .build(); var store = ModelStore.builder() @@ -64,12 +67,12 @@ class QueryTest { var p1 = new Variable("p1"); var p2 = new Variable("p2"); - var predicate = DNF.builder("RelationConstraint") + var predicate = Dnf.builder("RelationConstraint") .parameters(p1, p2) .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(friendMustView, p1, p2) + new RelationViewLiteral(personView, p1), + new RelationViewLiteral(personView, p2), + new RelationViewLiteral(friendMustView, p1, p2) ) .build(); @@ -111,13 +114,13 @@ class QueryTest { var p1 = new Variable("p1"); var p2 = new Variable("p2"); - var predicate = DNF.builder("RelationConstraint") + var predicate = Dnf.builder("RelationConstraint") .parameters(p1, p2) .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(friendMustView, p1, p2), - new RelationViewAtom(friendMustView, p2, p1) + new RelationViewLiteral(personView, p1), + new RelationViewLiteral(personView, p2), + new RelationViewLiteral(friendMustView, p1, p2), + new RelationViewLiteral(friendMustView, p2, p1) ) .build(); @@ -166,12 +169,12 @@ class QueryTest { var p1 = new Variable("p1"); var p2 = new Variable("p2"); - var predicate = DNF.builder("RelationConstraint") + var predicate = Dnf.builder("RelationConstraint") .parameters(p1) .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(friendMustView, p1, p2) + new RelationViewLiteral(personView, p1), + new RelationViewLiteral(personView, p2), + new RelationViewLiteral(friendMustView, p1, p2) ) .build(); @@ -213,17 +216,17 @@ class QueryTest { var p1 = new Variable("p1"); var p2 = new Variable("p2"); - var predicate = DNF.builder("Or") + var predicate = Dnf.builder("Or") .parameters(p1, p2) .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(friendMustView, p1, p2) + new RelationViewLiteral(personView, p1), + new RelationViewLiteral(personView, p2), + new RelationViewLiteral(friendMustView, p1, p2) ) .clause( - new RelationViewAtom(animalView, p1), - new RelationViewAtom(animalView, p2), - new RelationViewAtom(friendMustView, p1, p2) + new RelationViewLiteral(animalView, p1), + new RelationViewLiteral(animalView, p2), + new RelationViewLiteral(friendMustView, p1, p2) ) .build(); @@ -263,12 +266,12 @@ class QueryTest { var p1 = new Variable("p1"); var p2 = new Variable("p2"); - var predicate = DNF.builder("Equality") + var predicate = Dnf.builder("Equality") .parameters(p1, p2) .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new EquivalenceAtom(p1, p2) + new RelationViewLiteral(personView, p1), + new RelationViewLiteral(personView, p2), + new EquivalenceLiteral(p1, p2) ) .build(); @@ -302,14 +305,14 @@ class QueryTest { var p1 = new Variable("p1"); var p2 = new Variable("p2"); var p3 = new Variable("p3"); - var predicate = DNF.builder("Inequality") + var predicate = Dnf.builder("Inequality") .parameters(p1, p2, p3) .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(friendMustView, p1, p3), - new RelationViewAtom(friendMustView, p2, p3), - new EquivalenceAtom(false, p1, p2) + new RelationViewLiteral(personView, p1), + new RelationViewLiteral(personView, p2), + new RelationViewLiteral(friendMustView, p1, p3), + new RelationViewLiteral(friendMustView, p2, p3), + new EquivalenceLiteral(false, p1, p2) ) .build(); @@ -346,23 +349,23 @@ class QueryTest { var p1 = new Variable("p1"); var p2 = new Variable("p2"); - var friendPredicate = DNF.builder("RelationConstraint") + var friendPredicate = Dnf.builder("RelationConstraint") .parameters(p1, p2) .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(friendMustView, p1, p2) + new RelationViewLiteral(personView, p1), + new RelationViewLiteral(personView, p2), + new RelationViewLiteral(friendMustView, p1, p2) ) .build(); var p3 = new Variable("p3"); var p4 = new Variable("p4"); - var predicate = DNF.builder("PositivePatternCall") + var predicate = Dnf.builder("PositivePatternCall") .parameters(p3, p4) .clause( - new RelationViewAtom(personView, p3), - new RelationViewAtom(personView, p4), - new DNFCallAtom(friendPredicate, p3, p4) + new RelationViewLiteral(personView, p3), + new RelationViewLiteral(personView, p4), + new DnfCallLiteral(friendPredicate, p3, p4) ) .build(); @@ -399,12 +402,12 @@ class QueryTest { var p1 = new Variable("p1"); var p2 = new Variable("p2"); - var predicate = DNF.builder("NegativePatternCall") + var predicate = Dnf.builder("NegativePatternCall") .parameters(p1, p2) .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(false, friendMustView, p1, p2) + new RelationViewLiteral(personView, p1), + new RelationViewLiteral(personView, p2), + new RelationViewLiteral(false, friendMustView, p1, p2) ) .build(); @@ -441,23 +444,23 @@ class QueryTest { var p1 = new Variable("p1"); var p2 = new Variable("p2"); - var friendPredicate = DNF.builder("RelationConstraint") + var friendPredicate = Dnf.builder("RelationConstraint") .parameters(p1, p2) .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(friendMustView, p1, p2) + new RelationViewLiteral(personView, p1), + new RelationViewLiteral(personView, p2), + new RelationViewLiteral(friendMustView, p1, p2) ) .build(); var p3 = new Variable("p3"); var p4 = new Variable("p4"); - var predicate = DNF.builder("NegativePatternCall") + var predicate = Dnf.builder("NegativePatternCall") .parameters(p3, p4) .clause( - new RelationViewAtom(personView, p3), - new RelationViewAtom(personView, p4), - new DNFCallAtom(false, friendPredicate, p3, p4) + new RelationViewLiteral(personView, p3), + new RelationViewLiteral(personView, p4), + new DnfCallLiteral(false, friendPredicate, p3, p4) ) .build(); @@ -495,11 +498,11 @@ class QueryTest { var p1 = new Variable("p1"); var p2 = new Variable("p2"); - var predicate = DNF.builder("Count") + var predicate = Dnf.builder("Count") .parameters(p1) .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(false, friendMustView, p1, p2) + new RelationViewLiteral(personView, p1), + new RelationViewLiteral(false, friendMustView, p1, p2) ) .build(); @@ -536,20 +539,20 @@ class QueryTest { var p1 = new Variable("p1"); var p2 = new Variable("p2"); - var called = DNF.builder("Called") + var called = Dnf.builder("Called") .parameters(p1, p2) .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(friendMustView, p1, p2) + new RelationViewLiteral(personView, p1), + new RelationViewLiteral(personView, p2), + new RelationViewLiteral(friendMustView, p1, p2) ) .build(); - var predicate = DNF.builder("Count") + var predicate = Dnf.builder("Count") .parameters(p1) .clause( - new RelationViewAtom(personView, p1), - new DNFCallAtom(false, called, p1, p2) + new RelationViewLiteral(personView, p1), + new DnfCallLiteral(false, called, p1, p2) ) .build(); @@ -585,12 +588,12 @@ class QueryTest { var p1 = new Variable("p1"); var p2 = new Variable("p2"); - var predicate = DNF.builder("TransitivePatternCall") + var predicate = Dnf.builder("TransitivePatternCall") .parameters(p1, p2) .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(CallPolarity.TRANSITIVE, friendMustView, p1, p2) + new RelationViewLiteral(personView, p1), + new RelationViewLiteral(personView, p2), + new RelationViewLiteral(CallPolarity.TRANSITIVE, friendMustView, p1, p2) ) .build(); @@ -626,23 +629,23 @@ class QueryTest { var p1 = new Variable("p1"); var p2 = new Variable("p2"); - var friendPredicate = DNF.builder("RelationConstraint") + var friendPredicate = Dnf.builder("RelationConstraint") .parameters(p1, p2) .clause( - new RelationViewAtom(personView, p1), - new RelationViewAtom(personView, p2), - new RelationViewAtom(friendMustView, p1, p2) + new RelationViewLiteral(personView, p1), + new RelationViewLiteral(personView, p2), + new RelationViewLiteral(friendMustView, p1, p2) ) .build(); var p3 = new Variable("p3"); var p4 = new Variable("p4"); - var predicate = DNF.builder("TransitivePatternCall") + var predicate = Dnf.builder("TransitivePatternCall") .parameters(p3, p4) .clause( - new RelationViewAtom(personView, p3), - new RelationViewAtom(personView, p4), - new DNFCallAtom(CallPolarity.TRANSITIVE, friendPredicate, p3, p4) + new RelationViewLiteral(personView, p3), + new RelationViewLiteral(personView, p4), + new DnfCallLiteral(CallPolarity.TRANSITIVE, friendPredicate, p3, p4) ) .build(); diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java index 98995339..99b942d2 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java @@ -2,10 +2,10 @@ package tools.refinery.store.query.viatra; import org.junit.jupiter.api.Test; import tools.refinery.store.model.ModelStore; -import tools.refinery.store.query.DNF; +import tools.refinery.store.query.Dnf; import tools.refinery.store.query.ModelQuery; import tools.refinery.store.query.Variable; -import tools.refinery.store.query.atom.RelationViewAtom; +import tools.refinery.store.query.literal.RelationViewLiteral; import tools.refinery.store.query.view.KeyOnlyRelationView; import tools.refinery.store.representation.Symbol; import tools.refinery.store.tuple.Tuple; @@ -20,9 +20,9 @@ class QueryTransactionTest { var personView = new KeyOnlyRelationView<>(person); var p1 = new Variable("p1"); - var predicate = DNF.builder("TypeConstraint") + var predicate = Dnf.builder("TypeConstraint") .parameters(p1) - .clause(new RelationViewAtom(personView, p1)) + .clause(new RelationViewLiteral(personView, p1)) .build(); var store = ModelStore.builder() diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/DNF.java b/subprojects/store/src/main/java/tools/refinery/store/query/DNF.java deleted file mode 100644 index 95c5d787..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/query/DNF.java +++ /dev/null @@ -1,169 +0,0 @@ -package tools.refinery.store.query; - -import tools.refinery.store.query.atom.DNFAtom; - -import java.util.*; - -public final class DNF implements RelationLike { - private final String name; - - private final String uniqueName; - - private final List parameters; - - private final List> functionalDependencies; - - private final List clauses; - - private DNF(String name, List parameters, List> functionalDependencies, - List clauses) { - validateFunctionalDependencies(parameters, functionalDependencies); - this.name = name; - this.uniqueName = DNFUtils.generateUniqueName(name); - this.parameters = parameters; - this.functionalDependencies = functionalDependencies; - this.clauses = clauses; - } - - private static void validateFunctionalDependencies( - Collection parameters, Collection> functionalDependencies) { - var parameterSet = new HashSet<>(parameters); - for (var functionalDependency : functionalDependencies) { - validateParameters(parameters, parameterSet, functionalDependency.forEach(), functionalDependency); - validateParameters(parameters, parameterSet, functionalDependency.unique(), functionalDependency); - } - } - - private static void validateParameters(Collection parameters, Set parameterSet, - Collection toValidate, - FunctionalDependency functionalDependency) { - for (var variable : toValidate) { - if (!parameterSet.contains(variable)) { - throw new IllegalArgumentException( - "Variable %s of functional dependency %s does not appear in the parameter list %s" - .formatted(variable, functionalDependency, parameters)); - } - } - } - - @Override - public String name() { - return name; - } - - public String getUniqueName() { - return uniqueName; - } - - public List getParameters() { - return parameters; - } - - public List> getFunctionalDependencies() { - return functionalDependencies; - } - - @Override - public int arity() { - return parameters.size(); - } - - public List getClauses() { - return clauses; - } - - public static Builder builder() { - return builder(null); - } - - public static Builder builder(String name) { - return new Builder(name); - } - - @SuppressWarnings("UnusedReturnValue") - public static class Builder { - private final String name; - - private final List parameters = new ArrayList<>(); - - private final List> functionalDependencies = new ArrayList<>(); - - private final List> clauses = new ArrayList<>(); - - private Builder(String name) { - this.name = name; - } - - public Builder parameter(Variable variable) { - parameters.add(variable); - return this; - } - - public Builder parameters(Variable... variables) { - return parameters(List.of(variables)); - } - - public Builder parameters(Collection variables) { - parameters.addAll(variables); - return this; - } - - public Builder functionalDependencies(Collection> functionalDependencies) { - this.functionalDependencies.addAll(functionalDependencies); - return this; - } - - public Builder functionalDependency(FunctionalDependency functionalDependency) { - functionalDependencies.add(functionalDependency); - return this; - } - - public Builder functionalDependency(Set forEach, Set unique) { - return functionalDependency(new FunctionalDependency<>(forEach, unique)); - } - - public Builder clause(DNFAtom... atoms) { - clauses.add(List.of(atoms)); - return this; - } - - public Builder clause(Collection atoms) { - clauses.add(List.copyOf(atoms)); - return this; - } - - public Builder clause(DNFAnd clause) { - return clause(clause.constraints()); - } - - public Builder clauses(DNFAnd... clauses) { - for (var clause : clauses) { - this.clause(clause); - } - return this; - } - - public Builder clauses(Collection clauses) { - for (var clause : clauses) { - this.clause(clause); - } - return this; - } - - public DNF build() { - var postProcessedClauses = new ArrayList(); - for (var constraints : clauses) { - var variables = new HashSet(); - for (var constraint : constraints) { - constraint.collectAllVariables(variables); - } - parameters.forEach(variables::remove); - postProcessedClauses.add(new DNFAnd(Collections.unmodifiableSet(variables), - Collections.unmodifiableList(constraints))); - } - return new DNF(name, Collections.unmodifiableList(parameters), - Collections.unmodifiableList(functionalDependencies), - Collections.unmodifiableList(postProcessedClauses)); - } - } -} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/DNFAnd.java b/subprojects/store/src/main/java/tools/refinery/store/query/DNFAnd.java deleted file mode 100644 index 8c3bf05d..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/query/DNFAnd.java +++ /dev/null @@ -1,9 +0,0 @@ -package tools.refinery.store.query; - -import tools.refinery.store.query.atom.DNFAtom; - -import java.util.List; -import java.util.Set; - -public record DNFAnd(Set quantifiedVariables, List constraints) { -} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/DNFUtils.java b/subprojects/store/src/main/java/tools/refinery/store/query/DNFUtils.java deleted file mode 100644 index 0ef77d49..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/query/DNFUtils.java +++ /dev/null @@ -1,19 +0,0 @@ -package tools.refinery.store.query; - -import java.util.UUID; - -public final class DNFUtils { - private DNFUtils() { - throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); - } - - public static String generateUniqueName(String originalName) { - UUID uuid = UUID.randomUUID(); - String uniqueString = "_" + uuid.toString().replace('-', '_'); - if (originalName == null) { - return uniqueString; - } else { - return originalName + uniqueString; - } - } -} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/Dnf.java b/subprojects/store/src/main/java/tools/refinery/store/query/Dnf.java new file mode 100644 index 00000000..f7b27b81 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/query/Dnf.java @@ -0,0 +1,169 @@ +package tools.refinery.store.query; + +import tools.refinery.store.query.literal.Literal; + +import java.util.*; + +public final class Dnf implements RelationLike { + private final String name; + + private final String uniqueName; + + private final List parameters; + + private final List> functionalDependencies; + + private final List clauses; + + private Dnf(String name, List parameters, List> functionalDependencies, + List clauses) { + validateFunctionalDependencies(parameters, functionalDependencies); + this.name = name; + this.uniqueName = DnfUtils.generateUniqueName(name); + this.parameters = parameters; + this.functionalDependencies = functionalDependencies; + this.clauses = clauses; + } + + private static void validateFunctionalDependencies( + Collection parameters, Collection> functionalDependencies) { + var parameterSet = new HashSet<>(parameters); + for (var functionalDependency : functionalDependencies) { + validateParameters(parameters, parameterSet, functionalDependency.forEach(), functionalDependency); + validateParameters(parameters, parameterSet, functionalDependency.unique(), functionalDependency); + } + } + + private static void validateParameters(Collection parameters, Set parameterSet, + Collection toValidate, + FunctionalDependency functionalDependency) { + for (var variable : toValidate) { + if (!parameterSet.contains(variable)) { + throw new IllegalArgumentException( + "Variable %s of functional dependency %s does not appear in the parameter list %s" + .formatted(variable, functionalDependency, parameters)); + } + } + } + + @Override + public String name() { + return name; + } + + public String getUniqueName() { + return uniqueName; + } + + public List getParameters() { + return parameters; + } + + public List> getFunctionalDependencies() { + return functionalDependencies; + } + + @Override + public int arity() { + return parameters.size(); + } + + public List getClauses() { + return clauses; + } + + public static Builder builder() { + return builder(null); + } + + public static Builder builder(String name) { + return new Builder(name); + } + + @SuppressWarnings("UnusedReturnValue") + public static class Builder { + private final String name; + + private final List parameters = new ArrayList<>(); + + private final List> functionalDependencies = new ArrayList<>(); + + private final List> clauses = new ArrayList<>(); + + private Builder(String name) { + this.name = name; + } + + public Builder parameter(Variable variable) { + parameters.add(variable); + return this; + } + + public Builder parameters(Variable... variables) { + return parameters(List.of(variables)); + } + + public Builder parameters(Collection variables) { + parameters.addAll(variables); + return this; + } + + public Builder functionalDependencies(Collection> functionalDependencies) { + this.functionalDependencies.addAll(functionalDependencies); + return this; + } + + public Builder functionalDependency(FunctionalDependency functionalDependency) { + functionalDependencies.add(functionalDependency); + return this; + } + + public Builder functionalDependency(Set forEach, Set unique) { + return functionalDependency(new FunctionalDependency<>(forEach, unique)); + } + + public Builder clause(Literal... atoms) { + clauses.add(List.of(atoms)); + return this; + } + + public Builder clause(Collection atoms) { + clauses.add(List.copyOf(atoms)); + return this; + } + + public Builder clause(DnfClause clause) { + return clause(clause.literals()); + } + + public Builder clauses(DnfClause... clauses) { + for (var clause : clauses) { + this.clause(clause); + } + return this; + } + + public Builder clauses(Collection clauses) { + for (var clause : clauses) { + this.clause(clause); + } + return this; + } + + public Dnf build() { + var postProcessedClauses = new ArrayList(); + for (var constraints : clauses) { + var variables = new HashSet(); + for (var constraint : constraints) { + constraint.collectAllVariables(variables); + } + parameters.forEach(variables::remove); + postProcessedClauses.add(new DnfClause(Collections.unmodifiableSet(variables), + Collections.unmodifiableList(constraints))); + } + return new Dnf(name, Collections.unmodifiableList(parameters), + Collections.unmodifiableList(functionalDependencies), + Collections.unmodifiableList(postProcessedClauses)); + } + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/DnfClause.java b/subprojects/store/src/main/java/tools/refinery/store/query/DnfClause.java new file mode 100644 index 00000000..2ba6becc --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/query/DnfClause.java @@ -0,0 +1,9 @@ +package tools.refinery.store.query; + +import tools.refinery.store.query.literal.Literal; + +import java.util.List; +import java.util.Set; + +public record DnfClause(Set quantifiedVariables, List literals) { +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/DnfUtils.java b/subprojects/store/src/main/java/tools/refinery/store/query/DnfUtils.java new file mode 100644 index 00000000..c7a2849c --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/query/DnfUtils.java @@ -0,0 +1,19 @@ +package tools.refinery.store.query; + +import java.util.UUID; + +public final class DnfUtils { + private DnfUtils() { + throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); + } + + public static String generateUniqueName(String originalName) { + UUID uuid = UUID.randomUUID(); + String uniqueString = "_" + uuid.toString().replace('-', '_'); + if (originalName == null) { + return uniqueString; + } else { + return originalName + uniqueString; + } + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java index 7449e39b..f7762444 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java +++ b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java @@ -5,7 +5,7 @@ import tools.refinery.store.adapter.ModelAdapter; public interface ModelQueryAdapter extends ModelAdapter { ModelQueryStoreAdapter getStoreAdapter(); - ResultSet getResultSet(DNF query); + ResultSet getResultSet(Dnf query); boolean hasPendingChanges(); diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java index 4364d844..b3cfb4b4 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java +++ b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java @@ -7,16 +7,16 @@ import java.util.Collection; import java.util.List; public interface ModelQueryBuilder extends ModelAdapterBuilder { - default ModelQueryBuilder queries(DNF... queries) { + default ModelQueryBuilder queries(Dnf... queries) { return queries(List.of(queries)); } - default ModelQueryBuilder queries(Collection queries) { + default ModelQueryBuilder queries(Collection queries) { queries.forEach(this::query); return this; } - ModelQueryBuilder query(DNF query); + ModelQueryBuilder query(Dnf query); @Override ModelQueryStoreAdapter createStoreAdapter(ModelStore store); diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java index ef5a4587..3efeacaa 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java +++ b/subprojects/store/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java @@ -9,7 +9,7 @@ import java.util.Collection; public interface ModelQueryStoreAdapter extends ModelStoreAdapter { Collection getRelationViews(); - Collection getQueries(); + Collection getQueries(); @Override ModelQueryAdapter createModelAdapter(Model model); diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/Variable.java b/subprojects/store/src/main/java/tools/refinery/store/query/Variable.java index 3632f3c5..6a6831ae 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/query/Variable.java +++ b/subprojects/store/src/main/java/tools/refinery/store/query/Variable.java @@ -13,7 +13,7 @@ public class Variable { public Variable(String name) { super(); this.name = name; - this.uniqueName = DNFUtils.generateUniqueName(name); + this.uniqueName = DnfUtils.generateUniqueName(name); } public String getName() { diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/atom/CallAtom.java b/subprojects/store/src/main/java/tools/refinery/store/query/atom/CallAtom.java deleted file mode 100644 index 47121870..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/query/atom/CallAtom.java +++ /dev/null @@ -1,80 +0,0 @@ -package tools.refinery.store.query.atom; - -import tools.refinery.store.query.Variable; -import tools.refinery.store.query.RelationLike; - -import java.util.List; -import java.util.Objects; -import java.util.Set; - -public abstract class CallAtom implements DNFAtom { - private final CallPolarity polarity; - private final T target; - private final List substitution; - - protected CallAtom(CallPolarity polarity, T target, List substitution) { - if (substitution.size() != target.arity()) { - throw new IllegalArgumentException("%s needs %d arguments, but got %s".formatted(target.name(), - target.arity(), substitution.size())); - } - if (polarity.isTransitive() && target.arity() != 2) { - throw new IllegalArgumentException("Transitive closures can only take binary relations"); - } - this.polarity = polarity; - this.target = target; - this.substitution = substitution; - } - - protected CallAtom(CallPolarity polarity, T target, Variable... substitution) { - this(polarity, target, List.of(substitution)); - } - - protected CallAtom(boolean positive, T target, List substitution) { - this(CallPolarity.fromBoolean(positive), target, substitution); - } - - protected CallAtom(boolean positive, T target, Variable... substitution) { - this(positive, target, List.of(substitution)); - } - - protected CallAtom(T target, List substitution) { - this(true, target, substitution); - } - - protected CallAtom(T target, Variable... substitution) { - this(target, List.of(substitution)); - } - - public CallPolarity getPolarity() { - return polarity; - } - - public T getTarget() { - return target; - } - - public List getSubstitution() { - return substitution; - } - - @Override - public void collectAllVariables(Set variables) { - if (polarity.isPositive()) { - variables.addAll(substitution); - } - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - CallAtom callAtom = (CallAtom) o; - return polarity == callAtom.polarity && Objects.equals(target, callAtom.target) && Objects.equals(substitution - , callAtom.substitution); - } - - @Override - public int hashCode() { - return Objects.hash(polarity, target, substitution); - } -} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/atom/CallPolarity.java b/subprojects/store/src/main/java/tools/refinery/store/query/atom/CallPolarity.java deleted file mode 100644 index 957e9b7b..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/query/atom/CallPolarity.java +++ /dev/null @@ -1,28 +0,0 @@ -package tools.refinery.store.query.atom; - -public enum CallPolarity { - POSITIVE(true, false), - NEGATIVE(false, false), - TRANSITIVE(true, true); - - private final boolean positive; - - private final boolean transitive; - - CallPolarity(boolean positive, boolean transitive) { - this.positive = positive; - this.transitive = transitive; - } - - public boolean isPositive() { - return positive; - } - - public boolean isTransitive() { - return transitive; - } - - public static CallPolarity fromBoolean(boolean positive) { - return positive ? POSITIVE : NEGATIVE; - } -} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/atom/ConstantAtom.java b/subprojects/store/src/main/java/tools/refinery/store/query/atom/ConstantAtom.java deleted file mode 100644 index 13dae7d0..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/query/atom/ConstantAtom.java +++ /dev/null @@ -1,12 +0,0 @@ -package tools.refinery.store.query.atom; - -import tools.refinery.store.query.Variable; - -import java.util.Set; - -public record ConstantAtom(Variable variable, int nodeId) implements DNFAtom { - @Override - public void collectAllVariables(Set variables) { - variables.add(variable); - } -} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/atom/DNFAtom.java b/subprojects/store/src/main/java/tools/refinery/store/query/atom/DNFAtom.java deleted file mode 100644 index ebf71236..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/query/atom/DNFAtom.java +++ /dev/null @@ -1,9 +0,0 @@ -package tools.refinery.store.query.atom; - -import tools.refinery.store.query.Variable; - -import java.util.Set; - -public interface DNFAtom { - void collectAllVariables(Set variables); -} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/atom/DNFCallAtom.java b/subprojects/store/src/main/java/tools/refinery/store/query/atom/DNFCallAtom.java deleted file mode 100644 index 3b4f5cd1..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/query/atom/DNFCallAtom.java +++ /dev/null @@ -1,32 +0,0 @@ -package tools.refinery.store.query.atom; - -import tools.refinery.store.query.DNF; -import tools.refinery.store.query.Variable; - -import java.util.List; - -public class DNFCallAtom extends CallAtom { - public DNFCallAtom(CallPolarity polarity, DNF target, List substitution) { - super(polarity, target, substitution); - } - - public DNFCallAtom(CallPolarity polarity, DNF target, Variable... substitution) { - super(polarity, target, substitution); - } - - public DNFCallAtom(boolean positive, DNF target, List substitution) { - super(positive, target, substitution); - } - - public DNFCallAtom(boolean positive, DNF target, Variable... substitution) { - super(positive, target, substitution); - } - - public DNFCallAtom(DNF target, List substitution) { - super(target, substitution); - } - - public DNFCallAtom(DNF target, Variable... substitution) { - super(target, substitution); - } -} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/atom/EquivalenceAtom.java b/subprojects/store/src/main/java/tools/refinery/store/query/atom/EquivalenceAtom.java deleted file mode 100644 index b1b3a6f7..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/query/atom/EquivalenceAtom.java +++ /dev/null @@ -1,17 +0,0 @@ -package tools.refinery.store.query.atom; - -import tools.refinery.store.query.Variable; - -import java.util.Set; - -public record EquivalenceAtom(boolean positive, Variable left, Variable right) implements DNFAtom { - public EquivalenceAtom(Variable left, Variable right) { - this(true, left, right); - } - - @Override - public void collectAllVariables(Set variables) { - variables.add(left); - variables.add(right); - } -} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/atom/Modality.java b/subprojects/store/src/main/java/tools/refinery/store/query/atom/Modality.java deleted file mode 100644 index e389f563..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/query/atom/Modality.java +++ /dev/null @@ -1,22 +0,0 @@ -package tools.refinery.store.query.atom; - -import java.util.Locale; - -public enum Modality { - MUST, - MAY, - CURRENT; - - public Modality negate() { - return switch(this) { - case MUST -> MAY; - case MAY -> MUST; - case CURRENT -> CURRENT; - }; - } - - @Override - public String toString() { - return name().toLowerCase(Locale.ROOT); - } -} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/atom/RelationViewAtom.java b/subprojects/store/src/main/java/tools/refinery/store/query/atom/RelationViewAtom.java deleted file mode 100644 index a2b176c4..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/query/atom/RelationViewAtom.java +++ /dev/null @@ -1,32 +0,0 @@ -package tools.refinery.store.query.atom; - -import tools.refinery.store.query.Variable; -import tools.refinery.store.query.view.AnyRelationView; - -import java.util.List; - -public final class RelationViewAtom extends CallAtom { - public RelationViewAtom(CallPolarity polarity, AnyRelationView target, List substitution) { - super(polarity, target, substitution); - } - - public RelationViewAtom(CallPolarity polarity, AnyRelationView target, Variable... substitution) { - super(polarity, target, substitution); - } - - public RelationViewAtom(boolean positive, AnyRelationView target, List substitution) { - super(positive, target, substitution); - } - - public RelationViewAtom(boolean positive, AnyRelationView target, Variable... substitution) { - super(positive, target, substitution); - } - - public RelationViewAtom(AnyRelationView target, List substitution) { - super(target, substitution); - } - - public RelationViewAtom(AnyRelationView target, Variable... substitution) { - super(target, substitution); - } -} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/literal/CallLiteral.java b/subprojects/store/src/main/java/tools/refinery/store/query/literal/CallLiteral.java new file mode 100644 index 00000000..59120434 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/query/literal/CallLiteral.java @@ -0,0 +1,60 @@ +package tools.refinery.store.query.literal; + +import tools.refinery.store.query.Variable; +import tools.refinery.store.query.RelationLike; + +import java.util.List; +import java.util.Objects; +import java.util.Set; + +public abstract class CallLiteral implements Literal { + private final CallPolarity polarity; + private final T target; + private final List substitution; + + protected CallLiteral(CallPolarity polarity, T target, List substitution) { + if (substitution.size() != target.arity()) { + throw new IllegalArgumentException("%s needs %d arguments, but got %s".formatted(target.name(), + target.arity(), substitution.size())); + } + if (polarity.isTransitive() && target.arity() != 2) { + throw new IllegalArgumentException("Transitive closures can only take binary relations"); + } + this.polarity = polarity; + this.target = target; + this.substitution = substitution; + } + + public CallPolarity getPolarity() { + return polarity; + } + + public T getTarget() { + return target; + } + + public List getSubstitution() { + return substitution; + } + + @Override + public void collectAllVariables(Set variables) { + if (polarity.isPositive()) { + variables.addAll(substitution); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CallLiteral callAtom = (CallLiteral) o; + return polarity == callAtom.polarity && Objects.equals(target, callAtom.target) && + Objects.equals(substitution, callAtom.substitution); + } + + @Override + public int hashCode() { + return Objects.hash(polarity, target, substitution); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/literal/CallPolarity.java b/subprojects/store/src/main/java/tools/refinery/store/query/literal/CallPolarity.java new file mode 100644 index 00000000..ddea0221 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/query/literal/CallPolarity.java @@ -0,0 +1,28 @@ +package tools.refinery.store.query.literal; + +public enum CallPolarity { + POSITIVE(true, false), + NEGATIVE(false, false), + TRANSITIVE(true, true); + + private final boolean positive; + + private final boolean transitive; + + CallPolarity(boolean positive, boolean transitive) { + this.positive = positive; + this.transitive = transitive; + } + + public boolean isPositive() { + return positive; + } + + public boolean isTransitive() { + return transitive; + } + + public static CallPolarity fromBoolean(boolean positive) { + return positive ? POSITIVE : NEGATIVE; + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java b/subprojects/store/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java new file mode 100644 index 00000000..41426fdd --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java @@ -0,0 +1,12 @@ +package tools.refinery.store.query.literal; + +import tools.refinery.store.query.Variable; + +import java.util.Set; + +public record ConstantLiteral(Variable variable, int nodeId) implements Literal { + @Override + public void collectAllVariables(Set variables) { + variables.add(variable); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/literal/DnfCallLiteral.java b/subprojects/store/src/main/java/tools/refinery/store/query/literal/DnfCallLiteral.java new file mode 100644 index 00000000..e3410c21 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/query/literal/DnfCallLiteral.java @@ -0,0 +1,32 @@ +package tools.refinery.store.query.literal; + +import tools.refinery.store.query.Dnf; +import tools.refinery.store.query.Variable; + +import java.util.List; + +public final class DnfCallLiteral extends CallLiteral { + public DnfCallLiteral(CallPolarity polarity, Dnf target, List substitution) { + super(polarity, target, substitution); + } + + public DnfCallLiteral(CallPolarity polarity, Dnf target, Variable... substitution) { + this(polarity, target, List.of(substitution)); + } + + public DnfCallLiteral(boolean positive, Dnf target, List substitution) { + this(CallPolarity.fromBoolean(positive), target, substitution); + } + + public DnfCallLiteral(boolean positive, Dnf target, Variable... substitution) { + this(positive, target, List.of(substitution)); + } + + public DnfCallLiteral(Dnf target, List substitution) { + this(CallPolarity.POSITIVE, target, substitution); + } + + public DnfCallLiteral(Dnf target, Variable... substitution) { + this(target, List.of(substitution)); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java b/subprojects/store/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java new file mode 100644 index 00000000..a1ec2c41 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java @@ -0,0 +1,17 @@ +package tools.refinery.store.query.literal; + +import tools.refinery.store.query.Variable; + +import java.util.Set; + +public record EquivalenceLiteral(boolean positive, Variable left, Variable right) implements Literal { + public EquivalenceLiteral(Variable left, Variable right) { + this(true, left, right); + } + + @Override + public void collectAllVariables(Set variables) { + variables.add(left); + variables.add(right); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/literal/Literal.java b/subprojects/store/src/main/java/tools/refinery/store/query/literal/Literal.java new file mode 100644 index 00000000..676ac7fd --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/query/literal/Literal.java @@ -0,0 +1,9 @@ +package tools.refinery.store.query.literal; + +import tools.refinery.store.query.Variable; + +import java.util.Set; + +public interface Literal { + void collectAllVariables(Set variables); +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/literal/Modality.java b/subprojects/store/src/main/java/tools/refinery/store/query/literal/Modality.java new file mode 100644 index 00000000..93826161 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/query/literal/Modality.java @@ -0,0 +1,22 @@ +package tools.refinery.store.query.literal; + +import java.util.Locale; + +public enum Modality { + MUST, + MAY, + CURRENT; + + public Modality negate() { + return switch(this) { + case MUST -> MAY; + case MAY -> MUST; + case CURRENT -> CURRENT; + }; + } + + @Override + public String toString() { + return name().toLowerCase(Locale.ROOT); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/literal/RelationViewLiteral.java b/subprojects/store/src/main/java/tools/refinery/store/query/literal/RelationViewLiteral.java new file mode 100644 index 00000000..e2106ba9 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/query/literal/RelationViewLiteral.java @@ -0,0 +1,32 @@ +package tools.refinery.store.query.literal; + +import tools.refinery.store.query.Variable; +import tools.refinery.store.query.view.AnyRelationView; + +import java.util.List; + +public final class RelationViewLiteral extends CallLiteral { + public RelationViewLiteral(CallPolarity polarity, AnyRelationView target, List substitution) { + super(polarity, target, substitution); + } + + public RelationViewLiteral(CallPolarity polarity, AnyRelationView target, Variable... substitution) { + this(polarity, target, List.of(substitution)); + } + + public RelationViewLiteral(boolean positive, AnyRelationView target, List substitution) { + this(CallPolarity.fromBoolean(positive), target, substitution); + } + + public RelationViewLiteral(boolean positive, AnyRelationView target, Variable... substitution) { + this(positive, target, List.of(substitution)); + } + + public RelationViewLiteral(AnyRelationView target, List substitution) { + this(CallPolarity.POSITIVE, target, substitution); + } + + public RelationViewLiteral(AnyRelationView target, Variable... substitution) { + this(target, List.of(substitution)); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/Symbol.java b/subprojects/store/src/main/java/tools/refinery/store/representation/Symbol.java index 85ea15f4..30b1c03f 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/representation/Symbol.java +++ b/subprojects/store/src/main/java/tools/refinery/store/representation/Symbol.java @@ -1,12 +1,6 @@ package tools.refinery.store.representation; -import java.util.Objects; - public record Symbol(String name, int arity, Class valueType, T defaultValue) implements AnySymbol { - public boolean isDefaultValue(T value) { - return Objects.equals(defaultValue, value); - } - @Override public boolean equals(Object o) { return this == o; diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java b/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java index 371b5e47..9536a444 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java @@ -49,7 +49,7 @@ class ModelTest { assertEquals(3, ageInterpretation.get(Tuple.of(0))); assertEquals(1, ageInterpretation.get(Tuple.of(1))); - assertNull(ageInterpretation.get( Tuple.of(2))); + assertNull(ageInterpretation.get(Tuple.of(2))); assertTrue(friendInterpretation.get(Tuple.of(0, 1))); assertFalse(friendInterpretation.get(Tuple.of(0, 5))); -- cgit v1.2.3-70-g09d2