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 +++++++++++++++++++++ 6 files changed, 246 insertions(+), 246 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 (limited to 'subprojects/store-query-viatra/src/main/java/tools') 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()); + } +} -- cgit v1.2.3-70-g09d2 From 8183b588cf5bc665c0f96abc6d11b8dc70eecaa3 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Fri, 17 Feb 2023 17:35:48 +0100 Subject: feat: PartialInterpretation representations --- .../query/viatra/internal/pquery/Dnf2PQuery.java | 32 +++-------- .../store/partial/literal/ModalDnfCallLiteral.java | 30 ++++++++++ .../store/partial/literal/ModalLiteral.java | 45 +++++++++++++++ .../partial/literal/ModalRelationLiteral.java | 31 ++++++++++ .../refinery/store/partial/literal/Modality.java | 31 ++++++++++ .../store/partial/literal/PartialLiterals.java | 33 +++++++++++ .../partial/literal/PartialRelationLiteral.java | 27 +++++++++ .../partial/representation/AnyPartialFunction.java | 4 ++ .../partial/representation/AnyPartialSymbol.java | 11 ++++ .../partial/representation/PartialFunction.java | 32 +++++++++++ .../partial/representation/PartialRelation.java | 66 ++++++++++++++++++++++ .../partial/representation/PartialSymbol.java | 12 ++++ .../main/java/tools/refinery/store/query/Dnf.java | 12 ++-- .../java/tools/refinery/store/query/DnfUtils.java | 5 ++ .../refinery/store/query/literal/CallLiteral.java | 28 +++++---- .../store/query/literal/ConstantLiteral.java | 7 +++ .../store/query/literal/DnfCallLiteral.java | 12 +++- .../store/query/literal/EquivalenceLiteral.java | 8 +++ .../refinery/store/query/literal/Literal.java | 3 + .../refinery/store/query/literal/Modality.java | 22 -------- .../store/query/literal/RelationViewLiteral.java | 12 +++- .../refinery/store/query/view/RelationView.java | 12 ++-- .../store/representation/AbstractDomain.java | 29 ++++++++++ .../store/representation/AnyAbstractDomain.java | 7 +++ .../store/representation/TruthValueDomain.java | 60 ++++++++++++++++++++ .../refinery/store/util/CycleDetectingMapper.java | 51 +++++++++++++++++ 26 files changed, 546 insertions(+), 76 deletions(-) create mode 100644 subprojects/store/src/main/java/tools/refinery/store/partial/literal/ModalDnfCallLiteral.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/partial/literal/ModalLiteral.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/partial/literal/ModalRelationLiteral.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/partial/literal/Modality.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/partial/literal/PartialLiterals.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/partial/literal/PartialRelationLiteral.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/partial/representation/AnyPartialFunction.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/partial/representation/AnyPartialSymbol.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/partial/representation/PartialFunction.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/partial/representation/PartialRelation.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/partial/representation/PartialSymbol.java delete 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/representation/AbstractDomain.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/representation/AnyAbstractDomain.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/representation/TruthValueDomain.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java (limited to 'subprojects/store-query-viatra/src/main/java/tools') 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 index 02e26bde..201e0ed0 100644 --- 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 @@ -23,17 +23,16 @@ 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 tools.refinery.store.util.CycleDetectingMapper; 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 CycleDetectingMapper mapper = new CycleDetectingMapper<>(Dnf::name, + this::doTranslate); private final Map view2WrapperMap = new LinkedHashMap<>(); @@ -47,24 +46,7 @@ public class Dnf2PQuery { } 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; + return mapper.map(dnfQuery); } public Map getRelationViews() { @@ -72,7 +54,7 @@ public class Dnf2PQuery { } public RawPQuery getAlreadyTranslated(Dnf dnfQuery) { - return dnf2PQueryMap.get(dnfQuery); + return mapper.getAlreadyMapped(dnfQuery); } private RawPQuery doTranslate(Dnf dnfQuery) { @@ -148,7 +130,7 @@ public class Dnf2PQuery { } private void translateRelationViewLiteral(RelationViewLiteral relationViewLiteral, PBody body) { - var substitution = translateSubstitution(relationViewLiteral.getSubstitution(), body); + var substitution = translateSubstitution(relationViewLiteral.getArguments(), body); var polarity = relationViewLiteral.getPolarity(); var relationView = relationViewLiteral.getTarget(); if (polarity == CallPolarity.POSITIVE) { @@ -205,7 +187,7 @@ public class Dnf2PQuery { } private void translateDnfCallLiteral(DnfCallLiteral dnfCallLiteral, PBody body) { - var variablesTuple = translateSubstitution(dnfCallLiteral.getSubstitution(), body); + var variablesTuple = translateSubstitution(dnfCallLiteral.getArguments(), body); var translatedReferred = translate(dnfCallLiteral.getTarget()); var polarity = dnfCallLiteral.getPolarity(); switch (polarity) { diff --git a/subprojects/store/src/main/java/tools/refinery/store/partial/literal/ModalDnfCallLiteral.java b/subprojects/store/src/main/java/tools/refinery/store/partial/literal/ModalDnfCallLiteral.java new file mode 100644 index 00000000..8070726a --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/partial/literal/ModalDnfCallLiteral.java @@ -0,0 +1,30 @@ +package tools.refinery.store.partial.literal; + +import tools.refinery.store.query.Dnf; +import tools.refinery.store.query.Variable; +import tools.refinery.store.query.literal.CallPolarity; +import tools.refinery.store.query.literal.DnfCallLiteral; +import tools.refinery.store.query.literal.PolarLiteral; + +import java.util.List; +import java.util.Map; + +public class ModalDnfCallLiteral extends ModalLiteral implements PolarLiteral { + public ModalDnfCallLiteral(CallPolarity polarity, Modality modality, Dnf target, List arguments) { + super(polarity, modality, target, arguments); + } + + public ModalDnfCallLiteral(Modality modality, DnfCallLiteral baseLiteral) { + super(modality.commute(baseLiteral.getPolarity()), baseLiteral); + } + + @Override + public ModalDnfCallLiteral substitute(Map substitution) { + return new ModalDnfCallLiteral(getPolarity(), getModality(), getTarget(), substituteArguments(substitution)); + } + + @Override + public ModalDnfCallLiteral negate() { + return new ModalDnfCallLiteral(getPolarity().negate(), getModality(), getTarget(), getArguments()); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/partial/literal/ModalLiteral.java b/subprojects/store/src/main/java/tools/refinery/store/partial/literal/ModalLiteral.java new file mode 100644 index 00000000..a1b6c83e --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/partial/literal/ModalLiteral.java @@ -0,0 +1,45 @@ +package tools.refinery.store.partial.literal; + +import tools.refinery.store.query.RelationLike; +import tools.refinery.store.query.Variable; +import tools.refinery.store.query.literal.CallLiteral; +import tools.refinery.store.query.literal.CallPolarity; + +import java.util.List; +import java.util.Objects; + +public abstract class ModalLiteral extends CallLiteral { + private final Modality modality; + + protected ModalLiteral(CallPolarity polarity, Modality modality, T target, List arguments) { + super(polarity, target, arguments); + this.modality = modality; + } + + protected ModalLiteral(Modality modality, CallLiteral baseLiteral) { + this(baseLiteral.getPolarity(), commute(modality, baseLiteral.getPolarity()), baseLiteral.getTarget(), + baseLiteral.getArguments()); + } + + public Modality getModality() { + return modality; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + ModalLiteral that = (ModalLiteral) o; + return modality == that.modality; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), modality); + } + + private static Modality commute(Modality modality, CallPolarity polarity) { + return polarity.isPositive() ? modality : modality.negate(); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/partial/literal/ModalRelationLiteral.java b/subprojects/store/src/main/java/tools/refinery/store/partial/literal/ModalRelationLiteral.java new file mode 100644 index 00000000..dbaa524f --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/partial/literal/ModalRelationLiteral.java @@ -0,0 +1,31 @@ +package tools.refinery.store.partial.literal; + +import tools.refinery.store.partial.representation.PartialRelation; +import tools.refinery.store.query.Variable; +import tools.refinery.store.query.literal.CallPolarity; +import tools.refinery.store.query.literal.PolarLiteral; + +import java.util.List; +import java.util.Map; + +public final class ModalRelationLiteral extends ModalLiteral + implements PolarLiteral { + public ModalRelationLiteral(CallPolarity polarity, Modality modality, PartialRelation target, + List arguments) { + super(polarity, modality, target, arguments); + } + + public ModalRelationLiteral(Modality modality, PartialRelationLiteral baseLiteral) { + super(modality, baseLiteral); + } + + @Override + public ModalRelationLiteral substitute(Map substitution) { + return new ModalRelationLiteral(getPolarity(), getModality(), getTarget(), substituteArguments(substitution)); + } + + @Override + public ModalRelationLiteral negate() { + return new ModalRelationLiteral(getPolarity().negate(), getModality(), getTarget(), getArguments()); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/partial/literal/Modality.java b/subprojects/store/src/main/java/tools/refinery/store/partial/literal/Modality.java new file mode 100644 index 00000000..d647ef0a --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/partial/literal/Modality.java @@ -0,0 +1,31 @@ +package tools.refinery.store.partial.literal; + +import tools.refinery.store.query.literal.CallPolarity; + +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; + }; + } + + public Modality commute(CallPolarity polarity) { + if (polarity.isPositive()) { + return this; + } + return this.negate(); + } + + @Override + public String toString() { + return name().toLowerCase(Locale.ROOT); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/partial/literal/PartialLiterals.java b/subprojects/store/src/main/java/tools/refinery/store/partial/literal/PartialLiterals.java new file mode 100644 index 00000000..51d388d3 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/partial/literal/PartialLiterals.java @@ -0,0 +1,33 @@ +package tools.refinery.store.partial.literal; + +import tools.refinery.store.query.literal.DnfCallLiteral; + +public final class PartialLiterals { + private PartialLiterals() { + throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); + } + + public ModalRelationLiteral may(PartialRelationLiteral literal) { + return new ModalRelationLiteral(Modality.MAY, literal); + } + + public ModalRelationLiteral must(PartialRelationLiteral literal) { + return new ModalRelationLiteral(Modality.MUST, literal); + } + + public ModalRelationLiteral current(PartialRelationLiteral literal) { + return new ModalRelationLiteral(Modality.CURRENT, literal); + } + + public ModalDnfCallLiteral may(DnfCallLiteral literal) { + return new ModalDnfCallLiteral(Modality.MAY, literal); + } + + public ModalDnfCallLiteral must(DnfCallLiteral literal) { + return new ModalDnfCallLiteral(Modality.MUST, literal); + } + + public ModalDnfCallLiteral current(DnfCallLiteral literal) { + return new ModalDnfCallLiteral(Modality.CURRENT, literal); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/partial/literal/PartialRelationLiteral.java b/subprojects/store/src/main/java/tools/refinery/store/partial/literal/PartialRelationLiteral.java new file mode 100644 index 00000000..dc1a1da3 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/partial/literal/PartialRelationLiteral.java @@ -0,0 +1,27 @@ +package tools.refinery.store.partial.literal; + +import tools.refinery.store.partial.representation.PartialRelation; +import tools.refinery.store.query.Variable; +import tools.refinery.store.query.literal.CallLiteral; +import tools.refinery.store.query.literal.CallPolarity; +import tools.refinery.store.query.literal.PolarLiteral; + +import java.util.List; +import java.util.Map; + +public final class PartialRelationLiteral extends CallLiteral + implements PolarLiteral { + public PartialRelationLiteral(CallPolarity polarity, PartialRelation target, List substitution) { + super(polarity, target, substitution); + } + + @Override + public PartialRelationLiteral substitute(Map substitution) { + return new PartialRelationLiteral(getPolarity(), getTarget(), substituteArguments(substitution)); + } + + @Override + public PartialRelationLiteral negate() { + return new PartialRelationLiteral(getPolarity().negate(), getTarget(), getArguments()); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/partial/representation/AnyPartialFunction.java b/subprojects/store/src/main/java/tools/refinery/store/partial/representation/AnyPartialFunction.java new file mode 100644 index 00000000..1113245e --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/partial/representation/AnyPartialFunction.java @@ -0,0 +1,4 @@ +package tools.refinery.store.partial.representation; + +public sealed interface AnyPartialFunction extends AnyPartialSymbol permits PartialFunction { +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/partial/representation/AnyPartialSymbol.java b/subprojects/store/src/main/java/tools/refinery/store/partial/representation/AnyPartialSymbol.java new file mode 100644 index 00000000..25096e74 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/partial/representation/AnyPartialSymbol.java @@ -0,0 +1,11 @@ +package tools.refinery.store.partial.representation; + +import tools.refinery.store.representation.AnyAbstractDomain; + +public sealed interface AnyPartialSymbol permits AnyPartialFunction, PartialSymbol { + String name(); + + int arity(); + + AnyAbstractDomain abstractDomain(); +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/partial/representation/PartialFunction.java b/subprojects/store/src/main/java/tools/refinery/store/partial/representation/PartialFunction.java new file mode 100644 index 00000000..3c186f6f --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/partial/representation/PartialFunction.java @@ -0,0 +1,32 @@ +package tools.refinery.store.partial.representation; + +import tools.refinery.store.representation.AbstractDomain; + +public record PartialFunction(String name, int arity, AbstractDomain abstractDomain) + implements AnyPartialFunction, PartialSymbol { + @Override + public A defaultValue() { + return null; + } + + @Override + public C defaultConcreteValue() { + return null; + } + + @Override + public boolean equals(Object o) { + return this == o; + } + + @Override + public int hashCode() { + // Compare by identity to make hash table lookups more efficient. + return System.identityHashCode(this); + } + + @Override + public String toString() { + return "%s/%d".formatted(name, arity); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/partial/representation/PartialRelation.java b/subprojects/store/src/main/java/tools/refinery/store/partial/representation/PartialRelation.java new file mode 100644 index 00000000..127355ca --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/partial/representation/PartialRelation.java @@ -0,0 +1,66 @@ +package tools.refinery.store.partial.representation; + +import tools.refinery.store.partial.literal.ModalRelationLiteral; +import tools.refinery.store.partial.literal.PartialRelationLiteral; +import tools.refinery.store.query.RelationLike; +import tools.refinery.store.query.Variable; +import tools.refinery.store.query.literal.CallPolarity; +import tools.refinery.store.partial.literal.Modality; +import tools.refinery.store.representation.AbstractDomain; +import tools.refinery.store.representation.TruthValue; +import tools.refinery.store.representation.TruthValueDomain; + +import java.util.List; + +public record PartialRelation(String name, int arity) implements PartialSymbol, RelationLike { + @Override + public AbstractDomain abstractDomain() { + return TruthValueDomain.INSTANCE; + } + + @Override + public TruthValue defaultValue() { + return TruthValue.FALSE; + } + + @Override + public Boolean defaultConcreteValue() { + return false; + } + + public ModalRelationLiteral call(CallPolarity polarity, Modality modality, List arguments) { + return new ModalRelationLiteral(polarity, modality, this, arguments); + } + + public PartialRelationLiteral call(CallPolarity polarity, List arguments) { + return new PartialRelationLiteral(polarity, this, arguments); + } + + public PartialRelationLiteral call(CallPolarity polarity, Variable... arguments) { + return call(polarity, List.of(arguments)); + } + + public PartialRelationLiteral call(Variable... arguments) { + return call(CallPolarity.POSITIVE, arguments); + } + + public PartialRelationLiteral callTransitive(Variable left, Variable right) { + return call(CallPolarity.TRANSITIVE, List.of(left, right)); + } + + @Override + public boolean equals(Object o) { + return this == o; + } + + @Override + public int hashCode() { + // Compare by identity to make hash table lookups more efficient. + return System.identityHashCode(this); + } + + @Override + public String toString() { + return "%s/%d".formatted(name, arity); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/partial/representation/PartialSymbol.java b/subprojects/store/src/main/java/tools/refinery/store/partial/representation/PartialSymbol.java new file mode 100644 index 00000000..38533fa9 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/partial/representation/PartialSymbol.java @@ -0,0 +1,12 @@ +package tools.refinery.store.partial.representation; + +import tools.refinery.store.representation.AbstractDomain; + +public sealed interface PartialSymbol extends AnyPartialSymbol permits PartialFunction, PartialRelation { + @Override + AbstractDomain abstractDomain(); + + A defaultValue(); + + C defaultConcreteValue(); +} 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 index 1eb9ac76..b080094f 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/query/Dnf.java +++ b/subprojects/store/src/main/java/tools/refinery/store/query/Dnf.java @@ -74,16 +74,16 @@ public final class Dnf implements RelationLike { return clauses; } - public DnfCallLiteral call(CallPolarity polarity, List substitution) { - return new DnfCallLiteral(polarity, this, substitution); + public DnfCallLiteral call(CallPolarity polarity, List arguments) { + return new DnfCallLiteral(polarity, this, arguments); } - public DnfCallLiteral call(CallPolarity polarity, Variable... substitution) { - return call(polarity, List.of(substitution)); + public DnfCallLiteral call(CallPolarity polarity, Variable... arguments) { + return call(polarity, List.of(arguments)); } - public DnfCallLiteral call(Variable... substitution) { - return call(CallPolarity.POSITIVE, substitution); + public DnfCallLiteral call(Variable... arguments) { + return call(CallPolarity.POSITIVE, arguments); } public DnfCallLiteral callTransitive(Variable left, Variable right) { 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 index c7a2849c..17564d43 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/query/DnfUtils.java +++ b/subprojects/store/src/main/java/tools/refinery/store/query/DnfUtils.java @@ -1,5 +1,6 @@ package tools.refinery.store.query; +import java.util.Map; import java.util.UUID; public final class DnfUtils { @@ -16,4 +17,8 @@ public final class DnfUtils { return originalName + uniqueString; } } + + public static Variable maybeSubstitute(Variable variable, Map substitution) { + return substitution.getOrDefault(variable, variable); + } } 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 index 59120434..5e1ae94d 100644 --- 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 @@ -1,28 +1,30 @@ package tools.refinery.store.query.literal; -import tools.refinery.store.query.Variable; +import tools.refinery.store.query.DnfUtils; import tools.refinery.store.query.RelationLike; +import tools.refinery.store.query.Variable; import java.util.List; +import java.util.Map; 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; + private final List arguments; - protected CallLiteral(CallPolarity polarity, T target, List substitution) { - if (substitution.size() != target.arity()) { + protected CallLiteral(CallPolarity polarity, T target, List arguments) { + if (arguments.size() != target.arity()) { throw new IllegalArgumentException("%s needs %d arguments, but got %s".formatted(target.name(), - target.arity(), substitution.size())); + target.arity(), arguments.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; + this.arguments = arguments; } public CallPolarity getPolarity() { @@ -33,28 +35,32 @@ public abstract class CallLiteral implements Literal { return target; } - public List getSubstitution() { - return substitution; + public List getArguments() { + return arguments; } @Override public void collectAllVariables(Set variables) { if (polarity.isPositive()) { - variables.addAll(substitution); + variables.addAll(arguments); } } + protected List substituteArguments(Map substitution) { + return arguments.stream().map(variable -> DnfUtils.maybeSubstitute(variable, substitution)).toList(); + } + @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); + Objects.equals(arguments, callAtom.arguments); } @Override public int hashCode() { - return Objects.hash(polarity, target, substitution); + return Objects.hash(polarity, target, arguments); } } 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 index 41426fdd..746d23af 100644 --- 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 @@ -1,7 +1,9 @@ package tools.refinery.store.query.literal; +import tools.refinery.store.query.DnfUtils; import tools.refinery.store.query.Variable; +import java.util.Map; import java.util.Set; public record ConstantLiteral(Variable variable, int nodeId) implements Literal { @@ -9,4 +11,9 @@ public record ConstantLiteral(Variable variable, int nodeId) implements Literal public void collectAllVariables(Set variables) { variables.add(variable); } + + @Override + public ConstantLiteral substitute(Map substitution) { + return new ConstantLiteral(DnfUtils.maybeSubstitute(variable, substitution), nodeId); + } } 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 index 86149b33..40499222 100644 --- 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 @@ -4,14 +4,20 @@ import tools.refinery.store.query.Dnf; import tools.refinery.store.query.Variable; import java.util.List; +import java.util.Map; public final class DnfCallLiteral extends CallLiteral implements PolarLiteral { - public DnfCallLiteral(CallPolarity polarity, Dnf target, List substitution) { - super(polarity, target, substitution); + public DnfCallLiteral(CallPolarity polarity, Dnf target, List arguments) { + super(polarity, target, arguments); + } + + @Override + public DnfCallLiteral substitute(Map substitution) { + return new DnfCallLiteral(getPolarity(), getTarget(), substituteArguments(substitution)); } @Override public DnfCallLiteral negate() { - return new DnfCallLiteral(getPolarity().negate(), getTarget(), getSubstitution()); + return new DnfCallLiteral(getPolarity().negate(), getTarget(), getArguments()); } } 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 index 75afd50b..5fee54b1 100644 --- 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 @@ -1,7 +1,9 @@ package tools.refinery.store.query.literal; +import tools.refinery.store.query.DnfUtils; import tools.refinery.store.query.Variable; +import java.util.Map; import java.util.Set; public record EquivalenceLiteral(boolean positive, Variable left, Variable right) @@ -16,4 +18,10 @@ public record EquivalenceLiteral(boolean positive, Variable left, Variable right public EquivalenceLiteral negate() { return new EquivalenceLiteral(!positive, left, right); } + + @Override + public EquivalenceLiteral substitute(Map substitution) { + return new EquivalenceLiteral(positive, DnfUtils.maybeSubstitute(left, substitution), + DnfUtils.maybeSubstitute(right, substitution)); + } } 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 index 676ac7fd..e0f5f605 100644 --- 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 @@ -2,8 +2,11 @@ package tools.refinery.store.query.literal; import tools.refinery.store.query.Variable; +import java.util.Map; import java.util.Set; public interface Literal { void collectAllVariables(Set variables); + + Literal substitute(Map substitution); } 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 deleted file mode 100644 index 93826161..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/query/literal/Modality.java +++ /dev/null @@ -1,22 +0,0 @@ -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 index 7fa99abb..4718b550 100644 --- 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 @@ -4,15 +4,21 @@ import tools.refinery.store.query.Variable; import tools.refinery.store.query.view.AnyRelationView; import java.util.List; +import java.util.Map; public final class RelationViewLiteral extends CallLiteral implements PolarLiteral { - public RelationViewLiteral(CallPolarity polarity, AnyRelationView target, List substitution) { - super(polarity, target, substitution); + public RelationViewLiteral(CallPolarity polarity, AnyRelationView target, List arguments) { + super(polarity, target, arguments); + } + + @Override + public RelationViewLiteral substitute(Map substitution) { + return new RelationViewLiteral(getPolarity(), getTarget(), substituteArguments(substitution)); } @Override public RelationViewLiteral negate() { - return new RelationViewLiteral(getPolarity().negate(), getTarget(), getSubstitution()); + return new RelationViewLiteral(getPolarity().negate(), getTarget(), getArguments()); } } diff --git a/subprojects/store/src/main/java/tools/refinery/store/query/view/RelationView.java b/subprojects/store/src/main/java/tools/refinery/store/query/view/RelationView.java index 0bea962d..6accd27a 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/query/view/RelationView.java +++ b/subprojects/store/src/main/java/tools/refinery/store/query/view/RelationView.java @@ -51,16 +51,16 @@ public abstract non-sealed class RelationView implements AnyRelationView { return (() -> new CursorAsIterator<>(model.getInterpretation(symbol).getAll(), this::forwardMap, this::filter)); } - public RelationViewLiteral call(CallPolarity polarity, List substitution) { - return new RelationViewLiteral(polarity, this, substitution); + public RelationViewLiteral call(CallPolarity polarity, List arguments) { + return new RelationViewLiteral(polarity, this, arguments); } - public RelationViewLiteral call(CallPolarity polarity, Variable... substitution) { - return call(polarity, List.of(substitution)); + public RelationViewLiteral call(CallPolarity polarity, Variable... arguments) { + return call(polarity, List.of(arguments)); } - public RelationViewLiteral call(Variable... substitution) { - return call(CallPolarity.POSITIVE, substitution); + public RelationViewLiteral call(Variable... arguments) { + return call(CallPolarity.POSITIVE, arguments); } public RelationViewLiteral callTransitive(Variable left, Variable right) { diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/AbstractDomain.java b/subprojects/store/src/main/java/tools/refinery/store/representation/AbstractDomain.java new file mode 100644 index 00000000..18903ead --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/representation/AbstractDomain.java @@ -0,0 +1,29 @@ +package tools.refinery.store.representation; + +import java.util.Optional; + +public non-sealed interface AbstractDomain extends AnyAbstractDomain { + @Override + Class abstractType(); + + @Override + Class concreteType(); + + A toAbstract(C concreteValue); + + Optional toConcrete(A abstractValue); + + default boolean isConcrete(A abstractValue) { + return toConcrete(abstractValue).isPresent(); + } + + boolean isRefinement(A originalValue, A refinedValue); + + A commonRefinement(A leftValue, A rightValue); + + A commonAncestor(A leftValue, A rightValue); + + A unknown(); + + boolean isError(A abstractValue); +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/AnyAbstractDomain.java b/subprojects/store/src/main/java/tools/refinery/store/representation/AnyAbstractDomain.java new file mode 100644 index 00000000..4c428a1e --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/representation/AnyAbstractDomain.java @@ -0,0 +1,7 @@ +package tools.refinery.store.representation; + +public sealed interface AnyAbstractDomain permits AbstractDomain { + Class abstractType(); + + Class concreteType(); +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValueDomain.java b/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValueDomain.java new file mode 100644 index 00000000..29858bce --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValueDomain.java @@ -0,0 +1,60 @@ +package tools.refinery.store.representation; + +import java.util.Optional; + +public final class TruthValueDomain implements AbstractDomain { + public static final TruthValueDomain INSTANCE = new TruthValueDomain(); + + private TruthValueDomain() { + } + + @Override + public Class abstractType() { + return null; + } + + @Override + public Class concreteType() { + return null; + } + + @Override + public TruthValue toAbstract(Boolean concreteValue) { + return null; + } + + @Override + public Optional toConcrete(TruthValue abstractValue) { + return Optional.empty(); + } + + @Override + public boolean isConcrete(TruthValue abstractValue) { + return AbstractDomain.super.isConcrete(abstractValue); + } + + @Override + public boolean isRefinement(TruthValue originalValue, TruthValue refinedValue) { + return false; + } + + @Override + public TruthValue commonRefinement(TruthValue leftValue, TruthValue rightValue) { + return null; + } + + @Override + public TruthValue commonAncestor(TruthValue leftValue, TruthValue rightValue) { + return null; + } + + @Override + public TruthValue unknown() { + return null; + } + + @Override + public boolean isError(TruthValue abstractValue) { + return false; + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java b/subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java new file mode 100644 index 00000000..e4b462f0 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java @@ -0,0 +1,51 @@ +package tools.refinery.store.util; + +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class CycleDetectingMapper { + private static final String SEPARATOR = " -> "; + + private final Function getName; + + private final Function doMap; + + private final Set inProgress = new LinkedHashSet<>(); + + private final Map results = new HashMap<>(); + + public CycleDetectingMapper(Function getName, Function doMap) { + this.getName = getName; + this.doMap = doMap; + } + + public R map(T input) { + if (inProgress.contains(input)) { + var path = inProgress.stream().map(getName).collect(Collectors.joining(SEPARATOR)); + throw new IllegalArgumentException("Circular reference %s%s%s detected".formatted(path, SEPARATOR, + getName.apply(input))); + } + // We can't use computeIfAbsent here, because translating referenced queries calls this method in a reentrant + // way, which would cause a ConcurrentModificationException with computeIfAbsent. + @SuppressWarnings("squid:S3824") + var result = results.get(input); + if (result == null) { + inProgress.add(input); + try { + result = doMap.apply(input); + results.put(input, result); + } finally { + inProgress.remove(input); + } + } + return result; + } + + public R getAlreadyMapped(T input) { + return results.get(input); + } +} -- cgit v1.2.3-70-g09d2 From f8a3c575e400259a4985233c07b7a50e5d4d82c5 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Fri, 24 Feb 2023 20:21:15 +0100 Subject: feat: Dnf reduction and structural equality --- .../store/partial/literal/ModalDnfCallLiteral.java | 15 +- .../store/partial/literal/ModalLiteral.java | 18 ++ .../partial/literal/ModalRelationLiteral.java | 10 +- .../partial/literal/PartialRelationLiteral.java | 9 +- .../TypeAnalyzerExampleHierarchyTest.java | 61 +++--- .../translator/typehierarchy/TypeAnalyzerTest.java | 9 +- .../internal/ViatraModelQueryAdapterImpl.java | 9 +- .../internal/ViatraModelQueryBuilderImpl.java | 29 ++- .../internal/ViatraModelQueryStoreAdapterImpl.java | 19 +- .../refinery/store/query/viatra/QueryTest.java | 40 ++++ subprojects/store-query/build.gradle | 2 + .../main/java/tools/refinery/store/query/Dnf.java | 65 +++++- .../tools/refinery/store/query/DnfBuilder.java | 33 ++-- .../java/tools/refinery/store/query/DnfClause.java | 13 ++ .../java/tools/refinery/store/query/DnfUtils.java | 5 - .../tools/refinery/store/query/EmptyResultSet.java | 49 +++++ .../java/tools/refinery/store/query/Variable.java | 15 +- .../query/equality/DeepDnfEqualityChecker.java | 31 +++ .../store/query/equality/DnfEqualityChecker.java | 8 + .../query/equality/LiteralEqualityHelper.java | 48 +++++ .../store/query/literal/BooleanLiteral.java | 34 +++- .../refinery/store/query/literal/CallLiteral.java | 75 ++++++- .../store/query/literal/ConstantLiteral.java | 22 ++- .../store/query/literal/DnfCallLiteral.java | 15 +- .../store/query/literal/EquivalenceLiteral.java | 24 ++- .../refinery/store/query/literal/Literal.java | 8 +- .../store/query/literal/RelationViewLiteral.java | 15 +- .../query/substitution/MapBasedSubstitution.java | 13 ++ .../query/substitution/RenewingSubstitution.java | 19 ++ .../query/substitution/StatelessSubstitution.java | 18 ++ .../store/query/substitution/Substitution.java | 8 + .../store/query/substitution/Substitutions.java | 27 +++ .../refinery/store/query/view/AnyRelationView.java | 2 + .../refinery/store/query/view/RelationView.java | 17 +- .../tools/refinery/store/query/DnfBuilderTest.java | 218 +++++++++++++++++++++ .../refinery/store/query/DnfToStringTest.java | 172 ++++++++++++++++ .../store/query/tests/StructurallyEqualToTest.java | 77 ++++++++ .../MismatchDescribingDnfEqualityChecker.java | 43 ++++ .../refinery/store/query/tests/QueryMatchers.java | 14 ++ .../store/query/tests/StructurallyEqualTo.java | 36 ++++ .../refinery/store/util/CycleDetectingMapper.java | 9 +- 41 files changed, 1236 insertions(+), 118 deletions(-) create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java create mode 100644 subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java create mode 100644 subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToStringTest.java create mode 100644 subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java create mode 100644 subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java create mode 100644 subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java create mode 100644 subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java (limited to 'subprojects/store-query-viatra/src/main/java/tools') diff --git a/subprojects/store-partial/src/main/java/tools/refinery/store/partial/literal/ModalDnfCallLiteral.java b/subprojects/store-partial/src/main/java/tools/refinery/store/partial/literal/ModalDnfCallLiteral.java index a49e0625..8c157187 100644 --- a/subprojects/store-partial/src/main/java/tools/refinery/store/partial/literal/ModalDnfCallLiteral.java +++ b/subprojects/store-partial/src/main/java/tools/refinery/store/partial/literal/ModalDnfCallLiteral.java @@ -2,13 +2,14 @@ package tools.refinery.store.partial.literal; import tools.refinery.store.query.Dnf; import tools.refinery.store.query.Variable; +import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.literal.CallPolarity; import tools.refinery.store.query.literal.DnfCallLiteral; import tools.refinery.store.query.literal.LiteralReduction; import tools.refinery.store.query.literal.PolarLiteral; +import tools.refinery.store.query.substitution.Substitution; import java.util.List; -import java.util.Map; public class ModalDnfCallLiteral extends ModalLiteral implements PolarLiteral { public ModalDnfCallLiteral(CallPolarity polarity, Modality modality, Dnf target, List arguments) { @@ -20,7 +21,17 @@ public class ModalDnfCallLiteral extends ModalLiteral implements PolarLiter } @Override - public ModalDnfCallLiteral substitute(Map substitution) { + public Class getTargetType() { + return Dnf.class; + } + + @Override + protected boolean targetEquals(LiteralEqualityHelper helper, Dnf otherTarget) { + return helper.dnfEqual(getTarget(), otherTarget); + } + + @Override + public ModalDnfCallLiteral substitute(Substitution substitution) { return new ModalDnfCallLiteral(getPolarity(), getModality(), getTarget(), substituteArguments(substitution)); } diff --git a/subprojects/store-partial/src/main/java/tools/refinery/store/partial/literal/ModalLiteral.java b/subprojects/store-partial/src/main/java/tools/refinery/store/partial/literal/ModalLiteral.java index a1b6c83e..cebe9c9d 100644 --- a/subprojects/store-partial/src/main/java/tools/refinery/store/partial/literal/ModalLiteral.java +++ b/subprojects/store-partial/src/main/java/tools/refinery/store/partial/literal/ModalLiteral.java @@ -2,8 +2,10 @@ package tools.refinery.store.partial.literal; import tools.refinery.store.query.RelationLike; import tools.refinery.store.query.Variable; +import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.literal.CallLiteral; import tools.refinery.store.query.literal.CallPolarity; +import tools.refinery.store.query.literal.Literal; import java.util.List; import java.util.Objects; @@ -25,6 +27,22 @@ public abstract class ModalLiteral extends CallLiteral) other; + return modality == otherModalLiteral.modality; + } + + @Override + protected String targetToString() { + return "%s %s".formatted(modality, super.targetToString()); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/subprojects/store-partial/src/main/java/tools/refinery/store/partial/literal/ModalRelationLiteral.java b/subprojects/store-partial/src/main/java/tools/refinery/store/partial/literal/ModalRelationLiteral.java index dbaa524f..39054f22 100644 --- a/subprojects/store-partial/src/main/java/tools/refinery/store/partial/literal/ModalRelationLiteral.java +++ b/subprojects/store-partial/src/main/java/tools/refinery/store/partial/literal/ModalRelationLiteral.java @@ -4,9 +4,9 @@ import tools.refinery.store.partial.representation.PartialRelation; import tools.refinery.store.query.Variable; import tools.refinery.store.query.literal.CallPolarity; import tools.refinery.store.query.literal.PolarLiteral; +import tools.refinery.store.query.substitution.Substitution; import java.util.List; -import java.util.Map; public final class ModalRelationLiteral extends ModalLiteral implements PolarLiteral { @@ -15,12 +15,18 @@ public final class ModalRelationLiteral extends ModalLiteral super(polarity, modality, target, arguments); } + public ModalRelationLiteral(Modality modality, PartialRelationLiteral baseLiteral) { super(modality, baseLiteral); } @Override - public ModalRelationLiteral substitute(Map substitution) { + public Class getTargetType() { + return PartialRelation.class; + } + + @Override + public ModalRelationLiteral substitute(Substitution substitution) { return new ModalRelationLiteral(getPolarity(), getModality(), getTarget(), substituteArguments(substitution)); } diff --git a/subprojects/store-partial/src/main/java/tools/refinery/store/partial/literal/PartialRelationLiteral.java b/subprojects/store-partial/src/main/java/tools/refinery/store/partial/literal/PartialRelationLiteral.java index dc1a1da3..b81d9a3d 100644 --- a/subprojects/store-partial/src/main/java/tools/refinery/store/partial/literal/PartialRelationLiteral.java +++ b/subprojects/store-partial/src/main/java/tools/refinery/store/partial/literal/PartialRelationLiteral.java @@ -5,9 +5,9 @@ import tools.refinery.store.query.Variable; import tools.refinery.store.query.literal.CallLiteral; import tools.refinery.store.query.literal.CallPolarity; import tools.refinery.store.query.literal.PolarLiteral; +import tools.refinery.store.query.substitution.Substitution; import java.util.List; -import java.util.Map; public final class PartialRelationLiteral extends CallLiteral implements PolarLiteral { @@ -16,7 +16,12 @@ public final class PartialRelationLiteral extends CallLiteral } @Override - public PartialRelationLiteral substitute(Map substitution) { + public Class getTargetType() { + return PartialRelation.class; + } + + @Override + public PartialRelationLiteral substitute(Substitution substitution) { return new PartialRelationLiteral(getPolarity(), getTarget(), substituteArguments(substitution)); } diff --git a/subprojects/store-partial/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerExampleHierarchyTest.java b/subprojects/store-partial/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerExampleHierarchyTest.java index ad81e28f..5f528328 100644 --- a/subprojects/store-partial/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerExampleHierarchyTest.java +++ b/subprojects/store-partial/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerExampleHierarchyTest.java @@ -1,6 +1,5 @@ package tools.refinery.store.partial.translator.typehierarchy; -import org.hamcrest.Matchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import tools.refinery.store.partial.representation.PartialRelation; @@ -61,16 +60,16 @@ class TypeAnalyzerExampleHierarchyTest { @Test void inferredTypesTest() { assertAll( - () -> assertThat(sut.getUnknownType(), Matchers.is(new InferredType(Set.of(), Set.of(c1, c2, c3, c4), null))), - () -> assertThat(tester.getInferredType(a1), Matchers.is(new InferredType(Set.of(a1, a4), Set.of(c1, c2), c1))), - () -> assertThat(tester.getInferredType(a3), Matchers.is(new InferredType(Set.of(a3), Set.of(c2, c3), c2))), - () -> assertThat(tester.getInferredType(a4), Matchers.is(new InferredType(Set.of(a4), Set.of(c1, c2, c4), c1))), - () -> assertThat(tester.getInferredType(a5), Matchers.is(new InferredType(Set.of(a5), Set.of(), null))), - () -> assertThat(tester.getInferredType(c1), Matchers.is(new InferredType(Set.of(a1, a4, c1), Set.of(c1), c1))), + () -> assertThat(sut.getUnknownType(), is(new InferredType(Set.of(), Set.of(c1, c2, c3, c4), null))), + () -> assertThat(tester.getInferredType(a1), is(new InferredType(Set.of(a1, a4), Set.of(c1, c2), c1))), + () -> assertThat(tester.getInferredType(a3), is(new InferredType(Set.of(a3), Set.of(c2, c3), c2))), + () -> assertThat(tester.getInferredType(a4), is(new InferredType(Set.of(a4), Set.of(c1, c2, c4), c1))), + () -> assertThat(tester.getInferredType(a5), is(new InferredType(Set.of(a5), Set.of(), null))), + () -> assertThat(tester.getInferredType(c1), is(new InferredType(Set.of(a1, a4, c1), Set.of(c1), c1))), () -> assertThat(tester.getInferredType(c2), - Matchers.is(new InferredType(Set.of(a1, a3, a4, c2), Set.of(c2), c2))), - () -> assertThat(tester.getInferredType(c3), Matchers.is(new InferredType(Set.of(a3, c3), Set.of(c3), c3))), - () -> assertThat(tester.getInferredType(c4), Matchers.is(new InferredType(Set.of(a4, c4), Set.of(c4), c4))) + is(new InferredType(Set.of(a1, a3, a4, c2), Set.of(c2), c2))), + () -> assertThat(tester.getInferredType(c3), is(new InferredType(Set.of(a3, c3), Set.of(c3), c3))), + () -> assertThat(tester.getInferredType(c4), is(new InferredType(Set.of(a4, c4), Set.of(c4), c4))) ); } @@ -80,8 +79,8 @@ class TypeAnalyzerExampleHierarchyTest { var a3Result = tester.getPreservedType(a3); var expected = new InferredType(Set.of(a1, a3, a4, c2), Set.of(c2), c2); assertAll( - () -> assertThat(a1Result.merge(a3Result.asInferredType(), TruthValue.TRUE), Matchers.is(expected)), - () -> assertThat(a3Result.merge(a1Result.asInferredType(), TruthValue.TRUE), Matchers.is(expected)), + () -> assertThat(a1Result.merge(a3Result.asInferredType(), TruthValue.TRUE), is(expected)), + () -> assertThat(a3Result.merge(a1Result.asInferredType(), TruthValue.TRUE), is(expected)), () -> assertThat(a1Result.merge(sut.getUnknownType(), TruthValue.TRUE), is(a1Result.asInferredType())), () -> assertThat(a3Result.merge(sut.getUnknownType(), TruthValue.TRUE), is(a3Result.asInferredType())), () -> assertThat(a1Result.merge(a1Result.asInferredType(), TruthValue.TRUE), @@ -96,19 +95,19 @@ class TypeAnalyzerExampleHierarchyTest { var a4Result = tester.getPreservedType(a4); assertAll( () -> assertThat(a1Result.merge(a3Result.asInferredType(), TruthValue.FALSE), - Matchers.is(new InferredType(Set.of(a3, c3), Set.of(c3), c3))), + is(new InferredType(Set.of(a3, c3), Set.of(c3), c3))), () -> assertThat(a3Result.merge(a1Result.asInferredType(), TruthValue.FALSE), - Matchers.is(new InferredType(Set.of(a1, a4, c1), Set.of(c1), c1))), + is(new InferredType(Set.of(a1, a4, c1), Set.of(c1), c1))), () -> assertThat(a4Result.merge(a3Result.asInferredType(), TruthValue.FALSE), - Matchers.is(new InferredType(Set.of(a3, c3), Set.of(c3), c3))), + is(new InferredType(Set.of(a3, c3), Set.of(c3), c3))), () -> assertThat(a3Result.merge(a4Result.asInferredType(), TruthValue.FALSE), - Matchers.is(new InferredType(Set.of(a4), Set.of(c1, c4), c1))), + is(new InferredType(Set.of(a4), Set.of(c1, c4), c1))), () -> assertThat(a1Result.merge(sut.getUnknownType(), TruthValue.FALSE), - Matchers.is(new InferredType(Set.of(), Set.of(c3, c4), null))), + is(new InferredType(Set.of(), Set.of(c3, c4), null))), () -> assertThat(a3Result.merge(sut.getUnknownType(), TruthValue.FALSE), - Matchers.is(new InferredType(Set.of(), Set.of(c1, c4), null))), + is(new InferredType(Set.of(), Set.of(c1, c4), null))), () -> assertThat(a4Result.merge(sut.getUnknownType(), TruthValue.FALSE), - Matchers.is(new InferredType(Set.of(), Set.of(c3), null))) + is(new InferredType(Set.of(), Set.of(c3), null))) ); } @@ -118,8 +117,8 @@ class TypeAnalyzerExampleHierarchyTest { var a4Result = tester.getPreservedType(a4); var expected = new InferredType(Set.of(c1, a1, a4), Set.of(), null); assertAll( - () -> assertThat(c1Result.merge(a4Result.asInferredType(), TruthValue.ERROR), Matchers.is(expected)), - () -> assertThat(a4Result.merge(c1Result.asInferredType(), TruthValue.ERROR), Matchers.is(expected)) + () -> assertThat(c1Result.merge(a4Result.asInferredType(), TruthValue.ERROR), is(expected)), + () -> assertThat(a4Result.merge(c1Result.asInferredType(), TruthValue.ERROR), is(expected)) ); } @@ -141,9 +140,9 @@ class TypeAnalyzerExampleHierarchyTest { var c3Result = tester.getPreservedType(c3); assertAll( () -> assertThat(a1Result.merge(c3Result.asInferredType(), TruthValue.TRUE), - Matchers.is(new InferredType(Set.of(a1, a3, c3), Set.of(), null))), + is(new InferredType(Set.of(a1, a3, c3), Set.of(), null))), () -> assertThat(c3Result.merge(a1Result.asInferredType(), TruthValue.TRUE), - Matchers.is(new InferredType(Set.of(a1, a3, a4, c3), Set.of(), null))) + is(new InferredType(Set.of(a1, a3, a4, c3), Set.of(), null))) ); } @@ -154,13 +153,13 @@ class TypeAnalyzerExampleHierarchyTest { var c1Result = tester.getPreservedType(c1); assertAll( () -> assertThat(a4Result.merge(a1Result.asInferredType(), TruthValue.FALSE), - Matchers.is(new InferredType(Set.of(a1, a4), Set.of(), null))), + is(new InferredType(Set.of(a1, a4), Set.of(), null))), () -> assertThat(a1Result.merge(c1Result.asInferredType(), TruthValue.FALSE), - Matchers.is(new InferredType(Set.of(a1, a4, c1), Set.of(), null))), + is(new InferredType(Set.of(a1, a4, c1), Set.of(), null))), () -> assertThat(a4Result.merge(c1Result.asInferredType(), TruthValue.FALSE), - Matchers.is(new InferredType(Set.of(a1, a4, c1), Set.of(), null))), + is(new InferredType(Set.of(a1, a4, c1), Set.of(), null))), () -> assertThat(a1Result.merge(a1Result.asInferredType(), TruthValue.FALSE), - Matchers.is(new InferredType(Set.of(a1, a4), Set.of(), null))) + is(new InferredType(Set.of(a1, a4), Set.of(), null))) ); } @@ -170,9 +169,9 @@ class TypeAnalyzerExampleHierarchyTest { var a5Result = tester.getPreservedType(a5); assertAll( () -> assertThat(c1Result.merge(a5Result.asInferredType(), TruthValue.TRUE), - Matchers.is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))), + is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))), () -> assertThat(a5Result.merge(c1Result.asInferredType(), TruthValue.TRUE), - Matchers.is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))) + is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))) ); } @@ -194,9 +193,9 @@ class TypeAnalyzerExampleHierarchyTest { var a5Result = tester.getPreservedType(a5); assertAll( () -> assertThat(c1Result.merge(a5Result.asInferredType(), TruthValue.ERROR), - Matchers.is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))), + is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))), () -> assertThat(a5Result.merge(c1Result.asInferredType(), TruthValue.ERROR), - Matchers.is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))), + is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))), () -> assertThat(a5Result.merge(a5Result.asInferredType(), TruthValue.ERROR), is(a5Result.asInferredType())) ); diff --git a/subprojects/store-partial/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerTest.java b/subprojects/store-partial/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerTest.java index 1aab75bb..02903026 100644 --- a/subprojects/store-partial/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerTest.java +++ b/subprojects/store-partial/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerTest.java @@ -1,6 +1,5 @@ package tools.refinery.store.partial.translator.typehierarchy; -import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import tools.refinery.store.partial.representation.PartialRelation; import tools.refinery.store.representation.TruthValue; @@ -137,8 +136,8 @@ class TypeAnalyzerTest { var expected = new InferredType(Set.of(c3), Set.of(c1, c2, c3), c3); assertAll( - () -> assertThat(tester.getInferredType(c3), Matchers.is(expected)), - () -> assertThat(c3Result.merge(sut.getUnknownType(), TruthValue.TRUE), Matchers.is(expected)) + () -> assertThat(tester.getInferredType(c3), is(expected)), + () -> assertThat(c3Result.merge(sut.getUnknownType(), TruthValue.TRUE), is(expected)) ); } @@ -162,7 +161,7 @@ class TypeAnalyzerTest { var a1Result = tester.getPreservedType(a1); assertThat(c1Result.merge(a1Result.asInferredType(), TruthValue.FALSE), - Matchers.is(new InferredType(Set.of(a1), Set.of(c2, c3, c4), c2))); + is(new InferredType(Set.of(a1), Set.of(c2, c3, c4), c2))); } @Test @@ -185,7 +184,7 @@ class TypeAnalyzerTest { var a1Result = tester.getPreservedType(a1); assertThat(c1Result.merge(a1Result.asInferredType(), TruthValue.FALSE), - Matchers.is(new InferredType(Set.of(a1), Set.of(c2, c3, c4), c3))); + is(new InferredType(Set.of(a1), Set.of(c2, c3, c4), c3))); } @Test 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 e5d8e2f6..e0341598 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 @@ -8,6 +8,7 @@ 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.EmptyResultSet; import tools.refinery.store.query.ResultSet; import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; @@ -15,7 +16,7 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; public class ViatraModelQueryAdapterImpl implements ViatraModelQueryAdapter { @@ -51,11 +52,15 @@ public class ViatraModelQueryAdapterImpl implements ViatraModelQueryAdapter { GenericQueryGroup.of( Collections.>unmodifiableCollection(querySpecifications.values()).stream() ).prepare(queryEngine); - resultSets = new HashMap<>(querySpecifications.size()); + var vacuousQueries = storeAdapter.getVacuousQueries(); + resultSets = new LinkedHashMap<>(querySpecifications.size() + vacuousQueries.size()); for (var entry : querySpecifications.entrySet()) { var matcher = queryEngine.getMatcher(entry.getValue()); resultSets.put(entry.getKey(), matcher); } + for (var vacuousQuery : vacuousQueries) { + resultSets.put(vacuousQuery, new EmptyResultSet()); + } setUpdatePropagationDelayed(true); } 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 af20033a..13641ace 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 @@ -14,14 +14,13 @@ import tools.refinery.store.query.viatra.ViatraModelQueryBuilder; import tools.refinery.store.query.viatra.internal.pquery.Dnf2PQuery; import tools.refinery.store.query.viatra.internal.pquery.RawPatternMatcher; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.*; import java.util.function.Function; public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder implements ViatraModelQueryBuilder { private ViatraQueryEngineOptions.Builder engineOptionsBuilder; private final Dnf2PQuery dnf2PQuery = new Dnf2PQuery(); + private final Set vacuousQueries = new LinkedHashSet<>(); private final Map> querySpecifications = new LinkedHashMap<>(); public ViatraModelQueryBuilderImpl(ModelStoreBuilder storeBuilder) { @@ -64,11 +63,21 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp @Override public ViatraModelQueryBuilder query(Dnf query) { - if (querySpecifications.containsKey(query)) { - throw new IllegalArgumentException("%s was already added to the query engine".formatted(query.name())); + if (querySpecifications.containsKey(query) || vacuousQueries.contains(query)) { + // Ignore duplicate queries. + return this; + } + var reduction = query.getReduction(); + switch (reduction) { + case NOT_REDUCIBLE -> { + var pQuery = dnf2PQuery.translate(query); + querySpecifications.put(query, pQuery.build()); + } + case ALWAYS_FALSE -> vacuousQueries.add(query); + case ALWAYS_TRUE -> throw new IllegalArgumentException( + "Query %s is relationally unsafe (it matches every tuple)".formatted(query.name())); + default -> throw new IllegalArgumentException("Unknown reduction: " + reduction); } - var pQuery = dnf2PQuery.translate(query); - querySpecifications.put(query, pQuery.build()); return this; } @@ -89,6 +98,10 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp public ViatraModelQueryBuilder hint(Dnf dnf, QueryEvaluationHint queryEvaluationHint) { var pQuery = dnf2PQuery.getAlreadyTranslated(dnf); if (pQuery == null) { + if (vacuousQueries.contains(dnf)) { + // Ignore hits for queries that will never be executed by the query engine. + return this; + } throw new IllegalArgumentException( "Cannot specify hint for %s, because it was not added to the query engine".formatted(dnf.name())); } @@ -100,7 +113,7 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp public ViatraModelQueryStoreAdapterImpl createStoreAdapter(ModelStore store) { validateSymbols(store); return new ViatraModelQueryStoreAdapterImpl(store, engineOptionsBuilder.build(), dnf2PQuery.getRelationViews(), - Collections.unmodifiableMap(querySpecifications)); + Collections.unmodifiableMap(querySpecifications), Collections.unmodifiableSet(vacuousQueries)); } private void validateSymbols(ModelStore store) { 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 8323118b..00660d0b 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 @@ -10,22 +10,29 @@ import tools.refinery.store.query.viatra.ViatraModelQueryStoreAdapter; import tools.refinery.store.query.viatra.internal.pquery.RawPatternMatcher; import tools.refinery.store.query.view.AnyRelationView; -import java.util.Collection; -import java.util.Map; +import java.util.*; public class ViatraModelQueryStoreAdapterImpl implements ViatraModelQueryStoreAdapter { private final ModelStore store; private final ViatraQueryEngineOptions engineOptions; private final Map inputKeys; private final Map> querySpecifications; + private final Set vacuousQueries; + private final Set allQueries; ViatraModelQueryStoreAdapterImpl(ModelStore store, ViatraQueryEngineOptions engineOptions, Map inputKeys, - Map> querySpecifications) { + Map> querySpecifications, + Set vacuousQueries) { this.store = store; this.engineOptions = engineOptions; this.inputKeys = inputKeys; this.querySpecifications = querySpecifications; + this.vacuousQueries = vacuousQueries; + var mutableAllQueries = new LinkedHashSet(querySpecifications.size() + vacuousQueries.size()); + mutableAllQueries.addAll(querySpecifications.keySet()); + mutableAllQueries.addAll(vacuousQueries); + this.allQueries = Collections.unmodifiableSet(mutableAllQueries); } @Override @@ -43,13 +50,17 @@ public class ViatraModelQueryStoreAdapterImpl implements ViatraModelQueryStoreAd @Override public Collection getQueries() { - return querySpecifications.keySet(); + return allQueries; } Map> getQuerySpecifications() { return querySpecifications; } + Set getVacuousQueries() { + return vacuousQueries; + } + @Override public ViatraQueryEngineOptions getEngineOptions() { return engineOptions; 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 6a3a62e3..54ae70c3 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 @@ -17,6 +17,7 @@ import java.util.Set; import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static tools.refinery.store.query.literal.Literals.not; class QueryTest { @@ -669,6 +670,45 @@ class QueryTest { assertEquals(3, predicateResultSet.countResults()); } + @Test + void alwaysFalseTest() { + var person = new Symbol<>("Person", 1, Boolean.class, false); + + var p1 = new Variable("p1"); + var predicate = Dnf.builder("AlwaysFalse").parameters(p1).build(); + + var store = ModelStore.builder() + .symbols(person) + .with(ViatraModelQuery.ADAPTER) + .queries(predicate) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var predicateResultSet = queryEngine.getResultSet(predicate); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + personInterpretation.put(Tuple.of(2), true); + + queryEngine.flushChanges(); + assertEquals(0, predicateResultSet.countResults()); + } + + @Test + void alwaysTrueTest() { + var person = new Symbol<>("Person", 1, Boolean.class, false); + + var p1 = new Variable("p1"); + var predicate = Dnf.builder("AlwaysTrue").parameters(p1).clause().build(); + + var storeBuilder = ModelStore.builder().symbols(person); + var queryBuilder = storeBuilder.with(ViatraModelQuery.ADAPTER); + + assertThrows(IllegalArgumentException.class, () -> queryBuilder.queries(predicate)); + } + static void compareMatchSets(Stream matchSet, Set expected) { Set translatedMatchSet = new HashSet<>(); var iterator = matchSet.iterator(); diff --git a/subprojects/store-query/build.gradle b/subprojects/store-query/build.gradle index 2b76e608..97761936 100644 --- a/subprojects/store-query/build.gradle +++ b/subprojects/store-query/build.gradle @@ -1,7 +1,9 @@ plugins { id 'refinery-java-library' + id 'refinery-java-test-fixtures' } dependencies { api project(':refinery-store') + testFixturesApi libs.hamcrest } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/Dnf.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/Dnf.java index 760b264b..b6744b50 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/Dnf.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/Dnf.java @@ -1,5 +1,7 @@ package tools.refinery.store.query; +import tools.refinery.store.query.equality.DnfEqualityChecker; +import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.literal.CallPolarity; import tools.refinery.store.query.literal.DnfCallLiteral; import tools.refinery.store.query.literal.LiteralReduction; @@ -7,6 +9,8 @@ import tools.refinery.store.query.literal.LiteralReduction; import java.util.*; public final class Dnf implements RelationLike { + private static final String INDENTATION = " "; + private final String name; private final String uniqueName; @@ -50,7 +54,11 @@ public final class Dnf implements RelationLike { @Override public String name() { - return name; + return name == null ? uniqueName : name; + } + + public boolean isExplicitlyNamed() { + return name == null; } public String getUniqueName() { @@ -102,6 +110,61 @@ public final class Dnf implements RelationLike { return call(CallPolarity.TRANSITIVE, List.of(left, right)); } + public boolean equalsWithSubstitution(DnfEqualityChecker callEqualityChecker, Dnf other) { + if (arity() != other.arity()) { + return false; + } + int numClauses = clauses.size(); + if (numClauses != other.clauses.size()) { + return false; + } + for (int i = 0; i < numClauses; i++) { + var literalEqualityHelper = new LiteralEqualityHelper(callEqualityChecker, parameters, other.parameters); + if (!clauses.get(i).equalsWithSubstitution(literalEqualityHelper, other.clauses.get(i))) { + return false; + } + } + return true; + } + + @Override + public String toString() { + var builder = new StringBuilder(); + builder.append("pred ").append(name()).append("("); + var parameterIterator = parameters.iterator(); + if (parameterIterator.hasNext()) { + builder.append(parameterIterator.next()); + while (parameterIterator.hasNext()) { + builder.append(", ").append(parameterIterator.next()); + } + } + builder.append(") <->"); + var clauseIterator = clauses.iterator(); + if (clauseIterator.hasNext()) { + appendClause(clauseIterator.next(), builder); + while (clauseIterator.hasNext()) { + builder.append("\n;"); + appendClause(clauseIterator.next(), builder); + } + } else { + builder.append("\n").append(INDENTATION).append(""); + } + builder.append(".\n"); + return builder.toString(); + } + + private static void appendClause(DnfClause clause, StringBuilder builder) { + var iterator = clause.literals().iterator(); + if (!iterator.hasNext()) { + builder.append("\n").append(INDENTATION).append(""); + return; + } + builder.append("\n").append(INDENTATION).append(iterator.next()); + while (iterator.hasNext()) { + builder.append(",\n").append(INDENTATION).append(iterator.next()); + } + } + public static DnfBuilder builder() { return builder(null); } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfBuilder.java index b18b5177..ca47e979 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfBuilder.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfBuilder.java @@ -52,7 +52,8 @@ public class DnfBuilder { } public DnfBuilder clause(Collection literals) { - var filteredLiterals = new ArrayList(literals.size()); + // Remove duplicates by using a hashed data structure. + var filteredLiterals = new LinkedHashSet(literals.size()); for (var literal : literals) { var reduction = literal.getReduction(); switch (reduction) { @@ -65,10 +66,10 @@ public class DnfBuilder { // Clauses with {@code false} literals can be omitted entirely. return this; } - default -> throw new IllegalStateException("Invalid reduction %s".formatted(reduction)); + default -> throw new IllegalArgumentException("Invalid reduction: " + reduction); } } - clauses.add(Collections.unmodifiableList(filteredLiterals)); + clauses.add(List.copyOf(filteredLiterals)); return this; } @@ -77,10 +78,7 @@ public class DnfBuilder { } public DnfBuilder clauses(DnfClause... clauses) { - for (var clause : clauses) { - this.clause(clause); - } - return this; + return clauses(List.of(clauses)); } public DnfBuilder clauses(Collection clauses) { @@ -91,18 +89,27 @@ public class DnfBuilder { } public Dnf build() { + var postProcessedClauses = postProcessClauses(); + return new Dnf(name, Collections.unmodifiableList(parameters), + Collections.unmodifiableList(functionalDependencies), + Collections.unmodifiableList(postProcessedClauses)); + } + + private List postProcessClauses() { var postProcessedClauses = new ArrayList(clauses.size()); - for (var constraints : clauses) { + for (var literals : clauses) { + if (literals.isEmpty()) { + // Predicate will always match, the other clauses are irrelevant. + return List.of(new DnfClause(Set.of(), List.of())); + } var variables = new HashSet(); - for (var constraint : constraints) { + for (var constraint : literals) { constraint.collectAllVariables(variables); } parameters.forEach(variables::remove); postProcessedClauses.add(new DnfClause(Collections.unmodifiableSet(variables), - Collections.unmodifiableList(constraints))); + Collections.unmodifiableList(literals))); } - return new Dnf(name, Collections.unmodifiableList(parameters), - Collections.unmodifiableList(functionalDependencies), - Collections.unmodifiableList(postProcessedClauses)); + return postProcessedClauses; } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfClause.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfClause.java index 2ba6becc..c6e8b8c9 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfClause.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfClause.java @@ -1,9 +1,22 @@ package tools.refinery.store.query; +import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.literal.Literal; import java.util.List; import java.util.Set; public record DnfClause(Set quantifiedVariables, List literals) { + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, DnfClause other) { + int size = literals.size(); + if (size != other.literals.size()) { + return false; + } + for (int i = 0; i < size; i++) { + if (!literals.get(i).equalsWithSubstitution(helper, other.literals.get(i))) { + return false; + } + } + return true; + } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfUtils.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfUtils.java index 17564d43..c7a2849c 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfUtils.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfUtils.java @@ -1,6 +1,5 @@ package tools.refinery.store.query; -import java.util.Map; import java.util.UUID; public final class DnfUtils { @@ -17,8 +16,4 @@ public final class DnfUtils { return originalName + uniqueString; } } - - public static Variable maybeSubstitute(Variable variable, Map substitution) { - return substitution.getOrDefault(variable, variable); - } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java new file mode 100644 index 00000000..a01a5a2f --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java @@ -0,0 +1,49 @@ +package tools.refinery.store.query; + +import tools.refinery.store.tuple.Tuple; +import tools.refinery.store.tuple.TupleLike; + +import java.util.Optional; +import java.util.stream.Stream; + +public class EmptyResultSet implements ResultSet { + @Override + public boolean hasResult() { + return false; + } + + @Override + public boolean hasResult(Tuple parameters) { + return false; + } + + @Override + public Optional oneResult() { + return Optional.empty(); + } + + @Override + public Optional oneResult(Tuple parameters) { + return Optional.empty(); + } + + @Override + public Stream allResults() { + return Stream.of(); + } + + @Override + public Stream allResults(Tuple parameters) { + return Stream.of(); + } + + @Override + public int countResults() { + return 0; + } + + @Override + public int countResults(Tuple parameters) { + return 0; + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/Variable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/Variable.java index 2eb87649..d0e0dead 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/Variable.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/Variable.java @@ -20,15 +20,15 @@ public class Variable { } public String getName() { - return name; + return name == null ? uniqueName : name; } - public String getUniqueName() { - return uniqueName; + public boolean isExplicitlyNamed() { + return name != null; } - public boolean isNamed() { - return name != null; + public String getUniqueName() { + return uniqueName; } public ConstantLiteral isConstant(int value) { @@ -43,6 +43,11 @@ public class Variable { return new EquivalenceLiteral(false, this, other); } + @Override + public String toString() { + return getName(); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java new file mode 100644 index 00000000..ebd7f5b0 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java @@ -0,0 +1,31 @@ +package tools.refinery.store.query.equality; + +import tools.refinery.store.query.Dnf; +import tools.refinery.store.util.CycleDetectingMapper; + +import java.util.List; + +public class DeepDnfEqualityChecker implements DnfEqualityChecker { + private final CycleDetectingMapper mapper = new CycleDetectingMapper<>(Pair::toString, + this::doCheckEqual); + + @Override + public boolean dnfEqual(Dnf left, Dnf right) { + return mapper.map(new Pair(left, right)); + } + + protected boolean doCheckEqual(Pair pair) { + return pair.left.equalsWithSubstitution(this, pair.right); + } + + protected List getInProgress() { + return mapper.getInProgress(); + } + + protected record Pair(Dnf left, Dnf right) { + @Override + public String toString() { + return "(%s, %s)".formatted(left.name(), right.name()); + } + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java new file mode 100644 index 00000000..eb77de17 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java @@ -0,0 +1,8 @@ +package tools.refinery.store.query.equality; + +import tools.refinery.store.query.Dnf; + +@FunctionalInterface +public interface DnfEqualityChecker { + boolean dnfEqual(Dnf left, Dnf right); +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java new file mode 100644 index 00000000..23f1acc7 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java @@ -0,0 +1,48 @@ +package tools.refinery.store.query.equality; + +import tools.refinery.store.query.Dnf; +import tools.refinery.store.query.Variable; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class LiteralEqualityHelper { + private final DnfEqualityChecker dnfEqualityChecker; + private final Map leftToRight; + private final Map rightToLeft; + + public LiteralEqualityHelper(DnfEqualityChecker dnfEqualityChecker, List leftParameters, + List rightParameters) { + this.dnfEqualityChecker = dnfEqualityChecker; + var arity = leftParameters.size(); + if (arity != rightParameters.size()) { + throw new IllegalArgumentException("Parameter lists have unequal length"); + } + leftToRight = new HashMap<>(arity); + rightToLeft = new HashMap<>(arity); + for (int i = 0; i < arity; i++) { + if (!variableEqual(leftParameters.get(i), rightParameters.get(i))) { + throw new IllegalArgumentException("Parameter lists cannot be unified: duplicate parameter " + i); + } + } + } + + public boolean dnfEqual(Dnf left, Dnf right) { + return dnfEqualityChecker.dnfEqual(left, right); + } + + public boolean variableEqual(Variable left, Variable right) { + if (checkMapping(leftToRight, left, right) && checkMapping(rightToLeft, right, left)) { + leftToRight.put(left, right); + rightToLeft.put(right, left); + return true; + } + return false; + } + + private static boolean checkMapping(Map map, Variable key, Variable expectedValue) { + var currentValue = map.get(key); + return currentValue == null || currentValue.equals(expectedValue); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java index fd2f1eec..6d751be8 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java @@ -1,18 +1,19 @@ package tools.refinery.store.query.literal; import tools.refinery.store.query.Variable; +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.substitution.Substitution; -import java.util.Map; import java.util.Set; -public class BooleanLiteral implements Literal { - public static final BooleanLiteral TRUE = new BooleanLiteral(LiteralReduction.ALWAYS_TRUE); - public static final BooleanLiteral FALSE = new BooleanLiteral(LiteralReduction.ALWAYS_FALSE); +public enum BooleanLiteral implements PolarLiteral { + TRUE(true), + FALSE(false); - private final LiteralReduction reduction; + private final boolean value; - private BooleanLiteral(LiteralReduction reduction) { - this.reduction = reduction; + BooleanLiteral(boolean value) { + this.value = value; } @Override @@ -21,14 +22,29 @@ public class BooleanLiteral implements Literal { } @Override - public Literal substitute(Map substitution) { + public Literal substitute(Substitution substitution) { // No variables to substitute. return this; } @Override public LiteralReduction getReduction() { - return reduction; + return value ? LiteralReduction.ALWAYS_TRUE : LiteralReduction.ALWAYS_FALSE; + } + + @Override + public BooleanLiteral negate() { + return fromBoolean(!value); + } + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) { + return equals(other); + } + + @Override + public String toString() { + return Boolean.toString(value); } public static BooleanLiteral fromBoolean(boolean value) { diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java index 5e1ae94d..091b4e04 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java @@ -1,11 +1,11 @@ package tools.refinery.store.query.literal; -import tools.refinery.store.query.DnfUtils; import tools.refinery.store.query.RelationLike; import tools.refinery.store.query.Variable; +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.substitution.Substitution; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Set; @@ -31,6 +31,8 @@ public abstract class CallLiteral implements Literal { return polarity; } + public abstract Class getTargetType(); + public T getTarget() { return target; } @@ -46,8 +48,44 @@ public abstract class CallLiteral implements Literal { } } - protected List substituteArguments(Map substitution) { - return arguments.stream().map(variable -> DnfUtils.maybeSubstitute(variable, substitution)).toList(); + protected List substituteArguments(Substitution substitution) { + return arguments.stream().map(substitution::getSubstitute).toList(); + } + + /** + * Compares the target of this call literal with another object. + * + * @param helper Equality helper for comparing {@link Variable} and {@link tools.refinery.store.query.Dnf} + * instances. + * @param otherTarget The object to compare the target to. + * @return {@code true} if {@code otherTarget} is equal to the return value of {@link #getTarget()} according to + * {@code helper}, {@code false} otherwise. + */ + protected boolean targetEquals(LiteralEqualityHelper helper, T otherTarget) { + return target.equals(otherTarget); + } + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) { + if (other.getClass() != getClass()) { + return false; + } + var otherCallLiteral = (CallLiteral) other; + if (getTargetType() != otherCallLiteral.getTargetType() || polarity != otherCallLiteral.polarity) { + return false; + } + var arity = arguments.size(); + if (arity != otherCallLiteral.arguments.size()) { + return false; + } + for (int i = 0; i < arity; i++) { + if (!helper.variableEqual(arguments.get(i), otherCallLiteral.arguments.get(i))) { + return false; + } + } + @SuppressWarnings("unchecked") + var otherTarget = (T) otherCallLiteral.target; + return targetEquals(helper, otherTarget); } @Override @@ -63,4 +101,33 @@ public abstract class CallLiteral implements Literal { public int hashCode() { return Objects.hash(polarity, target, arguments); } + + protected String targetToString() { + return "@%s %s".formatted(getTargetType().getSimpleName(), target.name()); + } + + @Override + public String toString() { + var builder = new StringBuilder(); + if (!polarity.isPositive()) { + builder.append("!("); + } + builder.append(targetToString()); + if (polarity.isTransitive()) { + builder.append("+"); + } + builder.append("("); + var argumentIterator = arguments.iterator(); + if (argumentIterator.hasNext()) { + builder.append(argumentIterator.next()); + while (argumentIterator.hasNext()) { + builder.append(", ").append(argumentIterator.next()); + } + } + builder.append(")"); + if (!polarity.isPositive()) { + builder.append(")"); + } + return builder.toString(); + } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java index 746d23af..d01c7d20 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java @@ -1,9 +1,9 @@ package tools.refinery.store.query.literal; -import tools.refinery.store.query.DnfUtils; import tools.refinery.store.query.Variable; +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.substitution.Substitution; -import java.util.Map; import java.util.Set; public record ConstantLiteral(Variable variable, int nodeId) implements Literal { @@ -13,7 +13,21 @@ public record ConstantLiteral(Variable variable, int nodeId) implements Literal } @Override - public ConstantLiteral substitute(Map substitution) { - return new ConstantLiteral(DnfUtils.maybeSubstitute(variable, substitution), nodeId); + public ConstantLiteral substitute(Substitution substitution) { + return new ConstantLiteral(substitution.getSubstitute(variable), nodeId); + } + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) { + if (other.getClass() != getClass()) { + return false; + } + var otherConstantLiteral = (ConstantLiteral) other; + return helper.variableEqual(variable, otherConstantLiteral.variable) && nodeId == otherConstantLiteral.nodeId; + } + + @Override + public String toString() { + return "%s === @Constant %d".formatted(variable, nodeId); } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/DnfCallLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/DnfCallLiteral.java index de6c6005..27917265 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/DnfCallLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/DnfCallLiteral.java @@ -2,9 +2,10 @@ package tools.refinery.store.query.literal; import tools.refinery.store.query.Dnf; import tools.refinery.store.query.Variable; +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.substitution.Substitution; import java.util.List; -import java.util.Map; public final class DnfCallLiteral extends CallLiteral implements PolarLiteral { public DnfCallLiteral(CallPolarity polarity, Dnf target, List arguments) { @@ -12,7 +13,12 @@ public final class DnfCallLiteral extends CallLiteral implements PolarLiter } @Override - public DnfCallLiteral substitute(Map substitution) { + public Class getTargetType() { + return Dnf.class; + } + + @Override + public DnfCallLiteral substitute(Substitution substitution) { return new DnfCallLiteral(getPolarity(), getTarget(), substituteArguments(substitution)); } @@ -26,4 +32,9 @@ public final class DnfCallLiteral extends CallLiteral implements PolarLiter var dnfReduction = getTarget().getReduction(); return getPolarity().isPositive() ? dnfReduction : dnfReduction.negate(); } + + @Override + protected boolean targetEquals(LiteralEqualityHelper helper, Dnf otherTarget) { + return helper.dnfEqual(getTarget(), otherTarget); + } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java index f30179b2..61c753c3 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java @@ -1,9 +1,9 @@ package tools.refinery.store.query.literal; -import tools.refinery.store.query.DnfUtils; import tools.refinery.store.query.Variable; +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.substitution.Substitution; -import java.util.Map; import java.util.Set; public record EquivalenceLiteral(boolean positive, Variable left, Variable right) @@ -20,9 +20,8 @@ public record EquivalenceLiteral(boolean positive, Variable left, Variable right } @Override - public EquivalenceLiteral substitute(Map substitution) { - return new EquivalenceLiteral(positive, DnfUtils.maybeSubstitute(left, substitution), - DnfUtils.maybeSubstitute(right, substitution)); + public EquivalenceLiteral substitute(Substitution substitution) { + return new EquivalenceLiteral(positive, substitution.getSubstitute(left), substitution.getSubstitute(right)); } @Override @@ -32,4 +31,19 @@ public record EquivalenceLiteral(boolean positive, Variable left, Variable right } return LiteralReduction.NOT_REDUCIBLE; } + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) { + if (other.getClass() != getClass()) { + return false; + } + var otherEquivalenceLiteral = (EquivalenceLiteral) other; + return helper.variableEqual(left, otherEquivalenceLiteral.left) && helper.variableEqual(right, + otherEquivalenceLiteral.right); + } + + @Override + public String toString() { + return "%s %s %s".formatted(left, positive ? "===" : "!==", right); + } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java index a6893acf..ddd91775 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java @@ -1,16 +1,20 @@ package tools.refinery.store.query.literal; import tools.refinery.store.query.Variable; +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.substitution.Substitution; -import java.util.Map; import java.util.Set; public interface Literal { void collectAllVariables(Set variables); - Literal substitute(Map substitution); + Literal substitute(Substitution substitution); default LiteralReduction getReduction() { return LiteralReduction.NOT_REDUCIBLE; } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other); } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/RelationViewLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/RelationViewLiteral.java index 4718b550..fb8b3332 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/RelationViewLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/RelationViewLiteral.java @@ -1,10 +1,10 @@ package tools.refinery.store.query.literal; import tools.refinery.store.query.Variable; +import tools.refinery.store.query.substitution.Substitution; import tools.refinery.store.query.view.AnyRelationView; import java.util.List; -import java.util.Map; public final class RelationViewLiteral extends CallLiteral implements PolarLiteral { @@ -13,7 +13,18 @@ public final class RelationViewLiteral extends CallLiteral } @Override - public RelationViewLiteral substitute(Map substitution) { + public Class getTargetType() { + return AnyRelationView.class; + } + + @Override + protected String targetToString() { + var target = getTarget(); + return "@RelationView(\"%s\") %s".formatted(target.getViewName(), target.getSymbol().name()); + } + + @Override + public RelationViewLiteral substitute(Substitution substitution) { return new RelationViewLiteral(getPolarity(), getTarget(), substituteArguments(substitution)); } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java new file mode 100644 index 00000000..ffc65047 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java @@ -0,0 +1,13 @@ +package tools.refinery.store.query.substitution; + +import tools.refinery.store.query.Variable; + +import java.util.Map; + +public record MapBasedSubstitution(Map map, Substitution fallback) implements Substitution { + @Override + public Variable getSubstitute(Variable variable) { + var value = map.get(variable); + return value == null ? fallback.getSubstitute(variable) : value; + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java new file mode 100644 index 00000000..54d18a3f --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java @@ -0,0 +1,19 @@ +package tools.refinery.store.query.substitution; + +import tools.refinery.store.query.Variable; + +import java.util.HashMap; +import java.util.Map; + +public class RenewingSubstitution implements Substitution { + private final Map alreadyRenewed = new HashMap<>(); + + @Override + public Variable getSubstitute(Variable variable) { + return alreadyRenewed.computeIfAbsent(variable, RenewingSubstitution::renew); + } + + private static Variable renew(Variable variable) { + return variable.isExplicitlyNamed() ? new Variable(variable.getName()) : new Variable(); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java new file mode 100644 index 00000000..d33ad6fb --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java @@ -0,0 +1,18 @@ +package tools.refinery.store.query.substitution; + +import tools.refinery.store.query.Variable; + +public enum StatelessSubstitution implements Substitution { + FAILING { + @Override + public Variable getSubstitute(Variable variable) { + throw new IllegalArgumentException("No substitute for " + variable); + } + }, + IDENTITY { + @Override + public Variable getSubstitute(Variable variable) { + return variable; + } + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java new file mode 100644 index 00000000..9d086bf5 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java @@ -0,0 +1,8 @@ +package tools.refinery.store.query.substitution; + +import tools.refinery.store.query.Variable; + +@FunctionalInterface +public interface Substitution { + Variable getSubstitute(Variable variable); +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java new file mode 100644 index 00000000..26cf1a20 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java @@ -0,0 +1,27 @@ +package tools.refinery.store.query.substitution; + +import tools.refinery.store.query.Variable; + +import java.util.Map; + +public final class Substitutions { + private Substitutions() { + throw new IllegalStateException("This is a static utility class and should not be instantiate directly"); + } + + public static Substitution total(Map map) { + return new MapBasedSubstitution(map, StatelessSubstitution.FAILING); + } + + public static Substitution partial(Map map) { + return new MapBasedSubstitution(map, StatelessSubstitution.IDENTITY); + } + + public static Substitution renewing(Map map) { + return new MapBasedSubstitution(map, renewing()); + } + + public static Substitution renewing() { + return new RenewingSubstitution(); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnyRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnyRelationView.java index 328cde3a..bc3ac1ea 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnyRelationView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnyRelationView.java @@ -10,6 +10,8 @@ import java.util.Set; public sealed interface AnyRelationView extends RelationLike permits RelationView { AnySymbol getSymbol(); + String getViewName(); + default Set> getFunctionalDependencies() { return Set.of(); } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationView.java index 2714a8c5..ea9fd5e2 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationView.java @@ -21,11 +21,11 @@ import java.util.UUID; public abstract non-sealed class RelationView implements AnyRelationView { private final Symbol symbol; - private final String name; + private final String viewName; - protected RelationView(Symbol symbol, String name) { + protected RelationView(Symbol symbol, String viewName) { this.symbol = symbol; - this.name = name; + this.viewName = viewName; } protected RelationView(Symbol representation) { @@ -37,9 +37,14 @@ public abstract non-sealed class RelationView implements AnyRelationView { return symbol; } + @Override + public String getViewName() { + return viewName; + } + @Override public String name() { - return symbol.name() + "#" + name; + return symbol.name() + "#" + viewName; } public abstract boolean filter(Tuple key, T value); @@ -72,11 +77,11 @@ public abstract non-sealed class RelationView implements AnyRelationView { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; RelationView that = (RelationView) o; - return Objects.equals(symbol, that.symbol) && Objects.equals(name, that.name); + return Objects.equals(symbol, that.symbol) && Objects.equals(viewName, that.viewName); } @Override public int hashCode() { - return Objects.hash(symbol, name); + return Objects.hash(symbol, viewName); } } diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java new file mode 100644 index 00000000..e6701fe3 --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java @@ -0,0 +1,218 @@ +package tools.refinery.store.query; + +import org.junit.jupiter.api.Test; +import tools.refinery.store.query.literal.BooleanLiteral; +import tools.refinery.store.query.view.KeyOnlyRelationView; +import tools.refinery.store.representation.Symbol; + +import static org.hamcrest.MatcherAssert.assertThat; +import static tools.refinery.store.query.literal.Literals.not; +import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo; + +class DnfBuilderTest { + @Test + void eliminateTrueTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + + var actual = Dnf.builder() + .parameters(p, q) + .clause(BooleanLiteral.TRUE, friendView.call(p, q)) + .build(); + var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void eliminateFalseTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q)) + .clause(friendView.call(q, p), BooleanLiteral.FALSE) + .build(); + var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void alwaysTrueTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q)) + .clause(BooleanLiteral.TRUE) + .build(); + var expected = Dnf.builder().parameters(p, q).clause().build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void alwaysFalseTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q), BooleanLiteral.FALSE) + .build(); + var expected = Dnf.builder().parameters(p, q).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void eliminateTrueDnfTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var trueDnf = Dnf.builder().parameter(p).clause().build(); + + var actual = Dnf.builder() + .parameters(p, q) + .clause(trueDnf.call(q), friendView.call(p, q)) + .build(); + var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void eliminateFalseDnfTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var falseDnf = Dnf.builder().parameter(p).build(); + + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q)) + .clause(friendView.call(q, p), falseDnf.call(q)) + .build(); + var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void alwaysTrueDnfTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var trueDnf = Dnf.builder().parameter(p).clause().build(); + + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q)) + .clause(trueDnf.call(q)) + .build(); + var expected = Dnf.builder().parameters(p, q).clause().build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void alwaysFalseDnfTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var falseDnf = Dnf.builder().parameter(p).build(); + + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q), falseDnf.call(q)) + .build(); + var expected = Dnf.builder().parameters(p, q).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void eliminateNotFalseDnfTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var falseDnf = Dnf.builder().parameter(p).build(); + + var actual = Dnf.builder() + .parameters(p, q) + .clause(not(falseDnf.call(q)), friendView.call(p, q)) + .build(); + var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void eliminateNotTrueDnfTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var trueDnf = Dnf.builder().parameter(p).clause().build(); + + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q)) + .clause(friendView.call(q, p), not(trueDnf.call(q))) + .build(); + var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void alwaysNotFalseDnfTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var falseDnf = Dnf.builder().parameter(p).build(); + + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q)) + .clause(not(falseDnf.call(q))) + .build(); + var expected = Dnf.builder().parameters(p, q).clause().build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void alwaysNotTrueDnfTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var trueDnf = Dnf.builder().parameter(p).clause().build(); + + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q), not(trueDnf.call(q))) + .build(); + var expected = Dnf.builder().parameters(p, q).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } +} diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToStringTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToStringTest.java new file mode 100644 index 00000000..e6e4bef3 --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToStringTest.java @@ -0,0 +1,172 @@ +package tools.refinery.store.query; + +import org.junit.jupiter.api.Test; +import tools.refinery.store.query.view.KeyOnlyRelationView; +import tools.refinery.store.representation.Symbol; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static tools.refinery.store.query.literal.Literals.not; + +class DnfToStringTest { + @Test + void noClausesTest() { + var p = new Variable("p"); + var dnf = Dnf.builder("Example").parameter(p).build(); + + assertThat(dnf.toString(), is(""" + pred Example(p) <-> + . + """)); + } + + @Test + void noParametersTest() { + var dnf = Dnf.builder("Example").build(); + + assertThat(dnf.toString(), is(""" + pred Example() <-> + . + """)); + } + + @Test + void emptyClauseTest() { + var p = new Variable("p"); + var dnf = Dnf.builder("Example").parameter(p).clause().build(); + + assertThat(dnf.toString(), is(""" + pred Example(p) <-> + . + """)); + } + + @Test + void relationViewPositiveTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var dnf = Dnf.builder("Example").parameter(p).clause(friendView.call(p, q)).build(); + + assertThat(dnf.toString(), is(""" + pred Example(p) <-> + @RelationView("key") friend(p, q). + """)); + } + + @Test + void relationViewNegativeTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var dnf = Dnf.builder("Example").parameter(p).clause(not(friendView.call(p, q))).build(); + + assertThat(dnf.toString(), is(""" + pred Example(p) <-> + !(@RelationView("key") friend(p, q)). + """)); + } + + @Test + void relationViewTransitiveTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var dnf = Dnf.builder("Example").parameter(p).clause(friendView.callTransitive(p, q)).build(); + + assertThat(dnf.toString(), is(""" + pred Example(p) <-> + @RelationView("key") friend+(p, q). + """)); + } + + @Test + void multipleParametersTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var dnf = Dnf.builder("Example").parameters(p, q).clause(friendView.call(p, q)).build(); + + assertThat(dnf.toString(), is(""" + pred Example(p, q) <-> + @RelationView("key") friend(p, q). + """)); + } + + @Test + void multipleLiteralsTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var person = new Symbol<>("person", 1, Boolean.class, false); + var personView = new KeyOnlyRelationView<>(person); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var dnf = Dnf.builder("Example") + .parameter(p) + .clause( + personView.call(p), + personView.call(q), + friendView.call(p, q) + ) + .build(); + + assertThat(dnf.toString(), is(""" + pred Example(p) <-> + @RelationView("key") person(p), + @RelationView("key") person(q), + @RelationView("key") friend(p, q). + """)); + } + + @Test + void multipleClausesTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var dnf = Dnf.builder("Example") + .parameter(p) + .clause(friendView.call(p, q)) + .clause(friendView.call(q, p)) + .build(); + + assertThat(dnf.toString(), is(""" + pred Example(p) <-> + @RelationView("key") friend(p, q) + ; + @RelationView("key") friend(q, p). + """)); + } + + @Test + void dnfTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var r = new Variable("r"); + var s = new Variable("s"); + var person = new Symbol<>("person", 1, Boolean.class, false); + var personView = new KeyOnlyRelationView<>(person); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var called = Dnf.builder("Called").parameters(r, s).clause(friendView.call(r, s)).build(); + var dnf = Dnf.builder("Example") + .parameter(p) + .clause( + personView.call(p), + personView.call(q), + not(called.call(p, q)) + ) + .build(); + + assertThat(dnf.toString(), is(""" + pred Example(p) <-> + @RelationView("key") person(p), + @RelationView("key") person(q), + !(@Dnf Called(p, q)). + """)); + } +} diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java new file mode 100644 index 00000000..0cda22df --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java @@ -0,0 +1,77 @@ +package tools.refinery.store.query.tests; + +import org.junit.jupiter.api.Test; +import tools.refinery.store.query.Dnf; +import tools.refinery.store.query.Variable; +import tools.refinery.store.query.view.KeyOnlyRelationView; +import tools.refinery.store.representation.Symbol; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo; + +class StructurallyEqualToTest { + @Test + void flatEqualsTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var person = new Symbol<>("Person", 1, Boolean.class, false); + var personView = new KeyOnlyRelationView<>(person); + + var expected = Dnf.builder("Expected").parameters(q).clause(personView.call(q)).build(); + var actual = Dnf.builder("Actual").parameters(p).clause(personView.call(p)).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void flatNotEqualsTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var person = new Symbol<>("Person", 1, Boolean.class, false); + var personView = new KeyOnlyRelationView<>(person); + + var expected = Dnf.builder("Expected").parameters(q).clause(personView.call(q)).build(); + var actual = Dnf.builder("Actual").parameters(p).clause(personView.call(q)).build(); + + var assertion = structurallyEqualTo(expected); + assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); + } + + @Test + void deepEqualsTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var person = new Symbol<>("Person", 1, Boolean.class, false); + var personView = new KeyOnlyRelationView<>(person); + + var expected = Dnf.builder("Expected").parameters(q).clause( + Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build().call(q) + ).build(); + var actual = Dnf.builder("Actual").parameters(q).clause( + Dnf.builder("Actual2").parameters(p).clause(personView.call(p)).build().call(q) + ).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void deepNotEqualsTest() { + var p = new Variable("p"); + var q = new Variable("q"); + var person = new Symbol<>("Person", 1, Boolean.class, false); + var personView = new KeyOnlyRelationView<>(person); + + var expected = Dnf.builder("Expected").parameters(q).clause( + Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build().call(q) + ).build(); + var actual = Dnf.builder("Actual").parameters(q).clause( + Dnf.builder("Actual2").parameters(p).clause(personView.call(q)).build().call(q) + ).build(); + + var assertion = structurallyEqualTo(expected); + var error = assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); + assertThat(error.getMessage(), containsString(" called from Expected ")); + } +} diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java new file mode 100644 index 00000000..aaab2e7e --- /dev/null +++ b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java @@ -0,0 +1,43 @@ +package tools.refinery.store.query.tests; + +import org.hamcrest.Description; +import tools.refinery.store.query.equality.DeepDnfEqualityChecker; + +class MismatchDescribingDnfEqualityChecker extends DeepDnfEqualityChecker { + private final Description description; + private boolean described; + + MismatchDescribingDnfEqualityChecker(Description description) { + this.description = description; + } + + public boolean isDescribed() { + return described; + } + + @Override + protected boolean doCheckEqual(Pair pair) { + boolean result = super.doCheckEqual(pair); + if (!result && !described) { + describeMismatch(pair); + // Only describe the first found (innermost) mismatch. + described = true; + } + return result; + } + + private void describeMismatch(Pair pair) { + var inProgress = getInProgress(); + int size = inProgress.size(); + if (size <= 1) { + description.appendText("was ").appendValue(pair.left()); + return; + } + var last = inProgress.get(size - 1); + description.appendText("expected ").appendValue(last.right()); + for (int i = size - 2; i >= 0; i--) { + description.appendText(" called from ").appendText(inProgress.get(i).left().name()); + } + description.appendText(" was not structurally equal to ").appendValue(last.right()); + } +} diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java new file mode 100644 index 00000000..83614278 --- /dev/null +++ b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java @@ -0,0 +1,14 @@ +package tools.refinery.store.query.tests; + +import org.hamcrest.Matcher; +import tools.refinery.store.query.Dnf; + +public final class QueryMatchers { + private QueryMatchers() { + throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); + } + + public static Matcher structurallyEqualTo(Dnf expected) { + return new StructurallyEqualTo(expected); + } +} diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java new file mode 100644 index 00000000..a42396dd --- /dev/null +++ b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java @@ -0,0 +1,36 @@ +package tools.refinery.store.query.tests; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeMatcher; +import tools.refinery.store.query.Dnf; +import tools.refinery.store.query.equality.DeepDnfEqualityChecker; + +public class StructurallyEqualTo extends TypeSafeMatcher { + private final Dnf expected; + + public StructurallyEqualTo(Dnf expected) { + this.expected = expected; + } + + @Override + protected boolean matchesSafely(Dnf item) { + var checker = new DeepDnfEqualityChecker(); + return checker.dnfEqual(expected, item); + } + + @Override + protected void describeMismatchSafely(Dnf item, Description mismatchDescription) { + var describingChecker = new MismatchDescribingDnfEqualityChecker(mismatchDescription); + if (describingChecker.dnfEqual(expected, item)) { + throw new IllegalStateException("Mismatched Dnf was matching on repeated comparison"); + } + if (!describingChecker.isDescribed()) { + super.describeMismatchSafely(item, mismatchDescription); + } + } + + @Override + public void describeTo(Description description) { + description.appendText("structurally equal to ").appendValue(expected); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java b/subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java index e4b462f0..8a151d01 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java +++ b/subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java @@ -1,9 +1,6 @@ package tools.refinery.store.util; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -45,6 +42,10 @@ public class CycleDetectingMapper { return result; } + public List getInProgress() { + return List.copyOf(inProgress); + } + public R getAlreadyMapped(T input) { return results.get(input); } -- cgit v1.2.3-70-g09d2 From da5d898b3bad6f55efd6619f0abee0ec8aa1de4b Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Wed, 1 Mar 2023 02:15:50 +0100 Subject: refactor: more direct access to VIATRA result set Accessing VIATRA result sets through IQueryResultProvider requires a lot of indirection, allocations, and locking. We use reflection instead to have direct access to the underlying Indexer instead. Unfortunately, projection to arbitrary tuple masks (with wildcard entries in a tuple) is completely broken in VIATRA when RETE update propagation is delayed. While a new, ad-hoc projection indexer gets added to the RETE net immediately, it is not populated with the projection results until updates are flushed in the query engine. Therefore, when encountering an ad-hoc projection for the first time, the projection results will always be empty (thus usually out of date). While declaring the desired projections ahead of time would be a possible solution, for now, we completely remove ad-hoc projection support. If projections are needed on the ModelQuery level, we should create an API for declaring projections for each registered Dnf. --- .../internal/ViatraModelQueryAdapterImpl.java | 29 +++-- .../query/viatra/internal/pquery/IndexerUtils.java | 48 ++++++++ .../viatra/internal/pquery/RawPatternMatcher.java | 127 ++++++++++++--------- .../refinery/store/query/viatra/QueryTest.java | 7 +- .../tools/refinery/store/query/EmptyResultSet.java | 29 +---- .../java/tools/refinery/store/query/ResultSet.java | 16 +-- .../tools/refinery/store/reasoning/seed/Seed.java | 14 +++ .../refinery/store/reasoning/translator/Seed.java | 12 -- 8 files changed, 163 insertions(+), 119 deletions(-) create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/IndexerUtils.java create mode 100644 subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java delete mode 100644 subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Seed.java (limited to 'subprojects/store-query-viatra/src/main/java/tools') 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 e0341598..37700413 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 @@ -21,32 +21,37 @@ import java.util.Map; public class ViatraModelQueryAdapterImpl implements ViatraModelQueryAdapter { private static final String DELAY_MESSAGE_DELIVERY_FIELD_NAME = "delayMessageDelivery"; + private static final MethodHandle SET_UPDATE_PROPAGATION_DELAYED_HANDLE; private static final String QUERY_BACKENDS_FIELD_NAME = "queryBackends"; + private static final MethodHandle GET_QUERY_BACKENDS_HANDLE; private final Model model; private final ViatraModelQueryStoreAdapterImpl storeAdapter; private final ViatraQueryEngineImpl queryEngine; - private final MethodHandle setUpdatePropagationDelayedHandle; - private final MethodHandle getQueryBackendsHandle; + private final Map resultSets; private boolean pendingChanges; - ViatraModelQueryAdapterImpl(Model model, ViatraModelQueryStoreAdapterImpl storeAdapter) { - this.model = model; - this.storeAdapter = storeAdapter; - var scope = new RelationalScope(this); - queryEngine = (ViatraQueryEngineImpl) AdvancedViatraQueryEngine.createUnmanagedEngine(scope); - + static { try { var lookup = MethodHandles.privateLookupIn(ViatraQueryEngineImpl.class, MethodHandles.lookup()); - setUpdatePropagationDelayedHandle = lookup.findSetter(ViatraQueryEngineImpl.class, + SET_UPDATE_PROPAGATION_DELAYED_HANDLE = lookup.findSetter(ViatraQueryEngineImpl.class, DELAY_MESSAGE_DELIVERY_FIELD_NAME, Boolean.TYPE); - getQueryBackendsHandle = lookup.findGetter(ViatraQueryEngineImpl.class, QUERY_BACKENDS_FIELD_NAME, + GET_QUERY_BACKENDS_HANDLE = lookup.findGetter(ViatraQueryEngineImpl.class, QUERY_BACKENDS_FIELD_NAME, Map.class); } catch (IllegalAccessException | NoSuchFieldException e) { throw new IllegalStateException("Cannot access private members of %s" .formatted(ViatraQueryEngineImpl.class.getName()), e); } + } + + ViatraModelQueryAdapterImpl(Model model, ViatraModelQueryStoreAdapterImpl storeAdapter) { + this.model = model; + this.storeAdapter = storeAdapter; + var scope = new RelationalScope(this); + queryEngine = (ViatraQueryEngineImpl) AdvancedViatraQueryEngine.createUnmanagedEngine(scope); + + var querySpecifications = storeAdapter.getQuerySpecifications(); GenericQueryGroup.of( @@ -67,7 +72,7 @@ public class ViatraModelQueryAdapterImpl implements ViatraModelQueryAdapter { private void setUpdatePropagationDelayed(boolean value) { try { - setUpdatePropagationDelayedHandle.invokeExact(queryEngine, value); + SET_UPDATE_PROPAGATION_DELAYED_HANDLE.invokeExact(queryEngine, value); } catch (Error e) { // Fatal JVM errors should not be wrapped. throw e; @@ -79,7 +84,7 @@ public class ViatraModelQueryAdapterImpl implements ViatraModelQueryAdapter { private Collection getQueryBackends() { try { @SuppressWarnings("unchecked") - var backendMap = (Map) getQueryBackendsHandle.invokeExact(queryEngine); + var backendMap = (Map) GET_QUERY_BACKENDS_HANDLE.invokeExact(queryEngine); return backendMap.values(); } catch (Error e) { // Fatal JVM errors should not be wrapped. diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/IndexerUtils.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/IndexerUtils.java new file mode 100644 index 00000000..75588b81 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/IndexerUtils.java @@ -0,0 +1,48 @@ +package tools.refinery.store.query.viatra.internal.pquery; + +import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; +import org.eclipse.viatra.query.runtime.rete.index.Indexer; +import org.eclipse.viatra.query.runtime.rete.matcher.ReteEngine; +import org.eclipse.viatra.query.runtime.rete.matcher.RetePatternMatcher; +import org.eclipse.viatra.query.runtime.rete.traceability.RecipeTraceInfo; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +final class IndexerUtils { + private static final MethodHandle GET_ENGINE_HANDLE; + private static final MethodHandle GET_PRODUCTION_NODE_TRACE_HANDLE; + private static final MethodHandle ACCESS_PROJECTION_HANDLE; + + static { + try { + var lookup = MethodHandles.privateLookupIn(RetePatternMatcher.class, MethodHandles.lookup()); + GET_ENGINE_HANDLE = lookup.findGetter(RetePatternMatcher.class, "engine", ReteEngine.class); + GET_PRODUCTION_NODE_TRACE_HANDLE = lookup.findGetter(RetePatternMatcher.class, "productionNodeTrace", + RecipeTraceInfo.class); + ACCESS_PROJECTION_HANDLE = lookup.findVirtual(ReteEngine.class, "accessProjection", + MethodType.methodType(Indexer.class, RecipeTraceInfo.class, TupleMask.class)); + } catch (IllegalAccessException | NoSuchFieldException | NoSuchMethodException e) { + throw new IllegalStateException("Cannot access private members of %s" + .formatted(RetePatternMatcher.class.getPackageName()), e); + } + } + + private IndexerUtils() { + throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); + } + + public static Indexer getIndexer(RetePatternMatcher backend, TupleMask mask) { + try { + var engine = (ReteEngine) GET_ENGINE_HANDLE.invokeExact(backend); + var trace = (RecipeTraceInfo) GET_PRODUCTION_NODE_TRACE_HANDLE.invokeExact(backend); + return (Indexer) ACCESS_PROJECTION_HANDLE.invokeExact(engine, trace, mask); + } catch (Error e) { + // Fatal JVM errors should not be wrapped. + throw e; + } catch (Throwable e) { + throw new IllegalStateException("Cannot access matcher for mask " + mask, e); + } + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPatternMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPatternMatcher.java index e944e873..8f56586e 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPatternMatcher.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPatternMatcher.java @@ -2,71 +2,92 @@ package tools.refinery.store.query.viatra.internal.pquery; import org.eclipse.viatra.query.runtime.api.GenericPatternMatcher; import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; +import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; +import org.eclipse.viatra.query.runtime.matchers.backend.IMatcherCapability; +import org.eclipse.viatra.query.runtime.matchers.backend.IQueryResultProvider; +import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; +import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; +import org.eclipse.viatra.query.runtime.rete.index.Indexer; +import org.eclipse.viatra.query.runtime.rete.matcher.RetePatternMatcher; import tools.refinery.store.query.ResultSet; import tools.refinery.store.query.viatra.ViatraTupleLike; import tools.refinery.store.tuple.Tuple; import tools.refinery.store.tuple.TupleLike; -import java.util.Optional; import java.util.stream.Stream; +/** + * Directly access the tuples inside a VIATRA pattern matcher.

+ * This class neglects calling + * {@link org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext#wrapTuple(org.eclipse.viatra.query.runtime.matchers.tuple.Tuple)} + * and + * {@link org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext#unwrapTuple(org.eclipse.viatra.query.runtime.matchers.tuple.Tuple)}, + * because {@link tools.refinery.store.query.viatra.internal.context.RelationalRuntimeContext} provides a trivial + * implementation for these methods. + * Using this class with any other runtime context may lead to undefined behavior. + */ public class RawPatternMatcher extends GenericPatternMatcher implements ResultSet { - protected final Object[] empty; + private final Object[] empty; + private final TupleMask identityMask; + private Indexer emptyMaskIndexer; - public RawPatternMatcher(GenericQuerySpecification specification) { - super(specification); - empty = new Object[specification.getParameterNames().size()]; - } + public RawPatternMatcher(GenericQuerySpecification specification) { + super(specification); + var arity = specification.getParameterNames().size(); + empty = new Object[arity]; + identityMask = TupleMask.identity(arity); + } - @Override - public boolean hasResult() { - return backend.hasMatch(empty); - } + @Override + protected void setBackend(ViatraQueryEngine engine, IQueryResultProvider resultProvider, + IMatcherCapability capabilities) { + super.setBackend(engine, resultProvider, capabilities); + if (resultProvider instanceof RetePatternMatcher reteBackend) { + emptyMaskIndexer = IndexerUtils.getIndexer(reteBackend, TupleMask.empty(identityMask.sourceWidth)); + } + } - @Override - public boolean hasResult(Tuple parameters) { - return backend.hasMatch(toParametersArray(parameters)); - } + @Override + public boolean hasResult(TupleLike parameters) { + org.eclipse.viatra.query.runtime.matchers.tuple.Tuple tuple; + if (parameters instanceof ViatraTupleLike viatraTupleLike) { + tuple = viatraTupleLike.wrappedTuple().toImmutable(); + } else { + var parametersArray = toParametersArray(parameters); + tuple = Tuples.flatTupleOf(parametersArray); + } + if (emptyMaskIndexer == null) { + return backend.hasMatch(identityMask, tuple); + } + var matches = emptyMaskIndexer.get(Tuples.staticArityFlatTupleOf()); + return matches != null && matches.contains(tuple); + } - @Override - public Optional oneResult() { - return backend.getOneArbitraryMatch(empty).map(ViatraTupleLike::new); - } + @Override + public Stream allResults() { + if (emptyMaskIndexer == null) { + return backend.getAllMatches(empty).map(ViatraTupleLike::new); + } + var matches = emptyMaskIndexer.get(Tuples.staticArityFlatTupleOf()); + return matches == null ? Stream.of() : matches.stream().map(ViatraTupleLike::new); + } - @Override - public Optional oneResult(Tuple parameters) { - return backend.getOneArbitraryMatch(toParametersArray(parameters)).map(ViatraTupleLike::new); - } + @Override + public int countResults() { + if (emptyMaskIndexer == null) { + return backend.countMatches(empty); + } + var matches = emptyMaskIndexer.get(Tuples.staticArityFlatTupleOf()); + return matches == null ? 0 : matches.size(); + } - @Override - public Stream allResults() { - return backend.getAllMatches(empty).map(ViatraTupleLike::new); - } - - @Override - public Stream allResults(Tuple parameters) { - return backend.getAllMatches(toParametersArray(parameters)).map(ViatraTupleLike::new); - } - - @Override - public int countResults() { - return backend.countMatches(empty); - } - - @Override - public int countResults(Tuple parameters) { - return backend.countMatches(toParametersArray(parameters)); - } - - private Object[] toParametersArray(Tuple tuple) { - int size = tuple.getSize(); - var array = new Object[tuple.getSize()]; - for (int i = 0; i < size; i++) { - var value = tuple.get(i); - if (value >= 0) { - array[i] = Tuple.of(value); - } - } - return array; - } + private Object[] toParametersArray(TupleLike tuple) { + int size = tuple.getSize(); + var array = new Object[size]; + for (int i = 0; i < size; i++) { + var value = tuple.get(i); + array[i] = Tuple.of(value); + } + return array; + } } 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 54ae70c3..3dd517c4 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 @@ -16,8 +16,7 @@ import java.util.HashSet; import java.util.Set; import java.util.stream.Stream; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.*; import static tools.refinery.store.query.literal.Literals.not; class QueryTest { @@ -97,10 +96,14 @@ class QueryTest { friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); assertEquals(0, predicateResultSet.countResults()); + assertFalse(predicateResultSet.hasResult(Tuple.of(0, 1))); + assertFalse(predicateResultSet.hasResult(Tuple.of(0, 2))); queryEngine.flushChanges(); assertEquals(3, predicateResultSet.countResults()); compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(1, 2))); + assertTrue(predicateResultSet.hasResult(Tuple.of(0, 1))); + assertFalse(predicateResultSet.hasResult(Tuple.of(0, 2))); } @Test diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java index a01a5a2f..0c2e07d6 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java @@ -1,49 +1,22 @@ package tools.refinery.store.query; -import tools.refinery.store.tuple.Tuple; import tools.refinery.store.tuple.TupleLike; -import java.util.Optional; import java.util.stream.Stream; public class EmptyResultSet implements ResultSet { @Override - public boolean hasResult() { + public boolean hasResult(TupleLike parameters) { return false; } - @Override - public boolean hasResult(Tuple parameters) { - return false; - } - - @Override - public Optional oneResult() { - return Optional.empty(); - } - - @Override - public Optional oneResult(Tuple parameters) { - return Optional.empty(); - } - @Override public Stream allResults() { return Stream.of(); } - @Override - public Stream allResults(Tuple parameters) { - return Stream.of(); - } - @Override public int countResults() { return 0; } - - @Override - public int countResults(Tuple parameters) { - return 0; - } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java index 3542e252..407cf075 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java @@ -1,25 +1,17 @@ package tools.refinery.store.query; -import tools.refinery.store.tuple.Tuple; import tools.refinery.store.tuple.TupleLike; -import java.util.Optional; import java.util.stream.Stream; public interface ResultSet { - boolean hasResult(); + default boolean hasResult() { + return countResults() > 0; + } - boolean hasResult(Tuple parameters); - - Optional oneResult(); - - Optional oneResult(Tuple parameters); + boolean hasResult(TupleLike parameters); Stream allResults(); - Stream allResults(Tuple parameters); - int countResults(); - - int countResults(Tuple parameters); } diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java new file mode 100644 index 00000000..042c2636 --- /dev/null +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java @@ -0,0 +1,14 @@ +package tools.refinery.store.reasoning.translator; + +import tools.refinery.store.map.Cursor; +import tools.refinery.store.tuple.Tuple; + +public interface Seed { + int arity(); + + T getReducedValue(); + + T get(Tuple key); + + Cursor getCursor(T defaultValue, int nodeCount); +} diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Seed.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Seed.java deleted file mode 100644 index 779eadbe..00000000 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Seed.java +++ /dev/null @@ -1,12 +0,0 @@ -package tools.refinery.store.reasoning.translator; - -import tools.refinery.store.map.Cursor; -import tools.refinery.store.tuple.Tuple; - -public interface Seed { - int arity(); - - T get(Tuple key); - - Cursor getCursor(T defaultValue, int nodeCount); -} -- cgit v1.2.3-70-g09d2 From 2bf484cd882949c53a82c40e28319f74ef8ae477 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Wed, 1 Mar 2023 21:20:10 +0100 Subject: refactor: use Cursor in query result sets --- .../viatra/internal/pquery/RawPatternMatcher.java | 10 ++--- .../viatra/internal/pquery/ResultSetCursor.java | 43 ++++++++++++++++++++++ .../refinery/store/query/viatra/QueryTest.java | 9 ++--- .../tools/refinery/store/query/EmptyResultSet.java | 8 ++-- .../java/tools/refinery/store/query/ResultSet.java | 5 +-- .../java/tools/refinery/store/map/Cursors.java | 36 ++++++++++++++++++ 6 files changed, 94 insertions(+), 17 deletions(-) create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ResultSetCursor.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/map/Cursors.java (limited to 'subprojects/store-query-viatra/src/main/java/tools') diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPatternMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPatternMatcher.java index 8f56586e..5924ff15 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPatternMatcher.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPatternMatcher.java @@ -9,13 +9,13 @@ import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; import org.eclipse.viatra.query.runtime.rete.index.Indexer; import org.eclipse.viatra.query.runtime.rete.matcher.RetePatternMatcher; +import tools.refinery.store.map.Cursor; +import tools.refinery.store.map.Cursors; import tools.refinery.store.query.ResultSet; import tools.refinery.store.query.viatra.ViatraTupleLike; import tools.refinery.store.tuple.Tuple; import tools.refinery.store.tuple.TupleLike; -import java.util.stream.Stream; - /** * Directly access the tuples inside a VIATRA pattern matcher.

* This class neglects calling @@ -64,12 +64,12 @@ public class RawPatternMatcher extends GenericPatternMatcher implements ResultSe } @Override - public Stream allResults() { + public Cursor allResults() { if (emptyMaskIndexer == null) { - return backend.getAllMatches(empty).map(ViatraTupleLike::new); + return new ResultSetCursor(backend.getAllMatches(empty).iterator()); } var matches = emptyMaskIndexer.get(Tuples.staticArityFlatTupleOf()); - return matches == null ? Stream.of() : matches.stream().map(ViatraTupleLike::new); + return matches == null ? Cursors.empty() : new ResultSetCursor(matches.stream().iterator()); } @Override diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ResultSetCursor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ResultSetCursor.java new file mode 100644 index 00000000..5e6d1970 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ResultSetCursor.java @@ -0,0 +1,43 @@ +package tools.refinery.store.query.viatra.internal.pquery; + +import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; +import tools.refinery.store.map.Cursor; +import tools.refinery.store.query.viatra.ViatraTupleLike; +import tools.refinery.store.tuple.TupleLike; + +import java.util.Iterator; + +class ResultSetCursor implements Cursor { + private final Iterator tuplesIterator; + private boolean terminated; + private TupleLike key; + + public ResultSetCursor(Iterator tuplesIterator) { + this.tuplesIterator = tuplesIterator; + } + + @Override + public TupleLike getKey() { + return key; + } + + @Override + public Boolean getValue() { + return true; + } + + @Override + public boolean isTerminated() { + return terminated; + } + + @Override + public boolean move() { + if (!terminated && tuplesIterator.hasNext()) { + key = new ViatraTupleLike(tuplesIterator.next()); + return true; + } + terminated = true; + return false; + } +} 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 3dd517c4..8b25419d 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 @@ -1,6 +1,7 @@ package tools.refinery.store.query.viatra; import org.junit.jupiter.api.Test; +import tools.refinery.store.map.Cursor; import tools.refinery.store.model.ModelStore; import tools.refinery.store.query.Dnf; import tools.refinery.store.query.ModelQuery; @@ -14,7 +15,6 @@ import tools.refinery.store.tuple.TupleLike; import java.util.HashSet; import java.util.Set; -import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.*; import static tools.refinery.store.query.literal.Literals.not; @@ -712,11 +712,10 @@ class QueryTest { assertThrows(IllegalArgumentException.class, () -> queryBuilder.queries(predicate)); } - static void compareMatchSets(Stream matchSet, Set expected) { + private static void compareMatchSets(Cursor cursor, Set expected) { Set translatedMatchSet = new HashSet<>(); - var iterator = matchSet.iterator(); - while (iterator.hasNext()) { - var element = iterator.next(); + while (cursor.move()) { + var element = cursor.getKey(); translatedMatchSet.add(element.toTuple()); } assertEquals(expected, translatedMatchSet); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java index 0c2e07d6..9ff6df26 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java @@ -1,9 +1,9 @@ package tools.refinery.store.query; +import tools.refinery.store.map.Cursor; +import tools.refinery.store.map.Cursors; import tools.refinery.store.tuple.TupleLike; -import java.util.stream.Stream; - public class EmptyResultSet implements ResultSet { @Override public boolean hasResult(TupleLike parameters) { @@ -11,8 +11,8 @@ public class EmptyResultSet implements ResultSet { } @Override - public Stream allResults() { - return Stream.of(); + public Cursor allResults() { + return Cursors.empty(); } @Override diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java index 407cf075..d2b8c9dd 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java @@ -1,9 +1,8 @@ package tools.refinery.store.query; +import tools.refinery.store.map.Cursor; import tools.refinery.store.tuple.TupleLike; -import java.util.stream.Stream; - public interface ResultSet { default boolean hasResult() { return countResults() > 0; @@ -11,7 +10,7 @@ public interface ResultSet { boolean hasResult(TupleLike parameters); - Stream allResults(); + Cursor allResults(); int countResults(); } diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/Cursors.java b/subprojects/store/src/main/java/tools/refinery/store/map/Cursors.java new file mode 100644 index 00000000..fc8e628b --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/map/Cursors.java @@ -0,0 +1,36 @@ +package tools.refinery.store.map; + +public final class Cursors { + private Cursors() { + throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); + } + + public static Cursor empty() { + return new Empty<>(); + } + + private static class Empty implements Cursor { + private boolean terminated = false; + + @Override + public K getKey() { + return null; + } + + @Override + public V getValue() { + return null; + } + + @Override + public boolean isTerminated() { + return terminated; + } + + @Override + public boolean move() { + terminated = true; + return false; + } + } +} -- cgit v1.2.3-70-g09d2 From 372058e54825ab58a66c25ae528e81a656c22659 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Tue, 7 Mar 2023 16:26:26 +0100 Subject: feat: terms and improved query evaluation * Implement data terms for computations in queries. * Function-like queries with computed results. * Improved query evaluation, including positive and negative diagonal cosntraints. * Preliminary local search support. * Changes to the DNF representation for count and aggregation support. feat: terms wip feat: query terms wip feat: query evaluation, diagonal constraints, local search wip fix reasoning compilation wip --- .../query/viatra/ViatraModelQueryBuilder.java | 11 +- .../store/query/viatra/ViatraTupleLike.java | 18 - .../internal/ViatraModelQueryAdapterImpl.java | 51 +- .../internal/ViatraModelQueryBuilderImpl.java | 63 ++- .../internal/ViatraModelQueryStoreAdapterImpl.java | 22 +- .../context/RelationalQueryMetaContext.java | 19 + .../internal/context/RelationalRuntimeContext.java | 31 +- .../localsearch/ExtendOperationExecutor.java | 75 +++ .../localsearch/ExtendPositivePatternCall.java | 116 ++++ .../internal/localsearch/FlatCostFunction.java | 30 + .../internal/localsearch/GenericTypeExtend.java | 136 +++++ .../RelationalLocalSearchBackendFactory.java | 55 ++ .../RelationalLocalSearchResultProvider.java | 23 + .../localsearch/RelationalOperationCompiler.java | 65 +++ .../viatra/internal/matcher/FunctionalCursor.java | 48 ++ .../internal/matcher/FunctionalViatraMatcher.java | 91 +++ .../viatra/internal/matcher/IndexerUtils.java | 48 ++ .../viatra/internal/matcher/MatcherUtils.java | 50 ++ .../matcher/OmitOutputViatraTupleLike.java | 23 + .../viatra/internal/matcher/RawPatternMatcher.java | 15 + .../viatra/internal/matcher/RelationalCursor.java | 42 ++ .../internal/matcher/RelationalViatraMatcher.java | 89 +++ .../internal/matcher/UnsafeFunctionalCursor.java | 52 ++ .../viatra/internal/matcher/ViatraTupleLike.java | 23 + .../internal/pquery/AssumptionEvaluator.java | 16 + .../query/viatra/internal/pquery/Dnf2PQuery.java | 201 ++++--- .../query/viatra/internal/pquery/IndexerUtils.java | 48 -- .../internal/pquery/QueryWrapperFactory.java | 173 ++++++ .../query/viatra/internal/pquery/RawPQuery.java | 1 + .../viatra/internal/pquery/RawPatternMatcher.java | 93 ---- .../internal/pquery/RelationViewWrapper.java | 5 + .../viatra/internal/pquery/ResultSetCursor.java | 43 -- .../pquery/StatefulMultisetAggregator.java | 60 ++ .../pquery/StatelessMultisetAggregator.java | 50 ++ .../viatra/internal/pquery/TermEvaluator.java | 32 ++ .../pquery/ValueProviderBasedValuation.java | 14 + .../internal/update/ModelUpdateListener.java | 3 +- .../update/RelationViewUpdateListener.java | 22 +- .../TupleChangingRelationViewUpdateListener.java | 6 +- .../TuplePreservingRelationViewUpdateListener.java | 5 +- .../store/query/viatra/DiagonalQueryTest.java | 471 ++++++++++++++++ .../store/query/viatra/FunctionalQueryTest.java | 607 +++++++++++++++++++++ .../refinery/store/query/viatra/QueryTest.java | 428 +++++++++------ .../store/query/viatra/QueryTransactionTest.java | 384 ++++++++++++- .../store/query/viatra/tests/QueryAssertions.java | 52 ++ .../store/query/viatra/tests/QueryBackendHint.java | 22 + .../store/query/viatra/tests/QueryEngineTest.java | 16 + .../viatra/tests/QueryEvaluationHintSource.java | 19 + .../tools/refinery/store/query/AnyResultSet.java | 11 + .../tools/refinery/store/query/Constraint.java | 65 +++ .../main/java/tools/refinery/store/query/Dnf.java | 175 ------ .../tools/refinery/store/query/DnfBuilder.java | 115 ---- .../java/tools/refinery/store/query/DnfClause.java | 22 - .../java/tools/refinery/store/query/DnfUtils.java | 19 - .../tools/refinery/store/query/EmptyResultSet.java | 22 +- .../refinery/store/query/FunctionalDependency.java | 15 - .../refinery/store/query/ModelQueryAdapter.java | 8 +- .../refinery/store/query/ModelQueryBuilder.java | 8 +- .../store/query/ModelQueryStoreAdapter.java | 5 +- .../tools/refinery/store/query/RelationLike.java | 11 - .../java/tools/refinery/store/query/ResultSet.java | 13 +- .../java/tools/refinery/store/query/Variable.java | 63 --- .../tools/refinery/store/query/dnf/AnyQuery.java | 11 + .../java/tools/refinery/store/query/dnf/Dnf.java | 194 +++++++ .../tools/refinery/store/query/dnf/DnfBuilder.java | 110 ++++ .../tools/refinery/store/query/dnf/DnfClause.java | 23 + .../tools/refinery/store/query/dnf/DnfUtils.java | 19 + .../store/query/dnf/FunctionalDependency.java | 15 + .../refinery/store/query/dnf/FunctionalQuery.java | 103 ++++ .../store/query/dnf/FunctionalQueryBuilder.java | 46 ++ .../java/tools/refinery/store/query/dnf/Query.java | 16 + .../refinery/store/query/dnf/QueryBuilder.java | 71 +++ .../refinery/store/query/dnf/RelationalQuery.java | 93 ++++ .../query/equality/DeepDnfEqualityChecker.java | 2 +- .../store/query/equality/DnfEqualityChecker.java | 2 +- .../query/equality/LiteralEqualityHelper.java | 4 +- .../store/query/literal/AbstractCallLiteral.java | 80 +++ .../store/query/literal/AggregationLiteral.java | 113 ++++ .../store/query/literal/AssignLiteral.java | 44 ++ .../store/query/literal/AssumeLiteral.java | 53 ++ .../store/query/literal/BooleanLiteral.java | 8 +- .../refinery/store/query/literal/CallLiteral.java | 105 ++-- .../refinery/store/query/literal/CanNegate.java | 5 + .../store/query/literal/ConstantLiteral.java | 11 +- .../refinery/store/query/literal/CountLiteral.java | 83 +++ .../store/query/literal/DnfCallLiteral.java | 40 -- .../store/query/literal/EquivalenceLiteral.java | 17 +- .../refinery/store/query/literal/Literal.java | 4 +- .../refinery/store/query/literal/Literals.java | 8 +- .../refinery/store/query/literal/PolarLiteral.java | 5 - .../store/query/literal/RelationViewLiteral.java | 35 -- .../query/substitution/CompositeSubstitution.java | 10 + .../query/substitution/MapBasedSubstitution.java | 2 +- .../query/substitution/RenewingSubstitution.java | 8 +- .../query/substitution/StatelessSubstitution.java | 2 +- .../store/query/substitution/Substitution.java | 23 +- .../store/query/substitution/Substitutions.java | 8 +- .../refinery/store/query/term/Aggregator.java | 13 + .../refinery/store/query/term/AnyDataVariable.java | 33 ++ .../tools/refinery/store/query/term/AnyTerm.java | 16 + .../store/query/term/ArithmeticBinaryOperator.java | 26 + .../store/query/term/ArithmeticBinaryTerm.java | 56 ++ .../store/query/term/ArithmeticUnaryOperator.java | 16 + .../store/query/term/ArithmeticUnaryTerm.java | 51 ++ .../refinery/store/query/term/AssignedValue.java | 8 + .../refinery/store/query/term/BinaryTerm.java | 93 ++++ .../store/query/term/ComparisonOperator.java | 20 + .../refinery/store/query/term/ComparisonTerm.java | 63 +++ .../refinery/store/query/term/ConstantTerm.java | 52 ++ .../tools/refinery/store/query/term/DataSort.java | 29 + .../refinery/store/query/term/DataVariable.java | 87 +++ .../store/query/term/ExtremeValueAggregator.java | 103 ++++ .../tools/refinery/store/query/term/NodeSort.java | 30 + .../refinery/store/query/term/NodeVariable.java | 48 ++ .../refinery/store/query/term/OpaqueTerm.java | 80 +++ .../java/tools/refinery/store/query/term/Sort.java | 11 + .../store/query/term/StatefulAggregate.java | 17 + .../store/query/term/StatefulAggregator.java | 23 + .../store/query/term/StatelessAggregator.java | 20 + .../java/tools/refinery/store/query/term/Term.java | 21 + .../tools/refinery/store/query/term/UnaryTerm.java | 68 +++ .../tools/refinery/store/query/term/Variable.java | 76 +++ .../store/query/term/bool/BoolConstantTerm.java | 16 + .../store/query/term/bool/BoolLogicBinaryTerm.java | 78 +++ .../store/query/term/bool/BoolNotTerm.java | 36 ++ .../refinery/store/query/term/bool/BoolTerms.java | 30 + .../store/query/term/bool/LogicBinaryOperator.java | 17 + .../query/term/int_/IntArithmeticBinaryTerm.java | 48 ++ .../query/term/int_/IntArithmeticUnaryTerm.java | 30 + .../store/query/term/int_/IntComparisonTerm.java | 34 ++ .../query/term/int_/IntExtremeValueAggregator.java | 17 + .../store/query/term/int_/IntSumAggregator.java | 35 ++ .../refinery/store/query/term/int_/IntTerms.java | 81 +++ .../store/query/term/int_/RealToIntTerm.java | 36 ++ .../store/query/term/real/IntToRealTerm.java | 36 ++ .../query/term/real/RealArithmeticBinaryTerm.java | 36 ++ .../query/term/real/RealArithmeticUnaryTerm.java | 30 + .../store/query/term/real/RealComparisonTerm.java | 35 ++ .../term/real/RealExtremeValueAggregator.java | 17 + .../store/query/term/real/RealSumAggregator.java | 85 +++ .../refinery/store/query/term/real/RealTerms.java | 81 +++ .../store/query/valuation/RestrictedValuation.java | 16 + .../query/valuation/SubstitutedValuation.java | 11 + .../refinery/store/query/valuation/Valuation.java | 23 + .../refinery/store/query/view/AnyRelationView.java | 6 +- .../store/query/view/ForbiddenRelationView.java | 16 + .../store/query/view/FunctionalRelationView.java | 38 +- .../refinery/store/query/view/MayRelationView.java | 16 + .../store/query/view/MustRelationView.java | 16 + .../refinery/store/query/view/RelationView.java | 22 +- .../query/view/TuplePreservingRelationView.java | 13 + .../tools/refinery/store/query/DnfBuilderTest.java | 50 +- .../store/query/DnfToDefinitionStringTest.java | 174 ++++++ .../refinery/store/query/DnfToStringTest.java | 172 ------ .../store/query/tests/StructurallyEqualToTest.java | 22 +- .../MismatchDescribingDnfEqualityChecker.java | 8 +- .../refinery/store/query/tests/QueryMatchers.java | 2 +- .../store/query/tests/StructurallyEqualTo.java | 4 +- .../store/reasoning/PartialInterpretation.java | 2 - .../refinery/store/reasoning/ReasoningAdapter.java | 2 +- .../refinery/store/reasoning/ReasoningBuilder.java | 2 +- .../store/reasoning/ReasoningStoreAdapter.java | 2 +- .../reasoning/internal/ReasoningAdapterImpl.java | 2 +- .../reasoning/internal/ReasoningBuilderImpl.java | 2 +- .../internal/ReasoningStoreAdapterImpl.java | 2 +- .../store/reasoning/lifting/DnfLifter.java | 71 +-- .../refinery/store/reasoning/lifting/ModalDnf.java | 4 +- .../store/reasoning/literal/ModalConstraint.java | 46 ++ .../reasoning/literal/ModalDnfCallLiteral.java | 48 -- .../store/reasoning/literal/ModalLiteral.java | 63 --- .../reasoning/literal/ModalRelationLiteral.java | 37 -- .../store/reasoning/literal/PartialLiterals.java | 32 +- .../reasoning/literal/PartialRelationLiteral.java | 32 -- .../reasoning/representation/PartialRelation.java | 36 +- .../reasoning/rule/RelationRefinementAction.java | 2 +- .../tools/refinery/store/reasoning/rule/Rule.java | 2 +- .../refinery/store/reasoning/rule/RuleAction.java | 2 +- .../tools/refinery/store/reasoning/seed/Seed.java | 4 +- .../refinery/store/reasoning/seed/UniformSeed.java | 22 + .../store/reasoning/translator/Advice.java | 2 +- .../reasoning/translator/TranslatedRelation.java | 22 + .../reasoning/translator/TranslationUnit.java | 28 +- .../base/BaseDecisionInterpretation.java | 88 +++ .../base/BaseDecisionTranslationUnit.java | 49 ++ .../translator/base/TranslatedBaseDecision.java | 49 ++ .../TypeHierarchyTranslationUnit.java | 34 +- .../java/tools/refinery/store/tuple/TupleLike.java | 10 + .../java/tools/refinery/store/tuple/TupleN.java | 4 +- 188 files changed, 7325 insertions(+), 1715 deletions(-) delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraTupleLike.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendOperationExecutor.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendPositivePatternCall.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/FlatCostFunction.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/GenericTypeExtend.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchBackendFactory.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchResultProvider.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalOperationCompiler.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/IndexerUtils.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/OmitOutputViatraTupleLike.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RawPatternMatcher.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/ViatraTupleLike.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/AssumptionEvaluator.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/IndexerUtils.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPatternMatcher.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ResultSetCursor.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatefulMultisetAggregator.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatelessMultisetAggregator.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/TermEvaluator.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ValueProviderBasedValuation.java create mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java create mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java create mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java create mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.java create mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java create mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/AnyResultSet.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/Dnf.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/DnfBuilder.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/DnfClause.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/DnfUtils.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/FunctionalDependency.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/RelationLike.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/Variable.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AnyQuery.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfUtils.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalDependency.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQueryBuilder.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/QueryBuilder.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CanNegate.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/literal/DnfCallLiteral.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/literal/PolarLiteral.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/literal/RelationViewLiteral.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/CompositeSubstitution.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/Aggregator.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryOperator.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryOperator.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/AssignedValue.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonOperator.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataSort.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/ExtremeValueAggregator.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeSort.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/OpaqueTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/Sort.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregate.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregator.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatelessAggregator.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/Term.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolConstantTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolLogicBinaryTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/LogicBinaryOperator.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticBinaryTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticUnaryTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntComparisonTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntExtremeValueAggregator.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSumAggregator.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticBinaryTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticUnaryTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealComparisonTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealExtremeValueAggregator.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSumAggregator.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/RestrictedValuation.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/SubstitutedValuation.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenRelationView.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayRelationView.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustRelationView.java create mode 100644 subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToDefinitionStringTest.java delete mode 100644 subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToStringTest.java create mode 100644 subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java delete mode 100644 subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalDnfCallLiteral.java delete mode 100644 subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalLiteral.java delete mode 100644 subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalRelationLiteral.java delete mode 100644 subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/PartialRelationLiteral.java create mode 100644 subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/UniformSeed.java create mode 100644 subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslatedRelation.java create mode 100644 subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionInterpretation.java create mode 100644 subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionTranslationUnit.java create mode 100644 subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/TranslatedBaseDecision.java (limited to 'subprojects/store-query-viatra/src/main/java/tools') 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 24aa52e2..7ae86f9f 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,8 @@ 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.AnyQuery; +import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.query.ModelQueryBuilder; import java.util.Collection; @@ -23,21 +24,21 @@ public interface ViatraModelQueryBuilder extends ModelQueryBuilder { ViatraModelQueryBuilder searchBackend(IQueryBackendFactory queryBackendFactory); @Override - default ViatraModelQueryBuilder queries(Dnf... queries) { + default ViatraModelQueryBuilder queries(AnyQuery... 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(AnyQuery query); - ViatraModelQueryBuilder query(Dnf query, QueryEvaluationHint queryEvaluationHint); + ViatraModelQueryBuilder query(AnyQuery query, QueryEvaluationHint queryEvaluationHint); ViatraModelQueryBuilder computeHint(Function computeHint); diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraTupleLike.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraTupleLike.java deleted file mode 100644 index 46c28434..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraTupleLike.java +++ /dev/null @@ -1,18 +0,0 @@ -package tools.refinery.store.query.viatra; - -import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; -import tools.refinery.store.tuple.Tuple1; -import tools.refinery.store.tuple.TupleLike; - -public record ViatraTupleLike(ITuple wrappedTuple) implements TupleLike { - @Override - public int getSize() { - return wrappedTuple.getSize(); - } - - @Override - public int get(int element) { - var wrappedValue = (Tuple1) wrappedTuple.get(element); - return wrappedValue.value0(); - } -} 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 37700413..8be30fee 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,10 +7,18 @@ 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.model.ModelListener; +import tools.refinery.store.query.AnyResultSet; import tools.refinery.store.query.EmptyResultSet; import tools.refinery.store.query.ResultSet; +import tools.refinery.store.query.dnf.AnyQuery; +import tools.refinery.store.query.dnf.FunctionalQuery; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.query.dnf.RelationalQuery; import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; +import tools.refinery.store.query.viatra.internal.matcher.FunctionalViatraMatcher; +import tools.refinery.store.query.viatra.internal.matcher.RawPatternMatcher; +import tools.refinery.store.query.viatra.internal.matcher.RelationalViatraMatcher; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -19,7 +27,7 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; -public class ViatraModelQueryAdapterImpl implements ViatraModelQueryAdapter { +public class ViatraModelQueryAdapterImpl implements ViatraModelQueryAdapter, ModelListener { private static final String DELAY_MESSAGE_DELIVERY_FIELD_NAME = "delayMessageDelivery"; private static final MethodHandle SET_UPDATE_PROPAGATION_DELAYED_HANDLE; private static final String QUERY_BACKENDS_FIELD_NAME = "queryBackends"; @@ -28,8 +36,7 @@ public class ViatraModelQueryAdapterImpl implements ViatraModelQueryAdapter { private final Model model; private final ViatraModelQueryStoreAdapterImpl storeAdapter; private final ViatraQueryEngineImpl queryEngine; - - private final Map resultSets; + private final Map resultSets; private boolean pendingChanges; static { @@ -49,9 +56,8 @@ public class ViatraModelQueryAdapterImpl implements ViatraModelQueryAdapter { this.model = model; this.storeAdapter = storeAdapter; var scope = new RelationalScope(this); - queryEngine = (ViatraQueryEngineImpl) AdvancedViatraQueryEngine.createUnmanagedEngine(scope); - - + queryEngine = (ViatraQueryEngineImpl) AdvancedViatraQueryEngine.createUnmanagedEngine(scope, + storeAdapter.getEngineOptions()); var querySpecifications = storeAdapter.getQuerySpecifications(); GenericQueryGroup.of( @@ -60,14 +66,28 @@ public class ViatraModelQueryAdapterImpl implements ViatraModelQueryAdapter { var vacuousQueries = storeAdapter.getVacuousQueries(); resultSets = new LinkedHashMap<>(querySpecifications.size() + vacuousQueries.size()); for (var entry : querySpecifications.entrySet()) { - var matcher = queryEngine.getMatcher(entry.getValue()); - resultSets.put(entry.getKey(), matcher); + var rawPatternMatcher = queryEngine.getMatcher(entry.getValue()); + var query = entry.getKey(); + resultSets.put(query, createResultSet((Query) query, rawPatternMatcher)); } for (var vacuousQuery : vacuousQueries) { - resultSets.put(vacuousQuery, new EmptyResultSet()); + resultSets.put(vacuousQuery, new EmptyResultSet<>(this, (Query) vacuousQuery)); } setUpdatePropagationDelayed(true); + model.addListener(this); + } + + private ResultSet createResultSet(Query query, RawPatternMatcher matcher) { + if (query instanceof RelationalQuery relationalQuery) { + @SuppressWarnings("unchecked") + var resultSet = (ResultSet) new RelationalViatraMatcher(this, relationalQuery, matcher); + return resultSet; + } else if (query instanceof FunctionalQuery functionalQuery) { + return new FunctionalViatraMatcher<>(this, functionalQuery, matcher); + } else { + throw new IllegalArgumentException("Unknown query: " + query); + } } private void setUpdatePropagationDelayed(boolean value) { @@ -105,12 +125,14 @@ public class ViatraModelQueryAdapterImpl implements ViatraModelQueryAdapter { } @Override - public ResultSet getResultSet(Dnf query) { + public ResultSet getResultSet(Query query) { var resultSet = resultSets.get(query); if (resultSet == null) { throw new IllegalArgumentException("No matcher for query %s in model".formatted(query.name())); } - return resultSet; + @SuppressWarnings("unchecked") + var typedResultSet = (ResultSet) resultSet; + return typedResultSet; } @Override @@ -142,4 +164,9 @@ public class ViatraModelQueryAdapterImpl implements ViatraModelQueryAdapter { } pendingChanges = false; } + + @Override + public void afterRestore() { + flushChanges(); + } } 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 13641ace..bfabf26e 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 @@ -2,33 +2,40 @@ package tools.refinery.store.query.viatra.internal; import org.eclipse.viatra.query.runtime.api.IQuerySpecification; import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions; -import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.LocalSearchGenericBackendFactory; +import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.LocalSearchHintOptions; import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory; import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; 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.AnyQuery; +import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.query.viatra.ViatraModelQueryBuilder; +import tools.refinery.store.query.viatra.internal.localsearch.FlatCostFunction; +import tools.refinery.store.query.viatra.internal.localsearch.RelationalLocalSearchBackendFactory; +import tools.refinery.store.query.viatra.internal.matcher.RawPatternMatcher; import tools.refinery.store.query.viatra.internal.pquery.Dnf2PQuery; -import tools.refinery.store.query.viatra.internal.pquery.RawPatternMatcher; import java.util.*; import java.util.function.Function; public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder implements ViatraModelQueryBuilder { private ViatraQueryEngineOptions.Builder engineOptionsBuilder; + private QueryEvaluationHint defaultHint = new QueryEvaluationHint(Map.of( + // Use a cost function that ignores the initial (empty) model but allows higher arity input keys. + LocalSearchHintOptions.PLANNER_COST_FUNCTION, new FlatCostFunction() + ), (IQueryBackendFactory) null); private final Dnf2PQuery dnf2PQuery = new Dnf2PQuery(); - private final Set vacuousQueries = new LinkedHashSet<>(); - private final Map> querySpecifications = new LinkedHashMap<>(); + private final Set vacuousQueries = new LinkedHashSet<>(); + private final Map> querySpecifications = new LinkedHashMap<>(); public ViatraModelQueryBuilderImpl(ModelStoreBuilder storeBuilder) { super(storeBuilder); engineOptionsBuilder = new ViatraQueryEngineOptions.Builder() .withDefaultBackend(ReteBackendFactory.INSTANCE) .withDefaultCachingBackend(ReteBackendFactory.INSTANCE) - .withDefaultSearchBackend(LocalSearchGenericBackendFactory.INSTANCE); + .withDefaultSearchBackend(RelationalLocalSearchBackendFactory.INSTANCE); } @Override @@ -39,7 +46,7 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp @Override public ViatraModelQueryBuilder defaultHint(QueryEvaluationHint queryEvaluationHint) { - engineOptionsBuilder.withDefaultHint(queryEvaluationHint); + defaultHint = defaultHint.overrideBy(queryEvaluationHint); return this; } @@ -62,15 +69,16 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp } @Override - public ViatraModelQueryBuilder query(Dnf query) { + public ViatraModelQueryBuilder query(AnyQuery query) { if (querySpecifications.containsKey(query) || vacuousQueries.contains(query)) { // Ignore duplicate queries. return this; } - var reduction = query.getReduction(); + var dnf = query.getDnf(); + var reduction = dnf.getReduction(); switch (reduction) { case NOT_REDUCIBLE -> { - var pQuery = dnf2PQuery.translate(query); + var pQuery = dnf2PQuery.translate(dnf); querySpecifications.put(query, pQuery.build()); } case ALWAYS_FALSE -> vacuousQueries.add(query); @@ -82,9 +90,9 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp } @Override - public ViatraModelQueryBuilder query(Dnf query, QueryEvaluationHint queryEvaluationHint) { + public ViatraModelQueryBuilder query(AnyQuery query, QueryEvaluationHint queryEvaluationHint) { + hint(query.getDnf(), queryEvaluationHint); query(query); - hint(query, queryEvaluationHint); return this; } @@ -96,26 +104,35 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp @Override public ViatraModelQueryBuilder hint(Dnf dnf, QueryEvaluationHint queryEvaluationHint) { - var pQuery = dnf2PQuery.getAlreadyTranslated(dnf); - if (pQuery == null) { - if (vacuousQueries.contains(dnf)) { - // Ignore hits for queries that will never be executed by the query engine. - return this; - } - throw new IllegalArgumentException( - "Cannot specify hint for %s, because it was not added to the query engine".formatted(dnf.name())); - } - pQuery.setEvaluationHints(pQuery.getEvaluationHints().overrideBy(queryEvaluationHint)); + dnf2PQuery.hint(dnf, queryEvaluationHint); return this; } @Override public ViatraModelQueryStoreAdapterImpl createStoreAdapter(ModelStore store) { validateSymbols(store); - return new ViatraModelQueryStoreAdapterImpl(store, engineOptionsBuilder.build(), dnf2PQuery.getRelationViews(), + dnf2PQuery.assertNoUnusedHints(); + return new ViatraModelQueryStoreAdapterImpl(store, buildEngineOptions(), dnf2PQuery.getRelationViews(), Collections.unmodifiableMap(querySpecifications), Collections.unmodifiableSet(vacuousQueries)); } + private ViatraQueryEngineOptions buildEngineOptions() { + // Workaround: manually override the default backend, because {@link ViatraQueryEngineOptions.Builder} + // ignores all backend requirements except {@code SPECIFIC}. + switch (defaultHint.getQueryBackendRequirementType()) { + case SPECIFIC -> engineOptionsBuilder.withDefaultBackend(defaultHint.getQueryBackendFactory()); + case DEFAULT_CACHING -> engineOptionsBuilder.withDefaultBackend( + engineOptionsBuilder.build().getDefaultCachingBackendFactory()); + case DEFAULT_SEARCH -> engineOptionsBuilder.withDefaultBackend( + engineOptionsBuilder.build().getDefaultSearchBackendFactory()); + case UNSPECIFIED -> { + // Nothing to do, leave the default backend unchanged. + } + } + engineOptionsBuilder.withDefaultHint(defaultHint); + return engineOptionsBuilder.build(); + } + private void validateSymbols(ModelStore store) { var symbols = store.getSymbols(); for (var relationView : dnf2PQuery.getRelationViews().keySet()) { 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 00660d0b..04c48c43 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,9 +5,9 @@ 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.AnyQuery; import tools.refinery.store.query.viatra.ViatraModelQueryStoreAdapter; -import tools.refinery.store.query.viatra.internal.pquery.RawPatternMatcher; +import tools.refinery.store.query.viatra.internal.matcher.RawPatternMatcher; import tools.refinery.store.query.view.AnyRelationView; import java.util.*; @@ -16,20 +16,20 @@ public class ViatraModelQueryStoreAdapterImpl implements ViatraModelQueryStoreAd private final ModelStore store; private final ViatraQueryEngineOptions engineOptions; private final Map inputKeys; - private final Map> querySpecifications; - private final Set vacuousQueries; - private final Set allQueries; + private final Map> querySpecifications; + private final Set vacuousQueries; + private final Set allQueries; ViatraModelQueryStoreAdapterImpl(ModelStore store, ViatraQueryEngineOptions engineOptions, Map inputKeys, - Map> querySpecifications, - Set vacuousQueries) { + Map> querySpecifications, + Set vacuousQueries) { this.store = store; this.engineOptions = engineOptions; this.inputKeys = inputKeys; this.querySpecifications = querySpecifications; this.vacuousQueries = vacuousQueries; - var mutableAllQueries = new LinkedHashSet(querySpecifications.size() + vacuousQueries.size()); + var mutableAllQueries = new LinkedHashSet(querySpecifications.size() + vacuousQueries.size()); mutableAllQueries.addAll(querySpecifications.keySet()); mutableAllQueries.addAll(vacuousQueries); this.allQueries = Collections.unmodifiableSet(mutableAllQueries); @@ -49,15 +49,15 @@ public class ViatraModelQueryStoreAdapterImpl implements ViatraModelQueryStoreAd } @Override - public Collection getQueries() { + public Collection getQueries() { return allQueries; } - Map> getQuerySpecifications() { + Map> getQuerySpecifications() { return querySpecifications; } - Set getVacuousQueries() { + Set getVacuousQueries() { return vacuousQueries; } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java index cba3fa08..d2c6beb4 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java @@ -3,6 +3,8 @@ package tools.refinery.store.query.viatra.internal.context; import org.eclipse.viatra.query.runtime.matchers.context.AbstractQueryMetaContext; import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; import org.eclipse.viatra.query.runtime.matchers.context.InputKeyImplication; +import org.eclipse.viatra.query.runtime.matchers.context.common.JavaTransitiveInstancesKey; +import tools.refinery.store.query.term.DataSort; import tools.refinery.store.query.viatra.internal.pquery.RelationViewWrapper; import tools.refinery.store.query.view.AnyRelationView; @@ -37,6 +39,9 @@ public class RelationalQueryMetaContext extends AbstractQueryMetaContext { @Override public Collection getImplications(IInputKey implyingKey) { + if (implyingKey instanceof JavaTransitiveInstancesKey) { + return List.of(); + } var relationView = checkKey(implyingKey); var relationViewImplications = relationView.getImpliedRelationViews(); var inputKeyImplications = new HashSet(relationViewImplications.size()); @@ -52,11 +57,25 @@ public class RelationalQueryMetaContext extends AbstractQueryMetaContext { relationViewImplication.impliedIndices())); } } + var sorts = relationView.getSorts(); + int arity = relationView.arity(); + for (int i = 0; i < arity; i++) { + var sort = sorts.get(i); + if (sort instanceof DataSort dataSort) { + var javaTransitiveInstancesKey = new JavaTransitiveInstancesKey(dataSort.type()); + var javaImplication = new InputKeyImplication(implyingKey, javaTransitiveInstancesKey, + List.of(i)); + inputKeyImplications.add(javaImplication); + } + } return inputKeyImplications; } @Override public Map, Set> getFunctionalDependencies(IInputKey key) { + if (key instanceof JavaTransitiveInstancesKey) { + return Map.of(); + } var relationView = checkKey(key); var functionalDependencies = relationView.getFunctionalDependencies(); var flattened = new HashMap, Set>(functionalDependencies.size()); diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java index 01d20d3e..854817b1 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java @@ -54,7 +54,8 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext { @Override public boolean isIndexed(IInputKey key, IndexingService service) { - if (key instanceof AnyRelationView relationalKey) { + if (key instanceof RelationViewWrapper wrapper) { + var relationalKey = wrapper.getWrappedKey(); return this.modelUpdateListener.containsRelationView(relationalKey); } else { return false; @@ -83,10 +84,7 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext { @Override public int countTuples(IInputKey key, TupleMask seedMask, ITuple seed) { - var relationViewKey = checkKey(key); - Iterable allObjects = relationViewKey.getAll(model); - Iterable filteredBySeed = filter(allObjects, objectArray -> isMatching(objectArray, seedMask, seed)); - Iterator iterator = filteredBySeed.iterator(); + Iterator iterator = enumerate(key, seedMask, seed).iterator(); int result = 0; while (iterator.hasNext()) { iterator.next(); @@ -102,13 +100,25 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext { @Override public Iterable enumerateTuples(IInputKey key, TupleMask seedMask, ITuple seed) { + var filteredBySeed = enumerate(key, seedMask, seed); + return map(filteredBySeed, Tuples::flatTupleOf); + } + + @Override + public Iterable enumerateValues(IInputKey key, TupleMask seedMask, ITuple seed) { + var index = seedMask.getFirstOmittedIndex().orElseThrow( + () -> new IllegalArgumentException("Seed mask does not omit a value")); + var filteredBySeed = enumerate(key, seedMask, seed); + return map(filteredBySeed, array -> array[index]); + } + + private Iterable enumerate(IInputKey key, TupleMask seedMask, ITuple seed) { var relationViewKey = checkKey(key); Iterable allObjects = relationViewKey.getAll(model); - Iterable filteredBySeed = filter(allObjects, objectArray -> isMatching(objectArray, seedMask, seed)); - return map(filteredBySeed, Tuples::flatTupleOf); + return filter(allObjects, objectArray -> isMatching(objectArray, seedMask, seed)); } - private boolean isMatching(Object[] tuple, TupleMask seedMask, ITuple seed) { + private static boolean isMatching(Object[] tuple, TupleMask seedMask, ITuple seed) { for (int i = 0; i < seedMask.indices.length; i++) { final Object seedElement = seed.get(i); final Object tupleElement = tuple[seedMask.indices[i]]; @@ -119,11 +129,6 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext { return true; } - @Override - public Iterable enumerateValues(IInputKey key, TupleMask seedMask, ITuple seed) { - return enumerateTuples(key, seedMask, seed); - } - @Override public boolean containsTuple(IInputKey key, ITuple seed) { var relationViewKey = checkKey(key); diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendOperationExecutor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendOperationExecutor.java new file mode 100644 index 00000000..2d3dd5a7 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendOperationExecutor.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2010-2013, Zoltan Ujhelyi, Akos Horvath, Istvan Rath and Daniel Varro + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-v20.html. + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package tools.refinery.store.query.viatra.internal.localsearch; + +import org.eclipse.viatra.query.runtime.localsearch.MatchingFrame; +import org.eclipse.viatra.query.runtime.localsearch.matcher.ISearchContext; +import org.eclipse.viatra.query.runtime.localsearch.operations.ISearchOperation.ISearchOperationExecutor; + +import java.util.Iterator; + +/** + * An operation that can be used to enumerate all possible values for a single position based on a constraint + * @author Zoltan Ujhelyi, Akos Horvath + * @since 2.0 + */ +abstract class ExtendOperationExecutor implements ISearchOperationExecutor { + + private Iterator it; + + /** + * Returns an iterator with the possible options from the current state + * @since 2.0 + */ + @SuppressWarnings("squid:S1452") + protected abstract Iterator getIterator(MatchingFrame frame, ISearchContext context); + /** + * Updates the frame with the next element of the iterator. Called during {@link #execute(MatchingFrame, ISearchContext)}. + * + * @return true if the update is successful or false otherwise; in case of false is returned, the next element should be taken from the iterator. + * @since 2.0 + */ + protected abstract boolean fillInValue(T newValue, MatchingFrame frame, ISearchContext context); + + /** + * Restores the frame to the state before {@link #fillInValue(Object, MatchingFrame, ISearchContext)}. Called during + * {@link #onBacktrack(MatchingFrame, ISearchContext)}. + * + * @since 2.0 + */ + protected abstract void cleanup(MatchingFrame frame, ISearchContext context); + + @Override + public void onInitialize(MatchingFrame frame, ISearchContext context) { + it = getIterator(frame, context); + } + + @Override + public void onBacktrack(MatchingFrame frame, ISearchContext context) { + it = null; + + } + + /** + * Fixed version of {@link org.eclipse.viatra.query.runtime.localsearch.operations.ExtendOperationExecutor#execute} + * that handles failed unification of variables correctly. + * @param frame The matching frame to extend. + * @param context The search context. + * @return {@code true} if an extension was found, {@code false} otherwise. + */ + @Override + public boolean execute(MatchingFrame frame, ISearchContext context) { + while (it.hasNext()) { + var newValue = it.next(); + if (fillInValue(newValue, frame, context)) { + return true; + } + } + return false; + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendPositivePatternCall.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendPositivePatternCall.java new file mode 100644 index 00000000..aaaece80 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendPositivePatternCall.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-v20.html. + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package tools.refinery.store.query.viatra.internal.localsearch; + +import org.eclipse.viatra.query.runtime.localsearch.MatchingFrame; +import org.eclipse.viatra.query.runtime.localsearch.matcher.ISearchContext; +import org.eclipse.viatra.query.runtime.localsearch.operations.IPatternMatcherOperation; +import org.eclipse.viatra.query.runtime.localsearch.operations.ISearchOperation; +import org.eclipse.viatra.query.runtime.localsearch.operations.util.CallInformation; +import org.eclipse.viatra.query.runtime.matchers.backend.IQueryResultProvider; +import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; +import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; +import org.eclipse.viatra.query.runtime.matchers.tuple.VolatileModifiableMaskedTuple; + +import java.util.Iterator; +import java.util.List; +import java.util.function.Function; + +/** + * @author Grill Balázs + * @since 1.4 + * + */ +public class ExtendPositivePatternCall implements ISearchOperation, IPatternMatcherOperation { + + private class Executor extends ExtendOperationExecutor { + private final VolatileModifiableMaskedTuple maskedTuple; + + public Executor() { + maskedTuple = new VolatileModifiableMaskedTuple(information.getThinFrameMask()); + } + + @Override + protected Iterator getIterator(MatchingFrame frame, ISearchContext context) { + maskedTuple.updateTuple(frame); + IQueryResultProvider matcher = context.getMatcher(information.getCallWithAdornment()); + return matcher.getAllMatches(information.getParameterMask(), maskedTuple).iterator(); + } + + /** + * @since 2.0 + */ + @Override + protected boolean fillInValue(Tuple result, MatchingFrame frame, ISearchContext context) { + TupleMask mask = information.getFullFrameMask(); + // The first loop clears out the elements from a possible previous iteration + for(int i : information.getFreeParameterIndices()) { + mask.set(frame, i, null); + } + for(int i : information.getFreeParameterIndices()) { + Object oldValue = mask.getValue(frame, i); + Object valueToFill = result.get(i); + if (oldValue != null && !oldValue.equals(valueToFill)){ + // If the inverse map contains more than one values for the same key, it means that these arguments are unified by the caller. + // In this case if the callee assigns different values the frame shall be dropped + return false; + } + mask.set(frame, i, valueToFill); + } + return true; + } + + @Override + protected void cleanup(MatchingFrame frame, ISearchContext context) { + TupleMask mask = information.getFullFrameMask(); + for(int i : information.getFreeParameterIndices()){ + mask.set(frame, i, null); + } + + } + + @Override + public ISearchOperation getOperation() { + return ExtendPositivePatternCall.this; + } + } + + private final CallInformation information; + + /** + * @since 1.7 + */ + public ExtendPositivePatternCall(CallInformation information) { + this.information = information; + } + + @Override + public ISearchOperationExecutor createExecutor() { + return new Executor(); + } + + @Override + public List getVariablePositions() { + return information.getVariablePositions(); + } + + @Override + public String toString() { + return toString(Object::toString); + } + + @Override + public String toString(@SuppressWarnings("squid:S4276") Function variableMapping) { + return "extend find " + information.toString(variableMapping); + } + + @Override + public CallInformation getCallInformation() { + return information; + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/FlatCostFunction.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/FlatCostFunction.java new file mode 100644 index 00000000..84cab142 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/FlatCostFunction.java @@ -0,0 +1,30 @@ +package tools.refinery.store.query.viatra.internal.localsearch; + +import org.eclipse.viatra.query.runtime.localsearch.planner.cost.IConstraintEvaluationContext; +import org.eclipse.viatra.query.runtime.localsearch.planner.cost.impl.StatisticsBasedConstraintCostFunction; +import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; +import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.TypeConstraint; +import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; +import org.eclipse.viatra.query.runtime.matchers.util.Accuracy; + +import java.util.Optional; + +public class FlatCostFunction extends StatisticsBasedConstraintCostFunction { + public FlatCostFunction() { + // No inverse navigation penalty thanks to relational storage. + super(0); + } + + @Override + public Optional projectionSize(IConstraintEvaluationContext input, IInputKey supplierKey, TupleMask groupMask, Accuracy requiredAccuracy) { + // We always start from an empty model, where every projection is of size 0. + // Therefore, projection size estimation is meaningless. + return Optional.empty(); + } + + @Override + protected double _calculateCost(TypeConstraint constraint, IConstraintEvaluationContext input) { + // Assume a flat cost for each relation. Maybe adjust in the future if we perform indexing? + return DEFAULT_COST; + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/GenericTypeExtend.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/GenericTypeExtend.java new file mode 100644 index 00000000..64653658 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/GenericTypeExtend.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-v20.html. + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package tools.refinery.store.query.viatra.internal.localsearch; + +import org.eclipse.viatra.query.runtime.localsearch.MatchingFrame; +import org.eclipse.viatra.query.runtime.localsearch.matcher.ISearchContext; +import org.eclipse.viatra.query.runtime.localsearch.operations.IIteratingSearchOperation; +import org.eclipse.viatra.query.runtime.localsearch.operations.ISearchOperation; +import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; +import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; +import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; +import org.eclipse.viatra.query.runtime.matchers.tuple.VolatileMaskedTuple; +import org.eclipse.viatra.query.runtime.matchers.util.Preconditions; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * @author Zoltan Ujhelyi + * @since 1.7 + */ +public class GenericTypeExtend implements IIteratingSearchOperation { + private class Executor extends ExtendOperationExecutor { + private final VolatileMaskedTuple maskedTuple; + + public Executor() { + this.maskedTuple = new VolatileMaskedTuple(callMask); + } + + @Override + protected Iterator getIterator(MatchingFrame frame, ISearchContext context) { + maskedTuple.updateTuple(frame); + return context.getRuntimeContext().enumerateTuples(type, indexerMask, maskedTuple).iterator(); + } + + @Override + protected boolean fillInValue(Tuple newTuple, MatchingFrame frame, ISearchContext context) { + for (Integer position : unboundVariableIndices) { + frame.setValue(position, null); + } + for (int i = 0; i < positions.length; i++) { + Object newValue = newTuple.get(i); + Object oldValue = frame.getValue(positions[i]); + if (oldValue != null && !Objects.equals(oldValue, newValue)) { + // If positions tuple maps more than one values for the same element (e.g. loop), it means that + // these arguments are to unified by the caller. In this case if the callee assigns different values + // the frame shall be considered a failed match + return false; + } + frame.setValue(positions[i], newValue); + } + return true; + } + + @Override + protected void cleanup(MatchingFrame frame, ISearchContext context) { + for (Integer position : unboundVariableIndices) { + frame.setValue(position, null); + } + } + + @Override + public ISearchOperation getOperation() { + return GenericTypeExtend.this; + } + } + + private final IInputKey type; + private final int[] positions; + private final List positionList; + private final Set unboundVariableIndices; + private final TupleMask indexerMask; + private final TupleMask callMask; + + /** + * + * @param type + * the type to execute the extend operation on + * @param positions + * the parameter positions that represent the variables of the input key + * @param unboundVariableIndices + * the set of positions that are bound at the start of the operation + */ + public GenericTypeExtend(IInputKey type, int[] positions, TupleMask callMask, TupleMask indexerMask, Set unboundVariableIndices) { + Preconditions.checkArgument(positions.length == type.getArity(), + "The type %s requires %d parameters, but %d positions are provided", type.getPrettyPrintableName(), + type.getArity(), positions.length); + List modifiablePositionList = new ArrayList<>(); + for (int position : positions) { + modifiablePositionList.add(position); + } + this.positionList = Collections.unmodifiableList(modifiablePositionList); + this.positions = positions; + this.type = type; + + this.unboundVariableIndices = unboundVariableIndices; + this.indexerMask = indexerMask; + this.callMask = callMask; + } + + @Override + public IInputKey getIteratedInputKey() { + return type; + } + + @Override + public ISearchOperationExecutor createExecutor() { + return new Executor(); + } + + @Override + public List getVariablePositions() { + return positionList; + } + + @Override + public String toString() { + return toString(Object::toString); + } + + @Override + public String toString(@SuppressWarnings("squid:S4276") Function variableMapping) { + return "extend " + type.getPrettyPrintableName() + "(" + + positionList.stream() + .map(input -> String.format("%s%s", unboundVariableIndices.contains(input) ? "-" : "+", variableMapping.apply(input))) + .collect(Collectors.joining(", ")) + + ")"; + } + +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchBackendFactory.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchBackendFactory.java new file mode 100644 index 00000000..156eb313 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchBackendFactory.java @@ -0,0 +1,55 @@ +package tools.refinery.store.query.viatra.internal.localsearch; + +import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.AbstractLocalSearchResultProvider; +import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.LocalSearchBackend; +import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.LocalSearchHints; +import org.eclipse.viatra.query.runtime.localsearch.plan.IPlanProvider; +import org.eclipse.viatra.query.runtime.localsearch.plan.SimplePlanProvider; +import org.eclipse.viatra.query.runtime.matchers.backend.IMatcherCapability; +import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackend; +import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory; +import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; +import org.eclipse.viatra.query.runtime.matchers.context.IQueryBackendContext; +import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery; + +public class RelationalLocalSearchBackendFactory implements IQueryBackendFactory { + public static final RelationalLocalSearchBackendFactory INSTANCE = new RelationalLocalSearchBackendFactory(); + + private RelationalLocalSearchBackendFactory() { + } + + @Override + public IQueryBackend create(IQueryBackendContext context) { + return new LocalSearchBackend(context) { + // Create a new {@link IPlanProvider}, because the original {@link LocalSearchBackend#planProvider} is not + // accessible. + private final IPlanProvider planProvider = new SimplePlanProvider(context.getLogger()); + + @Override + protected AbstractLocalSearchResultProvider initializeResultProvider(PQuery query, + QueryEvaluationHint hints) { + return new RelationalLocalSearchResultProvider(this, context, query, planProvider, hints); + } + + @Override + public IQueryBackendFactory getFactory() { + return RelationalLocalSearchBackendFactory.this; + } + }; + } + + @Override + public Class getBackendClass() { + return LocalSearchBackend.class; + } + + @Override + public IMatcherCapability calculateRequiredCapability(PQuery pQuery, QueryEvaluationHint queryEvaluationHint) { + return LocalSearchHints.parse(queryEvaluationHint); + } + + @Override + public boolean isCaching() { + return false; + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchResultProvider.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchResultProvider.java new file mode 100644 index 00000000..be2a38ca --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchResultProvider.java @@ -0,0 +1,23 @@ +package tools.refinery.store.query.viatra.internal.localsearch; + +import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.AbstractLocalSearchResultProvider; +import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.LocalSearchBackend; +import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.LocalSearchHints; +import org.eclipse.viatra.query.runtime.localsearch.plan.IPlanProvider; +import org.eclipse.viatra.query.runtime.localsearch.planner.compiler.IOperationCompiler; +import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; +import org.eclipse.viatra.query.runtime.matchers.context.IQueryBackendContext; +import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery; + +class RelationalLocalSearchResultProvider extends AbstractLocalSearchResultProvider { + public RelationalLocalSearchResultProvider(LocalSearchBackend backend, IQueryBackendContext context, PQuery query, + IPlanProvider planProvider, QueryEvaluationHint userHints) { + super(backend, context, query, planProvider, userHints); + } + + @Override + protected IOperationCompiler getOperationCompiler(IQueryBackendContext backendContext, + LocalSearchHints configuration) { + return new RelationalOperationCompiler(runtimeContext); + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalOperationCompiler.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalOperationCompiler.java new file mode 100644 index 00000000..b6832b39 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalOperationCompiler.java @@ -0,0 +1,65 @@ +package tools.refinery.store.query.viatra.internal.localsearch; + +import org.eclipse.viatra.query.runtime.localsearch.operations.generic.GenericTypeExtendSingleValue; +import org.eclipse.viatra.query.runtime.localsearch.operations.util.CallInformation; +import org.eclipse.viatra.query.runtime.localsearch.planner.compiler.GenericOperationCompiler; +import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; +import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext; +import org.eclipse.viatra.query.runtime.matchers.psystem.PVariable; +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.tuple.Tuple; +import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; + +import java.util.*; + +public class RelationalOperationCompiler extends GenericOperationCompiler { + public RelationalOperationCompiler(IQueryRuntimeContext runtimeContext) { + super(runtimeContext); + } + + @Override + protected void createExtend(TypeConstraint typeConstraint, Map variableMapping) { + IInputKey inputKey = typeConstraint.getSupplierKey(); + Tuple tuple = typeConstraint.getVariablesTuple(); + + int[] positions = new int[tuple.getSize()]; + List boundVariableIndices = new ArrayList<>(); + List boundVariables = new ArrayList<>(); + Set unboundVariables = new HashSet<>(); + for (int i = 0; i < tuple.getSize(); i++) { + PVariable variable = (PVariable) tuple.get(i); + Integer position = variableMapping.get(variable); + positions[i] = position; + if (variableBindings.get(typeConstraint).contains(position)) { + boundVariableIndices.add(i); + boundVariables.add(position); + } else { + unboundVariables.add(position); + } + } + TupleMask indexerMask = TupleMask.fromSelectedIndices(inputKey.getArity(), boundVariableIndices); + TupleMask callMask = TupleMask.fromSelectedIndices(variableMapping.size(), boundVariables); + // If multiple tuple elements from the indexer should be bound to the same variable, we must use a + // {@link GenericTypeExtend} check whether the tuple elements have the same value. + if (unboundVariables.size() == 1 && indexerMask.getSize() + 1 == indexerMask.getSourceWidth()) { + operations.add(new GenericTypeExtendSingleValue(inputKey, positions, callMask, indexerMask, + unboundVariables.iterator().next())); + } else { + // Use a fixed version of + // {@code org.eclipse.viatra.query.runtime.localsearch.operations.generic.GenericTypeExtend} that handles + // failed unification of variables correctly. + operations.add(new GenericTypeExtend(inputKey, positions, callMask, indexerMask, unboundVariables)); + } + } + + @Override + protected void createExtend(PositivePatternCall pCall, Map variableMapping) { + CallInformation information = CallInformation.create(pCall, variableMapping, variableBindings.get(pCall)); + // Use a fixed version of + // {@code org.eclipse.viatra.query.runtime.localsearch.operations.extend.ExtendPositivePatternCall} that handles + // failed unification of variables correctly. + operations.add(new ExtendPositivePatternCall(information)); + dependencies.add(information.getCallWithAdornment()); + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java new file mode 100644 index 00000000..4daa14a1 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java @@ -0,0 +1,48 @@ +package tools.refinery.store.query.viatra.internal.matcher; + +import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; +import org.eclipse.viatra.query.runtime.rete.index.IterableIndexer; +import tools.refinery.store.map.Cursor; +import tools.refinery.store.tuple.TupleLike; + +import java.util.Iterator; + +class FunctionalCursor implements Cursor { + private final IterableIndexer indexer; + private final Iterator iterator; + private boolean terminated; + private TupleLike key; + private T value; + + public FunctionalCursor(IterableIndexer indexer) { + this.indexer = indexer; + iterator = indexer.getSignatures().iterator(); + } + + @Override + public TupleLike getKey() { + return key; + } + + @Override + public T getValue() { + return value; + } + + @Override + public boolean isTerminated() { + return terminated; + } + + @Override + public boolean move() { + if (!terminated && iterator.hasNext()) { + var match = iterator.next(); + key = new ViatraTupleLike(match); + value = MatcherUtils.getSingleValue(indexer.get(match)); + return true; + } + terminated = true; + return false; + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java new file mode 100644 index 00000000..6aa45af2 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java @@ -0,0 +1,91 @@ +package tools.refinery.store.query.viatra.internal.matcher; + +import org.eclipse.viatra.query.runtime.matchers.backend.IQueryResultProvider; +import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; +import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; +import org.eclipse.viatra.query.runtime.rete.index.IterableIndexer; +import org.eclipse.viatra.query.runtime.rete.matcher.RetePatternMatcher; +import tools.refinery.store.map.Cursor; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.ResultSet; +import tools.refinery.store.query.dnf.FunctionalQuery; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; +import tools.refinery.store.tuple.TupleLike; + +/** + * Directly access the tuples inside a VIATRA pattern matcher.

+ * This class neglects calling + * {@link org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext#wrapTuple(org.eclipse.viatra.query.runtime.matchers.tuple.Tuple)} + * and + * {@link org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext#unwrapTuple(org.eclipse.viatra.query.runtime.matchers.tuple.Tuple)}, + * because {@link tools.refinery.store.query.viatra.internal.context.RelationalRuntimeContext} provides a trivial + * implementation for these methods. + * Using this class with any other runtime context may lead to undefined behavior. + */ +public class FunctionalViatraMatcher implements ResultSet { + private final ViatraModelQueryAdapterImpl adapter; + private final FunctionalQuery query; + private final TupleMask emptyMask; + private final TupleMask omitOutputMask; + private final IQueryResultProvider backend; + private final IterableIndexer omitOutputIndexer; + + public FunctionalViatraMatcher(ViatraModelQueryAdapterImpl adapter, FunctionalQuery query, + RawPatternMatcher rawPatternMatcher) { + this.adapter = adapter; + this.query = query; + int arity = query.arity(); + int arityWithOutput = arity + 1; + emptyMask = TupleMask.empty(arityWithOutput); + omitOutputMask = TupleMask.omit(arity, arityWithOutput); + backend = rawPatternMatcher.getBackend(); + if (backend instanceof RetePatternMatcher reteBackend) { + var maybeIterableOmitOutputIndexer = IndexerUtils.getIndexer(reteBackend, omitOutputMask); + if (maybeIterableOmitOutputIndexer instanceof IterableIndexer iterableOmitOutputIndexer) { + omitOutputIndexer = iterableOmitOutputIndexer; + } else { + omitOutputIndexer = null; + } + } else { + omitOutputIndexer = null; + } + } + + @Override + public ModelQueryAdapter getAdapter() { + return adapter; + } + + @Override + public Query getQuery() { + return query; + } + + @Override + public T get(TupleLike parameters) { + var tuple = MatcherUtils.toViatraTuple(parameters); + if (omitOutputIndexer == null) { + return MatcherUtils.getSingleValue(backend.getAllMatches(omitOutputMask, tuple).iterator()); + } else { + return MatcherUtils.getSingleValue(omitOutputIndexer.get(tuple)); + } + } + + @Override + public Cursor getAll() { + if (omitOutputIndexer == null) { + var allMatches = backend.getAllMatches(emptyMask, Tuples.staticArityFlatTupleOf()); + return new UnsafeFunctionalCursor<>(allMatches.iterator()); + } + return new FunctionalCursor<>(omitOutputIndexer); + } + + @Override + public int size() { + if (omitOutputIndexer == null) { + return backend.countMatches(emptyMask, Tuples.staticArityFlatTupleOf()); + } + return omitOutputIndexer.getBucketCount(); + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/IndexerUtils.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/IndexerUtils.java new file mode 100644 index 00000000..55eb8c44 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/IndexerUtils.java @@ -0,0 +1,48 @@ +package tools.refinery.store.query.viatra.internal.matcher; + +import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; +import org.eclipse.viatra.query.runtime.rete.index.Indexer; +import org.eclipse.viatra.query.runtime.rete.matcher.ReteEngine; +import org.eclipse.viatra.query.runtime.rete.matcher.RetePatternMatcher; +import org.eclipse.viatra.query.runtime.rete.traceability.RecipeTraceInfo; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +final class IndexerUtils { + private static final MethodHandle GET_ENGINE_HANDLE; + private static final MethodHandle GET_PRODUCTION_NODE_TRACE_HANDLE; + private static final MethodHandle ACCESS_PROJECTION_HANDLE; + + static { + try { + var lookup = MethodHandles.privateLookupIn(RetePatternMatcher.class, MethodHandles.lookup()); + GET_ENGINE_HANDLE = lookup.findGetter(RetePatternMatcher.class, "engine", ReteEngine.class); + GET_PRODUCTION_NODE_TRACE_HANDLE = lookup.findGetter(RetePatternMatcher.class, "productionNodeTrace", + RecipeTraceInfo.class); + ACCESS_PROJECTION_HANDLE = lookup.findVirtual(ReteEngine.class, "accessProjection", + MethodType.methodType(Indexer.class, RecipeTraceInfo.class, TupleMask.class)); + } catch (IllegalAccessException | NoSuchFieldException | NoSuchMethodException e) { + throw new IllegalStateException("Cannot access private members of %s" + .formatted(RetePatternMatcher.class.getPackageName()), e); + } + } + + private IndexerUtils() { + throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); + } + + public static Indexer getIndexer(RetePatternMatcher backend, TupleMask mask) { + try { + var engine = (ReteEngine) GET_ENGINE_HANDLE.invokeExact(backend); + var trace = (RecipeTraceInfo) GET_PRODUCTION_NODE_TRACE_HANDLE.invokeExact(backend); + return (Indexer) ACCESS_PROJECTION_HANDLE.invokeExact(engine, trace, mask); + } catch (Error e) { + // Fatal JVM errors should not be wrapped. + throw e; + } catch (Throwable e) { + throw new IllegalStateException("Cannot access matcher for mask " + mask, e); + } + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java new file mode 100644 index 00000000..5d4be95d --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java @@ -0,0 +1,50 @@ +package tools.refinery.store.query.viatra.internal.matcher; + +import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; +import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; +import org.jetbrains.annotations.Nullable; +import tools.refinery.store.tuple.Tuple; +import tools.refinery.store.tuple.TupleLike; + +import java.util.Iterator; + +final class MatcherUtils { + private MatcherUtils() { + throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); + } + + public static org.eclipse.viatra.query.runtime.matchers.tuple.Tuple toViatraTuple(TupleLike tuple) { + if (tuple instanceof ViatraTupleLike viatraTupleLike) { + return viatraTupleLike.wrappedTuple().toImmutable(); + } + int size = tuple.getSize(); + var array = new Object[size]; + for (int i = 0; i < size; i++) { + var value = tuple.get(i); + array[i] = Tuple.of(value); + } + return Tuples.flatTupleOf(array); + } + + + public static T getSingleValue(@Nullable Iterable tuples) { + if (tuples == null) { + return null; + } + return getSingleValue(tuples.iterator()); + } + + public static T getSingleValue(Iterator iterator) { + if (!iterator.hasNext()) { + return null; + } + var match = iterator.next(); + @SuppressWarnings("unchecked") + var result = (T) match.get(match.getSize() - 1); + if (iterator.hasNext()) { + var input = new OmitOutputViatraTupleLike(match); + throw new IllegalStateException("Query is not functional for input tuple: " + input); + } + return result; + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/OmitOutputViatraTupleLike.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/OmitOutputViatraTupleLike.java new file mode 100644 index 00000000..bd9301ba --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/OmitOutputViatraTupleLike.java @@ -0,0 +1,23 @@ +package tools.refinery.store.query.viatra.internal.matcher; + +import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; +import tools.refinery.store.tuple.Tuple1; +import tools.refinery.store.tuple.TupleLike; + +record OmitOutputViatraTupleLike(ITuple wrappedTuple) implements TupleLike { + @Override + public int getSize() { + return wrappedTuple.getSize() - 1; + } + + @Override + public int get(int element) { + var wrappedValue = (Tuple1) wrappedTuple.get(element); + return wrappedValue.value0(); + } + + @Override + public String toString() { + return TupleLike.toString(this); + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RawPatternMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RawPatternMatcher.java new file mode 100644 index 00000000..b3d05967 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RawPatternMatcher.java @@ -0,0 +1,15 @@ +package tools.refinery.store.query.viatra.internal.matcher; + +import org.eclipse.viatra.query.runtime.api.GenericPatternMatcher; +import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; +import org.eclipse.viatra.query.runtime.matchers.backend.IQueryResultProvider; + +public class RawPatternMatcher extends GenericPatternMatcher { + public RawPatternMatcher(GenericQuerySpecification specification) { + super(specification); + } + + IQueryResultProvider getBackend() { + return backend; + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java new file mode 100644 index 00000000..c2dcc565 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java @@ -0,0 +1,42 @@ +package tools.refinery.store.query.viatra.internal.matcher; + +import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; +import tools.refinery.store.map.Cursor; +import tools.refinery.store.tuple.TupleLike; + +import java.util.Iterator; + +class RelationalCursor implements Cursor { + private final Iterator tuplesIterator; + private boolean terminated; + private TupleLike key; + + public RelationalCursor(Iterator tuplesIterator) { + this.tuplesIterator = tuplesIterator; + } + + @Override + public TupleLike getKey() { + return key; + } + + @Override + public Boolean getValue() { + return true; + } + + @Override + public boolean isTerminated() { + return terminated; + } + + @Override + public boolean move() { + if (!terminated && tuplesIterator.hasNext()) { + key = new ViatraTupleLike(tuplesIterator.next()); + return true; + } + terminated = true; + return false; + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java new file mode 100644 index 00000000..b9bc3f1e --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java @@ -0,0 +1,89 @@ +package tools.refinery.store.query.viatra.internal.matcher; + +import org.eclipse.viatra.query.runtime.matchers.backend.IQueryResultProvider; +import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; +import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; +import org.eclipse.viatra.query.runtime.rete.index.Indexer; +import org.eclipse.viatra.query.runtime.rete.matcher.RetePatternMatcher; +import tools.refinery.store.map.Cursor; +import tools.refinery.store.map.Cursors; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.ResultSet; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.query.dnf.RelationalQuery; +import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; +import tools.refinery.store.tuple.TupleLike; + +/** + * Directly access the tuples inside a VIATRA pattern matcher.

+ * This class neglects calling + * {@link org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext#wrapTuple(org.eclipse.viatra.query.runtime.matchers.tuple.Tuple)} + * and + * {@link org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext#unwrapTuple(org.eclipse.viatra.query.runtime.matchers.tuple.Tuple)}, + * because {@link tools.refinery.store.query.viatra.internal.context.RelationalRuntimeContext} provides a trivial + * implementation for these methods. + * Using this class with any other runtime context may lead to undefined behavior. + */ +public class RelationalViatraMatcher implements ResultSet { + private final ViatraModelQueryAdapterImpl adapter; + private final RelationalQuery query; + private final TupleMask emptyMask; + private final TupleMask identityMask; + private final IQueryResultProvider backend; + private final Indexer emptyMaskIndexer; + + public RelationalViatraMatcher(ViatraModelQueryAdapterImpl adapter, RelationalQuery query, + RawPatternMatcher rawPatternMatcher) { + this.adapter = adapter; + this.query = query; + int arity = query.arity(); + emptyMask = TupleMask.empty(arity); + identityMask = TupleMask.identity(arity); + backend = rawPatternMatcher.getBackend(); + if (backend instanceof RetePatternMatcher reteBackend) { + emptyMaskIndexer = IndexerUtils.getIndexer(reteBackend, emptyMask); + } else { + emptyMaskIndexer = null; + } + } + + @Override + public ModelQueryAdapter getAdapter() { + return adapter; + } + + @Override + public Query getQuery() { + return query; + } + + @Override + public Boolean get(TupleLike parameters) { + var tuple = MatcherUtils.toViatraTuple(parameters); + if (emptyMaskIndexer == null) { + return backend.hasMatch(identityMask, tuple); + } + var matches = emptyMaskIndexer.get(Tuples.staticArityFlatTupleOf()); + return matches != null && matches.contains(tuple); + } + + @Override + public Cursor getAll() { + if (emptyMaskIndexer == null) { + var allMatches = backend.getAllMatches(emptyMask, Tuples.staticArityFlatTupleOf()); + return new RelationalCursor(allMatches.iterator()); + } + var matches = emptyMaskIndexer.get(Tuples.staticArityFlatTupleOf()); + return matches == null ? Cursors.empty() : new RelationalCursor(matches.stream().iterator()); + } + + @Override + public int size() { + if (emptyMaskIndexer == null) { + return backend.countMatches(emptyMask, Tuples.staticArityFlatTupleOf()); + } + var matches = emptyMaskIndexer.get(Tuples.staticArityFlatTupleOf()); + return matches == null ? 0 : matches.size(); + } + +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java new file mode 100644 index 00000000..6c53fff1 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java @@ -0,0 +1,52 @@ +package tools.refinery.store.query.viatra.internal.matcher; + +import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; +import tools.refinery.store.map.Cursor; +import tools.refinery.store.tuple.TupleLike; + +import java.util.Iterator; + +/** + * Cursor for a functional result set that iterates over a stream of raw matches and doesn't check whether the + * functional dependency of the output on the inputs is obeyed. + * @param The output type. + */ +class UnsafeFunctionalCursor implements Cursor { + private final Iterator tuplesIterator; + private boolean terminated; + private TupleLike key; + private T value; + + public UnsafeFunctionalCursor(Iterator tuplesIterator) { + this.tuplesIterator = tuplesIterator; + } + + @Override + public TupleLike getKey() { + return key; + } + + @Override + public T getValue() { + return value; + } + + @Override + public boolean isTerminated() { + return terminated; + } + + @Override + public boolean move() { + if (!terminated && tuplesIterator.hasNext()) { + var match = tuplesIterator.next(); + key = new OmitOutputViatraTupleLike(match); + @SuppressWarnings("unchecked") + var typedValue = (T) match.get(match.getSize() - 1); + value = typedValue; + return true; + } + terminated = true; + return false; + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/ViatraTupleLike.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/ViatraTupleLike.java new file mode 100644 index 00000000..76a3e40b --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/ViatraTupleLike.java @@ -0,0 +1,23 @@ +package tools.refinery.store.query.viatra.internal.matcher; + +import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; +import tools.refinery.store.tuple.Tuple1; +import tools.refinery.store.tuple.TupleLike; + +record ViatraTupleLike(ITuple wrappedTuple) implements TupleLike { + @Override + public int getSize() { + return wrappedTuple.getSize(); + } + + @Override + public int get(int element) { + var wrappedValue = (Tuple1) wrappedTuple.get(element); + return wrappedValue.value0(); + } + + @Override + public String toString() { + return TupleLike.toString(this); + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/AssumptionEvaluator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/AssumptionEvaluator.java new file mode 100644 index 00000000..a80b0f90 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/AssumptionEvaluator.java @@ -0,0 +1,16 @@ +package tools.refinery.store.query.viatra.internal.pquery; + +import org.eclipse.viatra.query.runtime.matchers.psystem.IValueProvider; +import tools.refinery.store.query.term.Term; + +class AssumptionEvaluator extends TermEvaluator { + public AssumptionEvaluator(Term term) { + super(term); + } + + @Override + public Object evaluateExpression(IValueProvider provider) { + var result = super.evaluateExpression(provider); + return result == null ? Boolean.FALSE : result; + } +} 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 index 201e0ed0..7afeb977 100644 --- 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 @@ -1,45 +1,44 @@ package tools.refinery.store.query.viatra.internal.pquery; +import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory; 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.aggregations.BoundAggregator; +import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator; 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.basicdeferred.*; 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.psystem.queries.PQuery; 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.dnf.Dnf; +import tools.refinery.store.query.dnf.DnfClause; import tools.refinery.store.query.literal.*; +import tools.refinery.store.query.term.ConstantTerm; +import tools.refinery.store.query.term.StatefulAggregator; +import tools.refinery.store.query.term.StatelessAggregator; +import tools.refinery.store.query.term.Variable; import tools.refinery.store.query.view.AnyRelationView; import tools.refinery.store.util.CycleDetectingMapper; 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 CycleDetectingMapper mapper = new CycleDetectingMapper<>(Dnf::name, this::doTranslate); - - private final Map view2WrapperMap = new LinkedHashMap<>(); - - private final Map view2EmbeddedMap = new HashMap<>(); - + private final QueryWrapperFactory wrapperFactory = new QueryWrapperFactory(this); + private final Map hintOverrides = new LinkedHashMap<>(); private Function computeHint = dnf -> new QueryEvaluationHint(null, - QueryEvaluationHint.BackendRequirement.UNSPECIFIED); + (IQueryBackendFactory) null); public void setComputeHint(Function computeHint) { this.computeHint = computeHint; @@ -50,16 +49,33 @@ public class Dnf2PQuery { } public Map getRelationViews() { - return Collections.unmodifiableMap(view2WrapperMap); + return wrapperFactory.getRelationViews(); } - public RawPQuery getAlreadyTranslated(Dnf dnfQuery) { - return mapper.getAlreadyMapped(dnfQuery); + public void hint(Dnf dnf, QueryEvaluationHint hint) { + hintOverrides.compute(dnf, (ignoredKey, existingHint) -> + existingHint == null ? hint : existingHint.overrideBy(hint)); + } + + private QueryEvaluationHint consumeHint(Dnf dnf) { + var defaultHint = computeHint.apply(dnf); + var existingHint = hintOverrides.remove(dnf); + return defaultHint.overrideBy(existingHint); + } + + public void assertNoUnusedHints() { + if (hintOverrides.isEmpty()) { + return; + } + var unusedHints = hintOverrides.keySet().stream().map(Dnf::name).collect(Collectors.joining(", ")); + throw new IllegalStateException( + "Unused query evaluation hints for %s. Hints must be set before a query is added to the engine" + .formatted(unusedHints)); } private RawPQuery doTranslate(Dnf dnfQuery) { var pQuery = new RawPQuery(dnfQuery.getUniqueName()); - pQuery.setEvaluationHints(computeHint.apply(dnfQuery)); + pQuery.setEvaluationHints(consumeHint(dnfQuery)); Map parameters = new HashMap<>(); for (Variable variable : dnfQuery.getParameters()) { @@ -97,7 +113,7 @@ public class Dnf2PQuery { body.setSymbolicParameters(symbolicParameters); pQuery.addBody(body); for (Literal literal : clause.literals()) { - translateLiteral(literal, body); + translateLiteral(literal, clause, body); } } } @@ -105,15 +121,21 @@ public class Dnf2PQuery { return pQuery; } - private void translateLiteral(Literal literal, PBody body) { + private void translateLiteral(Literal literal, DnfClause clause, 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 CallLiteral callLiteral) { + translateCallLiteral(callLiteral, clause, body); } else if (literal instanceof ConstantLiteral constantLiteral) { translateConstantLiteral(constantLiteral, body); + } else if (literal instanceof AssignLiteral assignLiteral) { + translateAssignLiteral(assignLiteral, body); + } else if (literal instanceof AssumeLiteral assumeLiteral) { + translateAssumeLiteral(assumeLiteral, body); + } else if (literal instanceof CountLiteral countLiteral) { + translateCountLiteral(countLiteral, clause, body); + } else if (literal instanceof AggregationLiteral aggregationLiteral) { + translateAggregationLiteral(aggregationLiteral, clause, body); } else { throw new IllegalArgumentException("Unknown literal: " + literal.toString()); } @@ -129,20 +151,43 @@ public class Dnf2PQuery { } } - private void translateRelationViewLiteral(RelationViewLiteral relationViewLiteral, PBody body) { - var substitution = translateSubstitution(relationViewLiteral.getArguments(), 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 void translateCallLiteral(CallLiteral callLiteral, DnfClause clause, PBody body) { + var polarity = callLiteral.getPolarity(); + switch (polarity) { + case POSITIVE -> { + var substitution = translateSubstitution(callLiteral.getArguments(), body); + var constraint = callLiteral.getTarget(); + if (constraint instanceof Dnf dnf) { + var pattern = translate(dnf); + new PositivePatternCall(body, substitution, pattern); + } else if (constraint instanceof AnyRelationView relationView) { + var inputKey = wrapperFactory.getInputKey(relationView); + new TypeConstraint(body, substitution, inputKey); + } else { + throw new IllegalArgumentException("Unknown Constraint: " + constraint); } } + case TRANSITIVE -> { + var substitution = translateSubstitution(callLiteral.getArguments(), body); + var constraint = callLiteral.getTarget(); + PQuery pattern; + if (constraint instanceof Dnf dnf) { + pattern = translate(dnf); + } else if (constraint instanceof AnyRelationView relationView) { + pattern = wrapperFactory.wrapRelationViewIdentityArguments(relationView); + } else { + throw new IllegalArgumentException("Unknown Constraint: " + constraint); + } + new BinaryTransitiveClosure(body, substitution, pattern); + } + case NEGATIVE -> { + var wrappedCall = wrapperFactory.maybeWrapConstraint(callLiteral, clause); + var substitution = translateSubstitution(wrappedCall.remappedArguments(), body); + var pattern = wrappedCall.pattern(); + new NegativePatternCall(body, substitution, pattern); + } + default -> throw new IllegalArgumentException("Unknown polarity: " + polarity); + } } private static Tuple translateSubstitution(List substitution, PBody body) { @@ -155,51 +200,57 @@ public class Dnf2PQuery { return Tuples.flatTupleOf(variables); } - private RawPQuery translateEmbeddedRelationViewPQuery(AnyRelationView relationView) { - return view2EmbeddedMap.computeIfAbsent(relationView, this::doTranslateEmbeddedRelationViewPQuery); + private void translateConstantLiteral(ConstantLiteral constantLiteral, PBody body) { + var variable = body.getOrCreateVariableByName(constantLiteral.variable().getUniqueName()); + new ConstantValue(body, variable, constantLiteral.nodeId()); } - 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)); + private void translateAssignLiteral(AssignLiteral assignLiteral, PBody body) { + var variable = body.getOrCreateVariableByName(assignLiteral.variable().getUniqueName()); + var term = assignLiteral.term(); + if (term instanceof ConstantTerm constantTerm) { + new ConstantValue(body, variable, constantTerm.getValue()); + } else { + var evaluator = new TermEvaluator<>(term); + new ExpressionEvaluation(body, evaluator, variable); } - 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 translateAssumeLiteral(AssumeLiteral assumeLiteral, PBody body) { + var evaluator = new AssumptionEvaluator(assumeLiteral.term()); + new ExpressionEvaluation(body, evaluator, null); } - private void translateDnfCallLiteral(DnfCallLiteral dnfCallLiteral, PBody body) { - var variablesTuple = translateSubstitution(dnfCallLiteral.getArguments(), 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 translateCountLiteral(CountLiteral countLiteral, DnfClause clause, PBody body) { + var wrappedCall = wrapperFactory.maybeWrapConstraint(countLiteral, clause); + var substitution = translateSubstitution(wrappedCall.remappedArguments(), body); + var resultVariable = body.getOrCreateVariableByName(countLiteral.getResultVariable().getUniqueName()); + new PatternMatchCounter(body, substitution, wrappedCall.pattern(), resultVariable); } - private void translateConstantLiteral(ConstantLiteral constantLiteral, PBody body) { - var variable = body.getOrCreateVariableByName(constantLiteral.variable().getUniqueName()); - new ConstantValue(body, variable, constantLiteral.nodeId()); + private void translateAggregationLiteral(AggregationLiteral aggregationLiteral, DnfClause clause, + PBody body) { + var aggregator = aggregationLiteral.getAggregator(); + IMultisetAggregationOperator aggregationOperator; + if (aggregator instanceof StatelessAggregator statelessAggregator) { + aggregationOperator = new StatelessMultisetAggregator<>(statelessAggregator); + } else if (aggregator instanceof StatefulAggregator statefulAggregator) { + aggregationOperator = new StatefulMultisetAggregator<>(statefulAggregator); + } else { + throw new IllegalArgumentException("Unknown aggregator: " + aggregator); + } + var wrappedCall = wrapperFactory.maybeWrapConstraint(aggregationLiteral, clause); + var substitution = translateSubstitution(wrappedCall.remappedArguments(), body); + var inputVariable = body.getOrCreateVariableByName(aggregationLiteral.getInputVariable().getUniqueName()); + var aggregatedColumn = substitution.invertIndex().get(inputVariable); + if (aggregatedColumn == null) { + throw new IllegalStateException("Input variable %s not found in substitution %s".formatted(inputVariable, + substitution)); + } + var boundAggregator = new BoundAggregator(aggregationOperator, aggregator.getInputType(), + aggregator.getResultType()); + var resultVariable = body.getOrCreateVariableByName(aggregationLiteral.getResultVariable().getUniqueName()); + new AggregatorConstraint(boundAggregator, body, substitution, wrappedCall.pattern(), resultVariable, + aggregatedColumn); } } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/IndexerUtils.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/IndexerUtils.java deleted file mode 100644 index 75588b81..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/IndexerUtils.java +++ /dev/null @@ -1,48 +0,0 @@ -package tools.refinery.store.query.viatra.internal.pquery; - -import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; -import org.eclipse.viatra.query.runtime.rete.index.Indexer; -import org.eclipse.viatra.query.runtime.rete.matcher.ReteEngine; -import org.eclipse.viatra.query.runtime.rete.matcher.RetePatternMatcher; -import org.eclipse.viatra.query.runtime.rete.traceability.RecipeTraceInfo; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -final class IndexerUtils { - private static final MethodHandle GET_ENGINE_HANDLE; - private static final MethodHandle GET_PRODUCTION_NODE_TRACE_HANDLE; - private static final MethodHandle ACCESS_PROJECTION_HANDLE; - - static { - try { - var lookup = MethodHandles.privateLookupIn(RetePatternMatcher.class, MethodHandles.lookup()); - GET_ENGINE_HANDLE = lookup.findGetter(RetePatternMatcher.class, "engine", ReteEngine.class); - GET_PRODUCTION_NODE_TRACE_HANDLE = lookup.findGetter(RetePatternMatcher.class, "productionNodeTrace", - RecipeTraceInfo.class); - ACCESS_PROJECTION_HANDLE = lookup.findVirtual(ReteEngine.class, "accessProjection", - MethodType.methodType(Indexer.class, RecipeTraceInfo.class, TupleMask.class)); - } catch (IllegalAccessException | NoSuchFieldException | NoSuchMethodException e) { - throw new IllegalStateException("Cannot access private members of %s" - .formatted(RetePatternMatcher.class.getPackageName()), e); - } - } - - private IndexerUtils() { - throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); - } - - public static Indexer getIndexer(RetePatternMatcher backend, TupleMask mask) { - try { - var engine = (ReteEngine) GET_ENGINE_HANDLE.invokeExact(backend); - var trace = (RecipeTraceInfo) GET_PRODUCTION_NODE_TRACE_HANDLE.invokeExact(backend); - return (Indexer) ACCESS_PROJECTION_HANDLE.invokeExact(engine, trace, mask); - } catch (Error e) { - // Fatal JVM errors should not be wrapped. - throw e; - } catch (Throwable e) { - throw new IllegalStateException("Cannot access matcher for mask " + mask, e); - } - } -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java new file mode 100644 index 00000000..24ae5196 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java @@ -0,0 +1,173 @@ +package tools.refinery.store.query.viatra.internal.pquery; + +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.basicdeferred.ExportedParameter; +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.PQuery; +import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PVisibility; +import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; +import tools.refinery.store.query.Constraint; +import tools.refinery.store.query.dnf.Dnf; +import tools.refinery.store.query.dnf.DnfClause; +import tools.refinery.store.query.dnf.DnfUtils; +import tools.refinery.store.query.literal.AbstractCallLiteral; +import tools.refinery.store.query.term.Variable; +import tools.refinery.store.query.view.AnyRelationView; +import tools.refinery.store.query.view.RelationView; +import tools.refinery.store.util.CycleDetectingMapper; + +import java.util.*; +import java.util.function.ToIntFunction; + +class QueryWrapperFactory { + private final Dnf2PQuery dnf2PQuery; + private final Map view2WrapperMap = new LinkedHashMap<>(); + private final CycleDetectingMapper wrapConstraint = new CycleDetectingMapper<>( + RemappedConstraint::toString, this::doWrapConstraint); + + QueryWrapperFactory(Dnf2PQuery dnf2PQuery) { + this.dnf2PQuery = dnf2PQuery; + } + + public PQuery wrapRelationViewIdentityArguments(AnyRelationView relationView) { + var identity = new int[relationView.arity()]; + for (int i = 0; i < identity.length; i++) { + identity[i] = i; + } + return maybeWrapConstraint(relationView, identity); + } + public WrappedCall maybeWrapConstraint(AbstractCallLiteral callLiteral, DnfClause clause) { + var arguments = callLiteral.getArguments(); + int arity = arguments.size(); + var remappedParameters = new int[arity]; + var boundVariables = clause.boundVariables(); + var unboundVariableIndices = new HashMap(); + var appendVariable = new VariableAppender(); + for (int i = 0; i < arity; i++) { + var variable = arguments.get(i); + if (boundVariables.contains(variable)) { + // Do not join bound variable to make sure that the embedded pattern stays as general as possible. + remappedParameters[i] = appendVariable.applyAsInt(variable); + } else { + remappedParameters[i] = unboundVariableIndices.computeIfAbsent(variable, appendVariable::applyAsInt); + } + } + var pattern = maybeWrapConstraint(callLiteral.getTarget(), remappedParameters); + return new WrappedCall(pattern, appendVariable.getRemappedArguments()); + } + + private PQuery maybeWrapConstraint(Constraint constraint, int[] remappedParameters) { + if (remappedParameters.length != constraint.arity()) { + throw new IllegalArgumentException("Constraint %s expected %d parameters, but got %d parameters".formatted( + constraint, constraint.arity(), remappedParameters.length)); + } + if (constraint instanceof Dnf dnf && isIdentity(remappedParameters)) { + return dnf2PQuery.translate(dnf); + } + return wrapConstraint.map(new RemappedConstraint(constraint, remappedParameters)); + } + + private static boolean isIdentity(int[] remappedParameters) { + for (int i = 0; i < remappedParameters.length; i++) { + if (remappedParameters[i] != i) { + return false; + } + } + return true; + } + + private RawPQuery doWrapConstraint(RemappedConstraint remappedConstraint) { + var constraint = remappedConstraint.constraint(); + var remappedParameters = remappedConstraint.remappedParameters(); + + var embeddedPQuery = new RawPQuery(DnfUtils.generateUniqueName(constraint.name()), PVisibility.EMBEDDED); + var body = new PBody(embeddedPQuery); + int arity = Arrays.stream(remappedParameters).max().orElse(-1) + 1; + var parameters = new ArrayList(arity); + var parameterVariables = new PVariable[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); + parameterVariables[i] = variable; + symbolicParameters.add(new ExportedParameter(body, variable, parameter)); + } + embeddedPQuery.setParameters(parameters); + body.setSymbolicParameters(symbolicParameters); + + var arguments = new Object[remappedParameters.length]; + for (int i = 0; i < remappedParameters.length; i++) { + arguments[i] = parameterVariables[remappedParameters[i]]; + } + var argumentTuple = Tuples.flatTupleOf(arguments); + + if (constraint instanceof RelationView relationView) { + new TypeConstraint(body, argumentTuple, getInputKey(relationView)); + } else if (constraint instanceof Dnf dnf) { + var calledPQuery = dnf2PQuery.translate(dnf); + new PositivePatternCall(body, argumentTuple, calledPQuery); + } else { + throw new IllegalArgumentException("Unknown Constraint: " + constraint); + } + + embeddedPQuery.addBody(body); + return embeddedPQuery; + } + + public IInputKey getInputKey(AnyRelationView relationView) { + return view2WrapperMap.computeIfAbsent(relationView, RelationViewWrapper::new); + } + + public Map getRelationViews() { + return Collections.unmodifiableMap(view2WrapperMap); + } + + public record WrappedCall(PQuery pattern, List remappedArguments) { + } + + private static class VariableAppender implements ToIntFunction { + private final List remappedArguments = new ArrayList<>(); + private int nextIndex = 0; + + @Override + public int applyAsInt(Variable variable) { + remappedArguments.add(variable); + int index = nextIndex; + nextIndex++; + return index; + } + + public List getRemappedArguments() { + return remappedArguments; + } + } + + private record RemappedConstraint(Constraint constraint, int[] remappedParameters) { + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + RemappedConstraint that = (RemappedConstraint) o; + return constraint.equals(that.constraint) && Arrays.equals(remappedParameters, that.remappedParameters); + } + + @Override + public int hashCode() { + int result = Objects.hash(constraint); + result = 31 * result + Arrays.hashCode(remappedParameters); + return result; + } + + @Override + public String toString() { + return "RemappedConstraint{constraint=%s, remappedParameters=%s}".formatted(constraint, + Arrays.toString(remappedParameters)); + } + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java index 71b74396..aad4ba3c 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java @@ -9,6 +9,7 @@ import org.eclipse.viatra.query.runtime.matchers.psystem.queries.BasePQuery; import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PVisibility; import tools.refinery.store.query.viatra.internal.RelationalScope; +import tools.refinery.store.query.viatra.internal.matcher.RawPatternMatcher; import java.util.LinkedHashSet; import java.util.List; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPatternMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPatternMatcher.java deleted file mode 100644 index 5924ff15..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPatternMatcher.java +++ /dev/null @@ -1,93 +0,0 @@ -package tools.refinery.store.query.viatra.internal.pquery; - -import org.eclipse.viatra.query.runtime.api.GenericPatternMatcher; -import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; -import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; -import org.eclipse.viatra.query.runtime.matchers.backend.IMatcherCapability; -import org.eclipse.viatra.query.runtime.matchers.backend.IQueryResultProvider; -import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; -import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; -import org.eclipse.viatra.query.runtime.rete.index.Indexer; -import org.eclipse.viatra.query.runtime.rete.matcher.RetePatternMatcher; -import tools.refinery.store.map.Cursor; -import tools.refinery.store.map.Cursors; -import tools.refinery.store.query.ResultSet; -import tools.refinery.store.query.viatra.ViatraTupleLike; -import tools.refinery.store.tuple.Tuple; -import tools.refinery.store.tuple.TupleLike; - -/** - * Directly access the tuples inside a VIATRA pattern matcher.

- * This class neglects calling - * {@link org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext#wrapTuple(org.eclipse.viatra.query.runtime.matchers.tuple.Tuple)} - * and - * {@link org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext#unwrapTuple(org.eclipse.viatra.query.runtime.matchers.tuple.Tuple)}, - * because {@link tools.refinery.store.query.viatra.internal.context.RelationalRuntimeContext} provides a trivial - * implementation for these methods. - * Using this class with any other runtime context may lead to undefined behavior. - */ -public class RawPatternMatcher extends GenericPatternMatcher implements ResultSet { - private final Object[] empty; - private final TupleMask identityMask; - private Indexer emptyMaskIndexer; - - public RawPatternMatcher(GenericQuerySpecification specification) { - super(specification); - var arity = specification.getParameterNames().size(); - empty = new Object[arity]; - identityMask = TupleMask.identity(arity); - } - - @Override - protected void setBackend(ViatraQueryEngine engine, IQueryResultProvider resultProvider, - IMatcherCapability capabilities) { - super.setBackend(engine, resultProvider, capabilities); - if (resultProvider instanceof RetePatternMatcher reteBackend) { - emptyMaskIndexer = IndexerUtils.getIndexer(reteBackend, TupleMask.empty(identityMask.sourceWidth)); - } - } - - @Override - public boolean hasResult(TupleLike parameters) { - org.eclipse.viatra.query.runtime.matchers.tuple.Tuple tuple; - if (parameters instanceof ViatraTupleLike viatraTupleLike) { - tuple = viatraTupleLike.wrappedTuple().toImmutable(); - } else { - var parametersArray = toParametersArray(parameters); - tuple = Tuples.flatTupleOf(parametersArray); - } - if (emptyMaskIndexer == null) { - return backend.hasMatch(identityMask, tuple); - } - var matches = emptyMaskIndexer.get(Tuples.staticArityFlatTupleOf()); - return matches != null && matches.contains(tuple); - } - - @Override - public Cursor allResults() { - if (emptyMaskIndexer == null) { - return new ResultSetCursor(backend.getAllMatches(empty).iterator()); - } - var matches = emptyMaskIndexer.get(Tuples.staticArityFlatTupleOf()); - return matches == null ? Cursors.empty() : new ResultSetCursor(matches.stream().iterator()); - } - - @Override - public int countResults() { - if (emptyMaskIndexer == null) { - return backend.countMatches(empty); - } - var matches = emptyMaskIndexer.get(Tuples.staticArityFlatTupleOf()); - return matches == null ? 0 : matches.size(); - } - - private Object[] toParametersArray(TupleLike tuple) { - int size = tuple.getSize(); - var array = new Object[size]; - for (int i = 0; i < size; i++) { - var value = tuple.get(i); - array[i] = Tuple.of(value); - } - return array; - } -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java index c442add8..48bf558d 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java @@ -27,4 +27,9 @@ public class RelationViewWrapper extends BaseInputKeyWrapper { public boolean isEnumerable() { return true; } + + @Override + public String toString() { + return "RelationViewWrapper{wrappedKey=%s}".formatted(wrappedKey); + } } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ResultSetCursor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ResultSetCursor.java deleted file mode 100644 index 5e6d1970..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ResultSetCursor.java +++ /dev/null @@ -1,43 +0,0 @@ -package tools.refinery.store.query.viatra.internal.pquery; - -import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; -import tools.refinery.store.map.Cursor; -import tools.refinery.store.query.viatra.ViatraTupleLike; -import tools.refinery.store.tuple.TupleLike; - -import java.util.Iterator; - -class ResultSetCursor implements Cursor { - private final Iterator tuplesIterator; - private boolean terminated; - private TupleLike key; - - public ResultSetCursor(Iterator tuplesIterator) { - this.tuplesIterator = tuplesIterator; - } - - @Override - public TupleLike getKey() { - return key; - } - - @Override - public Boolean getValue() { - return true; - } - - @Override - public boolean isTerminated() { - return terminated; - } - - @Override - public boolean move() { - if (!terminated && tuplesIterator.hasNext()) { - key = new ViatraTupleLike(tuplesIterator.next()); - return true; - } - terminated = true; - return false; - } -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatefulMultisetAggregator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatefulMultisetAggregator.java new file mode 100644 index 00000000..2798a252 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatefulMultisetAggregator.java @@ -0,0 +1,60 @@ +package tools.refinery.store.query.viatra.internal.pquery; + +import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator; +import tools.refinery.store.query.term.StatefulAggregate; +import tools.refinery.store.query.term.StatefulAggregator; + +import java.util.stream.Stream; + +record StatefulMultisetAggregator(StatefulAggregator aggregator) + implements IMultisetAggregationOperator, R> { + @Override + public String getShortDescription() { + return getName(); + } + + @Override + public String getName() { + return aggregator.toString(); + } + + @Override + public StatefulAggregate createNeutral() { + return aggregator.createEmptyAggregate(); + } + + @Override + public boolean isNeutral(StatefulAggregate result) { + return result.isEmpty(); + } + + @Override + public StatefulAggregate update(StatefulAggregate oldResult, T updateValue, boolean isInsertion) { + if (isInsertion) { + oldResult.add(updateValue); + } else { + oldResult.remove(updateValue); + } + return oldResult; + } + + @Override + public R getAggregate(StatefulAggregate result) { + return result.getResult(); + } + + @Override + public R aggregateStream(Stream stream) { + return aggregator.aggregateStream(stream); + } + + @Override + public StatefulAggregate clone(StatefulAggregate original) { + return original.deepCopy(); + } + + @Override + public boolean contains(T value, StatefulAggregate accumulator) { + return accumulator.contains(value); + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatelessMultisetAggregator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatelessMultisetAggregator.java new file mode 100644 index 00000000..7cc71ee9 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatelessMultisetAggregator.java @@ -0,0 +1,50 @@ +package tools.refinery.store.query.viatra.internal.pquery; + +import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator; +import tools.refinery.store.query.term.StatelessAggregator; + +import java.util.stream.Stream; + +record StatelessMultisetAggregator(StatelessAggregator aggregator) + implements IMultisetAggregationOperator { + @Override + public String getShortDescription() { + return getName(); + } + + @Override + public String getName() { + return aggregator.toString(); + } + + @Override + public R createNeutral() { + return aggregator.getEmptyResult(); + } + + @Override + public boolean isNeutral(R result) { + return createNeutral().equals(result); + } + + @Override + public R update(R oldResult, T updateValue, boolean isInsertion) { + return isInsertion ? aggregator.add(oldResult, updateValue) : aggregator.remove(oldResult, updateValue); + } + + @Override + public R getAggregate(R result) { + return result; + } + + @Override + public R clone(R original) { + // Aggregate result is immutable. + return original; + } + + @Override + public R aggregateStream(Stream stream) { + return aggregator.aggregateStream(stream); + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/TermEvaluator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/TermEvaluator.java new file mode 100644 index 00000000..ab123c50 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/TermEvaluator.java @@ -0,0 +1,32 @@ +package tools.refinery.store.query.viatra.internal.pquery; + +import org.eclipse.viatra.query.runtime.matchers.psystem.IExpressionEvaluator; +import org.eclipse.viatra.query.runtime.matchers.psystem.IValueProvider; +import tools.refinery.store.query.term.Term; +import tools.refinery.store.query.term.Variable; + +import java.util.stream.Collectors; + +class TermEvaluator implements IExpressionEvaluator { + private final Term term; + + public TermEvaluator(Term term) { + this.term = term; + } + + @Override + public String getShortDescription() { + return term.toString(); + } + + @Override + public Iterable getInputParameterNames() { + return term.getInputVariables().stream().map(Variable::getUniqueName).collect(Collectors.toUnmodifiableSet()); + } + + @Override + public Object evaluateExpression(IValueProvider provider) { + var valuation = new ValueProviderBasedValuation(provider); + return term.evaluate(valuation); + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ValueProviderBasedValuation.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ValueProviderBasedValuation.java new file mode 100644 index 00000000..30c2fce7 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ValueProviderBasedValuation.java @@ -0,0 +1,14 @@ +package tools.refinery.store.query.viatra.internal.pquery; + +import org.eclipse.viatra.query.runtime.matchers.psystem.IValueProvider; +import tools.refinery.store.query.term.DataVariable; +import tools.refinery.store.query.valuation.Valuation; + +public record ValueProviderBasedValuation(IValueProvider valueProvider) implements Valuation { + @Override + public T getValue(DataVariable variable) { + @SuppressWarnings("unchecked") + var value = (T) valueProvider.getValue(variable.getUniqueName()); + return value; + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java index 8a467066..fc935aa6 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java @@ -22,10 +22,9 @@ public class ModelUpdateListener { } private void registerView(ViatraModelQueryAdapterImpl adapter, RelationView relationView) { - var listener = RelationViewUpdateListener.of(adapter, relationView); var model = adapter.getModel(); var interpretation = model.getInterpretation(relationView.getSymbol()); - interpretation.addListener(listener, true); + var listener = RelationViewUpdateListener.of(adapter, relationView, interpretation); relationViewUpdateListeners.put(relationView, listener); } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java index bf6b4197..5e5f60e3 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java @@ -4,6 +4,7 @@ import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; +import tools.refinery.store.model.Interpretation; import tools.refinery.store.model.InterpretationListener; import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; import tools.refinery.store.query.view.RelationView; @@ -14,18 +15,27 @@ import java.util.List; public abstract class RelationViewUpdateListener implements InterpretationListener { private final ViatraModelQueryAdapterImpl adapter; + private final Interpretation interpretation; private final List filters = new ArrayList<>(); - protected RelationViewUpdateListener(ViatraModelQueryAdapterImpl adapter) { + protected RelationViewUpdateListener(ViatraModelQueryAdapterImpl adapter, Interpretation interpretation) { this.adapter = adapter; + this.interpretation = interpretation; } public void addFilter(IInputKey inputKey, ITuple seed, IQueryRuntimeContextListener listener) { + if (filters.isEmpty()) { + // First filter to be added, from now on we have to subscribe to model updates. + interpretation.addListener(this, true); + } filters.add(new RelationViewFilter(inputKey, seed, listener)); } public void removeFilter(IInputKey inputKey, ITuple seed, IQueryRuntimeContextListener listener) { - filters.remove(new RelationViewFilter(inputKey, seed, listener)); + if (filters.remove(new RelationViewFilter(inputKey, seed, listener)) && filters.isEmpty()) { + // Last listener to be added, we don't have be subscribed to model updates anymore. + interpretation.removeListener(this); + } } protected void processUpdate(Tuple tuple, boolean isInsertion) { @@ -39,10 +49,12 @@ public abstract class RelationViewUpdateListener implements InterpretationLis } public static RelationViewUpdateListener of(ViatraModelQueryAdapterImpl adapter, - RelationView relationView) { + RelationView relationView, + Interpretation interpretation) { if (relationView instanceof TuplePreservingRelationView tuplePreservingRelationView) { - return new TuplePreservingRelationViewUpdateListener<>(adapter, tuplePreservingRelationView); + return new TuplePreservingRelationViewUpdateListener<>(adapter, tuplePreservingRelationView, + interpretation); } - return new TupleChangingRelationViewUpdateListener<>(adapter, relationView); + return new TupleChangingRelationViewUpdateListener<>(adapter, relationView, interpretation); } } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java index 14142884..0f6ed3b3 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java @@ -1,6 +1,7 @@ package tools.refinery.store.query.viatra.internal.update; import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; +import tools.refinery.store.model.Interpretation; import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; import tools.refinery.store.query.view.RelationView; import tools.refinery.store.tuple.Tuple; @@ -10,8 +11,9 @@ import java.util.Arrays; public class TupleChangingRelationViewUpdateListener extends RelationViewUpdateListener { private final RelationView relationView; - TupleChangingRelationViewUpdateListener(ViatraModelQueryAdapterImpl adapter, RelationView relationView) { - super(adapter); + TupleChangingRelationViewUpdateListener(ViatraModelQueryAdapterImpl adapter, RelationView relationView, + Interpretation interpretation) { + super(adapter, interpretation); this.relationView = relationView; } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java index 288e018a..91e9371b 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java @@ -1,6 +1,7 @@ package tools.refinery.store.query.viatra.internal.update; import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; +import tools.refinery.store.model.Interpretation; import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; import tools.refinery.store.query.view.TuplePreservingRelationView; import tools.refinery.store.tuple.Tuple; @@ -9,8 +10,8 @@ public class TuplePreservingRelationViewUpdateListener extends RelationViewUp private final TuplePreservingRelationView view; TuplePreservingRelationViewUpdateListener(ViatraModelQueryAdapterImpl adapter, - TuplePreservingRelationView view) { - super(adapter); + TuplePreservingRelationView view, Interpretation interpretation) { + super(adapter, interpretation); this.view = view; } diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java new file mode 100644 index 00000000..90229b73 --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java @@ -0,0 +1,471 @@ +package tools.refinery.store.query.viatra; + +import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; +import tools.refinery.store.model.ModelStore; +import tools.refinery.store.query.ModelQuery; +import tools.refinery.store.query.dnf.Dnf; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.query.term.Variable; +import tools.refinery.store.query.viatra.tests.QueryEngineTest; +import tools.refinery.store.query.view.FunctionalRelationView; +import tools.refinery.store.query.view.KeyOnlyRelationView; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.tuple.Tuple; + +import java.util.Map; +import java.util.Optional; + +import static tools.refinery.store.query.literal.Literals.not; +import static tools.refinery.store.query.term.int_.IntTerms.INT_SUM; +import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertNullableResults; +import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults; + +class DiagonalQueryTest { + @QueryEngineTest + void inputKeyNegationTest(QueryEvaluationHint hint) { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var symbol = new Symbol<>("symbol", 4, Boolean.class, false); + var personView = new KeyOnlyRelationView<>(person); + var symbolView = new KeyOnlyRelationView<>(symbol); + + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); + var query = Query.builder("Diagonal") + .parameter(p1) + .clause( + personView.call(p1), + not(symbolView.call(p1, p1, p2, p2)) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, symbol) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .queries(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var symbolInterpretation = model.getInterpretation(symbol); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + personInterpretation.put(Tuple.of(2), true); + + symbolInterpretation.put(Tuple.of(0, 0, 1, 1), true); + symbolInterpretation.put(Tuple.of(0, 0, 1, 2), true); + symbolInterpretation.put(Tuple.of(1, 1, 0, 1), true); + symbolInterpretation.put(Tuple.of(1, 2, 1, 1), true); + + queryEngine.flushChanges(); + assertResults(Map.of( + Tuple.of(0), false, + Tuple.of(1), true, + Tuple.of(2), true, + Tuple.of(3), false + ), queryResultSet); + } + + @QueryEngineTest + void subQueryNegationTest(QueryEvaluationHint hint) { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var symbol = new Symbol<>("symbol", 4, Boolean.class, false); + var personView = new KeyOnlyRelationView<>(person); + var symbolView = new KeyOnlyRelationView<>(symbol); + + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); + var p3 = Variable.of("p3"); + var p4 = Variable.of("p4"); + var subQuery = Dnf.builder("SubQuery") + .parameters(p1, p2, p3, p4) + .clause( + personView.call(p1), + symbolView.call(p1, p2, p3, p4) + ) + .clause( + personView.call(p2), + symbolView.call(p1, p2, p3, p4) + ) + .build(); + var query = Query.builder("Diagonal") + .parameter(p1) + .clause( + personView.call(p1), + not(subQuery.call(p1, p1, p2, p2)) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, symbol) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .queries(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var symbolInterpretation = model.getInterpretation(symbol); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + personInterpretation.put(Tuple.of(2), true); + + symbolInterpretation.put(Tuple.of(0, 0, 1, 1), true); + symbolInterpretation.put(Tuple.of(0, 0, 1, 2), true); + symbolInterpretation.put(Tuple.of(1, 1, 0, 1), true); + symbolInterpretation.put(Tuple.of(1, 2, 1, 1), true); + + queryEngine.flushChanges(); + assertResults(Map.of( + Tuple.of(0), false, + Tuple.of(1), true, + Tuple.of(2), true, + Tuple.of(3), false + ), queryResultSet); + } + + @QueryEngineTest + void inputKeyCountTest(QueryEvaluationHint hint) { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var symbol = new Symbol<>("symbol", 4, Boolean.class, false); + var personView = new KeyOnlyRelationView<>(person); + var symbolView = new KeyOnlyRelationView<>(symbol); + + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); + var x = Variable.of("x", Integer.class); + var query = Query.builder("Diagonal") + .parameter(p1) + .output(x) + .clause( + personView.call(p1), + x.assign(symbolView.count(p1, p1, p2, p2)) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, symbol) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .queries(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var symbolInterpretation = model.getInterpretation(symbol); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + personInterpretation.put(Tuple.of(2), true); + + symbolInterpretation.put(Tuple.of(0, 0, 1, 1), true); + symbolInterpretation.put(Tuple.of(0, 0, 2, 2), true); + symbolInterpretation.put(Tuple.of(0, 0, 1, 2), true); + symbolInterpretation.put(Tuple.of(1, 1, 0, 1), true); + symbolInterpretation.put(Tuple.of(1, 2, 1, 1), true); + + queryEngine.flushChanges(); + assertNullableResults(Map.of( + Tuple.of(0), Optional.of(2), + Tuple.of(1), Optional.of(0), + Tuple.of(2), Optional.of(0), + Tuple.of(3), Optional.empty() + ), queryResultSet); + } + + @QueryEngineTest + void subQueryCountTest(QueryEvaluationHint hint) { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var symbol = new Symbol<>("symbol", 4, Boolean.class, false); + var personView = new KeyOnlyRelationView<>(person); + var symbolView = new KeyOnlyRelationView<>(symbol); + + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); + var p3 = Variable.of("p3"); + var p4 = Variable.of("p4"); + var x = Variable.of("x", Integer.class); + var subQuery = Dnf.builder("SubQuery") + .parameters(p1, p2, p3, p4) + .clause( + personView.call(p1), + symbolView.call(p1, p2, p3, p4) + ) + .clause( + personView.call(p2), + symbolView.call(p1, p2, p3, p4) + ) + .build(); + var query = Query.builder("Diagonal") + .parameter(p1) + .output(x) + .clause( + personView.call(p1), + x.assign(subQuery.count(p1, p1, p2, p2)) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, symbol) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .queries(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var symbolInterpretation = model.getInterpretation(symbol); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + personInterpretation.put(Tuple.of(2), true); + + symbolInterpretation.put(Tuple.of(0, 0, 1, 1), true); + symbolInterpretation.put(Tuple.of(0, 0, 2, 2), true); + symbolInterpretation.put(Tuple.of(0, 0, 1, 2), true); + symbolInterpretation.put(Tuple.of(1, 1, 0, 1), true); + symbolInterpretation.put(Tuple.of(1, 2, 1, 1), true); + + queryEngine.flushChanges(); + assertNullableResults(Map.of( + Tuple.of(0), Optional.of(2), + Tuple.of(1), Optional.of(0), + Tuple.of(2), Optional.of(0), + Tuple.of(3), Optional.empty() + ), queryResultSet); + } + + @QueryEngineTest + void inputKeyAggregationTest(QueryEvaluationHint hint) { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var symbol = new Symbol<>("symbol", 4, Integer.class, null); + var personView = new KeyOnlyRelationView<>(person); + var symbolView = new FunctionalRelationView<>(symbol); + + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); + var x = Variable.of("x", Integer.class); + var y = Variable.of("y", Integer.class); + var query = Query.builder("Diagonal") + .parameter(p1) + .output(x) + .clause( + personView.call(p1), + x.assign(symbolView.aggregate(y, INT_SUM, p1, p1, p2, p2, y)) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, symbol) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .queries(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var symbolInterpretation = model.getInterpretation(symbol); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + personInterpretation.put(Tuple.of(2), true); + + symbolInterpretation.put(Tuple.of(0, 0, 1, 1), 1); + symbolInterpretation.put(Tuple.of(0, 0, 2, 2), 2); + symbolInterpretation.put(Tuple.of(0, 0, 1, 2), 10); + symbolInterpretation.put(Tuple.of(1, 1, 0, 1), 11); + symbolInterpretation.put(Tuple.of(1, 2, 1, 1), 12); + + queryEngine.flushChanges(); + assertNullableResults(Map.of( + Tuple.of(0), Optional.of(3), + Tuple.of(1), Optional.of(0), + Tuple.of(2), Optional.of(0), + Tuple.of(3), Optional.empty() + ), queryResultSet); + } + + @QueryEngineTest + void subQueryAggregationTest(QueryEvaluationHint hint) { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var symbol = new Symbol<>("symbol", 4, Integer.class, null); + var personView = new KeyOnlyRelationView<>(person); + var symbolView = new FunctionalRelationView<>(symbol); + + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); + var p3 = Variable.of("p3"); + var p4 = Variable.of("p4"); + var x = Variable.of("x", Integer.class); + var y = Variable.of("y", Integer.class); + var z = Variable.of("z", Integer.class); + var subQuery = Dnf.builder("SubQuery") + .parameters(p1, p2, p3, p4, x, y) + .clause( + personView.call(p1), + symbolView.call(p1, p2, p3, p4, x), + y.assign(x) + ) + .clause( + personView.call(p2), + symbolView.call(p1, p2, p3, p4, x), + y.assign(x) + ) + .build(); + var query = Query.builder("Diagonal") + .parameter(p1) + .output(x) + .clause( + personView.call(p1), + x.assign(subQuery.aggregate(z, INT_SUM, p1, p1, p2, p2, z, z)) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, symbol) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .queries(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var symbolInterpretation = model.getInterpretation(symbol); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + personInterpretation.put(Tuple.of(2), true); + + symbolInterpretation.put(Tuple.of(0, 0, 1, 1), 1); + symbolInterpretation.put(Tuple.of(0, 0, 2, 2), 2); + symbolInterpretation.put(Tuple.of(0, 0, 1, 2), 10); + symbolInterpretation.put(Tuple.of(1, 1, 0, 1), 11); + symbolInterpretation.put(Tuple.of(1, 2, 1, 1), 12); + + queryEngine.flushChanges(); + assertNullableResults(Map.of( + Tuple.of(0), Optional.of(3), + Tuple.of(1), Optional.of(0), + Tuple.of(2), Optional.of(0), + Tuple.of(3), Optional.empty() + ), queryResultSet); + } + + @QueryEngineTest + void inputKeyTransitiveTest(QueryEvaluationHint hint) { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var symbol = new Symbol<>("symbol", 2, Boolean.class, false); + var personView = new KeyOnlyRelationView<>(person); + var symbolView = new KeyOnlyRelationView<>(symbol); + + var p1 = Variable.of("p1"); + var query = Query.builder("Diagonal") + .parameter(p1) + .clause( + personView.call(p1), + symbolView.callTransitive(p1, p1) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, symbol) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .queries(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var symbolInterpretation = model.getInterpretation(symbol); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + personInterpretation.put(Tuple.of(2), true); + + symbolInterpretation.put(Tuple.of(0, 0), true); + symbolInterpretation.put(Tuple.of(0, 1), true); + symbolInterpretation.put(Tuple.of(1, 2), true); + + queryEngine.flushChanges(); + assertResults(Map.of( + Tuple.of(0), true, + Tuple.of(1), false, + Tuple.of(2), false, + Tuple.of(3), false + ), queryResultSet); + } + + @QueryEngineTest + void subQueryTransitiveTest(QueryEvaluationHint hint) { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var symbol = new Symbol<>("symbol", 2, Boolean.class, false); + var personView = new KeyOnlyRelationView<>(person); + var symbolView = new KeyOnlyRelationView<>(symbol); + + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); + var subQuery = Dnf.builder("SubQuery") + .parameters(p1, p2) + .clause( + personView.call(p1), + symbolView.call(p1, p2) + ) + .clause( + personView.call(p2), + symbolView.call(p1, p2) + ) + .build(); + var query = Query.builder("Diagonal") + .parameter(p1) + .clause( + personView.call(p1), + subQuery.callTransitive(p1, p1) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, symbol) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .queries(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var symbolInterpretation = model.getInterpretation(symbol); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + personInterpretation.put(Tuple.of(2), true); + + symbolInterpretation.put(Tuple.of(0, 0), true); + symbolInterpretation.put(Tuple.of(0, 1), true); + symbolInterpretation.put(Tuple.of(1, 2), true); + + queryEngine.flushChanges(); + assertResults(Map.of( + Tuple.of(0), true, + Tuple.of(1), false, + Tuple.of(2), false, + Tuple.of(3), false + ), queryResultSet); + } +} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java new file mode 100644 index 00000000..fa2a008f --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java @@ -0,0 +1,607 @@ +package tools.refinery.store.query.viatra; + +import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; +import tools.refinery.store.map.Cursor; +import tools.refinery.store.model.ModelStore; +import tools.refinery.store.query.ModelQuery; +import tools.refinery.store.query.dnf.Dnf; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.query.term.Variable; +import tools.refinery.store.query.viatra.tests.QueryEngineTest; +import tools.refinery.store.query.view.FilteredRelationView; +import tools.refinery.store.query.view.FunctionalRelationView; +import tools.refinery.store.query.view.KeyOnlyRelationView; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.representation.TruthValue; +import tools.refinery.store.tuple.Tuple; + +import java.util.Map; +import java.util.Optional; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static tools.refinery.store.query.literal.Literals.assume; +import static tools.refinery.store.query.term.int_.IntTerms.*; +import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertNullableResults; +import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults; + +class FunctionalQueryTest { + @QueryEngineTest + void inputKeyTest(QueryEvaluationHint hint) { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var age = new Symbol<>("age", 1, Integer.class, null); + var personView = new KeyOnlyRelationView<>(person); + var ageView = new FunctionalRelationView<>(age); + + var p1 = Variable.of("p1"); + var x = Variable.of("x", Integer.class); + var query = Query.builder("InputKey") + .parameter(p1) + .output(x) + .clause( + personView.call(p1), + ageView.call(p1, x) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, age) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .queries(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var ageInterpretation = model.getInterpretation(age); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + + ageInterpretation.put(Tuple.of(0), 12); + ageInterpretation.put(Tuple.of(1), 24); + ageInterpretation.put(Tuple.of(2), 36); + + queryEngine.flushChanges(); + assertNullableResults(Map.of( + Tuple.of(0), Optional.of(12), + Tuple.of(1), Optional.of(24), + Tuple.of(2), Optional.empty() + ), queryResultSet); + } + + @QueryEngineTest + void predicateTest(QueryEvaluationHint hint) { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var age = new Symbol<>("age", 1, Integer.class, null); + var personView = new KeyOnlyRelationView<>(person); + var ageView = new FunctionalRelationView<>(age); + + var p1 = Variable.of("p1"); + var x = Variable.of("x", Integer.class); + var subQuery = Dnf.builder("SubQuery") + .parameters(p1, x) + .clause( + personView.call(p1), + ageView.call(p1, x) + ) + .build(); + var query = Query.builder("Predicate") + .parameter(p1) + .output(x) + .clause( + personView.call(p1), + subQuery.call(p1, x) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, age) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .queries(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var ageInterpretation = model.getInterpretation(age); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + + ageInterpretation.put(Tuple.of(0), 12); + ageInterpretation.put(Tuple.of(1), 24); + ageInterpretation.put(Tuple.of(2), 36); + + queryEngine.flushChanges(); + assertNullableResults(Map.of( + Tuple.of(0), Optional.of(12), + Tuple.of(1), Optional.of(24), + Tuple.of(2), Optional.empty() + ), queryResultSet); + } + + @QueryEngineTest + void computationTest(QueryEvaluationHint hint) { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var age = new Symbol<>("age", 1, Integer.class, null); + var personView = new KeyOnlyRelationView<>(person); + var ageView = new FunctionalRelationView<>(age); + + var p1 = Variable.of("p1"); + var x = Variable.of("x", Integer.class); + var y = Variable.of("y", Integer.class); + var query = Query.builder("Computation") + .parameter(p1) + .output(y) + .clause( + personView.call(p1), + ageView.call(p1, x), + y.assign(mul(x, constant(7))) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, age) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .queries(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var ageInterpretation = model.getInterpretation(age); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + + ageInterpretation.put(Tuple.of(0), 12); + ageInterpretation.put(Tuple.of(1), 24); + + queryEngine.flushChanges(); + assertNullableResults(Map.of( + Tuple.of(0), Optional.of(84), + Tuple.of(1), Optional.of(168), + Tuple.of(2), Optional.empty() + ), queryResultSet); + } + + @QueryEngineTest + void inputKeyCountTest(QueryEvaluationHint hint) { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); + var personView = new KeyOnlyRelationView<>(person); + var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); + + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); + var x = Variable.of("x", Integer.class); + var query = Query.builder("Count") + .parameter(p1) + .output(x) + .clause( + personView.call(p1), + x.assign(friendMustView.count(p1, p2)) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, friend) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .queries(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var friendInterpretation = model.getInterpretation(friend); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + personInterpretation.put(Tuple.of(2), true); + + friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); + friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); + friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); + + queryEngine.flushChanges(); + assertNullableResults(Map.of( + Tuple.of(0), Optional.of(1), + Tuple.of(1), Optional.of(2), + Tuple.of(2), Optional.of(0), + Tuple.of(3), Optional.empty() + ), queryResultSet); + } + + @QueryEngineTest + void predicateCountTest(QueryEvaluationHint hint) { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); + var personView = new KeyOnlyRelationView<>(person); + var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); + + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); + var x = Variable.of("x", Integer.class); + var subQuery = Dnf.builder("SubQuery") + .parameters(p1, p2) + .clause( + personView.call(p1), + personView.call(p2), + friendMustView.call(p1, p2) + ) + .build(); + var query = Query.builder("Count") + .parameter(p1) + .output(x) + .clause( + personView.call(p1), + x.assign(subQuery.count(p1, p2)) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, friend) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .queries(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var friendInterpretation = model.getInterpretation(friend); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + personInterpretation.put(Tuple.of(2), true); + + friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); + friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); + friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); + + queryEngine.flushChanges(); + assertNullableResults(Map.of( + Tuple.of(0), Optional.of(1), + Tuple.of(1), Optional.of(2), + Tuple.of(2), Optional.of(0), + Tuple.of(3), Optional.empty() + ), queryResultSet); + } + + @QueryEngineTest + void inputKeyAggregationTest(QueryEvaluationHint hint) { + var age = new Symbol<>("age", 1, Integer.class, null); + var ageView = new FunctionalRelationView<>(age); + + var p1 = Variable.of("p1"); + var x = Variable.of("x", Integer.class); + var y = Variable.of("y", Integer.class); + var query = Query.builder("Aggregate") + .output(x) + .clause( + x.assign(ageView.aggregate(y, INT_SUM, p1, y)) + ) + .build(); + + var store = ModelStore.builder() + .symbols(age) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .queries(query) + .build(); + + var model = store.createEmptyModel(); + var ageInterpretation = model.getInterpretation(age); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + ageInterpretation.put(Tuple.of(0), 12); + ageInterpretation.put(Tuple.of(1), 24); + + queryEngine.flushChanges(); + assertResults(Map.of(Tuple.of(), 36), queryResultSet); + } + + @QueryEngineTest + void predicateAggregationTest(QueryEvaluationHint hint) { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var age = new Symbol<>("age", 1, Integer.class, null); + var personView = new KeyOnlyRelationView<>(person); + var ageView = new FunctionalRelationView<>(age); + + var p1 = Variable.of("p1"); + var x = Variable.of("x", Integer.class); + var y = Variable.of("y", Integer.class); + var subQuery = Dnf.builder("SubQuery") + .parameters(p1, x) + .clause( + personView.call(p1), + ageView.call(p1, x) + ) + .build(); + var query = Query.builder("Aggregate") + .output(x) + .clause( + x.assign(subQuery.aggregate(y, INT_SUM, p1, y)) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, age) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .queries(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var ageInterpretation = model.getInterpretation(age); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + + ageInterpretation.put(Tuple.of(0), 12); + ageInterpretation.put(Tuple.of(1), 24); + + queryEngine.flushChanges(); + assertResults(Map.of(Tuple.of(), 36), queryResultSet); + } + + @QueryEngineTest + void extremeValueTest(QueryEvaluationHint hint) { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); + var personView = new KeyOnlyRelationView<>(person); + var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); + + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); + var x = Variable.of("x", Integer.class); + var y = Variable.of("y", Integer.class); + var subQuery = Dnf.builder("SubQuery") + .parameters(p1, x) + .clause( + personView.call(p1), + x.assign(friendMustView.count(p1, p2)) + ) + .build(); + var minQuery = Query.builder("Min") + .output(x) + .clause( + x.assign(subQuery.aggregate(y, INT_MIN, p1, y)) + ) + .build(); + var maxQuery = Query.builder("Max") + .output(x) + .clause( + x.assign(subQuery.aggregate(y, INT_MAX, p1, y)) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, friend) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .queries(minQuery, maxQuery) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var friendInterpretation = model.getInterpretation(friend); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var minResultSet = queryEngine.getResultSet(minQuery); + var maxResultSet = queryEngine.getResultSet(maxQuery); + + assertResults(Map.of(Tuple.of(), Integer.MAX_VALUE), minResultSet); + assertResults(Map.of(Tuple.of(), Integer.MIN_VALUE), maxResultSet); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + personInterpretation.put(Tuple.of(2), true); + + friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); + friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); + friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); + + queryEngine.flushChanges(); + assertResults(Map.of(Tuple.of(), 0), minResultSet); + assertResults(Map.of(Tuple.of(), 2), maxResultSet); + + friendInterpretation.put(Tuple.of(2, 0), TruthValue.TRUE); + friendInterpretation.put(Tuple.of(2, 1), TruthValue.TRUE); + + queryEngine.flushChanges(); + assertResults(Map.of(Tuple.of(), 1), minResultSet); + assertResults(Map.of(Tuple.of(), 2), maxResultSet); + + friendInterpretation.put(Tuple.of(0, 1), TruthValue.FALSE); + friendInterpretation.put(Tuple.of(1, 0), TruthValue.FALSE); + friendInterpretation.put(Tuple.of(2, 0), TruthValue.FALSE); + + queryEngine.flushChanges(); + assertResults(Map.of(Tuple.of(), 0), minResultSet); + assertResults(Map.of(Tuple.of(), 1), maxResultSet); + } + + @QueryEngineTest + void invalidComputationTest(QueryEvaluationHint hint) { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var age = new Symbol<>("age", 1, Integer.class, null); + var personView = new KeyOnlyRelationView<>(person); + var ageView = new FunctionalRelationView<>(age); + + var p1 = Variable.of("p1"); + var x = Variable.of("x", Integer.class); + var y = Variable.of("y", Integer.class); + var query = Query.builder("InvalidComputation") + .parameter(p1) + .output(y) + .clause( + personView.call(p1), + ageView.call(p1, x), + y.assign(div(constant(120), x)) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, age) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .queries(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var ageInterpretation = model.getInterpretation(age); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + + ageInterpretation.put(Tuple.of(0), 0); + ageInterpretation.put(Tuple.of(1), 30); + + queryEngine.flushChanges(); + assertNullableResults(Map.of( + Tuple.of(0), Optional.empty(), + Tuple.of(1), Optional.of(4), + Tuple.of(2), Optional.empty() + ), queryResultSet); + } + + @QueryEngineTest + void invalidAssumeTest(QueryEvaluationHint hint) { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var age = new Symbol<>("age", 1, Integer.class, null); + var personView = new KeyOnlyRelationView<>(person); + var ageView = new FunctionalRelationView<>(age); + + var p1 = Variable.of("p1"); + var x = Variable.of("x", Integer.class); + var query = Query.builder("InvalidComputation") + .parameter(p1) + .clause( + personView.call(p1), + ageView.call(p1, x), + assume(lessEq(div(constant(120), x), constant(5))) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, age) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .queries(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var ageInterpretation = model.getInterpretation(age); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + personInterpretation.put(Tuple.of(2), true); + + ageInterpretation.put(Tuple.of(0), 0); + ageInterpretation.put(Tuple.of(1), 30); + ageInterpretation.put(Tuple.of(2), 20); + + queryEngine.flushChanges(); + assertResults(Map.of( + Tuple.of(0), false, + Tuple.of(1), true, + Tuple.of(2), false, + Tuple.of(3), false + ), queryResultSet); + } + + @QueryEngineTest + void notFunctionalTest(QueryEvaluationHint hint) { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var age = new Symbol<>("age", 1, Integer.class, null); + var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); + var personView = new KeyOnlyRelationView<>(person); + var ageView = new FunctionalRelationView<>(age); + var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); + + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); + var x = Variable.of("x", Integer.class); + var query = Query.builder("NotFunctional") + .parameter(p1) + .output(x) + .clause( + personView.call(p1), + friendMustView.call(p1, p2), + ageView.call(p2, x) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, age, friend) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .query(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var ageInterpretation = model.getInterpretation(age); + var friendInterpretation = model.getInterpretation(friend); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + personInterpretation.put(Tuple.of(2), true); + + ageInterpretation.put(Tuple.of(0), 24); + ageInterpretation.put(Tuple.of(1), 30); + ageInterpretation.put(Tuple.of(2), 36); + + friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); + friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); + friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); + + queryEngine.flushChanges(); + var invalidTuple = Tuple.of(1); + var cursor = queryResultSet.getAll(); + assertAll( + () -> assertThat("value for key 0", queryResultSet.get(Tuple.of(0)), is(30)), + () -> assertThrows(IllegalStateException.class, () -> queryResultSet.get(invalidTuple), + "multiple values for key 1"), + () -> assertThat("value for key 2", queryResultSet.get(Tuple.of(2)), is(nullValue())), + () -> assertThat("value for key 3", queryResultSet.get(Tuple.of(3)), is(nullValue())) + ); + if (hint.getQueryBackendRequirementType() != QueryEvaluationHint.BackendRequirement.DEFAULT_SEARCH) { + // Local search doesn't support throwing an error on multiple function return values. + assertThat("results size", queryResultSet.size(), is(2)); + assertThrows(IllegalStateException.class, () -> enumerateValues(cursor), "move cursor"); + } + } + + private static void enumerateValues(Cursor cursor) { + //noinspection StatementWithEmptyBody + while (cursor.move()) { + // Nothing do, just let the cursor move through the result set. + } + } +} 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 8b25419d..8a3f9d88 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 @@ -1,33 +1,38 @@ package tools.refinery.store.query.viatra; +import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; import org.junit.jupiter.api.Test; -import tools.refinery.store.map.Cursor; import tools.refinery.store.model.ModelStore; -import tools.refinery.store.query.Dnf; import tools.refinery.store.query.ModelQuery; -import tools.refinery.store.query.Variable; +import tools.refinery.store.query.dnf.Dnf; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.query.term.Variable; +import tools.refinery.store.query.viatra.tests.QueryEngineTest; import tools.refinery.store.query.view.FilteredRelationView; +import tools.refinery.store.query.view.FunctionalRelationView; import tools.refinery.store.query.view.KeyOnlyRelationView; import tools.refinery.store.representation.Symbol; import tools.refinery.store.representation.TruthValue; import tools.refinery.store.tuple.Tuple; -import tools.refinery.store.tuple.TupleLike; -import java.util.HashSet; -import java.util.Set; +import java.util.Map; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static tools.refinery.store.query.literal.Literals.assume; import static tools.refinery.store.query.literal.Literals.not; +import static tools.refinery.store.query.term.int_.IntTerms.constant; +import static tools.refinery.store.query.term.int_.IntTerms.greaterEq; +import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults; class QueryTest { - @Test - void typeConstraintTest() { + @QueryEngineTest + void typeConstraintTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var asset = new Symbol<>("Asset", 1, Boolean.class, false); var personView = new KeyOnlyRelationView<>(person); - var p1 = new Variable("p1"); - var predicate = Dnf.builder("TypeConstraint") + var p1 = Variable.of("p1"); + var predicate = Query.builder("TypeConstraint") .parameters(p1) .clause(personView.call(p1)) .build(); @@ -35,7 +40,8 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, asset) .with(ViatraModelQuery.ADAPTER) - .queries(predicate) + .defaultHint(hint) + .query(predicate) .build(); var model = store.createEmptyModel(); @@ -51,20 +57,23 @@ class QueryTest { assetInterpretation.put(Tuple.of(2), true); queryEngine.flushChanges(); - assertEquals(2, predicateResultSet.countResults()); - compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0), Tuple.of(1))); + assertResults(Map.of( + Tuple.of(0), true, + Tuple.of(1), true, + Tuple.of(2), false + ), predicateResultSet); } - @Test - void relationConstraintTest() { + @QueryEngineTest + void relationConstraintTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); var personView = new KeyOnlyRelationView<>(person); var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); - var p1 = new Variable("p1"); - var p2 = new Variable("p2"); - var predicate = Dnf.builder("RelationConstraint") + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); + var predicate = Query.builder("RelationConstraint") .parameters(p1, p2) .clause( personView.call(p1), @@ -76,6 +85,7 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) .queries(predicate) .build(); @@ -85,8 +95,6 @@ class QueryTest { var queryEngine = model.getAdapter(ModelQuery.ADAPTER); var predicateResultSet = queryEngine.getResultSet(predicate); - assertEquals(0, predicateResultSet.countResults()); - personInterpretation.put(Tuple.of(0), true); personInterpretation.put(Tuple.of(1), true); personInterpretation.put(Tuple.of(2), true); @@ -94,83 +102,27 @@ class QueryTest { friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); - - assertEquals(0, predicateResultSet.countResults()); - assertFalse(predicateResultSet.hasResult(Tuple.of(0, 1))); - assertFalse(predicateResultSet.hasResult(Tuple.of(0, 2))); + friendInterpretation.put(Tuple.of(1, 3), TruthValue.TRUE); queryEngine.flushChanges(); - assertEquals(3, predicateResultSet.countResults()); - compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(1, 2))); - assertTrue(predicateResultSet.hasResult(Tuple.of(0, 1))); - assertFalse(predicateResultSet.hasResult(Tuple.of(0, 2))); + assertResults(Map.of( + Tuple.of(0, 1), true, + Tuple.of(1, 0), true, + Tuple.of(1, 2), true, + Tuple.of(2, 1), false + ), predicateResultSet); } - @Test - void andTest() { + @QueryEngineTest + void existTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); var personView = new KeyOnlyRelationView<>(person); var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); - var p1 = new Variable("p1"); - var p2 = new Variable("p2"); - var predicate = Dnf.builder("RelationConstraint") - .parameters(p1, p2) - .clause( - personView.call(p1), - personView.call(p2), - friendMustView.call(p1, p2), - friendMustView.call(p2, p1) - ) - .build(); - - var store = ModelStore.builder() - .symbols(person, friend) - .with(ViatraModelQuery.ADAPTER) - .queries(predicate) - .build(); - - var model = store.createEmptyModel(); - var personInterpretation = model.getInterpretation(person); - var friendInterpretation = model.getInterpretation(friend); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); - var predicateResultSet = queryEngine.getResultSet(predicate); - - assertEquals(0, predicateResultSet.countResults()); - - personInterpretation.put(Tuple.of(0), true); - personInterpretation.put(Tuple.of(1), true); - personInterpretation.put(Tuple.of(2), true); - - friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); - friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE); - - queryEngine.flushChanges(); - assertEquals(0, predicateResultSet.countResults()); - - friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); - queryEngine.flushChanges(); - assertEquals(2, predicateResultSet.countResults()); - compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(1, 0))); - - friendInterpretation.put(Tuple.of(2, 0), TruthValue.TRUE); - queryEngine.flushChanges(); - assertEquals(4, predicateResultSet.countResults()); - compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(1, 0), Tuple.of(0, 2), - Tuple.of(2, 0))); - } - - @Test - void existTest() { - var person = new Symbol<>("Person", 1, Boolean.class, false); - var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); - var personView = new KeyOnlyRelationView<>(person); - var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); - - var p1 = new Variable("p1"); - var p2 = new Variable("p2"); - var predicate = Dnf.builder("RelationConstraint") + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); + var predicate = Query.builder("RelationConstraint") .parameters(p1) .clause( personView.call(p1), @@ -182,6 +134,7 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) .queries(predicate) .build(); @@ -198,16 +151,19 @@ class QueryTest { friendInterpretation.put(Tuple.of(0, 1), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 0), TruthValue.TRUE); friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); - - assertEquals(0, predicateResultSet.countResults()); + friendInterpretation.put(Tuple.of(3, 2), TruthValue.TRUE); queryEngine.flushChanges(); - assertEquals(2, predicateResultSet.countResults()); - compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0), Tuple.of(1))); + assertResults(Map.of( + Tuple.of(0), true, + Tuple.of(1), true, + Tuple.of(2), false, + Tuple.of(3), false + ), predicateResultSet); } - @Test - void orTest() { + @QueryEngineTest + void orTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var animal = new Symbol<>("Animal", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); @@ -215,9 +171,9 @@ class QueryTest { var animalView = new KeyOnlyRelationView<>(animal); var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); - var p1 = new Variable("p1"); - var p2 = new Variable("p2"); - var predicate = Dnf.builder("Or") + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); + var predicate = Query.builder("Or") .parameters(p1, p2) .clause( personView.call(p1), @@ -234,6 +190,7 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, animal, friend) .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) .queries(predicate) .build(); @@ -256,18 +213,23 @@ class QueryTest { friendInterpretation.put(Tuple.of(3, 0), TruthValue.TRUE); queryEngine.flushChanges(); - assertEquals(2, predicateResultSet.countResults()); - compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1), Tuple.of(2, 3))); + assertResults(Map.of( + Tuple.of(0, 1), true, + Tuple.of(0, 2), false, + Tuple.of(2, 3), true, + Tuple.of(3, 0), false, + Tuple.of(3, 2), false + ), predicateResultSet); } - @Test - void equalityTest() { + @QueryEngineTest + void equalityTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var personView = new KeyOnlyRelationView<>(person); - var p1 = new Variable("p1"); - var p2 = new Variable("p2"); - var predicate = Dnf.builder("Equality") + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); + var predicate = Query.builder("Equality") .parameters(p1, p2) .clause( personView.call(p1), @@ -279,6 +241,7 @@ class QueryTest { var store = ModelStore.builder() .symbols(person) .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) .queries(predicate) .build(); @@ -292,21 +255,26 @@ class QueryTest { personInterpretation.put(Tuple.of(2), true); queryEngine.flushChanges(); - assertEquals(3, predicateResultSet.countResults()); - compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 0), Tuple.of(1, 1), Tuple.of(2, 2))); + assertResults(Map.of( + Tuple.of(0, 0), true, + Tuple.of(1, 1), true, + Tuple.of(2, 2), true, + Tuple.of(0, 1), false, + Tuple.of(3, 3), false + ), predicateResultSet); } - @Test - void inequalityTest() { + @QueryEngineTest + void inequalityTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); var personView = new KeyOnlyRelationView<>(person); var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); - var p1 = new Variable("p1"); - var p2 = new Variable("p2"); - var p3 = new Variable("p3"); - var predicate = Dnf.builder("Inequality") + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); + var p3 = Variable.of("p3"); + var predicate = Query.builder("Inequality") .parameters(p1, p2, p3) .clause( personView.call(p1), @@ -320,6 +288,7 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) .queries(predicate) .build(); @@ -337,19 +306,22 @@ class QueryTest { friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); queryEngine.flushChanges(); - assertEquals(2, predicateResultSet.countResults()); - compareMatchSets(predicateResultSet.allResults(), Set.of(Tuple.of(0, 1, 2), Tuple.of(1, 0, 2))); + assertResults(Map.of( + Tuple.of(0, 1, 2), true, + Tuple.of(1, 0, 2), true, + Tuple.of(0, 0, 2), false + ), predicateResultSet); } - @Test - void patternCallTest() { + @QueryEngineTest + void patternCallTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); var personView = new KeyOnlyRelationView<>(person); var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); - var p1 = new Variable("p1"); - var p2 = new Variable("p2"); + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); var friendPredicate = Dnf.builder("RelationConstraint") .parameters(p1, p2) .clause( @@ -359,9 +331,9 @@ class QueryTest { ) .build(); - var p3 = new Variable("p3"); - var p4 = new Variable("p4"); - var predicate = Dnf.builder("PositivePatternCall") + var p3 = Variable.of("p3"); + var p4 = Variable.of("p4"); + var predicate = Query.builder("PositivePatternCall") .parameters(p3, p4) .clause( personView.call(p3), @@ -373,6 +345,7 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) .queries(predicate) .build(); @@ -391,19 +364,24 @@ class QueryTest { friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); queryEngine.flushChanges(); - assertEquals(3, predicateResultSet.countResults()); + assertResults(Map.of( + Tuple.of(0, 1), true, + Tuple.of(1, 0), true, + Tuple.of(1, 2), true, + Tuple.of(2, 1), false + ), predicateResultSet); } - @Test - void negativeRelationViewTest() { + @QueryEngineTest + void negativeRelationViewTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); var personView = new KeyOnlyRelationView<>(person); var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); - var p1 = new Variable("p1"); - var p2 = new Variable("p2"); - var predicate = Dnf.builder("NegativePatternCall") + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); + var predicate = Query.builder("NegativePatternCall") .parameters(p1, p2) .clause( personView.call(p1), @@ -415,6 +393,7 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) .queries(predicate) .build(); @@ -433,18 +412,29 @@ class QueryTest { friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); queryEngine.flushChanges(); - assertEquals(6, predicateResultSet.countResults()); + assertResults(Map.of( + Tuple.of(0, 0), true, + Tuple.of(0, 2), true, + Tuple.of(1, 1), true, + Tuple.of(2, 0), true, + Tuple.of(2, 1), true, + Tuple.of(2, 2), true, + Tuple.of(0, 1), false, + Tuple.of(1, 0), false, + Tuple.of(1, 2), false, + Tuple.of(0, 3), false + ), predicateResultSet); } - @Test - void negativePatternCallTest() { + @QueryEngineTest + void negativePatternCallTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); var personView = new KeyOnlyRelationView<>(person); var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); - var p1 = new Variable("p1"); - var p2 = new Variable("p2"); + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); var friendPredicate = Dnf.builder("RelationConstraint") .parameters(p1, p2) .clause( @@ -454,9 +444,9 @@ class QueryTest { ) .build(); - var p3 = new Variable("p3"); - var p4 = new Variable("p4"); - var predicate = Dnf.builder("NegativePatternCall") + var p3 = Variable.of("p3"); + var p4 = Variable.of("p4"); + var predicate = Query.builder("NegativePatternCall") .parameters(p3, p4) .clause( personView.call(p3), @@ -468,6 +458,7 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) .queries(predicate) .build(); @@ -486,20 +477,31 @@ class QueryTest { friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); queryEngine.flushChanges(); - assertEquals(6, predicateResultSet.countResults()); + assertResults(Map.of( + Tuple.of(0, 0), true, + Tuple.of(0, 2), true, + Tuple.of(1, 1), true, + Tuple.of(2, 0), true, + Tuple.of(2, 1), true, + Tuple.of(2, 2), true, + Tuple.of(0, 1), false, + Tuple.of(1, 0), false, + Tuple.of(1, 2), false, + Tuple.of(0, 3), false + ), predicateResultSet); } - @Test - void negativeRelationViewWithQuantificationTest() { + @QueryEngineTest + void negativeRelationViewWithQuantificationTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); var personView = new KeyOnlyRelationView<>(person); var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); - var p1 = new Variable("p1"); - var p2 = new Variable("p2"); + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); - var predicate = Dnf.builder("Count") + var predicate = Query.builder("Count") .parameters(p1) .clause( personView.call(p1), @@ -510,6 +512,7 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) .queries(predicate) .build(); @@ -527,18 +530,23 @@ class QueryTest { friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE); queryEngine.flushChanges(); - assertEquals(2, predicateResultSet.countResults()); + assertResults(Map.of( + Tuple.of(0), false, + Tuple.of(1), true, + Tuple.of(2), true, + Tuple.of(3), false + ), predicateResultSet); } - @Test - void negativeWithQuantificationTest() { + @QueryEngineTest + void negativeWithQuantificationTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); var personView = new KeyOnlyRelationView<>(person); var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); - var p1 = new Variable("p1"); - var p2 = new Variable("p2"); + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); var called = Dnf.builder("Called") .parameters(p1, p2) @@ -549,7 +557,7 @@ class QueryTest { ) .build(); - var predicate = Dnf.builder("Count") + var predicate = Query.builder("Count") .parameters(p1) .clause( personView.call(p1), @@ -560,6 +568,7 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) .queries(predicate) .build(); @@ -577,19 +586,24 @@ class QueryTest { friendInterpretation.put(Tuple.of(0, 2), TruthValue.TRUE); queryEngine.flushChanges(); - assertEquals(2, predicateResultSet.countResults()); + assertResults(Map.of( + Tuple.of(0), false, + Tuple.of(1), true, + Tuple.of(2), true, + Tuple.of(3), false + ), predicateResultSet); } - @Test - void transitiveRelationViewTest() { + @QueryEngineTest + void transitiveRelationViewTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); var personView = new KeyOnlyRelationView<>(person); var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); - var p1 = new Variable("p1"); - var p2 = new Variable("p2"); - var predicate = Dnf.builder("TransitivePatternCall") + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); + var predicate = Query.builder("TransitivePatternCall") .parameters(p1, p2) .clause( personView.call(p1), @@ -601,6 +615,7 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) .queries(predicate) .build(); @@ -618,18 +633,29 @@ class QueryTest { friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); queryEngine.flushChanges(); - assertEquals(3, predicateResultSet.countResults()); + assertResults(Map.of( + Tuple.of(0, 0), false, + Tuple.of(0, 1), true, + Tuple.of(0, 2), true, + Tuple.of(1, 0), false, + Tuple.of(1, 1), false, + Tuple.of(1, 2), true, + Tuple.of(2, 0), false, + Tuple.of(2, 1), false, + Tuple.of(2, 2), false, + Tuple.of(2, 3), false + ), predicateResultSet); } - @Test - void transitivePatternCallTest() { + @QueryEngineTest + void transitivePatternCallTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); var personView = new KeyOnlyRelationView<>(person); var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); - var p1 = new Variable("p1"); - var p2 = new Variable("p2"); + var p1 = Variable.of("p1"); + var p2 = Variable.of("p2"); var friendPredicate = Dnf.builder("RelationConstraint") .parameters(p1, p2) .clause( @@ -639,9 +665,9 @@ class QueryTest { ) .build(); - var p3 = new Variable("p3"); - var p4 = new Variable("p4"); - var predicate = Dnf.builder("TransitivePatternCall") + var p3 = Variable.of("p3"); + var p4 = Variable.of("p4"); + var predicate = Query.builder("TransitivePatternCall") .parameters(p3, p4) .clause( personView.call(p3), @@ -653,6 +679,7 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) .queries(predicate) .build(); @@ -670,15 +697,71 @@ class QueryTest { friendInterpretation.put(Tuple.of(1, 2), TruthValue.TRUE); queryEngine.flushChanges(); - assertEquals(3, predicateResultSet.countResults()); + assertResults(Map.of( + Tuple.of(0, 0), false, + Tuple.of(0, 1), true, + Tuple.of(0, 2), true, + Tuple.of(1, 0), false, + Tuple.of(1, 1), false, + Tuple.of(1, 2), true, + Tuple.of(2, 0), false, + Tuple.of(2, 1), false, + Tuple.of(2, 2), false, + Tuple.of(2, 3), false + ), predicateResultSet); + } + + @QueryEngineTest + void assumeTest(QueryEvaluationHint hint) { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var age = new Symbol<>("age", 1, Integer.class, null); + var personView = new KeyOnlyRelationView<>(person); + var ageView = new FunctionalRelationView<>(age); + + var p1 = Variable.of("p1"); + var x = Variable.of("x", Integer.class); + var query = Query.builder("Constraint") + .parameter(p1) + .clause( + personView.call(p1), + ageView.call(p1, x), + assume(greaterEq(x, constant(18))) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, age) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(hint) + .queries(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var ageInterpretation = model.getInterpretation(age); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + + ageInterpretation.put(Tuple.of(0), 12); + ageInterpretation.put(Tuple.of(1), 24); + + queryEngine.flushChanges(); + assertResults(Map.of( + Tuple.of(0), false, + Tuple.of(1), true, + Tuple.of(2), false + ), queryResultSet); } @Test void alwaysFalseTest() { var person = new Symbol<>("Person", 1, Boolean.class, false); - var p1 = new Variable("p1"); - var predicate = Dnf.builder("AlwaysFalse").parameters(p1).build(); + var p1 = Variable.of("p1"); + var predicate = Query.builder("AlwaysFalse").parameters(p1).build(); var store = ModelStore.builder() .symbols(person) @@ -696,28 +779,19 @@ class QueryTest { personInterpretation.put(Tuple.of(2), true); queryEngine.flushChanges(); - assertEquals(0, predicateResultSet.countResults()); + assertResults(Map.of(), predicateResultSet); } @Test void alwaysTrueTest() { var person = new Symbol<>("Person", 1, Boolean.class, false); - var p1 = new Variable("p1"); - var predicate = Dnf.builder("AlwaysTrue").parameters(p1).clause().build(); + var p1 = Variable.of("p1"); + var predicate = Query.builder("AlwaysTrue").parameters(p1).clause().build(); var storeBuilder = ModelStore.builder().symbols(person); var queryBuilder = storeBuilder.with(ViatraModelQuery.ADAPTER); assertThrows(IllegalArgumentException.class, () -> queryBuilder.queries(predicate)); } - - private static void compareMatchSets(Cursor cursor, Set expected) { - Set translatedMatchSet = new HashSet<>(); - while (cursor.move()) { - var element = cursor.getKey(); - translatedMatchSet.add(element.toTuple()); - } - assertEquals(expected, translatedMatchSet); - } } 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 461685b5..abd49341 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 @@ -1,25 +1,160 @@ package tools.refinery.store.query.viatra; +import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import tools.refinery.store.model.ModelStore; -import tools.refinery.store.query.Dnf; import tools.refinery.store.query.ModelQuery; -import tools.refinery.store.query.Variable; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.query.term.Variable; +import tools.refinery.store.query.view.FilteredRelationView; +import tools.refinery.store.query.view.FunctionalRelationView; import tools.refinery.store.query.view.KeyOnlyRelationView; import tools.refinery.store.representation.Symbol; import tools.refinery.store.tuple.Tuple; -import static org.junit.jupiter.api.Assertions.*; +import java.util.Map; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertNullableResults; +import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults; class QueryTransactionTest { @Test void flushTest() { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var personView = new KeyOnlyRelationView<>(person); + + var p1 = Variable.of("p1"); + var predicate = Query.builder("TypeConstraint") + .parameters(p1) + .clause(personView.call(p1)) + .build(); + + var store = ModelStore.builder() + .symbols(person) + .with(ViatraModelQuery.ADAPTER) + .queries(predicate) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var predicateResultSet = queryEngine.getResultSet(predicate); + + assertResults(Map.of( + Tuple.of(0), false, + Tuple.of(1), false, + Tuple.of(2), false, + Tuple.of(3), false + ), predicateResultSet); + assertFalse(queryEngine.hasPendingChanges()); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + + assertResults(Map.of( + Tuple.of(0), false, + Tuple.of(1), false, + Tuple.of(2), false, + Tuple.of(3), false + ), predicateResultSet); + assertTrue(queryEngine.hasPendingChanges()); + + queryEngine.flushChanges(); + assertResults(Map.of( + Tuple.of(0), true, + Tuple.of(1), true, + Tuple.of(2), false, + Tuple.of(3), false + ), predicateResultSet); + assertFalse(queryEngine.hasPendingChanges()); + + personInterpretation.put(Tuple.of(1), false); + personInterpretation.put(Tuple.of(2), true); + + assertResults(Map.of( + Tuple.of(0), true, + Tuple.of(1), true, + Tuple.of(2), false, + Tuple.of(3), false + ), predicateResultSet); + assertTrue(queryEngine.hasPendingChanges()); + + queryEngine.flushChanges(); + assertResults(Map.of( + Tuple.of(0), true, + Tuple.of(1), false, + Tuple.of(2), true, + Tuple.of(3), false + ), predicateResultSet); + assertFalse(queryEngine.hasPendingChanges()); + } + + @Test + void localSearchTest() { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var personView = new KeyOnlyRelationView<>(person); + + var p1 = Variable.of("p1"); + var predicate = Query.builder("TypeConstraint") + .parameters(p1) + .clause(personView.call(p1)) + .build(); + + var store = ModelStore.builder() + .symbols(person) + .with(ViatraModelQuery.ADAPTER) + .defaultHint(new QueryEvaluationHint(null, QueryEvaluationHint.BackendRequirement.DEFAULT_SEARCH)) + .queries(predicate) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var predicateResultSet = queryEngine.getResultSet(predicate); + + assertResults(Map.of( + Tuple.of(0), false, + Tuple.of(1), false, + Tuple.of(2), false, + Tuple.of(3), false + ), predicateResultSet); + assertFalse(queryEngine.hasPendingChanges()); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + + assertResults(Map.of( + Tuple.of(0), true, + Tuple.of(1), true, + Tuple.of(2), false, + Tuple.of(3), false + ), predicateResultSet); + assertFalse(queryEngine.hasPendingChanges()); + + personInterpretation.put(Tuple.of(1), false); + personInterpretation.put(Tuple.of(2), true); + + assertResults(Map.of( + Tuple.of(0), true, + Tuple.of(1), false, + Tuple.of(2), true, + Tuple.of(3), false + ), predicateResultSet); + assertFalse(queryEngine.hasPendingChanges()); + } + + @Test + void unrelatedChangesTest() { var person = new Symbol<>("Person", 1, Boolean.class, false); var asset = new Symbol<>("Asset", 1, Boolean.class, false); var personView = new KeyOnlyRelationView<>(person); - var p1 = new Variable("p1"); - var predicate = Dnf.builder("TypeConstraint") + var p1 = Variable.of("p1"); + var predicate = Query.builder("TypeConstraint") .parameters(p1) .clause(personView.call(p1)) .build(); @@ -36,7 +171,6 @@ class QueryTransactionTest { var queryEngine = model.getAdapter(ModelQuery.ADAPTER); var predicateResultSet = queryEngine.getResultSet(predicate); - assertEquals(0, predicateResultSet.countResults()); assertFalse(queryEngine.hasPendingChanges()); personInterpretation.put(Tuple.of(0), true); @@ -45,19 +179,245 @@ class QueryTransactionTest { assetInterpretation.put(Tuple.of(1), true); assetInterpretation.put(Tuple.of(2), true); - assertEquals(0, predicateResultSet.countResults()); + assertResults(Map.of( + Tuple.of(0), false, + Tuple.of(1), false, + Tuple.of(2), false, + Tuple.of(3), false, + Tuple.of(4), false + ), predicateResultSet); assertTrue(queryEngine.hasPendingChanges()); queryEngine.flushChanges(); - assertEquals(2, predicateResultSet.countResults()); + assertResults(Map.of( + Tuple.of(0), true, + Tuple.of(1), true, + Tuple.of(2), false, + Tuple.of(3), false, + Tuple.of(4), false + ), predicateResultSet); assertFalse(queryEngine.hasPendingChanges()); - personInterpretation.put(Tuple.of(4), true); - assertEquals(2, predicateResultSet.countResults()); - assertTrue(queryEngine.hasPendingChanges()); + assetInterpretation.put(Tuple.of(3), true); + assertFalse(queryEngine.hasPendingChanges()); + + assertResults(Map.of( + Tuple.of(0), true, + Tuple.of(1), true, + Tuple.of(2), false, + Tuple.of(3), false, + Tuple.of(4), false + ), predicateResultSet); + + queryEngine.flushChanges(); + assertResults(Map.of( + Tuple.of(0), true, + Tuple.of(1), true, + Tuple.of(2), false, + Tuple.of(3), false, + Tuple.of(4), false + ), predicateResultSet); + assertFalse(queryEngine.hasPendingChanges()); + } + + @Test + void tupleChangingChangeTest() { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var age = new Symbol<>("age", 1, Integer.class, null); + var personView = new KeyOnlyRelationView<>(person); + var ageView = new FunctionalRelationView<>(age); + + var p1 = Variable.of("p1"); + var x = Variable.of("x", Integer.class); + var query = Query.builder() + .parameter(p1) + .output(x) + .clause( + personView.call(p1), + ageView.call(p1, x) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, age) + .with(ViatraModelQuery.ADAPTER) + .query(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var ageInterpretation = model.getInterpretation(age); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + + ageInterpretation.put(Tuple.of(0), 24); + + queryEngine.flushChanges(); + assertResults(Map.of(Tuple.of(0), 24), queryResultSet); + + ageInterpretation.put(Tuple.of(0), 25); + + queryEngine.flushChanges(); + assertResults(Map.of(Tuple.of(0), 25), queryResultSet); + + ageInterpretation.put(Tuple.of(0), null); + + queryEngine.flushChanges(); + assertNullableResults(Map.of(Tuple.of(0), Optional.empty()), queryResultSet); + } + + @Test + void tuplePreservingUnchangedTest() { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var age = new Symbol<>("age", 1, Integer.class, null); + var personView = new KeyOnlyRelationView<>(person); + var adultView = new FilteredRelationView<>(age, "adult", n -> n != null && n >= 18); + + var p1 = Variable.of("p1"); + var x = Variable.of("x", Integer.class); + var query = Query.builder() + .parameter(p1) + .clause( + personView.call(p1), + adultView.call(p1) + ) + .build(); + + var store = ModelStore.builder() + .symbols(person, age) + .with(ViatraModelQuery.ADAPTER) + .query(query) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var ageInterpretation = model.getInterpretation(age); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryResultSet = queryEngine.getResultSet(query); + + personInterpretation.put(Tuple.of(0), true); + + ageInterpretation.put(Tuple.of(0), 24); + + queryEngine.flushChanges(); + assertResults(Map.of(Tuple.of(0), true), queryResultSet); + + ageInterpretation.put(Tuple.of(0), 25); + + queryEngine.flushChanges(); + assertResults(Map.of(Tuple.of(0), true), queryResultSet); + + ageInterpretation.put(Tuple.of(0), 17); queryEngine.flushChanges(); - assertEquals(3, predicateResultSet.countResults()); + assertResults(Map.of(Tuple.of(0), false), queryResultSet); + } + + @Disabled("TODO Fix DiffCursor") + @Test + void commitAfterFlushTest() { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var personView = new KeyOnlyRelationView<>(person); + + var p1 = Variable.of("p1"); + var predicate = Query.builder("TypeConstraint") + .parameters(p1) + .clause(personView.call(p1)) + .build(); + + var store = ModelStore.builder() + .symbols(person) + .with(ViatraModelQuery.ADAPTER) + .queries(predicate) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var predicateResultSet = queryEngine.getResultSet(predicate); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + + queryEngine.flushChanges(); + assertResults(Map.of( + Tuple.of(0), true, + Tuple.of(1), true, + Tuple.of(2), false, + Tuple.of(3), false + ), predicateResultSet); + + var state1 = model.commit(); + + personInterpretation.put(Tuple.of(1), false); + personInterpretation.put(Tuple.of(2), true); + + queryEngine.flushChanges(); + assertResults(Map.of( + Tuple.of(0), true, + Tuple.of(1), false, + Tuple.of(2), true, + Tuple.of(3), false + ), predicateResultSet); + + model.restore(state1); + + assertFalse(queryEngine.hasPendingChanges()); + assertResults(Map.of( + Tuple.of(0), true, + Tuple.of(1), true, + Tuple.of(2), false, + Tuple.of(3), false + ), predicateResultSet); + } + + @Disabled("TODO Fix DiffCursor") + @Test + void commitWithoutFlushTest() { + var person = new Symbol<>("Person", 1, Boolean.class, false); + var personView = new KeyOnlyRelationView<>(person); + + var p1 = Variable.of("p1"); + var predicate = Query.builder("TypeConstraint") + .parameters(p1) + .clause(personView.call(p1)) + .build(); + + var store = ModelStore.builder() + .symbols(person) + .with(ViatraModelQuery.ADAPTER) + .queries(predicate) + .build(); + + var model = store.createEmptyModel(); + var personInterpretation = model.getInterpretation(person); + var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var predicateResultSet = queryEngine.getResultSet(predicate); + + personInterpretation.put(Tuple.of(0), true); + personInterpretation.put(Tuple.of(1), true); + + assertResults(Map.of(), predicateResultSet); + assertTrue(queryEngine.hasPendingChanges()); + + var state1 = model.commit(); + + personInterpretation.put(Tuple.of(1), false); + personInterpretation.put(Tuple.of(2), true); + + assertResults(Map.of(), predicateResultSet); + assertTrue(queryEngine.hasPendingChanges()); + + model.restore(state1); + + assertResults(Map.of( + Tuple.of(0), true, + Tuple.of(1), true, + Tuple.of(2), false, + Tuple.of(3), false + ), predicateResultSet); assertFalse(queryEngine.hasPendingChanges()); } } diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java new file mode 100644 index 00000000..6f50ec73 --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java @@ -0,0 +1,52 @@ +package tools.refinery.store.query.viatra.tests; + +import org.junit.jupiter.api.function.Executable; +import tools.refinery.store.query.ResultSet; +import tools.refinery.store.tuple.Tuple; + +import java.util.*; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.jupiter.api.Assertions.assertAll; + +public final class QueryAssertions { + private QueryAssertions() { + throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); + } + + public static void assertNullableResults(Map> expected, ResultSet resultSet) { + var nullableValuesMap = new LinkedHashMap(expected.size()); + for (var entry : expected.entrySet()) { + nullableValuesMap.put(entry.getKey(), entry.getValue().orElse(null)); + } + assertResults(nullableValuesMap, resultSet); + } + + public static void assertResults(Map expected, ResultSet resultSet) { + var defaultValue = resultSet.getQuery().defaultValue(); + var filteredExpected = new LinkedHashMap(); + var executables = new ArrayList(); + for (var entry : expected.entrySet()) { + var key = entry.getKey(); + var value = entry.getValue(); + if (!Objects.equals(value, defaultValue)) { + filteredExpected.put(key, value); + } + executables.add(() -> assertThat("value for key " + key,resultSet.get(key), is(value))); + } + executables.add(() -> assertThat("results size", resultSet.size(), is(filteredExpected.size()))); + + var actual = new LinkedHashMap(); + var cursor = resultSet.getAll(); + while (cursor.move()) { + var key = cursor.getKey(); + var previous = actual.put(key.toTuple(), cursor.getValue()); + assertThat("duplicate value for key " + key, previous, nullValue()); + } + executables.add(() -> assertThat("results cursor", actual, is(filteredExpected))); + + assertAll(executables); + } +} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.java new file mode 100644 index 00000000..b1818a17 --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.java @@ -0,0 +1,22 @@ +package tools.refinery.store.query.viatra.tests; + +import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; + +/** + * Overrides {@link QueryEvaluationHint#toString()} for pretty names in parametric test names. + */ +class QueryBackendHint extends QueryEvaluationHint { + public QueryBackendHint(BackendRequirement backendRequirementType) { + super(null, backendRequirementType); + } + + @Override + public String toString() { + return switch (getQueryBackendRequirementType()) { + case UNSPECIFIED -> "default"; + case DEFAULT_CACHING -> "incremental"; + case DEFAULT_SEARCH -> "localSearch"; + default -> throw new IllegalStateException("Unknown BackendRequirement"); + }; + } +} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java new file mode 100644 index 00000000..f129520c --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java @@ -0,0 +1,16 @@ +package tools.refinery.store.query.viatra.tests; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@ParameterizedTest(name = "backend = {0}") +@ArgumentsSource(QueryEvaluationHintSource.class) +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface QueryEngineTest { +} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java new file mode 100644 index 00000000..a55762e2 --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java @@ -0,0 +1,19 @@ +package tools.refinery.store.query.viatra.tests; + +import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; + +import java.util.stream.Stream; + +public class QueryEvaluationHintSource implements ArgumentsProvider { + @Override + public Stream provideArguments(ExtensionContext context) { + return Stream.of( + Arguments.of(new QueryBackendHint(QueryEvaluationHint.BackendRequirement.UNSPECIFIED)), + Arguments.of(new QueryBackendHint(QueryEvaluationHint.BackendRequirement.DEFAULT_CACHING)), + Arguments.of(new QueryBackendHint(QueryEvaluationHint.BackendRequirement.DEFAULT_SEARCH)) + ); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/AnyResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/AnyResultSet.java new file mode 100644 index 00000000..6d411212 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/AnyResultSet.java @@ -0,0 +1,11 @@ +package tools.refinery.store.query; + +import tools.refinery.store.query.dnf.AnyQuery; + +public sealed interface AnyResultSet permits ResultSet { + ModelQueryAdapter getAdapter(); + + AnyQuery getQuery(); + + int size(); +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java new file mode 100644 index 00000000..cec4c19f --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java @@ -0,0 +1,65 @@ +package tools.refinery.store.query; + +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.literal.*; +import tools.refinery.store.query.term.*; + +import java.util.List; + +public interface Constraint { + String name(); + + List getSorts(); + + default int arity() { + return getSorts().size(); + } + + default boolean invalidIndex(int i) { + return i < 0 || i >= arity(); + } + + default LiteralReduction getReduction() { + return LiteralReduction.NOT_REDUCIBLE; + } + + default boolean equals(LiteralEqualityHelper helper, Constraint other) { + return equals(other); + } + + String toReferenceString(); + + default CallLiteral call(CallPolarity polarity, List arguments) { + return new CallLiteral(polarity, this, arguments); + } + + default CallLiteral call(CallPolarity polarity, Variable... arguments) { + return call(polarity, List.of(arguments)); + } + + default CallLiteral call(Variable... arguments) { + return call(CallPolarity.POSITIVE, arguments); + } + + default CallLiteral callTransitive(NodeVariable left, NodeVariable right) { + return call(CallPolarity.TRANSITIVE, List.of(left, right)); + } + + default AssignedValue count(List arguments) { + return targetVariable -> new CountLiteral(targetVariable, this, arguments); + } + + default AssignedValue count(Variable... arguments) { + return count(List.of(arguments)); + } + + default AssignedValue aggregate(DataVariable inputVariable, Aggregator aggregator, + List arguments) { + return targetVariable -> new AggregationLiteral<>(targetVariable, aggregator, inputVariable, this, arguments); + } + + default AssignedValue aggregate(DataVariable inputVariable, Aggregator aggregator, + Variable... arguments) { + return aggregate(inputVariable, aggregator, List.of(arguments)); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/Dnf.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/Dnf.java deleted file mode 100644 index b6744b50..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/Dnf.java +++ /dev/null @@ -1,175 +0,0 @@ -package tools.refinery.store.query; - -import tools.refinery.store.query.equality.DnfEqualityChecker; -import tools.refinery.store.query.equality.LiteralEqualityHelper; -import tools.refinery.store.query.literal.CallPolarity; -import tools.refinery.store.query.literal.DnfCallLiteral; -import tools.refinery.store.query.literal.LiteralReduction; - -import java.util.*; - -public final class Dnf implements RelationLike { - private static final String INDENTATION = " "; - - private final String name; - - private final String uniqueName; - - private final List parameters; - - private final List> functionalDependencies; - - private final List clauses; - - 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 == null ? uniqueName : name; - } - - public boolean isExplicitlyNamed() { - return name == null; - } - - 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 LiteralReduction getReduction() { - if (clauses.isEmpty()) { - return LiteralReduction.ALWAYS_FALSE; - } - for (var clause : clauses) { - if (clause.literals().isEmpty()) { - return LiteralReduction.ALWAYS_TRUE; - } - } - return LiteralReduction.NOT_REDUCIBLE; - } - - public DnfCallLiteral call(CallPolarity polarity, List arguments) { - return new DnfCallLiteral(polarity, this, arguments); - } - - public DnfCallLiteral call(CallPolarity polarity, Variable... arguments) { - return call(polarity, List.of(arguments)); - } - - public DnfCallLiteral call(Variable... arguments) { - return call(CallPolarity.POSITIVE, arguments); - } - - public DnfCallLiteral callTransitive(Variable left, Variable right) { - return call(CallPolarity.TRANSITIVE, List.of(left, right)); - } - - public boolean equalsWithSubstitution(DnfEqualityChecker callEqualityChecker, Dnf other) { - if (arity() != other.arity()) { - return false; - } - int numClauses = clauses.size(); - if (numClauses != other.clauses.size()) { - return false; - } - for (int i = 0; i < numClauses; i++) { - var literalEqualityHelper = new LiteralEqualityHelper(callEqualityChecker, parameters, other.parameters); - if (!clauses.get(i).equalsWithSubstitution(literalEqualityHelper, other.clauses.get(i))) { - return false; - } - } - return true; - } - - @Override - public String toString() { - var builder = new StringBuilder(); - builder.append("pred ").append(name()).append("("); - var parameterIterator = parameters.iterator(); - if (parameterIterator.hasNext()) { - builder.append(parameterIterator.next()); - while (parameterIterator.hasNext()) { - builder.append(", ").append(parameterIterator.next()); - } - } - builder.append(") <->"); - var clauseIterator = clauses.iterator(); - if (clauseIterator.hasNext()) { - appendClause(clauseIterator.next(), builder); - while (clauseIterator.hasNext()) { - builder.append("\n;"); - appendClause(clauseIterator.next(), builder); - } - } else { - builder.append("\n").append(INDENTATION).append(""); - } - builder.append(".\n"); - return builder.toString(); - } - - private static void appendClause(DnfClause clause, StringBuilder builder) { - var iterator = clause.literals().iterator(); - if (!iterator.hasNext()) { - builder.append("\n").append(INDENTATION).append(""); - return; - } - builder.append("\n").append(INDENTATION).append(iterator.next()); - while (iterator.hasNext()) { - builder.append(",\n").append(INDENTATION).append(iterator.next()); - } - } - - public static DnfBuilder builder() { - return builder(null); - } - - public static DnfBuilder builder(String name) { - return new DnfBuilder(name); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfBuilder.java deleted file mode 100644 index ca47e979..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfBuilder.java +++ /dev/null @@ -1,115 +0,0 @@ -package tools.refinery.store.query; - -import tools.refinery.store.query.literal.Literal; - -import java.util.*; - -@SuppressWarnings("UnusedReturnValue") -public class DnfBuilder { - private final String name; - - private final List parameters = new ArrayList<>(); - - private final List> functionalDependencies = new ArrayList<>(); - - private final List> clauses = new ArrayList<>(); - - DnfBuilder(String name) { - this.name = name; - } - - public DnfBuilder parameter(Variable variable) { - parameters.add(variable); - return this; - } - - public DnfBuilder parameters(Variable... variables) { - return parameters(List.of(variables)); - } - - public DnfBuilder parameters(Collection variables) { - parameters.addAll(variables); - return this; - } - - public DnfBuilder functionalDependencies(Collection> functionalDependencies) { - this.functionalDependencies.addAll(functionalDependencies); - return this; - } - - public DnfBuilder functionalDependency(FunctionalDependency functionalDependency) { - functionalDependencies.add(functionalDependency); - return this; - } - - public DnfBuilder functionalDependency(Set forEach, Set unique) { - return functionalDependency(new FunctionalDependency<>(forEach, unique)); - } - - public DnfBuilder clause(Literal... literals) { - clause(List.of(literals)); - return this; - } - - public DnfBuilder clause(Collection literals) { - // Remove duplicates by using a hashed data structure. - var filteredLiterals = new LinkedHashSet(literals.size()); - for (var literal : literals) { - var reduction = literal.getReduction(); - switch (reduction) { - case NOT_REDUCIBLE -> filteredLiterals.add(literal); - case ALWAYS_TRUE -> { - // Literals reducible to {@code true} can be omitted, because the model is always assumed to have at - // least on object. - } - case ALWAYS_FALSE -> { - // Clauses with {@code false} literals can be omitted entirely. - return this; - } - default -> throw new IllegalArgumentException("Invalid reduction: " + reduction); - } - } - clauses.add(List.copyOf(filteredLiterals)); - return this; - } - - public DnfBuilder clause(DnfClause clause) { - return clause(clause.literals()); - } - - public DnfBuilder clauses(DnfClause... clauses) { - return clauses(List.of(clauses)); - } - - public DnfBuilder clauses(Collection clauses) { - for (var clause : clauses) { - this.clause(clause); - } - return this; - } - - public Dnf build() { - var postProcessedClauses = postProcessClauses(); - return new Dnf(name, Collections.unmodifiableList(parameters), - Collections.unmodifiableList(functionalDependencies), - Collections.unmodifiableList(postProcessedClauses)); - } - - private List postProcessClauses() { - var postProcessedClauses = new ArrayList(clauses.size()); - for (var literals : clauses) { - if (literals.isEmpty()) { - // Predicate will always match, the other clauses are irrelevant. - return List.of(new DnfClause(Set.of(), List.of())); - } - var variables = new HashSet(); - for (var constraint : literals) { - constraint.collectAllVariables(variables); - } - parameters.forEach(variables::remove); - postProcessedClauses.add(new DnfClause(Collections.unmodifiableSet(variables), - Collections.unmodifiableList(literals))); - } - return postProcessedClauses; - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfClause.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfClause.java deleted file mode 100644 index c6e8b8c9..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfClause.java +++ /dev/null @@ -1,22 +0,0 @@ -package tools.refinery.store.query; - -import tools.refinery.store.query.equality.LiteralEqualityHelper; -import tools.refinery.store.query.literal.Literal; - -import java.util.List; -import java.util.Set; - -public record DnfClause(Set quantifiedVariables, List literals) { - public boolean equalsWithSubstitution(LiteralEqualityHelper helper, DnfClause other) { - int size = literals.size(); - if (size != other.literals.size()) { - return false; - } - for (int i = 0; i < size; i++) { - if (!literals.get(i).equalsWithSubstitution(helper, other.literals.get(i))) { - return false; - } - } - return true; - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfUtils.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/DnfUtils.java deleted file mode 100644 index c7a2849c..00000000 --- a/subprojects/store-query/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-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java index 9ff6df26..9af73bdd 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java @@ -2,21 +2,33 @@ package tools.refinery.store.query; import tools.refinery.store.map.Cursor; import tools.refinery.store.map.Cursors; +import tools.refinery.store.query.dnf.Query; import tools.refinery.store.tuple.TupleLike; -public class EmptyResultSet implements ResultSet { +public record EmptyResultSet(ModelQueryAdapter adapter, Query query) implements ResultSet { @Override - public boolean hasResult(TupleLike parameters) { - return false; + public ModelQueryAdapter getAdapter() { + return adapter; } @Override - public Cursor allResults() { + public Query getQuery() { + return query; + } + + @Override + public T get(TupleLike parameters) { + return query.defaultValue(); + } + + + @Override + public Cursor getAll() { return Cursors.empty(); } @Override - public int countResults() { + public int size() { return 0; } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/FunctionalDependency.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/FunctionalDependency.java deleted file mode 100644 index 63a81713..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/FunctionalDependency.java +++ /dev/null @@ -1,15 +0,0 @@ -package tools.refinery.store.query; - -import java.util.HashSet; -import java.util.Set; - -public record FunctionalDependency(Set forEach, Set unique) { - public FunctionalDependency { - var uniqueForEach = new HashSet<>(unique); - uniqueForEach.retainAll(forEach); - if (!uniqueForEach.isEmpty()) { - throw new IllegalArgumentException("Variables %s appear on both sides of the functional dependency" - .formatted(uniqueForEach)); - } - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java index f7762444..2e30fec4 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java @@ -1,11 +1,17 @@ package tools.refinery.store.query; import tools.refinery.store.adapter.ModelAdapter; +import tools.refinery.store.query.dnf.AnyQuery; +import tools.refinery.store.query.dnf.Query; public interface ModelQueryAdapter extends ModelAdapter { ModelQueryStoreAdapter getStoreAdapter(); - ResultSet getResultSet(Dnf query); + default AnyResultSet getResultSet(AnyQuery query) { + return getResultSet((Query) query); + } + + ResultSet getResultSet(Query query); boolean hasPendingChanges(); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java index b3cfb4b4..4fdc9210 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java @@ -2,21 +2,23 @@ package tools.refinery.store.query; import tools.refinery.store.adapter.ModelAdapterBuilder; import tools.refinery.store.model.ModelStore; +import tools.refinery.store.query.dnf.AnyQuery; import java.util.Collection; import java.util.List; +@SuppressWarnings("UnusedReturnValue") public interface ModelQueryBuilder extends ModelAdapterBuilder { - default ModelQueryBuilder queries(Dnf... queries) { + default ModelQueryBuilder queries(AnyQuery... 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(AnyQuery query); @Override ModelQueryStoreAdapter createStoreAdapter(ModelStore store); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java index 091d6d06..514e582b 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java @@ -1,15 +1,16 @@ package tools.refinery.store.query; -import tools.refinery.store.query.view.AnyRelationView; import tools.refinery.store.adapter.ModelStoreAdapter; import tools.refinery.store.model.Model; +import tools.refinery.store.query.dnf.AnyQuery; +import tools.refinery.store.query.view.AnyRelationView; 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-query/src/main/java/tools/refinery/store/query/RelationLike.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/RelationLike.java deleted file mode 100644 index 8c784d8b..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/RelationLike.java +++ /dev/null @@ -1,11 +0,0 @@ -package tools.refinery.store.query; - -public interface RelationLike { - String name(); - - int arity(); - - default boolean invalidIndex(int i) { - return i < 0 || i >= arity(); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java index d2b8c9dd..3f6bc06f 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java @@ -1,16 +1,13 @@ package tools.refinery.store.query; import tools.refinery.store.map.Cursor; +import tools.refinery.store.query.dnf.Query; import tools.refinery.store.tuple.TupleLike; -public interface ResultSet { - default boolean hasResult() { - return countResults() > 0; - } +public non-sealed interface ResultSet extends AnyResultSet { + Query getQuery(); - boolean hasResult(TupleLike parameters); + T get(TupleLike parameters); - Cursor allResults(); - - int countResults(); + Cursor getAll(); } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/Variable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/Variable.java deleted file mode 100644 index d0e0dead..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/Variable.java +++ /dev/null @@ -1,63 +0,0 @@ -package tools.refinery.store.query; - -import tools.refinery.store.query.literal.ConstantLiteral; -import tools.refinery.store.query.literal.EquivalenceLiteral; - -import java.util.Objects; - -public class Variable { - private final String name; - private final String uniqueName; - - public Variable() { - this(null); - } - - public Variable(String name) { - super(); - this.name = name; - this.uniqueName = DnfUtils.generateUniqueName(name); - - } - public String getName() { - return name == null ? uniqueName : name; - } - - public boolean isExplicitlyNamed() { - return name != null; - } - - public String getUniqueName() { - return uniqueName; - } - - public ConstantLiteral isConstant(int value) { - return new ConstantLiteral(this, value); - } - - public EquivalenceLiteral isEquivalent(Variable other) { - return new EquivalenceLiteral(true, this, other); - } - - public EquivalenceLiteral notEquivalent(Variable other) { - return new EquivalenceLiteral(false, this, other); - } - - @Override - public String toString() { - return getName(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Variable variable = (Variable) o; - return Objects.equals(uniqueName, variable.uniqueName); - } - - @Override - public int hashCode() { - return Objects.hash(uniqueName); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AnyQuery.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AnyQuery.java new file mode 100644 index 00000000..d0a2367f --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AnyQuery.java @@ -0,0 +1,11 @@ +package tools.refinery.store.query.dnf; + +public sealed interface AnyQuery permits Query { + String name(); + + int arity(); + + Class valueType(); + + Dnf getDnf(); +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java new file mode 100644 index 00000000..1b7759c7 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java @@ -0,0 +1,194 @@ +package tools.refinery.store.query.dnf; + +import tools.refinery.store.query.equality.DnfEqualityChecker; +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.Constraint; +import tools.refinery.store.query.literal.LiteralReduction; +import tools.refinery.store.query.term.Sort; +import tools.refinery.store.query.term.Variable; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public final class Dnf implements Constraint { + private static final String INDENTATION = " "; + + private final String name; + + private final String uniqueName; + + private final List parameters; + + private final List> functionalDependencies; + + private final List clauses; + + 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 == null ? uniqueName : name; + } + + public boolean isExplicitlyNamed() { + return name == null; + } + + public String getUniqueName() { + return uniqueName; + } + + public List getParameters() { + return parameters; + } + + @Override + public List getSorts() { + return parameters.stream().map(Variable::getSort).toList(); + } + + public List> getFunctionalDependencies() { + return functionalDependencies; + } + + @Override + public int arity() { + return parameters.size(); + } + + public List getClauses() { + return clauses; + } + + public RelationalQuery asRelation() { + return new RelationalQuery(this); + } + + public FunctionalQuery asFunction(Class type) { + return new FunctionalQuery<>(this, type); + } + + @Override + public LiteralReduction getReduction() { + if (clauses.isEmpty()) { + return LiteralReduction.ALWAYS_FALSE; + } + for (var clause : clauses) { + if (clause.literals().isEmpty()) { + return LiteralReduction.ALWAYS_TRUE; + } + } + return LiteralReduction.NOT_REDUCIBLE; + } + + public boolean equalsWithSubstitution(DnfEqualityChecker callEqualityChecker, Dnf other) { + if (arity() != other.arity()) { + return false; + } + int numClauses = clauses.size(); + if (numClauses != other.clauses.size()) { + return false; + } + for (int i = 0; i < numClauses; i++) { + var literalEqualityHelper = new LiteralEqualityHelper(callEqualityChecker, parameters, other.parameters); + if (!clauses.get(i).equalsWithSubstitution(literalEqualityHelper, other.clauses.get(i))) { + return false; + } + } + return true; + } + + @Override + public boolean equals(LiteralEqualityHelper helper, Constraint other) { + if (other instanceof Dnf otherDnf) { + return helper.dnfEqual(this, otherDnf); + } + return false; + } + + @Override + public String toString() { + return "%s/%d".formatted(name, arity()); + } + + @Override + public String toReferenceString() { + return "@Dnf " + name; + } + + public String toDefinitionString() { + var builder = new StringBuilder(); + builder.append("pred ").append(name()).append("("); + var parameterIterator = parameters.iterator(); + if (parameterIterator.hasNext()) { + builder.append(parameterIterator.next()); + while (parameterIterator.hasNext()) { + builder.append(", ").append(parameterIterator.next()); + } + } + builder.append(") <->"); + var clauseIterator = clauses.iterator(); + if (clauseIterator.hasNext()) { + appendClause(clauseIterator.next(), builder); + while (clauseIterator.hasNext()) { + builder.append("\n;"); + appendClause(clauseIterator.next(), builder); + } + } else { + builder.append("\n").append(INDENTATION).append(""); + } + builder.append(".\n"); + return builder.toString(); + } + + private static void appendClause(DnfClause clause, StringBuilder builder) { + var iterator = clause.literals().iterator(); + if (!iterator.hasNext()) { + builder.append("\n").append(INDENTATION).append(""); + return; + } + builder.append("\n").append(INDENTATION).append(iterator.next()); + while (iterator.hasNext()) { + builder.append(",\n").append(INDENTATION).append(iterator.next()); + } + } + + public static DnfBuilder builder() { + return builder(null); + } + + public static DnfBuilder builder(String name) { + return new DnfBuilder(name); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java new file mode 100644 index 00000000..aad5a85f --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java @@ -0,0 +1,110 @@ +package tools.refinery.store.query.dnf; + +import tools.refinery.store.query.literal.Literal; +import tools.refinery.store.query.term.DataVariable; +import tools.refinery.store.query.term.Variable; + +import java.util.*; + +@SuppressWarnings("UnusedReturnValue") +public final class DnfBuilder { + private final String name; + + private final List parameters = new ArrayList<>(); + + private final List> functionalDependencies = new ArrayList<>(); + + private final List> clauses = new ArrayList<>(); + + DnfBuilder(String name) { + this.name = name; + } + + public DnfBuilder parameter(Variable variable) { + if (parameters.contains(variable)) { + throw new IllegalArgumentException("Duplicate parameter: " + variable); + } + parameters.add(variable); + return this; + } + + public DnfBuilder parameters(Variable... variables) { + return parameters(List.of(variables)); + } + + public DnfBuilder parameters(Collection variables) { + parameters.addAll(variables); + return this; + } + + public DnfBuilder functionalDependencies(Collection> functionalDependencies) { + this.functionalDependencies.addAll(functionalDependencies); + return this; + } + + public DnfBuilder functionalDependency(FunctionalDependency functionalDependency) { + functionalDependencies.add(functionalDependency); + return this; + } + + public DnfBuilder functionalDependency(Set forEach, Set unique) { + return functionalDependency(new FunctionalDependency<>(Set.copyOf(forEach), Set.copyOf(unique))); + } + + public DnfBuilder clause(Literal... literals) { + clause(List.of(literals)); + return this; + } + + public DnfBuilder clause(Collection literals) { + // Remove duplicates by using a hashed data structure. + var filteredLiterals = new LinkedHashSet(literals.size()); + for (var literal : literals) { + var reduction = literal.getReduction(); + switch (reduction) { + case NOT_REDUCIBLE -> filteredLiterals.add(literal); + case ALWAYS_TRUE -> { + // Literals reducible to {@code true} can be omitted, because the model is always assumed to have at + // least on object. + } + case ALWAYS_FALSE -> { + // Clauses with {@code false} literals can be omitted entirely. + return this; + } + default -> throw new IllegalArgumentException("Invalid reduction: " + reduction); + } + } + clauses.add(List.copyOf(filteredLiterals)); + return this; + } + + public Dnf build() { + var postProcessedClauses = postProcessClauses(); + return new Dnf(name, Collections.unmodifiableList(parameters), + Collections.unmodifiableList(functionalDependencies), + Collections.unmodifiableList(postProcessedClauses)); + } + + void output(DataVariable outputVariable) { + functionalDependency(Set.copyOf(parameters), Set.of(outputVariable)); + parameter(outputVariable); + } + + private List postProcessClauses() { + var postProcessedClauses = new ArrayList(clauses.size()); + for (var literals : clauses) { + if (literals.isEmpty()) { + // Predicate will always match, the other clauses are irrelevant. + return List.of(new DnfClause(Set.of(), List.of())); + } + var variables = new HashSet(); + for (var literal : literals) { + variables.addAll(literal.getBoundVariables()); + } + parameters.forEach(variables::remove); + postProcessedClauses.add(new DnfClause(Collections.unmodifiableSet(variables), + Collections.unmodifiableList(literals))); + } + return postProcessedClauses; + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java new file mode 100644 index 00000000..01830af1 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java @@ -0,0 +1,23 @@ +package tools.refinery.store.query.dnf; + +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.literal.Literal; +import tools.refinery.store.query.term.Variable; + +import java.util.List; +import java.util.Set; + +public record DnfClause(Set boundVariables, List literals) { + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, DnfClause other) { + int size = literals.size(); + if (size != other.literals.size()) { + return false; + } + for (int i = 0; i < size; i++) { + if (!literals.get(i).equalsWithSubstitution(helper, other.literals.get(i))) { + return false; + } + } + return true; + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfUtils.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfUtils.java new file mode 100644 index 00000000..9bcf944c --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfUtils.java @@ -0,0 +1,19 @@ +package tools.refinery.store.query.dnf; + +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-query/src/main/java/tools/refinery/store/query/dnf/FunctionalDependency.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalDependency.java new file mode 100644 index 00000000..f4cd109f --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalDependency.java @@ -0,0 +1,15 @@ +package tools.refinery.store.query.dnf; + +import java.util.HashSet; +import java.util.Set; + +public record FunctionalDependency(Set forEach, Set unique) { + public FunctionalDependency { + var uniqueForEach = new HashSet<>(unique); + uniqueForEach.retainAll(forEach); + if (!uniqueForEach.isEmpty()) { + throw new IllegalArgumentException("Variables %s appear on both sides of the functional dependency" + .formatted(uniqueForEach)); + } + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java new file mode 100644 index 00000000..5bf6f8c5 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java @@ -0,0 +1,103 @@ +package tools.refinery.store.query.dnf; + +import tools.refinery.store.query.literal.CallPolarity; +import tools.refinery.store.query.term.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public final class FunctionalQuery implements Query { + private final Dnf dnf; + private final Class type; + + FunctionalQuery(Dnf dnf, Class type) { + var parameters = dnf.getParameters(); + int outputIndex = dnf.arity() - 1; + for (int i = 0; i < outputIndex; i++) { + var parameter = parameters.get(i); + if (!(parameter instanceof NodeVariable)) { + throw new IllegalArgumentException("Expected parameter %s of %s to be of sort %s, but got %s instead" + .formatted(parameter, dnf, NodeSort.INSTANCE, parameter.getSort())); + } + } + var outputParameter = parameters.get(outputIndex); + if (!(outputParameter instanceof DataVariable dataOutputParameter) || + !dataOutputParameter.getType().equals(type)) { + throw new IllegalArgumentException("Expected parameter %s of %s to be of sort %s, but got %s instead" + .formatted(outputParameter, dnf, type, outputParameter.getSort())); + } + this.dnf = dnf; + this.type = type; + } + + @Override + public String name() { + return dnf.name(); + } + + @Override + public int arity() { + return dnf.arity() - 1; + } + + @Override + public Class valueType() { + return type; + } + + @Override + public T defaultValue() { + return null; + } + + @Override + public Dnf getDnf() { + return dnf; + } + + public AssignedValue call(List arguments) { + return targetVariable -> { + var argumentsWithTarget = new ArrayList(arguments.size() + 1); + argumentsWithTarget.addAll(arguments); + argumentsWithTarget.add(targetVariable); + return dnf.call(CallPolarity.POSITIVE, argumentsWithTarget); + }; + } + + public AssignedValue call(NodeVariable... arguments) { + return call(List.of(arguments)); + } + + public AssignedValue aggregate(Aggregator aggregator, List arguments) { + return targetVariable -> { + var placeholderVariable = Variable.of(type); + var argumentsWithPlaceholder = new ArrayList(arguments.size() + 1); + argumentsWithPlaceholder.addAll(arguments); + argumentsWithPlaceholder.add(placeholderVariable); + return dnf.aggregate(placeholderVariable, aggregator, argumentsWithPlaceholder).toLiteral(targetVariable); + }; + } + + public AssignedValue aggregate(Aggregator aggregator, NodeVariable... arguments) { + return aggregate(aggregator, List.of(arguments)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + FunctionalQuery that = (FunctionalQuery) o; + return dnf.equals(that.dnf) && type.equals(that.type); + } + + @Override + public int hashCode() { + return Objects.hash(dnf, type); + } + + @Override + public String toString() { + return dnf.toString(); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQueryBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQueryBuilder.java new file mode 100644 index 00000000..ca2bc006 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQueryBuilder.java @@ -0,0 +1,46 @@ +package tools.refinery.store.query.dnf; + +import tools.refinery.store.query.literal.Literal; +import tools.refinery.store.query.term.Variable; + +import java.util.Collection; +import java.util.Set; + +public final class FunctionalQueryBuilder { + private final DnfBuilder dnfBuilder; + private final Class type; + + FunctionalQueryBuilder(DnfBuilder dnfBuilder, Class type) { + this.dnfBuilder = dnfBuilder; + this.type = type; + } + + public FunctionalQueryBuilder functionalDependencies(Collection> functionalDependencies) { + dnfBuilder.functionalDependencies(functionalDependencies); + return this; + } + + public FunctionalQueryBuilder functionalDependency(FunctionalDependency functionalDependency) { + dnfBuilder.functionalDependency(functionalDependency); + return this; + } + + public FunctionalQueryBuilder functionalDependency(Set forEach, Set unique) { + dnfBuilder.functionalDependency(forEach, unique); + return this; + } + + public FunctionalQueryBuilder clause(Literal... literals) { + dnfBuilder.clause(literals); + return this; + } + + public FunctionalQueryBuilder clause(Collection literals) { + dnfBuilder.clause(literals); + return this; + } + + public FunctionalQuery build() { + return dnfBuilder.build().asFunction(type); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java new file mode 100644 index 00000000..32e33052 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java @@ -0,0 +1,16 @@ +package tools.refinery.store.query.dnf; + +public sealed interface Query extends AnyQuery permits RelationalQuery, FunctionalQuery { + @Override + Class valueType(); + + T defaultValue(); + + static QueryBuilder builder() { + return new QueryBuilder(); + } + + static QueryBuilder builder(String name) { + return new QueryBuilder(name); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/QueryBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/QueryBuilder.java new file mode 100644 index 00000000..ed253cc9 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/QueryBuilder.java @@ -0,0 +1,71 @@ +package tools.refinery.store.query.dnf; + +import tools.refinery.store.query.literal.Literal; +import tools.refinery.store.query.term.DataVariable; +import tools.refinery.store.query.term.NodeVariable; +import tools.refinery.store.query.term.Variable; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +public final class QueryBuilder { + private final DnfBuilder dnfBuilder; + + QueryBuilder(String name) { + dnfBuilder = Dnf.builder(name); + } + + QueryBuilder() { + dnfBuilder = Dnf.builder(); + } + + public QueryBuilder parameter(NodeVariable variable) { + dnfBuilder.parameter(variable); + return this; + } + + public QueryBuilder parameters(NodeVariable... variables) { + dnfBuilder.parameters(variables); + return this; + } + + public QueryBuilder parameters(List variables) { + dnfBuilder.parameters(variables); + return this; + } + + public FunctionalQueryBuilder output(DataVariable outputVariable) { + dnfBuilder.output(outputVariable); + return new FunctionalQueryBuilder<>(dnfBuilder, outputVariable.getType()); + } + + public QueryBuilder functionalDependencies(Collection> functionalDependencies) { + dnfBuilder.functionalDependencies(functionalDependencies); + return this; + } + + public QueryBuilder functionalDependency(FunctionalDependency functionalDependency) { + dnfBuilder.functionalDependency(functionalDependency); + return this; + } + + public QueryBuilder functionalDependency(Set forEach, Set unique) { + dnfBuilder.functionalDependency(forEach, unique); + return this; + } + + public QueryBuilder clause(Literal... literals) { + dnfBuilder.clause(literals); + return this; + } + + public QueryBuilder clause(Collection literals) { + dnfBuilder.clause(literals); + return this; + } + + public RelationalQuery build() { + return dnfBuilder.build().asRelation(); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java new file mode 100644 index 00000000..5307e509 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java @@ -0,0 +1,93 @@ +package tools.refinery.store.query.dnf; + +import tools.refinery.store.query.literal.CallLiteral; +import tools.refinery.store.query.literal.CallPolarity; +import tools.refinery.store.query.term.AssignedValue; +import tools.refinery.store.query.term.NodeSort; +import tools.refinery.store.query.term.NodeVariable; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +public final class RelationalQuery implements Query { + private final Dnf dnf; + + RelationalQuery(Dnf dnf) { + for (var parameter : dnf.getParameters()) { + if (!(parameter instanceof NodeVariable)) { + throw new IllegalArgumentException("Expected parameter %s of %s to be of sort %s, but got %s instead" + .formatted(parameter, dnf, NodeSort.INSTANCE, parameter.getSort())); + } + } + this.dnf = dnf; + } + + @Override + public String name() { + return dnf.name(); + } + + @Override + public int arity() { + return dnf.arity(); + } + + @Override + public Class valueType() { + return Boolean.class; + } + + @Override + public Boolean defaultValue() { + return false; + } + + @Override + public Dnf getDnf() { + return dnf; + } + + public CallLiteral call(CallPolarity polarity, List arguments) { + return dnf.call(polarity, Collections.unmodifiableList(arguments)); + } + + public CallLiteral call(CallPolarity polarity, NodeVariable... arguments) { + return dnf.call(polarity, arguments); + } + + public CallLiteral call(NodeVariable... arguments) { + return dnf.call(arguments); + } + + public CallLiteral callTransitive(NodeVariable left, NodeVariable right) { + return dnf.callTransitive(left, right); + } + + public AssignedValue count(List arguments) { + return dnf.count(Collections.unmodifiableList(arguments)); + } + + public AssignedValue count(NodeVariable... arguments) { + return dnf.count(arguments); + } + + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + RelationalQuery that = (RelationalQuery) o; + return dnf.equals(that.dnf); + } + + @Override + public int hashCode() { + return Objects.hash(dnf); + } + + @Override + public String toString() { + return dnf.toString(); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java index ebd7f5b0..c3bc3ea3 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java @@ -1,6 +1,6 @@ package tools.refinery.store.query.equality; -import tools.refinery.store.query.Dnf; +import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.util.CycleDetectingMapper; import java.util.List; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java index eb77de17..6b1f2076 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java @@ -1,6 +1,6 @@ package tools.refinery.store.query.equality; -import tools.refinery.store.query.Dnf; +import tools.refinery.store.query.dnf.Dnf; @FunctionalInterface public interface DnfEqualityChecker { diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java index 23f1acc7..07d261ea 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java @@ -1,7 +1,7 @@ package tools.refinery.store.query.equality; -import tools.refinery.store.query.Dnf; -import tools.refinery.store.query.Variable; +import tools.refinery.store.query.dnf.Dnf; +import tools.refinery.store.query.term.Variable; import java.util.HashMap; import java.util.List; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java new file mode 100644 index 00000000..657ca26b --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java @@ -0,0 +1,80 @@ +package tools.refinery.store.query.literal; + +import tools.refinery.store.query.Constraint; +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Variable; + +import java.util.List; +import java.util.Objects; + +public abstract class AbstractCallLiteral implements Literal { + private final Constraint target; + private final List arguments; + + protected AbstractCallLiteral(Constraint target, List arguments) { + int arity = target.arity(); + if (arguments.size() != arity) { + throw new IllegalArgumentException("%s needs %d arguments, but got %s".formatted(target.name(), + target.arity(), arguments.size())); + } + this.target = target; + this.arguments = arguments; + var sorts = target.getSorts(); + for (int i = 0; i < arity; i++) { + var argument = arguments.get(i); + var sort = sorts.get(i); + if (!sort.isInstance(argument)) { + throw new IllegalArgumentException("Required argument %d of %s to be of sort %s, but got %s instead" + .formatted(i, target, sort, argument.getSort())); + } + } + } + + public Constraint getTarget() { + return target; + } + + public List getArguments() { + return arguments; + } + + @Override + public Literal substitute(Substitution substitution) { + var substitutedArguments = arguments.stream().map(substitution::getSubstitute).toList(); + return doSubstitute(substitution, substitutedArguments); + } + + protected abstract Literal doSubstitute(Substitution substitution, List substitutedArguments); + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) { + if (other == null || getClass() != other.getClass()) { + return false; + } + var otherCallLiteral = (AbstractCallLiteral) other; + var arity = arguments.size(); + if (arity != otherCallLiteral.arguments.size()) { + return false; + } + for (int i = 0; i < arity; i++) { + if (!helper.variableEqual(arguments.get(i), otherCallLiteral.arguments.get(i))) { + return false; + } + } + return target.equals(helper, otherCallLiteral.target); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AbstractCallLiteral that = (AbstractCallLiteral) o; + return target.equals(that.target) && arguments.equals(that.arguments); + } + + @Override + public int hashCode() { + return Objects.hash(target, arguments); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java new file mode 100644 index 00000000..df64839c --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java @@ -0,0 +1,113 @@ +package tools.refinery.store.query.literal; + +import tools.refinery.store.query.Constraint; +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Aggregator; +import tools.refinery.store.query.term.DataVariable; +import tools.refinery.store.query.term.Variable; + +import java.util.List; +import java.util.Objects; +import java.util.Set; + +public class AggregationLiteral extends AbstractCallLiteral { + private final DataVariable resultVariable; + private final DataVariable inputVariable; + private final Aggregator aggregator; + + public AggregationLiteral(DataVariable resultVariable, Aggregator aggregator, + DataVariable inputVariable, Constraint target, List arguments) { + super(target, arguments); + if (!inputVariable.getType().equals(aggregator.getInputType())) { + throw new IllegalArgumentException("Input variable %s must of type %s, got %s instead".formatted( + inputVariable, aggregator.getInputType().getName(), inputVariable.getType().getName())); + } + if (!resultVariable.getType().equals(aggregator.getResultType())) { + throw new IllegalArgumentException("Result variable %s must of type %s, got %s instead".formatted( + resultVariable, aggregator.getResultType().getName(), resultVariable.getType().getName())); + } + if (!arguments.contains(inputVariable)) { + throw new IllegalArgumentException("Input variable %s must appear in the argument list".formatted( + inputVariable)); + } + if (arguments.contains(resultVariable)) { + throw new IllegalArgumentException("Result variable %s must not appear in the argument list".formatted( + resultVariable)); + } + this.resultVariable = resultVariable; + this.inputVariable = inputVariable; + this.aggregator = aggregator; + } + + public DataVariable getResultVariable() { + return resultVariable; + } + + public DataVariable getInputVariable() { + return inputVariable; + } + + public Aggregator getAggregator() { + return aggregator; + } + + @Override + public Set getBoundVariables() { + return Set.of(resultVariable); + } + + @Override + protected Literal doSubstitute(Substitution substitution, List substitutedArguments) { + return new AggregationLiteral<>(substitution.getTypeSafeSubstitute(resultVariable), aggregator, + substitution.getTypeSafeSubstitute(inputVariable), getTarget(), substitutedArguments); + } + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) { + if (!super.equalsWithSubstitution(helper, other)) { + return false; + } + var otherAggregationLiteral = (AggregationLiteral) other; + return helper.variableEqual(resultVariable, otherAggregationLiteral.resultVariable) && + aggregator.equals(otherAggregationLiteral.aggregator) && + helper.variableEqual(inputVariable, otherAggregationLiteral.inputVariable); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + AggregationLiteral that = (AggregationLiteral) o; + return resultVariable.equals(that.resultVariable) && inputVariable.equals(that.inputVariable) && + aggregator.equals(that.aggregator); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), resultVariable, inputVariable, aggregator); + } + + @Override + public String toString() { + var builder = new StringBuilder(); + builder.append(resultVariable); + builder.append(" is "); + builder.append(getTarget().toReferenceString()); + builder.append("("); + var argumentIterator = getArguments().iterator(); + if (argumentIterator.hasNext()) { + var argument = argumentIterator.next(); + if (inputVariable.equals(argument)) { + builder.append("@Aggregate(\"").append(aggregator).append("\") "); + } + builder.append(argument); + while (argumentIterator.hasNext()) { + builder.append(", ").append(argumentIterator.next()); + } + } + builder.append(")"); + return builder.toString(); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java new file mode 100644 index 00000000..52ac42d7 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java @@ -0,0 +1,44 @@ +package tools.refinery.store.query.literal; + +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.DataVariable; +import tools.refinery.store.query.term.Term; +import tools.refinery.store.query.term.Variable; + +import java.util.Set; + +public record AssignLiteral(DataVariable variable, Term term) implements Literal { + public AssignLiteral { + if (!term.getType().equals(variable.getType())) { + throw new IllegalArgumentException("Term %s must be of type %s, got %s instead".formatted( + term, variable.getType().getName(), term.getType().getName())); + } + } + + @Override + public Set getBoundVariables() { + return Set.of(variable); + } + + @Override + public Literal substitute(Substitution substitution) { + return new AssignLiteral<>(substitution.getTypeSafeSubstitute(variable), term.substitute(substitution)); + } + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) { + if (other == null || getClass() != other.getClass()) { + return false; + } + var otherLetLiteral = (AssignLiteral) other; + return helper.variableEqual(variable, otherLetLiteral.variable) && term.equalsWithSubstitution(helper, + otherLetLiteral.term); + } + + + @Override + public String toString() { + return "%s is (%s)".formatted(variable, term); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java new file mode 100644 index 00000000..0b4267b4 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java @@ -0,0 +1,53 @@ +package tools.refinery.store.query.literal; + +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; +import tools.refinery.store.query.term.Variable; +import tools.refinery.store.query.term.bool.BoolConstantTerm; + +import java.util.Set; + +public record AssumeLiteral(Term term) implements Literal { + public AssumeLiteral { + if (!term.getType().equals(Boolean.class)) { + throw new IllegalArgumentException("Term %s must be of type %s, got %s instead".formatted( + term, Boolean.class.getName(), term.getType().getName())); + } + } + + @Override + public Set getBoundVariables() { + return Set.of(); + } + + @Override + public Literal substitute(Substitution substitution) { + return new AssumeLiteral(term.substitute(substitution)); + } + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) { + if (other == null || getClass() != other.getClass()) { + return false; + } + var otherAssumeLiteral = (AssumeLiteral) other; + return term.equalsWithSubstitution(helper, otherAssumeLiteral.term); + } + + @Override + public LiteralReduction getReduction() { + if (BoolConstantTerm.TRUE.equals(term)) { + return LiteralReduction.ALWAYS_TRUE; + } else if (BoolConstantTerm.FALSE.equals(term)) { + return LiteralReduction.ALWAYS_FALSE; + } else { + return LiteralReduction.NOT_REDUCIBLE; + } + } + + @Override + public String toString() { + return "(%s)".formatted(term); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java index 6d751be8..38be61a4 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java @@ -1,12 +1,12 @@ package tools.refinery.store.query.literal; -import tools.refinery.store.query.Variable; +import tools.refinery.store.query.term.Variable; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; import java.util.Set; -public enum BooleanLiteral implements PolarLiteral { +public enum BooleanLiteral implements CanNegate { TRUE(true), FALSE(false); @@ -17,8 +17,8 @@ public enum BooleanLiteral implements PolarLiteral { } @Override - public void collectAllVariables(Set variables) { - // No variables to collect. + public Set getBoundVariables() { + return Set.of(); } @Override diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java index 091b4e04..78fae7f5 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java @@ -1,109 +1,78 @@ package tools.refinery.store.query.literal; -import tools.refinery.store.query.RelationLike; -import tools.refinery.store.query.Variable; +import tools.refinery.store.query.Constraint; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.NodeSort; +import tools.refinery.store.query.term.Variable; import java.util.List; import java.util.Objects; import java.util.Set; -public abstract class CallLiteral implements Literal { +public final class CallLiteral extends AbstractCallLiteral implements CanNegate { private final CallPolarity polarity; - private final T target; - private final List arguments; - protected CallLiteral(CallPolarity polarity, T target, List arguments) { - if (arguments.size() != target.arity()) { - throw new IllegalArgumentException("%s needs %d arguments, but got %s".formatted(target.name(), - target.arity(), arguments.size())); - } - if (polarity.isTransitive() && target.arity() != 2) { - throw new IllegalArgumentException("Transitive closures can only take binary relations"); + public CallLiteral(CallPolarity polarity, Constraint target, List arguments) { + super(target, arguments); + if (polarity.isTransitive()) { + if (target.arity() != 2) { + throw new IllegalArgumentException("Transitive closures can only take binary relations"); + } + var sorts = target.getSorts(); + if (!sorts.get(0).equals(NodeSort.INSTANCE) || !sorts.get(1).equals(NodeSort.INSTANCE)) { + throw new IllegalArgumentException("Transitive closures can only be computed over nodes"); + } } this.polarity = polarity; - this.target = target; - this.arguments = arguments; } public CallPolarity getPolarity() { return polarity; } - public abstract Class getTargetType(); - - public T getTarget() { - return target; - } - - public List getArguments() { - return arguments; - } - @Override - public void collectAllVariables(Set variables) { - if (polarity.isPositive()) { - variables.addAll(arguments); - } + public Set getBoundVariables() { + return polarity.isPositive() ? Set.copyOf(getArguments()) : Set.of(); } - protected List substituteArguments(Substitution substitution) { - return arguments.stream().map(substitution::getSubstitute).toList(); + @Override + protected Literal doSubstitute(Substitution substitution, List substitutedArguments) { + return new CallLiteral(polarity, getTarget(), substitutedArguments); } - /** - * Compares the target of this call literal with another object. - * - * @param helper Equality helper for comparing {@link Variable} and {@link tools.refinery.store.query.Dnf} - * instances. - * @param otherTarget The object to compare the target to. - * @return {@code true} if {@code otherTarget} is equal to the return value of {@link #getTarget()} according to - * {@code helper}, {@code false} otherwise. - */ - protected boolean targetEquals(LiteralEqualityHelper helper, T otherTarget) { - return target.equals(otherTarget); + @Override + public LiteralReduction getReduction() { + var reduction = getTarget().getReduction(); + return polarity.isPositive() ? reduction : reduction.negate(); } @Override public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) { - if (other.getClass() != getClass()) { + if (!super.equalsWithSubstitution(helper, other)) { return false; } - var otherCallLiteral = (CallLiteral) other; - if (getTargetType() != otherCallLiteral.getTargetType() || polarity != otherCallLiteral.polarity) { - return false; - } - var arity = arguments.size(); - if (arity != otherCallLiteral.arguments.size()) { - return false; - } - for (int i = 0; i < arity; i++) { - if (!helper.variableEqual(arguments.get(i), otherCallLiteral.arguments.get(i))) { - return false; - } - } - @SuppressWarnings("unchecked") - var otherTarget = (T) otherCallLiteral.target; - return targetEquals(helper, otherTarget); + var otherCallLiteral = (CallLiteral) other; + return polarity.equals(otherCallLiteral.polarity); + } + + @Override + public CallLiteral negate() { + return new CallLiteral(polarity.negate(), getTarget(), getArguments()); } @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(arguments, callAtom.arguments); + if (!super.equals(o)) return false; + CallLiteral that = (CallLiteral) o; + return polarity == that.polarity; } @Override public int hashCode() { - return Objects.hash(polarity, target, arguments); - } - - protected String targetToString() { - return "@%s %s".formatted(getTargetType().getSimpleName(), target.name()); + return Objects.hash(super.hashCode(), polarity); } @Override @@ -112,12 +81,12 @@ public abstract class CallLiteral implements Literal { if (!polarity.isPositive()) { builder.append("!("); } - builder.append(targetToString()); + builder.append(getTarget().toReferenceString()); if (polarity.isTransitive()) { builder.append("+"); } builder.append("("); - var argumentIterator = arguments.iterator(); + var argumentIterator = getArguments().iterator(); if (argumentIterator.hasNext()) { builder.append(argumentIterator.next()); while (argumentIterator.hasNext()) { diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CanNegate.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CanNegate.java new file mode 100644 index 00000000..3e159c43 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CanNegate.java @@ -0,0 +1,5 @@ +package tools.refinery.store.query.literal; + +public interface CanNegate> extends Literal { + T negate(); +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java index d01c7d20..93fa3df0 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java @@ -1,20 +1,21 @@ package tools.refinery.store.query.literal; -import tools.refinery.store.query.Variable; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.NodeVariable; +import tools.refinery.store.query.term.Variable; import java.util.Set; -public record ConstantLiteral(Variable variable, int nodeId) implements Literal { +public record ConstantLiteral(NodeVariable variable, int nodeId) implements Literal { @Override - public void collectAllVariables(Set variables) { - variables.add(variable); + public Set getBoundVariables() { + return Set.of(variable); } @Override public ConstantLiteral substitute(Substitution substitution) { - return new ConstantLiteral(substitution.getSubstitute(variable), nodeId); + return new ConstantLiteral(substitution.getTypeSafeSubstitute(variable), nodeId); } @Override diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java new file mode 100644 index 00000000..32e7ba3a --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java @@ -0,0 +1,83 @@ +package tools.refinery.store.query.literal; + +import tools.refinery.store.query.Constraint; +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.DataVariable; +import tools.refinery.store.query.term.Variable; + +import java.util.List; +import java.util.Objects; +import java.util.Set; + +public class CountLiteral extends AbstractCallLiteral { + private final DataVariable resultVariable; + + public CountLiteral(DataVariable resultVariable, Constraint target, List arguments) { + super(target, arguments); + if (!resultVariable.getType().equals(Integer.class)) { + throw new IllegalArgumentException("Count result variable %s must be of type %s, got %s instead".formatted( + resultVariable, Integer.class.getName(), resultVariable.getType().getName())); + } + if (arguments.contains(resultVariable)) { + throw new IllegalArgumentException("Count result variable %s must not appear in the argument list" + .formatted(resultVariable)); + } + this.resultVariable = resultVariable; + } + + public DataVariable getResultVariable() { + return resultVariable; + } + + @Override + public Set getBoundVariables() { + return Set.of(resultVariable); + } + + @Override + protected Literal doSubstitute(Substitution substitution, List substitutedArguments) { + return new CountLiteral(substitution.getTypeSafeSubstitute(resultVariable), getTarget(), substitutedArguments); + } + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) { + if (!super.equalsWithSubstitution(helper, other)) { + return false; + } + var otherCountLiteral = (CountLiteral) other; + return helper.variableEqual(resultVariable, otherCountLiteral.resultVariable); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + CountLiteral that = (CountLiteral) o; + return resultVariable.equals(that.resultVariable); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), resultVariable); + } + + @Override + public String toString() { + var builder = new StringBuilder(); + builder.append(resultVariable); + builder.append(" is count "); + builder.append(getTarget().toReferenceString()); + builder.append("("); + var argumentIterator = getArguments().iterator(); + if (argumentIterator.hasNext()) { + builder.append(argumentIterator.next()); + while (argumentIterator.hasNext()) { + builder.append(", ").append(argumentIterator.next()); + } + } + builder.append(")"); + return builder.toString(); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/DnfCallLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/DnfCallLiteral.java deleted file mode 100644 index 27917265..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/DnfCallLiteral.java +++ /dev/null @@ -1,40 +0,0 @@ -package tools.refinery.store.query.literal; - -import tools.refinery.store.query.Dnf; -import tools.refinery.store.query.Variable; -import tools.refinery.store.query.equality.LiteralEqualityHelper; -import tools.refinery.store.query.substitution.Substitution; - -import java.util.List; - -public final class DnfCallLiteral extends CallLiteral implements PolarLiteral { - public DnfCallLiteral(CallPolarity polarity, Dnf target, List arguments) { - super(polarity, target, arguments); - } - - @Override - public Class getTargetType() { - return Dnf.class; - } - - @Override - public DnfCallLiteral substitute(Substitution substitution) { - return new DnfCallLiteral(getPolarity(), getTarget(), substituteArguments(substitution)); - } - - @Override - public DnfCallLiteral negate() { - return new DnfCallLiteral(getPolarity().negate(), getTarget(), getArguments()); - } - - @Override - public LiteralReduction getReduction() { - var dnfReduction = getTarget().getReduction(); - return getPolarity().isPositive() ? dnfReduction : dnfReduction.negate(); - } - - @Override - protected boolean targetEquals(LiteralEqualityHelper helper, Dnf otherTarget) { - return helper.dnfEqual(getTarget(), otherTarget); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java index 61c753c3..4dc86b98 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java @@ -1,17 +1,19 @@ package tools.refinery.store.query.literal; -import tools.refinery.store.query.Variable; +import tools.refinery.store.query.term.NodeVariable; +import tools.refinery.store.query.term.Variable; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; import java.util.Set; -public record EquivalenceLiteral(boolean positive, Variable left, Variable right) - implements PolarLiteral { +public record EquivalenceLiteral(boolean positive, NodeVariable left, NodeVariable right) + implements CanNegate { @Override - public void collectAllVariables(Set variables) { - variables.add(left); - variables.add(right); + public Set getBoundVariables() { + // If one side of a {@code positive} equivalence is bound, it may bind its other side, but we under-approximate + // this behavior by not binding any of the sides by default. + return Set.of(); } @Override @@ -21,7 +23,8 @@ public record EquivalenceLiteral(boolean positive, Variable left, Variable right @Override public EquivalenceLiteral substitute(Substitution substitution) { - return new EquivalenceLiteral(positive, substitution.getSubstitute(left), substitution.getSubstitute(right)); + return new EquivalenceLiteral(positive, substitution.getTypeSafeSubstitute(left), + substitution.getTypeSafeSubstitute(right)); } @Override diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java index ddd91775..6347410e 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java @@ -1,13 +1,13 @@ package tools.refinery.store.query.literal; -import tools.refinery.store.query.Variable; +import tools.refinery.store.query.term.Variable; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; import java.util.Set; public interface Literal { - void collectAllVariables(Set variables); + Set getBoundVariables(); Literal substitute(Substitution substitution); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java index 2c7e893f..89039352 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java @@ -1,11 +1,17 @@ package tools.refinery.store.query.literal; +import tools.refinery.store.query.term.Term; + public final class Literals { private Literals() { throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); } - public static > T not(PolarLiteral literal) { + public static > T not(CanNegate literal) { return literal.negate(); } + + public static AssumeLiteral assume(Term term) { + return new AssumeLiteral(term); + } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/PolarLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/PolarLiteral.java deleted file mode 100644 index 32523675..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/PolarLiteral.java +++ /dev/null @@ -1,5 +0,0 @@ -package tools.refinery.store.query.literal; - -public interface PolarLiteral> extends Literal { - T negate(); -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/RelationViewLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/RelationViewLiteral.java deleted file mode 100644 index fb8b3332..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/RelationViewLiteral.java +++ /dev/null @@ -1,35 +0,0 @@ -package tools.refinery.store.query.literal; - -import tools.refinery.store.query.Variable; -import tools.refinery.store.query.substitution.Substitution; -import tools.refinery.store.query.view.AnyRelationView; - -import java.util.List; - -public final class RelationViewLiteral extends CallLiteral - implements PolarLiteral { - public RelationViewLiteral(CallPolarity polarity, AnyRelationView target, List arguments) { - super(polarity, target, arguments); - } - - @Override - public Class getTargetType() { - return AnyRelationView.class; - } - - @Override - protected String targetToString() { - var target = getTarget(); - return "@RelationView(\"%s\") %s".formatted(target.getViewName(), target.getSymbol().name()); - } - - @Override - public RelationViewLiteral substitute(Substitution substitution) { - return new RelationViewLiteral(getPolarity(), getTarget(), substituteArguments(substitution)); - } - - @Override - public RelationViewLiteral negate() { - return new RelationViewLiteral(getPolarity().negate(), getTarget(), getArguments()); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/CompositeSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/CompositeSubstitution.java new file mode 100644 index 00000000..f8064ca2 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/CompositeSubstitution.java @@ -0,0 +1,10 @@ +package tools.refinery.store.query.substitution; + +import tools.refinery.store.query.term.Variable; + +public record CompositeSubstitution(Substitution first, Substitution second) implements Substitution { + @Override + public Variable getSubstitute(Variable variable) { + return second.getSubstitute(first.getSubstitute(variable)); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java index ffc65047..c7754619 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java @@ -1,6 +1,6 @@ package tools.refinery.store.query.substitution; -import tools.refinery.store.query.Variable; +import tools.refinery.store.query.term.Variable; import java.util.Map; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java index 54d18a3f..7847e582 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java @@ -1,6 +1,6 @@ package tools.refinery.store.query.substitution; -import tools.refinery.store.query.Variable; +import tools.refinery.store.query.term.Variable; import java.util.HashMap; import java.util.Map; @@ -10,10 +10,6 @@ public class RenewingSubstitution implements Substitution { @Override public Variable getSubstitute(Variable variable) { - return alreadyRenewed.computeIfAbsent(variable, RenewingSubstitution::renew); - } - - private static Variable renew(Variable variable) { - return variable.isExplicitlyNamed() ? new Variable(variable.getName()) : new Variable(); + return alreadyRenewed.computeIfAbsent(variable, Variable::renew); } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java index d33ad6fb..eed414d9 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java @@ -1,6 +1,6 @@ package tools.refinery.store.query.substitution; -import tools.refinery.store.query.Variable; +import tools.refinery.store.query.term.Variable; public enum StatelessSubstitution implements Substitution { FAILING { diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java index 9d086bf5..99f84b9e 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java @@ -1,8 +1,29 @@ package tools.refinery.store.query.substitution; -import tools.refinery.store.query.Variable; +import tools.refinery.store.query.term.AnyDataVariable; +import tools.refinery.store.query.term.DataVariable; +import tools.refinery.store.query.term.NodeVariable; +import tools.refinery.store.query.term.Variable; @FunctionalInterface public interface Substitution { Variable getSubstitute(Variable variable); + + default NodeVariable getTypeSafeSubstitute(NodeVariable variable) { + var substitute = getSubstitute(variable); + return substitute.asNodeVariable(); + } + + default AnyDataVariable getTypeSafeSubstitute(AnyDataVariable variable) { + return getTypeSafeSubstitute((DataVariable) variable); + } + + default DataVariable getTypeSafeSubstitute(DataVariable variable) { + var substitute = getSubstitute(variable); + return substitute.asDataVariable(variable.getType()); + } + + default Substitution andThen(Substitution second) { + return new CompositeSubstitution(this, second); + } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java index 26cf1a20..5d4654da 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java @@ -1,6 +1,8 @@ package tools.refinery.store.query.substitution; -import tools.refinery.store.query.Variable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import tools.refinery.store.query.term.Variable; import java.util.Map; @@ -24,4 +26,8 @@ public final class Substitutions { public static Substitution renewing() { return new RenewingSubstitution(); } + + public static Substitution compose(@Nullable Substitution first, @NotNull Substitution second) { + return first == null ? second : first.andThen(second); + } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Aggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Aggregator.java new file mode 100644 index 00000000..47421a94 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Aggregator.java @@ -0,0 +1,13 @@ +package tools.refinery.store.query.term; + +import java.util.stream.Stream; + +public interface Aggregator { + Class getResultType(); + + Class getInputType(); + + R aggregateStream(Stream stream); + + R getEmptyResult(); +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java new file mode 100644 index 00000000..ecfefcf9 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java @@ -0,0 +1,33 @@ +package tools.refinery.store.query.term; + +import org.jetbrains.annotations.Nullable; +import tools.refinery.store.query.equality.LiteralEqualityHelper; + +import java.util.Set; + +public abstract sealed class AnyDataVariable extends Variable implements AnyTerm permits DataVariable { + protected AnyDataVariable(String name) { + super(name); + } + + @Override + public NodeVariable asNodeVariable() { + throw new IllegalStateException("%s is a data variable".formatted(this)); + } + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { + return other instanceof AnyDataVariable dataVariable && helper.variableEqual(this, dataVariable); + } + + @Override + public Set getInputVariables() { + return Set.of(this); + } + + @Override + public abstract AnyDataVariable renew(@Nullable String name); + + @Override + public abstract AnyDataVariable renew(); +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java new file mode 100644 index 00000000..8f998d45 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java @@ -0,0 +1,16 @@ +package tools.refinery.store.query.term; + +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.substitution.Substitution; + +import java.util.Set; + +public sealed interface AnyTerm permits AnyDataVariable, Term { + Class getType(); + + AnyTerm substitute(Substitution substitution); + + boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other); + + Set getInputVariables(); +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryOperator.java new file mode 100644 index 00000000..8706a046 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryOperator.java @@ -0,0 +1,26 @@ +package tools.refinery.store.query.term; + +public enum ArithmeticBinaryOperator { + ADD("+", true), + SUB("-", true), + MUL("*", true), + DIV("/", true), + POW("**", true), + MIN("min", false), + MAX("max", false); + + private final String text; + private final boolean infix; + + ArithmeticBinaryOperator(String text, boolean infix) { + this.text = text; + this.infix = infix; + } + + public String formatString(String left, String right) { + if (infix) { + return "(%s) %s (%s)".formatted(left, text, right); + } + return "%s(%s, %s)".formatted(text, left, right); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryTerm.java new file mode 100644 index 00000000..887a1e6e --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryTerm.java @@ -0,0 +1,56 @@ +package tools.refinery.store.query.term; + +import tools.refinery.store.query.equality.LiteralEqualityHelper; + +import java.util.Objects; + +public abstract class ArithmeticBinaryTerm extends BinaryTerm { + private final ArithmeticBinaryOperator operator; + + protected ArithmeticBinaryTerm(ArithmeticBinaryOperator operator, Term left, Term right) { + super(left, right); + this.operator = operator; + } + + @Override + public Class getLeftType() { + return getType(); + } + + @Override + public Class getRightType() { + return getType(); + } + + public ArithmeticBinaryOperator getOperator() { + return operator; + } + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { + if (!super.equalsWithSubstitution(helper, other)) { + return false; + } + var otherArithmeticBinaryTerm = (ArithmeticBinaryTerm) other; + return operator == otherArithmeticBinaryTerm.operator; + } + + @Override + public String toString() { + return operator.formatString(getLeft().toString(), getRight().toString()); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + ArithmeticBinaryTerm that = (ArithmeticBinaryTerm) o; + return operator == that.operator; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), operator); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryOperator.java new file mode 100644 index 00000000..6a7c25db --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryOperator.java @@ -0,0 +1,16 @@ +package tools.refinery.store.query.term; + +public enum ArithmeticUnaryOperator { + PLUS("+"), + MINUS("-"); + + private final String prefix; + + ArithmeticUnaryOperator(String prefix) { + this.prefix = prefix; + } + + public String formatString(String body) { + return "%s(%s)".formatted(prefix, body); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryTerm.java new file mode 100644 index 00000000..b78239c7 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryTerm.java @@ -0,0 +1,51 @@ +package tools.refinery.store.query.term; + +import tools.refinery.store.query.equality.LiteralEqualityHelper; + +import java.util.Objects; + +public abstract class ArithmeticUnaryTerm extends UnaryTerm { + private final ArithmeticUnaryOperator operator; + + protected ArithmeticUnaryTerm(ArithmeticUnaryOperator operator, Term body) { + super(body); + this.operator = operator; + } + + @Override + public Class getBodyType() { + return getType(); + } + + public ArithmeticUnaryOperator getOperator() { + return operator; + } + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { + if (!super.equalsWithSubstitution(helper, other)) { + return false; + } + var otherArithmeticUnaryTerm = (ArithmeticUnaryTerm) other; + return operator == otherArithmeticUnaryTerm.operator; + } + + @Override + public String toString() { + return operator.formatString(getBody().toString()); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + ArithmeticUnaryTerm that = (ArithmeticUnaryTerm) o; + return operator == that.operator; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), operator); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AssignedValue.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AssignedValue.java new file mode 100644 index 00000000..465e690f --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AssignedValue.java @@ -0,0 +1,8 @@ +package tools.refinery.store.query.term; + +import tools.refinery.store.query.literal.Literal; + +@FunctionalInterface +public interface AssignedValue { + Literal toLiteral(DataVariable targetVariable); +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java new file mode 100644 index 00000000..34f48ccc --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java @@ -0,0 +1,93 @@ +package tools.refinery.store.query.term; + +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.valuation.Valuation; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +public abstract class BinaryTerm implements Term { + private final Term left; + private final Term right; + + protected BinaryTerm(Term left, Term right) { + if (!left.getType().equals(getLeftType())) { + throw new IllegalArgumentException("Expected left %s to be of type %s, got %s instead".formatted(left, + getLeftType().getName(), left.getType().getName())); + } + if (!right.getType().equals(getRightType())) { + throw new IllegalArgumentException("Expected right %s to be of type %s, got %s instead".formatted(right, + getRightType().getName(), right.getType().getName())); + } + this.left = left; + this.right = right; + } + + public abstract Class getLeftType(); + + public abstract Class getRightType(); + + public Term getLeft() { + return left; + } + + public Term getRight() { + return right; + } + + @Override + public R evaluate(Valuation valuation) { + var leftValue = left.evaluate(valuation); + if (leftValue == null) { + return null; + } + var rightValue = right.evaluate(valuation); + if (rightValue == null) { + return null; + } + return doEvaluate(leftValue, rightValue); + } + + protected abstract R doEvaluate(T1 leftValue, T2 rightValue); + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { + if (getClass() != other.getClass()) { + return false; + } + var otherBinaryTerm = (BinaryTerm) other; + return left.equalsWithSubstitution(helper, otherBinaryTerm.left) && right.equalsWithSubstitution(helper, + otherBinaryTerm.right); + } + + @Override + public Term substitute(Substitution substitution) { + return doSubstitute(substitution, left.substitute(substitution), right.substitute(substitution)); + } + + public abstract Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight); + + @Override + public Set getInputVariables() { + var inputVariables = new HashSet<>(left.getInputVariables()); + inputVariables.addAll(right.getInputVariables()); + return Collections.unmodifiableSet(inputVariables); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BinaryTerm that = (BinaryTerm) o; + return left.equals(that.left) && right.equals(that.right); + } + + @Override + public int hashCode() { + return Objects.hash(getClass(), left, right); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonOperator.java new file mode 100644 index 00000000..44dcce10 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonOperator.java @@ -0,0 +1,20 @@ +package tools.refinery.store.query.term; + +public enum ComparisonOperator { + EQ("=="), + NOT_EQ("!="), + LESS("<"), + LESS_EQ("<="), + GREATER(">"), + GREATER_EQ(">="); + + private final String text; + + ComparisonOperator(String text) { + this.text = text; + } + + public String formatString(String left, String right) { + return "(%s) %s (%s)".formatted(left, text, right); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonTerm.java new file mode 100644 index 00000000..320d42df --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonTerm.java @@ -0,0 +1,63 @@ +package tools.refinery.store.query.term; + +import tools.refinery.store.query.equality.LiteralEqualityHelper; + +import java.util.Objects; + +public abstract class ComparisonTerm extends BinaryTerm { + private final ComparisonOperator operator; + + protected ComparisonTerm(ComparisonOperator operator, Term left, Term right) { + super(left, right); + this.operator = operator; + } + + @Override + public Class getType() { + return Boolean.class; + } + + public abstract Class getOperandType(); + + @Override + public Class getLeftType() { + return getOperandType(); + } + + @Override + public Class getRightType() { + return getOperandType(); + } + + public ComparisonOperator getOperator() { + return operator; + } + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { + if (!super.equalsWithSubstitution(helper, other)) { + return false; + } + var otherComparisonTerm = (ComparisonTerm) other; + return operator == otherComparisonTerm.operator; + } + + @Override + public String toString() { + return operator.formatString(getLeft().toString(), getRight().toString()); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + ComparisonTerm that = (ComparisonTerm) o; + return operator == that.operator; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), operator); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java new file mode 100644 index 00000000..2185fe37 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java @@ -0,0 +1,52 @@ +package tools.refinery.store.query.term; + +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.valuation.Valuation; + +import java.util.Set; + +public record ConstantTerm(Class type, T value) implements Term { + public ConstantTerm { + if (value == null) { + throw new IllegalArgumentException("value should not be null"); + } + if (!type.isInstance(value)) { + throw new IllegalArgumentException("value %s is not an instance of %s".formatted(value, type.getName())); + } + } + + @Override + public Class getType() { + return type; + } + + public T getValue() { + return value; + } + + @Override + public T evaluate(Valuation valuation) { + return getValue(); + } + + @Override + public Term substitute(Substitution substitution) { + return this; + } + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { + return equals(other); + } + + @Override + public Set getInputVariables() { + return Set.of(); + } + + @Override + public String toString() { + return getValue().toString(); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataSort.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataSort.java new file mode 100644 index 00000000..4fb44492 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataSort.java @@ -0,0 +1,29 @@ +package tools.refinery.store.query.term; + +import org.jetbrains.annotations.Nullable; + +public record DataSort(Class type) implements Sort { + public static final DataSort INT = new DataSort<>(Integer.class); + + public static final DataSort BOOL = new DataSort<>(Boolean.class); + + @Override + public boolean isInstance(Variable variable) { + return variable instanceof DataVariable dataVariable && type.equals(dataVariable.getType()); + } + + @Override + public DataVariable newInstance(@Nullable String name) { + return Variable.of(name, type); + } + + @Override + public DataVariable newInstance() { + return newInstance(null); + } + + @Override + public String toString() { + return type.getName(); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java new file mode 100644 index 00000000..af070ca7 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java @@ -0,0 +1,87 @@ +package tools.refinery.store.query.term; + +import org.jetbrains.annotations.Nullable; +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.literal.Literal; +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.valuation.Valuation; + +import java.util.Objects; + +public final class DataVariable extends AnyDataVariable implements Term { + private final Class type; + + DataVariable(String name, Class type) { + super(name); + this.type = type; + } + + @Override + public DataSort getSort() { + return new DataSort<>(getType()); + } + + @Override + public Class getType() { + return type; + } + + @Override + public DataVariable renew(@Nullable String name) { + return new DataVariable<>(name, type); + } + + @Override + public DataVariable renew() { + return renew(getExplicitName()); + } + + @Override + public NodeVariable asNodeVariable() { + throw new IllegalStateException("%s is a data variable".formatted(this)); + } + + @Override + public DataVariable asDataVariable(Class newType) { + if (!getType().equals(newType)) { + throw new IllegalStateException("%s is not of type %s but of type %s".formatted(this, newType.getName(), + getType().getName())); + } + @SuppressWarnings("unchecked") + var result = (DataVariable) this; + return result; + } + + @Override + public T evaluate(Valuation valuation) { + return valuation.getValue(this); + } + + @Override + public Term substitute(Substitution substitution) { + return substitution.getTypeSafeSubstitute(this); + } + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { + return other instanceof DataVariable dataVariable && helper.variableEqual(this, dataVariable); + } + + public Literal assign(AssignedValue value) { + return value.toLiteral(this); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + DataVariable that = (DataVariable) o; + return type.equals(that.type); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), type); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ExtremeValueAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ExtremeValueAggregator.java new file mode 100644 index 00000000..57ff597c --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ExtremeValueAggregator.java @@ -0,0 +1,103 @@ +package tools.refinery.store.query.term; + +import java.util.Comparator; +import java.util.Objects; +import java.util.SortedMap; +import java.util.TreeMap; + +public class ExtremeValueAggregator implements StatefulAggregator { + private final Class type; + private final T emptyResult; + private final Comparator comparator; + + public ExtremeValueAggregator(Class type, T emptyResult) { + this(type, emptyResult, null); + } + + public ExtremeValueAggregator(Class type, T emptyResult, Comparator comparator) { + this.type = type; + this.emptyResult = emptyResult; + this.comparator = comparator; + } + + @Override + public Class getResultType() { + return getInputType(); + } + + @Override + public Class getInputType() { + return type; + } + + @Override + public StatefulAggregate createEmptyAggregate() { + return new Aggregate(); + } + + @Override + public T getEmptyResult() { + return emptyResult; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ExtremeValueAggregator that = (ExtremeValueAggregator) o; + return type.equals(that.type) && Objects.equals(emptyResult, that.emptyResult) && Objects.equals(comparator, + that.comparator); + } + + @Override + public int hashCode() { + return Objects.hash(type, emptyResult, comparator); + } + + private class Aggregate implements StatefulAggregate { + private final SortedMap values; + + private Aggregate() { + values = new TreeMap<>(comparator); + } + + private Aggregate(Aggregate other) { + values = new TreeMap<>(other.values); + } + + @Override + public void add(T value) { + values.compute(value, (ignoredValue, currentCount) -> currentCount == null ? 1 : currentCount + 1); + } + + @Override + public void remove(T value) { + values.compute(value, (theValue, currentCount) -> { + if (currentCount == null || currentCount <= 0) { + throw new IllegalStateException("Invalid count %d for value %s".formatted(currentCount, theValue)); + } + return currentCount.equals(1) ? null : currentCount - 1; + }); + } + + @Override + public T getResult() { + return isEmpty() ? emptyResult : values.firstKey(); + } + + @Override + public boolean isEmpty() { + return values.isEmpty(); + } + + @Override + public StatefulAggregate deepCopy() { + return new Aggregate(this); + } + + @Override + public boolean contains(T value) { + return StatefulAggregate.super.contains(value); + } + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeSort.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeSort.java new file mode 100644 index 00000000..1a4b2d4b --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeSort.java @@ -0,0 +1,30 @@ +package tools.refinery.store.query.term; + +import org.jetbrains.annotations.Nullable; + +public final class NodeSort implements Sort { + public static final NodeSort INSTANCE = new NodeSort(); + + private NodeSort() { + } + + @Override + public boolean isInstance(Variable variable) { + return variable instanceof NodeVariable; + } + + @Override + public NodeVariable newInstance(@Nullable String name) { + return new NodeVariable(name); + } + + @Override + public NodeVariable newInstance() { + return newInstance(null); + } + + @Override + public String toString() { + return ""; + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java new file mode 100644 index 00000000..7419aaad --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java @@ -0,0 +1,48 @@ +package tools.refinery.store.query.term; + +import org.jetbrains.annotations.Nullable; +import tools.refinery.store.query.literal.ConstantLiteral; +import tools.refinery.store.query.literal.EquivalenceLiteral; + +public final class NodeVariable extends Variable { + NodeVariable(@Nullable String name) { + super(name); + } + + @Override + public NodeSort getSort() { + return NodeSort.INSTANCE; + } + + @Override + public NodeVariable renew(@Nullable String name) { + return Variable.of(name); + } + + @Override + public NodeVariable renew() { + return renew(getExplicitName()); + } + + @Override + public NodeVariable asNodeVariable() { + return this; + } + + @Override + public DataVariable asDataVariable(Class type) { + throw new IllegalStateException("%s is a node variable".formatted(this)); + } + + public ConstantLiteral isConstant(int value) { + return new ConstantLiteral(this, value); + } + + public EquivalenceLiteral isEquivalent(NodeVariable other) { + return new EquivalenceLiteral(true, this, other); + } + + public EquivalenceLiteral notEquivalent(NodeVariable other) { + return new EquivalenceLiteral(false, this, other); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/OpaqueTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/OpaqueTerm.java new file mode 100644 index 00000000..8faa9c75 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/OpaqueTerm.java @@ -0,0 +1,80 @@ +package tools.refinery.store.query.term; + +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.substitution.Substitutions; +import tools.refinery.store.query.valuation.Valuation; + +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +public final class OpaqueTerm implements Term { + private final Class type; + private final Function evaluator; + private final Set variables; + private final Substitution substitution; + + public OpaqueTerm(Class type, Function evaluator, + Set variables) { + this(type, evaluator, variables, null); + } + + private OpaqueTerm(Class type, Function evaluator, + Set variables, Substitution substitution) { + this.type = type; + this.evaluator = evaluator; + this.variables = Set.copyOf(variables); + this.substitution = substitution; + } + + @Override + public Class getType() { + return type; + } + + @Override + public Set getInputVariables() { + return variables; + } + + @Override + public T evaluate(Valuation valuation) { + return evaluator.apply(valuation.substitute(substitution)); + } + + @Override + public Term substitute(Substitution newSubstitution) { + var substitutedVariables = variables.stream() + .map(newSubstitution::getTypeSafeSubstitute) + .collect(Collectors.toUnmodifiableSet()); + return new OpaqueTerm<>(type, evaluator, substitutedVariables, + Substitutions.compose(substitution, newSubstitution)); + } + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { + // Cannot inspect the opaque evaluator for deep equality. + return equals(other); + } + + @Override + public String toString() { + return ""; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + OpaqueTerm that = (OpaqueTerm) o; + return type.equals(that.type) && evaluator.equals(that.evaluator) && Objects.equals(substitution, + that.substitution); + } + + @Override + public int hashCode() { + return Objects.hash(type, evaluator, substitution); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Sort.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Sort.java new file mode 100644 index 00000000..622bcfce --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Sort.java @@ -0,0 +1,11 @@ +package tools.refinery.store.query.term; + +import org.jetbrains.annotations.Nullable; + +public sealed interface Sort permits DataSort, NodeSort { + boolean isInstance(Variable variable); + + Variable newInstance(@Nullable String name); + + Variable newInstance(); +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregate.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregate.java new file mode 100644 index 00000000..7ce91305 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregate.java @@ -0,0 +1,17 @@ +package tools.refinery.store.query.term; + +public interface StatefulAggregate { + void add(T value); + + void remove(T value); + + R getResult(); + + boolean isEmpty(); + + StatefulAggregate deepCopy(); + + default boolean contains(T value) { + throw new UnsupportedOperationException(); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregator.java new file mode 100644 index 00000000..c215a511 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregator.java @@ -0,0 +1,23 @@ +package tools.refinery.store.query.term; + +import java.util.stream.Stream; + +public interface StatefulAggregator extends Aggregator { + StatefulAggregate createEmptyAggregate(); + + @Override + default R aggregateStream(Stream stream) { + var accumulator = createEmptyAggregate(); + var iterator = stream.iterator(); + while (iterator.hasNext()) { + var value = iterator.next(); + accumulator.add(value); + } + return accumulator.getResult(); + } + + @Override + default R getEmptyResult() { + return createEmptyAggregate().getResult(); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatelessAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatelessAggregator.java new file mode 100644 index 00000000..74dbd335 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatelessAggregator.java @@ -0,0 +1,20 @@ +package tools.refinery.store.query.term; + +import java.util.stream.Stream; + +public interface StatelessAggregator extends Aggregator { + R add(R current, T value); + + R remove(R current, T value); + + @Override + default R aggregateStream(Stream stream) { + var accumulator = getEmptyResult(); + var iterator = stream.iterator(); + while (iterator.hasNext()) { + var value = iterator.next(); + accumulator = add(accumulator, value); + } + return accumulator; + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Term.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Term.java new file mode 100644 index 00000000..95434db2 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Term.java @@ -0,0 +1,21 @@ +package tools.refinery.store.query.term; + +import tools.refinery.store.query.literal.AssignLiteral; +import tools.refinery.store.query.literal.Literal; +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.valuation.Valuation; + +public non-sealed interface Term extends AnyTerm, AssignedValue { + @Override + Class getType(); + + T evaluate(Valuation valuation); + + @Override + Term substitute(Substitution substitution); + + @Override + default Literal toLiteral(DataVariable targetVariable) { + return new AssignLiteral<>(targetVariable, this); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java new file mode 100644 index 00000000..4083111a --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java @@ -0,0 +1,68 @@ +package tools.refinery.store.query.term; + +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.valuation.Valuation; + +import java.util.Objects; +import java.util.Set; + +public abstract class UnaryTerm implements Term { + private final Term body; + + protected UnaryTerm(Term body) { + if (!body.getType().equals(getBodyType())) { + throw new IllegalArgumentException("Expected body %s to be of type %s, got %s instead".formatted(body, + getBodyType().getName(), body.getType().getName())); + } + this.body = body; + } + + public abstract Class getBodyType(); + + public Term getBody() { + return body; + } + + @Override + public R evaluate(Valuation valuation) { + var bodyValue = body.evaluate(valuation); + return bodyValue == null ? null : doEvaluate(bodyValue); + } + + protected abstract R doEvaluate(T bodyValue); + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { + if (getClass() != other.getClass()) { + return false; + } + var otherUnaryTerm = (UnaryTerm) other; + return body.equalsWithSubstitution(helper, otherUnaryTerm.body); + } + + @Override + public Term substitute(Substitution substitution) { + return doSubstitute(substitution, body.substitute(substitution)); + } + + protected abstract Term doSubstitute(Substitution substitution, Term substitutedBody); + + @Override + public Set getInputVariables() { + return body.getInputVariables(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + UnaryTerm unaryTerm = (UnaryTerm) o; + return body.equals(unaryTerm.body); + } + + @Override + public int hashCode() { + return Objects.hash(getClass(), body); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java new file mode 100644 index 00000000..957e10f8 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java @@ -0,0 +1,76 @@ +package tools.refinery.store.query.term; + +import org.jetbrains.annotations.Nullable; +import tools.refinery.store.query.dnf.DnfUtils; + +import java.util.Objects; + +public abstract sealed class Variable permits AnyDataVariable, NodeVariable { + private final String explicitName; + private final String uniqueName; + + protected Variable(String name) { + this.explicitName = name; + uniqueName = DnfUtils.generateUniqueName(name); + } + + public abstract Sort getSort(); + + public String getName() { + return explicitName == null ? uniqueName : explicitName; + } + + protected String getExplicitName() { + return explicitName; + } + + public boolean isExplicitlyNamed() { + return explicitName != null; + } + + public String getUniqueName() { + return uniqueName; + } + + public abstract Variable renew(@Nullable String name); + + public abstract Variable renew(); + + public abstract NodeVariable asNodeVariable(); + + public abstract DataVariable asDataVariable(Class type); + + @Override + public String toString() { + return getName(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Variable variable = (Variable) o; + return Objects.equals(uniqueName, variable.uniqueName); + } + + @Override + public int hashCode() { + return Objects.hash(uniqueName); + } + + public static NodeVariable of(@Nullable String name) { + return new NodeVariable(name); + } + + public static NodeVariable of() { + return of((String) null); + } + + public static DataVariable of(@Nullable String name, Class type) { + return new DataVariable<>(name, type); + } + + public static DataVariable of(Class type) { + return of(null, type); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolConstantTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolConstantTerm.java new file mode 100644 index 00000000..5079f1ce --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolConstantTerm.java @@ -0,0 +1,16 @@ +package tools.refinery.store.query.term.bool; + +import tools.refinery.store.query.term.ConstantTerm; + +public final class BoolConstantTerm { + public static final ConstantTerm TRUE = new ConstantTerm<>(Boolean.class, true); + public static final ConstantTerm FALSE = new ConstantTerm<>(Boolean.class, false); + + private BoolConstantTerm() { + throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); + } + + public static ConstantTerm valueOf(boolean boolValue) { + return boolValue ? TRUE : FALSE; + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolLogicBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolLogicBinaryTerm.java new file mode 100644 index 00000000..d85f864d --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolLogicBinaryTerm.java @@ -0,0 +1,78 @@ +package tools.refinery.store.query.term.bool; + +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.*; + +import java.util.Objects; + +public class BoolLogicBinaryTerm extends BinaryTerm { + private final LogicBinaryOperator operator; + + protected BoolLogicBinaryTerm(LogicBinaryOperator operator, Term left, Term right) { + super(left, right); + this.operator = operator; + } + + @Override + public Class getType() { + return Boolean.class; + } + + @Override + public Class getLeftType() { + return getType(); + } + + @Override + public Class getRightType() { + return getType(); + } + + public LogicBinaryOperator getOperator() { + return operator; + } + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { + if (!super.equalsWithSubstitution(helper, other)) { + return false; + } + var otherBoolLogicBinaryTerm = (BoolLogicBinaryTerm) other; + return operator == otherBoolLogicBinaryTerm.operator; + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new BoolLogicBinaryTerm(getOperator(), substitutedLeft, substitutedRight); + } + + @Override + protected Boolean doEvaluate(Boolean leftValue, Boolean rightValue) { + return switch (getOperator()) { + case AND -> leftValue && rightValue; + case OR -> leftValue || rightValue; + case XOR -> leftValue ^ rightValue; + }; + } + + @Override + public String toString() { + return operator.formatString(getLeft().toString(), getRight().toString()); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + BoolLogicBinaryTerm that = (BoolLogicBinaryTerm) o; + return operator == that.operator; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), operator); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java new file mode 100644 index 00000000..855139b5 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java @@ -0,0 +1,36 @@ +package tools.refinery.store.query.term.bool; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; +import tools.refinery.store.query.term.UnaryTerm; + +public class BoolNotTerm extends UnaryTerm { + protected BoolNotTerm(Term body) { + super(body); + } + + @Override + public Class getType() { + return Boolean.class; + } + + @Override + public Class getBodyType() { + return getType(); + } + + @Override + protected Term doSubstitute(Substitution substitution, Term substitutedBody) { + return new BoolNotTerm(substitutedBody); + } + + @Override + protected Boolean doEvaluate(Boolean bodyValue) { + return !bodyValue; + } + + @Override + public String toString() { + return "!(%s)".formatted(getBody()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java new file mode 100644 index 00000000..3d6c8d9d --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java @@ -0,0 +1,30 @@ +package tools.refinery.store.query.term.bool; + +import tools.refinery.store.query.term.ConstantTerm; +import tools.refinery.store.query.term.Term; + +public final class BoolTerms { + private BoolTerms() { + throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly"); + } + + public static ConstantTerm constant(boolean value) { + return BoolConstantTerm.valueOf(value); + } + + public static BoolNotTerm not(Term body) { + return new BoolNotTerm(body); + } + + public static BoolLogicBinaryTerm and(Term left, Term right) { + return new BoolLogicBinaryTerm(LogicBinaryOperator.AND, left, right); + } + + public static BoolLogicBinaryTerm or(Term left, Term right) { + return new BoolLogicBinaryTerm(LogicBinaryOperator.OR, left, right); + } + + public static BoolLogicBinaryTerm xor(Term left, Term right) { + return new BoolLogicBinaryTerm(LogicBinaryOperator.XOR, left, right); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/LogicBinaryOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/LogicBinaryOperator.java new file mode 100644 index 00000000..ca9ac66e --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/LogicBinaryOperator.java @@ -0,0 +1,17 @@ +package tools.refinery.store.query.term.bool; + +public enum LogicBinaryOperator { + AND("&&"), + OR("||"), + XOR("^^"); + + private final String text; + + LogicBinaryOperator(String text) { + this.text = text; + } + + public String formatString(String left, String right) { + return "(%s) %s (%s)".formatted(left, text, right); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticBinaryTerm.java new file mode 100644 index 00000000..32e41718 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticBinaryTerm.java @@ -0,0 +1,48 @@ +package tools.refinery.store.query.term.int_; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.ArithmeticBinaryOperator; +import tools.refinery.store.query.term.ArithmeticBinaryTerm; +import tools.refinery.store.query.term.Term; + +public class IntArithmeticBinaryTerm extends ArithmeticBinaryTerm { + public IntArithmeticBinaryTerm(ArithmeticBinaryOperator operator, Term left, Term right) { + super(operator, left, right); + } + + @Override + public Class getType() { + return Integer.class; + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new IntArithmeticBinaryTerm(getOperator(), substitutedLeft, substitutedRight); + } + + @Override + protected Integer doEvaluate(Integer leftValue, Integer rightValue) { + return switch (getOperator()) { + case ADD -> leftValue + rightValue; + case SUB -> leftValue - rightValue; + case MUL -> leftValue * rightValue; + case DIV -> rightValue == 0 ? null : leftValue / rightValue; + case POW -> rightValue < 0 ? null : power(leftValue, rightValue); + case MIN -> Math.min(leftValue, rightValue); + case MAX -> Math.max(leftValue, rightValue); + }; + } + + private static int power(int base, int exponent) { + int accum = 1; + while (exponent > 0) { + if (exponent % 2 == 1) { + accum = accum * base; + } + base = base * base; + exponent = exponent / 2; + } + return accum; + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticUnaryTerm.java new file mode 100644 index 00000000..1e769259 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticUnaryTerm.java @@ -0,0 +1,30 @@ +package tools.refinery.store.query.term.int_; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; +import tools.refinery.store.query.term.ArithmeticUnaryOperator; +import tools.refinery.store.query.term.ArithmeticUnaryTerm; + +public class IntArithmeticUnaryTerm extends ArithmeticUnaryTerm { + public IntArithmeticUnaryTerm(ArithmeticUnaryOperator operation, Term body) { + super(operation, body); + } + + @Override + public Class getType() { + return Integer.class; + } + + @Override + protected Term doSubstitute(Substitution substitution, Term substitutedBody) { + return new IntArithmeticUnaryTerm(getOperator(), substitutedBody); + } + + @Override + protected Integer doEvaluate(Integer bodyValue) { + return switch(getOperator()) { + case PLUS -> bodyValue; + case MINUS -> -bodyValue; + }; + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntComparisonTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntComparisonTerm.java new file mode 100644 index 00000000..322d2b80 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntComparisonTerm.java @@ -0,0 +1,34 @@ +package tools.refinery.store.query.term.int_; +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.ComparisonOperator; +import tools.refinery.store.query.term.ComparisonTerm; +import tools.refinery.store.query.term.Term; + +public class IntComparisonTerm extends ComparisonTerm { + public IntComparisonTerm(ComparisonOperator operator, Term left, Term right) { + super(operator, left, right); + } + + @Override + public Class getOperandType() { + return Integer.class; + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new IntComparisonTerm(getOperator(), substitutedLeft, substitutedRight); + } + + @Override + protected Boolean doEvaluate(Integer leftValue, Integer rightValue) { + return switch (getOperator()) { + case EQ -> leftValue.equals(rightValue); + case NOT_EQ -> !leftValue.equals(rightValue); + case LESS -> leftValue < rightValue; + case LESS_EQ -> leftValue <= rightValue; + case GREATER -> leftValue > rightValue; + case GREATER_EQ -> leftValue >= rightValue; + }; + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntExtremeValueAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntExtremeValueAggregator.java new file mode 100644 index 00000000..d5a6add0 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntExtremeValueAggregator.java @@ -0,0 +1,17 @@ +package tools.refinery.store.query.term.int_; + +import tools.refinery.store.query.term.ExtremeValueAggregator; + +import java.util.Comparator; + +public final class IntExtremeValueAggregator { + public static final ExtremeValueAggregator MINIMUM = new ExtremeValueAggregator<>(Integer.class, + Integer.MAX_VALUE); + + public static final ExtremeValueAggregator MAXIMUM = new ExtremeValueAggregator<>(Integer.class, + Integer.MIN_VALUE, Comparator.reverseOrder()); + + private IntExtremeValueAggregator() { + throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSumAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSumAggregator.java new file mode 100644 index 00000000..65024f52 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSumAggregator.java @@ -0,0 +1,35 @@ +package tools.refinery.store.query.term.int_; + +import tools.refinery.store.query.term.StatelessAggregator; + +public final class IntSumAggregator implements StatelessAggregator { + public static final IntSumAggregator INSTANCE = new IntSumAggregator(); + + private IntSumAggregator() { + } + + @Override + public Class getResultType() { + return Integer.class; + } + + @Override + public Class getInputType() { + return Integer.class; + } + + @Override + public Integer getEmptyResult() { + return 0; + } + + @Override + public Integer add(Integer current, Integer value) { + return current + value; + } + + @Override + public Integer remove(Integer current, Integer value) { + return current - value; + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java new file mode 100644 index 00000000..86594deb --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java @@ -0,0 +1,81 @@ +package tools.refinery.store.query.term.int_; + +import tools.refinery.store.query.term.*; + +public final class IntTerms { + public static final Aggregator INT_SUM = IntSumAggregator.INSTANCE; + public static final Aggregator INT_MIN = IntExtremeValueAggregator.MINIMUM; + public static final Aggregator INT_MAX = IntExtremeValueAggregator.MAXIMUM; + + private IntTerms() { + throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly"); + } + + public static ConstantTerm constant(int value) { + return new ConstantTerm<>(Integer.class, value); + } + + public static IntArithmeticUnaryTerm plus(Term body) { + return new IntArithmeticUnaryTerm(ArithmeticUnaryOperator.PLUS, body); + } + + public static IntArithmeticUnaryTerm minus(Term body) { + return new IntArithmeticUnaryTerm(ArithmeticUnaryOperator.MINUS, body); + } + + public static IntArithmeticBinaryTerm add(Term left, Term right) { + return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.ADD, left, right); + } + + public static IntArithmeticBinaryTerm sub(Term left, Term right) { + return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.SUB, left, right); + } + + public static IntArithmeticBinaryTerm mul(Term left, Term right) { + return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.MUL, left, right); + } + + public static IntArithmeticBinaryTerm div(Term left, Term right) { + return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.DIV, left, right); + } + + public static IntArithmeticBinaryTerm pow(Term left, Term right) { + return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.POW, left, right); + } + + public static IntArithmeticBinaryTerm min(Term left, Term right) { + return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.MIN, left, right); + } + + public static IntArithmeticBinaryTerm max(Term left, Term right) { + return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.MAX, left, right); + } + + public static IntComparisonTerm eq(Term left, Term right) { + return new IntComparisonTerm(ComparisonOperator.EQ, left, right); + } + + public static IntComparisonTerm notEq(Term left, Term right) { + return new IntComparisonTerm(ComparisonOperator.NOT_EQ, left, right); + } + + public static IntComparisonTerm less(Term left, Term right) { + return new IntComparisonTerm(ComparisonOperator.LESS, left, right); + } + + public static IntComparisonTerm lessEq(Term left, Term right) { + return new IntComparisonTerm(ComparisonOperator.LESS_EQ, left, right); + } + + public static IntComparisonTerm greater(Term left, Term right) { + return new IntComparisonTerm(ComparisonOperator.GREATER, left, right); + } + + public static IntComparisonTerm greaterEq(Term left, Term right) { + return new IntComparisonTerm(ComparisonOperator.GREATER_EQ, left, right); + } + + public static RealToIntTerm asInt(Term body) { + return new RealToIntTerm(body); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java new file mode 100644 index 00000000..53875ddc --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java @@ -0,0 +1,36 @@ +package tools.refinery.store.query.term.int_; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; +import tools.refinery.store.query.term.UnaryTerm; + +public class RealToIntTerm extends UnaryTerm { + protected RealToIntTerm(Term body) { + super(body); + } + + @Override + public Class getType() { + return Integer.class; + } + + @Override + public Class getBodyType() { + return Double.class; + } + + @Override + protected Integer doEvaluate(Double bodyValue) { + return bodyValue.intValue(); + } + + @Override + protected Term doSubstitute(Substitution substitution, Term substitutedBody) { + return new RealToIntTerm(substitutedBody); + } + + @Override + public String toString() { + return "(%s) as int".formatted(getBody()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java new file mode 100644 index 00000000..55590824 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java @@ -0,0 +1,36 @@ +package tools.refinery.store.query.term.real; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; +import tools.refinery.store.query.term.UnaryTerm; + +public class IntToRealTerm extends UnaryTerm { + protected IntToRealTerm(Term body) { + super(body); + } + + @Override + public Class getType() { + return Double.class; + } + + @Override + public Class getBodyType() { + return Integer.class; + } + + @Override + protected Term doSubstitute(Substitution substitution, Term substitutedBody) { + return new IntToRealTerm(substitutedBody); + } + + @Override + protected Double doEvaluate(Integer bodyValue) { + return bodyValue.doubleValue(); + } + + @Override + public String toString() { + return "(%s) as real".formatted(getBody()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticBinaryTerm.java new file mode 100644 index 00000000..57bcbe5e --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticBinaryTerm.java @@ -0,0 +1,36 @@ +package tools.refinery.store.query.term.real; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.ArithmeticBinaryOperator; +import tools.refinery.store.query.term.ArithmeticBinaryTerm; +import tools.refinery.store.query.term.Term; + +public class RealArithmeticBinaryTerm extends ArithmeticBinaryTerm { + public RealArithmeticBinaryTerm(ArithmeticBinaryOperator operator, Term left, Term right) { + super(operator, left, right); + } + + @Override + public Class getType() { + return Double.class; + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new RealArithmeticBinaryTerm(getOperator(), substitutedLeft, substitutedRight); + } + + @Override + protected Double doEvaluate(Double leftValue, Double rightValue) { + return switch (getOperator()) { + case ADD -> leftValue + rightValue; + case SUB -> leftValue - rightValue; + case MUL -> leftValue * rightValue; + case DIV -> leftValue / rightValue; + case POW -> Math.pow(leftValue, rightValue); + case MIN -> Math.min(leftValue, rightValue); + case MAX -> Math.max(leftValue, rightValue); + }; + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticUnaryTerm.java new file mode 100644 index 00000000..632e68bf --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticUnaryTerm.java @@ -0,0 +1,30 @@ +package tools.refinery.store.query.term.real; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.ArithmeticUnaryOperator; +import tools.refinery.store.query.term.ArithmeticUnaryTerm; +import tools.refinery.store.query.term.Term; + +public class RealArithmeticUnaryTerm extends ArithmeticUnaryTerm { + public RealArithmeticUnaryTerm(ArithmeticUnaryOperator operation, Term body) { + super(operation, body); + } + + @Override + public Class getType() { + return Double.class; + } + + @Override + protected Term doSubstitute(Substitution substitution, Term substitutedBody) { + return new RealArithmeticUnaryTerm(getOperator(), substitutedBody); + } + + @Override + protected Double doEvaluate(Double bodyValue) { + return switch(getOperator()) { + case PLUS -> bodyValue; + case MINUS -> -bodyValue; + }; + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealComparisonTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealComparisonTerm.java new file mode 100644 index 00000000..75d97adb --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealComparisonTerm.java @@ -0,0 +1,35 @@ +package tools.refinery.store.query.term.real; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.ComparisonOperator; +import tools.refinery.store.query.term.ComparisonTerm; +import tools.refinery.store.query.term.Term; + +public class RealComparisonTerm extends ComparisonTerm { + public RealComparisonTerm(ComparisonOperator operator, Term left, Term right) { + super(operator, left, right); + } + + @Override + public Class getOperandType() { + return Double.class; + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new RealComparisonTerm(getOperator(), substitutedLeft, substitutedRight); + } + + @Override + protected Boolean doEvaluate(Double leftValue, Double rightValue) { + return switch (getOperator()) { + case EQ -> leftValue.equals(rightValue); + case NOT_EQ -> !leftValue.equals(rightValue); + case LESS -> leftValue < rightValue; + case LESS_EQ -> leftValue <= rightValue; + case GREATER -> leftValue > rightValue; + case GREATER_EQ -> leftValue >= rightValue; + }; + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealExtremeValueAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealExtremeValueAggregator.java new file mode 100644 index 00000000..23384530 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealExtremeValueAggregator.java @@ -0,0 +1,17 @@ +package tools.refinery.store.query.term.real; + +import tools.refinery.store.query.term.ExtremeValueAggregator; + +import java.util.Comparator; + +public final class RealExtremeValueAggregator { + public static final ExtremeValueAggregator MINIMUM = new ExtremeValueAggregator<>(Double.class, + Double.POSITIVE_INFINITY); + + public static final ExtremeValueAggregator MAXIMUM = new ExtremeValueAggregator<>(Double.class, + Double.NEGATIVE_INFINITY, Comparator.reverseOrder()); + + private RealExtremeValueAggregator() { + throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSumAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSumAggregator.java new file mode 100644 index 00000000..d5888664 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSumAggregator.java @@ -0,0 +1,85 @@ +package tools.refinery.store.query.term.real; + +import tools.refinery.store.query.term.StatefulAggregate; +import tools.refinery.store.query.term.StatefulAggregator; + +import java.util.Map; +import java.util.TreeMap; + +public final class RealSumAggregator implements StatefulAggregator { + public static final RealSumAggregator INSTANCE = new RealSumAggregator(); + + private RealSumAggregator() { + } + + @Override + public Class getResultType() { + return null; + } + + @Override + public Class getInputType() { + return null; + } + + @Override + public StatefulAggregate createEmptyAggregate() { + return new Aggregate(); + } + + @Override + public Double getEmptyResult() { + return 0d; + } + + private static class Aggregate implements StatefulAggregate { + private final Map values; + + public Aggregate() { + values = new TreeMap<>(); + } + + private Aggregate(Aggregate other) { + values = new TreeMap<>(other.values); + } + + @Override + public void add(Double value) { + values.compute(value, (ignoredValue, currentCount) -> currentCount == null ? 1 : currentCount + 1); + } + + @Override + public void remove(Double value) { + values.compute(value, (theValue, currentCount) -> { + if (currentCount == null || currentCount <= 0) { + throw new IllegalStateException("Invalid count %d for value %f".formatted(currentCount, theValue)); + } + return currentCount.equals(1) ? null : currentCount - 1; + }); + } + + @Override + public Double getResult() { + return values.entrySet() + .stream() + .mapToDouble(entry -> entry.getKey() * entry.getValue()) + .reduce(Double::sum) + .orElse(0d); + } + + @Override + public boolean isEmpty() { + return values.isEmpty(); + } + + @Override + public StatefulAggregate deepCopy() { + return new Aggregate(this); + } + + @Override + public boolean contains(Double value) { + return values.containsKey(value); + } + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java new file mode 100644 index 00000000..a8117842 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java @@ -0,0 +1,81 @@ +package tools.refinery.store.query.term.real; + +import tools.refinery.store.query.term.*; + +public final class RealTerms { + public static final Aggregator REAL_SUM = RealSumAggregator.INSTANCE; + public static final Aggregator REAL_MIN = RealExtremeValueAggregator.MINIMUM; + public static final Aggregator REAL_MAX = RealExtremeValueAggregator.MAXIMUM; + + private RealTerms() { + throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly"); + } + + public static ConstantTerm constant(double value) { + return new ConstantTerm<>(Double.class, value); + } + + public static RealArithmeticUnaryTerm plus(Term body) { + return new RealArithmeticUnaryTerm(ArithmeticUnaryOperator.PLUS, body); + } + + public static RealArithmeticUnaryTerm minus(Term body) { + return new RealArithmeticUnaryTerm(ArithmeticUnaryOperator.MINUS, body); + } + + public static RealArithmeticBinaryTerm add(Term left, Term right) { + return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.ADD, left, right); + } + + public static RealArithmeticBinaryTerm sub(Term left, Term right) { + return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.SUB, left, right); + } + + public static RealArithmeticBinaryTerm mul(Term left, Term right) { + return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.MUL, left, right); + } + + public static RealArithmeticBinaryTerm div(Term left, Term right) { + return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.DIV, left, right); + } + + public static RealArithmeticBinaryTerm pow(Term left, Term right) { + return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.POW, left, right); + } + + public static RealArithmeticBinaryTerm min(Term left, Term right) { + return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.MIN, left, right); + } + + public static RealArithmeticBinaryTerm max(Term left, Term right) { + return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.MAX, left, right); + } + + public static RealComparisonTerm eq(Term left, Term right) { + return new RealComparisonTerm(ComparisonOperator.EQ, left, right); + } + + public static RealComparisonTerm notEq(Term left, Term right) { + return new RealComparisonTerm(ComparisonOperator.NOT_EQ, left, right); + } + + public static RealComparisonTerm less(Term left, Term right) { + return new RealComparisonTerm(ComparisonOperator.LESS, left, right); + } + + public static RealComparisonTerm lessEq(Term left, Term right) { + return new RealComparisonTerm(ComparisonOperator.LESS_EQ, left, right); + } + + public static RealComparisonTerm greater(Term left, Term right) { + return new RealComparisonTerm(ComparisonOperator.GREATER, left, right); + } + + public static RealComparisonTerm greaterEq(Term left, Term right) { + return new RealComparisonTerm(ComparisonOperator.GREATER_EQ, left, right); + } + + public static IntToRealTerm asReal(Term body) { + return new IntToRealTerm(body); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/RestrictedValuation.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/RestrictedValuation.java new file mode 100644 index 00000000..fb512d88 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/RestrictedValuation.java @@ -0,0 +1,16 @@ +package tools.refinery.store.query.valuation; + +import tools.refinery.store.query.term.AnyDataVariable; +import tools.refinery.store.query.term.DataVariable; + +import java.util.Set; + +public record RestrictedValuation(Valuation valuation, Set allowedVariables) implements Valuation { + @Override + public T getValue(DataVariable variable) { + if (!allowedVariables.contains(variable)) { + throw new IllegalArgumentException("Variable %s is not in scope".formatted(variable)); + } + return valuation.getValue(variable); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/SubstitutedValuation.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/SubstitutedValuation.java new file mode 100644 index 00000000..8e79663c --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/SubstitutedValuation.java @@ -0,0 +1,11 @@ +package tools.refinery.store.query.valuation; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.DataVariable; + +public record SubstitutedValuation(Valuation originalValuation, Substitution substitution) implements Valuation { + @Override + public T getValue(DataVariable variable) { + return originalValuation.getValue(substitution.getTypeSafeSubstitute(variable)); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java new file mode 100644 index 00000000..3ba9a6b8 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java @@ -0,0 +1,23 @@ +package tools.refinery.store.query.valuation; + +import org.jetbrains.annotations.Nullable; +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.AnyDataVariable; +import tools.refinery.store.query.term.DataVariable; + +import java.util.Set; + +public interface Valuation { + T getValue(DataVariable variable); + + default Valuation substitute(@Nullable Substitution substitution) { + if (substitution == null) { + return this; + } + return new SubstitutedValuation(this, substitution); + } + + default Valuation restrict(Set allowedVariables) { + return new RestrictedValuation(this, Set.copyOf(allowedVariables)); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnyRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnyRelationView.java index bc3ac1ea..6ae410f2 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnyRelationView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnyRelationView.java @@ -1,13 +1,13 @@ package tools.refinery.store.query.view; import tools.refinery.store.model.Model; -import tools.refinery.store.query.FunctionalDependency; +import tools.refinery.store.query.dnf.FunctionalDependency; import tools.refinery.store.representation.AnySymbol; -import tools.refinery.store.query.RelationLike; +import tools.refinery.store.query.Constraint; import java.util.Set; -public sealed interface AnyRelationView extends RelationLike permits RelationView { +public sealed interface AnyRelationView extends Constraint permits RelationView { AnySymbol getSymbol(); String getViewName(); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenRelationView.java new file mode 100644 index 00000000..050b9496 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenRelationView.java @@ -0,0 +1,16 @@ +package tools.refinery.store.query.view; + +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.representation.TruthValue; +import tools.refinery.store.tuple.Tuple; + +public class ForbiddenRelationView extends TuplePreservingRelationView { + public ForbiddenRelationView(Symbol symbol) { + super(symbol, "forbidden"); + } + + @Override + public boolean filter(Tuple key, TruthValue value) { + return !value.may(); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java index 3d278a8b..7ec9e7ac 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java @@ -1,22 +1,31 @@ package tools.refinery.store.query.view; import tools.refinery.store.model.Model; -import tools.refinery.store.query.FunctionalDependency; +import tools.refinery.store.query.dnf.FunctionalDependency; +import tools.refinery.store.query.term.DataSort; +import tools.refinery.store.query.term.NodeSort; +import tools.refinery.store.query.term.Sort; import tools.refinery.store.representation.Symbol; import tools.refinery.store.tuple.Tuple; import tools.refinery.store.tuple.Tuple1; +import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.IntStream; public final class FunctionalRelationView extends RelationView { + private final T defaultValue; + public FunctionalRelationView(Symbol symbol, String name) { super(symbol, name); + defaultValue = symbol.defaultValue(); } public FunctionalRelationView(Symbol symbol) { super(symbol); + defaultValue = symbol.defaultValue(); } @Override @@ -37,7 +46,7 @@ public final class FunctionalRelationView extends RelationView { @Override public boolean filter(Tuple key, T value) { - return true; + return !Objects.equals(defaultValue, value); } @Override @@ -68,4 +77,29 @@ public final class FunctionalRelationView extends RelationView { public int arity() { return getSymbol().arity() + 1; } + + @Override + public List getSorts() { + var sorts = new Sort[arity()]; + int valueIndex = sorts.length - 1; + for (int i = 0; i < valueIndex; i++) { + sorts[i] = NodeSort.INSTANCE; + } + sorts[valueIndex] = new DataSort<>(getSymbol().valueType()); + return List.of(sorts); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + FunctionalRelationView that = (FunctionalRelationView) o; + return Objects.equals(defaultValue, that.defaultValue); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), defaultValue); + } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayRelationView.java new file mode 100644 index 00000000..a2a84b3c --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayRelationView.java @@ -0,0 +1,16 @@ +package tools.refinery.store.query.view; + +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.representation.TruthValue; +import tools.refinery.store.tuple.Tuple; + +public class MayRelationView extends TuplePreservingRelationView { + public MayRelationView(Symbol symbol) { + super(symbol, "may"); + } + + @Override + public boolean filter(Tuple key, TruthValue value) { + return value.may(); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustRelationView.java new file mode 100644 index 00000000..72ac0ca3 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustRelationView.java @@ -0,0 +1,16 @@ +package tools.refinery.store.query.view; + +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.representation.TruthValue; +import tools.refinery.store.tuple.Tuple; + +public class MustRelationView extends TuplePreservingRelationView { + public MustRelationView(Symbol symbol) { + super(symbol, "must"); + } + + @Override + public boolean filter(Tuple key, TruthValue value) { + return value.must(); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationView.java index ea9fd5e2..d7164b3b 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationView.java @@ -1,14 +1,10 @@ package tools.refinery.store.query.view; -import tools.refinery.store.query.Variable; import tools.refinery.store.map.CursorAsIterator; import tools.refinery.store.model.Model; -import tools.refinery.store.query.literal.CallPolarity; -import tools.refinery.store.query.literal.RelationViewLiteral; import tools.refinery.store.representation.Symbol; import tools.refinery.store.tuple.Tuple; -import java.util.List; import java.util.Objects; import java.util.UUID; @@ -56,20 +52,14 @@ public abstract non-sealed class RelationView implements AnyRelationView { return (() -> new CursorAsIterator<>(model.getInterpretation(symbol).getAll(), this::forwardMap, this::filter)); } - public RelationViewLiteral call(CallPolarity polarity, List arguments) { - return new RelationViewLiteral(polarity, this, arguments); - } - - public RelationViewLiteral call(CallPolarity polarity, Variable... arguments) { - return call(polarity, List.of(arguments)); - } - - public RelationViewLiteral call(Variable... arguments) { - return call(CallPolarity.POSITIVE, arguments); + @Override + public String toString() { + return name(); } - public RelationViewLiteral callTransitive(Variable left, Variable right) { - return call(CallPolarity.TRANSITIVE, List.of(left, right)); + @Override + public String toReferenceString() { + return "@RelationView(\"%s\") %s".formatted(viewName, symbol.name()); } @Override diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java index 8cc4986e..234b3a9a 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java @@ -1,10 +1,15 @@ package tools.refinery.store.query.view; import tools.refinery.store.model.Model; +import tools.refinery.store.query.term.NodeSort; +import tools.refinery.store.query.term.Sort; import tools.refinery.store.tuple.Tuple; import tools.refinery.store.tuple.Tuple1; import tools.refinery.store.representation.Symbol; +import java.util.Arrays; +import java.util.List; + public abstract class TuplePreservingRelationView extends RelationView { protected TuplePreservingRelationView(Symbol symbol, String name) { super(symbol, name); @@ -38,7 +43,15 @@ public abstract class TuplePreservingRelationView extends RelationView { return filter(key, value); } + @Override public int arity() { return this.getSymbol().arity(); } + + @Override + public List getSorts() { + var sorts = new Sort[arity()]; + Arrays.fill(sorts, NodeSort.INSTANCE); + return List.of(sorts); + } } diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java index e6701fe3..ceb46d6f 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java @@ -1,7 +1,9 @@ package tools.refinery.store.query; import org.junit.jupiter.api.Test; +import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.query.literal.BooleanLiteral; +import tools.refinery.store.query.term.Variable; import tools.refinery.store.query.view.KeyOnlyRelationView; import tools.refinery.store.representation.Symbol; @@ -12,8 +14,8 @@ import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo class DnfBuilderTest { @Test void eliminateTrueTest() { - var p = new Variable("p"); - var q = new Variable("q"); + var p = Variable.of("p"); + var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); var friendView = new KeyOnlyRelationView<>(friend); @@ -28,8 +30,8 @@ class DnfBuilderTest { @Test void eliminateFalseTest() { - var p = new Variable("p"); - var q = new Variable("q"); + var p = Variable.of("p"); + var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); var friendView = new KeyOnlyRelationView<>(friend); @@ -45,8 +47,8 @@ class DnfBuilderTest { @Test void alwaysTrueTest() { - var p = new Variable("p"); - var q = new Variable("q"); + var p = Variable.of("p"); + var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); var friendView = new KeyOnlyRelationView<>(friend); @@ -62,8 +64,8 @@ class DnfBuilderTest { @Test void alwaysFalseTest() { - var p = new Variable("p"); - var q = new Variable("q"); + var p = Variable.of("p"); + var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); var friendView = new KeyOnlyRelationView<>(friend); @@ -78,8 +80,8 @@ class DnfBuilderTest { @Test void eliminateTrueDnfTest() { - var p = new Variable("p"); - var q = new Variable("q"); + var p = Variable.of("p"); + var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); var friendView = new KeyOnlyRelationView<>(friend); var trueDnf = Dnf.builder().parameter(p).clause().build(); @@ -95,8 +97,8 @@ class DnfBuilderTest { @Test void eliminateFalseDnfTest() { - var p = new Variable("p"); - var q = new Variable("q"); + var p = Variable.of("p"); + var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); var friendView = new KeyOnlyRelationView<>(friend); var falseDnf = Dnf.builder().parameter(p).build(); @@ -113,8 +115,8 @@ class DnfBuilderTest { @Test void alwaysTrueDnfTest() { - var p = new Variable("p"); - var q = new Variable("q"); + var p = Variable.of("p"); + var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); var friendView = new KeyOnlyRelationView<>(friend); var trueDnf = Dnf.builder().parameter(p).clause().build(); @@ -131,8 +133,8 @@ class DnfBuilderTest { @Test void alwaysFalseDnfTest() { - var p = new Variable("p"); - var q = new Variable("q"); + var p = Variable.of("p"); + var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); var friendView = new KeyOnlyRelationView<>(friend); var falseDnf = Dnf.builder().parameter(p).build(); @@ -148,8 +150,8 @@ class DnfBuilderTest { @Test void eliminateNotFalseDnfTest() { - var p = new Variable("p"); - var q = new Variable("q"); + var p = Variable.of("p"); + var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); var friendView = new KeyOnlyRelationView<>(friend); var falseDnf = Dnf.builder().parameter(p).build(); @@ -165,8 +167,8 @@ class DnfBuilderTest { @Test void eliminateNotTrueDnfTest() { - var p = new Variable("p"); - var q = new Variable("q"); + var p = Variable.of("p"); + var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); var friendView = new KeyOnlyRelationView<>(friend); var trueDnf = Dnf.builder().parameter(p).clause().build(); @@ -183,8 +185,8 @@ class DnfBuilderTest { @Test void alwaysNotFalseDnfTest() { - var p = new Variable("p"); - var q = new Variable("q"); + var p = Variable.of("p"); + var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); var friendView = new KeyOnlyRelationView<>(friend); var falseDnf = Dnf.builder().parameter(p).build(); @@ -201,8 +203,8 @@ class DnfBuilderTest { @Test void alwaysNotTrueDnfTest() { - var p = new Variable("p"); - var q = new Variable("q"); + var p = Variable.of("p"); + var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); var friendView = new KeyOnlyRelationView<>(friend); var trueDnf = Dnf.builder().parameter(p).clause().build(); diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToDefinitionStringTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToDefinitionStringTest.java new file mode 100644 index 00000000..9b469bb0 --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToDefinitionStringTest.java @@ -0,0 +1,174 @@ +package tools.refinery.store.query; + +import org.junit.jupiter.api.Test; +import tools.refinery.store.query.dnf.Dnf; +import tools.refinery.store.query.term.Variable; +import tools.refinery.store.query.view.KeyOnlyRelationView; +import tools.refinery.store.representation.Symbol; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static tools.refinery.store.query.literal.Literals.not; + +class DnfToDefinitionStringTest { + @Test + void noClausesTest() { + var p = Variable.of("p"); + var dnf = Dnf.builder("Example").parameter(p).build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example(p) <-> + . + """)); + } + + @Test + void noParametersTest() { + var dnf = Dnf.builder("Example").build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example() <-> + . + """)); + } + + @Test + void emptyClauseTest() { + var p = Variable.of("p"); + var dnf = Dnf.builder("Example").parameter(p).clause().build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example(p) <-> + . + """)); + } + + @Test + void relationViewPositiveTest() { + var p = Variable.of("p"); + var q = Variable.of("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var dnf = Dnf.builder("Example").parameter(p).clause(friendView.call(p, q)).build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example(p) <-> + @RelationView("key") friend(p, q). + """)); + } + + @Test + void relationViewNegativeTest() { + var p = Variable.of("p"); + var q = Variable.of("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var dnf = Dnf.builder("Example").parameter(p).clause(not(friendView.call(p, q))).build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example(p) <-> + !(@RelationView("key") friend(p, q)). + """)); + } + + @Test + void relationViewTransitiveTest() { + var p = Variable.of("p"); + var q = Variable.of("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var dnf = Dnf.builder("Example").parameter(p).clause(friendView.callTransitive(p, q)).build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example(p) <-> + @RelationView("key") friend+(p, q). + """)); + } + + @Test + void multipleParametersTest() { + var p = Variable.of("p"); + var q = Variable.of("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var dnf = Dnf.builder("Example").parameters(p, q).clause(friendView.call(p, q)).build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example(p, q) <-> + @RelationView("key") friend(p, q). + """)); + } + + @Test + void multipleLiteralsTest() { + var p = Variable.of("p"); + var q = Variable.of("q"); + var person = new Symbol<>("person", 1, Boolean.class, false); + var personView = new KeyOnlyRelationView<>(person); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var dnf = Dnf.builder("Example") + .parameter(p) + .clause( + personView.call(p), + personView.call(q), + friendView.call(p, q) + ) + .build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example(p) <-> + @RelationView("key") person(p), + @RelationView("key") person(q), + @RelationView("key") friend(p, q). + """)); + } + + @Test + void multipleClausesTest() { + var p = Variable.of("p"); + var q = Variable.of("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var dnf = Dnf.builder("Example") + .parameter(p) + .clause(friendView.call(p, q)) + .clause(friendView.call(q, p)) + .build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example(p) <-> + @RelationView("key") friend(p, q) + ; + @RelationView("key") friend(q, p). + """)); + } + + @Test + void dnfTest() { + var p = Variable.of("p"); + var q = Variable.of("q"); + var r = Variable.of("r"); + var s = Variable.of("s"); + var person = new Symbol<>("person", 1, Boolean.class, false); + var personView = new KeyOnlyRelationView<>(person); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyRelationView<>(friend); + var called = Dnf.builder("Called").parameters(r, s).clause(friendView.call(r, s)).build(); + var dnf = Dnf.builder("Example") + .parameter(p) + .clause( + personView.call(p), + personView.call(q), + not(called.call(p, q)) + ) + .build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example(p) <-> + @RelationView("key") person(p), + @RelationView("key") person(q), + !(@Dnf Called(p, q)). + """)); + } +} diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToStringTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToStringTest.java deleted file mode 100644 index e6e4bef3..00000000 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToStringTest.java +++ /dev/null @@ -1,172 +0,0 @@ -package tools.refinery.store.query; - -import org.junit.jupiter.api.Test; -import tools.refinery.store.query.view.KeyOnlyRelationView; -import tools.refinery.store.representation.Symbol; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static tools.refinery.store.query.literal.Literals.not; - -class DnfToStringTest { - @Test - void noClausesTest() { - var p = new Variable("p"); - var dnf = Dnf.builder("Example").parameter(p).build(); - - assertThat(dnf.toString(), is(""" - pred Example(p) <-> - . - """)); - } - - @Test - void noParametersTest() { - var dnf = Dnf.builder("Example").build(); - - assertThat(dnf.toString(), is(""" - pred Example() <-> - . - """)); - } - - @Test - void emptyClauseTest() { - var p = new Variable("p"); - var dnf = Dnf.builder("Example").parameter(p).clause().build(); - - assertThat(dnf.toString(), is(""" - pred Example(p) <-> - . - """)); - } - - @Test - void relationViewPositiveTest() { - var p = new Variable("p"); - var q = new Variable("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); - var dnf = Dnf.builder("Example").parameter(p).clause(friendView.call(p, q)).build(); - - assertThat(dnf.toString(), is(""" - pred Example(p) <-> - @RelationView("key") friend(p, q). - """)); - } - - @Test - void relationViewNegativeTest() { - var p = new Variable("p"); - var q = new Variable("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); - var dnf = Dnf.builder("Example").parameter(p).clause(not(friendView.call(p, q))).build(); - - assertThat(dnf.toString(), is(""" - pred Example(p) <-> - !(@RelationView("key") friend(p, q)). - """)); - } - - @Test - void relationViewTransitiveTest() { - var p = new Variable("p"); - var q = new Variable("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); - var dnf = Dnf.builder("Example").parameter(p).clause(friendView.callTransitive(p, q)).build(); - - assertThat(dnf.toString(), is(""" - pred Example(p) <-> - @RelationView("key") friend+(p, q). - """)); - } - - @Test - void multipleParametersTest() { - var p = new Variable("p"); - var q = new Variable("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); - var dnf = Dnf.builder("Example").parameters(p, q).clause(friendView.call(p, q)).build(); - - assertThat(dnf.toString(), is(""" - pred Example(p, q) <-> - @RelationView("key") friend(p, q). - """)); - } - - @Test - void multipleLiteralsTest() { - var p = new Variable("p"); - var q = new Variable("q"); - var person = new Symbol<>("person", 1, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); - var dnf = Dnf.builder("Example") - .parameter(p) - .clause( - personView.call(p), - personView.call(q), - friendView.call(p, q) - ) - .build(); - - assertThat(dnf.toString(), is(""" - pred Example(p) <-> - @RelationView("key") person(p), - @RelationView("key") person(q), - @RelationView("key") friend(p, q). - """)); - } - - @Test - void multipleClausesTest() { - var p = new Variable("p"); - var q = new Variable("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); - var dnf = Dnf.builder("Example") - .parameter(p) - .clause(friendView.call(p, q)) - .clause(friendView.call(q, p)) - .build(); - - assertThat(dnf.toString(), is(""" - pred Example(p) <-> - @RelationView("key") friend(p, q) - ; - @RelationView("key") friend(q, p). - """)); - } - - @Test - void dnfTest() { - var p = new Variable("p"); - var q = new Variable("q"); - var r = new Variable("r"); - var s = new Variable("s"); - var person = new Symbol<>("person", 1, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); - var called = Dnf.builder("Called").parameters(r, s).clause(friendView.call(r, s)).build(); - var dnf = Dnf.builder("Example") - .parameter(p) - .clause( - personView.call(p), - personView.call(q), - not(called.call(p, q)) - ) - .build(); - - assertThat(dnf.toString(), is(""" - pred Example(p) <-> - @RelationView("key") person(p), - @RelationView("key") person(q), - !(@Dnf Called(p, q)). - """)); - } -} diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java index 0cda22df..a61e2b65 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java @@ -1,8 +1,8 @@ package tools.refinery.store.query.tests; import org.junit.jupiter.api.Test; -import tools.refinery.store.query.Dnf; -import tools.refinery.store.query.Variable; +import tools.refinery.store.query.dnf.Dnf; +import tools.refinery.store.query.term.Variable; import tools.refinery.store.query.view.KeyOnlyRelationView; import tools.refinery.store.representation.Symbol; @@ -14,8 +14,8 @@ import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo class StructurallyEqualToTest { @Test void flatEqualsTest() { - var p = new Variable("p"); - var q = new Variable("q"); + var p = Variable.of("p"); + var q = Variable.of("q"); var person = new Symbol<>("Person", 1, Boolean.class, false); var personView = new KeyOnlyRelationView<>(person); @@ -27,8 +27,8 @@ class StructurallyEqualToTest { @Test void flatNotEqualsTest() { - var p = new Variable("p"); - var q = new Variable("q"); + var p = Variable.of("p"); + var q = Variable.of("q"); var person = new Symbol<>("Person", 1, Boolean.class, false); var personView = new KeyOnlyRelationView<>(person); @@ -41,8 +41,8 @@ class StructurallyEqualToTest { @Test void deepEqualsTest() { - var p = new Variable("p"); - var q = new Variable("q"); + var p = Variable.of("p"); + var q = Variable.of("q"); var person = new Symbol<>("Person", 1, Boolean.class, false); var personView = new KeyOnlyRelationView<>(person); @@ -58,8 +58,8 @@ class StructurallyEqualToTest { @Test void deepNotEqualsTest() { - var p = new Variable("p"); - var q = new Variable("q"); + var p = Variable.of("p"); + var q = Variable.of("q"); var person = new Symbol<>("Person", 1, Boolean.class, false); var personView = new KeyOnlyRelationView<>(person); @@ -72,6 +72,6 @@ class StructurallyEqualToTest { var assertion = structurallyEqualTo(expected); var error = assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); - assertThat(error.getMessage(), containsString(" called from Expected ")); + assertThat(error.getMessage(), containsString(" called from Expected/1 ")); } } diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java index aaab2e7e..685957c9 100644 --- a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java +++ b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java @@ -30,14 +30,14 @@ class MismatchDescribingDnfEqualityChecker extends DeepDnfEqualityChecker { var inProgress = getInProgress(); int size = inProgress.size(); if (size <= 1) { - description.appendText("was ").appendValue(pair.left()); + description.appendText("was ").appendText(pair.left().toDefinitionString()); return; } var last = inProgress.get(size - 1); - description.appendText("expected ").appendValue(last.right()); + description.appendText("expected ").appendText(last.right().toDefinitionString()); for (int i = size - 2; i >= 0; i--) { - description.appendText(" called from ").appendText(inProgress.get(i).left().name()); + description.appendText(" called from ").appendText(inProgress.get(i).left().toString()); } - description.appendText(" was not structurally equal to ").appendValue(last.right()); + description.appendText(" was not structurally equal to ").appendText(last.right().toDefinitionString()); } } diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java index 83614278..bf1c1b74 100644 --- a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java +++ b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java @@ -1,7 +1,7 @@ package tools.refinery.store.query.tests; import org.hamcrest.Matcher; -import tools.refinery.store.query.Dnf; +import tools.refinery.store.query.dnf.Dnf; public final class QueryMatchers { private QueryMatchers() { diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java index a42396dd..a9a78f88 100644 --- a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java +++ b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java @@ -2,7 +2,7 @@ package tools.refinery.store.query.tests; import org.hamcrest.Description; import org.hamcrest.TypeSafeMatcher; -import tools.refinery.store.query.Dnf; +import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.query.equality.DeepDnfEqualityChecker; public class StructurallyEqualTo extends TypeSafeMatcher { @@ -31,6 +31,6 @@ public class StructurallyEqualTo extends TypeSafeMatcher { @Override public void describeTo(Description description) { - description.appendText("structurally equal to ").appendValue(expected); + description.appendText("structurally equal to ").appendText(expected.toDefinitionString()); } } diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/PartialInterpretation.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/PartialInterpretation.java index 99656da8..4f195e97 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/PartialInterpretation.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/PartialInterpretation.java @@ -12,8 +12,6 @@ public non-sealed interface PartialInterpretation extends AnyPartialInterp Cursor getAll(); - Cursor getAllErrors(); - MergeResult merge(Tuple key, A value); C getConcrete(Tuple key); diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java index e602242e..de039dd9 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java @@ -3,7 +3,7 @@ package tools.refinery.store.reasoning; import tools.refinery.store.adapter.ModelAdapter; import tools.refinery.store.reasoning.representation.AnyPartialSymbol; import tools.refinery.store.reasoning.representation.PartialSymbol; -import tools.refinery.store.query.Dnf; +import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.query.ResultSet; public interface ReasoningAdapter extends ModelAdapter { diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java index 588c2711..4030d296 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java @@ -3,7 +3,7 @@ package tools.refinery.store.reasoning; import tools.refinery.store.adapter.ModelAdapterBuilder; import tools.refinery.store.model.ModelStore; import tools.refinery.store.reasoning.literal.Modality; -import tools.refinery.store.query.Dnf; +import tools.refinery.store.query.dnf.Dnf; import java.util.Collection; import java.util.List; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningStoreAdapter.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningStoreAdapter.java index 69c0f5eb..f6a6e414 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningStoreAdapter.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningStoreAdapter.java @@ -3,7 +3,7 @@ package tools.refinery.store.reasoning; import tools.refinery.store.adapter.ModelStoreAdapter; import tools.refinery.store.model.Model; import tools.refinery.store.reasoning.representation.AnyPartialSymbol; -import tools.refinery.store.query.Dnf; +import tools.refinery.store.query.dnf.Dnf; import java.util.Collection; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java index a7a56680..0acf0d49 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java @@ -4,7 +4,7 @@ import tools.refinery.store.model.Model; import tools.refinery.store.reasoning.ReasoningAdapter; import tools.refinery.store.reasoning.PartialInterpretation; import tools.refinery.store.reasoning.representation.PartialSymbol; -import tools.refinery.store.query.Dnf; +import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.query.ResultSet; public class ReasoningAdapterImpl implements ReasoningAdapter { diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java index 2860e2b9..e11b14bf 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java @@ -5,7 +5,7 @@ import tools.refinery.store.model.ModelStore; import tools.refinery.store.model.ModelStoreBuilder; import tools.refinery.store.reasoning.ReasoningBuilder; import tools.refinery.store.reasoning.literal.Modality; -import tools.refinery.store.query.Dnf; +import tools.refinery.store.query.dnf.Dnf; public class ReasoningBuilderImpl extends AbstractModelAdapterBuilder implements ReasoningBuilder { public ReasoningBuilderImpl(ModelStoreBuilder storeBuilder) { diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningStoreAdapterImpl.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningStoreAdapterImpl.java index 763dad6d..ac06e68b 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningStoreAdapterImpl.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningStoreAdapterImpl.java @@ -4,7 +4,7 @@ import tools.refinery.store.reasoning.ReasoningStoreAdapter; import tools.refinery.store.model.Model; import tools.refinery.store.model.ModelStore; import tools.refinery.store.reasoning.representation.AnyPartialSymbol; -import tools.refinery.store.query.Dnf; +import tools.refinery.store.query.dnf.Dnf; import java.util.Collection; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java index 966e080a..2b0e0f08 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java @@ -1,18 +1,18 @@ package tools.refinery.store.reasoning.lifting; import org.jetbrains.annotations.Nullable; -import tools.refinery.store.reasoning.literal.ModalDnfCallLiteral; -import tools.refinery.store.reasoning.Reasoning; -import tools.refinery.store.reasoning.literal.ModalRelationLiteral; -import tools.refinery.store.reasoning.literal.PartialRelationLiteral; -import tools.refinery.store.query.Dnf; -import tools.refinery.store.query.DnfBuilder; -import tools.refinery.store.query.DnfClause; -import tools.refinery.store.query.Variable; +import tools.refinery.store.query.dnf.Dnf; +import tools.refinery.store.query.dnf.DnfBuilder; +import tools.refinery.store.query.dnf.DnfClause; +import tools.refinery.store.query.literal.CallLiteral; import tools.refinery.store.query.literal.CallPolarity; -import tools.refinery.store.query.literal.DnfCallLiteral; import tools.refinery.store.query.literal.Literal; +import tools.refinery.store.query.term.DataVariable; +import tools.refinery.store.query.term.Variable; +import tools.refinery.store.reasoning.Reasoning; +import tools.refinery.store.reasoning.literal.ModalConstraint; import tools.refinery.store.reasoning.literal.Modality; +import tools.refinery.store.reasoning.literal.PartialLiterals; import tools.refinery.store.util.CycleDetectingMapper; import java.util.ArrayList; @@ -46,7 +46,10 @@ public class DnfLifter { private boolean liftClause(Modality modality, DnfClause clause, DnfBuilder builder) { boolean changed = false; - var quantifiedVariables = new HashSet<>(clause.quantifiedVariables()); + var quantifiedVariables = new HashSet<>(clause.boundVariables() + .stream() + .filter(DataVariable.class::isInstance) + .toList()); var literals = clause.literals(); var liftedLiterals = new ArrayList(literals.size()); for (var literal : literals) { @@ -65,8 +68,8 @@ public class DnfLifter { } } for (var quantifiedVariable : quantifiedVariables) { - // Quantify over variables that are not already quantified with the expected modality. - liftedLiterals.add(Reasoning.EXISTS.call(CallPolarity.POSITIVE, modality, + // Quantify over data variables that are not already quantified with the expected modality. + liftedLiterals.add(new CallLiteral(CallPolarity.POSITIVE, new ModalConstraint(modality, Reasoning.EXISTS), List.of(quantifiedVariable))); } builder.clause(liftedLiterals); @@ -75,33 +78,39 @@ public class DnfLifter { @Nullable private Variable isExistsLiteralForVariable(Modality modality, Literal literal) { - if (literal instanceof ModalRelationLiteral modalRelationLiteral && - modalRelationLiteral.getPolarity() == CallPolarity.POSITIVE && - modalRelationLiteral.getModality() == modality && - modalRelationLiteral.getTarget().equals(Reasoning.EXISTS)) { - return modalRelationLiteral.getArguments().get(0); + if (literal instanceof CallLiteral callLiteral && + callLiteral.getPolarity() == CallPolarity.POSITIVE && + callLiteral.getTarget() instanceof ModalConstraint modalConstraint && + modalConstraint.modality() == modality && + modalConstraint.constraint().equals(Reasoning.EXISTS)) { + return callLiteral.getArguments().get(0); } return null; } @Nullable private Literal liftLiteral(Modality modality, Literal literal) { - if (literal instanceof PartialRelationLiteral partialRelationLiteral) { - return new ModalRelationLiteral(modality, partialRelationLiteral); - } else if (literal instanceof DnfCallLiteral dnfCallLiteral) { - var polarity = dnfCallLiteral.getPolarity(); - var target = dnfCallLiteral.getTarget(); - var liftedTarget = lift(modality.commute(polarity), target); - if (target.equals(liftedTarget)) { - return null; + if (!(literal instanceof CallLiteral callLiteral)) { + return null; + } + var target = callLiteral.getTarget(); + if (target instanceof ModalConstraint modalTarget) { + var actualTarget = modalTarget.constraint(); + if (actualTarget instanceof Dnf dnf) { + var targetModality = modalTarget.modality(); + var liftedTarget = lift(targetModality, dnf); + return new CallLiteral(callLiteral.getPolarity(), liftedTarget, callLiteral.getArguments()); } - return new DnfCallLiteral(polarity, liftedTarget, dnfCallLiteral.getArguments()); - } else if (literal instanceof ModalDnfCallLiteral modalDnfCallLiteral) { - var liftedTarget = lift(modalDnfCallLiteral.getModality(), modalDnfCallLiteral.getTarget()); - return new DnfCallLiteral(modalDnfCallLiteral.getPolarity(), liftedTarget, - modalDnfCallLiteral.getArguments()); - } else { + // No more lifting to be done, pass any modal call to a partial symbol through. return null; + } else if (target instanceof Dnf dnf) { + var polarity = callLiteral.getPolarity(); + var liftedTarget = lift(modality.commute(polarity), dnf); + // Use == instead of equals(), because lift will return the same object by reference is there are no + // changes made during lifting. + return liftedTarget == target ? null : new CallLiteral(polarity, liftedTarget, callLiteral.getArguments()); + } else { + return PartialLiterals.addModality(callLiteral, modality); } } } diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/ModalDnf.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/ModalDnf.java index 7aa98bf2..ec381bb8 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/ModalDnf.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/ModalDnf.java @@ -1,9 +1,9 @@ package tools.refinery.store.reasoning.lifting; -import tools.refinery.store.query.Dnf; +import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.reasoning.literal.Modality; -public record ModalDnf(Modality modality, Dnf dnf) { +record ModalDnf(Modality modality, Dnf dnf) { @Override public String toString() { return "%s %s".formatted(modality, dnf.name()); diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java new file mode 100644 index 00000000..2fbb4607 --- /dev/null +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java @@ -0,0 +1,46 @@ +package tools.refinery.store.reasoning.literal; + +import tools.refinery.store.query.Constraint; +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.literal.LiteralReduction; +import tools.refinery.store.query.term.Sort; + +import java.util.List; + +public record ModalConstraint(Modality modality, Constraint constraint) implements Constraint { + private static final String FORMAT = "%s %s"; + + @Override + public String name() { + return FORMAT.formatted(modality, constraint.name()); + } + + @Override + public List getSorts() { + return constraint.getSorts(); + } + + @Override + public LiteralReduction getReduction() { + return constraint.getReduction(); + } + + @Override + public boolean equals(LiteralEqualityHelper helper, Constraint other) { + if (getClass() != other.getClass()) { + return false; + } + var otherModalConstraint = (ModalConstraint) other; + return modality == otherModalConstraint.modality && constraint.equals(helper, otherModalConstraint.constraint); + } + + @Override + public String toReferenceString() { + return FORMAT.formatted(modality, constraint.toReferenceString()); + } + + @Override + public String toString() { + return FORMAT.formatted(modality, constraint); + } +} diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalDnfCallLiteral.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalDnfCallLiteral.java deleted file mode 100644 index 1090f1ae..00000000 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalDnfCallLiteral.java +++ /dev/null @@ -1,48 +0,0 @@ -package tools.refinery.store.reasoning.literal; - -import tools.refinery.store.query.Dnf; -import tools.refinery.store.query.Variable; -import tools.refinery.store.query.equality.LiteralEqualityHelper; -import tools.refinery.store.query.literal.CallPolarity; -import tools.refinery.store.query.literal.DnfCallLiteral; -import tools.refinery.store.query.literal.LiteralReduction; -import tools.refinery.store.query.literal.PolarLiteral; -import tools.refinery.store.query.substitution.Substitution; - -import java.util.List; - -public class ModalDnfCallLiteral extends ModalLiteral implements PolarLiteral { - public ModalDnfCallLiteral(CallPolarity polarity, Modality modality, Dnf target, List arguments) { - super(polarity, modality, target, arguments); - } - - public ModalDnfCallLiteral(Modality modality, DnfCallLiteral baseLiteral) { - super(modality.commute(baseLiteral.getPolarity()), baseLiteral); - } - - @Override - public Class getTargetType() { - return Dnf.class; - } - - @Override - protected boolean targetEquals(LiteralEqualityHelper helper, Dnf otherTarget) { - return helper.dnfEqual(getTarget(), otherTarget); - } - - @Override - public ModalDnfCallLiteral substitute(Substitution substitution) { - return new ModalDnfCallLiteral(getPolarity(), getModality(), getTarget(), substituteArguments(substitution)); - } - - @Override - public ModalDnfCallLiteral negate() { - return new ModalDnfCallLiteral(getPolarity().negate(), getModality(), getTarget(), getArguments()); - } - - @Override - public LiteralReduction getReduction() { - var dnfReduction = getTarget().getReduction(); - return getPolarity().isPositive() ? dnfReduction : dnfReduction.negate(); - } -} diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalLiteral.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalLiteral.java deleted file mode 100644 index 5992f172..00000000 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalLiteral.java +++ /dev/null @@ -1,63 +0,0 @@ -package tools.refinery.store.reasoning.literal; - -import tools.refinery.store.query.RelationLike; -import tools.refinery.store.query.Variable; -import tools.refinery.store.query.equality.LiteralEqualityHelper; -import tools.refinery.store.query.literal.CallLiteral; -import tools.refinery.store.query.literal.CallPolarity; -import tools.refinery.store.query.literal.Literal; - -import java.util.List; -import java.util.Objects; - -public abstract class ModalLiteral extends CallLiteral { - private final Modality modality; - - protected ModalLiteral(CallPolarity polarity, Modality modality, T target, List arguments) { - super(polarity, target, arguments); - this.modality = modality; - } - - protected ModalLiteral(Modality modality, CallLiteral baseLiteral) { - this(baseLiteral.getPolarity(), commute(modality, baseLiteral.getPolarity()), baseLiteral.getTarget(), - baseLiteral.getArguments()); - } - - public Modality getModality() { - return modality; - } - - @Override - public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) { - if (!super.equalsWithSubstitution(helper, other)) { - return false; - } - // If {@link CallLiteral#equalsWithSubstitution(LiteralEqualityHelper, Literal)} has returned {@code true}, - // we must have the same dynamic type as {@code other}. - var otherModalLiteral = (ModalLiteral) other; - return modality == otherModalLiteral.modality; - } - - @Override - protected String targetToString() { - return "%s %s".formatted(modality, super.targetToString()); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - ModalLiteral that = (ModalLiteral) o; - return modality == that.modality; - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), modality); - } - - private static Modality commute(Modality modality, CallPolarity polarity) { - return polarity.isPositive() ? modality : modality.negate(); - } -} diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalRelationLiteral.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalRelationLiteral.java deleted file mode 100644 index 9c72bd37..00000000 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalRelationLiteral.java +++ /dev/null @@ -1,37 +0,0 @@ -package tools.refinery.store.reasoning.literal; - -import tools.refinery.store.reasoning.representation.PartialRelation; -import tools.refinery.store.query.Variable; -import tools.refinery.store.query.literal.CallPolarity; -import tools.refinery.store.query.literal.PolarLiteral; -import tools.refinery.store.query.substitution.Substitution; - -import java.util.List; - -public final class ModalRelationLiteral extends ModalLiteral - implements PolarLiteral { - public ModalRelationLiteral(CallPolarity polarity, Modality modality, PartialRelation target, - List arguments) { - super(polarity, modality, target, arguments); - } - - - public ModalRelationLiteral(Modality modality, PartialRelationLiteral baseLiteral) { - super(modality, baseLiteral); - } - - @Override - public Class getTargetType() { - return PartialRelation.class; - } - - @Override - public ModalRelationLiteral substitute(Substitution substitution) { - return new ModalRelationLiteral(getPolarity(), getModality(), getTarget(), substituteArguments(substitution)); - } - - @Override - public ModalRelationLiteral negate() { - return new ModalRelationLiteral(getPolarity().negate(), getModality(), getTarget(), getArguments()); - } -} diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/PartialLiterals.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/PartialLiterals.java index 10e4c7f7..f991f87f 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/PartialLiterals.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/PartialLiterals.java @@ -1,33 +1,31 @@ package tools.refinery.store.reasoning.literal; -import tools.refinery.store.query.literal.DnfCallLiteral; +import tools.refinery.store.query.literal.CallLiteral; public final class PartialLiterals { private PartialLiterals() { throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); } - public ModalRelationLiteral may(PartialRelationLiteral literal) { - return new ModalRelationLiteral(Modality.MAY, literal); + public static CallLiteral may(CallLiteral literal) { + return addModality(literal, Modality.MAY); } - public ModalRelationLiteral must(PartialRelationLiteral literal) { - return new ModalRelationLiteral(Modality.MUST, literal); + public static CallLiteral must(CallLiteral literal) { + return addModality(literal, Modality.MUST); } - public ModalRelationLiteral current(PartialRelationLiteral literal) { - return new ModalRelationLiteral(Modality.CURRENT, literal); + public static CallLiteral current(CallLiteral literal) { + return addModality(literal, Modality.CURRENT); } - public ModalDnfCallLiteral may(DnfCallLiteral literal) { - return new ModalDnfCallLiteral(Modality.MAY, literal); - } - - public ModalDnfCallLiteral must(DnfCallLiteral literal) { - return new ModalDnfCallLiteral(Modality.MUST, literal); - } - - public ModalDnfCallLiteral current(DnfCallLiteral literal) { - return new ModalDnfCallLiteral(Modality.CURRENT, literal); + public static CallLiteral addModality(CallLiteral literal, Modality modality) { + var target = literal.getTarget(); + if (target instanceof ModalConstraint) { + throw new IllegalArgumentException("Literal %s already has modality".formatted(literal)); + } + var polarity = literal.getPolarity(); + var modalTarget = new ModalConstraint(modality.commute(polarity), target); + return new CallLiteral(polarity, modalTarget, literal.getArguments()); } } diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/PartialRelationLiteral.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/PartialRelationLiteral.java deleted file mode 100644 index aff84538..00000000 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/PartialRelationLiteral.java +++ /dev/null @@ -1,32 +0,0 @@ -package tools.refinery.store.reasoning.literal; - -import tools.refinery.store.reasoning.representation.PartialRelation; -import tools.refinery.store.query.Variable; -import tools.refinery.store.query.literal.CallLiteral; -import tools.refinery.store.query.literal.CallPolarity; -import tools.refinery.store.query.literal.PolarLiteral; -import tools.refinery.store.query.substitution.Substitution; - -import java.util.List; - -public final class PartialRelationLiteral extends CallLiteral - implements PolarLiteral { - public PartialRelationLiteral(CallPolarity polarity, PartialRelation target, List substitution) { - super(polarity, target, substitution); - } - - @Override - public Class getTargetType() { - return PartialRelation.class; - } - - @Override - public PartialRelationLiteral substitute(Substitution substitution) { - return new PartialRelationLiteral(getPolarity(), getTarget(), substituteArguments(substitution)); - } - - @Override - public PartialRelationLiteral negate() { - return new PartialRelationLiteral(getPolarity().negate(), getTarget(), getArguments()); - } -} diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialRelation.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialRelation.java index f884f8d6..9bae53a9 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialRelation.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialRelation.java @@ -1,18 +1,16 @@ package tools.refinery.store.reasoning.representation; -import tools.refinery.store.reasoning.literal.Modality; -import tools.refinery.store.reasoning.literal.PartialRelationLiteral; -import tools.refinery.store.reasoning.literal.ModalRelationLiteral; -import tools.refinery.store.query.RelationLike; -import tools.refinery.store.query.Variable; -import tools.refinery.store.query.literal.CallPolarity; +import tools.refinery.store.query.Constraint; +import tools.refinery.store.query.term.NodeSort; +import tools.refinery.store.query.term.Sort; import tools.refinery.store.representation.AbstractDomain; import tools.refinery.store.representation.TruthValue; import tools.refinery.store.representation.TruthValueDomain; +import java.util.Arrays; import java.util.List; -public record PartialRelation(String name, int arity) implements PartialSymbol, RelationLike { +public record PartialRelation(String name, int arity) implements PartialSymbol, Constraint { @Override public AbstractDomain abstractDomain() { return TruthValueDomain.INSTANCE; @@ -28,24 +26,16 @@ public record PartialRelation(String name, int arity) implements PartialSymbol arguments) { - return new ModalRelationLiteral(polarity, modality, this, arguments); - } - - public PartialRelationLiteral call(CallPolarity polarity, List arguments) { - return new PartialRelationLiteral(polarity, this, arguments); - } - - public PartialRelationLiteral call(CallPolarity polarity, Variable... arguments) { - return call(polarity, List.of(arguments)); - } - - public PartialRelationLiteral call(Variable... arguments) { - return call(CallPolarity.POSITIVE, arguments); + @Override + public List getSorts() { + var sorts = new Sort[arity()]; + Arrays.fill(sorts, NodeSort.INSTANCE); + return List.of(sorts); } - public PartialRelationLiteral callTransitive(Variable left, Variable right) { - return call(CallPolarity.TRANSITIVE, List.of(left, right)); + @Override + public String toReferenceString() { + return name; } @Override diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RelationRefinementAction.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RelationRefinementAction.java index c7681b53..e8ed05a3 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RelationRefinementAction.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RelationRefinementAction.java @@ -3,7 +3,7 @@ package tools.refinery.store.reasoning.rule; import tools.refinery.store.reasoning.Reasoning; import tools.refinery.store.reasoning.representation.PartialRelation; import tools.refinery.store.model.Model; -import tools.refinery.store.query.Variable; +import tools.refinery.store.query.term.Variable; import tools.refinery.store.representation.TruthValue; import tools.refinery.store.tuple.Tuple; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/Rule.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/Rule.java index 8a812518..c7b16d47 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/Rule.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/Rule.java @@ -1,7 +1,7 @@ package tools.refinery.store.reasoning.rule; import tools.refinery.store.model.Model; -import tools.refinery.store.query.Dnf; +import tools.refinery.store.query.dnf.Dnf; import java.util.ArrayList; import java.util.HashSet; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleAction.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleAction.java index bf980759..4753b8bc 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleAction.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleAction.java @@ -1,7 +1,7 @@ package tools.refinery.store.reasoning.rule; import tools.refinery.store.model.Model; -import tools.refinery.store.query.Variable; +import tools.refinery.store.query.term.Variable; import java.util.List; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java index 042c2636..90633495 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java @@ -1,4 +1,4 @@ -package tools.refinery.store.reasoning.translator; +package tools.refinery.store.reasoning.seed; import tools.refinery.store.map.Cursor; import tools.refinery.store.tuple.Tuple; @@ -6,7 +6,7 @@ import tools.refinery.store.tuple.Tuple; public interface Seed { int arity(); - T getReducedValue(); + T reducedValue(); T get(Tuple key); diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/UniformSeed.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/UniformSeed.java new file mode 100644 index 00000000..a030f6ea --- /dev/null +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/UniformSeed.java @@ -0,0 +1,22 @@ +package tools.refinery.store.reasoning.seed; + +import tools.refinery.store.map.Cursor; +import tools.refinery.store.tuple.Tuple; + +public record UniformSeed(int arity, T reducedValue) implements Seed { + public UniformSeed { + if (arity < 0) { + throw new IllegalArgumentException("Arity must not be negative"); + } + } + + @Override + public T get(Tuple key) { + return reducedValue; + } + + @Override + public Cursor getCursor(T defaultValue, int nodeCount) { + return null; + } +} diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java index 7909a7e1..5cdfedf7 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java @@ -2,7 +2,7 @@ package tools.refinery.store.reasoning.translator; import tools.refinery.store.reasoning.representation.AnyPartialSymbol; import tools.refinery.store.reasoning.representation.PartialRelation; -import tools.refinery.store.query.Variable; +import tools.refinery.store.query.term.Variable; import tools.refinery.store.query.literal.Literal; import tools.refinery.store.query.substitution.Substitutions; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslatedRelation.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslatedRelation.java new file mode 100644 index 00000000..9bab80c9 --- /dev/null +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslatedRelation.java @@ -0,0 +1,22 @@ +package tools.refinery.store.reasoning.translator; + +import tools.refinery.store.model.Model; +import tools.refinery.store.query.term.Variable; +import tools.refinery.store.query.literal.CallPolarity; +import tools.refinery.store.query.literal.Literal; +import tools.refinery.store.reasoning.PartialInterpretation; +import tools.refinery.store.reasoning.literal.Modality; +import tools.refinery.store.reasoning.representation.PartialRelation; +import tools.refinery.store.representation.TruthValue; + +import java.util.List; + +public interface TranslatedRelation { + PartialRelation getSource(); + + void configure(List advices); + + List call(CallPolarity polarity, Modality modality, List arguments); + + PartialInterpretation createPartialInterpretation(Model model); +} diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslationUnit.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslationUnit.java index e45d20c8..24b93911 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslationUnit.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslationUnit.java @@ -1,48 +1,32 @@ package tools.refinery.store.reasoning.translator; -import tools.refinery.store.reasoning.ReasoningBuilder; import tools.refinery.store.model.Model; import tools.refinery.store.model.ModelStoreBuilder; -import tools.refinery.store.reasoning.AnyPartialInterpretation; -import tools.refinery.store.reasoning.literal.Modality; -import tools.refinery.store.reasoning.representation.AnyPartialSymbol; -import tools.refinery.store.reasoning.representation.PartialRelation; -import tools.refinery.store.query.Variable; -import tools.refinery.store.query.literal.CallPolarity; -import tools.refinery.store.query.literal.Literal; +import tools.refinery.store.reasoning.ReasoningBuilder; import java.util.Collection; -import java.util.List; -import java.util.Map; public abstract class TranslationUnit { private ReasoningBuilder reasoningBuilder; - protected ReasoningBuilder getPartialInterpretationBuilder() { + protected ReasoningBuilder getReasoningBuilder() { return reasoningBuilder; } public void setPartialInterpretationBuilder(ReasoningBuilder reasoningBuilder) { this.reasoningBuilder = reasoningBuilder; + configureReasoningBuilder(); } protected ModelStoreBuilder getModelStoreBuilder() { return reasoningBuilder.getStoreBuilder(); } - public abstract Collection getTranslatedPartialSymbols(); - - public Collection computeAdvices() { - // No advices to give by default. - return List.of(); + protected void configureReasoningBuilder() { + // Nothing to configure by default. } - public abstract void configure(Collection advices); - - public abstract List call(CallPolarity polarity, Modality modality, PartialRelation target, - List arguments); - - public abstract Map createPartialInterpretations(Model model); + public abstract Collection getTranslatedRelations(); public abstract void initializeModel(Model model, int nodeCount); } diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionInterpretation.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionInterpretation.java new file mode 100644 index 00000000..b703f142 --- /dev/null +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionInterpretation.java @@ -0,0 +1,88 @@ +package tools.refinery.store.reasoning.translator.base; + +import tools.refinery.store.map.Cursor; +import tools.refinery.store.model.Interpretation; +import tools.refinery.store.query.ResultSet; +import tools.refinery.store.reasoning.MergeResult; +import tools.refinery.store.reasoning.PartialInterpretation; +import tools.refinery.store.reasoning.ReasoningAdapter; +import tools.refinery.store.reasoning.representation.PartialRelation; +import tools.refinery.store.representation.TruthValue; +import tools.refinery.store.tuple.Tuple; + +public class BaseDecisionInterpretation implements PartialInterpretation { + private final ReasoningAdapter reasoningAdapter; + private PartialRelation partialRelation; + private final ResultSet mustResultSet; + private final ResultSet mayResultSet; + private final ResultSet errorResultSet; + private final ResultSet currentResultSet; + private final Interpretation interpretation; + + public BaseDecisionInterpretation(ReasoningAdapter reasoningAdapter, ResultSet mustResultSet, + ResultSet mayResultSet, ResultSet errorResultSet, + ResultSet currentResultSet, Interpretation interpretation) { + this.reasoningAdapter = reasoningAdapter; + this.mustResultSet = mustResultSet; + this.mayResultSet = mayResultSet; + this.errorResultSet = errorResultSet; + this.currentResultSet = currentResultSet; + this.interpretation = interpretation; + } + + @Override + public ReasoningAdapter getAdapter() { + return reasoningAdapter; + } + + @Override + public int countUnfinished() { + return 0; + } + + @Override + public int countErrors() { + return errorResultSet.size(); + } + + @Override + public PartialRelation getPartialSymbol() { + return partialRelation; + } + + @Override + public TruthValue get(Tuple key) { + return null; + } + + @Override + public Cursor getAll() { + return null; + } + + @Override + public MergeResult merge(Tuple key, TruthValue value) { + TruthValue newValue; + switch (value) { + case UNKNOWN -> { + return MergeResult.UNCHANGED; + } + case TRUE -> newValue = mayResultSet.get(key) ? TruthValue.TRUE : TruthValue.ERROR; + case FALSE -> newValue = mustResultSet.get(key) ? TruthValue.ERROR : TruthValue.FALSE; + case ERROR -> newValue = TruthValue.ERROR; + default -> throw new IllegalArgumentException("Unknown truth value: " + value); + } + var oldValue = interpretation.put(key, newValue); + return oldValue == TruthValue.ERROR ? MergeResult.UNCHANGED : MergeResult.REFINED; + } + + @Override + public Boolean getConcrete(Tuple key) { + return currentResultSet.get(key); + } + + @Override + public Cursor getAllConcrete() { + return null; + } +} diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionTranslationUnit.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionTranslationUnit.java new file mode 100644 index 00000000..36e2782a --- /dev/null +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionTranslationUnit.java @@ -0,0 +1,49 @@ +package tools.refinery.store.reasoning.translator.base; + +import tools.refinery.store.model.Model; +import tools.refinery.store.reasoning.representation.PartialRelation; +import tools.refinery.store.reasoning.seed.Seed; +import tools.refinery.store.reasoning.seed.UniformSeed; +import tools.refinery.store.reasoning.translator.TranslatedRelation; +import tools.refinery.store.reasoning.translator.TranslationUnit; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.representation.TruthValue; + +import java.util.Collection; +import java.util.List; + +public class BaseDecisionTranslationUnit extends TranslationUnit { + private final PartialRelation partialRelation; + private final Seed seed; + private final Symbol symbol; + + public BaseDecisionTranslationUnit(PartialRelation partialRelation, Seed seed) { + if (seed.arity() != partialRelation.arity()) { + throw new IllegalArgumentException("Expected seed with arity %d for %s, got arity %s" + .formatted(partialRelation.arity(), partialRelation, seed.arity())); + } + this.partialRelation = partialRelation; + this.seed = seed; + symbol = new Symbol<>(partialRelation.name(), partialRelation.arity(), TruthValue.class, TruthValue.UNKNOWN); + } + + public BaseDecisionTranslationUnit(PartialRelation partialRelation) { + this(partialRelation, new UniformSeed<>(partialRelation.arity(), TruthValue.UNKNOWN)); + } + + @Override + protected void configureReasoningBuilder() { + getModelStoreBuilder().symbol(symbol); + } + + @Override + public Collection getTranslatedRelations() { + return List.of(new TranslatedBaseDecision(getReasoningBuilder(), partialRelation, symbol)); + } + + @Override + public void initializeModel(Model model, int nodeCount) { + var interpretation = model.getInterpretation(symbol); + interpretation.putAll(seed.getCursor(TruthValue.UNKNOWN, nodeCount)); + } +} diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/TranslatedBaseDecision.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/TranslatedBaseDecision.java new file mode 100644 index 00000000..2294b4fd --- /dev/null +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/TranslatedBaseDecision.java @@ -0,0 +1,49 @@ +package tools.refinery.store.reasoning.translator.base; + +import tools.refinery.store.model.Model; +import tools.refinery.store.query.term.Variable; +import tools.refinery.store.query.literal.CallPolarity; +import tools.refinery.store.query.literal.Literal; +import tools.refinery.store.reasoning.PartialInterpretation; +import tools.refinery.store.reasoning.ReasoningBuilder; +import tools.refinery.store.reasoning.literal.Modality; +import tools.refinery.store.reasoning.representation.PartialRelation; +import tools.refinery.store.reasoning.translator.Advice; +import tools.refinery.store.reasoning.translator.TranslatedRelation; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.representation.TruthValue; + +import java.util.List; + +class TranslatedBaseDecision implements TranslatedRelation { + private final ReasoningBuilder reasoningBuilder; + private final PartialRelation partialRelation; + private final Symbol symbol; + + public TranslatedBaseDecision(ReasoningBuilder reasoningBuilder, PartialRelation partialRelation, + Symbol symbol) { + this.reasoningBuilder = reasoningBuilder; + this.partialRelation = partialRelation; + this.symbol = symbol; + } + + @Override + public PartialRelation getSource() { + return partialRelation; + } + + @Override + public void configure(List advices) { + + } + + @Override + public List call(CallPolarity polarity, Modality modality, List arguments) { + return null; + } + + @Override + public PartialInterpretation createPartialInterpretation(Model model) { + return null; + } +} diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslationUnit.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslationUnit.java index c800b4cd..4b0761f2 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslationUnit.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslationUnit.java @@ -1,18 +1,14 @@ package tools.refinery.store.reasoning.translator.typehierarchy; -import tools.refinery.store.reasoning.AnyPartialInterpretation; -import tools.refinery.store.reasoning.literal.Modality; -import tools.refinery.store.reasoning.representation.AnyPartialSymbol; +import tools.refinery.store.model.Model; import tools.refinery.store.reasoning.representation.PartialRelation; -import tools.refinery.store.reasoning.translator.Advice; +import tools.refinery.store.reasoning.translator.TranslatedRelation; import tools.refinery.store.reasoning.translator.TranslationUnit; -import tools.refinery.store.model.Model; -import tools.refinery.store.query.Variable; -import tools.refinery.store.query.literal.CallPolarity; -import tools.refinery.store.query.literal.Literal; import tools.refinery.store.representation.Symbol; -import java.util.*; +import java.util.Collection; +import java.util.List; +import java.util.Map; public class TypeHierarchyTranslationUnit extends TranslationUnit { static final Symbol INFERRED_TYPE_SYMBOL = new Symbol<>("inferredType", 1, @@ -25,24 +21,8 @@ public class TypeHierarchyTranslationUnit extends TranslationUnit { } @Override - public Collection getTranslatedPartialSymbols() { - return null; - } - - @Override - public void configure(Collection advices) { - - } - - @Override - public List call(CallPolarity polarity, Modality modality, PartialRelation target, - List arguments) { - return null; - } - - @Override - public Map createPartialInterpretations(Model model) { - return null; + public Collection getTranslatedRelations() { + return List.of(); } @Override diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleLike.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleLike.java index 470ca298..953ea9f8 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleLike.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleLike.java @@ -1,5 +1,8 @@ package tools.refinery.store.tuple; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + public interface TupleLike { int getSize(); @@ -22,4 +25,11 @@ public interface TupleLike { default -> Tuple.of(toArray()); }; } + + static String toString(TupleLike tuple) { + var valuesString = IntStream.range(0, tuple.getSize()) + .mapToObj(i -> Integer.toString(tuple.get(i))) + .collect(Collectors.joining(", ")); + return "[" + valuesString + "]"; + } } diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java index 15fd063b..c3aed847 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java @@ -1,7 +1,6 @@ package tools.refinery.store.tuple; import java.util.Arrays; -import java.util.stream.Collectors; public record TupleN(int[] values) implements Tuple { static final int CUSTOM_TUPLE_SIZE = 2; @@ -29,8 +28,7 @@ public record TupleN(int[] values) implements Tuple { @Override public String toString() { - var valuesString = Arrays.stream(values).mapToObj(Integer::toString).collect(Collectors.joining(", ")); - return "[" + valuesString + "]"; + return TupleLike.toString(this); } @Override -- cgit v1.2.3-70-g09d2 From 6ae4346b6248198cb687a9cbbeba3bfb9c37c4b5 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Fri, 7 Apr 2023 19:49:23 +0200 Subject: refactor: remove TupleLike * Directly transform VIATRA tuples into Refinery tuples, since creating the additional wrapper object doesn't save any memory. * Adds static arity Tuple3 and Tuple4 implementations to be more aligned with VIATRA internals and save memory for queries with up to 4 parameters. * Makes sure no new objects are allocated (for varargs handling) when a static arity tuple is hashed. --- .../viatra/internal/matcher/FunctionalCursor.java | 13 +- .../internal/matcher/FunctionalViatraMatcher.java | 6 +- .../viatra/internal/matcher/MatcherUtils.java | 84 ++++++-- .../matcher/OmitOutputViatraTupleLike.java | 23 -- .../viatra/internal/matcher/RelationalCursor.java | 10 +- .../internal/matcher/RelationalViatraMatcher.java | 7 +- .../internal/matcher/UnsafeFunctionalCursor.java | 10 +- .../viatra/internal/matcher/ViatraTupleLike.java | 23 -- .../viatra/internal/matcher/MatcherUtilsTest.java | 234 +++++++++++++++++++++ .../store/query/viatra/tests/QueryAssertions.java | 2 +- .../tools/refinery/store/query/EmptyResultSet.java | 7 +- .../java/tools/refinery/store/query/ResultSet.java | 6 +- .../store/reasoning/rule/RuleActionExecutor.java | 4 +- .../store/reasoning/rule/RuleExecutor.java | 7 +- .../java/tools/refinery/store/tuple/Tuple.java | 25 ++- .../java/tools/refinery/store/tuple/Tuple0.java | 17 +- .../java/tools/refinery/store/tuple/Tuple1.java | 31 ++- .../java/tools/refinery/store/tuple/Tuple2.java | 20 +- .../java/tools/refinery/store/tuple/Tuple3.java | 41 ++++ .../java/tools/refinery/store/tuple/Tuple4.java | 44 ++++ .../tools/refinery/store/tuple/TupleConstants.java | 12 ++ .../java/tools/refinery/store/tuple/TupleLike.java | 35 --- .../java/tools/refinery/store/tuple/TupleN.java | 35 +-- 23 files changed, 522 insertions(+), 174 deletions(-) delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/OmitOutputViatraTupleLike.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/ViatraTupleLike.java create mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtilsTest.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/tuple/TupleConstants.java delete mode 100644 subprojects/store/src/main/java/tools/refinery/store/tuple/TupleLike.java (limited to 'subprojects/store-query-viatra/src/main/java/tools') diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java index 4daa14a1..52a83f69 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java @@ -1,17 +1,16 @@ package tools.refinery.store.query.viatra.internal.matcher; -import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; import org.eclipse.viatra.query.runtime.rete.index.IterableIndexer; import tools.refinery.store.map.Cursor; -import tools.refinery.store.tuple.TupleLike; +import tools.refinery.store.tuple.Tuple; import java.util.Iterator; -class FunctionalCursor implements Cursor { +class FunctionalCursor implements Cursor { private final IterableIndexer indexer; - private final Iterator iterator; + private final Iterator iterator; private boolean terminated; - private TupleLike key; + private Tuple key; private T value; public FunctionalCursor(IterableIndexer indexer) { @@ -20,7 +19,7 @@ class FunctionalCursor implements Cursor { } @Override - public TupleLike getKey() { + public Tuple getKey() { return key; } @@ -38,7 +37,7 @@ class FunctionalCursor implements Cursor { public boolean move() { if (!terminated && iterator.hasNext()) { var match = iterator.next(); - key = new ViatraTupleLike(match); + key = MatcherUtils.toRefineryTuple(match); value = MatcherUtils.getSingleValue(indexer.get(match)); return true; } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java index 6aa45af2..adb34b8b 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java @@ -11,7 +11,7 @@ import tools.refinery.store.query.ResultSet; import tools.refinery.store.query.dnf.FunctionalQuery; import tools.refinery.store.query.dnf.Query; import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; -import tools.refinery.store.tuple.TupleLike; +import tools.refinery.store.tuple.Tuple; /** * Directly access the tuples inside a VIATRA pattern matcher.

@@ -63,7 +63,7 @@ public class FunctionalViatraMatcher implements ResultSet { } @Override - public T get(TupleLike parameters) { + public T get(Tuple parameters) { var tuple = MatcherUtils.toViatraTuple(parameters); if (omitOutputIndexer == null) { return MatcherUtils.getSingleValue(backend.getAllMatches(omitOutputMask, tuple).iterator()); @@ -73,7 +73,7 @@ public class FunctionalViatraMatcher implements ResultSet { } @Override - public Cursor getAll() { + public Cursor getAll() { if (omitOutputIndexer == null) { var allMatches = backend.getAllMatches(emptyMask, Tuples.staticArityFlatTupleOf()); return new UnsafeFunctionalCursor<>(allMatches.iterator()); diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java index 5d4be95d..d327c537 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java @@ -3,8 +3,7 @@ package tools.refinery.store.query.viatra.internal.matcher; import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; import org.jetbrains.annotations.Nullable; -import tools.refinery.store.tuple.Tuple; -import tools.refinery.store.tuple.TupleLike; +import tools.refinery.store.tuple.*; import java.util.Iterator; @@ -13,25 +12,80 @@ final class MatcherUtils { throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); } - public static org.eclipse.viatra.query.runtime.matchers.tuple.Tuple toViatraTuple(TupleLike tuple) { - if (tuple instanceof ViatraTupleLike viatraTupleLike) { - return viatraTupleLike.wrappedTuple().toImmutable(); + public static org.eclipse.viatra.query.runtime.matchers.tuple.Tuple toViatraTuple(Tuple refineryTuple) { + if (refineryTuple instanceof Tuple0) { + return Tuples.staticArityFlatTupleOf(); + } else if (refineryTuple instanceof Tuple1) { + return Tuples.staticArityFlatTupleOf(refineryTuple); + } else if (refineryTuple instanceof Tuple2 tuple2) { + return Tuples.staticArityFlatTupleOf(Tuple.of(tuple2.value0()), Tuple.of(tuple2.value1())); + } else if (refineryTuple instanceof Tuple3 tuple3) { + return Tuples.staticArityFlatTupleOf(Tuple.of(tuple3.value0()), Tuple.of(tuple3.value1()), + Tuple.of(tuple3.value2())); + } else if (refineryTuple instanceof Tuple4 tuple4) { + return Tuples.staticArityFlatTupleOf(Tuple.of(tuple4.value0()), Tuple.of(tuple4.value1()), + Tuple.of(tuple4.value2()), Tuple.of(tuple4.value3())); + } else { + int arity = refineryTuple.getSize(); + var values = new Object[arity]; + for (int i = 0; i < arity; i++) { + values[i] = Tuple.of(refineryTuple.get(i)); + } + return Tuples.flatTupleOf(values); } - int size = tuple.getSize(); - var array = new Object[size]; - for (int i = 0; i < size; i++) { - var value = tuple.get(i); - array[i] = Tuple.of(value); + } + + public static Tuple toRefineryTuple(ITuple viatraTuple) { + int arity = viatraTuple.getSize(); + if (arity == 1) { + return getWrapper(viatraTuple, 0); } - return Tuples.flatTupleOf(array); + return prefixToRefineryTuple(viatraTuple, viatraTuple.getSize()); + } + + public static Tuple keyToRefineryTuple(ITuple viatraTuple) { + return prefixToRefineryTuple(viatraTuple, viatraTuple.getSize() - 1); } + private static Tuple prefixToRefineryTuple(ITuple viatraTuple, int targetArity) { + if (targetArity < 0) { + throw new IllegalArgumentException("Requested negative prefix %d of %s" + .formatted(targetArity, viatraTuple)); + } + return switch (targetArity) { + case 0 -> Tuple.of(); + case 1 -> Tuple.of(unwrap(viatraTuple, 0)); + case 2 -> Tuple.of(unwrap(viatraTuple, 0), unwrap(viatraTuple, 1)); + case 3 -> Tuple.of(unwrap(viatraTuple, 0), unwrap(viatraTuple, 1), unwrap(viatraTuple, 2)); + case 4 -> Tuple.of(unwrap(viatraTuple, 0), unwrap(viatraTuple, 1), unwrap(viatraTuple, 2), + unwrap(viatraTuple, 3)); + default -> { + var entries = new int[targetArity]; + for (int i = 0; i < targetArity; i++) { + entries[i] = unwrap(viatraTuple, i); + } + yield Tuple.of(entries); + } + }; + } + + private static Tuple1 getWrapper(ITuple viatraTuple, int index) { + if (!((viatraTuple.get(index)) instanceof Tuple1 wrappedObjectId)) { + throw new IllegalArgumentException("Element %d of tuple %s is not an object id" + .formatted(index, viatraTuple)); + } + return wrappedObjectId; + } + + private static int unwrap(ITuple viatraTuple, int index) { + return getWrapper(viatraTuple, index).value0(); + } - public static T getSingleValue(@Nullable Iterable tuples) { - if (tuples == null) { + public static T getSingleValue(@Nullable Iterable viatraTuples) { + if (viatraTuples == null) { return null; } - return getSingleValue(tuples.iterator()); + return getSingleValue(viatraTuples.iterator()); } public static T getSingleValue(Iterator iterator) { @@ -42,7 +96,7 @@ final class MatcherUtils { @SuppressWarnings("unchecked") var result = (T) match.get(match.getSize() - 1); if (iterator.hasNext()) { - var input = new OmitOutputViatraTupleLike(match); + var input = keyToRefineryTuple(match); throw new IllegalStateException("Query is not functional for input tuple: " + input); } return result; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/OmitOutputViatraTupleLike.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/OmitOutputViatraTupleLike.java deleted file mode 100644 index bd9301ba..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/OmitOutputViatraTupleLike.java +++ /dev/null @@ -1,23 +0,0 @@ -package tools.refinery.store.query.viatra.internal.matcher; - -import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; -import tools.refinery.store.tuple.Tuple1; -import tools.refinery.store.tuple.TupleLike; - -record OmitOutputViatraTupleLike(ITuple wrappedTuple) implements TupleLike { - @Override - public int getSize() { - return wrappedTuple.getSize() - 1; - } - - @Override - public int get(int element) { - var wrappedValue = (Tuple1) wrappedTuple.get(element); - return wrappedValue.value0(); - } - - @Override - public String toString() { - return TupleLike.toString(this); - } -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java index c2dcc565..e3df0441 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java @@ -2,21 +2,21 @@ package tools.refinery.store.query.viatra.internal.matcher; import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; import tools.refinery.store.map.Cursor; -import tools.refinery.store.tuple.TupleLike; +import tools.refinery.store.tuple.Tuple; import java.util.Iterator; -class RelationalCursor implements Cursor { +class RelationalCursor implements Cursor { private final Iterator tuplesIterator; private boolean terminated; - private TupleLike key; + private Tuple key; public RelationalCursor(Iterator tuplesIterator) { this.tuplesIterator = tuplesIterator; } @Override - public TupleLike getKey() { + public Tuple getKey() { return key; } @@ -33,7 +33,7 @@ class RelationalCursor implements Cursor { @Override public boolean move() { if (!terminated && tuplesIterator.hasNext()) { - key = new ViatraTupleLike(tuplesIterator.next()); + key = MatcherUtils.toRefineryTuple(tuplesIterator.next()); return true; } terminated = true; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java index b9bc3f1e..9373709d 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java @@ -12,7 +12,7 @@ import tools.refinery.store.query.ResultSet; import tools.refinery.store.query.dnf.Query; import tools.refinery.store.query.dnf.RelationalQuery; import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; -import tools.refinery.store.tuple.TupleLike; +import tools.refinery.store.tuple.Tuple; /** * Directly access the tuples inside a VIATRA pattern matcher.

@@ -58,7 +58,7 @@ public class RelationalViatraMatcher implements ResultSet { } @Override - public Boolean get(TupleLike parameters) { + public Boolean get(Tuple parameters) { var tuple = MatcherUtils.toViatraTuple(parameters); if (emptyMaskIndexer == null) { return backend.hasMatch(identityMask, tuple); @@ -68,7 +68,7 @@ public class RelationalViatraMatcher implements ResultSet { } @Override - public Cursor getAll() { + public Cursor getAll() { if (emptyMaskIndexer == null) { var allMatches = backend.getAllMatches(emptyMask, Tuples.staticArityFlatTupleOf()); return new RelationalCursor(allMatches.iterator()); @@ -85,5 +85,4 @@ public class RelationalViatraMatcher implements ResultSet { var matches = emptyMaskIndexer.get(Tuples.staticArityFlatTupleOf()); return matches == null ? 0 : matches.size(); } - } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java index 6c53fff1..e9540d1d 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java @@ -2,7 +2,7 @@ package tools.refinery.store.query.viatra.internal.matcher; import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; import tools.refinery.store.map.Cursor; -import tools.refinery.store.tuple.TupleLike; +import tools.refinery.store.tuple.Tuple; import java.util.Iterator; @@ -11,10 +11,10 @@ import java.util.Iterator; * functional dependency of the output on the inputs is obeyed. * @param The output type. */ -class UnsafeFunctionalCursor implements Cursor { +class UnsafeFunctionalCursor implements Cursor { private final Iterator tuplesIterator; private boolean terminated; - private TupleLike key; + private Tuple key; private T value; public UnsafeFunctionalCursor(Iterator tuplesIterator) { @@ -22,7 +22,7 @@ class UnsafeFunctionalCursor implements Cursor { } @Override - public TupleLike getKey() { + public Tuple getKey() { return key; } @@ -40,7 +40,7 @@ class UnsafeFunctionalCursor implements Cursor { public boolean move() { if (!terminated && tuplesIterator.hasNext()) { var match = tuplesIterator.next(); - key = new OmitOutputViatraTupleLike(match); + key = MatcherUtils.keyToRefineryTuple(match); @SuppressWarnings("unchecked") var typedValue = (T) match.get(match.getSize() - 1); value = typedValue; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/ViatraTupleLike.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/ViatraTupleLike.java deleted file mode 100644 index 76a3e40b..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/ViatraTupleLike.java +++ /dev/null @@ -1,23 +0,0 @@ -package tools.refinery.store.query.viatra.internal.matcher; - -import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; -import tools.refinery.store.tuple.Tuple1; -import tools.refinery.store.tuple.TupleLike; - -record ViatraTupleLike(ITuple wrappedTuple) implements TupleLike { - @Override - public int getSize() { - return wrappedTuple.getSize(); - } - - @Override - public int get(int element) { - var wrappedValue = (Tuple1) wrappedTuple.get(element); - return wrappedValue.value0(); - } - - @Override - public String toString() { - return TupleLike.toString(this); - } -} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtilsTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtilsTest.java new file mode 100644 index 00000000..ea0b15ec --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtilsTest.java @@ -0,0 +1,234 @@ +package tools.refinery.store.query.viatra.internal.matcher; + +import org.eclipse.viatra.query.runtime.matchers.tuple.*; +import org.junit.jupiter.api.Test; +import tools.refinery.store.tuple.Tuple; +import tools.refinery.store.tuple.*; + +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class MatcherUtilsTest { + @Test + void toViatra0Test() { + var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of()); + assertThat(viatraTuple.getSize(), is(0)); + assertThat(viatraTuple, instanceOf(FlatTuple0.class)); + } + + @Test + void toViatra1Test() { + var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2)); + assertThat(viatraTuple.getSize(), is(1)); + assertThat(viatraTuple.get(0), is(Tuple.of(2))); + assertThat(viatraTuple, instanceOf(FlatTuple1.class)); + } + + @Test + void toViatra2Test() { + var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2, 3)); + assertThat(viatraTuple.getSize(), is(2)); + assertThat(viatraTuple.get(0), is(Tuple.of(2))); + assertThat(viatraTuple.get(1), is(Tuple.of(3))); + assertThat(viatraTuple, instanceOf(FlatTuple2.class)); + } + + @Test + void toViatra3Test() { + var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2, 3, 5)); + assertThat(viatraTuple.getSize(), is(3)); + assertThat(viatraTuple.get(0), is(Tuple.of(2))); + assertThat(viatraTuple.get(1), is(Tuple.of(3))); + assertThat(viatraTuple.get(2), is(Tuple.of(5))); + assertThat(viatraTuple, instanceOf(FlatTuple3.class)); + } + + @Test + void toViatra4Test() { + var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2, 3, 5, 8)); + assertThat(viatraTuple.getSize(), is(4)); + assertThat(viatraTuple.get(0), is(Tuple.of(2))); + assertThat(viatraTuple.get(1), is(Tuple.of(3))); + assertThat(viatraTuple.get(2), is(Tuple.of(5))); + assertThat(viatraTuple.get(3), is(Tuple.of(8))); + assertThat(viatraTuple, instanceOf(FlatTuple4.class)); + } + + @Test + void toViatra5Test() { + var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2, 3, 5, 8, 13)); + assertThat(viatraTuple.getSize(), is(5)); + assertThat(viatraTuple.get(0), is(Tuple.of(2))); + assertThat(viatraTuple.get(1), is(Tuple.of(3))); + assertThat(viatraTuple.get(2), is(Tuple.of(5))); + assertThat(viatraTuple.get(3), is(Tuple.of(8))); + assertThat(viatraTuple.get(4), is(Tuple.of(13))); + assertThat(viatraTuple, instanceOf(FlatTuple.class)); + } + + @Test + void toRefinery0Test() { + var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf()); + assertThat(refineryTuple.getSize(), is(0)); + assertThat(refineryTuple, instanceOf(Tuple0.class)); + } + + @Test + void toRefinery1Test() { + var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2))); + assertThat(refineryTuple.getSize(), is(1)); + assertThat(refineryTuple.get(0), is(2)); + assertThat(refineryTuple, instanceOf(Tuple1.class)); + } + + @Test + void toRefinery2Test() { + var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3))); + assertThat(refineryTuple.getSize(), is(2)); + assertThat(refineryTuple.get(0), is(2)); + assertThat(refineryTuple.get(1), is(3)); + assertThat(refineryTuple, instanceOf(Tuple2.class)); + } + + @Test + void toRefinery3Test() { + var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5))); + assertThat(refineryTuple.getSize(), is(3)); + assertThat(refineryTuple.get(0), is(2)); + assertThat(refineryTuple.get(1), is(3)); + assertThat(refineryTuple.get(2), is(5)); + assertThat(refineryTuple, instanceOf(Tuple3.class)); + } + + @Test + void toRefinery4Test() { + var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5), + Tuple.of(8))); + assertThat(refineryTuple.getSize(), is(4)); + assertThat(refineryTuple.get(0), is(2)); + assertThat(refineryTuple.get(1), is(3)); + assertThat(refineryTuple.get(2), is(5)); + assertThat(refineryTuple.get(3), is(8)); + assertThat(refineryTuple, instanceOf(Tuple4.class)); + } + + @Test + void toRefinery5Test() { + var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5), + Tuple.of(8), Tuple.of(13))); + assertThat(refineryTuple.getSize(), is(5)); + assertThat(refineryTuple.get(0), is(2)); + assertThat(refineryTuple.get(1), is(3)); + assertThat(refineryTuple.get(2), is(5)); + assertThat(refineryTuple.get(3), is(8)); + assertThat(refineryTuple.get(4), is(13)); + assertThat(refineryTuple, instanceOf(TupleN.class)); + } + + @Test + void toRefineryInvalidValueTest() { + var viatraTuple = Tuples.flatTupleOf(Tuple.of(2), -98); + assertThrows(IllegalArgumentException.class, () -> MatcherUtils.toRefineryTuple(viatraTuple)); + } + + @Test + void keyToRefinery0Test() { + var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(-99)); + assertThat(refineryTuple.getSize(), is(0)); + assertThat(refineryTuple, instanceOf(Tuple0.class)); + } + + @Test + void keyToRefinery1Test() { + var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), -99)); + assertThat(refineryTuple.getSize(), is(1)); + assertThat(refineryTuple.get(0), is(2)); + assertThat(refineryTuple, instanceOf(Tuple1.class)); + } + + @Test + void keyToRefinery2Test() { + var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), -99)); + assertThat(refineryTuple.getSize(), is(2)); + assertThat(refineryTuple.get(0), is(2)); + assertThat(refineryTuple.get(1), is(3)); + assertThat(refineryTuple, instanceOf(Tuple2.class)); + } + + @Test + void keyToRefinery3Test() { + var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5), + -99)); + assertThat(refineryTuple.getSize(), is(3)); + assertThat(refineryTuple.get(0), is(2)); + assertThat(refineryTuple.get(1), is(3)); + assertThat(refineryTuple.get(2), is(5)); + assertThat(refineryTuple, instanceOf(Tuple3.class)); + } + + @Test + void keyToRefinery4Test() { + var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5), + Tuple.of(8), -99)); + assertThat(refineryTuple.getSize(), is(4)); + assertThat(refineryTuple.get(0), is(2)); + assertThat(refineryTuple.get(1), is(3)); + assertThat(refineryTuple.get(2), is(5)); + assertThat(refineryTuple.get(3), is(8)); + assertThat(refineryTuple, instanceOf(Tuple4.class)); + } + + @Test + void keyToRefinery5Test() { + var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5), + Tuple.of(8), Tuple.of(13), -99)); + assertThat(refineryTuple.getSize(), is(5)); + assertThat(refineryTuple.get(0), is(2)); + assertThat(refineryTuple.get(1), is(3)); + assertThat(refineryTuple.get(2), is(5)); + assertThat(refineryTuple.get(3), is(8)); + assertThat(refineryTuple.get(4), is(13)); + assertThat(refineryTuple, instanceOf(TupleN.class)); + } + + @Test + void keyToRefineryTooShortTest() { + var viatraTuple = Tuples.flatTupleOf(); + assertThrows(IllegalArgumentException.class, () -> MatcherUtils.keyToRefineryTuple(viatraTuple)); + } + + @Test + void keyToRefineryInvalidValueTest() { + var viatraTuple = Tuples.flatTupleOf(Tuple.of(2), -98, -99); + assertThrows(IllegalArgumentException.class, () -> MatcherUtils.keyToRefineryTuple(viatraTuple)); + } + + @Test + void getSingleValueTest() { + var value = MatcherUtils.getSingleValue(List.of(Tuples.flatTupleOf(Tuple.of(2), -99))); + assertThat(value, is(-99)); + } + + // Static analysis accurately determines that the result is always {@code null}, but we check anyways. + @SuppressWarnings("ConstantValue") + @Test + void getSingleValueNullTest() { + var value = MatcherUtils.getSingleValue((Iterable) null); + assertThat(value, nullValue()); + } + + @Test + void getSingleValueEmptyTest() { + var value = MatcherUtils.getSingleValue(List.of()); + assertThat(value, nullValue()); + } + + @Test + void getSingleValueMultipleTest() { + var viatraTuples = List.of(Tuples.flatTupleOf(Tuple.of(2), -98), Tuples.flatTupleOf(Tuple.of(2), -99)); + assertThrows(IllegalStateException.class, () -> MatcherUtils.getSingleValue(viatraTuples)); + } +} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java index 6f50ec73..2769621d 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java @@ -42,7 +42,7 @@ public final class QueryAssertions { var cursor = resultSet.getAll(); while (cursor.move()) { var key = cursor.getKey(); - var previous = actual.put(key.toTuple(), cursor.getValue()); + var previous = actual.put(key, cursor.getValue()); assertThat("duplicate value for key " + key, previous, nullValue()); } executables.add(() -> assertThat("results cursor", actual, is(filteredExpected))); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java index 9af73bdd..4c8eeab0 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java @@ -3,7 +3,7 @@ package tools.refinery.store.query; import tools.refinery.store.map.Cursor; import tools.refinery.store.map.Cursors; import tools.refinery.store.query.dnf.Query; -import tools.refinery.store.tuple.TupleLike; +import tools.refinery.store.tuple.Tuple; public record EmptyResultSet(ModelQueryAdapter adapter, Query query) implements ResultSet { @Override @@ -17,13 +17,12 @@ public record EmptyResultSet(ModelQueryAdapter adapter, Query query) imple } @Override - public T get(TupleLike parameters) { + public T get(Tuple parameters) { return query.defaultValue(); } - @Override - public Cursor getAll() { + public Cursor getAll() { return Cursors.empty(); } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java index 3f6bc06f..2758c74f 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java @@ -2,12 +2,12 @@ package tools.refinery.store.query; import tools.refinery.store.map.Cursor; import tools.refinery.store.query.dnf.Query; -import tools.refinery.store.tuple.TupleLike; +import tools.refinery.store.tuple.Tuple; public non-sealed interface ResultSet extends AnyResultSet { Query getQuery(); - T get(TupleLike parameters); + T get(Tuple parameters); - Cursor getAll(); + Cursor getAll(); } diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleActionExecutor.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleActionExecutor.java index 80bfa6f8..7c51e3df 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleActionExecutor.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleActionExecutor.java @@ -1,9 +1,9 @@ package tools.refinery.store.reasoning.rule; import tools.refinery.store.reasoning.MergeResult; -import tools.refinery.store.tuple.TupleLike; +import tools.refinery.store.tuple.Tuple; @FunctionalInterface public interface RuleActionExecutor { - MergeResult execute(TupleLike activationTuple); + MergeResult execute(Tuple activationTuple); } diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleExecutor.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleExecutor.java index 1e5322b4..c20645fc 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleExecutor.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleExecutor.java @@ -1,8 +1,8 @@ package tools.refinery.store.reasoning.rule; -import tools.refinery.store.reasoning.MergeResult; import tools.refinery.store.model.Model; -import tools.refinery.store.tuple.TupleLike; +import tools.refinery.store.reasoning.MergeResult; +import tools.refinery.store.tuple.Tuple; import java.util.List; @@ -24,7 +24,8 @@ public final class RuleExecutor { public Model getModel() { return model; } - public MergeResult execute(TupleLike activationTuple) { + + public MergeResult execute(Tuple activationTuple) { MergeResult mergeResult = MergeResult.UNCHANGED; for (var actionExecutor : actionExecutors) { mergeResult = mergeResult.andAlso(actionExecutor.execute(activationTuple)); diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java index bf844c6d..51e2895a 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java @@ -1,28 +1,37 @@ package tools.refinery.store.tuple; -public sealed interface Tuple extends TupleLike permits Tuple0, Tuple1, Tuple2, TupleN { - @Override - default Tuple toTuple() { - return this; - } +public sealed interface Tuple permits Tuple0, Tuple1, Tuple2, Tuple3, Tuple4, TupleN { + int getSize(); + + int get(int element); - static Tuple of() { + static Tuple0 of() { return Tuple0.INSTANCE; } - static Tuple of(int value) { + static Tuple1 of(int value) { return Tuple1.Cache.INSTANCE.getOrCreate(value); } - static Tuple of(int value1, int value2) { + static Tuple2 of(int value1, int value2) { return new Tuple2(value1, value2); } + static Tuple3 of(int value1, int value2, int value3) { + return new Tuple3(value1, value2, value3); + } + + static Tuple4 of(int value1, int value2, int value3, int value4) { + return new Tuple4(value1, value2, value3, value4); + } + static Tuple of(int... values) { return switch (values.length) { case 0 -> of(); case 1 -> of(values[0]); case 2 -> of(values[0], values[1]); + case 3 -> of(values[0], values[1], values[2]); + case 4 -> of(values[0], values[1], values[2], values[3]); default -> new TupleN(values); }; } diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java index 8eea5c3a..266e2cca 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java @@ -1,7 +1,13 @@ package tools.refinery.store.tuple; -public record Tuple0() implements Tuple { - public static Tuple0 INSTANCE = new Tuple0(); +import static tools.refinery.store.tuple.TupleConstants.TUPLE_BEGIN; +import static tools.refinery.store.tuple.TupleConstants.TUPLE_END; + +public final class Tuple0 implements Tuple { + public static final Tuple0 INSTANCE = new Tuple0(); + + private Tuple0() { + } @Override public int getSize() { @@ -13,13 +19,8 @@ public record Tuple0() implements Tuple { throw new IndexOutOfBoundsException(element); } - @Override - public int[] toArray() { - return new int[]{}; - } - @Override public String toString() { - return "[]"; + return TUPLE_BEGIN + TUPLE_END; } } diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java index 07380966..bdcc47b5 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java @@ -4,7 +4,20 @@ import tools.refinery.store.model.TupleHashProvider; import java.util.Arrays; -public record Tuple1(int value0) implements Tuple { +import static tools.refinery.store.tuple.TupleConstants.TUPLE_BEGIN; +import static tools.refinery.store.tuple.TupleConstants.TUPLE_END; + +public final class Tuple1 implements Tuple { + private final int value0; + + private Tuple1(int value0) { + this.value0 = value0; + } + + public int value0() { + return value0; + } + @Override public int getSize() { return 1; @@ -19,13 +32,21 @@ public record Tuple1(int value0) implements Tuple { } @Override - public int[] toArray() { - return new int[]{value0}; + public String toString() { + return TUPLE_BEGIN + value0 + TUPLE_END; } @Override - public String toString() { - return "[" + value0 + "]"; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Tuple1 tuple1 = (Tuple1) o; + return value0 == tuple1.value0; + } + + @Override + public int hashCode() { + return 31 + value0; } /** diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java index 0836a32d..fc0fbd8e 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java @@ -1,5 +1,7 @@ package tools.refinery.store.tuple; +import static tools.refinery.store.tuple.TupleConstants.*; + public record Tuple2(int value0, int value1) implements Tuple { @Override public int getSize() { @@ -16,12 +18,22 @@ public record Tuple2(int value0, int value1) implements Tuple { } @Override - public int[] toArray() { - return new int[]{value0, value1}; + public String toString() { + return TUPLE_BEGIN + value0 + TUPLE_SEPARATOR + value1 + TUPLE_END; } @Override - public String toString() { - return "[" + value0 + ", " + value1 + "]"; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Tuple2 tuple2 = (Tuple2) o; + return value0 == tuple2.value0 && value1 == tuple2.value1; + } + + @Override + public int hashCode() { + int hash = 31 + value0; + hash = 31 * hash + value1; + return hash; } } diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java new file mode 100644 index 00000000..a6ec17b0 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java @@ -0,0 +1,41 @@ +package tools.refinery.store.tuple; + +import static tools.refinery.store.tuple.TupleConstants.*; + +public record Tuple3(int value0, int value1, int value2) implements Tuple { + @Override + public int getSize() { + return 3; + } + + @Override + public int get(int element) { + return switch (element) { + case 0 -> value0; + case 1 -> value1; + case 2 -> value2; + default -> throw new ArrayIndexOutOfBoundsException(element); + }; + } + + @Override + public String toString() { + return TUPLE_BEGIN + value0 + TUPLE_SEPARATOR + value1 + TUPLE_SEPARATOR + value2 + TUPLE_END; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Tuple3 tuple3 = (Tuple3) o; + return value0 == tuple3.value0 && value1 == tuple3.value1 && value2 == tuple3.value2; + } + + @Override + public int hashCode() { + int hash = 31 + value0; + hash = 31 * hash + value1; + hash = 31 * hash + value2; + return hash; + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java new file mode 100644 index 00000000..66cef32b --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java @@ -0,0 +1,44 @@ +package tools.refinery.store.tuple; + +import static tools.refinery.store.tuple.TupleConstants.*; + +public record Tuple4(int value0, int value1, int value2, int value3) implements Tuple { + @Override + public int getSize() { + return 4; + } + + @Override + public int get(int element) { + return switch (element) { + case 0 -> value0; + case 1 -> value1; + case 2 -> value2; + case 3 -> value3; + default -> throw new ArrayIndexOutOfBoundsException(element); + }; + } + + @Override + public String toString() { + return TUPLE_BEGIN + value0 + TUPLE_SEPARATOR + value1 + TUPLE_SEPARATOR + value2 + TUPLE_SEPARATOR + value3 + + TUPLE_END; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Tuple4 tuple4 = (Tuple4) o; + return value0 == tuple4.value0 && value1 == tuple4.value1 && value2 == tuple4.value2 && value3 == tuple4.value3; + } + + @Override + public int hashCode() { + int hash = 31 + value0; + hash = 31 * hash + value1; + hash = 31 * hash + value2; + hash = 31 * hash + value3; + return hash; + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleConstants.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleConstants.java new file mode 100644 index 00000000..3d95a655 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleConstants.java @@ -0,0 +1,12 @@ +package tools.refinery.store.tuple; + +final class TupleConstants { + public static final int MAX_STATIC_ARITY_TUPLE_SIZE = 4; + public static final String TUPLE_BEGIN = "["; + public static final String TUPLE_SEPARATOR = ", "; + public static final String TUPLE_END = "]"; + + private TupleConstants() { + throw new IllegalArgumentException("This is a static utility class an should not instantiated directly"); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleLike.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleLike.java deleted file mode 100644 index 953ea9f8..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleLike.java +++ /dev/null @@ -1,35 +0,0 @@ -package tools.refinery.store.tuple; - -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -public interface TupleLike { - int getSize(); - - int get(int element); - - default int[] toArray() { - int size = getSize(); - var array = new int[size]; - for (int i = 0; i < size; i++) { - array[i] = get(i); - } - return array; - } - - default Tuple toTuple() { - return switch (getSize()) { - case 0 -> Tuple.of(); - case 1 -> Tuple.of(get(0)); - case 2 -> Tuple.of(get(0), get(1)); - default -> Tuple.of(toArray()); - }; - } - - static String toString(TupleLike tuple) { - var valuesString = IntStream.range(0, tuple.getSize()) - .mapToObj(i -> Integer.toString(tuple.get(i))) - .collect(Collectors.joining(", ")); - return "[" + valuesString + "]"; - } -} diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java index c3aed847..512bab49 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java @@ -1,13 +1,18 @@ package tools.refinery.store.tuple; import java.util.Arrays; +import java.util.stream.Collectors; -public record TupleN(int[] values) implements Tuple { - static final int CUSTOM_TUPLE_SIZE = 2; +import static tools.refinery.store.tuple.TupleConstants.*; - public TupleN(int[] values) { - if (values.length < CUSTOM_TUPLE_SIZE) - throw new IllegalArgumentException(); +public final class TupleN implements Tuple { + private final int[] values; + + TupleN(int[] values) { + if (values.length < MAX_STATIC_ARITY_TUPLE_SIZE) { + throw new IllegalArgumentException("Tuples of size at most %d must use static arity Tuple classes" + .formatted(MAX_STATIC_ARITY_TUPLE_SIZE)); + } this.values = Arrays.copyOf(values, values.length); } @@ -21,19 +26,12 @@ public record TupleN(int[] values) implements Tuple { return values[element]; } - @Override - public int[] toArray() { - return values; - } - @Override public String toString() { - return TupleLike.toString(this); - } - - @Override - public int hashCode() { - return Arrays.hashCode(values); + var valuesString = Arrays.stream(values) + .mapToObj(Integer::toString) + .collect(Collectors.joining(TUPLE_SEPARATOR)); + return TUPLE_BEGIN + valuesString + TUPLE_END; } @Override @@ -47,4 +45,9 @@ public record TupleN(int[] values) implements Tuple { TupleN other = (TupleN) obj; return Arrays.equals(values, other.values); } + + @Override + public int hashCode() { + return Arrays.hashCode(values); + } } -- cgit v1.2.3-70-g09d2 From 12669b3bf4dcefda337d141ab2a2f2bf3cf04ee5 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Mon, 10 Apr 2023 00:55:10 +0200 Subject: chore: add copyright headers Make sure we obey the REUSE (https://reuse.software) specification and the origin, copyright owner, and license of all files are clearly marked. The whole project is under the EPL-2.0, except for trivial files where copyright is not applicable that are marked with the CC0-1.0 license. Moreover, code included from third parties is also available under the respective license. chore: add CONTRIBUTORS.md List all authors and supporting organizations in accordance with the REUSE specification. --- .editorconfig | 4 + .gitattributes | 4 + .github/workflows/build.yml | 4 + .gitignore | 4 + .reuse/dep5 | 29 +++ .vscode/extensions.json | 5 + .vscode/settings.json | 5 + .yarn/sdks/integrations.yml.license | 3 + .yarnrc.yml | 6 +- CONTRIBUTORS.md | 28 ++ LICENSE | 286 ++++----------------- LICENSES/Apache-2.0.txt | 73 ++++++ LICENSES/BSD-2-Clause.txt | 9 + LICENSES/CC0-1.0.txt | 121 +++++++++ LICENSES/EPL-2.0.txt | 80 ++++++ LICENSES/MIT.txt | 9 + README.md | 13 +- build.gradle.kts | 6 + buildSrc/build.gradle.kts | 6 + buildSrc/settings.gradle.kts | 6 + .../tools/refinery/gradle/utils/EclipseUtils.java | 5 + .../gradle/utils/SonarPropertiesUtils.java | 5 + .../tools/refinery/gradle/eclipse.gradle.kts | 5 + .../refinery/gradle/frontend-workspace.gradle.kts | 5 + .../refinery/gradle/frontend-worktree.gradle.kts | 5 + .../internal/frontend-conventions.gradle.kts | 5 + .../gradle/internal/java-conventions.gradle.kts | 5 + .../refinery/gradle/java-application.gradle.kts | 5 + .../tools/refinery/gradle/java-library.gradle.kts | 5 + .../refinery/gradle/java-test-fixtures.gradle.kts | 5 + .../kotlin/tools/refinery/gradle/jmh.gradle.kts | 5 + .../kotlin/tools/refinery/gradle/mwe2.gradle.kts | 5 + .../tools/refinery/gradle/sonarqube.gradle.kts | 5 + .../refinery/gradle/xtext-generated.gradle.kts | 5 + gradle.properties | 4 + gradle/libs.versions.toml | 4 + gradle/wrapper/gradle-wrapper.jar.license | 3 + gradle/wrapper/gradle-wrapper.properties.license | 3 + gradlew.bat.license | 3 + gradlew.license | 3 + package.json | 15 ++ settings.gradle.kts | 6 + subprojects/frontend/.eslintrc.cjs | 6 + .../frontend/assets-src/favicon.svg.license | 3 + subprojects/frontend/assets-src/icon.svg.license | 3 + .../frontend/assets-src/mask-icon.svg.license | 3 + subprojects/frontend/build.gradle.kts | 6 + .../frontend/config/backendConfigVitePlugin.ts | 6 + .../frontend/config/detectDevModeOptions.ts | 6 + subprojects/frontend/config/eslintReport.cjs | 6 + .../frontend/config/fetchPackageMetadata.ts | 6 + subprojects/frontend/config/manifest.ts | 8 +- .../frontend/config/minifyHTMLVitePlugin.ts | 6 + .../frontend/config/preloadFontsVitePlugin.ts | 6 + subprojects/frontend/index.html | 5 + subprojects/frontend/package.json | 9 +- subprojects/frontend/prettier.config.cjs | 6 + .../frontend/public/apple-touch-icon.png.license | 3 + .../frontend/public/favicon-96x96.png.license | 3 + subprojects/frontend/public/favicon.png.license | 3 + subprojects/frontend/public/favicon.svg.license | 3 + .../frontend/public/icon-192x192.png.license | 3 + .../frontend/public/icon-512x512.png.license | 3 + subprojects/frontend/public/icon-any.svg.license | 3 + subprojects/frontend/public/mask-icon.svg.license | 3 + subprojects/frontend/public/robots.txt | 4 + subprojects/frontend/src/App.tsx | 6 + subprojects/frontend/src/Loading.tsx | 6 + subprojects/frontend/src/PWAStore.ts | 6 + subprojects/frontend/src/Refinery.tsx | 6 + subprojects/frontend/src/RootStore.ts | 6 + subprojects/frontend/src/RootStoreProvider.tsx | 6 + subprojects/frontend/src/ToggleDarkModeButton.tsx | 6 + subprojects/frontend/src/TopBar.tsx | 6 + subprojects/frontend/src/UpdateNotification.tsx | 6 + .../frontend/src/WindowControlsOverlayColor.tsx | 6 + subprojects/frontend/src/editor/AnimatedButton.tsx | 6 + subprojects/frontend/src/editor/ConnectButton.tsx | 6 + .../src/editor/ConnectionStatusNotification.tsx | 6 + subprojects/frontend/src/editor/DiagnosticValue.ts | 6 + subprojects/frontend/src/editor/EditorArea.tsx | 6 + subprojects/frontend/src/editor/EditorButtons.tsx | 6 + subprojects/frontend/src/editor/EditorPane.tsx | 6 + subprojects/frontend/src/editor/EditorStore.ts | 6 + subprojects/frontend/src/editor/EditorTheme.ts | 6 + subprojects/frontend/src/editor/GenerateButton.tsx | 6 + subprojects/frontend/src/editor/LintPanelStore.ts | 6 + subprojects/frontend/src/editor/PanelStore.ts | 6 + subprojects/frontend/src/editor/SearchPanel.ts | 6 + .../frontend/src/editor/SearchPanelPortal.tsx | 6 + .../frontend/src/editor/SearchPanelStore.ts | 6 + subprojects/frontend/src/editor/SearchToolbar.tsx | 6 + .../frontend/src/editor/createEditorState.ts | 6 + .../src/editor/defineDecorationSetExtension.ts | 6 + .../frontend/src/editor/exposeDiagnostics.ts | 6 + subprojects/frontend/src/editor/findOccurrences.ts | 6 + .../src/editor/indentationMarkerViewPlugin.ts | 10 +- .../frontend/src/editor/scrollbarViewPlugin.ts | 6 + .../frontend/src/editor/semanticHighlighting.ts | 6 + subprojects/frontend/src/index.tsx | 6 + subprojects/frontend/src/language/folding.ts | 6 + subprojects/frontend/src/language/indentation.ts | 7 + subprojects/frontend/src/language/problem.grammar | 6 + .../src/language/problemLanguageSupport.ts | 6 + subprojects/frontend/src/language/props.ts | 6 + subprojects/frontend/src/theme/ThemeProvider.tsx | 6 + subprojects/frontend/src/theme/ThemeStore.ts | 6 + subprojects/frontend/src/utils/CancelledError.ts | 6 + subprojects/frontend/src/utils/PendingTask.ts | 6 + subprojects/frontend/src/utils/PriorityMutex.ts | 6 + subprojects/frontend/src/utils/TimeoutError.ts | 6 + subprojects/frontend/src/utils/getLogger.ts | 6 + .../frontend/src/utils/useDelayedSnackbar.ts | 6 + subprojects/frontend/src/xtext/BackendConfig.ts | 6 + .../frontend/src/xtext/ContentAssistService.ts | 6 + .../frontend/src/xtext/HighlightingService.ts | 6 + .../frontend/src/xtext/OccurrencesService.ts | 6 + subprojects/frontend/src/xtext/UpdateService.ts | 6 + .../frontend/src/xtext/UpdateStateTracker.ts | 6 + .../frontend/src/xtext/ValidationService.ts | 6 + subprojects/frontend/src/xtext/XtextClient.ts | 6 + .../frontend/src/xtext/XtextWebSocketClient.ts | 6 + .../frontend/src/xtext/fetchBackendConfig.ts | 6 + subprojects/frontend/src/xtext/webSocketMachine.ts | 6 + subprojects/frontend/src/xtext/xtextMessages.ts | 6 + .../frontend/src/xtext/xtextServiceResults.ts | 6 + subprojects/frontend/tsconfig.base.json | 13 + subprojects/frontend/tsconfig.json | 5 + subprojects/frontend/tsconfig.node.json | 5 + subprojects/frontend/tsconfig.shared.json | 7 +- subprojects/frontend/types/ImportMeta.d.ts | 7 + subprojects/frontend/types/grammar.d.ts | 7 + .../types/node/@lezer-generator-rollup.d.ts | 7 + .../frontend/types/windowControlsOverlay.d.ts | 6 + subprojects/frontend/vite.config.ts | 6 + subprojects/language-ide/build.gradle.kts | 6 + .../refinery/language/ide/ProblemIdeModule.java | 6 + .../refinery/language/ide/ProblemIdeSetup.java | 6 + .../language/ide/contentassist/FuzzyMatcher.java | 5 + .../ProblemCrossrefProposalProvider.java | 5 + ...InjectingPartialProblemContentAssistParser.java | 5 + .../TokenSourceInjectingProblemParser.java | 5 + .../contentassist/antlr/ProblemTokenSource.java | 6 + .../ProblemSemanticHighlightingCalculator.java | 5 + .../language-model/META-INF/MANIFEST.MF.license | 3 + subprojects/language-model/build.gradle.kts | 6 + subprojects/language-model/build.properties | 2 + subprojects/language-model/plugin.properties | 2 + subprojects/language-model/plugin.xml | 3 + subprojects/language-model/problem.aird.license | 3 + .../language/model/GenerateProblemModel.mwe2 | 5 + .../src/main/resources/model/problem.ecore.license | 3 + .../main/resources/model/problem.genmodel.license | 3 + subprojects/language-semantics/build.gradle.kts | 6 + .../language/semantics/model/ModelInitializer.java | 5 + .../semantics/model/internal/DecisionTree.java | 5 + .../model/internal/DecisionTreeCursor.java | 5 + .../semantics/model/internal/DecisionTreeNode.java | 5 + .../model/internal/DecisionTreeValue.java | 5 + .../semantics/model/internal/IntermediateNode.java | 5 + .../semantics/model/internal/TerminalNode.java | 5 + .../semantics/model/tests/DecisionTreeTests.java | 5 + subprojects/language-web/build.gradle.kts | 6 + .../refinery/language/web/CacheControlFilter.java | 5 + .../refinery/language/web/ProblemWebModule.java | 6 + .../refinery/language/web/ProblemWebSetup.java | 6 + .../language/web/ProblemWebSocketServlet.java | 5 + .../language/web/SecurityHeadersFilter.java | 5 + .../refinery/language/web/ServerLauncher.java | 6 + .../refinery/language/web/VirtualThreadUtils.java | 5 + .../language/web/config/BackendConfig.java | 5 + .../language/web/config/BackendConfigServlet.java | 5 + .../web/occurrences/ProblemOccurrencesService.java | 5 + .../VirtualThreadExecutorServiceProvider.java | 5 + .../language/web/xtext/server/PongResult.java | 5 + .../language/web/xtext/server/ResponseHandler.java | 5 + .../web/xtext/server/ResponseHandlerException.java | 5 + .../xtext/server/SubscribingServiceContext.java | 5 + .../web/xtext/server/TransactionExecutor.java | 5 + .../xtext/server/message/XtextWebErrorKind.java | 5 + .../server/message/XtextWebErrorResponse.java | 5 + .../xtext/server/message/XtextWebOkResponse.java | 5 + .../xtext/server/message/XtextWebPushMessage.java | 5 + .../web/xtext/server/message/XtextWebRequest.java | 5 + .../web/xtext/server/message/XtextWebResponse.java | 5 + .../xtext/server/push/PrecomputationListener.java | 5 + .../xtext/server/push/PushServiceDispatcher.java | 5 + .../web/xtext/server/push/PushWebDocument.java | 5 + .../xtext/server/push/PushWebDocumentAccess.java | 5 + .../xtext/server/push/PushWebDocumentProvider.java | 5 + .../web/xtext/servlet/SimpleServiceContext.java | 5 + .../language/web/xtext/servlet/SimpleSession.java | 5 + .../web/xtext/servlet/XtextStatusCode.java | 5 + .../language/web/xtext/servlet/XtextWebSocket.java | 5 + .../web/xtext/servlet/XtextWebSocketServlet.java | 5 + .../ProblemWebSocketServletIntegrationTest.java | 5 + .../AwaitTerminationExecutorServiceProvider.java | 5 + .../web/tests/ProblemWebInjectorProvider.java | 5 + .../web/tests/RestartableCachedThreadPool.java | 5 + .../web/tests/WebSocketIntegrationTestClient.java | 5 + .../web/xtext/servlet/TransactionExecutorTest.java | 5 + subprojects/language/build.gradle.kts | 6 + .../tools/refinery/language/GenerateProblem.mwe2 | 7 +- .../java/tools/refinery/language/Problem.xtext | 5 + .../refinery/language/ProblemRuntimeModule.java | 6 + .../refinery/language/ProblemStandaloneSetup.java | 6 + .../conversion/ProblemValueConverterService.java | 5 + .../conversion/UpperBoundValueConverter.java | 5 + .../language/formatting2/ProblemFormatter.java | 6 + .../tools/refinery/language/naming/NamingUtil.java | 5 + .../naming/ProblemQualifiedNameConverter.java | 5 + .../parser/antlr/IdentifierTokenProvider.java | 5 + .../language/parser/antlr/ProblemTokenSource.java | 6 + .../antlr/TokenSourceInjectingProblemParser.java | 5 + .../language/resource/DerivedVariableComputer.java | 5 + .../language/resource/ImplicitVariableScope.java | 5 + .../language/resource/NodeNameCollector.java | 5 + .../resource/ProblemDerivedStateComputer.java | 5 + .../resource/ProblemLocationInFileProvider.java | 5 + .../ProblemResourceDescriptionStrategy.java | 5 + .../language/resource/ReferenceCounter.java | 5 + .../scoping/ProblemGlobalScopeProvider.java | 5 + .../scoping/ProblemLocalScopeProvider.java | 5 + .../language/scoping/ProblemScopeProvider.java | 6 + ...ferShortAssertionsProblemSemanticSequencer.java | 5 + .../refinery/language/utils/BuiltinSymbols.java | 5 + .../refinery/language/utils/CollectedSymbols.java | 5 + .../refinery/language/utils/ContainmentRole.java | 5 + .../tools/refinery/language/utils/NodeInfo.java | 5 + .../refinery/language/utils/ProblemDesugarer.java | 5 + .../tools/refinery/language/utils/ProblemUtil.java | 5 + .../refinery/language/utils/RelationInfo.java | 5 + .../refinery/language/utils/SymbolCollector.java | 5 + .../language/validation/ProblemValidator.java | 6 + .../tools/refinery/language/builtin.problem | 3 + .../language/tests/ProblemParsingTest.java | 5 + .../tests/formatting2/ProblemFormatterTest.java | 5 + .../parser/antlr/IdentifierTokenProviderTest.java | 5 + .../tests/parser/antlr/ProblemTokenSourceTest.java | 5 + .../parser/antlr/TransitiveClosureParserTest.java | 5 + .../language/tests/rules/RuleParsingTest.java | 5 + .../language/tests/scoping/NodeScopingTest.java | 5 + .../tests/serializer/ProblemSerializerTest.java | 5 + .../language/tests/utils/SymbolCollectorTest.java | 5 + .../model/tests/utils/ProblemNavigationUtil.java | 5 + .../model/tests/utils/ProblemParseHelper.java | 5 + .../language/model/tests/utils/WrappedAction.java | 5 + .../model/tests/utils/WrappedArgument.java | 5 + .../model/tests/utils/WrappedAssertion.java | 5 + .../tests/utils/WrappedAssertionArgument.java | 5 + .../language/model/tests/utils/WrappedAtom.java | 5 + .../model/tests/utils/WrappedClassDeclaration.java | 5 + .../model/tests/utils/WrappedConjunction.java | 5 + .../model/tests/utils/WrappedConsequent.java | 5 + .../model/tests/utils/WrappedEnumDeclaration.java | 5 + .../language/model/tests/utils/WrappedLiteral.java | 5 + .../tests/utils/WrappedParametricDefinition.java | 5 + .../tests/utils/WrappedPredicateDefinition.java | 5 + .../language/model/tests/utils/WrappedProblem.java | 5 + .../model/tests/utils/WrappedRuleDefinition.java | 5 + subprojects/store-query-viatra/NOTICE.md | 87 +++++++ subprojects/store-query-viatra/build.gradle.kts | 6 + .../store/query/viatra/ViatraModelQuery.java | 5 + .../query/viatra/ViatraModelQueryAdapter.java | 5 + .../query/viatra/ViatraModelQueryBuilder.java | 5 + .../query/viatra/ViatraModelQueryStoreAdapter.java | 5 + .../query/viatra/internal/RelationalScope.java | 5 + .../internal/ViatraModelQueryAdapterImpl.java | 5 + .../internal/ViatraModelQueryBuilderImpl.java | 5 + .../internal/ViatraModelQueryStoreAdapterImpl.java | 5 + .../UpperCardinalitySumAggregationOperator.java | 5 + .../viatra/internal/context/DummyBaseIndexer.java | 5 + .../internal/context/RelationalEngineContext.java | 5 + .../context/RelationalQueryMetaContext.java | 5 + .../internal/context/RelationalRuntimeContext.java | 5 + .../localsearch/ExtendOperationExecutor.java | 1 + .../localsearch/ExtendPositivePatternCall.java | 1 + .../internal/localsearch/FlatCostFunction.java | 5 + .../internal/localsearch/GenericTypeExtend.java | 1 + .../RelationalLocalSearchBackendFactory.java | 5 + .../RelationalLocalSearchResultProvider.java | 5 + .../localsearch/RelationalOperationCompiler.java | 5 + .../viatra/internal/matcher/FunctionalCursor.java | 5 + .../internal/matcher/FunctionalViatraMatcher.java | 5 + .../viatra/internal/matcher/IndexerUtils.java | 5 + .../viatra/internal/matcher/MatcherUtils.java | 5 + .../viatra/internal/matcher/RawPatternMatcher.java | 5 + .../viatra/internal/matcher/RelationalCursor.java | 5 + .../internal/matcher/RelationalViatraMatcher.java | 5 + .../internal/matcher/UnsafeFunctionalCursor.java | 5 + .../internal/pquery/AssumptionEvaluator.java | 5 + .../query/viatra/internal/pquery/Dnf2PQuery.java | 5 + .../internal/pquery/QueryWrapperFactory.java | 5 + .../query/viatra/internal/pquery/RawPQuery.java | 5 + .../internal/pquery/RelationViewWrapper.java | 5 + .../pquery/StatefulMultisetAggregator.java | 5 + .../pquery/StatelessMultisetAggregator.java | 5 + .../viatra/internal/pquery/TermEvaluator.java | 5 + .../pquery/ValueProviderBasedValuation.java | 5 + .../internal/update/ModelUpdateListener.java | 5 + .../viatra/internal/update/RelationViewFilter.java | 5 + .../update/RelationViewUpdateListener.java | 5 + .../TupleChangingRelationViewUpdateListener.java | 5 + .../TuplePreservingRelationViewUpdateListener.java | 5 + .../store/query/viatra/DiagonalQueryTest.java | 5 + .../store/query/viatra/FunctionalQueryTest.java | 5 + .../refinery/store/query/viatra/QueryTest.java | 5 + .../store/query/viatra/QueryTransactionTest.java | 5 + ...ardinalitySumAggregationOperatorStreamTest.java | 5 + ...UpperCardinalitySumAggregationOperatorTest.java | 5 + .../viatra/internal/matcher/MatcherUtilsTest.java | 5 + .../store/query/viatra/tests/QueryAssertions.java | 5 + .../store/query/viatra/tests/QueryBackendHint.java | 5 + .../store/query/viatra/tests/QueryEngineTest.java | 5 + .../viatra/tests/QueryEvaluationHintSource.java | 5 + subprojects/store-query/build.gradle.kts | 6 + .../tools/refinery/store/query/AnyResultSet.java | 5 + .../tools/refinery/store/query/Constraint.java | 5 + .../tools/refinery/store/query/EmptyResultSet.java | 5 + .../tools/refinery/store/query/ModelQuery.java | 5 + .../refinery/store/query/ModelQueryAdapter.java | 5 + .../refinery/store/query/ModelQueryBuilder.java | 5 + .../store/query/ModelQueryStoreAdapter.java | 5 + .../java/tools/refinery/store/query/ResultSet.java | 5 + .../tools/refinery/store/query/dnf/AnyQuery.java | 5 + .../java/tools/refinery/store/query/dnf/Dnf.java | 5 + .../tools/refinery/store/query/dnf/DnfBuilder.java | 5 + .../tools/refinery/store/query/dnf/DnfClause.java | 5 + .../tools/refinery/store/query/dnf/DnfUtils.java | 5 + .../store/query/dnf/FunctionalDependency.java | 5 + .../refinery/store/query/dnf/FunctionalQuery.java | 5 + .../store/query/dnf/FunctionalQueryBuilder.java | 5 + .../java/tools/refinery/store/query/dnf/Query.java | 5 + .../refinery/store/query/dnf/QueryBuilder.java | 5 + .../refinery/store/query/dnf/RelationalQuery.java | 5 + .../query/equality/DeepDnfEqualityChecker.java | 5 + .../store/query/equality/DnfEqualityChecker.java | 5 + .../query/equality/LiteralEqualityHelper.java | 5 + .../store/query/literal/AbstractCallLiteral.java | 5 + .../store/query/literal/AggregationLiteral.java | 5 + .../store/query/literal/AssignLiteral.java | 5 + .../store/query/literal/AssumeLiteral.java | 5 + .../store/query/literal/BooleanLiteral.java | 5 + .../refinery/store/query/literal/CallLiteral.java | 5 + .../refinery/store/query/literal/CallPolarity.java | 5 + .../refinery/store/query/literal/CanNegate.java | 5 + .../store/query/literal/ConstantLiteral.java | 5 + .../refinery/store/query/literal/CountLiteral.java | 5 + .../store/query/literal/EquivalenceLiteral.java | 5 + .../refinery/store/query/literal/Literal.java | 5 + .../store/query/literal/LiteralReduction.java | 5 + .../refinery/store/query/literal/Literals.java | 5 + .../query/substitution/CompositeSubstitution.java | 5 + .../query/substitution/MapBasedSubstitution.java | 5 + .../query/substitution/RenewingSubstitution.java | 5 + .../query/substitution/StatelessSubstitution.java | 5 + .../store/query/substitution/Substitution.java | 5 + .../store/query/substitution/Substitutions.java | 5 + .../refinery/store/query/term/Aggregator.java | 5 + .../refinery/store/query/term/AnyDataVariable.java | 5 + .../tools/refinery/store/query/term/AnyTerm.java | 5 + .../store/query/term/ArithmeticBinaryOperator.java | 5 + .../store/query/term/ArithmeticBinaryTerm.java | 5 + .../store/query/term/ArithmeticUnaryOperator.java | 5 + .../store/query/term/ArithmeticUnaryTerm.java | 5 + .../refinery/store/query/term/AssignedValue.java | 5 + .../refinery/store/query/term/BinaryTerm.java | 5 + .../store/query/term/ComparisonOperator.java | 5 + .../refinery/store/query/term/ComparisonTerm.java | 5 + .../refinery/store/query/term/ConstantTerm.java | 5 + .../tools/refinery/store/query/term/DataSort.java | 5 + .../refinery/store/query/term/DataVariable.java | 5 + .../store/query/term/ExtremeValueAggregator.java | 5 + .../tools/refinery/store/query/term/NodeSort.java | 5 + .../refinery/store/query/term/NodeVariable.java | 5 + .../refinery/store/query/term/OpaqueTerm.java | 5 + .../java/tools/refinery/store/query/term/Sort.java | 5 + .../store/query/term/StatefulAggregate.java | 5 + .../store/query/term/StatefulAggregator.java | 5 + .../store/query/term/StatelessAggregator.java | 5 + .../java/tools/refinery/store/query/term/Term.java | 5 + .../tools/refinery/store/query/term/UnaryTerm.java | 5 + .../tools/refinery/store/query/term/Variable.java | 5 + .../store/query/term/bool/BoolConstantTerm.java | 5 + .../store/query/term/bool/BoolLogicBinaryTerm.java | 5 + .../store/query/term/bool/BoolNotTerm.java | 5 + .../refinery/store/query/term/bool/BoolTerms.java | 5 + .../store/query/term/bool/LogicBinaryOperator.java | 5 + .../query/term/int_/IntArithmeticBinaryTerm.java | 5 + .../query/term/int_/IntArithmeticUnaryTerm.java | 5 + .../store/query/term/int_/IntComparisonTerm.java | 5 + .../query/term/int_/IntExtremeValueAggregator.java | 5 + .../store/query/term/int_/IntSumAggregator.java | 5 + .../refinery/store/query/term/int_/IntTerms.java | 5 + .../store/query/term/int_/RealToIntTerm.java | 5 + .../store/query/term/real/IntToRealTerm.java | 5 + .../query/term/real/RealArithmeticBinaryTerm.java | 5 + .../query/term/real/RealArithmeticUnaryTerm.java | 5 + .../store/query/term/real/RealComparisonTerm.java | 5 + .../term/real/RealExtremeValueAggregator.java | 5 + .../store/query/term/real/RealSumAggregator.java | 5 + .../refinery/store/query/term/real/RealTerms.java | 5 + .../store/query/valuation/RestrictedValuation.java | 5 + .../query/valuation/SubstitutedValuation.java | 5 + .../refinery/store/query/valuation/Valuation.java | 5 + .../refinery/store/query/view/AnyRelationView.java | 5 + .../store/query/view/FilteredRelationView.java | 5 + .../store/query/view/ForbiddenRelationView.java | 5 + .../refinery/store/query/view/FunctionView.java | 25 ++ .../store/query/view/FunctionalRelationView.java | 5 + .../store/query/view/KeyOnlyRelationView.java | 5 + .../refinery/store/query/view/MayRelationView.java | 5 + .../store/query/view/MustRelationView.java | 5 + .../store/query/view/NodeFunctionView.java | 26 ++ .../refinery/store/query/view/RelationView.java | 5 + .../store/query/view/RelationViewImplication.java | 5 + .../query/view/TuplePreservingRelationView.java | 5 + .../refinery/store/query/view/ViewImplication.java | 23 ++ .../tools/refinery/store/query/DnfBuilderTest.java | 5 + .../store/query/DnfToDefinitionStringTest.java | 5 + .../store/query/tests/StructurallyEqualToTest.java | 5 + .../MismatchDescribingDnfEqualityChecker.java | 5 + .../refinery/store/query/tests/QueryMatchers.java | 5 + .../store/query/tests/StructurallyEqualTo.java | 5 + subprojects/store-reasoning/build.gradle.kts | 6 + .../store/reasoning/AnyPartialInterpretation.java | 5 + .../refinery/store/reasoning/MergeResult.java | 5 + .../store/reasoning/PartialInterpretation.java | 5 + .../tools/refinery/store/reasoning/Reasoning.java | 5 + .../refinery/store/reasoning/ReasoningAdapter.java | 5 + .../refinery/store/reasoning/ReasoningBuilder.java | 5 + .../store/reasoning/ReasoningStoreAdapter.java | 5 + .../reasoning/internal/ReasoningAdapterImpl.java | 5 + .../reasoning/internal/ReasoningBuilderImpl.java | 5 + .../internal/ReasoningStoreAdapterImpl.java | 5 + .../store/reasoning/lifting/DnfLifter.java | 5 + .../refinery/store/reasoning/lifting/ModalDnf.java | 5 + .../store/reasoning/literal/ModalConstraint.java | 5 + .../refinery/store/reasoning/literal/Modality.java | 5 + .../store/reasoning/literal/PartialLiterals.java | 5 + .../representation/AnyPartialFunction.java | 5 + .../reasoning/representation/AnyPartialSymbol.java | 5 + .../reasoning/representation/PartialFunction.java | 5 + .../reasoning/representation/PartialRelation.java | 5 + .../reasoning/representation/PartialSymbol.java | 5 + .../reasoning/rule/RelationRefinementAction.java | 5 + .../tools/refinery/store/reasoning/rule/Rule.java | 5 + .../refinery/store/reasoning/rule/RuleAction.java | 5 + .../store/reasoning/rule/RuleActionExecutor.java | 5 + .../store/reasoning/rule/RuleExecutor.java | 5 + .../tools/refinery/store/reasoning/seed/Seed.java | 5 + .../refinery/store/reasoning/seed/UniformSeed.java | 5 + .../store/reasoning/translator/Advice.java | 5 + .../store/reasoning/translator/AdviceSlot.java | 5 + .../reasoning/translator/TranslatedRelation.java | 5 + .../reasoning/translator/TranslationUnit.java | 5 + .../base/BaseDecisionInterpretation.java | 5 + .../base/BaseDecisionTranslationUnit.java | 5 + .../translator/base/TranslatedBaseDecision.java | 5 + .../translator/typehierarchy/EliminatedType.java | 5 + .../translator/typehierarchy/ExtendedTypeInfo.java | 5 + .../typehierarchy/InferredMayTypeRelationView.java | 5 + .../InferredMustTypeRelationView.java | 5 + .../translator/typehierarchy/InferredType.java | 5 + .../translator/typehierarchy/PreservedType.java | 5 + .../typehierarchy/TypeAnalysisResult.java | 5 + .../translator/typehierarchy/TypeAnalyzer.java | 5 + .../TypeHierarchyTranslationUnit.java | 5 + .../translator/typehierarchy/TypeInfo.java | 5 + .../translator/typehierarchy/InferredTypeTest.java | 5 + .../TypeAnalyzerExampleHierarchyTest.java | 5 + .../translator/typehierarchy/TypeAnalyzerTest.java | 5 + .../typehierarchy/TypeAnalyzerTester.java | 5 + subprojects/store/build.gradle.kts | 6 + .../map/benchmarks/ImmutablePutBenchmark.java | 5 + .../map/benchmarks/ImmutablePutExecutionPlan.java | 5 + .../store/adapter/AbstractModelAdapterBuilder.java | 5 + .../tools/refinery/store/adapter/AdapterList.java | 5 + .../store/adapter/AnyModelAdapterType.java | 5 + .../tools/refinery/store/adapter/ModelAdapter.java | 5 + .../store/adapter/ModelAdapterBuilder.java | 5 + .../store/adapter/ModelAdapterBuilderFactory.java | 5 + .../refinery/store/adapter/ModelAdapterType.java | 5 + .../refinery/store/adapter/ModelStoreAdapter.java | 5 + .../tools/refinery/store/map/AnyVersionedMap.java | 5 + .../tools/refinery/store/map/ContentHashCode.java | 5 + .../refinery/store/map/ContinousHashProvider.java | 5 + .../main/java/tools/refinery/store/map/Cursor.java | 5 + .../tools/refinery/store/map/CursorAsIterator.java | 5 + .../java/tools/refinery/store/map/Cursors.java | 5 + .../java/tools/refinery/store/map/DiffCursor.java | 5 + .../tools/refinery/store/map/MapAsIterable.java | 5 + .../java/tools/refinery/store/map/Versioned.java | 5 + .../tools/refinery/store/map/VersionedMap.java | 5 + .../refinery/store/map/VersionedMapStore.java | 5 + .../store/map/VersionedMapStoreConfiguration.java | 5 + .../refinery/store/map/VersionedMapStoreImpl.java | 5 + .../refinery/store/map/internal/HashClash.java | 5 + .../refinery/store/map/internal/ImmutableNode.java | 5 + .../refinery/store/map/internal/MapCursor.java | 5 + .../refinery/store/map/internal/MapDiffCursor.java | 5 + .../refinery/store/map/internal/MutableNode.java | 9 +- .../tools/refinery/store/map/internal/Node.java | 5 + .../refinery/store/map/internal/OldValueBox.java | 5 + .../store/map/internal/VersionedMapImpl.java | 5 + .../refinery/store/model/AnyInterpretation.java | 5 + .../tools/refinery/store/model/Interpretation.java | 5 + .../store/model/InterpretationListener.java | 5 + .../java/tools/refinery/store/model/Model.java | 5 + .../refinery/store/model/ModelDiffCursor.java | 5 + .../tools/refinery/store/model/ModelListener.java | 5 + .../tools/refinery/store/model/ModelStore.java | 5 + .../refinery/store/model/ModelStoreBuilder.java | 5 + .../refinery/store/model/TupleHashProvider.java | 5 + .../store/model/TupleHashProviderBitMagic.java | 5 + .../refinery/store/model/internal/ModelAction.java | 5 + .../refinery/store/model/internal/ModelImpl.java | 5 + .../model/internal/ModelStoreBuilderImpl.java | 5 + .../store/model/internal/ModelStoreImpl.java | 5 + .../model/internal/SymbolEquivalenceClass.java | 5 + .../model/internal/VersionedInterpretation.java | 5 + .../store/representation/AbstractDomain.java | 5 + .../store/representation/AnyAbstractDomain.java | 5 + .../refinery/store/representation/AnySymbol.java | 5 + .../refinery/store/representation/Symbol.java | 5 + .../refinery/store/representation/TruthValue.java | 5 + .../store/representation/TruthValueDomain.java | 5 + .../cardinality/CardinalityInterval.java | 5 + .../cardinality/CardinalityIntervals.java | 5 + .../cardinality/EmptyCardinalityInterval.java | 5 + .../cardinality/FiniteUpperCardinality.java | 5 + .../cardinality/NonEmptyCardinalityInterval.java | 5 + .../cardinality/UnboundedUpperCardinality.java | 5 + .../cardinality/UpperCardinalities.java | 5 + .../cardinality/UpperCardinality.java | 5 + .../java/tools/refinery/store/tuple/Tuple.java | 5 + .../java/tools/refinery/store/tuple/Tuple0.java | 5 + .../java/tools/refinery/store/tuple/Tuple1.java | 5 + .../java/tools/refinery/store/tuple/Tuple2.java | 5 + .../java/tools/refinery/store/tuple/Tuple3.java | 5 + .../java/tools/refinery/store/tuple/Tuple4.java | 5 + .../tools/refinery/store/tuple/TupleConstants.java | 5 + .../java/tools/refinery/store/tuple/TupleN.java | 5 + .../tools/refinery/store/util/CollectionsUtil.java | 5 + .../refinery/store/util/CycleDetectingMapper.java | 5 + .../refinery/store/map/tests/MapUnitTests.java | 5 + .../store/map/tests/fuzz/CommitFuzzTest.java | 5 + .../map/tests/fuzz/ContentEqualsFuzzTest.java | 5 + .../store/map/tests/fuzz/DiffCursorFuzzTest.java | 5 + .../store/map/tests/fuzz/MultiThreadFuzzTest.java | 5 + .../map/tests/fuzz/MultiThreadTestRunnable.java | 5 + .../store/map/tests/fuzz/MutableFuzzTest.java | 5 + .../fuzz/MutableImmutableCompareFuzzTest.java | 5 + .../store/map/tests/fuzz/RestoreFuzzTest.java | 5 + .../store/map/tests/fuzz/SharedStoreFuzzTest.java | 5 + .../store/map/tests/fuzz/utils/FuzzTestUtils.java | 5 + .../map/tests/fuzz/utils/FuzzTestUtilsTest.java | 5 + .../store/map/tests/utils/MapTestEnvironment.java | 5 + .../store/model/hashtests/HashEfficiencyTest.java | 5 + .../refinery/store/model/tests/ModelTest.java | 5 + .../cardinality/CardinalityIntervalTest.java | 5 + .../cardinality/CardinalityIntervalsTest.java | 5 + .../cardinality/EmptyCardinalityIntervalTest.java | 5 + .../cardinality/FiniteCardinalityIntervalTest.java | 5 + .../cardinality/FiniteUpperCardinalityTest.java | 5 + .../cardinality/UpperCardinalitiesTest.java | 5 + .../cardinality/UpperCardinalityTest.java | 5 + .../refinery/store/util/CollectionsUtilTests.java | 5 + yarn.lock.license | 3 + 569 files changed, 3406 insertions(+), 253 deletions(-) create mode 100644 .reuse/dep5 create mode 100644 .yarn/sdks/integrations.yml.license create mode 100644 CONTRIBUTORS.md create mode 100644 LICENSES/Apache-2.0.txt create mode 100644 LICENSES/BSD-2-Clause.txt create mode 100644 LICENSES/CC0-1.0.txt create mode 100644 LICENSES/EPL-2.0.txt create mode 100644 LICENSES/MIT.txt create mode 100644 gradle/wrapper/gradle-wrapper.jar.license create mode 100644 gradle/wrapper/gradle-wrapper.properties.license create mode 100644 gradlew.bat.license create mode 100644 gradlew.license create mode 100644 subprojects/frontend/assets-src/favicon.svg.license create mode 100644 subprojects/frontend/assets-src/icon.svg.license create mode 100644 subprojects/frontend/assets-src/mask-icon.svg.license create mode 100644 subprojects/frontend/public/apple-touch-icon.png.license create mode 100644 subprojects/frontend/public/favicon-96x96.png.license create mode 100644 subprojects/frontend/public/favicon.png.license create mode 100644 subprojects/frontend/public/favicon.svg.license create mode 100644 subprojects/frontend/public/icon-192x192.png.license create mode 100644 subprojects/frontend/public/icon-512x512.png.license create mode 100644 subprojects/frontend/public/icon-any.svg.license create mode 100644 subprojects/frontend/public/mask-icon.svg.license create mode 100644 subprojects/language-model/META-INF/MANIFEST.MF.license create mode 100644 subprojects/language-model/problem.aird.license create mode 100644 subprojects/language-model/src/main/resources/model/problem.ecore.license create mode 100644 subprojects/language-model/src/main/resources/model/problem.genmodel.license create mode 100644 subprojects/store-query-viatra/NOTICE.md create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionView.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/NodeFunctionView.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/ViewImplication.java create mode 100644 yarn.lock.license (limited to 'subprojects/store-query-viatra/src/main/java/tools') diff --git a/.editorconfig b/.editorconfig index 64f6b1ac..7e5e9f16 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2021-2023 The Refinery Authors +# +# SPDX-License-Identifier: EPL-2.0 + root = true [*] diff --git a/.gitattributes b/.gitattributes index edd224df..847ceced 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2021-2023 The Refinery Authors +# +# SPDX-License-Identifier: CC0-1.0 + .yarn/releases/** binary .yarn/plugins/** binary *.cjs eol=lf diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 64aa23e4..15c62e89 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2021-2023 The Refinery Authors +# +# SPDX-License-Identifier: EPL-2.0 + name: Build on: push: diff --git a/.gitignore b/.gitignore index 559618ab..3117507a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2021-2023 The Refinery Authors +# +# SPDX-License-Identifier: CC0-1.0 + *._trace .classpath .idea/ diff --git a/.reuse/dep5 b/.reuse/dep5 new file mode 100644 index 00000000..523ac368 --- /dev/null +++ b/.reuse/dep5 @@ -0,0 +1,29 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: Refinery +Upstream-Contact: Dániel Varró +Source: https://github.com/graphs4value/refinery + +# Sample paragraph, commented out: +# +# Files: src/* +# Copyright: $YEAR $NAME <$CONTACT> +# License: ... + +Files: .yarn/releases/*.cjs +Copyright: (c) 2016-present, Yarn Contributors. All rights reserved. + (c) 2014-present, Jon Schlinkert. + (c) 2014-2016, Jon Schlinkert. + (c) 2014-2017, Jon Schlinkert. + © 2015-2018, Jon Schlinkert. + (c) 2015-present, Jon Schlinkert. + (c) 2015, Rebecca Turner + Joyent, Inc. and other Node contributors. + Node.js contributors. All rights reserved. + (c) 2014 Blake Embrey (hello@blakeembrey.com) + (c) Facebook, Inc. and its affiliates. +License: BSD-2-Clause AND MIT + +Files: .yarn/sdks/eslint/* + .yarn/sdks/typescript/* +Copyright: (c) 2016-present, Yarn Contributors. All rights reserved. +License: BSD-2-Clause diff --git a/.vscode/extensions.json b/.vscode/extensions.json index fa381855..8ff62a2a 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: CC0-1.0 + */ { "recommendations": [ "EditorConfig.EditorConfig", diff --git a/.vscode/settings.json b/.vscode/settings.json index 66e5806b..52d43dba 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: CC0-1.0 + */ { "search.exclude": { "**/.yarn": true, diff --git a/.yarn/sdks/integrations.yml.license b/.yarn/sdks/integrations.yml.license new file mode 100644 index 00000000..08673e9c --- /dev/null +++ b/.yarn/sdks/integrations.yml.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + +SPDX-License-Identifier: CC0-1.0 diff --git a/.yarnrc.yml b/.yarnrc.yml index 37765fad..5b46a42b 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -1,6 +1,10 @@ +# SPDX-FileCopyrightText: 2021-2023 The Refinery Authors +# +# SPDX-License-Identifier: EPL-2.0 + enableGlobalCache: false -enableTelemetry: 0 +enableTelemetry: false nodeLinker: pnp diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md new file mode 100644 index 00000000..a408945b --- /dev/null +++ b/CONTRIBUTORS.md @@ -0,0 +1,28 @@ + + +# Contributors + +## The Refinery Authors + +**Project leader:** [Prof. Dániel Varró](https://liu.se/en/employee/danva91) <daniel.varro@liu.se> + +Other contributors (in alphabetical order): + +* Ficsor, Attila <ficsorattila96@gmail.com> +* Garami, Bence <85867500+garamibence@users.noreply.github.com> +* Golej, Márton Marcell <golejmarci@gmail.com> +* Marussy, Kristóf <marussy@mit.bme.hu> +* Semeráth, Oszkár <semerath@mit.bme.hu> + +## Support + +Refinery was also supported by + +* [Budapest University of Technology and Economics (BME)](https://www.bme.hu/?language=en), [Department of Measurement and Information Systems (MIT)](https://mit.bme.hu/eng/), [Critical Systems Research Group (FTSRG)](https://ftsrg.mit.bme.hu/en/) +* [Department of Electrical and Computer Engineering](https://www.mcgill.ca/ece/), [McGill University](https://www.mcgill.ca/) +* [2022 Amazon Research Awards](https://www.amazon.science/research-awards/recipients/daniel-varro-fall-2021) +* [Linköping University](https://liu.se/en), [Department of Computer and Information Science (IDA)](https://liu.se/en/organisation/liu/ida), [Software and Systems (SAS)](https://liu.se/en/organisation/liu/ida/sas) diff --git a/LICENSE b/LICENSE index c43ced49..78756b5e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,278 +1,80 @@ Eclipse Public License - v 2.0 - - THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE - PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION - OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 1. DEFINITIONS +“Contribution” means: -"Contribution" means: - - a) in the case of the initial Contributor, the initial content - Distributed under this Agreement, and - - b) in the case of each subsequent Contributor: - i) changes to the Program, and - ii) additions to the Program; - where such changes and/or additions to the Program originate from - and are Distributed by that particular Contributor. A Contribution - "originates" from a Contributor if it was added to the Program by - such Contributor itself or anyone acting on such Contributor's behalf. - Contributions do not include changes or additions to the Program that - are not Modified Works. +a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and +b) in the case of each subsequent Contributor: +i) changes to the Program, and +ii) additions to the Program; +where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works. +“Contributor” means any person or entity that Distributes the Program. -"Contributor" means any person or entity that Distributes the Program. +“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. -"Licensed Patents" mean patent claims licensable by a Contributor which -are necessarily infringed by the use or sale of its Contribution alone -or when combined with the Program. +“Program” means the Contributions Distributed in accordance with this Agreement. -"Program" means the Contributions Distributed in accordance with this -Agreement. +“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors. -"Recipient" means anyone who receives the Program under this Agreement -or any Secondary License (as applicable), including Contributors. +“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. -"Derivative Works" shall mean any work, whether in Source Code or other -form, that is based on (or derived from) the Program and for which the -editorial revisions, annotations, elaborations, or other modifications -represent, as a whole, an original work of authorship. +“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof. -"Modified Works" shall mean any work in Source Code or other form that -results from an addition to, deletion from, or modification of the -contents of the Program, including, for purposes of clarity any new file -in Source Code form that contains any contents of the Program. Modified -Works shall not include works that contain only declarations, -interfaces, types, classes, structures, or files of the Program solely -in each case in order to link to, bind by name, or subclass the Program -or Modified Works thereof. +“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy. -"Distribute" means the acts of a) distributing or b) making available -in any manner that enables the transfer of a copy. +“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files. -"Source Code" means the form of a Program preferred for making -modifications, including but not limited to software source code, -documentation source, and configuration files. - -"Secondary License" means either the GNU General Public License, -Version 2.0, or any later versions of that license, including any -exceptions or additional permissions as identified by the initial -Contributor. +“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor. 2. GRANT OF RIGHTS - - a) Subject to the terms of this Agreement, each Contributor hereby - grants Recipient a non-exclusive, worldwide, royalty-free copyright - license to reproduce, prepare Derivative Works of, publicly display, - publicly perform, Distribute and sublicense the Contribution of such - Contributor, if any, and such Derivative Works. - - b) Subject to the terms of this Agreement, each Contributor hereby - grants Recipient a non-exclusive, worldwide, royalty-free patent - license under Licensed Patents to make, use, sell, offer to sell, - import and otherwise transfer the Contribution of such Contributor, - if any, in Source Code or other form. This patent license shall - apply to the combination of the Contribution and the Program if, at - the time the Contribution is added by the Contributor, such addition - of the Contribution causes such combination to be covered by the - Licensed Patents. The patent license shall not apply to any other - combinations which include the Contribution. No hardware per se is - licensed hereunder. - - c) Recipient understands that although each Contributor grants the - licenses to its Contributions set forth herein, no assurances are - provided by any Contributor that the Program does not infringe the - patent or other intellectual property rights of any other entity. - Each Contributor disclaims any liability to Recipient for claims - brought by any other entity based on infringement of intellectual - property rights or otherwise. As a condition to exercising the - rights and licenses granted hereunder, each Recipient hereby - assumes sole responsibility to secure any other intellectual - property rights needed, if any. For example, if a third party - patent license is required to allow Recipient to Distribute the - Program, it is Recipient's responsibility to acquire that license - before distributing the Program. - - d) Each Contributor represents that to its knowledge it has - sufficient copyright rights in its Contribution, if any, to grant - the copyright license set forth in this Agreement. - - e) Notwithstanding the terms of any Secondary License, no - Contributor makes additional grants to any Recipient (other than - those set forth in this Agreement) as a result of such Recipient's - receipt of the Program under the terms of a Secondary License - (if permitted under the terms of Section 3). - +a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works. +b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. +c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. +d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. +e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3). 3. REQUIREMENTS - 3.1 If a Contributor Distributes the Program in any form, then: - a) the Program must also be made available as Source Code, in - accordance with section 3.2, and the Contributor must accompany - the Program with a statement that the Source Code for the Program - is available under this Agreement, and informs Recipients how to - obtain it in a reasonable manner on or through a medium customarily - used for software exchange; and - - b) the Contributor may Distribute the Program under a license - different than this Agreement, provided that such license: - i) effectively disclaims on behalf of all other Contributors all - warranties and conditions, express and implied, including - warranties or conditions of title and non-infringement, and - implied warranties or conditions of merchantability and fitness - for a particular purpose; - - ii) effectively excludes on behalf of all other Contributors all - liability for damages, including direct, indirect, special, - incidental and consequential damages, such as lost profits; - - iii) does not attempt to limit or alter the recipients' rights - in the Source Code under section 3.2; and - - iv) requires any subsequent distribution of the Program by any - party to be under a license that satisfies the requirements - of this section 3. - +a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and +b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license: +i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; +ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; +iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and +iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3. 3.2 When the Program is Distributed as Source Code: - a) it must be made available under this Agreement, or if the - Program (i) is combined with other material in a separate file or - files made available under a Secondary License, and (ii) the initial - Contributor attached to the Source Code the notice described in - Exhibit A of this Agreement, then the Program may be made available - under the terms of such Secondary Licenses, and - - b) a copy of this Agreement must be included with each copy of - the Program. - -3.3 Contributors may not remove or alter any copyright, patent, -trademark, attribution notices, disclaimers of warranty, or limitations -of liability ("notices") contained within the Program from any copy of -the Program which they Distribute, provided that Contributors may add -their own appropriate notices. +a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and +b) a copy of this Agreement must be included with each copy of the Program. +3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices. 4. COMMERCIAL DISTRIBUTION +Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. -Commercial distributors of software may accept certain responsibilities -with respect to end users, business partners and the like. While this -license is intended to facilitate the commercial use of the Program, -the Contributor who includes the Program in a commercial product -offering should do so in a manner which does not create potential -liability for other Contributors. Therefore, if a Contributor includes -the Program in a commercial product offering, such Contributor -("Commercial Contributor") hereby agrees to defend and indemnify every -other Contributor ("Indemnified Contributor") against any losses, -damages and costs (collectively "Losses") arising from claims, lawsuits -and other legal actions brought by a third party against the Indemnified -Contributor to the extent caused by the acts or omissions of such -Commercial Contributor in connection with its distribution of the Program -in a commercial product offering. The obligations in this section do not -apply to any claims or Losses relating to any actual or alleged -intellectual property infringement. In order to qualify, an Indemnified -Contributor must: a) promptly notify the Commercial Contributor in -writing of such claim, and b) allow the Commercial Contributor to control, -and cooperate with the Commercial Contributor in, the defense and any -related settlement negotiations. The Indemnified Contributor may -participate in any such claim at its own expense. - -For example, a Contributor might include the Program in a commercial -product offering, Product X. That Contributor is then a Commercial -Contributor. If that Commercial Contributor then makes performance -claims, or offers warranties related to Product X, those performance -claims and warranties are such Commercial Contributor's responsibility -alone. Under this section, the Commercial Contributor would have to -defend claims against the other Contributors related to those performance -claims and warranties, and if a court requires any other Contributor to -pay any damages as a result, the Commercial Contributor must pay -those damages. +For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. 5. NO WARRANTY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT -PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" -BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR -IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF -TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR -PURPOSE. Each Recipient is solely responsible for determining the -appropriateness of using and distributing the Program and assumes all -risks associated with its exercise of rights under this Agreement, -including but not limited to the risks and costs of program errors, -compliance with applicable laws, damage to or loss of data, programs -or equipment, and unavailability or interruption of operations. +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. 6. DISCLAIMER OF LIABILITY - -EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT -PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS -SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST -PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE -EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. GENERAL +If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. -If any provision of this Agreement is invalid or unenforceable under -applicable law, it shall not affect the validity or enforceability of -the remainder of the terms of this Agreement, and without further -action by the parties hereto, such provision shall be reformed to the -minimum extent necessary to make such provision valid and enforceable. - -If Recipient institutes patent litigation against any entity -(including a cross-claim or counterclaim in a lawsuit) alleging that the -Program itself (excluding combinations of the Program with other software -or hardware) infringes such Recipient's patent(s), then such Recipient's -rights granted under Section 2(b) shall terminate as of the date such -litigation is filed. - -All Recipient's rights under this Agreement shall terminate if it -fails to comply with any of the material terms or conditions of this -Agreement and does not cure such failure in a reasonable period of -time after becoming aware of such noncompliance. If all Recipient's -rights under this Agreement terminate, Recipient agrees to cease use -and distribution of the Program as soon as reasonably practicable. -However, Recipient's obligations under this Agreement and any licenses -granted by Recipient relating to the Program shall continue and survive. - -Everyone is permitted to copy and distribute copies of this Agreement, -but in order to avoid inconsistency the Agreement is copyrighted and -may only be modified in the following manner. The Agreement Steward -reserves the right to publish new versions (including revisions) of -this Agreement from time to time. No one other than the Agreement -Steward has the right to modify this Agreement. The Eclipse Foundation -is the initial Agreement Steward. The Eclipse Foundation may assign the -responsibility to serve as the Agreement Steward to a suitable separate -entity. Each new version of the Agreement will be given a distinguishing -version number. The Program (including Contributions) may always be -Distributed subject to the version of the Agreement under which it was -received. In addition, after a new version of the Agreement is published, -Contributor may elect to Distribute the Program (including its -Contributions) under the new version. +If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. -Except as expressly stated in Sections 2(a) and 2(b) above, Recipient -receives no rights or licenses to the intellectual property of any -Contributor under this Agreement, whether expressly, by implication, -estoppel or otherwise. All rights in the Program not expressly granted -under this Agreement are reserved. Nothing in this Agreement is intended -to be enforceable by any entity that is not a Contributor or Recipient. -No third-party beneficiary rights are created under this Agreement. +All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. -Exhibit A - Form of Secondary Licenses Notice +Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version. -"This Source Code may also be made available under the following -Secondary Licenses when the conditions for such availability set forth -in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), -version(s), and exceptions or additional permissions here}." +Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement. - Simply including a copy of this Agreement, including this Exhibit A - is not sufficient to license the Source Code under Secondary Licenses. +Exhibit A – Form of Secondary Licenses Notice +“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.” - If it is not possible or desirable to put the notice in a particular - file, then You may include the notice in a location (such as a LICENSE - file in a relevant directory) where a recipient would be likely to - look for such a notice. +Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses. - You may add additional accurate notices of copyright ownership. +If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. +You may add additional accurate notices of copyright ownership. diff --git a/LICENSES/Apache-2.0.txt b/LICENSES/Apache-2.0.txt new file mode 100644 index 00000000..137069b8 --- /dev/null +++ b/LICENSES/Apache-2.0.txt @@ -0,0 +1,73 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSES/BSD-2-Clause.txt b/LICENSES/BSD-2-Clause.txt new file mode 100644 index 00000000..5f662b35 --- /dev/null +++ b/LICENSES/BSD-2-Clause.txt @@ -0,0 +1,9 @@ +Copyright (c) + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSES/CC0-1.0.txt b/LICENSES/CC0-1.0.txt new file mode 100644 index 00000000..0e259d42 --- /dev/null +++ b/LICENSES/CC0-1.0.txt @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/LICENSES/EPL-2.0.txt b/LICENSES/EPL-2.0.txt new file mode 100644 index 00000000..78756b5e --- /dev/null +++ b/LICENSES/EPL-2.0.txt @@ -0,0 +1,80 @@ +Eclipse Public License - v 2.0 +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS +“Contribution” means: + +a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and +b) in the case of each subsequent Contributor: +i) changes to the Program, and +ii) additions to the Program; +where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works. +“Contributor” means any person or entity that Distributes the Program. + +“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + +“Program” means the Contributions Distributed in accordance with this Agreement. + +“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors. + +“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. + +“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof. + +“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy. + +“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files. + +“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor. + +2. GRANT OF RIGHTS +a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works. +b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. +c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. +d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. +e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3). +3. REQUIREMENTS +3.1 If a Contributor Distributes the Program in any form, then: + +a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and +b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license: +i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; +ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; +iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and +iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3. +3.2 When the Program is Distributed as Source Code: + +a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and +b) a copy of this Agreement must be included with each copy of the Program. +3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices. + +4. COMMERCIAL DISTRIBUTION +Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + +5. NO WARRANTY +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL +If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version. + +Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement. + +Exhibit A – Form of Secondary Licenses Notice +“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.” + +Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses. + +If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. diff --git a/LICENSES/MIT.txt b/LICENSES/MIT.txt new file mode 100644 index 00000000..2071b23b --- /dev/null +++ b/LICENSES/MIT.txt @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 33d89786..4dbc3bf5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ + + # Refinery [![Build](https://github.com/graphs4value/refinery/actions/workflows/build.yml/badge.svg)](https://github.com/graphs4value/refinery/actions/workflows/build.yml) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=graphs4value_refinery&metric=alert_status)](https://sonarcloud.io/dashboard?id=graphs4value_refinery) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=graphs4value_refinery&metric=coverage)](https://sonarcloud.io/dashboard?id=graphs4value_refinery) @@ -45,4 +51,9 @@ It is possible to import the project into IntelliJ IDEA, but it gives no editing ## License -All code in this repository is available under the [Eclipse Public License - v 2.0](https://www.eclipse.org/legal/epl-2.0/). +Copyright (c) 2021-2023 [The Refinery Authors](CONTRIBUTORS.md) + +Refinery is available under the [Eclipse Public License - v 2.0](https://www.eclipse.org/legal/epl-2.0/). + +Refinery complies with the [REUSE Specification – Version 3.0](https://reuse.software/) to provide copyright and licensing information to each file, including files available under other licenses. +For more information, see the comments headers in each file and the license texts in the [LICENSES](LICENSES/) directory. diff --git a/build.gradle.kts b/build.gradle.kts index 5a673f33..ed1c8aa6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + plugins { // Workaround for https://github.com/gradle/gradle/issues/22797 @Suppress("DSL_SCOPE_VIOLATION") diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 7a5ee5c4..90864a8f 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + plugins { `kotlin-dsl` // Workaround for https://github.com/gradle/gradle/issues/22797 diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts index 8e6efa3d..1daa9bbd 100644 --- a/buildSrc/settings.gradle.kts +++ b/buildSrc/settings.gradle.kts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + dependencyResolutionManagement { versionCatalogs { create("libs") { diff --git a/buildSrc/src/main/java/tools/refinery/gradle/utils/EclipseUtils.java b/buildSrc/src/main/java/tools/refinery/gradle/utils/EclipseUtils.java index 1e33a95d..ac7ba3f4 100644 --- a/buildSrc/src/main/java/tools/refinery/gradle/utils/EclipseUtils.java +++ b/buildSrc/src/main/java/tools/refinery/gradle/utils/EclipseUtils.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.gradle.utils; import groovy.lang.Closure; diff --git a/buildSrc/src/main/java/tools/refinery/gradle/utils/SonarPropertiesUtils.java b/buildSrc/src/main/java/tools/refinery/gradle/utils/SonarPropertiesUtils.java index 3810fccf..183cd56a 100644 --- a/buildSrc/src/main/java/tools/refinery/gradle/utils/SonarPropertiesUtils.java +++ b/buildSrc/src/main/java/tools/refinery/gradle/utils/SonarPropertiesUtils.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.gradle.utils; import java.util.ArrayList; diff --git a/buildSrc/src/main/kotlin/tools/refinery/gradle/eclipse.gradle.kts b/buildSrc/src/main/kotlin/tools/refinery/gradle/eclipse.gradle.kts index 25e7e573..8bab1d2b 100644 --- a/buildSrc/src/main/kotlin/tools/refinery/gradle/eclipse.gradle.kts +++ b/buildSrc/src/main/kotlin/tools/refinery/gradle/eclipse.gradle.kts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.gradle import java.util.Properties diff --git a/buildSrc/src/main/kotlin/tools/refinery/gradle/frontend-workspace.gradle.kts b/buildSrc/src/main/kotlin/tools/refinery/gradle/frontend-workspace.gradle.kts index 174a2d65..f1f6d952 100644 --- a/buildSrc/src/main/kotlin/tools/refinery/gradle/frontend-workspace.gradle.kts +++ b/buildSrc/src/main/kotlin/tools/refinery/gradle/frontend-workspace.gradle.kts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.gradle plugins { diff --git a/buildSrc/src/main/kotlin/tools/refinery/gradle/frontend-worktree.gradle.kts b/buildSrc/src/main/kotlin/tools/refinery/gradle/frontend-worktree.gradle.kts index 3225a1b1..218f5207 100644 --- a/buildSrc/src/main/kotlin/tools/refinery/gradle/frontend-worktree.gradle.kts +++ b/buildSrc/src/main/kotlin/tools/refinery/gradle/frontend-worktree.gradle.kts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.gradle import java.io.FileInputStream diff --git a/buildSrc/src/main/kotlin/tools/refinery/gradle/internal/frontend-conventions.gradle.kts b/buildSrc/src/main/kotlin/tools/refinery/gradle/internal/frontend-conventions.gradle.kts index b15de515..bd5d0197 100644 --- a/buildSrc/src/main/kotlin/tools/refinery/gradle/internal/frontend-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/tools/refinery/gradle/internal/frontend-conventions.gradle.kts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.gradle.internal plugins { diff --git a/buildSrc/src/main/kotlin/tools/refinery/gradle/internal/java-conventions.gradle.kts b/buildSrc/src/main/kotlin/tools/refinery/gradle/internal/java-conventions.gradle.kts index 67bb5d88..d8deffae 100644 --- a/buildSrc/src/main/kotlin/tools/refinery/gradle/internal/java-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/tools/refinery/gradle/internal/java-conventions.gradle.kts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.gradle.internal import org.gradle.accessors.dm.LibrariesForLibs diff --git a/buildSrc/src/main/kotlin/tools/refinery/gradle/java-application.gradle.kts b/buildSrc/src/main/kotlin/tools/refinery/gradle/java-application.gradle.kts index 269af11c..0924311b 100644 --- a/buildSrc/src/main/kotlin/tools/refinery/gradle/java-application.gradle.kts +++ b/buildSrc/src/main/kotlin/tools/refinery/gradle/java-application.gradle.kts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.gradle import org.gradle.accessors.dm.LibrariesForLibs diff --git a/buildSrc/src/main/kotlin/tools/refinery/gradle/java-library.gradle.kts b/buildSrc/src/main/kotlin/tools/refinery/gradle/java-library.gradle.kts index 084f65ae..3aff3833 100644 --- a/buildSrc/src/main/kotlin/tools/refinery/gradle/java-library.gradle.kts +++ b/buildSrc/src/main/kotlin/tools/refinery/gradle/java-library.gradle.kts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.gradle plugins { diff --git a/buildSrc/src/main/kotlin/tools/refinery/gradle/java-test-fixtures.gradle.kts b/buildSrc/src/main/kotlin/tools/refinery/gradle/java-test-fixtures.gradle.kts index 7e599c3f..a28484d4 100644 --- a/buildSrc/src/main/kotlin/tools/refinery/gradle/java-test-fixtures.gradle.kts +++ b/buildSrc/src/main/kotlin/tools/refinery/gradle/java-test-fixtures.gradle.kts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.gradle import org.gradle.plugins.ide.eclipse.model.AbstractClasspathEntry diff --git a/buildSrc/src/main/kotlin/tools/refinery/gradle/jmh.gradle.kts b/buildSrc/src/main/kotlin/tools/refinery/gradle/jmh.gradle.kts index eda7d5c6..6fb8fbac 100644 --- a/buildSrc/src/main/kotlin/tools/refinery/gradle/jmh.gradle.kts +++ b/buildSrc/src/main/kotlin/tools/refinery/gradle/jmh.gradle.kts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.gradle import org.gradle.accessors.dm.LibrariesForLibs diff --git a/buildSrc/src/main/kotlin/tools/refinery/gradle/mwe2.gradle.kts b/buildSrc/src/main/kotlin/tools/refinery/gradle/mwe2.gradle.kts index 8eeabf47..f4381434 100644 --- a/buildSrc/src/main/kotlin/tools/refinery/gradle/mwe2.gradle.kts +++ b/buildSrc/src/main/kotlin/tools/refinery/gradle/mwe2.gradle.kts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.gradle import org.gradle.accessors.dm.LibrariesForLibs diff --git a/buildSrc/src/main/kotlin/tools/refinery/gradle/sonarqube.gradle.kts b/buildSrc/src/main/kotlin/tools/refinery/gradle/sonarqube.gradle.kts index ebd9170a..93406492 100644 --- a/buildSrc/src/main/kotlin/tools/refinery/gradle/sonarqube.gradle.kts +++ b/buildSrc/src/main/kotlin/tools/refinery/gradle/sonarqube.gradle.kts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.gradle plugins { diff --git a/buildSrc/src/main/kotlin/tools/refinery/gradle/xtext-generated.gradle.kts b/buildSrc/src/main/kotlin/tools/refinery/gradle/xtext-generated.gradle.kts index 25aeb826..59fe921b 100644 --- a/buildSrc/src/main/kotlin/tools/refinery/gradle/xtext-generated.gradle.kts +++ b/buildSrc/src/main/kotlin/tools/refinery/gradle/xtext-generated.gradle.kts @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.gradle import tools.refinery.gradle.utils.SonarPropertiesUtils diff --git a/gradle.properties b/gradle.properties index 8faaa0eb..d6faa150 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2021-2023 The Refinery Authors +# +# SPDX-License-Identifier: EPL-2.0 + file.encoding=UTF-8 frontend.nodeVersion=18.15.0 frontend.yarnVersion=4.0.0-rc.42 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fe5966af..113bf3a5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2021-2023 The Refinery Authors +# +# SPDX-License-Identifier: EPL-2.0 + [versions] eclipseCollections = "12.0.0.M1" jetty = "12.0.0.beta0" diff --git a/gradle/wrapper/gradle-wrapper.jar.license b/gradle/wrapper/gradle-wrapper.jar.license new file mode 100644 index 00000000..13cd9906 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.jar.license @@ -0,0 +1,3 @@ +Copyright © 2015-2021 the original authors. + +SPDX-License-Identifier: Apache-2.0 diff --git a/gradle/wrapper/gradle-wrapper.properties.license b/gradle/wrapper/gradle-wrapper.properties.license new file mode 100644 index 00000000..13cd9906 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties.license @@ -0,0 +1,3 @@ +Copyright © 2015-2021 the original authors. + +SPDX-License-Identifier: Apache-2.0 diff --git a/gradlew.bat.license b/gradlew.bat.license new file mode 100644 index 00000000..0bcf26f6 --- /dev/null +++ b/gradlew.bat.license @@ -0,0 +1,3 @@ +Copyright 2015 the original author or authors. + +SPDX-License-Identifier: Apache-2.0 diff --git a/gradlew.license b/gradlew.license new file mode 100644 index 00000000..13cd9906 --- /dev/null +++ b/gradlew.license @@ -0,0 +1,3 @@ +Copyright © 2015-2021 the original authors. + +SPDX-License-Identifier: Apache-2.0 diff --git a/package.json b/package.json index 2da37157..c714ecd0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,22 @@ { + "//": [ + "SPDX-FileCopyrightText: 2021-2023 The Refinery Authors ", + "", + "SPDX-License-Identifier: EPL-2.0" + ], "name": "@refinery/root", "version": "0.0.0", "private": true, + "repository": { + "type": "git", + "url": "git+https://github.com/graphs4value/refinery.git" + }, + "author": "The Refinery Authors ", + "license": "EPL-2.0", + "bugs": { + "url": "https://github.com/graphs4value/refinery/issues" + }, + "homepage": "https://refinery.tools", "workspaces": [ "subprojects/frontend" ], diff --git a/settings.gradle.kts b/settings.gradle.kts index cca283dc..2b1c179d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + rootProject.name = "refinery" include( diff --git a/subprojects/frontend/.eslintrc.cjs b/subprojects/frontend/.eslintrc.cjs index dc03d721..466e5668 100644 --- a/subprojects/frontend/.eslintrc.cjs +++ b/subprojects/frontend/.eslintrc.cjs @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + const path = require('node:path'); // Allow the Codium ESLint plugin to find `tsconfig.json` from the repository root. diff --git a/subprojects/frontend/assets-src/favicon.svg.license b/subprojects/frontend/assets-src/favicon.svg.license new file mode 100644 index 00000000..e5db6ccd --- /dev/null +++ b/subprojects/frontend/assets-src/favicon.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/frontend/assets-src/icon.svg.license b/subprojects/frontend/assets-src/icon.svg.license new file mode 100644 index 00000000..e5db6ccd --- /dev/null +++ b/subprojects/frontend/assets-src/icon.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/frontend/assets-src/mask-icon.svg.license b/subprojects/frontend/assets-src/mask-icon.svg.license new file mode 100644 index 00000000..e5db6ccd --- /dev/null +++ b/subprojects/frontend/assets-src/mask-icon.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/frontend/build.gradle.kts b/subprojects/frontend/build.gradle.kts index 80f10f7e..9fd99742 100644 --- a/subprojects/frontend/build.gradle.kts +++ b/subprojects/frontend/build.gradle.kts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import org.siouan.frontendgradleplugin.infrastructure.gradle.RunYarn import tools.refinery.gradle.utils.SonarPropertiesUtils diff --git a/subprojects/frontend/config/backendConfigVitePlugin.ts b/subprojects/frontend/config/backendConfigVitePlugin.ts index 7a6bc3db..3bffce3a 100644 --- a/subprojects/frontend/config/backendConfigVitePlugin.ts +++ b/subprojects/frontend/config/backendConfigVitePlugin.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import type { PluginOption } from 'vite'; import type BackendConfig from '../src/xtext/BackendConfig'; diff --git a/subprojects/frontend/config/detectDevModeOptions.ts b/subprojects/frontend/config/detectDevModeOptions.ts index b3696241..665204dc 100644 --- a/subprojects/frontend/config/detectDevModeOptions.ts +++ b/subprojects/frontend/config/detectDevModeOptions.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import type { PluginOption, ServerOptions } from 'vite'; import backendConfigVitePlugin, { diff --git a/subprojects/frontend/config/eslintReport.cjs b/subprojects/frontend/config/eslintReport.cjs index 5bf6a041..7c4b7bd6 100644 --- a/subprojects/frontend/config/eslintReport.cjs +++ b/subprojects/frontend/config/eslintReport.cjs @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + const { writeFile } = require('node:fs/promises'); const path = require('node:path'); const { Readable } = require('node:stream'); diff --git a/subprojects/frontend/config/fetchPackageMetadata.ts b/subprojects/frontend/config/fetchPackageMetadata.ts index 50807b03..02e16d57 100644 --- a/subprojects/frontend/config/fetchPackageMetadata.ts +++ b/subprojects/frontend/config/fetchPackageMetadata.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { readFile } from 'node:fs/promises'; import path from 'node:path'; diff --git a/subprojects/frontend/config/manifest.ts b/subprojects/frontend/config/manifest.ts index 3cec777c..1822dc7c 100644 --- a/subprojects/frontend/config/manifest.ts +++ b/subprojects/frontend/config/manifest.ts @@ -1,10 +1,16 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import type { ManifestOptions } from 'vite-plugin-pwa'; const manifest: Partial = { lang: 'en-US', name: 'Refinery', short_name: 'Refinery', - description: 'An efficient graph sovler for generating well-formed models', + description: 'An efficient graph solver for generating well-formed models', theme_color: '#f5f5f5', display_override: ['window-controls-overlay'], display: 'standalone', diff --git a/subprojects/frontend/config/minifyHTMLVitePlugin.ts b/subprojects/frontend/config/minifyHTMLVitePlugin.ts index 18336d4d..7c08c488 100644 --- a/subprojects/frontend/config/minifyHTMLVitePlugin.ts +++ b/subprojects/frontend/config/minifyHTMLVitePlugin.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { minify, type Options as TerserOptions } from 'html-minifier-terser'; import type { PluginOption } from 'vite'; diff --git a/subprojects/frontend/config/preloadFontsVitePlugin.ts b/subprojects/frontend/config/preloadFontsVitePlugin.ts index bc6f8eaf..5c04477a 100644 --- a/subprojects/frontend/config/preloadFontsVitePlugin.ts +++ b/subprojects/frontend/config/preloadFontsVitePlugin.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import micromatch from 'micromatch'; import type { PluginOption } from 'vite'; diff --git a/subprojects/frontend/index.html b/subprojects/frontend/index.html index 8b6814eb..e1d2bf14 100644 --- a/subprojects/frontend/index.html +++ b/subprojects/frontend/index.html @@ -1,4 +1,9 @@ + diff --git a/subprojects/frontend/package.json b/subprojects/frontend/package.json index e6bcc89e..cd96a574 100644 --- a/subprojects/frontend/package.json +++ b/subprojects/frontend/package.json @@ -1,4 +1,9 @@ { + "//": [ + "SPDX-FileCopyrightText: 2021-2023 The Refinery Authors ", + "", + "SPDX-License-Identifier: EPL-2.0" + ], "name": "@refinery/frontend", "version": "0.0.0", "description": "Web frontend for Refinery", @@ -16,10 +21,10 @@ "type": "git", "url": "git+https://github.com/graphs4value/refinery.git" }, - "author": "Refinery authors", + "author": "The Refinery Authors ", "license": "EPL-2.0", "bugs": { - "url": "https://github.com/graphs4value/issues" + "url": "https://github.com/graphs4value/refinery/issues" }, "homepage": "https://refinery.tools", "dependencies": { diff --git a/subprojects/frontend/prettier.config.cjs b/subprojects/frontend/prettier.config.cjs index 75f5c54d..6f9ff7ad 100644 --- a/subprojects/frontend/prettier.config.cjs +++ b/subprojects/frontend/prettier.config.cjs @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + /** @type {import('prettier').Config} */ module.exports = { singleQuote: true, diff --git a/subprojects/frontend/public/apple-touch-icon.png.license b/subprojects/frontend/public/apple-touch-icon.png.license new file mode 100644 index 00000000..e5db6ccd --- /dev/null +++ b/subprojects/frontend/public/apple-touch-icon.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/frontend/public/favicon-96x96.png.license b/subprojects/frontend/public/favicon-96x96.png.license new file mode 100644 index 00000000..e5db6ccd --- /dev/null +++ b/subprojects/frontend/public/favicon-96x96.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/frontend/public/favicon.png.license b/subprojects/frontend/public/favicon.png.license new file mode 100644 index 00000000..e5db6ccd --- /dev/null +++ b/subprojects/frontend/public/favicon.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/frontend/public/favicon.svg.license b/subprojects/frontend/public/favicon.svg.license new file mode 100644 index 00000000..e5db6ccd --- /dev/null +++ b/subprojects/frontend/public/favicon.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/frontend/public/icon-192x192.png.license b/subprojects/frontend/public/icon-192x192.png.license new file mode 100644 index 00000000..e5db6ccd --- /dev/null +++ b/subprojects/frontend/public/icon-192x192.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/frontend/public/icon-512x512.png.license b/subprojects/frontend/public/icon-512x512.png.license new file mode 100644 index 00000000..e5db6ccd --- /dev/null +++ b/subprojects/frontend/public/icon-512x512.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/frontend/public/icon-any.svg.license b/subprojects/frontend/public/icon-any.svg.license new file mode 100644 index 00000000..e5db6ccd --- /dev/null +++ b/subprojects/frontend/public/icon-any.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/frontend/public/mask-icon.svg.license b/subprojects/frontend/public/mask-icon.svg.license new file mode 100644 index 00000000..e5db6ccd --- /dev/null +++ b/subprojects/frontend/public/mask-icon.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/frontend/public/robots.txt b/subprojects/frontend/public/robots.txt index c2a49f4f..e7c73099 100644 --- a/subprojects/frontend/public/robots.txt +++ b/subprojects/frontend/public/robots.txt @@ -1,2 +1,6 @@ +# SPDX-FileCopyrightText: 2021-2023 The Refinery Authors +# +# SPDX-License-Identifier: CC0-1.0 + User-agent: * Allow: / diff --git a/subprojects/frontend/src/App.tsx b/subprojects/frontend/src/App.tsx index cd394345..7f242529 100644 --- a/subprojects/frontend/src/App.tsx +++ b/subprojects/frontend/src/App.tsx @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import Box from '@mui/material/Box'; import CssBaseline from '@mui/material/CssBaseline'; import { throttle } from 'lodash-es'; diff --git a/subprojects/frontend/src/Loading.tsx b/subprojects/frontend/src/Loading.tsx index 489563e0..adee4f0e 100644 --- a/subprojects/frontend/src/Loading.tsx +++ b/subprojects/frontend/src/Loading.tsx @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import CircularProgress from '@mui/material/CircularProgress'; import { styled } from '@mui/material/styles'; diff --git a/subprojects/frontend/src/PWAStore.ts b/subprojects/frontend/src/PWAStore.ts index e9f99e2a..a1b3ffd9 100644 --- a/subprojects/frontend/src/PWAStore.ts +++ b/subprojects/frontend/src/PWAStore.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { makeAutoObservable, observable } from 'mobx'; import ms from 'ms'; // eslint-disable-next-line import/no-unresolved -- Importing virtual module. diff --git a/subprojects/frontend/src/Refinery.tsx b/subprojects/frontend/src/Refinery.tsx index f0162349..b5ff94e1 100644 --- a/subprojects/frontend/src/Refinery.tsx +++ b/subprojects/frontend/src/Refinery.tsx @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import Grow from '@mui/material/Grow'; import Stack from '@mui/material/Stack'; import { SnackbarProvider } from 'notistack'; diff --git a/subprojects/frontend/src/RootStore.ts b/subprojects/frontend/src/RootStore.ts index 2e76d66d..b84c0ce0 100644 --- a/subprojects/frontend/src/RootStore.ts +++ b/subprojects/frontend/src/RootStore.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { getLogger } from 'loglevel'; import { makeAutoObservable, runInAction } from 'mobx'; diff --git a/subprojects/frontend/src/RootStoreProvider.tsx b/subprojects/frontend/src/RootStoreProvider.tsx index 2c11a0f9..7cb89af1 100644 --- a/subprojects/frontend/src/RootStoreProvider.tsx +++ b/subprojects/frontend/src/RootStoreProvider.tsx @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { type ReactNode, createContext, useContext } from 'react'; import type RootStore from './RootStore'; diff --git a/subprojects/frontend/src/ToggleDarkModeButton.tsx b/subprojects/frontend/src/ToggleDarkModeButton.tsx index 59714f20..7a835e61 100644 --- a/subprojects/frontend/src/ToggleDarkModeButton.tsx +++ b/subprojects/frontend/src/ToggleDarkModeButton.tsx @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import DarkModeIcon from '@mui/icons-material/DarkMode'; import LightModeIcon from '@mui/icons-material/LightMode'; import IconButton from '@mui/material/IconButton'; diff --git a/subprojects/frontend/src/TopBar.tsx b/subprojects/frontend/src/TopBar.tsx index 5a825512..f2542b14 100644 --- a/subprojects/frontend/src/TopBar.tsx +++ b/subprojects/frontend/src/TopBar.tsx @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import GitHubIcon from '@mui/icons-material/GitHub'; import AppBar from '@mui/material/AppBar'; import Button from '@mui/material/Button'; diff --git a/subprojects/frontend/src/UpdateNotification.tsx b/subprojects/frontend/src/UpdateNotification.tsx index 5c8c2d01..d86c0703 100644 --- a/subprojects/frontend/src/UpdateNotification.tsx +++ b/subprojects/frontend/src/UpdateNotification.tsx @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import Button from '@mui/material/Button'; import { observer } from 'mobx-react-lite'; import { useEffect } from 'react'; diff --git a/subprojects/frontend/src/WindowControlsOverlayColor.tsx b/subprojects/frontend/src/WindowControlsOverlayColor.tsx index 14eda566..cfa468ea 100644 --- a/subprojects/frontend/src/WindowControlsOverlayColor.tsx +++ b/subprojects/frontend/src/WindowControlsOverlayColor.tsx @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { useTheme } from '@mui/material/styles'; import { useEffect } from 'react'; diff --git a/subprojects/frontend/src/editor/AnimatedButton.tsx b/subprojects/frontend/src/editor/AnimatedButton.tsx index f75d4617..dbbda618 100644 --- a/subprojects/frontend/src/editor/AnimatedButton.tsx +++ b/subprojects/frontend/src/editor/AnimatedButton.tsx @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import { styled, type SxProps, type Theme } from '@mui/material/styles'; diff --git a/subprojects/frontend/src/editor/ConnectButton.tsx b/subprojects/frontend/src/editor/ConnectButton.tsx index e2d251f3..eed6fbc7 100644 --- a/subprojects/frontend/src/editor/ConnectButton.tsx +++ b/subprojects/frontend/src/editor/ConnectButton.tsx @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import CloudIcon from '@mui/icons-material/Cloud'; import CloudOffIcon from '@mui/icons-material/CloudOff'; import SyncIcon from '@mui/icons-material/Sync'; diff --git a/subprojects/frontend/src/editor/ConnectionStatusNotification.tsx b/subprojects/frontend/src/editor/ConnectionStatusNotification.tsx index 9b27f45c..b7b962ab 100644 --- a/subprojects/frontend/src/editor/ConnectionStatusNotification.tsx +++ b/subprojects/frontend/src/editor/ConnectionStatusNotification.tsx @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import Button from '@mui/material/Button'; import { observer } from 'mobx-react-lite'; import { useEffect } from 'react'; diff --git a/subprojects/frontend/src/editor/DiagnosticValue.ts b/subprojects/frontend/src/editor/DiagnosticValue.ts index b4e0b165..20478262 100644 --- a/subprojects/frontend/src/editor/DiagnosticValue.ts +++ b/subprojects/frontend/src/editor/DiagnosticValue.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import type { Diagnostic } from '@codemirror/lint'; import { RangeValue } from '@codemirror/state'; diff --git a/subprojects/frontend/src/editor/EditorArea.tsx b/subprojects/frontend/src/editor/EditorArea.tsx index cfb988b2..905fa2ec 100644 --- a/subprojects/frontend/src/editor/EditorArea.tsx +++ b/subprojects/frontend/src/editor/EditorArea.tsx @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import Box from '@mui/material/Box'; import { useTheme } from '@mui/material/styles'; import { observer } from 'mobx-react-lite'; diff --git a/subprojects/frontend/src/editor/EditorButtons.tsx b/subprojects/frontend/src/editor/EditorButtons.tsx index 53b06e23..9b187e5c 100644 --- a/subprojects/frontend/src/editor/EditorButtons.tsx +++ b/subprojects/frontend/src/editor/EditorButtons.tsx @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import type { Diagnostic } from '@codemirror/lint'; import CheckIcon from '@mui/icons-material/Check'; import ErrorIcon from '@mui/icons-material/Error'; diff --git a/subprojects/frontend/src/editor/EditorPane.tsx b/subprojects/frontend/src/editor/EditorPane.tsx index f7f8241a..87f408fe 100644 --- a/subprojects/frontend/src/editor/EditorPane.tsx +++ b/subprojects/frontend/src/editor/EditorPane.tsx @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import Box from '@mui/material/Box'; import Skeleton from '@mui/material/Skeleton'; import Stack from '@mui/material/Stack'; diff --git a/subprojects/frontend/src/editor/EditorStore.ts b/subprojects/frontend/src/editor/EditorStore.ts index 0a0d885d..b98f085e 100644 --- a/subprojects/frontend/src/editor/EditorStore.ts +++ b/subprojects/frontend/src/editor/EditorStore.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import type { CompletionContext, CompletionResult, diff --git a/subprojects/frontend/src/editor/EditorTheme.ts b/subprojects/frontend/src/editor/EditorTheme.ts index 01b65a7e..023a8f73 100644 --- a/subprojects/frontend/src/editor/EditorTheme.ts +++ b/subprojects/frontend/src/editor/EditorTheme.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import errorSVG from '@material-icons/svg/svg/error/baseline.svg?raw'; import expandMoreSVG from '@material-icons/svg/svg/expand_more/baseline.svg?raw'; import infoSVG from '@material-icons/svg/svg/info/baseline.svg?raw'; diff --git a/subprojects/frontend/src/editor/GenerateButton.tsx b/subprojects/frontend/src/editor/GenerateButton.tsx index 2036fc28..3837ef8e 100644 --- a/subprojects/frontend/src/editor/GenerateButton.tsx +++ b/subprojects/frontend/src/editor/GenerateButton.tsx @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import DangerousOutlinedIcon from '@mui/icons-material/DangerousOutlined'; import PlayArrowIcon from '@mui/icons-material/PlayArrow'; import Button from '@mui/material/Button'; diff --git a/subprojects/frontend/src/editor/LintPanelStore.ts b/subprojects/frontend/src/editor/LintPanelStore.ts index 502f9c59..f81587fa 100644 --- a/subprojects/frontend/src/editor/LintPanelStore.ts +++ b/subprojects/frontend/src/editor/LintPanelStore.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { closeLintPanel, openLintPanel } from '@codemirror/lint'; import type EditorStore from './EditorStore'; diff --git a/subprojects/frontend/src/editor/PanelStore.ts b/subprojects/frontend/src/editor/PanelStore.ts index 4f827280..25ef8b6c 100644 --- a/subprojects/frontend/src/editor/PanelStore.ts +++ b/subprojects/frontend/src/editor/PanelStore.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import type { Command } from '@codemirror/view'; import { action, makeObservable, observable } from 'mobx'; diff --git a/subprojects/frontend/src/editor/SearchPanel.ts b/subprojects/frontend/src/editor/SearchPanel.ts index c9df41b7..b63d5eed 100644 --- a/subprojects/frontend/src/editor/SearchPanel.ts +++ b/subprojects/frontend/src/editor/SearchPanel.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { type EditorView, type Panel, diff --git a/subprojects/frontend/src/editor/SearchPanelPortal.tsx b/subprojects/frontend/src/editor/SearchPanelPortal.tsx index 5cf1c90e..b4b07c74 100644 --- a/subprojects/frontend/src/editor/SearchPanelPortal.tsx +++ b/subprojects/frontend/src/editor/SearchPanelPortal.tsx @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import Portal from '@mui/material/Portal'; import { observer } from 'mobx-react-lite'; diff --git a/subprojects/frontend/src/editor/SearchPanelStore.ts b/subprojects/frontend/src/editor/SearchPanelStore.ts index 65d595a8..6a97baf1 100644 --- a/subprojects/frontend/src/editor/SearchPanelStore.ts +++ b/subprojects/frontend/src/editor/SearchPanelStore.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { closeSearchPanel, findNext, diff --git a/subprojects/frontend/src/editor/SearchToolbar.tsx b/subprojects/frontend/src/editor/SearchToolbar.tsx index 54f3dba7..4ae7e893 100644 --- a/subprojects/frontend/src/editor/SearchToolbar.tsx +++ b/subprojects/frontend/src/editor/SearchToolbar.tsx @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import CloseIcon from '@mui/icons-material/Close'; import FindReplaceIcon from '@mui/icons-material/FindReplace'; import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; diff --git a/subprojects/frontend/src/editor/createEditorState.ts b/subprojects/frontend/src/editor/createEditorState.ts index ce1efa4f..4a8e9832 100644 --- a/subprojects/frontend/src/editor/createEditorState.ts +++ b/subprojects/frontend/src/editor/createEditorState.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { closeBrackets, closeBracketsKeymap, diff --git a/subprojects/frontend/src/editor/defineDecorationSetExtension.ts b/subprojects/frontend/src/editor/defineDecorationSetExtension.ts index d9c7bc7d..0887c92e 100644 --- a/subprojects/frontend/src/editor/defineDecorationSetExtension.ts +++ b/subprojects/frontend/src/editor/defineDecorationSetExtension.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { StateEffect, StateField, TransactionSpec } from '@codemirror/state'; import { EditorView, Decoration, DecorationSet } from '@codemirror/view'; diff --git a/subprojects/frontend/src/editor/exposeDiagnostics.ts b/subprojects/frontend/src/editor/exposeDiagnostics.ts index 82f24c93..c4dcbb87 100644 --- a/subprojects/frontend/src/editor/exposeDiagnostics.ts +++ b/subprojects/frontend/src/editor/exposeDiagnostics.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { setDiagnosticsEffect } from '@codemirror/lint'; import { StateField, diff --git a/subprojects/frontend/src/editor/findOccurrences.ts b/subprojects/frontend/src/editor/findOccurrences.ts index 08c078c2..00dffc96 100644 --- a/subprojects/frontend/src/editor/findOccurrences.ts +++ b/subprojects/frontend/src/editor/findOccurrences.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { type Range, RangeSet, diff --git a/subprojects/frontend/src/editor/indentationMarkerViewPlugin.ts b/subprojects/frontend/src/editor/indentationMarkerViewPlugin.ts index 730fa6e3..57a946d5 100644 --- a/subprojects/frontend/src/editor/indentationMarkerViewPlugin.ts +++ b/subprojects/frontend/src/editor/indentationMarkerViewPlugin.ts @@ -1,10 +1,16 @@ +/* + * Copyright (c) 2022 Replit + * Copyright (c) 2022-2023 The Refinery Authors + * + * SPDX-License-Identifier: MIT OR EPL-2.0 + */ + /** * @file CodeMirror plugin to highlight indentation * * This file is based on the * [@replit/codemirror-indentation-markers](https://github.com/replit/codemirror-indentation-markers) - * package, which is available under the - * [MIT License](https://github.com/replit/codemirror-indentation-markers/blob/543cc508ca5cef5d8350af23973eb1425e31525c/LICENSE). + * package. * * The highlighting heuristics were adjusted to make them more suitable * for logic programming. diff --git a/subprojects/frontend/src/editor/scrollbarViewPlugin.ts b/subprojects/frontend/src/editor/scrollbarViewPlugin.ts index f44034fd..878d369d 100644 --- a/subprojects/frontend/src/editor/scrollbarViewPlugin.ts +++ b/subprojects/frontend/src/editor/scrollbarViewPlugin.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { EditorSelection } from '@codemirror/state'; import { type EditorView, diff --git a/subprojects/frontend/src/editor/semanticHighlighting.ts b/subprojects/frontend/src/editor/semanticHighlighting.ts index 2c1bd67d..1f2e564c 100644 --- a/subprojects/frontend/src/editor/semanticHighlighting.ts +++ b/subprojects/frontend/src/editor/semanticHighlighting.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { RangeSet, type TransactionSpec } from '@codemirror/state'; import { Decoration } from '@codemirror/view'; diff --git a/subprojects/frontend/src/index.tsx b/subprojects/frontend/src/index.tsx index 29b2b196..cb11e6c3 100644 --- a/subprojects/frontend/src/index.tsx +++ b/subprojects/frontend/src/index.tsx @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { configure } from 'mobx'; import { type Root, createRoot } from 'react-dom/client'; diff --git a/subprojects/frontend/src/language/folding.ts b/subprojects/frontend/src/language/folding.ts index 4dabfa27..b4d4ca22 100644 --- a/subprojects/frontend/src/language/folding.ts +++ b/subprojects/frontend/src/language/folding.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import type { EditorState } from '@codemirror/state'; import type { SyntaxNode } from '@lezer/common'; diff --git a/subprojects/frontend/src/language/indentation.ts b/subprojects/frontend/src/language/indentation.ts index a0f7032d..8446d7fa 100644 --- a/subprojects/frontend/src/language/indentation.ts +++ b/subprojects/frontend/src/language/indentation.ts @@ -1,3 +1,10 @@ +/* + * Copyright (C) 2018-2021 by Marijn Haverbeke and others + * Copyright (C) 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: MIT OR EPL-2.0 + */ + import type { TreeIndentContext } from '@codemirror/language'; /** diff --git a/subprojects/frontend/src/language/problem.grammar b/subprojects/frontend/src/language/problem.grammar index 704badab..a7b1fb0a 100644 --- a/subprojects/frontend/src/language/problem.grammar +++ b/subprojects/frontend/src/language/problem.grammar @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + @detectDelim @external prop implicitCompletion from './props' diff --git a/subprojects/frontend/src/language/problemLanguageSupport.ts b/subprojects/frontend/src/language/problemLanguageSupport.ts index c3ae7ed9..2121e05f 100644 --- a/subprojects/frontend/src/language/problemLanguageSupport.ts +++ b/subprojects/frontend/src/language/problemLanguageSupport.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { foldInside, foldNodeProp, diff --git a/subprojects/frontend/src/language/props.ts b/subprojects/frontend/src/language/props.ts index 65392e75..aa67145a 100644 --- a/subprojects/frontend/src/language/props.ts +++ b/subprojects/frontend/src/language/props.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + /* eslint-disable import/prefer-default-export -- Lezer needs non-default exports */ import { NodeProp } from '@lezer/common'; diff --git a/subprojects/frontend/src/theme/ThemeProvider.tsx b/subprojects/frontend/src/theme/ThemeProvider.tsx index ff97d524..740e9562 100644 --- a/subprojects/frontend/src/theme/ThemeProvider.tsx +++ b/subprojects/frontend/src/theme/ThemeProvider.tsx @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { alpha, createTheme, diff --git a/subprojects/frontend/src/theme/ThemeStore.ts b/subprojects/frontend/src/theme/ThemeStore.ts index e09d8d99..7c657449 100644 --- a/subprojects/frontend/src/theme/ThemeStore.ts +++ b/subprojects/frontend/src/theme/ThemeStore.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { makeAutoObservable } from 'mobx'; export enum ThemePreference { diff --git a/subprojects/frontend/src/utils/CancelledError.ts b/subprojects/frontend/src/utils/CancelledError.ts index ee23676f..96b67af7 100644 --- a/subprojects/frontend/src/utils/CancelledError.ts +++ b/subprojects/frontend/src/utils/CancelledError.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + export default class CancelledError extends Error { constructor(message = 'Operation cancelled') { super(message); diff --git a/subprojects/frontend/src/utils/PendingTask.ts b/subprojects/frontend/src/utils/PendingTask.ts index d0b24c1f..80d1a346 100644 --- a/subprojects/frontend/src/utils/PendingTask.ts +++ b/subprojects/frontend/src/utils/PendingTask.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import TimeoutError from './TimeoutError'; import getLogger from './getLogger'; diff --git a/subprojects/frontend/src/utils/PriorityMutex.ts b/subprojects/frontend/src/utils/PriorityMutex.ts index 78736141..c1215c76 100644 --- a/subprojects/frontend/src/utils/PriorityMutex.ts +++ b/subprojects/frontend/src/utils/PriorityMutex.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import CancelledError from './CancelledError'; import PendingTask from './PendingTask'; import getLogger from './getLogger'; diff --git a/subprojects/frontend/src/utils/TimeoutError.ts b/subprojects/frontend/src/utils/TimeoutError.ts index eb800f40..21365502 100644 --- a/subprojects/frontend/src/utils/TimeoutError.ts +++ b/subprojects/frontend/src/utils/TimeoutError.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + export default class TimeoutError extends Error { constructor() { super('Operation timed out'); diff --git a/subprojects/frontend/src/utils/getLogger.ts b/subprojects/frontend/src/utils/getLogger.ts index 301fd76d..09b0b17f 100644 --- a/subprojects/frontend/src/utils/getLogger.ts +++ b/subprojects/frontend/src/utils/getLogger.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import styles, { type CSPair } from 'ansi-styles'; import log from 'loglevel'; import prefix from 'loglevel-plugin-prefix'; diff --git a/subprojects/frontend/src/utils/useDelayedSnackbar.ts b/subprojects/frontend/src/utils/useDelayedSnackbar.ts index 03ad6caa..3d6df3e3 100644 --- a/subprojects/frontend/src/utils/useDelayedSnackbar.ts +++ b/subprojects/frontend/src/utils/useDelayedSnackbar.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { useSnackbar, type SnackbarKey, diff --git a/subprojects/frontend/src/xtext/BackendConfig.ts b/subprojects/frontend/src/xtext/BackendConfig.ts index 41737c0b..4c7eac5f 100644 --- a/subprojects/frontend/src/xtext/BackendConfig.ts +++ b/subprojects/frontend/src/xtext/BackendConfig.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + /* eslint-disable @typescript-eslint/no-redeclare -- Declare types with their companion objects */ import { z } from 'zod'; diff --git a/subprojects/frontend/src/xtext/ContentAssistService.ts b/subprojects/frontend/src/xtext/ContentAssistService.ts index 78f61c06..fd30c4f9 100644 --- a/subprojects/frontend/src/xtext/ContentAssistService.ts +++ b/subprojects/frontend/src/xtext/ContentAssistService.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import type { Completion, CompletionContext, diff --git a/subprojects/frontend/src/xtext/HighlightingService.ts b/subprojects/frontend/src/xtext/HighlightingService.ts index a126ee40..447f1401 100644 --- a/subprojects/frontend/src/xtext/HighlightingService.ts +++ b/subprojects/frontend/src/xtext/HighlightingService.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import type EditorStore from '../editor/EditorStore'; import type { IHighlightRange } from '../editor/semanticHighlighting'; diff --git a/subprojects/frontend/src/xtext/OccurrencesService.ts b/subprojects/frontend/src/xtext/OccurrencesService.ts index fc72ead2..c9c6c699 100644 --- a/subprojects/frontend/src/xtext/OccurrencesService.ts +++ b/subprojects/frontend/src/xtext/OccurrencesService.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import type { Transaction } from '@codemirror/state'; import { debounce } from 'lodash-es'; import ms from 'ms'; diff --git a/subprojects/frontend/src/xtext/UpdateService.ts b/subprojects/frontend/src/xtext/UpdateService.ts index 63e28652..ee5ebde2 100644 --- a/subprojects/frontend/src/xtext/UpdateService.ts +++ b/subprojects/frontend/src/xtext/UpdateService.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import type { ChangeDesc, Transaction } from '@codemirror/state'; import { debounce } from 'lodash-es'; import { nanoid } from 'nanoid'; diff --git a/subprojects/frontend/src/xtext/UpdateStateTracker.ts b/subprojects/frontend/src/xtext/UpdateStateTracker.ts index 5d4ce49e..4ce93ed6 100644 --- a/subprojects/frontend/src/xtext/UpdateStateTracker.ts +++ b/subprojects/frontend/src/xtext/UpdateStateTracker.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { type ChangeDesc, ChangeSet, diff --git a/subprojects/frontend/src/xtext/ValidationService.ts b/subprojects/frontend/src/xtext/ValidationService.ts index 72414590..64fb63eb 100644 --- a/subprojects/frontend/src/xtext/ValidationService.ts +++ b/subprojects/frontend/src/xtext/ValidationService.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import type { Diagnostic } from '@codemirror/lint'; import type EditorStore from '../editor/EditorStore'; diff --git a/subprojects/frontend/src/xtext/XtextClient.ts b/subprojects/frontend/src/xtext/XtextClient.ts index 14fb2430..e8181af0 100644 --- a/subprojects/frontend/src/xtext/XtextClient.ts +++ b/subprojects/frontend/src/xtext/XtextClient.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import type { CompletionContext, CompletionResult, diff --git a/subprojects/frontend/src/xtext/XtextWebSocketClient.ts b/subprojects/frontend/src/xtext/XtextWebSocketClient.ts index 6b734546..6bb7eec8 100644 --- a/subprojects/frontend/src/xtext/XtextWebSocketClient.ts +++ b/subprojects/frontend/src/xtext/XtextWebSocketClient.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import { createAtom, makeAutoObservable, observable } from 'mobx'; import ms from 'ms'; import { nanoid } from 'nanoid'; diff --git a/subprojects/frontend/src/xtext/fetchBackendConfig.ts b/subprojects/frontend/src/xtext/fetchBackendConfig.ts index 15e976d8..71ff2e63 100644 --- a/subprojects/frontend/src/xtext/fetchBackendConfig.ts +++ b/subprojects/frontend/src/xtext/fetchBackendConfig.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import BackendConfig, { ENDPOINT } from './BackendConfig'; export default async function fetchBackendConfig(): Promise { diff --git a/subprojects/frontend/src/xtext/webSocketMachine.ts b/subprojects/frontend/src/xtext/webSocketMachine.ts index fc53fef3..2fb1f52f 100644 --- a/subprojects/frontend/src/xtext/webSocketMachine.ts +++ b/subprojects/frontend/src/xtext/webSocketMachine.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import ms from 'ms'; import { actions, assign, createMachine } from 'xstate'; diff --git a/subprojects/frontend/src/xtext/xtextMessages.ts b/subprojects/frontend/src/xtext/xtextMessages.ts index ec7a2a31..bbbff064 100644 --- a/subprojects/frontend/src/xtext/xtextMessages.ts +++ b/subprojects/frontend/src/xtext/xtextMessages.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + /* eslint-disable @typescript-eslint/no-redeclare -- Declare types with their companion objects */ import { z } from 'zod'; diff --git a/subprojects/frontend/src/xtext/xtextServiceResults.ts b/subprojects/frontend/src/xtext/xtextServiceResults.ts index e93c6714..d3b467ad 100644 --- a/subprojects/frontend/src/xtext/xtextServiceResults.ts +++ b/subprojects/frontend/src/xtext/xtextServiceResults.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + /* eslint-disable @typescript-eslint/no-redeclare -- Declare types with their companion objects */ import { z } from 'zod'; diff --git a/subprojects/frontend/tsconfig.base.json b/subprojects/frontend/tsconfig.base.json index 30e707ae..58a2a6f2 100644 --- a/subprojects/frontend/tsconfig.base.json +++ b/subprojects/frontend/tsconfig.base.json @@ -1,3 +1,13 @@ +/* + * Copyright (c) Microsoft Corporation. + * Copyright (c) 2023 The Refinery Authors + * + * SPDX-License-Identifier: MIT OR EPL-2.0 + * + * This file is based on + * https://github.com/tsconfig/bases/blob/7db25a41bc5a9c0f66d91f6f3aa28438afcb2f18/bases/strictest.json + * but we moved it inside the project for better tooling support. + */ { "compilerOptions": { "strict": true, @@ -11,6 +21,8 @@ "noUncheckedIndexedAccess": true, "noUnusedLocals": true, "noUnusedParameters": true, + // "verbatimModuleSyntax" is incompatible with `import` syntax in modules + // with CommonJS import resolution, so we use "isolatedModules" only. "verbatimModuleSyntax": false, "isolatedModules": true, "checkJs": true, @@ -18,6 +30,7 @@ "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "useDefineForClassFields": true, + // Project-specific configuration below. "module": "es2022", "moduleResolution": "node", "incremental": true, diff --git a/subprojects/frontend/tsconfig.json b/subprojects/frontend/tsconfig.json index 35d0d164..06f6d8fe 100644 --- a/subprojects/frontend/tsconfig.json +++ b/subprojects/frontend/tsconfig.json @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ { "extends": "./tsconfig.base.json", "compilerOptions": { diff --git a/subprojects/frontend/tsconfig.node.json b/subprojects/frontend/tsconfig.node.json index cfa2da13..47feaf97 100644 --- a/subprojects/frontend/tsconfig.node.json +++ b/subprojects/frontend/tsconfig.node.json @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ { "extends": "./tsconfig.base.json", "compilerOptions": { diff --git a/subprojects/frontend/tsconfig.shared.json b/subprojects/frontend/tsconfig.shared.json index f7b56a1d..154fe122 100644 --- a/subprojects/frontend/tsconfig.shared.json +++ b/subprojects/frontend/tsconfig.shared.json @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ { "extends": "./tsconfig.base.json", "compilerOptions": { @@ -6,6 +11,6 @@ "types": [], }, "include": [ - "src/xtext/BackendConfig.ts", + "src/xtext/BackendConfig.ts" ] } diff --git a/subprojects/frontend/types/ImportMeta.d.ts b/subprojects/frontend/types/ImportMeta.d.ts index c32b48f5..f5a32ef1 100644 --- a/subprojects/frontend/types/ImportMeta.d.ts +++ b/subprojects/frontend/types/ImportMeta.d.ts @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2019-present, Yuxi (Evan) You and Vite contributors + * Copyright (c) 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: MIT OR EPL-2.0 + */ + interface ImportMeta { env: { BASE_URL: string; diff --git a/subprojects/frontend/types/grammar.d.ts b/subprojects/frontend/types/grammar.d.ts index 1480085b..e7a7eebf 100644 --- a/subprojects/frontend/types/grammar.d.ts +++ b/subprojects/frontend/types/grammar.d.ts @@ -1,3 +1,10 @@ +/* + * Copyright (C) 2018 by Marijn Haverbeke and others + * Copyright (C) 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: MIT OR EPL-2.0 + */ + declare module '*.grammar' { import type { LRParser } from '@lezer/lr'; diff --git a/subprojects/frontend/types/node/@lezer-generator-rollup.d.ts b/subprojects/frontend/types/node/@lezer-generator-rollup.d.ts index 9c1ff03e..4ef9f4e3 100644 --- a/subprojects/frontend/types/node/@lezer-generator-rollup.d.ts +++ b/subprojects/frontend/types/node/@lezer-generator-rollup.d.ts @@ -1,3 +1,10 @@ +/* + * Copyright (C) 2018 by Marijn Haverbeke and others + * Copyright (C) 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: MIT OR EPL-2.0 + */ + // We have to explicitly redeclare the type of the `./rollup` ESM export of `@lezer/generator`, // because TypeScript can't find it on its own even with `"moduleResolution": "Node16"`. declare module '@lezer/generator/rollup' { diff --git a/subprojects/frontend/types/windowControlsOverlay.d.ts b/subprojects/frontend/types/windowControlsOverlay.d.ts index d8f3182f..2513d620 100644 --- a/subprojects/frontend/types/windowControlsOverlay.d.ts +++ b/subprojects/frontend/types/windowControlsOverlay.d.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + interface WindowControlsOverlayGeometryChangeEvent extends Event { titlebarAreaRect: DOMRect; diff --git a/subprojects/frontend/vite.config.ts b/subprojects/frontend/vite.config.ts index cd9993cc..9e08ccc4 100644 --- a/subprojects/frontend/vite.config.ts +++ b/subprojects/frontend/vite.config.ts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import path from 'node:path'; import { fileURLToPath } from 'node:url'; diff --git a/subprojects/language-ide/build.gradle.kts b/subprojects/language-ide/build.gradle.kts index f996c00d..ff8630f9 100644 --- a/subprojects/language-ide/build.gradle.kts +++ b/subprojects/language-ide/build.gradle.kts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + plugins { id("tools.refinery.gradle.java-library") id("tools.refinery.gradle.xtext-generated") diff --git a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/ProblemIdeModule.java b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/ProblemIdeModule.java index fb620065..122fe874 100644 --- a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/ProblemIdeModule.java +++ b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/ProblemIdeModule.java @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + /* * generated by Xtext 2.25.0 */ diff --git a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/ProblemIdeSetup.java b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/ProblemIdeSetup.java index 5b88d41f..9d77e022 100644 --- a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/ProblemIdeSetup.java +++ b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/ProblemIdeSetup.java @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + /* * generated by Xtext 2.25.0 */ diff --git a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/FuzzyMatcher.java b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/FuzzyMatcher.java index fe722ca1..4511223b 100644 --- a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/FuzzyMatcher.java +++ b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/FuzzyMatcher.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.ide.contentassist; import org.eclipse.xtext.ide.editor.contentassist.IPrefixMatcher; diff --git a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/ProblemCrossrefProposalProvider.java b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/ProblemCrossrefProposalProvider.java index 8f04ed00..e194ee31 100644 --- a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/ProblemCrossrefProposalProvider.java +++ b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/ProblemCrossrefProposalProvider.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.ide.contentassist; import java.util.Objects; diff --git a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/TokenSourceInjectingPartialProblemContentAssistParser.java b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/TokenSourceInjectingPartialProblemContentAssistParser.java index 3ece6f67..146bd8da 100644 --- a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/TokenSourceInjectingPartialProblemContentAssistParser.java +++ b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/TokenSourceInjectingPartialProblemContentAssistParser.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.ide.contentassist; import com.google.inject.Inject; diff --git a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/TokenSourceInjectingProblemParser.java b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/TokenSourceInjectingProblemParser.java index 80dfee5c..f906d881 100644 --- a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/TokenSourceInjectingProblemParser.java +++ b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/TokenSourceInjectingProblemParser.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.ide.contentassist; import com.google.inject.Inject; diff --git a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/antlr/ProblemTokenSource.java b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/antlr/ProblemTokenSource.java index c6c7f41f..fdc17c4f 100644 --- a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/antlr/ProblemTokenSource.java +++ b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/antlr/ProblemTokenSource.java @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + /* * generated by Xtext 2.29.0.M2 */ diff --git a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/syntaxcoloring/ProblemSemanticHighlightingCalculator.java b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/syntaxcoloring/ProblemSemanticHighlightingCalculator.java index 7703e4e3..e8f97d51 100644 --- a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/syntaxcoloring/ProblemSemanticHighlightingCalculator.java +++ b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/syntaxcoloring/ProblemSemanticHighlightingCalculator.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.ide.syntaxcoloring; import com.google.common.collect.ImmutableList; diff --git a/subprojects/language-model/META-INF/MANIFEST.MF.license b/subprojects/language-model/META-INF/MANIFEST.MF.license new file mode 100644 index 00000000..e5db6ccd --- /dev/null +++ b/subprojects/language-model/META-INF/MANIFEST.MF.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/language-model/build.gradle.kts b/subprojects/language-model/build.gradle.kts index 12b6bc13..4f15e5e6 100644 --- a/subprojects/language-model/build.gradle.kts +++ b/subprojects/language-model/build.gradle.kts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import tools.refinery.gradle.utils.SonarPropertiesUtils plugins { diff --git a/subprojects/language-model/build.properties b/subprojects/language-model/build.properties index 65dfc7c4..9b9859ff 100644 --- a/subprojects/language-model/build.properties +++ b/subprojects/language-model/build.properties @@ -1,4 +1,6 @@ +# SPDX-FileCopyrightText: 2021-2023 The Refinery Authors # +# SPDX-License-Identifier: EPL-2.0 bin.includes = .,\ src/main/resources/model/,\ diff --git a/subprojects/language-model/plugin.properties b/subprojects/language-model/plugin.properties index c4fb7e23..c410feb7 100644 --- a/subprojects/language-model/plugin.properties +++ b/subprojects/language-model/plugin.properties @@ -1,4 +1,6 @@ +# SPDX-FileCopyrightText: 2021-2023 The Refinery Authors # +# SPDX-License-Identifier: EPL-2.0 pluginName = tools.refinery.language.model providerName = refinery.tools diff --git a/subprojects/language-model/plugin.xml b/subprojects/language-model/plugin.xml index 4ca005a8..ef1e21f4 100644 --- a/subprojects/language-model/plugin.xml +++ b/subprojects/language-model/plugin.xml @@ -2,6 +2,9 @@ diff --git a/subprojects/language-model/problem.aird.license b/subprojects/language-model/problem.aird.license new file mode 100644 index 00000000..e5db6ccd --- /dev/null +++ b/subprojects/language-model/problem.aird.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/language-model/src/main/java/tools/refinery/language/model/GenerateProblemModel.mwe2 b/subprojects/language-model/src/main/java/tools/refinery/language/model/GenerateProblemModel.mwe2 index 15198d69..074b6b71 100644 --- a/subprojects/language-model/src/main/java/tools/refinery/language/model/GenerateProblemModel.mwe2 +++ b/subprojects/language-model/src/main/java/tools/refinery/language/model/GenerateProblemModel.mwe2 @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ module tools.refinery.language.model.GenerateProblemModel Workflow { diff --git a/subprojects/language-model/src/main/resources/model/problem.ecore.license b/subprojects/language-model/src/main/resources/model/problem.ecore.license new file mode 100644 index 00000000..e5db6ccd --- /dev/null +++ b/subprojects/language-model/src/main/resources/model/problem.ecore.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/language-model/src/main/resources/model/problem.genmodel.license b/subprojects/language-model/src/main/resources/model/problem.genmodel.license new file mode 100644 index 00000000..e5db6ccd --- /dev/null +++ b/subprojects/language-model/src/main/resources/model/problem.genmodel.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/language-semantics/build.gradle.kts b/subprojects/language-semantics/build.gradle.kts index bf016dc9..38cd9e0d 100644 --- a/subprojects/language-semantics/build.gradle.kts +++ b/subprojects/language-semantics/build.gradle.kts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + plugins { id("tools.refinery.gradle.java-library") } diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java index a6712a89..41b4fcb0 100644 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.semantics.model; import com.google.inject.Inject; diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java index 55edee6d..c1afecf9 100644 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.semantics.model.internal; import org.eclipse.collections.api.factory.primitive.IntObjectMaps; diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java index fdf8e452..9a1e15a3 100644 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.semantics.model.internal; import tools.refinery.store.map.Cursor; diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java index b81ea3fe..3c54e3c5 100644 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.semantics.model.internal; import org.eclipse.collections.api.LazyIntIterable; diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java index 495a53dd..915ae2bf 100644 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.semantics.model.internal; import tools.refinery.store.representation.TruthValue; diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java index c4200509..e6f01d48 100644 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.semantics.model.internal; import org.eclipse.collections.api.LazyIntIterable; diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java index 4af836ff..ce49aa62 100644 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.semantics.model.internal; import org.eclipse.collections.api.LazyIntIterable; diff --git a/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/tests/DecisionTreeTests.java b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/tests/DecisionTreeTests.java index 4630bf53..b3fcbabb 100644 --- a/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/tests/DecisionTreeTests.java +++ b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/tests/DecisionTreeTests.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.semantics.model.tests; import org.junit.jupiter.api.Test; diff --git a/subprojects/language-web/build.gradle.kts b/subprojects/language-web/build.gradle.kts index d2a39d56..e1d250ec 100644 --- a/subprojects/language-web/build.gradle.kts +++ b/subprojects/language-web/build.gradle.kts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + plugins { id("tools.refinery.gradle.java-application") id("tools.refinery.gradle.xtext-generated") diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/CacheControlFilter.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/CacheControlFilter.java index fd2af1b2..53f78c3c 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/CacheControlFilter.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/CacheControlFilter.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web; import jakarta.servlet.*; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebModule.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebModule.java index 706413a9..12e39e55 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebModule.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebModule.java @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + /* * generated by Xtext 2.25.0 */ diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebSetup.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebSetup.java index 4738bc80..53a394d8 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebSetup.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebSetup.java @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + /* * generated by Xtext 2.25.0 */ diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebSocketServlet.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebSocketServlet.java index df67b521..7b48cde8 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebSocketServlet.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebSocketServlet.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web; import org.eclipse.xtext.util.DisposableRegistry; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/SecurityHeadersFilter.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/SecurityHeadersFilter.java index c41db799..7b094fde 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/SecurityHeadersFilter.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/SecurityHeadersFilter.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web; import jakarta.servlet.*; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/ServerLauncher.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/ServerLauncher.java index d40e50af..1924f661 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/ServerLauncher.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/ServerLauncher.java @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + /* * generated by Xtext 2.25.0 */ diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/VirtualThreadUtils.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/VirtualThreadUtils.java index a055e755..27802e0c 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/VirtualThreadUtils.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/VirtualThreadUtils.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web; import org.eclipse.jetty.server.Server; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfig.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfig.java index 2e864998..807b789c 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfig.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfig.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.config; import com.google.gson.annotations.SerializedName; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfigServlet.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfigServlet.java index 47e8de7c..a2f04e34 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfigServlet.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfigServlet.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.config; import com.google.gson.Gson; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/occurrences/ProblemOccurrencesService.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/occurrences/ProblemOccurrencesService.java index d32bbb54..34117384 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/occurrences/ProblemOccurrencesService.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/occurrences/ProblemOccurrencesService.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.occurrences; import org.eclipse.emf.ecore.EObject; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/VirtualThreadExecutorServiceProvider.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/VirtualThreadExecutorServiceProvider.java index abbcbd53..699a09ab 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/VirtualThreadExecutorServiceProvider.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/VirtualThreadExecutorServiceProvider.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext; import org.eclipse.xtext.ide.ExecutorServiceProvider; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/PongResult.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/PongResult.java index fe510f51..27b2e04e 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/PongResult.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/PongResult.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.server; import java.util.Objects; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandler.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandler.java index 2a85afe3..3069c2dd 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandler.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandler.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.server; import tools.refinery.language.web.xtext.server.message.XtextWebResponse; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandlerException.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandlerException.java index b686d33a..366ef0a7 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandlerException.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandlerException.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.server; import java.io.Serial; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/SubscribingServiceContext.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/SubscribingServiceContext.java index 78e00a9e..04212b84 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/SubscribingServiceContext.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/SubscribingServiceContext.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.server; import java.util.Set; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/TransactionExecutor.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/TransactionExecutor.java index 7bb11d2e..0135d8f5 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/TransactionExecutor.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/TransactionExecutor.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.server; import com.google.common.base.Strings; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebErrorKind.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebErrorKind.java index f74bae74..6f4f265c 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebErrorKind.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebErrorKind.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.server.message; import com.google.gson.annotations.SerializedName; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebErrorResponse.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebErrorResponse.java index 01d78c31..af38ad70 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebErrorResponse.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebErrorResponse.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.server.message; import java.util.Objects; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebOkResponse.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebOkResponse.java index 8af27247..73527ee5 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebOkResponse.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebOkResponse.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.server.message; import java.util.Objects; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebPushMessage.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebPushMessage.java index c9432e1c..e9ff87c4 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebPushMessage.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebPushMessage.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.server.message; import java.util.Objects; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebRequest.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebRequest.java index 959749f8..ff788e94 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebRequest.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebRequest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.server.message; import java.util.Map; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebResponse.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebResponse.java index 3bd13047..61444c99 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebResponse.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebResponse.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.server.message; public sealed interface XtextWebResponse permits XtextWebOkResponse,XtextWebErrorResponse,XtextWebPushMessage { diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PrecomputationListener.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PrecomputationListener.java index 79a284db..110c8f52 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PrecomputationListener.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PrecomputationListener.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.server.push; import org.eclipse.xtext.web.server.IServiceResult; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushServiceDispatcher.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushServiceDispatcher.java index c7b8108d..4c9135c8 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushServiceDispatcher.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushServiceDispatcher.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.server.push; import org.eclipse.xtext.web.server.IServiceContext; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocument.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocument.java index 906b9e30..56fd12c9 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocument.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocument.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.server.push; import java.util.ArrayList; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocumentAccess.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocumentAccess.java index b3666a86..d9e548cd 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocumentAccess.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocumentAccess.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.server.push; import org.eclipse.xtext.service.OperationCanceledManager; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocumentProvider.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocumentProvider.java index b6f04748..b6f4fb43 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocumentProvider.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocumentProvider.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.server.push; import org.eclipse.xtext.web.server.IServiceContext; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/SimpleServiceContext.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/SimpleServiceContext.java index 43e37160..fee1141d 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/SimpleServiceContext.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/SimpleServiceContext.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.servlet; import java.util.Map; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/SimpleSession.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/SimpleSession.java index 09c055a2..bc60c282 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/SimpleSession.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/SimpleSession.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.servlet; import java.util.HashMap; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextStatusCode.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextStatusCode.java index 0cd229e8..caa98e84 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextStatusCode.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextStatusCode.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.servlet; public final class XtextStatusCode { diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java index 1d9e0463..f7d33e9e 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.servlet; import com.google.gson.Gson; diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocketServlet.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocketServlet.java index 9a32b937..5e4fb0ce 100644 --- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocketServlet.java +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocketServlet.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.servlet; import jakarta.servlet.ServletConfig; diff --git a/subprojects/language-web/src/test/java/tools/refinery/language/web/ProblemWebSocketServletIntegrationTest.java b/subprojects/language-web/src/test/java/tools/refinery/language/web/ProblemWebSocketServletIntegrationTest.java index ecbefc4f..53a757eb 100644 --- a/subprojects/language-web/src/test/java/tools/refinery/language/web/ProblemWebSocketServletIntegrationTest.java +++ b/subprojects/language-web/src/test/java/tools/refinery/language/web/ProblemWebSocketServletIntegrationTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; diff --git a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/AwaitTerminationExecutorServiceProvider.java b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/AwaitTerminationExecutorServiceProvider.java index c634e8fc..630549d4 100644 --- a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/AwaitTerminationExecutorServiceProvider.java +++ b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/AwaitTerminationExecutorServiceProvider.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.tests; import com.google.inject.Singleton; diff --git a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/ProblemWebInjectorProvider.java b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/ProblemWebInjectorProvider.java index 43c12faa..4a5eed95 100644 --- a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/ProblemWebInjectorProvider.java +++ b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/ProblemWebInjectorProvider.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.tests; import org.eclipse.xtext.ide.ExecutorServiceProvider; diff --git a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/RestartableCachedThreadPool.java b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/RestartableCachedThreadPool.java index cf805eda..09079aa8 100644 --- a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/RestartableCachedThreadPool.java +++ b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/RestartableCachedThreadPool.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.tests; import com.google.inject.Provider; diff --git a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/WebSocketIntegrationTestClient.java b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/WebSocketIntegrationTestClient.java index f19c10ca..2ac53ea6 100644 --- a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/WebSocketIntegrationTestClient.java +++ b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/WebSocketIntegrationTestClient.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.tests; import org.eclipse.jetty.ee10.websocket.api.Session; diff --git a/subprojects/language-web/src/test/java/tools/refinery/language/web/xtext/servlet/TransactionExecutorTest.java b/subprojects/language-web/src/test/java/tools/refinery/language/web/xtext/servlet/TransactionExecutorTest.java index 17f1ff5c..841bacd3 100644 --- a/subprojects/language-web/src/test/java/tools/refinery/language/web/xtext/servlet/TransactionExecutorTest.java +++ b/subprojects/language-web/src/test/java/tools/refinery/language/web/xtext/servlet/TransactionExecutorTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.web.xtext.servlet; import com.google.inject.Inject; diff --git a/subprojects/language/build.gradle.kts b/subprojects/language/build.gradle.kts index 4cfe6895..aa799c3b 100644 --- a/subprojects/language/build.gradle.kts +++ b/subprojects/language/build.gradle.kts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + import tools.refinery.gradle.utils.SonarPropertiesUtils plugins { diff --git a/subprojects/language/src/main/java/tools/refinery/language/GenerateProblem.mwe2 b/subprojects/language/src/main/java/tools/refinery/language/GenerateProblem.mwe2 index 21ff456e..d8d89173 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/GenerateProblem.mwe2 +++ b/subprojects/language/src/main/java/tools/refinery/language/GenerateProblem.mwe2 @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ module tools.refinery.language.GenerateProblem import org.eclipse.xtext.xtext.generator.* @@ -55,7 +60,7 @@ Workflow { } webSupport = { // We only generate the {@code AbstractProblemWebModule}, - // because we write our own integration code for CodeMirror 6. + // because we write our own integration code for CodeMirror 6. framework = 'codemirror' generateHtmlExample = false generateJettyLauncher = false diff --git a/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext b/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext index 187ebf1f..9e330347 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext +++ b/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ grammar tools.refinery.language.Problem with org.eclipse.xtext.common.Terminals import "http://www.eclipse.org/emf/2002/Ecore" as ecore diff --git a/subprojects/language/src/main/java/tools/refinery/language/ProblemRuntimeModule.java b/subprojects/language/src/main/java/tools/refinery/language/ProblemRuntimeModule.java index 5efcdc81..2636a8ee 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/ProblemRuntimeModule.java +++ b/subprojects/language/src/main/java/tools/refinery/language/ProblemRuntimeModule.java @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + /* * generated by Xtext 2.25.0 */ diff --git a/subprojects/language/src/main/java/tools/refinery/language/ProblemStandaloneSetup.java b/subprojects/language/src/main/java/tools/refinery/language/ProblemStandaloneSetup.java index 41c96114..639d6778 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/ProblemStandaloneSetup.java +++ b/subprojects/language/src/main/java/tools/refinery/language/ProblemStandaloneSetup.java @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + /* * generated by Xtext 2.25.0 */ diff --git a/subprojects/language/src/main/java/tools/refinery/language/conversion/ProblemValueConverterService.java b/subprojects/language/src/main/java/tools/refinery/language/conversion/ProblemValueConverterService.java index 508688ed..afbc367e 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/conversion/ProblemValueConverterService.java +++ b/subprojects/language/src/main/java/tools/refinery/language/conversion/ProblemValueConverterService.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.conversion; import org.eclipse.xtext.common.services.DefaultTerminalConverters; diff --git a/subprojects/language/src/main/java/tools/refinery/language/conversion/UpperBoundValueConverter.java b/subprojects/language/src/main/java/tools/refinery/language/conversion/UpperBoundValueConverter.java index be0d15ad..4886757d 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/conversion/UpperBoundValueConverter.java +++ b/subprojects/language/src/main/java/tools/refinery/language/conversion/UpperBoundValueConverter.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.conversion; import org.eclipse.xtext.conversion.ValueConverterException; diff --git a/subprojects/language/src/main/java/tools/refinery/language/formatting2/ProblemFormatter.java b/subprojects/language/src/main/java/tools/refinery/language/formatting2/ProblemFormatter.java index 797535ea..55a5ac20 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/formatting2/ProblemFormatter.java +++ b/subprojects/language/src/main/java/tools/refinery/language/formatting2/ProblemFormatter.java @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + /* * generated by Xtext 2.26.0.M2 */ diff --git a/subprojects/language/src/main/java/tools/refinery/language/naming/NamingUtil.java b/subprojects/language/src/main/java/tools/refinery/language/naming/NamingUtil.java index e959be74..1647d4e7 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/naming/NamingUtil.java +++ b/subprojects/language/src/main/java/tools/refinery/language/naming/NamingUtil.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.naming; import java.util.regex.Pattern; diff --git a/subprojects/language/src/main/java/tools/refinery/language/naming/ProblemQualifiedNameConverter.java b/subprojects/language/src/main/java/tools/refinery/language/naming/ProblemQualifiedNameConverter.java index 5453906f..74b4e208 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/naming/ProblemQualifiedNameConverter.java +++ b/subprojects/language/src/main/java/tools/refinery/language/naming/ProblemQualifiedNameConverter.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.naming; import org.eclipse.xtext.naming.IQualifiedNameConverter; diff --git a/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/IdentifierTokenProvider.java b/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/IdentifierTokenProvider.java index ab133a90..306a86fc 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/IdentifierTokenProvider.java +++ b/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/IdentifierTokenProvider.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.parser.antlr; import com.google.inject.Inject; diff --git a/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/ProblemTokenSource.java b/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/ProblemTokenSource.java index 0b4e7185..5b91a6cc 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/ProblemTokenSource.java +++ b/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/ProblemTokenSource.java @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + /* * generated by Xtext 2.29.0.M2 */ diff --git a/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/TokenSourceInjectingProblemParser.java b/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/TokenSourceInjectingProblemParser.java index 0cdd38d8..fe4c0bc7 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/TokenSourceInjectingProblemParser.java +++ b/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/TokenSourceInjectingProblemParser.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.parser.antlr; import com.google.inject.Inject; diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/DerivedVariableComputer.java b/subprojects/language/src/main/java/tools/refinery/language/resource/DerivedVariableComputer.java index 6176b0c4..07c5da41 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/resource/DerivedVariableComputer.java +++ b/subprojects/language/src/main/java/tools/refinery/language/resource/DerivedVariableComputer.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.resource; import com.google.inject.Inject; diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/ImplicitVariableScope.java b/subprojects/language/src/main/java/tools/refinery/language/resource/ImplicitVariableScope.java index b0ac2ab6..e97c8287 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/resource/ImplicitVariableScope.java +++ b/subprojects/language/src/main/java/tools/refinery/language/resource/ImplicitVariableScope.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.resource; import org.eclipse.emf.ecore.EObject; diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/NodeNameCollector.java b/subprojects/language/src/main/java/tools/refinery/language/resource/NodeNameCollector.java index 419be0d3..e5deca4d 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/resource/NodeNameCollector.java +++ b/subprojects/language/src/main/java/tools/refinery/language/resource/NodeNameCollector.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.resource; import com.google.common.collect.ImmutableSet; diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemDerivedStateComputer.java b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemDerivedStateComputer.java index 8d3a552a..b145ef27 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemDerivedStateComputer.java +++ b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemDerivedStateComputer.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.resource; import com.google.inject.Inject; diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemLocationInFileProvider.java b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemLocationInFileProvider.java index df822987..1fe2df89 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemLocationInFileProvider.java +++ b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemLocationInFileProvider.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.resource; import org.eclipse.emf.ecore.EObject; diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemResourceDescriptionStrategy.java b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemResourceDescriptionStrategy.java index 1a0b73a8..630be379 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemResourceDescriptionStrategy.java +++ b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemResourceDescriptionStrategy.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.resource; import org.eclipse.emf.ecore.EObject; diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/ReferenceCounter.java b/subprojects/language/src/main/java/tools/refinery/language/resource/ReferenceCounter.java index ca20325e..f1be55ee 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/resource/ReferenceCounter.java +++ b/subprojects/language/src/main/java/tools/refinery/language/resource/ReferenceCounter.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.resource; import java.util.HashMap; diff --git a/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemGlobalScopeProvider.java b/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemGlobalScopeProvider.java index b749154c..4d2dd772 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemGlobalScopeProvider.java +++ b/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemGlobalScopeProvider.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.scoping; import java.util.LinkedHashSet; diff --git a/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemLocalScopeProvider.java b/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemLocalScopeProvider.java index 61883f0e..229960a0 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemLocalScopeProvider.java +++ b/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemLocalScopeProvider.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.scoping; import java.util.List; diff --git a/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemScopeProvider.java b/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemScopeProvider.java index 3ab07496..cf099aba 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemScopeProvider.java +++ b/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemScopeProvider.java @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + /* * generated by Xtext 2.25.0 */ diff --git a/subprojects/language/src/main/java/tools/refinery/language/serializer/PreferShortAssertionsProblemSemanticSequencer.java b/subprojects/language/src/main/java/tools/refinery/language/serializer/PreferShortAssertionsProblemSemanticSequencer.java index 27ce1521..b9cafbc2 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/serializer/PreferShortAssertionsProblemSemanticSequencer.java +++ b/subprojects/language/src/main/java/tools/refinery/language/serializer/PreferShortAssertionsProblemSemanticSequencer.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.serializer; import com.google.inject.Inject; diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/BuiltinSymbols.java b/subprojects/language/src/main/java/tools/refinery/language/utils/BuiltinSymbols.java index d3777cd3..c8c7fd4a 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/utils/BuiltinSymbols.java +++ b/subprojects/language/src/main/java/tools/refinery/language/utils/BuiltinSymbols.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.utils; import tools.refinery.language.model.problem.*; diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/CollectedSymbols.java b/subprojects/language/src/main/java/tools/refinery/language/utils/CollectedSymbols.java index b5682f32..e4e4d07a 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/utils/CollectedSymbols.java +++ b/subprojects/language/src/main/java/tools/refinery/language/utils/CollectedSymbols.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.utils; import java.util.Map; diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/ContainmentRole.java b/subprojects/language/src/main/java/tools/refinery/language/utils/ContainmentRole.java index 708e10a9..a43c7dfe 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/utils/ContainmentRole.java +++ b/subprojects/language/src/main/java/tools/refinery/language/utils/ContainmentRole.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.utils; import tools.refinery.language.model.problem.PredicateKind; diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/NodeInfo.java b/subprojects/language/src/main/java/tools/refinery/language/utils/NodeInfo.java index c8f47653..0fa7a454 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/utils/NodeInfo.java +++ b/subprojects/language/src/main/java/tools/refinery/language/utils/NodeInfo.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.utils; public record NodeInfo(String name, boolean individual) { diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemDesugarer.java b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemDesugarer.java index b8200919..738a0896 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemDesugarer.java +++ b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemDesugarer.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.utils; import com.google.inject.Inject; diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java index 1e5164d3..9486dc2a 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java +++ b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.utils; import org.eclipse.emf.common.util.URI; diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/RelationInfo.java b/subprojects/language/src/main/java/tools/refinery/language/utils/RelationInfo.java index 2253d257..1c46fe72 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/utils/RelationInfo.java +++ b/subprojects/language/src/main/java/tools/refinery/language/utils/RelationInfo.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.utils; import tools.refinery.language.model.problem.*; diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/SymbolCollector.java b/subprojects/language/src/main/java/tools/refinery/language/utils/SymbolCollector.java index 65167ed6..a4ea1113 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/utils/SymbolCollector.java +++ b/subprojects/language/src/main/java/tools/refinery/language/utils/SymbolCollector.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.utils; import com.google.inject.Inject; diff --git a/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java b/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java index 659d882c..88d50c5b 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java +++ b/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + /* * generated by Xtext 2.25.0 */ diff --git a/subprojects/language/src/main/resources/tools/refinery/language/builtin.problem b/subprojects/language/src/main/resources/tools/refinery/language/builtin.problem index 06b6da1d..9c1d7669 100644 --- a/subprojects/language/src/main/resources/tools/refinery/language/builtin.problem +++ b/subprojects/language/src/main/resources/tools/refinery/language/builtin.problem @@ -1,3 +1,6 @@ +% SPDX-FileCopyrightText: 2021-2023 The Refinery Authors +% +% SPDX-License-Identifier: EPL-2.0 problem builtin. abstract class node { diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java index 58daa365..c7952369 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.tests; import com.google.inject.Inject; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java index 6e0802ca..f688d970 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.tests.formatting2; import com.google.inject.Inject; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java index abff8d9c..37d38dd9 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.tests.parser.antlr; import com.google.inject.Inject; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java index cb42d5d0..644744a0 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.tests.parser.antlr; import com.google.inject.Inject; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java index 65ceb45f..1180d131 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.tests.parser.antlr; import com.google.inject.Inject; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java index 72e5e18a..68514bfa 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.tests.rules; import com.google.inject.Inject; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java index fa462691..734bfcd1 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.tests.scoping; import com.google.inject.Inject; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java index 4a18704a..3f3a081f 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.tests.serializer; import com.google.inject.Inject; diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/utils/SymbolCollectorTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/utils/SymbolCollectorTest.java index af6de37f..d200eeff 100644 --- a/subprojects/language/src/test/java/tools/refinery/language/tests/utils/SymbolCollectorTest.java +++ b/subprojects/language/src/test/java/tools/refinery/language/tests/utils/SymbolCollectorTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.tests.utils; import com.google.inject.Inject; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemNavigationUtil.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemNavigationUtil.java index 5761935b..d92011a9 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemNavigationUtil.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemNavigationUtil.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.model.tests.utils; import java.util.List; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemParseHelper.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemParseHelper.java index 5e044a94..6f6a87f7 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemParseHelper.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemParseHelper.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.model.tests.utils; import org.eclipse.xtext.testing.util.ParseHelper; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAction.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAction.java index d176727b..3a49a0b9 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAction.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAction.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.model.tests.utils; import tools.refinery.language.model.problem.Action; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedArgument.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedArgument.java index 9e4c59f5..ed749fed 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedArgument.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedArgument.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.model.tests.utils; import tools.refinery.language.model.problem.*; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertion.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertion.java index 2c38639d..b2ef6e48 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertion.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertion.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.model.tests.utils; import tools.refinery.language.model.problem.Assertion; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java index 840c1f74..b36f2506 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.model.tests.utils; import tools.refinery.language.model.problem.AssertionArgument; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAtom.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAtom.java index 498991f8..c02f447b 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAtom.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAtom.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.model.tests.utils; import tools.refinery.language.model.problem.Atom; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java index 41b2ea62..a228137c 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.model.tests.utils; import tools.refinery.language.model.problem.ClassDeclaration; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConjunction.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConjunction.java index 88ff71ab..b126b1ce 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConjunction.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConjunction.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.model.tests.utils; import tools.refinery.language.model.problem.Conjunction; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConsequent.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConsequent.java index 46faa7da..8d6a92f8 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConsequent.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConsequent.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.model.tests.utils; import tools.refinery.language.model.problem.Consequent; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedEnumDeclaration.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedEnumDeclaration.java index 74dcf01b..229a8c0a 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedEnumDeclaration.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedEnumDeclaration.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.model.tests.utils; import tools.refinery.language.model.problem.EnumDeclaration; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedLiteral.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedLiteral.java index 4aa71b99..160e5dd8 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedLiteral.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedLiteral.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.model.tests.utils; import tools.refinery.language.model.problem.Atom; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedParametricDefinition.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedParametricDefinition.java index c2f18a60..d44b79ed 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedParametricDefinition.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedParametricDefinition.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.model.tests.utils; import tools.refinery.language.model.problem.Parameter; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedPredicateDefinition.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedPredicateDefinition.java index 7b95ecc1..2cf5fd89 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedPredicateDefinition.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedPredicateDefinition.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.model.tests.utils; import tools.refinery.language.model.problem.PredicateDefinition; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java index 78ca95c7..e5aa0043 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.model.tests.utils; import org.eclipse.emf.ecore.resource.Resource.Diagnostic; diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedRuleDefinition.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedRuleDefinition.java index a4cf2eaf..326d8ec3 100644 --- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedRuleDefinition.java +++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedRuleDefinition.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.language.model.tests.utils; import tools.refinery.language.model.problem.RuleDefinition; diff --git a/subprojects/store-query-viatra/NOTICE.md b/subprojects/store-query-viatra/NOTICE.md new file mode 100644 index 00000000..7c21726a --- /dev/null +++ b/subprojects/store-query-viatra/NOTICE.md @@ -0,0 +1,87 @@ + + +This module contains source code from the [Eclipse VIATRA project](https://projects.eclipse.org/projects/modeling.viatra), which is available under the terms of the [Eclipse Public License v 2.0](http://www.eclipse.org/legal/epl-v20.html). + +We reproduce the [accompanying notices](https://github.com/viatra/org.eclipse.viatra/blob/d422bcc626a99c4640c0d13931f393ccea0d2326/NOTICE.md) in full below: + +# Notices for Eclipse VIATRA + +This content is produced and maintained by the Eclipse VIATRA project. + +* Project home: https://projects.eclipse.org/projects/modeling.viatra + +## Trademarks + +Eclipse VIATRA, and VIATRA are trademarks of the Eclipse Foundation. + +## Copyright + +All content is the property of the respective authors or their employers. For +more information regarding authorship of content, please consult the listed +source code repository logs. + +## Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Public License v. 2.0 which is available at +http://www.eclipse.org/legal/epl-v20.html. + +SPDX-License-Identifier: EPL-2.0 + +## Source Code + +The project maintains the following source code repositories: + +* http://git.eclipse.org/c/viatra/org.eclipse.viatra.git +* http://git.eclipse.org/c/viatra/org.eclipse.viatra.modelobfuscator.git +* http://git.eclipse.org/c/viatra/org.eclipse.viatra.examples.git +* http://git.eclipse.org/c/viatra/org.eclipse.viatra2.vpm.git + +## Third-party Content + +This project leverages the following third party content. + +ANTLR Runtime only: (3.2) + +* License: New BSD license + +Apache Commons Language Library (2.1) + +* License: Apache License, 2.0 + +Google Guice / Inject Core API (3.0.0) + +* License: Apache License, 2.0 + +Google Guice / Inject Core API (3.0.0) + +* License: Apache License 2.0 + +Guava (10.0.1) + +* License: Apache License, 2.0 + +Guice (2.0) + +* License: Apache License, 2.0 + +guice-multibindings (3.0.0) + +* License: Apache License, 2.0 + +log4j (1.2.15) + +* License: Apache License 2.0 + +LPG Java Runtime (lpgjavaruntime.jar) (1.1) + +* License: Eclipse Public License + +mockito (1.9.5) + +* License: Apache License, 2.0, New BSD license, MIT license diff --git a/subprojects/store-query-viatra/build.gradle.kts b/subprojects/store-query-viatra/build.gradle.kts index 4a894f52..e3a22145 100644 --- a/subprojects/store-query-viatra/build.gradle.kts +++ b/subprojects/store-query-viatra/build.gradle.kts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + plugins { id("tools.refinery.gradle.java-library") } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java index 677e3c7d..3fff6f2e 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra; import tools.refinery.store.adapter.ModelAdapterBuilderFactory; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryAdapter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryAdapter.java index 7e21476b..411e251e 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryAdapter.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryAdapter.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra; import tools.refinery.store.query.ModelQueryAdapter; 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 7ae86f9f..310171e8 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 @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra; import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java index 1ee02f12..da6d7bd5 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra; import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java index 8328e759..d1a65a89 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal; import org.apache.log4j.Logger; 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 8be30fee..7103a561 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 @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal; import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine; 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 bfabf26e..999d349a 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 @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal; import org.eclipse.viatra.query.runtime.api.IQuerySpecification; 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 04c48c43..aa102a35 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 @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal; import org.eclipse.viatra.query.runtime.api.IQuerySpecification; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java index e0bca9e0..bfd4c049 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.cardinality; import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.BoundAggregator; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/DummyBaseIndexer.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/DummyBaseIndexer.java index 2a24b67c..8cb199d2 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/DummyBaseIndexer.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/DummyBaseIndexer.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.context; import org.eclipse.viatra.query.runtime.api.scope.IBaseIndex; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java index 28bc69d0..7220f8ca 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.context; import org.eclipse.viatra.query.runtime.api.scope.IBaseIndex; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java index d2c6beb4..07a5a6ea 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.context; import org.eclipse.viatra.query.runtime.matchers.context.AbstractQueryMetaContext; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java index 854817b1..71943737 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.context; import org.eclipse.viatra.query.runtime.matchers.context.*; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendOperationExecutor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendOperationExecutor.java index 2d3dd5a7..37177cbf 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendOperationExecutor.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendOperationExecutor.java @@ -1,5 +1,6 @@ /******************************************************************************* * Copyright (c) 2010-2013, Zoltan Ujhelyi, Akos Horvath, Istvan Rath and Daniel Varro + * Copyright (c) 2023 The Refinery Authors * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at * http://www.eclipse.org/legal/epl-v20.html. diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendPositivePatternCall.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendPositivePatternCall.java index aaaece80..9d48c785 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendPositivePatternCall.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendPositivePatternCall.java @@ -1,5 +1,6 @@ /******************************************************************************* * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs + * Copyright (c) 2023 The Refinery Authors * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at * http://www.eclipse.org/legal/epl-v20.html. diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/FlatCostFunction.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/FlatCostFunction.java index 84cab142..cc906f22 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/FlatCostFunction.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/FlatCostFunction.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.localsearch; import org.eclipse.viatra.query.runtime.localsearch.planner.cost.IConstraintEvaluationContext; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/GenericTypeExtend.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/GenericTypeExtend.java index 64653658..96ac4a72 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/GenericTypeExtend.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/GenericTypeExtend.java @@ -1,5 +1,6 @@ /******************************************************************************* * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd. + * Copyright (c) 2023 The Refinery Authors * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at * http://www.eclipse.org/legal/epl-v20.html. diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchBackendFactory.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchBackendFactory.java index 156eb313..0c77f587 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchBackendFactory.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchBackendFactory.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.localsearch; import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.AbstractLocalSearchResultProvider; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchResultProvider.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchResultProvider.java index be2a38ca..da37be14 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchResultProvider.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchResultProvider.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.localsearch; import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.AbstractLocalSearchResultProvider; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalOperationCompiler.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalOperationCompiler.java index b6832b39..f76ef486 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalOperationCompiler.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalOperationCompiler.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.localsearch; import org.eclipse.viatra.query.runtime.localsearch.operations.generic.GenericTypeExtendSingleValue; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java index 52a83f69..47efb2aa 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.matcher; import org.eclipse.viatra.query.runtime.rete.index.IterableIndexer; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java index adb34b8b..f018288b 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.matcher; import org.eclipse.viatra.query.runtime.matchers.backend.IQueryResultProvider; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/IndexerUtils.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/IndexerUtils.java index 55eb8c44..15f00b2d 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/IndexerUtils.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/IndexerUtils.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.matcher; import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java index d327c537..1c784492 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.matcher; import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RawPatternMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RawPatternMatcher.java index b3d05967..5b82c4b7 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RawPatternMatcher.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RawPatternMatcher.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.matcher; import org.eclipse.viatra.query.runtime.api.GenericPatternMatcher; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java index e3df0441..1dc8f5db 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.matcher; import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java index 9373709d..d1476920 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.matcher; import org.eclipse.viatra.query.runtime.matchers.backend.IQueryResultProvider; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java index e9540d1d..4a41d724 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.matcher; import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/AssumptionEvaluator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/AssumptionEvaluator.java index a80b0f90..cf127291 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/AssumptionEvaluator.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/AssumptionEvaluator.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.pquery; import org.eclipse.viatra.query.runtime.matchers.psystem.IValueProvider; 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 index 7afeb977..714d41c0 100644 --- 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 @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.pquery; import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java index 24ae5196..30f848a6 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.pquery; import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java index aad4ba3c..255738c5 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.pquery; import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java index 48bf558d..02da932b 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.pquery; import org.eclipse.viatra.query.runtime.matchers.context.common.BaseInputKeyWrapper; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatefulMultisetAggregator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatefulMultisetAggregator.java index 2798a252..461416f7 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatefulMultisetAggregator.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatefulMultisetAggregator.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.pquery; import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatelessMultisetAggregator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatelessMultisetAggregator.java index 7cc71ee9..49175d75 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatelessMultisetAggregator.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatelessMultisetAggregator.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.pquery; import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/TermEvaluator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/TermEvaluator.java index ab123c50..1187f57a 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/TermEvaluator.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/TermEvaluator.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.pquery; import org.eclipse.viatra.query.runtime.matchers.psystem.IExpressionEvaluator; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ValueProviderBasedValuation.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ValueProviderBasedValuation.java index 30c2fce7..62cb8b3a 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ValueProviderBasedValuation.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ValueProviderBasedValuation.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.pquery; import org.eclipse.viatra.query.runtime.matchers.psystem.IValueProvider; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java index fc935aa6..c612574f 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.update; import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewFilter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewFilter.java index 221f1b4a..efdbfcbe 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewFilter.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewFilter.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.update; import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java index 5e5f60e3..185e4ebc 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.update; import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java index 0f6ed3b3..be4951af 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.update; import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java index 91e9371b..9638266b 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.update; import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java index 90229b73..da4aba7f 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra; import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java index fa2a008f..3af67a50 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra; import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; 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 8a3f9d88..e82f0a15 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 @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra; import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; 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 abd49341..07b799ac 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 @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra; import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java index c529117e..53d03cbd 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.cardinality; import org.junit.jupiter.params.ParameterizedTest; diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java index 20dad543..677eeeac 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.cardinality; import org.junit.jupiter.api.BeforeEach; diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtilsTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtilsTest.java index ea0b15ec..968c6c5e 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtilsTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtilsTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.internal.matcher; import org.eclipse.viatra.query.runtime.matchers.tuple.*; diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java index 2769621d..7a25cfdc 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.tests; import org.junit.jupiter.api.function.Executable; diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.java index b1818a17..dc0e92c8 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.tests; import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java index f129520c..d4f16da7 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.tests; import org.junit.jupiter.params.ParameterizedTest; diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java index a55762e2..9e75d5f3 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.viatra.tests; import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; diff --git a/subprojects/store-query/build.gradle.kts b/subprojects/store-query/build.gradle.kts index 889a0479..4d8e2605 100644 --- a/subprojects/store-query/build.gradle.kts +++ b/subprojects/store-query/build.gradle.kts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + plugins { id("tools.refinery.gradle.java-library") id("tools.refinery.gradle.java-test-fixtures") diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/AnyResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/AnyResultSet.java index 6d411212..f29bb278 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/AnyResultSet.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/AnyResultSet.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query; import tools.refinery.store.query.dnf.AnyQuery; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java index cec4c19f..10d8a579 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query; import tools.refinery.store.query.equality.LiteralEqualityHelper; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java index 4c8eeab0..5361f645 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query; import tools.refinery.store.map.Cursor; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQuery.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQuery.java index 6a1aeabb..60698498 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQuery.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQuery.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query; import tools.refinery.store.adapter.ModelAdapterType; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java index 2e30fec4..ae3bbcbb 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query; import tools.refinery.store.adapter.ModelAdapter; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java index 4fdc9210..76d6c3ba 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query; import tools.refinery.store.adapter.ModelAdapterBuilder; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java index 514e582b..33318abc 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query; import tools.refinery.store.adapter.ModelStoreAdapter; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java index 2758c74f..9ab83172 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query; import tools.refinery.store.map.Cursor; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AnyQuery.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AnyQuery.java index d0a2367f..5e28af68 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AnyQuery.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AnyQuery.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.dnf; public sealed interface AnyQuery permits Query { diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java index 1b7759c7..3321a10f 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.dnf; import tools.refinery.store.query.equality.DnfEqualityChecker; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java index aad5a85f..4f920f8f 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.dnf; import tools.refinery.store.query.literal.Literal; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java index 01830af1..a01d7d55 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.dnf; import tools.refinery.store.query.equality.LiteralEqualityHelper; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfUtils.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfUtils.java index 9bcf944c..65ab3634 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfUtils.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfUtils.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.dnf; import java.util.UUID; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalDependency.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalDependency.java index f4cd109f..b00b2cb7 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalDependency.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalDependency.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.dnf; import java.util.HashSet; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java index 5bf6f8c5..680fa631 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.dnf; import tools.refinery.store.query.literal.CallPolarity; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQueryBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQueryBuilder.java index ca2bc006..63580676 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQueryBuilder.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQueryBuilder.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.dnf; import tools.refinery.store.query.literal.Literal; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java index 32e33052..d3de475f 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.dnf; public sealed interface Query extends AnyQuery permits RelationalQuery, FunctionalQuery { diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/QueryBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/QueryBuilder.java index ed253cc9..f925c9ac 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/QueryBuilder.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/QueryBuilder.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.dnf; import tools.refinery.store.query.literal.Literal; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java index 5307e509..0741d8d9 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.dnf; import tools.refinery.store.query.literal.CallLiteral; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java index c3bc3ea3..bb60ccc9 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.equality; import tools.refinery.store.query.dnf.Dnf; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java index 6b1f2076..4a8bee3b 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.equality; import tools.refinery.store.query.dnf.Dnf; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java index 07d261ea..0f6ee6c2 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.equality; import tools.refinery.store.query.dnf.Dnf; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java index 657ca26b..b08c1037 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.literal; import tools.refinery.store.query.Constraint; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java index df64839c..93e59291 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.literal; import tools.refinery.store.query.Constraint; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java index 52ac42d7..8cc3fae6 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.literal; import tools.refinery.store.query.equality.LiteralEqualityHelper; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java index 0b4267b4..58d563da 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.literal; import tools.refinery.store.query.equality.LiteralEqualityHelper; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java index 38be61a4..a32cfd80 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.literal; import tools.refinery.store.query.term.Variable; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java index 78fae7f5..82088c8b 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.literal; import tools.refinery.store.query.Constraint; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallPolarity.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallPolarity.java index 84b4b771..ca70b0fd 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallPolarity.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallPolarity.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.literal; public enum CallPolarity { diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CanNegate.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CanNegate.java index 3e159c43..35dcb3fb 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CanNegate.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CanNegate.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.literal; public interface CanNegate> extends Literal { diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java index 93fa3df0..fa7979d1 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.literal; import tools.refinery.store.query.equality.LiteralEqualityHelper; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java index 32e7ba3a..11f78fa8 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.literal; import tools.refinery.store.query.Constraint; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java index 4dc86b98..3876574c 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.literal; import tools.refinery.store.query.term.NodeVariable; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java index 6347410e..52411ee8 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.literal; import tools.refinery.store.query.term.Variable; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/LiteralReduction.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/LiteralReduction.java index 146089f6..9d8352ea 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/LiteralReduction.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/LiteralReduction.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.literal; public enum LiteralReduction { diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java index 89039352..b3a87811 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.literal; import tools.refinery.store.query.term.Term; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/CompositeSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/CompositeSubstitution.java index f8064ca2..d175130e 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/CompositeSubstitution.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/CompositeSubstitution.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.substitution; import tools.refinery.store.query.term.Variable; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java index c7754619..a8201eef 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.substitution; import tools.refinery.store.query.term.Variable; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java index 7847e582..9b737ceb 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.substitution; import tools.refinery.store.query.term.Variable; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java index eed414d9..bb3803d3 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.substitution; import tools.refinery.store.query.term.Variable; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java index 99f84b9e..5714edf4 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.substitution; import tools.refinery.store.query.term.AnyDataVariable; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java index 5d4654da..c4791bf1 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.substitution; import org.jetbrains.annotations.NotNull; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Aggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Aggregator.java index 47421a94..0684a9d9 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Aggregator.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Aggregator.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import java.util.stream.Stream; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java index ecfefcf9..ccc063af 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import org.jetbrains.annotations.Nullable; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java index 8f998d45..c12c0166 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import tools.refinery.store.query.equality.LiteralEqualityHelper; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryOperator.java index 8706a046..5ff7c65c 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryOperator.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryOperator.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; public enum ArithmeticBinaryOperator { diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryTerm.java index 887a1e6e..e405df00 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryTerm.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import tools.refinery.store.query.equality.LiteralEqualityHelper; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryOperator.java index 6a7c25db..d98134f3 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryOperator.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryOperator.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; public enum ArithmeticUnaryOperator { diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryTerm.java index b78239c7..bdc87545 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryTerm.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import tools.refinery.store.query.equality.LiteralEqualityHelper; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AssignedValue.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AssignedValue.java index 465e690f..0cf30aa6 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AssignedValue.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AssignedValue.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import tools.refinery.store.query.literal.Literal; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java index 34f48ccc..b2994d23 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import tools.refinery.store.query.equality.LiteralEqualityHelper; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonOperator.java index 44dcce10..d04ae22c 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonOperator.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonOperator.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; public enum ComparisonOperator { diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonTerm.java index 320d42df..2c304aef 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonTerm.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import tools.refinery.store.query.equality.LiteralEqualityHelper; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java index 2185fe37..b03f07fd 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import tools.refinery.store.query.equality.LiteralEqualityHelper; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataSort.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataSort.java index 4fb44492..6b8669ee 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataSort.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataSort.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import org.jetbrains.annotations.Nullable; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java index af070ca7..50ef745c 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import org.jetbrains.annotations.Nullable; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ExtremeValueAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ExtremeValueAggregator.java index 57ff597c..657cb631 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ExtremeValueAggregator.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ExtremeValueAggregator.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import java.util.Comparator; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeSort.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeSort.java index 1a4b2d4b..b9be03f7 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeSort.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeSort.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import org.jetbrains.annotations.Nullable; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java index 7419aaad..de2f945a 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import org.jetbrains.annotations.Nullable; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/OpaqueTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/OpaqueTerm.java index 8faa9c75..6626365f 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/OpaqueTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/OpaqueTerm.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import tools.refinery.store.query.equality.LiteralEqualityHelper; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Sort.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Sort.java index 622bcfce..2b3345f9 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Sort.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Sort.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import org.jetbrains.annotations.Nullable; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregate.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregate.java index 7ce91305..ab310556 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregate.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregate.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; public interface StatefulAggregate { diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregator.java index c215a511..df746a90 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregator.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregator.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import java.util.stream.Stream; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatelessAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatelessAggregator.java index 74dbd335..a094919e 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatelessAggregator.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatelessAggregator.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import java.util.stream.Stream; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Term.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Term.java index 95434db2..e6818b88 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Term.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Term.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import tools.refinery.store.query.literal.AssignLiteral; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java index 4083111a..069e0d95 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import tools.refinery.store.query.equality.LiteralEqualityHelper; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java index 957e10f8..c4ca6f77 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term; import org.jetbrains.annotations.Nullable; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolConstantTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolConstantTerm.java index 5079f1ce..e5690ab6 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolConstantTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolConstantTerm.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term.bool; import tools.refinery.store.query.term.ConstantTerm; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolLogicBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolLogicBinaryTerm.java index d85f864d..11e764c2 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolLogicBinaryTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolLogicBinaryTerm.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term.bool; import tools.refinery.store.query.equality.LiteralEqualityHelper; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java index 855139b5..bb06cf8b 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term.bool; import tools.refinery.store.query.substitution.Substitution; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java index 3d6c8d9d..55825952 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term.bool; import tools.refinery.store.query.term.ConstantTerm; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/LogicBinaryOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/LogicBinaryOperator.java index ca9ac66e..93a72f88 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/LogicBinaryOperator.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/LogicBinaryOperator.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term.bool; public enum LogicBinaryOperator { diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticBinaryTerm.java index 32e41718..8a76ecbd 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticBinaryTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticBinaryTerm.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term.int_; import tools.refinery.store.query.substitution.Substitution; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticUnaryTerm.java index 1e769259..8522f2c1 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticUnaryTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticUnaryTerm.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term.int_; import tools.refinery.store.query.substitution.Substitution; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntComparisonTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntComparisonTerm.java index 322d2b80..2ce2b2f3 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntComparisonTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntComparisonTerm.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term.int_; import tools.refinery.store.query.substitution.Substitution; import tools.refinery.store.query.term.ComparisonOperator; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntExtremeValueAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntExtremeValueAggregator.java index d5a6add0..7982f45c 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntExtremeValueAggregator.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntExtremeValueAggregator.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term.int_; import tools.refinery.store.query.term.ExtremeValueAggregator; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSumAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSumAggregator.java index 65024f52..cd718c53 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSumAggregator.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSumAggregator.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term.int_; import tools.refinery.store.query.term.StatelessAggregator; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java index 86594deb..38f7f449 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term.int_; import tools.refinery.store.query.term.*; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java index 53875ddc..399adf4a 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term.int_; import tools.refinery.store.query.substitution.Substitution; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java index 55590824..4f7d5687 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term.real; import tools.refinery.store.query.substitution.Substitution; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticBinaryTerm.java index 57bcbe5e..8d5c9242 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticBinaryTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticBinaryTerm.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term.real; import tools.refinery.store.query.substitution.Substitution; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticUnaryTerm.java index 632e68bf..9d233dfc 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticUnaryTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticUnaryTerm.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term.real; import tools.refinery.store.query.substitution.Substitution; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealComparisonTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealComparisonTerm.java index 75d97adb..25c88f89 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealComparisonTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealComparisonTerm.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term.real; import tools.refinery.store.query.substitution.Substitution; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealExtremeValueAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealExtremeValueAggregator.java index 23384530..526e643b 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealExtremeValueAggregator.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealExtremeValueAggregator.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term.real; import tools.refinery.store.query.term.ExtremeValueAggregator; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSumAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSumAggregator.java index d5888664..306191a3 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSumAggregator.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSumAggregator.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term.real; import tools.refinery.store.query.term.StatefulAggregate; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java index a8117842..1240d478 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.term.real; import tools.refinery.store.query.term.*; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/RestrictedValuation.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/RestrictedValuation.java index fb512d88..fc8406aa 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/RestrictedValuation.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/RestrictedValuation.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.valuation; import tools.refinery.store.query.term.AnyDataVariable; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/SubstitutedValuation.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/SubstitutedValuation.java index 8e79663c..1c14112c 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/SubstitutedValuation.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/SubstitutedValuation.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.valuation; import tools.refinery.store.query.substitution.Substitution; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java index 3ba9a6b8..88fee35b 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.valuation; import org.jetbrains.annotations.Nullable; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnyRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnyRelationView.java index 6ae410f2..9aa923af 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnyRelationView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnyRelationView.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.view; import tools.refinery.store.model.Model; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java index 64c601bb..9717b2c1 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.view; import tools.refinery.store.tuple.Tuple; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenRelationView.java index 050b9496..c19d9282 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenRelationView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenRelationView.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.view; import tools.refinery.store.representation.Symbol; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionView.java new file mode 100644 index 00000000..cf946d54 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionView.java @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.view; + +import tools.refinery.store.query.term.DataSort; +import tools.refinery.store.query.term.Sort; +import tools.refinery.store.representation.Symbol; + +public final class FunctionView extends AbstractFunctionView { + public FunctionView(Symbol symbol, String name) { + super(symbol, name); + } + + public FunctionView(Symbol symbol) { + this(symbol, "function"); + } + + @Override + protected Sort getForwardMappedValueSort() { + return new DataSort<>(getSymbol().valueType()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java index 7ec9e7ac..ab48386e 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.view; import tools.refinery.store.model.Model; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java index e1b2e45b..9553a0cc 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.view; import tools.refinery.store.representation.Symbol; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayRelationView.java index a2a84b3c..60325f35 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayRelationView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayRelationView.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.view; import tools.refinery.store.representation.Symbol; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustRelationView.java index 72ac0ca3..d7e7ae2e 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustRelationView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustRelationView.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.view; import tools.refinery.store.representation.Symbol; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/NodeFunctionView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/NodeFunctionView.java new file mode 100644 index 00000000..73c296e0 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/NodeFunctionView.java @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.view; + +import tools.refinery.store.query.term.NodeSort; +import tools.refinery.store.query.term.Sort; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.tuple.Tuple1; + +public final class NodeFunctionView extends AbstractFunctionView { + public NodeFunctionView(Symbol symbol, String name) { + super(symbol, name); + } + + public NodeFunctionView(Symbol symbol) { + this(symbol, "function"); + } + + @Override + protected Sort getForwardMappedValueSort() { + return NodeSort.INSTANCE; + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationView.java index d7164b3b..fd4f47b4 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationView.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.view; import tools.refinery.store.map.CursorAsIterator; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationViewImplication.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationViewImplication.java index 2ba1fcc4..c54cce2f 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationViewImplication.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationViewImplication.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.view; import java.util.List; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java index 234b3a9a..e6e54aa1 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.view; import tools.refinery.store.model.Model; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ViewImplication.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ViewImplication.java new file mode 100644 index 00000000..fc2db9f2 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ViewImplication.java @@ -0,0 +1,23 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.view; + +import java.util.List; + +public record ViewImplication(AnySymbolView implyingView, AnySymbolView impliedView, List impliedIndices) { + public ViewImplication { + if (impliedIndices.size() != impliedView.arity()) { + throw new IllegalArgumentException("Expected %d implied indices for %s, but %d are provided" + .formatted(impliedView.arity(), impliedView, impliedIndices.size())); + } + for (var index : impliedIndices) { + if (impliedView.invalidIndex(index)) { + throw new IllegalArgumentException("%d is not a valid index for %s".formatted(index, + implyingView)); + } + } + } +} diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java index ceb46d6f..70cd386b 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query; import org.junit.jupiter.api.Test; diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToDefinitionStringTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToDefinitionStringTest.java index 9b469bb0..7be57745 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToDefinitionStringTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToDefinitionStringTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query; import org.junit.jupiter.api.Test; diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java index a61e2b65..e292b3ab 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.tests; import org.junit.jupiter.api.Test; diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java index 685957c9..526832c4 100644 --- a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java +++ b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.tests; import org.hamcrest.Description; diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java index bf1c1b74..8706ef70 100644 --- a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java +++ b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.tests; import org.hamcrest.Matcher; diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java index a9a78f88..ba51c084 100644 --- a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java +++ b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.query.tests; import org.hamcrest.Description; diff --git a/subprojects/store-reasoning/build.gradle.kts b/subprojects/store-reasoning/build.gradle.kts index bb37d9d3..abad0491 100644 --- a/subprojects/store-reasoning/build.gradle.kts +++ b/subprojects/store-reasoning/build.gradle.kts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + plugins { id("tools.refinery.gradle.java-library") } diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/AnyPartialInterpretation.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/AnyPartialInterpretation.java index ebe82c8b..000171a1 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/AnyPartialInterpretation.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/AnyPartialInterpretation.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning; import tools.refinery.store.reasoning.representation.AnyPartialSymbol; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/MergeResult.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/MergeResult.java index 0d51598b..d3a216d8 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/MergeResult.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/MergeResult.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning; public enum MergeResult { diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/PartialInterpretation.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/PartialInterpretation.java index 4f195e97..4140d640 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/PartialInterpretation.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/PartialInterpretation.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning; import tools.refinery.store.reasoning.representation.PartialSymbol; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/Reasoning.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/Reasoning.java index d7d0a999..3d3df2b2 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/Reasoning.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/Reasoning.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning; import tools.refinery.store.reasoning.internal.ReasoningBuilderImpl; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java index de039dd9..8dedddf7 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning; import tools.refinery.store.adapter.ModelAdapter; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java index 4030d296..df7b6e4d 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning; import tools.refinery.store.adapter.ModelAdapterBuilder; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningStoreAdapter.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningStoreAdapter.java index f6a6e414..c9795255 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningStoreAdapter.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningStoreAdapter.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning; import tools.refinery.store.adapter.ModelStoreAdapter; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java index 0acf0d49..96514d36 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.internal; import tools.refinery.store.model.Model; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java index e11b14bf..49f7c7d3 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.internal; import tools.refinery.store.adapter.AbstractModelAdapterBuilder; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningStoreAdapterImpl.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningStoreAdapterImpl.java index ac06e68b..cdddd8d6 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningStoreAdapterImpl.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningStoreAdapterImpl.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.internal; import tools.refinery.store.reasoning.ReasoningStoreAdapter; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java index 2b0e0f08..157f06e8 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.lifting; import org.jetbrains.annotations.Nullable; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/ModalDnf.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/ModalDnf.java index ec381bb8..16fb8fbf 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/ModalDnf.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/ModalDnf.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.lifting; import tools.refinery.store.query.dnf.Dnf; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java index 2fbb4607..7fa98104 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.literal; import tools.refinery.store.query.Constraint; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/Modality.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/Modality.java index f0cb59de..96466d5c 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/Modality.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/Modality.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.literal; import tools.refinery.store.query.literal.CallPolarity; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/PartialLiterals.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/PartialLiterals.java index f991f87f..0e46a795 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/PartialLiterals.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/PartialLiterals.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.literal; import tools.refinery.store.query.literal.CallLiteral; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/AnyPartialFunction.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/AnyPartialFunction.java index e74cd58b..8d2cb5cf 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/AnyPartialFunction.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/AnyPartialFunction.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.representation; public sealed interface AnyPartialFunction extends AnyPartialSymbol permits PartialFunction { diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/AnyPartialSymbol.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/AnyPartialSymbol.java index 6ff5031b..788eef73 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/AnyPartialSymbol.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/AnyPartialSymbol.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.representation; import tools.refinery.store.representation.AnyAbstractDomain; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialFunction.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialFunction.java index 59eeeefe..d58d026f 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialFunction.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialFunction.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.representation; import tools.refinery.store.representation.AbstractDomain; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialRelation.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialRelation.java index 9bae53a9..fc3dc074 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialRelation.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialRelation.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.representation; import tools.refinery.store.query.Constraint; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialSymbol.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialSymbol.java index 1af11f2e..3a08bdd8 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialSymbol.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialSymbol.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.representation; import tools.refinery.store.representation.AbstractDomain; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RelationRefinementAction.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RelationRefinementAction.java index e8ed05a3..e4c702ea 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RelationRefinementAction.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RelationRefinementAction.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.rule; import tools.refinery.store.reasoning.Reasoning; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/Rule.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/Rule.java index c7b16d47..45b0f02e 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/Rule.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/Rule.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.rule; import tools.refinery.store.model.Model; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleAction.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleAction.java index 4753b8bc..97ea7313 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleAction.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleAction.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.rule; import tools.refinery.store.model.Model; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleActionExecutor.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleActionExecutor.java index 7c51e3df..5d743869 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleActionExecutor.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleActionExecutor.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.rule; import tools.refinery.store.reasoning.MergeResult; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleExecutor.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleExecutor.java index c20645fc..32cf13ea 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleExecutor.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleExecutor.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.rule; import tools.refinery.store.model.Model; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java index 90633495..08079f12 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.seed; import tools.refinery.store.map.Cursor; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/UniformSeed.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/UniformSeed.java index a030f6ea..451d1513 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/UniformSeed.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/UniformSeed.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.seed; import tools.refinery.store.map.Cursor; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java index 5cdfedf7..dd7a018d 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator; import tools.refinery.store.reasoning.representation.AnyPartialSymbol; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/AdviceSlot.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/AdviceSlot.java index f3bd9c5e..bab20340 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/AdviceSlot.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/AdviceSlot.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator; import tools.refinery.store.representation.TruthValue; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslatedRelation.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslatedRelation.java index 9bab80c9..4a5a8843 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslatedRelation.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslatedRelation.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator; import tools.refinery.store.model.Model; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslationUnit.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslationUnit.java index 24b93911..7f01122b 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslationUnit.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslationUnit.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator; import tools.refinery.store.model.Model; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionInterpretation.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionInterpretation.java index b703f142..e7b67ae4 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionInterpretation.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionInterpretation.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator.base; import tools.refinery.store.map.Cursor; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionTranslationUnit.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionTranslationUnit.java index 36e2782a..d41e11c6 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionTranslationUnit.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionTranslationUnit.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator.base; import tools.refinery.store.model.Model; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/TranslatedBaseDecision.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/TranslatedBaseDecision.java index 2294b4fd..4782eb46 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/TranslatedBaseDecision.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/TranslatedBaseDecision.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator.base; import tools.refinery.store.model.Model; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/EliminatedType.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/EliminatedType.java index 1b8d7cc9..6e4728db 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/EliminatedType.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/EliminatedType.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator.typehierarchy; import tools.refinery.store.reasoning.representation.PartialRelation; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/ExtendedTypeInfo.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/ExtendedTypeInfo.java index 43b8e1dd..7a917dcf 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/ExtendedTypeInfo.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/ExtendedTypeInfo.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator.typehierarchy; import org.jetbrains.annotations.NotNull; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeRelationView.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeRelationView.java index 12c37c86..aea0a4b9 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeRelationView.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeRelationView.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator.typehierarchy; import tools.refinery.store.reasoning.representation.PartialRelation; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeRelationView.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeRelationView.java index 975f627e..6c995e3a 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeRelationView.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeRelationView.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator.typehierarchy; import tools.refinery.store.reasoning.representation.PartialRelation; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredType.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredType.java index a366e262..fd05158b 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredType.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredType.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator.typehierarchy; import tools.refinery.store.reasoning.representation.PartialRelation; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/PreservedType.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/PreservedType.java index 63dba964..0696f4c3 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/PreservedType.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/PreservedType.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator.typehierarchy; import tools.refinery.store.reasoning.representation.PartialRelation; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalysisResult.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalysisResult.java index 4f915108..fbf8a7c9 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalysisResult.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalysisResult.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator.typehierarchy; sealed interface TypeAnalysisResult permits EliminatedType, PreservedType { diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzer.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzer.java index 62f8e750..e97ce954 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzer.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzer.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator.typehierarchy; import tools.refinery.store.reasoning.representation.PartialRelation; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslationUnit.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslationUnit.java index 4b0761f2..e1aa2014 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslationUnit.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslationUnit.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator.typehierarchy; import tools.refinery.store.model.Model; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeInfo.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeInfo.java index 313df4df..9f897e46 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeInfo.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeInfo.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator.typehierarchy; import tools.refinery.store.reasoning.representation.PartialRelation; diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredTypeTest.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredTypeTest.java index a8df2312..1d76855c 100644 --- a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredTypeTest.java +++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredTypeTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator.typehierarchy; import org.junit.jupiter.api.Test; diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerExampleHierarchyTest.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerExampleHierarchyTest.java index b2c1ef1b..05a476c6 100644 --- a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerExampleHierarchyTest.java +++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerExampleHierarchyTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator.typehierarchy; import org.junit.jupiter.api.BeforeEach; diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTest.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTest.java index b7b69ed8..d0ef9d57 100644 --- a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTest.java +++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator.typehierarchy; import org.junit.jupiter.api.Test; diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTester.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTester.java index 56407730..2924816e 100644 --- a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTester.java +++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTester.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.reasoning.translator.typehierarchy; import tools.refinery.store.reasoning.representation.PartialRelation; diff --git a/subprojects/store/build.gradle.kts b/subprojects/store/build.gradle.kts index d62e5159..2c485020 100644 --- a/subprojects/store/build.gradle.kts +++ b/subprojects/store/build.gradle.kts @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + plugins { id("tools.refinery.gradle.java-library") id("tools.refinery.gradle.jmh") diff --git a/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutBenchmark.java b/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutBenchmark.java index cdf3d3c8..485fda3d 100644 --- a/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutBenchmark.java +++ b/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutBenchmark.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.benchmarks; import java.util.ArrayList; diff --git a/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutExecutionPlan.java b/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutExecutionPlan.java index 756d504e..edd4f53e 100644 --- a/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutExecutionPlan.java +++ b/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutExecutionPlan.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.benchmarks; import java.util.Random; diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java index 4c142217..70602ef5 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java +++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.adapter; import tools.refinery.store.model.ModelStore; diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java index 74bae6f0..e896d8d9 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java +++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.adapter; import org.jetbrains.annotations.NotNull; diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java index 37a247fe..f161a60b 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java +++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.adapter; import java.util.Collection; diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapter.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapter.java index aa079e01..672007aa 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapter.java +++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapter.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.adapter; import tools.refinery.store.model.Model; diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java index 64b3e59f..709cbb3e 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java +++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.adapter; import tools.refinery.store.model.ModelStore; diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java index 7c9b01bc..1d549d5b 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java +++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.adapter; import tools.refinery.store.model.ModelStoreBuilder; diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java index 82ddeb12..6255fe52 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java +++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.adapter; import tools.refinery.store.model.Model; diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelStoreAdapter.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelStoreAdapter.java index 1eb40ada..bc5f7b6b 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelStoreAdapter.java +++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelStoreAdapter.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.adapter; import tools.refinery.store.model.Model; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java b/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java index f82a8bb1..25fc91e6 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map; public sealed interface AnyVersionedMap extends Versioned permits VersionedMap { diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/ContentHashCode.java b/subprojects/store/src/main/java/tools/refinery/store/map/ContentHashCode.java index 8deeab23..cbea05e1 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/ContentHashCode.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/ContentHashCode.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map; public enum ContentHashCode { diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/ContinousHashProvider.java b/subprojects/store/src/main/java/tools/refinery/store/map/ContinousHashProvider.java index 75f1e2ab..8e451230 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/ContinousHashProvider.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/ContinousHashProvider.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map; import tools.refinery.store.map.internal.Node; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/Cursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/Cursor.java index b420585c..3bdca104 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/Cursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/Cursor.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map; import java.util.Set; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/CursorAsIterator.java b/subprojects/store/src/main/java/tools/refinery/store/map/CursorAsIterator.java index 65ae6648..c7e4d279 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/CursorAsIterator.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/CursorAsIterator.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map; import java.util.Iterator; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/Cursors.java b/subprojects/store/src/main/java/tools/refinery/store/map/Cursors.java index fc8e628b..0a94d449 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/Cursors.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/Cursors.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map; public final class Cursors { diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/DiffCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/DiffCursor.java index 701f3ec8..4322e041 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/DiffCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/DiffCursor.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map; public interface DiffCursor extends Cursor { diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/MapAsIterable.java b/subprojects/store/src/main/java/tools/refinery/store/map/MapAsIterable.java index 6b986732..199b548f 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/MapAsIterable.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/MapAsIterable.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map; import java.util.Iterator; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/Versioned.java b/subprojects/store/src/main/java/tools/refinery/store/map/Versioned.java index 6a23e9d5..55720db3 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/Versioned.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/Versioned.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map; public interface Versioned { diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMap.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMap.java index 31985e94..9bbde24d 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMap.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMap.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map; public non-sealed interface VersionedMap extends AnyVersionedMap { diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStore.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStore.java index a8d7fb1a..5aafa338 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStore.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStore.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map; import java.util.Set; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreConfiguration.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreConfiguration.java index 3856460d..b00cd961 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreConfiguration.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreConfiguration.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map; public class VersionedMapStoreConfiguration { diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreImpl.java index 113874e7..aade4aeb 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreImpl.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map; import tools.refinery.store.map.internal.ImmutableNode; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/HashClash.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/HashClash.java index 5402ed4a..61b3d1b8 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/HashClash.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/HashClash.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; enum HashClash { diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java index 9397dede..03dffc15 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; import java.util.Arrays; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java index 91a71e3d..f34ec7bb 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; import tools.refinery.store.map.AnyVersionedMap; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java index 9cd78113..d31f1a05 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; import tools.refinery.store.map.AnyVersionedMap; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java index 7c3cf7e8..1129ee5a 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java @@ -1,10 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; +import tools.refinery.store.map.ContinousHashProvider; + import java.util.Arrays; import java.util.Map; -import tools.refinery.store.map.ContinousHashProvider; - public class MutableNode extends Node { int cachedHash; protected Object[] content; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/Node.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/Node.java index 2260cd5b..958d645f 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/Node.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/Node.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; import java.util.Map; diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/OldValueBox.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/OldValueBox.java index 5534c703..354af51d 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/OldValueBox.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/OldValueBox.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; public class OldValueBox{ diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java index 301bcb95..7abece0d 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.internal; import tools.refinery.store.map.*; diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/AnyInterpretation.java b/subprojects/store/src/main/java/tools/refinery/store/model/AnyInterpretation.java index d18ba71d..f906b48a 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/AnyInterpretation.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/AnyInterpretation.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.model; import tools.refinery.store.representation.AnySymbol; diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java b/subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java index 55949d0c..26ad9a69 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.model; import tools.refinery.store.map.Cursor; diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/InterpretationListener.java b/subprojects/store/src/main/java/tools/refinery/store/model/InterpretationListener.java index 73950779..6f7b24c1 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/InterpretationListener.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/InterpretationListener.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.model; import tools.refinery.store.tuple.Tuple; diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/Model.java b/subprojects/store/src/main/java/tools/refinery/store/model/Model.java index 6ca1ac7b..f4131756 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/Model.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/Model.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.model; import tools.refinery.store.adapter.ModelAdapter; diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelDiffCursor.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelDiffCursor.java index 97bf2039..7b236891 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelDiffCursor.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelDiffCursor.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.model; import tools.refinery.store.map.DiffCursor; diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java index f67540bb..a9ad8cfd 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.model; public interface ModelListener { diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java index 2e7e62c3..a72399f7 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.model; import tools.refinery.store.adapter.ModelAdapterType; diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java index 289099da..d9354bdb 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.model; import tools.refinery.store.adapter.ModelAdapterBuilder; diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java b/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java index 4bcf9ff4..fe1c2ab5 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.model; import tools.refinery.store.map.ContinousHashProvider; diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProviderBitMagic.java b/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProviderBitMagic.java index 33059a1b..14116a90 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProviderBitMagic.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProviderBitMagic.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.model; import tools.refinery.store.map.ContinousHashProvider; diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelAction.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelAction.java index f68859db..dbd95d80 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelAction.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelAction.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.model.internal; public enum ModelAction { diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java index 9eb438c4..50a408da 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.model.internal; import tools.refinery.store.adapter.AdapterList; diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java index 79f7195d..70bccb96 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.model.internal; import tools.refinery.store.adapter.AdapterList; diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java index e8c205e4..bfae7181 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.model.internal; import tools.refinery.store.adapter.AdapterList; diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/SymbolEquivalenceClass.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/SymbolEquivalenceClass.java index 5bf1b90d..136f2976 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/SymbolEquivalenceClass.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/SymbolEquivalenceClass.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.model.internal; import tools.refinery.store.representation.Symbol; diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java index 6d82f5d7..86101ce3 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.model.internal; import tools.refinery.store.map.Cursor; diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/AbstractDomain.java b/subprojects/store/src/main/java/tools/refinery/store/representation/AbstractDomain.java index 18903ead..52c740e8 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/representation/AbstractDomain.java +++ b/subprojects/store/src/main/java/tools/refinery/store/representation/AbstractDomain.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation; import java.util.Optional; diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/AnyAbstractDomain.java b/subprojects/store/src/main/java/tools/refinery/store/representation/AnyAbstractDomain.java index 4c428a1e..c354fab7 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/representation/AnyAbstractDomain.java +++ b/subprojects/store/src/main/java/tools/refinery/store/representation/AnyAbstractDomain.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation; public sealed interface AnyAbstractDomain permits AbstractDomain { diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/AnySymbol.java b/subprojects/store/src/main/java/tools/refinery/store/representation/AnySymbol.java index 20b9eead..b2377905 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/representation/AnySymbol.java +++ b/subprojects/store/src/main/java/tools/refinery/store/representation/AnySymbol.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation; public sealed interface AnySymbol permits Symbol { 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 30b1c03f..aad88921 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,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation; public record Symbol(String name, int arity, Class valueType, T defaultValue) implements AnySymbol { diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValue.java b/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValue.java index b7893fd3..40baf9a5 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValue.java +++ b/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValue.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation; public enum TruthValue { diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValueDomain.java b/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValueDomain.java index 29858bce..89f8dd19 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValueDomain.java +++ b/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValueDomain.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation; import java.util.Optional; diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityInterval.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityInterval.java index 273d0de7..704ca2fc 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityInterval.java +++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityInterval.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation.cardinality; public sealed interface CardinalityInterval permits NonEmptyCardinalityInterval, EmptyCardinalityInterval { diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityIntervals.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityIntervals.java index e1a08bf9..ad16a3e8 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityIntervals.java +++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityIntervals.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation.cardinality; public final class CardinalityIntervals { diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/EmptyCardinalityInterval.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/EmptyCardinalityInterval.java index ab3ad9d1..49911c29 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/EmptyCardinalityInterval.java +++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/EmptyCardinalityInterval.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation.cardinality; public final class EmptyCardinalityInterval implements CardinalityInterval { diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinality.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinality.java index 381c8a57..82afdbbc 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinality.java +++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinality.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation.cardinality; import org.jetbrains.annotations.NotNull; diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/NonEmptyCardinalityInterval.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/NonEmptyCardinalityInterval.java index 32b3786f..38bd53bf 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/NonEmptyCardinalityInterval.java +++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/NonEmptyCardinalityInterval.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation.cardinality; import java.util.function.BinaryOperator; diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UnboundedUpperCardinality.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UnboundedUpperCardinality.java index 593bc322..a5634020 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UnboundedUpperCardinality.java +++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UnboundedUpperCardinality.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation.cardinality; import org.jetbrains.annotations.NotNull; diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinalities.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinalities.java index d850fdc9..1e18dde0 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinalities.java +++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinalities.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation.cardinality; public final class UpperCardinalities { diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinality.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinality.java index c6e31cb7..5dbaa922 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinality.java +++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinality.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation.cardinality; public sealed interface UpperCardinality extends Comparable permits FiniteUpperCardinality, diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java index 51e2895a..6700417a 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.tuple; public sealed interface Tuple permits Tuple0, Tuple1, Tuple2, Tuple3, Tuple4, TupleN { diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java index 266e2cca..1451099c 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.tuple; import static tools.refinery.store.tuple.TupleConstants.TUPLE_BEGIN; diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java index bdcc47b5..cda145d7 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.tuple; import tools.refinery.store.model.TupleHashProvider; diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java index fc0fbd8e..b669674b 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.tuple; import static tools.refinery.store.tuple.TupleConstants.*; diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java index a6ec17b0..542ed328 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.tuple; import static tools.refinery.store.tuple.TupleConstants.*; diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java index 66cef32b..121a15f6 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.tuple; import static tools.refinery.store.tuple.TupleConstants.*; diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleConstants.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleConstants.java index 3d95a655..f7d27848 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleConstants.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleConstants.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.tuple; final class TupleConstants { diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java index 512bab49..b66af491 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.tuple; import java.util.Arrays; diff --git a/subprojects/store/src/main/java/tools/refinery/store/util/CollectionsUtil.java b/subprojects/store/src/main/java/tools/refinery/store/util/CollectionsUtil.java index 841d0dfa..adecd79b 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/util/CollectionsUtil.java +++ b/subprojects/store/src/main/java/tools/refinery/store/util/CollectionsUtil.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.util; import java.util.Iterator; diff --git a/subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java b/subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java index 8a151d01..78ad2ad7 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java +++ b/subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.util; import java.util.*; diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java index 77c62305..153f2e78 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.tests; import org.junit.jupiter.api.Test; diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java index 1f9d022f..eabe5bd1 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.tests.fuzz; import static org.junit.jupiter.api.Assertions.fail; diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java index 93ecfec3..b0502a2b 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.tests.fuzz; import org.junit.jupiter.api.Tag; diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java index e6334224..8274336e 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.tests.fuzz; import static org.junit.jupiter.api.Assertions.fail; diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java index 1ab431a8..ab2b9435 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.tests.fuzz; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java index f77f9ee5..502c8362 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.tests.fuzz; import java.util.ArrayList; diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java index d40c49c4..32dde0da 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.tests.fuzz; import static org.junit.jupiter.api.Assertions.fail; diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java index 410705a2..347c49be 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.tests.fuzz; import static org.junit.jupiter.api.Assertions.fail; diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java index 2e29a03f..f7b9d61e 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.tests.fuzz; import static org.junit.jupiter.api.Assertions.fail; diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java index 914a0f63..4b4172d0 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.tests.fuzz; import java.util.HashMap; diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java index e75d7f5a..a819d348 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.tests.fuzz.utils; import java.util.Arrays; diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java index 72f2a46c..dc621574 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.tests.fuzz.utils; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java index 2d03ebaf..f861f496 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.map.tests.utils; import tools.refinery.store.map.*; diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java b/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java index bb083805..4d4f5e26 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.model.hashtests; import static org.junit.jupiter.api.Assertions.assertEquals; 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 9536a444..1017ff28 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 @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.model.tests; import org.junit.jupiter.api.Test; diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalTest.java index 96fdc49e..6a66fa84 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation.cardinality; import org.junit.jupiter.params.ParameterizedTest; diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalsTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalsTest.java index 4a9ef8da..9fe76159 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalsTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalsTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation.cardinality; import org.junit.jupiter.api.Test; diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/EmptyCardinalityIntervalTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/EmptyCardinalityIntervalTest.java index e8b77b9f..24a788a8 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/EmptyCardinalityIntervalTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/EmptyCardinalityIntervalTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation.cardinality; import org.junit.jupiter.api.Test; diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteCardinalityIntervalTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteCardinalityIntervalTest.java index 9a190818..6cf56fae 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteCardinalityIntervalTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteCardinalityIntervalTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation.cardinality; import org.junit.jupiter.api.Test; diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinalityTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinalityTest.java index 90c21759..7c641c47 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinalityTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinalityTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation.cardinality; import org.junit.jupiter.api.Test; diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalitiesTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalitiesTest.java index 3c7c0320..e61f7b36 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalitiesTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalitiesTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation.cardinality; import org.junit.jupiter.api.Test; diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalityTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalityTest.java index e87ce29b..10b4dd20 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalityTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalityTest.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.representation.cardinality; import org.junit.jupiter.params.ParameterizedTest; diff --git a/subprojects/store/src/test/java/tools/refinery/store/util/CollectionsUtilTests.java b/subprojects/store/src/test/java/tools/refinery/store/util/CollectionsUtilTests.java index 171be0e5..8d50fa8a 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/util/CollectionsUtilTests.java +++ b/subprojects/store/src/test/java/tools/refinery/store/util/CollectionsUtilTests.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ package tools.refinery.store.util; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/yarn.lock.license b/yarn.lock.license new file mode 100644 index 00000000..7a5a2a4b --- /dev/null +++ b/yarn.lock.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + +SPDX-License-Identifier: CC0-1.0 -- cgit v1.2.3-70-g09d2 From 7c15c0e6e6a035458bdd89a939aacdf4a207e1cd Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Mon, 10 Apr 2023 19:18:29 +0200 Subject: refactor: rename RelationView to SymbolView * Add NodeFunctionView for symbols that hold function-like (single associated object for each key) relations as integer values for performance. --- .../internal/ViatraModelQueryBuilderImpl.java | 10 +- .../internal/ViatraModelQueryStoreAdapterImpl.java | 10 +- .../context/RelationalQueryMetaContext.java | 34 +++--- .../internal/context/RelationalRuntimeContext.java | 22 ++-- .../query/viatra/internal/pquery/Dnf2PQuery.java | 14 +-- .../internal/pquery/QueryWrapperFactory.java | 22 ++-- .../internal/pquery/RelationViewWrapper.java | 40 ------- .../viatra/internal/pquery/SymbolViewWrapper.java | 40 +++++++ .../internal/update/ModelUpdateListener.java | 38 +++---- .../update/RelationViewUpdateListener.java | 65 ------------ .../internal/update/SymbolViewUpdateListener.java | 65 ++++++++++++ .../TupleChangingRelationViewUpdateListener.java | 44 -------- .../update/TupleChangingViewUpdateListener.java | 44 ++++++++ .../TuplePreservingRelationViewUpdateListener.java | 33 ------ .../update/TuplePreservingViewUpdateListener.java | 33 ++++++ .../store/query/viatra/DiagonalQueryTest.java | 36 +++---- .../store/query/viatra/FunctionalQueryTest.java | 50 ++++----- .../refinery/store/query/viatra/QueryTest.java | 60 +++++------ .../store/query/viatra/QueryTransactionTest.java | 24 ++--- .../store/query/ModelQueryStoreAdapter.java | 4 +- .../store/query/view/AbstractFunctionView.java | 116 +++++++++++++++++++++ .../refinery/store/query/view/AnyRelationView.java | 31 ------ .../refinery/store/query/view/AnySymbolView.java | 31 ++++++ .../store/query/view/FilteredRelationView.java | 54 ---------- .../refinery/store/query/view/FilteredView.java | 54 ++++++++++ .../store/query/view/ForbiddenRelationView.java | 21 ---- .../refinery/store/query/view/ForbiddenView.java | 21 ++++ .../store/query/view/FunctionalRelationView.java | 110 ------------------- .../store/query/view/KeyOnlyRelationView.java | 41 -------- .../refinery/store/query/view/KeyOnlyView.java | 41 ++++++++ .../refinery/store/query/view/MayRelationView.java | 21 ---- .../tools/refinery/store/query/view/MayView.java | 21 ++++ .../store/query/view/MustRelationView.java | 21 ---- .../tools/refinery/store/query/view/MustView.java | 21 ++++ .../refinery/store/query/view/RelationView.java | 82 --------------- .../store/query/view/RelationViewImplication.java | 24 ----- .../refinery/store/query/view/SymbolView.java | 82 +++++++++++++++ .../query/view/TuplePreservingRelationView.java | 62 ----------- .../store/query/view/TuplePreservingView.java | 65 ++++++++++++ .../tools/refinery/store/query/DnfBuilderTest.java | 26 ++--- .../store/query/DnfToDefinitionStringTest.java | 20 ++-- .../store/query/tests/StructurallyEqualToTest.java | 10 +- .../typehierarchy/InferredMayTypeRelationView.java | 24 ----- .../typehierarchy/InferredMayTypeView.java | 24 +++++ .../InferredMustTypeRelationView.java | 24 ----- .../typehierarchy/InferredMustTypeView.java | 24 +++++ 46 files changed, 872 insertions(+), 887 deletions(-) delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/SymbolViewWrapper.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/SymbolViewUpdateListener.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingViewUpdateListener.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingViewUpdateListener.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnyRelationView.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnySymbolView.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredView.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenRelationView.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenView.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyView.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayRelationView.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayView.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustRelationView.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustView.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationView.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationViewImplication.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/SymbolView.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingView.java delete mode 100644 subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeRelationView.java create mode 100644 subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeView.java delete mode 100644 subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeRelationView.java create mode 100644 subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeView.java (limited to 'subprojects/store-query-viatra/src/main/java/tools') 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 999d349a..44ed1505 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 @@ -117,7 +117,7 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp public ViatraModelQueryStoreAdapterImpl createStoreAdapter(ModelStore store) { validateSymbols(store); dnf2PQuery.assertNoUnusedHints(); - return new ViatraModelQueryStoreAdapterImpl(store, buildEngineOptions(), dnf2PQuery.getRelationViews(), + return new ViatraModelQueryStoreAdapterImpl(store, buildEngineOptions(), dnf2PQuery.getSymbolViews(), Collections.unmodifiableMap(querySpecifications), Collections.unmodifiableSet(vacuousQueries)); } @@ -140,11 +140,11 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp private void validateSymbols(ModelStore store) { var symbols = store.getSymbols(); - for (var relationView : dnf2PQuery.getRelationViews().keySet()) { - var symbol = relationView.getSymbol(); + for (var symbolView : dnf2PQuery.getSymbolViews().keySet()) { + var symbol = symbolView.getSymbol(); if (!symbols.contains(symbol)) { - throw new IllegalArgumentException("Cannot query relation view %s: symbol %s is not in the model" - .formatted(relationView, symbol)); + throw new IllegalArgumentException("Cannot query view %s: symbol %s is not in the model" + .formatted(symbolView, symbol)); } } } 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 aa102a35..11a3c7fd 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 @@ -13,20 +13,20 @@ import tools.refinery.store.model.ModelStore; import tools.refinery.store.query.dnf.AnyQuery; import tools.refinery.store.query.viatra.ViatraModelQueryStoreAdapter; import tools.refinery.store.query.viatra.internal.matcher.RawPatternMatcher; -import tools.refinery.store.query.view.AnyRelationView; +import tools.refinery.store.query.view.AnySymbolView; import java.util.*; public class ViatraModelQueryStoreAdapterImpl implements ViatraModelQueryStoreAdapter { private final ModelStore store; private final ViatraQueryEngineOptions engineOptions; - private final Map inputKeys; + private final Map inputKeys; private final Map> querySpecifications; private final Set vacuousQueries; private final Set allQueries; ViatraModelQueryStoreAdapterImpl(ModelStore store, ViatraQueryEngineOptions engineOptions, - Map inputKeys, + Map inputKeys, Map> querySpecifications, Set vacuousQueries) { this.store = store; @@ -45,11 +45,11 @@ public class ViatraModelQueryStoreAdapterImpl implements ViatraModelQueryStoreAd return store; } - public Collection getRelationViews() { + public Collection getSymbolViews() { return inputKeys.keySet(); } - public Map getInputKeys() { + public Map getInputKeys() { return inputKeys; } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java index 07a5a6ea..cf96b7fd 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java @@ -10,8 +10,8 @@ import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; import org.eclipse.viatra.query.runtime.matchers.context.InputKeyImplication; import org.eclipse.viatra.query.runtime.matchers.context.common.JavaTransitiveInstancesKey; import tools.refinery.store.query.term.DataSort; -import tools.refinery.store.query.viatra.internal.pquery.RelationViewWrapper; -import tools.refinery.store.query.view.AnyRelationView; +import tools.refinery.store.query.viatra.internal.pquery.SymbolViewWrapper; +import tools.refinery.store.query.view.AnySymbolView; import java.util.*; @@ -19,9 +19,9 @@ import java.util.*; * The meta context information for String scopes. */ public class RelationalQueryMetaContext extends AbstractQueryMetaContext { - private final Map inputKeys; + private final Map inputKeys; - RelationalQueryMetaContext(Map inputKeys) { + RelationalQueryMetaContext(Map inputKeys) { this.inputKeys = inputKeys; } @@ -47,23 +47,23 @@ public class RelationalQueryMetaContext extends AbstractQueryMetaContext { if (implyingKey instanceof JavaTransitiveInstancesKey) { return List.of(); } - var relationView = checkKey(implyingKey); - var relationViewImplications = relationView.getImpliedRelationViews(); + var symbolView = checkKey(implyingKey); + var relationViewImplications = symbolView.getImpliedRelationViews(); var inputKeyImplications = new HashSet(relationViewImplications.size()); for (var relationViewImplication : relationViewImplications) { - if (!relationView.equals(relationViewImplication.implyingRelationView())) { + if (!symbolView.equals(relationViewImplication.implyingView())) { throw new IllegalArgumentException("Relation view %s returned unrelated implication %s".formatted( - relationView, relationViewImplication)); + symbolView, relationViewImplication)); } - var impliedInputKey = inputKeys.get(relationViewImplication.impliedRelationView()); + var impliedInputKey = inputKeys.get(relationViewImplication.impliedView()); // Ignore implications not relevant for any queries included in the model. if (impliedInputKey != null) { inputKeyImplications.add(new InputKeyImplication(implyingKey, impliedInputKey, relationViewImplication.impliedIndices())); } } - var sorts = relationView.getSorts(); - int arity = relationView.arity(); + var sorts = symbolView.getSorts(); + int arity = symbolView.arity(); for (int i = 0; i < arity; i++) { var sort = sorts.get(i); if (sort instanceof DataSort dataSort) { @@ -99,20 +99,20 @@ public class RelationalQueryMetaContext extends AbstractQueryMetaContext { return flattened; } - private static void checkValidIndices(AnyRelationView relationView, Collection indices) { + private static void checkValidIndices(AnySymbolView relationView, Collection indices) { indices.stream().filter(relationView::invalidIndex).findAny().ifPresent(i -> { throw new IllegalArgumentException("Index %d is invalid for %s".formatted(i, relationView)); }); } - public AnyRelationView checkKey(IInputKey key) { - if (!(key instanceof RelationViewWrapper wrapper)) { + public AnySymbolView checkKey(IInputKey key) { + if (!(key instanceof SymbolViewWrapper wrapper)) { throw new IllegalArgumentException("The input key %s is not a valid input key".formatted(key)); } - var relationView = wrapper.getWrappedKey(); - if (!inputKeys.containsKey(relationView)) { + var symbolView = wrapper.getWrappedKey(); + if (!inputKeys.containsKey(symbolView)) { throw new IllegalArgumentException("The input key %s is not present in the model".formatted(key)); } - return relationView; + return symbolView; } } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java index 71943737..0f2daca8 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java @@ -13,9 +13,9 @@ import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; import org.eclipse.viatra.query.runtime.matchers.util.Accuracy; import tools.refinery.store.model.Model; import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; -import tools.refinery.store.query.viatra.internal.pquery.RelationViewWrapper; +import tools.refinery.store.query.viatra.internal.pquery.SymbolViewWrapper; import tools.refinery.store.query.viatra.internal.update.ModelUpdateListener; -import tools.refinery.store.query.view.AnyRelationView; +import tools.refinery.store.query.view.AnySymbolView; import java.lang.reflect.InvocationTargetException; import java.util.Iterator; @@ -59,9 +59,9 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext { @Override public boolean isIndexed(IInputKey key, IndexingService service) { - if (key instanceof RelationViewWrapper wrapper) { - var relationalKey = wrapper.getWrappedKey(); - return this.modelUpdateListener.containsRelationView(relationalKey); + if (key instanceof SymbolViewWrapper wrapper) { + var symbolViewKey = wrapper.getWrappedKey(); + return this.modelUpdateListener.containsSymbolView(symbolViewKey); } else { return false; } @@ -74,13 +74,13 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext { } } - AnyRelationView checkKey(IInputKey key) { - if (key instanceof RelationViewWrapper wrappedKey) { - var relationViewKey = wrappedKey.getWrappedKey(); - if (modelUpdateListener.containsRelationView(relationViewKey)) { - return relationViewKey; + AnySymbolView checkKey(IInputKey key) { + if (key instanceof SymbolViewWrapper wrappedKey) { + var symbolViewKey = wrappedKey.getWrappedKey(); + if (modelUpdateListener.containsSymbolView(symbolViewKey)) { + return symbolViewKey; } else { - throw new IllegalStateException("Query is asking for non-indexed key %s".formatted(relationViewKey)); + throw new IllegalStateException("Query is asking for non-indexed key %s".formatted(symbolViewKey)); } } else { throw new IllegalStateException("Query is asking for non-relational key"); 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 index 714d41c0..b511a5c7 100644 --- 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 @@ -29,7 +29,7 @@ import tools.refinery.store.query.term.ConstantTerm; import tools.refinery.store.query.term.StatefulAggregator; import tools.refinery.store.query.term.StatelessAggregator; import tools.refinery.store.query.term.Variable; -import tools.refinery.store.query.view.AnyRelationView; +import tools.refinery.store.query.view.AnySymbolView; import tools.refinery.store.util.CycleDetectingMapper; import java.util.*; @@ -53,8 +53,8 @@ public class Dnf2PQuery { return mapper.map(dnfQuery); } - public Map getRelationViews() { - return wrapperFactory.getRelationViews(); + public Map getSymbolViews() { + return wrapperFactory.getSymbolViews(); } public void hint(Dnf dnf, QueryEvaluationHint hint) { @@ -165,8 +165,8 @@ public class Dnf2PQuery { if (constraint instanceof Dnf dnf) { var pattern = translate(dnf); new PositivePatternCall(body, substitution, pattern); - } else if (constraint instanceof AnyRelationView relationView) { - var inputKey = wrapperFactory.getInputKey(relationView); + } else if (constraint instanceof AnySymbolView symbolView) { + var inputKey = wrapperFactory.getInputKey(symbolView); new TypeConstraint(body, substitution, inputKey); } else { throw new IllegalArgumentException("Unknown Constraint: " + constraint); @@ -178,8 +178,8 @@ public class Dnf2PQuery { PQuery pattern; if (constraint instanceof Dnf dnf) { pattern = translate(dnf); - } else if (constraint instanceof AnyRelationView relationView) { - pattern = wrapperFactory.wrapRelationViewIdentityArguments(relationView); + } else if (constraint instanceof AnySymbolView symbolView) { + pattern = wrapperFactory.wrapSymbolViewIdentityArguments(symbolView); } else { throw new IllegalArgumentException("Unknown Constraint: " + constraint); } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java index 30f848a6..0d046455 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java @@ -21,8 +21,8 @@ import tools.refinery.store.query.dnf.DnfClause; import tools.refinery.store.query.dnf.DnfUtils; import tools.refinery.store.query.literal.AbstractCallLiteral; import tools.refinery.store.query.term.Variable; -import tools.refinery.store.query.view.AnyRelationView; -import tools.refinery.store.query.view.RelationView; +import tools.refinery.store.query.view.AnySymbolView; +import tools.refinery.store.query.view.SymbolView; import tools.refinery.store.util.CycleDetectingMapper; import java.util.*; @@ -30,7 +30,7 @@ import java.util.function.ToIntFunction; class QueryWrapperFactory { private final Dnf2PQuery dnf2PQuery; - private final Map view2WrapperMap = new LinkedHashMap<>(); + private final Map view2WrapperMap = new LinkedHashMap<>(); private final CycleDetectingMapper wrapConstraint = new CycleDetectingMapper<>( RemappedConstraint::toString, this::doWrapConstraint); @@ -38,12 +38,12 @@ class QueryWrapperFactory { this.dnf2PQuery = dnf2PQuery; } - public PQuery wrapRelationViewIdentityArguments(AnyRelationView relationView) { - var identity = new int[relationView.arity()]; + public PQuery wrapSymbolViewIdentityArguments(AnySymbolView symbolView) { + var identity = new int[symbolView.arity()]; for (int i = 0; i < identity.length; i++) { identity[i] = i; } - return maybeWrapConstraint(relationView, identity); + return maybeWrapConstraint(symbolView, identity); } public WrappedCall maybeWrapConstraint(AbstractCallLiteral callLiteral, DnfClause clause) { var arguments = callLiteral.getArguments(); @@ -112,8 +112,8 @@ class QueryWrapperFactory { } var argumentTuple = Tuples.flatTupleOf(arguments); - if (constraint instanceof RelationView relationView) { - new TypeConstraint(body, argumentTuple, getInputKey(relationView)); + if (constraint instanceof SymbolView view) { + new TypeConstraint(body, argumentTuple, getInputKey(view)); } else if (constraint instanceof Dnf dnf) { var calledPQuery = dnf2PQuery.translate(dnf); new PositivePatternCall(body, argumentTuple, calledPQuery); @@ -125,11 +125,11 @@ class QueryWrapperFactory { return embeddedPQuery; } - public IInputKey getInputKey(AnyRelationView relationView) { - return view2WrapperMap.computeIfAbsent(relationView, RelationViewWrapper::new); + public IInputKey getInputKey(AnySymbolView symbolView) { + return view2WrapperMap.computeIfAbsent(symbolView, SymbolViewWrapper::new); } - public Map getRelationViews() { + public Map getSymbolViews() { return Collections.unmodifiableMap(view2WrapperMap); } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java deleted file mode 100644 index 02da932b..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.viatra.internal.pquery; - -import org.eclipse.viatra.query.runtime.matchers.context.common.BaseInputKeyWrapper; -import tools.refinery.store.query.view.AnyRelationView; - -public class RelationViewWrapper extends BaseInputKeyWrapper { - public RelationViewWrapper(AnyRelationView wrappedKey) { - super(wrappedKey); - } - - @Override - public String getPrettyPrintableName() { - return wrappedKey.name(); - } - - @Override - public String getStringID() { - return getPrettyPrintableName(); - } - - @Override - public int getArity() { - return wrappedKey.arity(); - } - - @Override - public boolean isEnumerable() { - return true; - } - - @Override - public String toString() { - return "RelationViewWrapper{wrappedKey=%s}".formatted(wrappedKey); - } -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/SymbolViewWrapper.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/SymbolViewWrapper.java new file mode 100644 index 00000000..a777613e --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/SymbolViewWrapper.java @@ -0,0 +1,40 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.viatra.internal.pquery; + +import org.eclipse.viatra.query.runtime.matchers.context.common.BaseInputKeyWrapper; +import tools.refinery.store.query.view.AnySymbolView; + +public class SymbolViewWrapper extends BaseInputKeyWrapper { + public SymbolViewWrapper(AnySymbolView wrappedKey) { + super(wrappedKey); + } + + @Override + public String getPrettyPrintableName() { + return wrappedKey.name(); + } + + @Override + public String getStringID() { + return getPrettyPrintableName(); + } + + @Override + public int getArity() { + return wrappedKey.arity(); + } + + @Override + public boolean isEnumerable() { + return true; + } + + @Override + public String toString() { + return "RelationViewWrapper{wrappedKey=%s}".formatted(wrappedKey); + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java index c612574f..986bb0b1 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java @@ -9,43 +9,43 @@ import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; -import tools.refinery.store.query.view.AnyRelationView; -import tools.refinery.store.query.view.RelationView; +import tools.refinery.store.query.view.AnySymbolView; +import tools.refinery.store.query.view.SymbolView; import java.util.HashMap; import java.util.Map; public class ModelUpdateListener { - private final Map> relationViewUpdateListeners; + private final Map> symbolViewUpdateListeners; public ModelUpdateListener(ViatraModelQueryAdapterImpl adapter) { - var relationViews = adapter.getStoreAdapter().getInputKeys().keySet(); - relationViewUpdateListeners = new HashMap<>(relationViews.size()); - for (var relationView : relationViews) { - registerView(adapter, (RelationView) relationView); + var symbolViews = adapter.getStoreAdapter().getInputKeys().keySet(); + symbolViewUpdateListeners = new HashMap<>(symbolViews.size()); + for (var symbolView : symbolViews) { + registerView(adapter, (SymbolView) symbolView); } } - private void registerView(ViatraModelQueryAdapterImpl adapter, RelationView relationView) { + private void registerView(ViatraModelQueryAdapterImpl adapter, SymbolView view) { var model = adapter.getModel(); - var interpretation = model.getInterpretation(relationView.getSymbol()); - var listener = RelationViewUpdateListener.of(adapter, relationView, interpretation); - relationViewUpdateListeners.put(relationView, listener); + var interpretation = model.getInterpretation(view.getSymbol()); + var listener = SymbolViewUpdateListener.of(adapter, view, interpretation); + symbolViewUpdateListeners.put(view, listener); } - public boolean containsRelationView(AnyRelationView relationView) { - return relationViewUpdateListeners.containsKey(relationView); + public boolean containsSymbolView(AnySymbolView relationView) { + return symbolViewUpdateListeners.containsKey(relationView); } - public void addListener(IInputKey key, AnyRelationView relationView, ITuple seed, + public void addListener(IInputKey key, AnySymbolView symbolView, ITuple seed, IQueryRuntimeContextListener listener) { - var relationViewUpdateListener = relationViewUpdateListeners.get(relationView); - relationViewUpdateListener.addFilter(key, seed, listener); + var symbolViewUpdateListener = symbolViewUpdateListeners.get(symbolView); + symbolViewUpdateListener.addFilter(key, seed, listener); } - public void removeListener(IInputKey key, AnyRelationView relationView, ITuple seed, + public void removeListener(IInputKey key, AnySymbolView symbolView, ITuple seed, IQueryRuntimeContextListener listener) { - var relationViewUpdateListener = relationViewUpdateListeners.get(relationView); - relationViewUpdateListener.removeFilter(key, seed, listener); + var symbolViewUpdateListener = symbolViewUpdateListeners.get(symbolView); + symbolViewUpdateListener.removeFilter(key, seed, listener); } } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java deleted file mode 100644 index 185e4ebc..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.viatra.internal.update; - -import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; -import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; -import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; -import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; -import tools.refinery.store.model.Interpretation; -import tools.refinery.store.model.InterpretationListener; -import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; -import tools.refinery.store.query.view.RelationView; -import tools.refinery.store.query.view.TuplePreservingRelationView; - -import java.util.ArrayList; -import java.util.List; - -public abstract class RelationViewUpdateListener implements InterpretationListener { - private final ViatraModelQueryAdapterImpl adapter; - private final Interpretation interpretation; - private final List filters = new ArrayList<>(); - - protected RelationViewUpdateListener(ViatraModelQueryAdapterImpl adapter, Interpretation interpretation) { - this.adapter = adapter; - this.interpretation = interpretation; - } - - public void addFilter(IInputKey inputKey, ITuple seed, IQueryRuntimeContextListener listener) { - if (filters.isEmpty()) { - // First filter to be added, from now on we have to subscribe to model updates. - interpretation.addListener(this, true); - } - filters.add(new RelationViewFilter(inputKey, seed, listener)); - } - - public void removeFilter(IInputKey inputKey, ITuple seed, IQueryRuntimeContextListener listener) { - if (filters.remove(new RelationViewFilter(inputKey, seed, listener)) && filters.isEmpty()) { - // Last listener to be added, we don't have be subscribed to model updates anymore. - interpretation.removeListener(this); - } - } - - protected void processUpdate(Tuple tuple, boolean isInsertion) { - adapter.markAsPending(); - int size = filters.size(); - // Use a for loop instead of a for-each loop to avoid Iterator allocation overhead. - //noinspection ForLoopReplaceableByForEach - for (int i = 0; i < size; i++) { - filters.get(i).update(tuple, isInsertion); - } - } - - public static RelationViewUpdateListener of(ViatraModelQueryAdapterImpl adapter, - RelationView relationView, - Interpretation interpretation) { - if (relationView instanceof TuplePreservingRelationView tuplePreservingRelationView) { - return new TuplePreservingRelationViewUpdateListener<>(adapter, tuplePreservingRelationView, - interpretation); - } - return new TupleChangingRelationViewUpdateListener<>(adapter, relationView, interpretation); - } -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/SymbolViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/SymbolViewUpdateListener.java new file mode 100644 index 00000000..f1a2ac7c --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/SymbolViewUpdateListener.java @@ -0,0 +1,65 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.viatra.internal.update; + +import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; +import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; +import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; +import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; +import tools.refinery.store.model.Interpretation; +import tools.refinery.store.model.InterpretationListener; +import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; +import tools.refinery.store.query.view.SymbolView; +import tools.refinery.store.query.view.TuplePreservingView; + +import java.util.ArrayList; +import java.util.List; + +public abstract class SymbolViewUpdateListener implements InterpretationListener { + private final ViatraModelQueryAdapterImpl adapter; + private final Interpretation interpretation; + private final List filters = new ArrayList<>(); + + protected SymbolViewUpdateListener(ViatraModelQueryAdapterImpl adapter, Interpretation interpretation) { + this.adapter = adapter; + this.interpretation = interpretation; + } + + public void addFilter(IInputKey inputKey, ITuple seed, IQueryRuntimeContextListener listener) { + if (filters.isEmpty()) { + // First filter to be added, from now on we have to subscribe to model updates. + interpretation.addListener(this, true); + } + filters.add(new RelationViewFilter(inputKey, seed, listener)); + } + + public void removeFilter(IInputKey inputKey, ITuple seed, IQueryRuntimeContextListener listener) { + if (filters.remove(new RelationViewFilter(inputKey, seed, listener)) && filters.isEmpty()) { + // Last listener to be added, we don't have be subscribed to model updates anymore. + interpretation.removeListener(this); + } + } + + protected void processUpdate(Tuple tuple, boolean isInsertion) { + adapter.markAsPending(); + int size = filters.size(); + // Use a for loop instead of a for-each loop to avoid Iterator allocation overhead. + //noinspection ForLoopReplaceableByForEach + for (int i = 0; i < size; i++) { + filters.get(i).update(tuple, isInsertion); + } + } + + public static SymbolViewUpdateListener of(ViatraModelQueryAdapterImpl adapter, + SymbolView view, + Interpretation interpretation) { + if (view instanceof TuplePreservingView tuplePreservingRelationView) { + return new TuplePreservingViewUpdateListener<>(adapter, tuplePreservingRelationView, + interpretation); + } + return new TupleChangingViewUpdateListener<>(adapter, view, interpretation); + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java deleted file mode 100644 index be4951af..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.viatra.internal.update; - -import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; -import tools.refinery.store.model.Interpretation; -import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; -import tools.refinery.store.query.view.RelationView; -import tools.refinery.store.tuple.Tuple; - -import java.util.Arrays; - -public class TupleChangingRelationViewUpdateListener extends RelationViewUpdateListener { - private final RelationView relationView; - - TupleChangingRelationViewUpdateListener(ViatraModelQueryAdapterImpl adapter, RelationView relationView, - Interpretation interpretation) { - super(adapter, interpretation); - this.relationView = relationView; - } - - @Override - public void put(Tuple key, T fromValue, T toValue, boolean restoring) { - boolean fromPresent = relationView.filter(key, fromValue); - boolean toPresent = relationView.filter(key, toValue); - if (fromPresent) { - if (toPresent) { // value change - var fromArray = relationView.forwardMap(key, fromValue); - var toArray = relationView.forwardMap(key, toValue); - if (!Arrays.equals(fromArray, toArray)) { - processUpdate(Tuples.flatTupleOf(fromArray), false); - processUpdate(Tuples.flatTupleOf(toArray), true); - } - } else { // fromValue disappears - processUpdate(Tuples.flatTupleOf(relationView.forwardMap(key, fromValue)), false); - } - } else if (toPresent) { // toValue appears - processUpdate(Tuples.flatTupleOf(relationView.forwardMap(key, toValue)), true); - } - } -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingViewUpdateListener.java new file mode 100644 index 00000000..45d35571 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingViewUpdateListener.java @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.viatra.internal.update; + +import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; +import tools.refinery.store.model.Interpretation; +import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; +import tools.refinery.store.query.view.SymbolView; +import tools.refinery.store.tuple.Tuple; + +import java.util.Arrays; + +public class TupleChangingViewUpdateListener extends SymbolViewUpdateListener { + private final SymbolView view; + + TupleChangingViewUpdateListener(ViatraModelQueryAdapterImpl adapter, SymbolView view, + Interpretation interpretation) { + super(adapter, interpretation); + this.view = view; + } + + @Override + public void put(Tuple key, T fromValue, T toValue, boolean restoring) { + boolean fromPresent = view.filter(key, fromValue); + boolean toPresent = view.filter(key, toValue); + if (fromPresent) { + if (toPresent) { // value change + var fromArray = view.forwardMap(key, fromValue); + var toArray = view.forwardMap(key, toValue); + if (!Arrays.equals(fromArray, toArray)) { + processUpdate(Tuples.flatTupleOf(fromArray), false); + processUpdate(Tuples.flatTupleOf(toArray), true); + } + } else { // fromValue disappears + processUpdate(Tuples.flatTupleOf(view.forwardMap(key, fromValue)), false); + } + } else if (toPresent) { // toValue appears + processUpdate(Tuples.flatTupleOf(view.forwardMap(key, toValue)), true); + } + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java deleted file mode 100644 index 9638266b..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.viatra.internal.update; - -import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; -import tools.refinery.store.model.Interpretation; -import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; -import tools.refinery.store.query.view.TuplePreservingRelationView; -import tools.refinery.store.tuple.Tuple; - -public class TuplePreservingRelationViewUpdateListener extends RelationViewUpdateListener { - private final TuplePreservingRelationView view; - - TuplePreservingRelationViewUpdateListener(ViatraModelQueryAdapterImpl adapter, - TuplePreservingRelationView view, Interpretation interpretation) { - super(adapter, interpretation); - this.view = view; - } - - @Override - public void put(Tuple key, T fromValue, T toValue, boolean restoring) { - boolean fromPresent = view.filter(key, fromValue); - boolean toPresent = view.filter(key, toValue); - if (fromPresent == toPresent) { - return; - } - var translated = Tuples.flatTupleOf(view.forwardMap(key)); - processUpdate(translated, toPresent); - } -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingViewUpdateListener.java new file mode 100644 index 00000000..c18dbafb --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingViewUpdateListener.java @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.viatra.internal.update; + +import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; +import tools.refinery.store.model.Interpretation; +import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; +import tools.refinery.store.query.view.TuplePreservingView; +import tools.refinery.store.tuple.Tuple; + +public class TuplePreservingViewUpdateListener extends SymbolViewUpdateListener { + private final TuplePreservingView view; + + TuplePreservingViewUpdateListener(ViatraModelQueryAdapterImpl adapter, TuplePreservingView view, + Interpretation interpretation) { + super(adapter, interpretation); + this.view = view; + } + + @Override + public void put(Tuple key, T fromValue, T toValue, boolean restoring) { + boolean fromPresent = view.filter(key, fromValue); + boolean toPresent = view.filter(key, toValue); + if (fromPresent == toPresent) { + return; + } + var translated = Tuples.flatTupleOf(view.forwardMap(key)); + processUpdate(translated, toPresent); + } +} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java index da4aba7f..5cffef71 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java @@ -12,8 +12,8 @@ import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.query.dnf.Query; import tools.refinery.store.query.term.Variable; import tools.refinery.store.query.viatra.tests.QueryEngineTest; -import tools.refinery.store.query.view.FunctionalRelationView; -import tools.refinery.store.query.view.KeyOnlyRelationView; +import tools.refinery.store.query.view.FunctionView; +import tools.refinery.store.query.view.KeyOnlyView; import tools.refinery.store.representation.Symbol; import tools.refinery.store.tuple.Tuple; @@ -30,8 +30,8 @@ class DiagonalQueryTest { void inputKeyNegationTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var symbol = new Symbol<>("symbol", 4, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); - var symbolView = new KeyOnlyRelationView<>(symbol); + var personView = new KeyOnlyView<>(person); + var symbolView = new KeyOnlyView<>(symbol); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -78,8 +78,8 @@ class DiagonalQueryTest { void subQueryNegationTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var symbol = new Symbol<>("symbol", 4, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); - var symbolView = new KeyOnlyRelationView<>(symbol); + var personView = new KeyOnlyView<>(person); + var symbolView = new KeyOnlyView<>(symbol); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -139,8 +139,8 @@ class DiagonalQueryTest { void inputKeyCountTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var symbol = new Symbol<>("symbol", 4, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); - var symbolView = new KeyOnlyRelationView<>(symbol); + var personView = new KeyOnlyView<>(person); + var symbolView = new KeyOnlyView<>(symbol); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -190,8 +190,8 @@ class DiagonalQueryTest { void subQueryCountTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var symbol = new Symbol<>("symbol", 4, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); - var symbolView = new KeyOnlyRelationView<>(symbol); + var personView = new KeyOnlyView<>(person); + var symbolView = new KeyOnlyView<>(symbol); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -254,8 +254,8 @@ class DiagonalQueryTest { void inputKeyAggregationTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var symbol = new Symbol<>("symbol", 4, Integer.class, null); - var personView = new KeyOnlyRelationView<>(person); - var symbolView = new FunctionalRelationView<>(symbol); + var personView = new KeyOnlyView<>(person); + var symbolView = new FunctionView<>(symbol); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -306,8 +306,8 @@ class DiagonalQueryTest { void subQueryAggregationTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var symbol = new Symbol<>("symbol", 4, Integer.class, null); - var personView = new KeyOnlyRelationView<>(person); - var symbolView = new FunctionalRelationView<>(symbol); + var personView = new KeyOnlyView<>(person); + var symbolView = new FunctionView<>(symbol); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -374,8 +374,8 @@ class DiagonalQueryTest { void inputKeyTransitiveTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var symbol = new Symbol<>("symbol", 2, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); - var symbolView = new KeyOnlyRelationView<>(symbol); + var personView = new KeyOnlyView<>(person); + var symbolView = new KeyOnlyView<>(symbol); var p1 = Variable.of("p1"); var query = Query.builder("Diagonal") @@ -420,8 +420,8 @@ class DiagonalQueryTest { void subQueryTransitiveTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var symbol = new Symbol<>("symbol", 2, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); - var symbolView = new KeyOnlyRelationView<>(symbol); + var personView = new KeyOnlyView<>(person); + var symbolView = new KeyOnlyView<>(symbol); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java index 3af67a50..19584273 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java @@ -13,9 +13,9 @@ import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.query.dnf.Query; import tools.refinery.store.query.term.Variable; import tools.refinery.store.query.viatra.tests.QueryEngineTest; -import tools.refinery.store.query.view.FilteredRelationView; -import tools.refinery.store.query.view.FunctionalRelationView; -import tools.refinery.store.query.view.KeyOnlyRelationView; +import tools.refinery.store.query.view.FilteredView; +import tools.refinery.store.query.view.FunctionView; +import tools.refinery.store.query.view.KeyOnlyView; import tools.refinery.store.representation.Symbol; import tools.refinery.store.representation.TruthValue; import tools.refinery.store.tuple.Tuple; @@ -38,8 +38,8 @@ class FunctionalQueryTest { void inputKeyTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var age = new Symbol<>("age", 1, Integer.class, null); - var personView = new KeyOnlyRelationView<>(person); - var ageView = new FunctionalRelationView<>(age); + var personView = new KeyOnlyView<>(person); + var ageView = new FunctionView<>(age); var p1 = Variable.of("p1"); var x = Variable.of("x", Integer.class); @@ -84,8 +84,8 @@ class FunctionalQueryTest { void predicateTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var age = new Symbol<>("age", 1, Integer.class, null); - var personView = new KeyOnlyRelationView<>(person); - var ageView = new FunctionalRelationView<>(age); + var personView = new KeyOnlyView<>(person); + var ageView = new FunctionView<>(age); var p1 = Variable.of("p1"); var x = Variable.of("x", Integer.class); @@ -137,8 +137,8 @@ class FunctionalQueryTest { void computationTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var age = new Symbol<>("age", 1, Integer.class, null); - var personView = new KeyOnlyRelationView<>(person); - var ageView = new FunctionalRelationView<>(age); + var personView = new KeyOnlyView<>(person); + var ageView = new FunctionView<>(age); var p1 = Variable.of("p1"); var x = Variable.of("x", Integer.class); @@ -184,8 +184,8 @@ class FunctionalQueryTest { void inputKeyCountTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); - var personView = new KeyOnlyRelationView<>(person); - var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); + var personView = new KeyOnlyView<>(person); + var friendMustView = new FilteredView<>(friend, "must", TruthValue::must); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -233,8 +233,8 @@ class FunctionalQueryTest { void predicateCountTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); - var personView = new KeyOnlyRelationView<>(person); - var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); + var personView = new KeyOnlyView<>(person); + var friendMustView = new FilteredView<>(friend, "must", TruthValue::must); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -289,7 +289,7 @@ class FunctionalQueryTest { @QueryEngineTest void inputKeyAggregationTest(QueryEvaluationHint hint) { var age = new Symbol<>("age", 1, Integer.class, null); - var ageView = new FunctionalRelationView<>(age); + var ageView = new FunctionView<>(age); var p1 = Variable.of("p1"); var x = Variable.of("x", Integer.class); @@ -324,8 +324,8 @@ class FunctionalQueryTest { void predicateAggregationTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var age = new Symbol<>("age", 1, Integer.class, null); - var personView = new KeyOnlyRelationView<>(person); - var ageView = new FunctionalRelationView<>(age); + var personView = new KeyOnlyView<>(person); + var ageView = new FunctionView<>(age); var p1 = Variable.of("p1"); var x = Variable.of("x", Integer.class); @@ -371,8 +371,8 @@ class FunctionalQueryTest { void extremeValueTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); - var personView = new KeyOnlyRelationView<>(person); - var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); + var personView = new KeyOnlyView<>(person); + var friendMustView = new FilteredView<>(friend, "must", TruthValue::must); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -447,8 +447,8 @@ class FunctionalQueryTest { void invalidComputationTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var age = new Symbol<>("age", 1, Integer.class, null); - var personView = new KeyOnlyRelationView<>(person); - var ageView = new FunctionalRelationView<>(age); + var personView = new KeyOnlyView<>(person); + var ageView = new FunctionView<>(age); var p1 = Variable.of("p1"); var x = Variable.of("x", Integer.class); @@ -494,8 +494,8 @@ class FunctionalQueryTest { void invalidAssumeTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var age = new Symbol<>("age", 1, Integer.class, null); - var personView = new KeyOnlyRelationView<>(person); - var ageView = new FunctionalRelationView<>(age); + var personView = new KeyOnlyView<>(person); + var ageView = new FunctionView<>(age); var p1 = Variable.of("p1"); var x = Variable.of("x", Integer.class); @@ -543,9 +543,9 @@ class FunctionalQueryTest { var person = new Symbol<>("Person", 1, Boolean.class, false); var age = new Symbol<>("age", 1, Integer.class, null); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); - var personView = new KeyOnlyRelationView<>(person); - var ageView = new FunctionalRelationView<>(age); - var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); + var personView = new KeyOnlyView<>(person); + var ageView = new FunctionView<>(age); + var friendMustView = new FilteredView<>(friend, "must", TruthValue::must); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); 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 e82f0a15..11ee98f5 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 @@ -13,9 +13,9 @@ import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.query.dnf.Query; import tools.refinery.store.query.term.Variable; import tools.refinery.store.query.viatra.tests.QueryEngineTest; -import tools.refinery.store.query.view.FilteredRelationView; -import tools.refinery.store.query.view.FunctionalRelationView; -import tools.refinery.store.query.view.KeyOnlyRelationView; +import tools.refinery.store.query.view.FilteredView; +import tools.refinery.store.query.view.FunctionView; +import tools.refinery.store.query.view.KeyOnlyView; import tools.refinery.store.representation.Symbol; import tools.refinery.store.representation.TruthValue; import tools.refinery.store.tuple.Tuple; @@ -34,7 +34,7 @@ class QueryTest { void typeConstraintTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var asset = new Symbol<>("Asset", 1, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); + var personView = new KeyOnlyView<>(person); var p1 = Variable.of("p1"); var predicate = Query.builder("TypeConstraint") @@ -73,8 +73,8 @@ class QueryTest { void relationConstraintTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); - var personView = new KeyOnlyRelationView<>(person); - var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); + var personView = new KeyOnlyView<>(person); + var friendMustView = new FilteredView<>(friend, "must", TruthValue::must); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -122,8 +122,8 @@ class QueryTest { void existTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); - var personView = new KeyOnlyRelationView<>(person); - var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); + var personView = new KeyOnlyView<>(person); + var friendMustView = new FilteredView<>(friend, "must", TruthValue::must); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -172,9 +172,9 @@ class QueryTest { var person = new Symbol<>("Person", 1, Boolean.class, false); var animal = new Symbol<>("Animal", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); - var personView = new KeyOnlyRelationView<>(person); - var animalView = new KeyOnlyRelationView<>(animal); - var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); + var personView = new KeyOnlyView<>(person); + var animalView = new KeyOnlyView<>(animal); + var friendMustView = new FilteredView<>(friend, "must", TruthValue::must); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -230,7 +230,7 @@ class QueryTest { @QueryEngineTest void equalityTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); + var personView = new KeyOnlyView<>(person); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -273,8 +273,8 @@ class QueryTest { void inequalityTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); - var personView = new KeyOnlyRelationView<>(person); - var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); + var personView = new KeyOnlyView<>(person); + var friendMustView = new FilteredView<>(friend, "must", TruthValue::must); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -322,8 +322,8 @@ class QueryTest { void patternCallTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); - var personView = new KeyOnlyRelationView<>(person); - var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); + var personView = new KeyOnlyView<>(person); + var friendMustView = new FilteredView<>(friend, "must", TruthValue::must); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -381,8 +381,8 @@ class QueryTest { void negativeRelationViewTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); - var personView = new KeyOnlyRelationView<>(person); - var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); + var personView = new KeyOnlyView<>(person); + var friendMustView = new FilteredView<>(friend, "must", TruthValue::must); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -435,8 +435,8 @@ class QueryTest { void negativePatternCallTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); - var personView = new KeyOnlyRelationView<>(person); - var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); + var personView = new KeyOnlyView<>(person); + var friendMustView = new FilteredView<>(friend, "must", TruthValue::must); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -500,8 +500,8 @@ class QueryTest { void negativeRelationViewWithQuantificationTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); - var personView = new KeyOnlyRelationView<>(person); - var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); + var personView = new KeyOnlyView<>(person); + var friendMustView = new FilteredView<>(friend, "must", TruthValue::must); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -547,8 +547,8 @@ class QueryTest { void negativeWithQuantificationTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); - var personView = new KeyOnlyRelationView<>(person); - var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); + var personView = new KeyOnlyView<>(person); + var friendMustView = new FilteredView<>(friend, "must", TruthValue::must); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -603,8 +603,8 @@ class QueryTest { void transitiveRelationViewTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); - var personView = new KeyOnlyRelationView<>(person); - var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); + var personView = new KeyOnlyView<>(person); + var friendMustView = new FilteredView<>(friend, "must", TruthValue::must); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -656,8 +656,8 @@ class QueryTest { void transitivePatternCallTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); - var personView = new KeyOnlyRelationView<>(person); - var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); + var personView = new KeyOnlyView<>(person); + var friendMustView = new FilteredView<>(friend, "must", TruthValue::must); var p1 = Variable.of("p1"); var p2 = Variable.of("p2"); @@ -720,8 +720,8 @@ class QueryTest { void assumeTest(QueryEvaluationHint hint) { var person = new Symbol<>("Person", 1, Boolean.class, false); var age = new Symbol<>("age", 1, Integer.class, null); - var personView = new KeyOnlyRelationView<>(person); - var ageView = new FunctionalRelationView<>(age); + var personView = new KeyOnlyView<>(person); + var ageView = new FunctionView<>(age); var p1 = Variable.of("p1"); var x = Variable.of("x", Integer.class); 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 07b799ac..bd6b6b81 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 @@ -12,9 +12,9 @@ import tools.refinery.store.model.ModelStore; import tools.refinery.store.query.ModelQuery; import tools.refinery.store.query.dnf.Query; import tools.refinery.store.query.term.Variable; -import tools.refinery.store.query.view.FilteredRelationView; -import tools.refinery.store.query.view.FunctionalRelationView; -import tools.refinery.store.query.view.KeyOnlyRelationView; +import tools.refinery.store.query.view.FilteredView; +import tools.refinery.store.query.view.FunctionView; +import tools.refinery.store.query.view.KeyOnlyView; import tools.refinery.store.representation.Symbol; import tools.refinery.store.tuple.Tuple; @@ -30,7 +30,7 @@ class QueryTransactionTest { @Test void flushTest() { var person = new Symbol<>("Person", 1, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); + var personView = new KeyOnlyView<>(person); var p1 = Variable.of("p1"); var predicate = Query.builder("TypeConstraint") @@ -101,7 +101,7 @@ class QueryTransactionTest { @Test void localSearchTest() { var person = new Symbol<>("Person", 1, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); + var personView = new KeyOnlyView<>(person); var p1 = Variable.of("p1"); var predicate = Query.builder("TypeConstraint") @@ -156,7 +156,7 @@ class QueryTransactionTest { void unrelatedChangesTest() { var person = new Symbol<>("Person", 1, Boolean.class, false); var asset = new Symbol<>("Asset", 1, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); + var personView = new KeyOnlyView<>(person); var p1 = Variable.of("p1"); var predicate = Query.builder("TypeConstraint") @@ -229,8 +229,8 @@ class QueryTransactionTest { void tupleChangingChangeTest() { var person = new Symbol<>("Person", 1, Boolean.class, false); var age = new Symbol<>("age", 1, Integer.class, null); - var personView = new KeyOnlyRelationView<>(person); - var ageView = new FunctionalRelationView<>(age); + var personView = new KeyOnlyView<>(person); + var ageView = new FunctionView<>(age); var p1 = Variable.of("p1"); var x = Variable.of("x", Integer.class); @@ -277,8 +277,8 @@ class QueryTransactionTest { void tuplePreservingUnchangedTest() { var person = new Symbol<>("Person", 1, Boolean.class, false); var age = new Symbol<>("age", 1, Integer.class, null); - var personView = new KeyOnlyRelationView<>(person); - var adultView = new FilteredRelationView<>(age, "adult", n -> n != null && n >= 18); + var personView = new KeyOnlyView<>(person); + var adultView = new FilteredView<>(age, "adult", n -> n != null && n >= 18); var p1 = Variable.of("p1"); var x = Variable.of("x", Integer.class); @@ -324,7 +324,7 @@ class QueryTransactionTest { @Test void commitAfterFlushTest() { var person = new Symbol<>("Person", 1, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); + var personView = new KeyOnlyView<>(person); var p1 = Variable.of("p1"); var predicate = Query.builder("TypeConstraint") @@ -382,7 +382,7 @@ class QueryTransactionTest { @Test void commitWithoutFlushTest() { var person = new Symbol<>("Person", 1, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); + var personView = new KeyOnlyView<>(person); var p1 = Variable.of("p1"); var predicate = Query.builder("TypeConstraint") diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java index 33318abc..f0a950a6 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java @@ -8,12 +8,12 @@ package tools.refinery.store.query; import tools.refinery.store.adapter.ModelStoreAdapter; import tools.refinery.store.model.Model; import tools.refinery.store.query.dnf.AnyQuery; -import tools.refinery.store.query.view.AnyRelationView; +import tools.refinery.store.query.view.AnySymbolView; import java.util.Collection; public interface ModelQueryStoreAdapter extends ModelStoreAdapter { - Collection getRelationViews(); + Collection getSymbolViews(); Collection getQueries(); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java new file mode 100644 index 00000000..c0aa35bf --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java @@ -0,0 +1,116 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.view; + +import tools.refinery.store.model.Model; +import tools.refinery.store.query.dnf.FunctionalDependency; +import tools.refinery.store.query.term.NodeSort; +import tools.refinery.store.query.term.Sort; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.tuple.Tuple; +import tools.refinery.store.tuple.Tuple1; + +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public abstract class AbstractFunctionView extends SymbolView { + private final T defaultValue; + + protected AbstractFunctionView(Symbol symbol, String name) { + super(symbol, name); + defaultValue = symbol.defaultValue(); + } + + @Override + public Set> getFunctionalDependencies() { + var arity = getSymbol().arity(); + var forEach = IntStream.range(0, arity).boxed().collect(Collectors.toUnmodifiableSet()); + var unique = Set.of(arity); + return Set.of(new FunctionalDependency<>(forEach, unique)); + } + + @Override + public Set getImpliedRelationViews() { + var symbol = getSymbol(); + var impliedIndices = IntStream.range(0, symbol.arity()).boxed().toList(); + var keysView = new KeyOnlyView<>(symbol); + return Set.of(new ViewImplication(this, keysView, impliedIndices)); + } + + @Override + public final boolean filter(Tuple key, T value) { + return !Objects.equals(defaultValue, value); + } + + protected abstract Sort getForwardMappedValueSort(); + + protected Object forwardMapValue(Tuple key, T value) { + return value; + } + + protected boolean valueEquals(Tuple key, T value, Object otherForwardMappedValue) { + return Objects.equals(otherForwardMappedValue, forwardMapValue(key, value)); + } + + @Override + public Object[] forwardMap(Tuple key, T value) { + int size = key.getSize(); + Object[] result = new Object[size + 1]; + for (int i = 0; i < size; i++) { + result[i] = Tuple.of(key.get(i)); + } + result[key.getSize()] = forwardMapValue(key, value); + return result; + } + + @Override + public boolean get(Model model, Object[] tuple) { + int[] content = new int[tuple.length - 1]; + for (int i = 0; i < tuple.length - 1; i++) { + if (!(tuple[i] instanceof Tuple1 wrapper)) { + return false; + } + content[i] = wrapper.value0(); + } + Tuple key = Tuple.of(content); + var valueInTuple = tuple[tuple.length - 1]; + T valueInMap = model.getInterpretation(getSymbol()).get(key); + return valueEquals(key, valueInMap, valueInTuple); + } + + @Override + public int arity() { + return getSymbol().arity() + 1; + } + + @Override + public List getSorts() { + var sorts = new Sort[arity()]; + int valueIndex = sorts.length - 1; + for (int i = 0; i < valueIndex; i++) { + sorts[i] = NodeSort.INSTANCE; + } + sorts[valueIndex] = getForwardMappedValueSort(); + return List.of(sorts); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + AbstractFunctionView that = (AbstractFunctionView) o; + return Objects.equals(defaultValue, that.defaultValue); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), defaultValue); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnyRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnyRelationView.java deleted file mode 100644 index 9aa923af..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnyRelationView.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.view; - -import tools.refinery.store.model.Model; -import tools.refinery.store.query.dnf.FunctionalDependency; -import tools.refinery.store.representation.AnySymbol; -import tools.refinery.store.query.Constraint; - -import java.util.Set; - -public sealed interface AnyRelationView extends Constraint permits RelationView { - AnySymbol getSymbol(); - - String getViewName(); - - default Set> getFunctionalDependencies() { - return Set.of(); - } - - default Set getImpliedRelationViews() { - return Set.of(); - } - - boolean get(Model model, Object[] tuple); - - Iterable getAll(Model model); -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnySymbolView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnySymbolView.java new file mode 100644 index 00000000..90b27ebb --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnySymbolView.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.view; + +import tools.refinery.store.model.Model; +import tools.refinery.store.query.dnf.FunctionalDependency; +import tools.refinery.store.representation.AnySymbol; +import tools.refinery.store.query.Constraint; + +import java.util.Set; + +public sealed interface AnySymbolView extends Constraint permits SymbolView { + AnySymbol getSymbol(); + + String getViewName(); + + default Set> getFunctionalDependencies() { + return Set.of(); + } + + default Set getImpliedRelationViews() { + return Set.of(); + } + + boolean get(Model model, Object[] tuple); + + Iterable getAll(Model model); +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java deleted file mode 100644 index 9717b2c1..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.view; - -import tools.refinery.store.tuple.Tuple; -import tools.refinery.store.representation.Symbol; - -import java.util.Objects; -import java.util.function.BiPredicate; -import java.util.function.Predicate; - -public class FilteredRelationView extends TuplePreservingRelationView { - private final BiPredicate predicate; - - public FilteredRelationView(Symbol symbol, String name, BiPredicate predicate) { - super(symbol, name); - this.predicate = predicate; - } - - public FilteredRelationView(Symbol symbol, BiPredicate predicate) { - super(symbol); - this.predicate = predicate; - } - - public FilteredRelationView(Symbol symbol, String name, Predicate predicate) { - this(symbol, name, (k, v) -> predicate.test(v)); - } - - public FilteredRelationView(Symbol symbol, Predicate predicate) { - this(symbol, (k, v) -> predicate.test(v)); - } - - @Override - public boolean filter(Tuple key, T value) { - return this.predicate.test(key, value); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - FilteredRelationView that = (FilteredRelationView) o; - return Objects.equals(predicate, that.predicate); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), predicate); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredView.java new file mode 100644 index 00000000..922c7355 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredView.java @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.view; + +import tools.refinery.store.tuple.Tuple; +import tools.refinery.store.representation.Symbol; + +import java.util.Objects; +import java.util.function.BiPredicate; +import java.util.function.Predicate; + +public class FilteredView extends TuplePreservingView { + private final BiPredicate predicate; + + public FilteredView(Symbol symbol, String name, BiPredicate predicate) { + super(symbol, name); + this.predicate = predicate; + } + + public FilteredView(Symbol symbol, BiPredicate predicate) { + super(symbol); + this.predicate = predicate; + } + + public FilteredView(Symbol symbol, String name, Predicate predicate) { + this(symbol, name, (k, v) -> predicate.test(v)); + } + + public FilteredView(Symbol symbol, Predicate predicate) { + this(symbol, (k, v) -> predicate.test(v)); + } + + @Override + public boolean filter(Tuple key, T value) { + return this.predicate.test(key, value); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + FilteredView that = (FilteredView) o; + return Objects.equals(predicate, that.predicate); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), predicate); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenRelationView.java deleted file mode 100644 index c19d9282..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenRelationView.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.view; - -import tools.refinery.store.representation.Symbol; -import tools.refinery.store.representation.TruthValue; -import tools.refinery.store.tuple.Tuple; - -public class ForbiddenRelationView extends TuplePreservingRelationView { - public ForbiddenRelationView(Symbol symbol) { - super(symbol, "forbidden"); - } - - @Override - public boolean filter(Tuple key, TruthValue value) { - return !value.may(); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenView.java new file mode 100644 index 00000000..26b717ee --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenView.java @@ -0,0 +1,21 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.view; + +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.representation.TruthValue; +import tools.refinery.store.tuple.Tuple; + +public class ForbiddenView extends TuplePreservingView { + public ForbiddenView(Symbol symbol) { + super(symbol, "forbidden"); + } + + @Override + public boolean filter(Tuple key, TruthValue value) { + return !value.may(); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java deleted file mode 100644 index ab48386e..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.view; - -import tools.refinery.store.model.Model; -import tools.refinery.store.query.dnf.FunctionalDependency; -import tools.refinery.store.query.term.DataSort; -import tools.refinery.store.query.term.NodeSort; -import tools.refinery.store.query.term.Sort; -import tools.refinery.store.representation.Symbol; -import tools.refinery.store.tuple.Tuple; -import tools.refinery.store.tuple.Tuple1; - -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -public final class FunctionalRelationView extends RelationView { - private final T defaultValue; - - public FunctionalRelationView(Symbol symbol, String name) { - super(symbol, name); - defaultValue = symbol.defaultValue(); - } - - public FunctionalRelationView(Symbol symbol) { - super(symbol); - defaultValue = symbol.defaultValue(); - } - - @Override - public Set> getFunctionalDependencies() { - var arity = getSymbol().arity(); - var forEach = IntStream.range(0, arity).boxed().collect(Collectors.toUnmodifiableSet()); - var unique = Set.of(arity); - return Set.of(new FunctionalDependency<>(forEach, unique)); - } - - @Override - public Set getImpliedRelationViews() { - var symbol = getSymbol(); - var impliedIndices = IntStream.range(0, symbol.arity()).boxed().toList(); - var keyOnlyRelationView = new KeyOnlyRelationView<>(symbol); - return Set.of(new RelationViewImplication(this, keyOnlyRelationView, impliedIndices)); - } - - @Override - public boolean filter(Tuple key, T value) { - return !Objects.equals(defaultValue, value); - } - - @Override - public Object[] forwardMap(Tuple key, T value) { - int size = key.getSize(); - Object[] result = new Object[size + 1]; - for (int i = 0; i < size; i++) { - result[i] = Tuple.of(key.get(i)); - } - result[key.getSize()] = value; - return result; - } - - @Override - public boolean get(Model model, Object[] tuple) { - int[] content = new int[tuple.length - 1]; - for (int i = 0; i < tuple.length - 1; i++) { - content[i] = ((Tuple1) tuple[i]).value0(); - } - Tuple key = Tuple.of(content); - @SuppressWarnings("unchecked") - T valueInTuple = (T) tuple[tuple.length - 1]; - T valueInMap = model.getInterpretation(getSymbol()).get(key); - return valueInTuple.equals(valueInMap); - } - - @Override - public int arity() { - return getSymbol().arity() + 1; - } - - @Override - public List getSorts() { - var sorts = new Sort[arity()]; - int valueIndex = sorts.length - 1; - for (int i = 0; i < valueIndex; i++) { - sorts[i] = NodeSort.INSTANCE; - } - sorts[valueIndex] = new DataSort<>(getSymbol().valueType()); - return List.of(sorts); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - FunctionalRelationView that = (FunctionalRelationView) o; - return Objects.equals(defaultValue, that.defaultValue); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), defaultValue); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java deleted file mode 100644 index 9553a0cc..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.view; - -import tools.refinery.store.representation.Symbol; -import tools.refinery.store.tuple.Tuple; - -import java.util.Objects; - -public final class KeyOnlyRelationView extends TuplePreservingRelationView { - public static final String VIEW_NAME = "key"; - - private final T defaultValue; - - public KeyOnlyRelationView(Symbol symbol) { - super(symbol, VIEW_NAME); - defaultValue = symbol.defaultValue(); - } - - @Override - public boolean filter(Tuple key, T value) { - return !Objects.equals(value, defaultValue); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - KeyOnlyRelationView that = (KeyOnlyRelationView) o; - return Objects.equals(defaultValue, that.defaultValue); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), defaultValue); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyView.java new file mode 100644 index 00000000..7e86f6e4 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyView.java @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.view; + +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.tuple.Tuple; + +import java.util.Objects; + +public final class KeyOnlyView extends TuplePreservingView { + public static final String VIEW_NAME = "key"; + + private final T defaultValue; + + public KeyOnlyView(Symbol symbol) { + super(symbol, VIEW_NAME); + defaultValue = symbol.defaultValue(); + } + + @Override + public boolean filter(Tuple key, T value) { + return !Objects.equals(value, defaultValue); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + KeyOnlyView that = (KeyOnlyView) o; + return Objects.equals(defaultValue, that.defaultValue); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), defaultValue); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayRelationView.java deleted file mode 100644 index 60325f35..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayRelationView.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.view; - -import tools.refinery.store.representation.Symbol; -import tools.refinery.store.representation.TruthValue; -import tools.refinery.store.tuple.Tuple; - -public class MayRelationView extends TuplePreservingRelationView { - public MayRelationView(Symbol symbol) { - super(symbol, "may"); - } - - @Override - public boolean filter(Tuple key, TruthValue value) { - return value.may(); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayView.java new file mode 100644 index 00000000..e75a8171 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayView.java @@ -0,0 +1,21 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.view; + +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.representation.TruthValue; +import tools.refinery.store.tuple.Tuple; + +public class MayView extends TuplePreservingView { + public MayView(Symbol symbol) { + super(symbol, "may"); + } + + @Override + public boolean filter(Tuple key, TruthValue value) { + return value.may(); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustRelationView.java deleted file mode 100644 index d7e7ae2e..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustRelationView.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.view; - -import tools.refinery.store.representation.Symbol; -import tools.refinery.store.representation.TruthValue; -import tools.refinery.store.tuple.Tuple; - -public class MustRelationView extends TuplePreservingRelationView { - public MustRelationView(Symbol symbol) { - super(symbol, "must"); - } - - @Override - public boolean filter(Tuple key, TruthValue value) { - return value.must(); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustView.java new file mode 100644 index 00000000..a48f8045 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustView.java @@ -0,0 +1,21 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.view; + +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.representation.TruthValue; +import tools.refinery.store.tuple.Tuple; + +public class MustView extends TuplePreservingView { + public MustView(Symbol symbol) { + super(symbol, "must"); + } + + @Override + public boolean filter(Tuple key, TruthValue value) { + return value.must(); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationView.java deleted file mode 100644 index fd4f47b4..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationView.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.view; - -import tools.refinery.store.map.CursorAsIterator; -import tools.refinery.store.model.Model; -import tools.refinery.store.representation.Symbol; -import tools.refinery.store.tuple.Tuple; - -import java.util.Objects; -import java.util.UUID; - -/** - * Represents a view of a {@link Symbol} that can be queried. - * - * @param - * @author Oszkar Semerath - */ -public abstract non-sealed class RelationView implements AnyRelationView { - private final Symbol symbol; - - private final String viewName; - - protected RelationView(Symbol symbol, String viewName) { - this.symbol = symbol; - this.viewName = viewName; - } - - protected RelationView(Symbol representation) { - this(representation, UUID.randomUUID().toString()); - } - - @Override - public Symbol getSymbol() { - return symbol; - } - - @Override - public String getViewName() { - return viewName; - } - - @Override - public String name() { - return symbol.name() + "#" + viewName; - } - - public abstract boolean filter(Tuple key, T value); - - public abstract Object[] forwardMap(Tuple key, T value); - - @Override - public Iterable getAll(Model model) { - return (() -> new CursorAsIterator<>(model.getInterpretation(symbol).getAll(), this::forwardMap, this::filter)); - } - - @Override - public String toString() { - return name(); - } - - @Override - public String toReferenceString() { - return "@RelationView(\"%s\") %s".formatted(viewName, symbol.name()); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - RelationView that = (RelationView) o; - return Objects.equals(symbol, that.symbol) && Objects.equals(viewName, that.viewName); - } - - @Override - public int hashCode() { - return Objects.hash(symbol, viewName); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationViewImplication.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationViewImplication.java deleted file mode 100644 index c54cce2f..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationViewImplication.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.view; - -import java.util.List; - -public record RelationViewImplication(AnyRelationView implyingRelationView, AnyRelationView impliedRelationView, - List impliedIndices) { - public RelationViewImplication { - if (impliedIndices.size() != impliedRelationView.arity()) { - throw new IllegalArgumentException("Expected %d implied indices for %s, but %d are provided" - .formatted(impliedRelationView.arity(), impliedRelationView, impliedIndices.size())); - } - for (var index : impliedIndices) { - if (impliedRelationView.invalidIndex(index)) { - throw new IllegalArgumentException("%d is not a valid index for %s".formatted(index, - implyingRelationView)); - } - } - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/SymbolView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/SymbolView.java new file mode 100644 index 00000000..267a99d3 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/SymbolView.java @@ -0,0 +1,82 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.view; + +import tools.refinery.store.map.CursorAsIterator; +import tools.refinery.store.model.Model; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.tuple.Tuple; + +import java.util.Objects; +import java.util.UUID; + +/** + * Represents a view of a {@link Symbol} that can be queried. + * + * @param + * @author Oszkar Semerath + */ +public abstract non-sealed class SymbolView implements AnySymbolView { + private final Symbol symbol; + + private final String viewName; + + protected SymbolView(Symbol symbol, String viewName) { + this.symbol = symbol; + this.viewName = viewName; + } + + protected SymbolView(Symbol representation) { + this(representation, UUID.randomUUID().toString()); + } + + @Override + public Symbol getSymbol() { + return symbol; + } + + @Override + public String getViewName() { + return viewName; + } + + @Override + public String name() { + return symbol.name() + "#" + viewName; + } + + public abstract boolean filter(Tuple key, T value); + + public abstract Object[] forwardMap(Tuple key, T value); + + @Override + public Iterable getAll(Model model) { + return (() -> new CursorAsIterator<>(model.getInterpretation(symbol).getAll(), this::forwardMap, this::filter)); + } + + @Override + public String toString() { + return name(); + } + + @Override + public String toReferenceString() { + return "@RelationView(\"%s\") %s".formatted(viewName, symbol.name()); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SymbolView that = (SymbolView) o; + return Objects.equals(symbol, that.symbol) && Objects.equals(viewName, that.viewName); + } + + @Override + public int hashCode() { + return Objects.hash(symbol, viewName); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java deleted file mode 100644 index e6e54aa1..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.view; - -import tools.refinery.store.model.Model; -import tools.refinery.store.query.term.NodeSort; -import tools.refinery.store.query.term.Sort; -import tools.refinery.store.tuple.Tuple; -import tools.refinery.store.tuple.Tuple1; -import tools.refinery.store.representation.Symbol; - -import java.util.Arrays; -import java.util.List; - -public abstract class TuplePreservingRelationView extends RelationView { - protected TuplePreservingRelationView(Symbol symbol, String name) { - super(symbol, name); - } - - protected TuplePreservingRelationView(Symbol symbol) { - super(symbol); - } - - public Object[] forwardMap(Tuple key) { - Object[] result = new Object[key.getSize()]; - for (int i = 0; i < key.getSize(); i++) { - result[i] = Tuple.of(key.get(i)); - } - return result; - } - - @Override - public Object[] forwardMap(Tuple key, T value) { - return forwardMap(key); - } - - @Override - public boolean get(Model model, Object[] tuple) { - int[] content = new int[tuple.length]; - for (int i = 0; i < tuple.length; i++) { - content[i] = ((Tuple1) tuple[i]).value0(); - } - Tuple key = Tuple.of(content); - T value = model.getInterpretation(getSymbol()).get(key); - return filter(key, value); - } - - @Override - public int arity() { - return this.getSymbol().arity(); - } - - @Override - public List getSorts() { - var sorts = new Sort[arity()]; - Arrays.fill(sorts, NodeSort.INSTANCE); - return List.of(sorts); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingView.java new file mode 100644 index 00000000..19862e3a --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingView.java @@ -0,0 +1,65 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.view; + +import tools.refinery.store.model.Model; +import tools.refinery.store.query.term.NodeSort; +import tools.refinery.store.query.term.Sort; +import tools.refinery.store.tuple.Tuple; +import tools.refinery.store.tuple.Tuple1; +import tools.refinery.store.representation.Symbol; + +import java.util.Arrays; +import java.util.List; + +public abstract class TuplePreservingView extends SymbolView { + protected TuplePreservingView(Symbol symbol, String name) { + super(symbol, name); + } + + protected TuplePreservingView(Symbol symbol) { + super(symbol); + } + + public Object[] forwardMap(Tuple key) { + Object[] result = new Object[key.getSize()]; + for (int i = 0; i < key.getSize(); i++) { + result[i] = Tuple.of(key.get(i)); + } + return result; + } + + @Override + public Object[] forwardMap(Tuple key, T value) { + return forwardMap(key); + } + + @Override + public boolean get(Model model, Object[] tuple) { + int[] content = new int[tuple.length]; + for (int i = 0; i < tuple.length; i++) { + if (!(tuple[i] instanceof Tuple1 wrapper)) { + return false; + } + content[i] = wrapper.value0(); + } + Tuple key = Tuple.of(content); + T value = model.getInterpretation(getSymbol()).get(key); + return filter(key, value); + } + + @Override + public int arity() { + return this.getSymbol().arity(); + } + + @Override + public List getSorts() { + var sorts = new Sort[arity()]; + Arrays.fill(sorts, NodeSort.INSTANCE); + return List.of(sorts); + } +} diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java index 70cd386b..152840f8 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java @@ -9,7 +9,7 @@ import org.junit.jupiter.api.Test; import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.query.literal.BooleanLiteral; import tools.refinery.store.query.term.Variable; -import tools.refinery.store.query.view.KeyOnlyRelationView; +import tools.refinery.store.query.view.KeyOnlyView; import tools.refinery.store.representation.Symbol; import static org.hamcrest.MatcherAssert.assertThat; @@ -22,7 +22,7 @@ class DnfBuilderTest { var p = Variable.of("p"); var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); + var friendView = new KeyOnlyView<>(friend); var actual = Dnf.builder() .parameters(p, q) @@ -38,7 +38,7 @@ class DnfBuilderTest { var p = Variable.of("p"); var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); + var friendView = new KeyOnlyView<>(friend); var actual = Dnf.builder() .parameters(p, q) @@ -55,7 +55,7 @@ class DnfBuilderTest { var p = Variable.of("p"); var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); + var friendView = new KeyOnlyView<>(friend); var actual = Dnf.builder() .parameters(p, q) @@ -72,7 +72,7 @@ class DnfBuilderTest { var p = Variable.of("p"); var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); + var friendView = new KeyOnlyView<>(friend); var actual = Dnf.builder() .parameters(p, q) @@ -88,7 +88,7 @@ class DnfBuilderTest { var p = Variable.of("p"); var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); + var friendView = new KeyOnlyView<>(friend); var trueDnf = Dnf.builder().parameter(p).clause().build(); var actual = Dnf.builder() @@ -105,7 +105,7 @@ class DnfBuilderTest { var p = Variable.of("p"); var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); + var friendView = new KeyOnlyView<>(friend); var falseDnf = Dnf.builder().parameter(p).build(); var actual = Dnf.builder() @@ -123,7 +123,7 @@ class DnfBuilderTest { var p = Variable.of("p"); var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); + var friendView = new KeyOnlyView<>(friend); var trueDnf = Dnf.builder().parameter(p).clause().build(); var actual = Dnf.builder() @@ -141,7 +141,7 @@ class DnfBuilderTest { var p = Variable.of("p"); var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); + var friendView = new KeyOnlyView<>(friend); var falseDnf = Dnf.builder().parameter(p).build(); var actual = Dnf.builder() @@ -158,7 +158,7 @@ class DnfBuilderTest { var p = Variable.of("p"); var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); + var friendView = new KeyOnlyView<>(friend); var falseDnf = Dnf.builder().parameter(p).build(); var actual = Dnf.builder() @@ -175,7 +175,7 @@ class DnfBuilderTest { var p = Variable.of("p"); var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); + var friendView = new KeyOnlyView<>(friend); var trueDnf = Dnf.builder().parameter(p).clause().build(); var actual = Dnf.builder() @@ -193,7 +193,7 @@ class DnfBuilderTest { var p = Variable.of("p"); var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); + var friendView = new KeyOnlyView<>(friend); var falseDnf = Dnf.builder().parameter(p).build(); var actual = Dnf.builder() @@ -211,7 +211,7 @@ class DnfBuilderTest { var p = Variable.of("p"); var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); + var friendView = new KeyOnlyView<>(friend); var trueDnf = Dnf.builder().parameter(p).clause().build(); var actual = Dnf.builder() diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToDefinitionStringTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToDefinitionStringTest.java index 7be57745..e89ab682 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToDefinitionStringTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToDefinitionStringTest.java @@ -8,7 +8,7 @@ package tools.refinery.store.query; import org.junit.jupiter.api.Test; import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.query.term.Variable; -import tools.refinery.store.query.view.KeyOnlyRelationView; +import tools.refinery.store.query.view.KeyOnlyView; import tools.refinery.store.representation.Symbol; import static org.hamcrest.MatcherAssert.assertThat; @@ -53,7 +53,7 @@ class DnfToDefinitionStringTest { var p = Variable.of("p"); var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); + var friendView = new KeyOnlyView<>(friend); var dnf = Dnf.builder("Example").parameter(p).clause(friendView.call(p, q)).build(); assertThat(dnf.toDefinitionString(), is(""" @@ -67,7 +67,7 @@ class DnfToDefinitionStringTest { var p = Variable.of("p"); var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); + var friendView = new KeyOnlyView<>(friend); var dnf = Dnf.builder("Example").parameter(p).clause(not(friendView.call(p, q))).build(); assertThat(dnf.toDefinitionString(), is(""" @@ -81,7 +81,7 @@ class DnfToDefinitionStringTest { var p = Variable.of("p"); var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); + var friendView = new KeyOnlyView<>(friend); var dnf = Dnf.builder("Example").parameter(p).clause(friendView.callTransitive(p, q)).build(); assertThat(dnf.toDefinitionString(), is(""" @@ -95,7 +95,7 @@ class DnfToDefinitionStringTest { var p = Variable.of("p"); var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); + var friendView = new KeyOnlyView<>(friend); var dnf = Dnf.builder("Example").parameters(p, q).clause(friendView.call(p, q)).build(); assertThat(dnf.toDefinitionString(), is(""" @@ -109,9 +109,9 @@ class DnfToDefinitionStringTest { var p = Variable.of("p"); var q = Variable.of("q"); var person = new Symbol<>("person", 1, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); + var personView = new KeyOnlyView<>(person); var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); + var friendView = new KeyOnlyView<>(friend); var dnf = Dnf.builder("Example") .parameter(p) .clause( @@ -134,7 +134,7 @@ class DnfToDefinitionStringTest { var p = Variable.of("p"); var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); + var friendView = new KeyOnlyView<>(friend); var dnf = Dnf.builder("Example") .parameter(p) .clause(friendView.call(p, q)) @@ -156,9 +156,9 @@ class DnfToDefinitionStringTest { var r = Variable.of("r"); var s = Variable.of("s"); var person = new Symbol<>("person", 1, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); + var personView = new KeyOnlyView<>(person); var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyRelationView<>(friend); + var friendView = new KeyOnlyView<>(friend); var called = Dnf.builder("Called").parameters(r, s).clause(friendView.call(r, s)).build(); var dnf = Dnf.builder("Example") .parameter(p) diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java index e292b3ab..a1407288 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java @@ -8,7 +8,7 @@ package tools.refinery.store.query.tests; import org.junit.jupiter.api.Test; import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.query.term.Variable; -import tools.refinery.store.query.view.KeyOnlyRelationView; +import tools.refinery.store.query.view.KeyOnlyView; import tools.refinery.store.representation.Symbol; import static org.hamcrest.CoreMatchers.containsString; @@ -22,7 +22,7 @@ class StructurallyEqualToTest { var p = Variable.of("p"); var q = Variable.of("q"); var person = new Symbol<>("Person", 1, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); + var personView = new KeyOnlyView<>(person); var expected = Dnf.builder("Expected").parameters(q).clause(personView.call(q)).build(); var actual = Dnf.builder("Actual").parameters(p).clause(personView.call(p)).build(); @@ -35,7 +35,7 @@ class StructurallyEqualToTest { var p = Variable.of("p"); var q = Variable.of("q"); var person = new Symbol<>("Person", 1, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); + var personView = new KeyOnlyView<>(person); var expected = Dnf.builder("Expected").parameters(q).clause(personView.call(q)).build(); var actual = Dnf.builder("Actual").parameters(p).clause(personView.call(q)).build(); @@ -49,7 +49,7 @@ class StructurallyEqualToTest { var p = Variable.of("p"); var q = Variable.of("q"); var person = new Symbol<>("Person", 1, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); + var personView = new KeyOnlyView<>(person); var expected = Dnf.builder("Expected").parameters(q).clause( Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build().call(q) @@ -66,7 +66,7 @@ class StructurallyEqualToTest { var p = Variable.of("p"); var q = Variable.of("q"); var person = new Symbol<>("Person", 1, Boolean.class, false); - var personView = new KeyOnlyRelationView<>(person); + var personView = new KeyOnlyView<>(person); var expected = Dnf.builder("Expected").parameters(q).clause( Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build().call(q) diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeRelationView.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeRelationView.java deleted file mode 100644 index aea0a4b9..00000000 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeRelationView.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.reasoning.translator.typehierarchy; - -import tools.refinery.store.reasoning.representation.PartialRelation; -import tools.refinery.store.query.view.TuplePreservingRelationView; -import tools.refinery.store.tuple.Tuple; - -class InferredMayTypeRelationView extends TuplePreservingRelationView { - private final PartialRelation type; - - InferredMayTypeRelationView(PartialRelation type) { - super(TypeHierarchyTranslationUnit.INFERRED_TYPE_SYMBOL, "%s#may".formatted(type)); - this.type = type; - } - - @Override - public boolean filter(Tuple key, InferredType value) { - return value.mayConcreteTypes().contains(type); - } -} diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeView.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeView.java new file mode 100644 index 00000000..ce2d6ff3 --- /dev/null +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeView.java @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.reasoning.translator.typehierarchy; + +import tools.refinery.store.reasoning.representation.PartialRelation; +import tools.refinery.store.query.view.TuplePreservingView; +import tools.refinery.store.tuple.Tuple; + +class InferredMayTypeView extends TuplePreservingView { + private final PartialRelation type; + + InferredMayTypeView(PartialRelation type) { + super(TypeHierarchyTranslationUnit.INFERRED_TYPE_SYMBOL, "%s#may".formatted(type)); + this.type = type; + } + + @Override + public boolean filter(Tuple key, InferredType value) { + return value.mayConcreteTypes().contains(type); + } +} diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeRelationView.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeRelationView.java deleted file mode 100644 index 6c995e3a..00000000 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeRelationView.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.reasoning.translator.typehierarchy; - -import tools.refinery.store.reasoning.representation.PartialRelation; -import tools.refinery.store.query.view.TuplePreservingRelationView; -import tools.refinery.store.tuple.Tuple; - -class InferredMustTypeRelationView extends TuplePreservingRelationView { - private final PartialRelation type; - - InferredMustTypeRelationView(PartialRelation type) { - super(TypeHierarchyTranslationUnit.INFERRED_TYPE_SYMBOL, "%s#must".formatted(type)); - this.type = type; - } - - @Override - public boolean filter(Tuple key, InferredType value) { - return value.mustTypes().contains(type); - } -} diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeView.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeView.java new file mode 100644 index 00000000..beda1796 --- /dev/null +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeView.java @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.reasoning.translator.typehierarchy; + +import tools.refinery.store.reasoning.representation.PartialRelation; +import tools.refinery.store.query.view.TuplePreservingView; +import tools.refinery.store.tuple.Tuple; + +class InferredMustTypeView extends TuplePreservingView { + private final PartialRelation type; + + InferredMustTypeView(PartialRelation type) { + super(TypeHierarchyTranslationUnit.INFERRED_TYPE_SYMBOL, "%s#must".formatted(type)); + this.type = type; + } + + @Override + public boolean filter(Tuple key, InferredType value) { + return value.mustTypes().contains(type); + } +} -- cgit v1.2.3-70-g09d2 From ea0f09096afe05e2d414c707584e1e33c0c44383 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Fri, 21 Apr 2023 02:12:04 +0200 Subject: refactor: simplify ModelAdapter * Remove the reflection-based machinery around adapter types. * Adapter builders, store adapters, and model adapters are now only associated with each other based on static and runtime types. * Simplifies writing new adapters. * Hierarchical syntax for adding adapter builders to the store builder. --- .../store/query/viatra/ViatraModelQuery.java | 26 ----- .../query/viatra/ViatraModelQueryAdapter.java | 5 + .../query/viatra/ViatraModelQueryBuilder.java | 2 +- .../internal/ViatraModelQueryBuilderImpl.java | 22 +++- .../store/query/viatra/DiagonalQueryTest.java | 66 +++++------ .../store/query/viatra/FunctionalQueryTest.java | 90 +++++++-------- .../refinery/store/query/viatra/QueryTest.java | 123 ++++++++++----------- .../store/query/viatra/QueryTransactionTest.java | 46 ++++---- .../tools/refinery/store/query/ModelQuery.java | 16 --- .../refinery/store/query/ModelQueryBuilder.java | 2 +- .../tools/refinery/store/reasoning/Reasoning.java | 29 ----- .../refinery/store/reasoning/ReasoningAdapter.java | 9 +- .../refinery/store/reasoning/ReasoningBuilder.java | 2 +- .../reasoning/internal/ReasoningAdapterImpl.java | 2 +- .../reasoning/internal/ReasoningBuilderImpl.java | 13 +-- .../store/reasoning/lifting/DnfLifter.java | 8 +- .../reasoning/rule/RelationRefinementAction.java | 4 +- .../reasoning/translator/TranslationUnit.java | 5 - .../base/BaseDecisionTranslationUnit.java | 5 - .../store/adapter/AbstractModelAdapterBuilder.java | 42 ++++--- .../tools/refinery/store/adapter/AdapterList.java | 102 ----------------- .../tools/refinery/store/adapter/AdapterUtils.java | 33 ++++++ .../store/adapter/AnyModelAdapterType.java | 24 ---- .../store/adapter/ModelAdapterBuilder.java | 11 +- .../store/adapter/ModelAdapterBuilderFactory.java | 19 ---- .../refinery/store/adapter/ModelAdapterType.java | 84 -------------- .../java/tools/refinery/store/model/Model.java | 5 +- .../tools/refinery/store/model/ModelStore.java | 5 +- .../refinery/store/model/ModelStoreBuilder.java | 8 +- .../refinery/store/model/internal/ModelImpl.java | 20 ++-- .../model/internal/ModelStoreBuilderImpl.java | 59 +++------- .../store/model/internal/ModelStoreImpl.java | 26 ++--- 32 files changed, 316 insertions(+), 597 deletions(-) delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQuery.java delete mode 100644 subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/Reasoning.java delete mode 100644 subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java create mode 100644 subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterUtils.java delete mode 100644 subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java delete mode 100644 subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java delete mode 100644 subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java (limited to 'subprojects/store-query-viatra/src/main/java/tools') diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java deleted file mode 100644 index 3fff6f2e..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.viatra; - -import tools.refinery.store.adapter.ModelAdapterBuilderFactory; -import tools.refinery.store.model.ModelStoreBuilder; -import tools.refinery.store.query.ModelQuery; -import tools.refinery.store.query.viatra.internal.ViatraModelQueryBuilderImpl; - -public final class ViatraModelQuery extends ModelAdapterBuilderFactory { - public static final ViatraModelQuery ADAPTER = new ViatraModelQuery(); - - private ViatraModelQuery() { - super(ViatraModelQueryAdapter.class, ViatraModelQueryStoreAdapter.class, ViatraModelQueryBuilder.class); - extendsAdapter(ModelQuery.ADAPTER); - } - - @Override - public ViatraModelQueryBuilder createBuilder(ModelStoreBuilder storeBuilder) { - return new ViatraModelQueryBuilderImpl(storeBuilder); - } -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryAdapter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryAdapter.java index 411e251e..12c93f62 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryAdapter.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryAdapter.java @@ -6,8 +6,13 @@ package tools.refinery.store.query.viatra; import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.viatra.internal.ViatraModelQueryBuilderImpl; public interface ViatraModelQueryAdapter extends ModelQueryAdapter { @Override ViatraModelQueryStoreAdapter getStoreAdapter(); + + static ViatraModelQueryBuilder builder() { + return new ViatraModelQueryBuilderImpl(); + } } 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 310171e8..931a07aa 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 @@ -50,5 +50,5 @@ public interface ViatraModelQueryBuilder extends ModelQueryBuilder { ViatraModelQueryBuilder hint(Dnf dnf, QueryEvaluationHint queryEvaluationHint); @Override - ViatraModelQueryStoreAdapter createStoreAdapter(ModelStore store); + ViatraModelQueryStoreAdapter build(ModelStore store); } 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 44ed1505..ce2467b4 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 @@ -25,7 +25,8 @@ import tools.refinery.store.query.viatra.internal.pquery.Dnf2PQuery; import java.util.*; import java.util.function.Function; -public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder implements ViatraModelQueryBuilder { +public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder + implements ViatraModelQueryBuilder { private ViatraQueryEngineOptions.Builder engineOptionsBuilder; private QueryEvaluationHint defaultHint = new QueryEvaluationHint(Map.of( // Use a cost function that ignores the initial (empty) model but allows higher arity input keys. @@ -35,8 +36,7 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp private final Set vacuousQueries = new LinkedHashSet<>(); private final Map> querySpecifications = new LinkedHashMap<>(); - public ViatraModelQueryBuilderImpl(ModelStoreBuilder storeBuilder) { - super(storeBuilder); + public ViatraModelQueryBuilderImpl() { engineOptionsBuilder = new ViatraQueryEngineOptions.Builder() .withDefaultBackend(ReteBackendFactory.INSTANCE) .withDefaultCachingBackend(ReteBackendFactory.INSTANCE) @@ -45,36 +45,42 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp @Override public ViatraModelQueryBuilder engineOptions(ViatraQueryEngineOptions engineOptions) { + checkNotConfigured(); engineOptionsBuilder = new ViatraQueryEngineOptions.Builder(engineOptions); return this; } @Override public ViatraModelQueryBuilder defaultHint(QueryEvaluationHint queryEvaluationHint) { + checkNotConfigured(); defaultHint = defaultHint.overrideBy(queryEvaluationHint); return this; } @Override public ViatraModelQueryBuilder backend(IQueryBackendFactory queryBackendFactory) { + checkNotConfigured(); engineOptionsBuilder.withDefaultBackend(queryBackendFactory); return this; } @Override public ViatraModelQueryBuilder cachingBackend(IQueryBackendFactory queryBackendFactory) { + checkNotConfigured(); engineOptionsBuilder.withDefaultCachingBackend(queryBackendFactory); return this; } @Override public ViatraModelQueryBuilder searchBackend(IQueryBackendFactory queryBackendFactory) { + checkNotConfigured(); engineOptionsBuilder.withDefaultSearchBackend(queryBackendFactory); return this; } @Override public ViatraModelQueryBuilder query(AnyQuery query) { + checkNotConfigured(); if (querySpecifications.containsKey(query) || vacuousQueries.contains(query)) { // Ignore duplicate queries. return this; @@ -103,20 +109,26 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp @Override public ViatraModelQueryBuilder computeHint(Function computeHint) { + checkNotConfigured(); dnf2PQuery.setComputeHint(computeHint); return this; } @Override public ViatraModelQueryBuilder hint(Dnf dnf, QueryEvaluationHint queryEvaluationHint) { + checkNotConfigured(); dnf2PQuery.hint(dnf, queryEvaluationHint); return this; } @Override - public ViatraModelQueryStoreAdapterImpl createStoreAdapter(ModelStore store) { - validateSymbols(store); + public void doConfigure(ModelStoreBuilder storeBuilder) { dnf2PQuery.assertNoUnusedHints(); + } + + @Override + public ViatraModelQueryStoreAdapterImpl doBuild(ModelStore store) { + validateSymbols(store); return new ViatraModelQueryStoreAdapterImpl(store, buildEngineOptions(), dnf2PQuery.getSymbolViews(), Collections.unmodifiableMap(querySpecifications), Collections.unmodifiableSet(vacuousQueries)); } diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java index 3ff01064..56ddb9b4 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java @@ -7,7 +7,7 @@ package tools.refinery.store.query.viatra; import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; import tools.refinery.store.model.ModelStore; -import tools.refinery.store.query.ModelQuery; +import tools.refinery.store.query.ModelQueryAdapter; import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.query.dnf.Query; import tools.refinery.store.query.viatra.tests.QueryEngineTest; @@ -40,15 +40,15 @@ class DiagonalQueryTest { var store = ModelStore.builder() .symbols(person, symbol) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(query) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var symbolInterpretation = model.getInterpretation(symbol); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); @@ -97,15 +97,15 @@ class DiagonalQueryTest { var store = ModelStore.builder() .symbols(person, symbol) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(query) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var symbolInterpretation = model.getInterpretation(symbol); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); @@ -140,15 +140,15 @@ class DiagonalQueryTest { var store = ModelStore.builder() .symbols(person, symbol) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(query) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var symbolInterpretation = model.getInterpretation(symbol); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); @@ -198,15 +198,15 @@ class DiagonalQueryTest { var store = ModelStore.builder() .symbols(person, symbol) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(query) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var symbolInterpretation = model.getInterpretation(symbol); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); @@ -243,15 +243,15 @@ class DiagonalQueryTest { var store = ModelStore.builder() .symbols(person, symbol) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(query) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var symbolInterpretation = model.getInterpretation(symbol); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); @@ -306,15 +306,15 @@ class DiagonalQueryTest { var store = ModelStore.builder() .symbols(person, symbol) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(query) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var symbolInterpretation = model.getInterpretation(symbol); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); @@ -350,15 +350,15 @@ class DiagonalQueryTest { var store = ModelStore.builder() .symbols(person, symbol) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(query) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var symbolInterpretation = model.getInterpretation(symbol); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); @@ -404,15 +404,15 @@ class DiagonalQueryTest { var store = ModelStore.builder() .symbols(person, symbol) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(query) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var symbolInterpretation = model.getInterpretation(symbol); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java index ffa5e60b..98c8cd92 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java @@ -8,7 +8,7 @@ package tools.refinery.store.query.viatra; import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; import tools.refinery.store.map.Cursor; import tools.refinery.store.model.ModelStore; -import tools.refinery.store.query.ModelQuery; +import tools.refinery.store.query.ModelQueryAdapter; import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.query.dnf.Query; import tools.refinery.store.query.term.Variable; @@ -49,15 +49,15 @@ class FunctionalQueryTest { var store = ModelStore.builder() .symbols(person, age) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(query) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var ageInterpretation = model.getInterpretation(age); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); @@ -97,15 +97,15 @@ class FunctionalQueryTest { var store = ModelStore.builder() .symbols(person, age) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(query) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var ageInterpretation = model.getInterpretation(age); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); @@ -141,15 +141,15 @@ class FunctionalQueryTest { var store = ModelStore.builder() .symbols(person, age) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(query) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var ageInterpretation = model.getInterpretation(age); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); @@ -180,15 +180,15 @@ class FunctionalQueryTest { var store = ModelStore.builder() .symbols(person, friend) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(query) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); @@ -231,15 +231,15 @@ class FunctionalQueryTest { var store = ModelStore.builder() .symbols(person, friend) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(query) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); @@ -269,14 +269,14 @@ class FunctionalQueryTest { var store = ModelStore.builder() .symbols(age) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(query) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(query)) .build(); var model = store.createEmptyModel(); var ageInterpretation = model.getInterpretation(age); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); ageInterpretation.put(Tuple.of(0), 12); @@ -306,15 +306,15 @@ class FunctionalQueryTest { var store = ModelStore.builder() .symbols(person, age) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(query) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var ageInterpretation = model.getInterpretation(age); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); @@ -349,15 +349,15 @@ class FunctionalQueryTest { var store = ModelStore.builder() .symbols(person, friend) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(minQuery, maxQuery) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(minQuery, maxQuery)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var minResultSet = queryEngine.getResultSet(minQuery); var maxResultSet = queryEngine.getResultSet(maxQuery); @@ -408,15 +408,15 @@ class FunctionalQueryTest { var store = ModelStore.builder() .symbols(person, age) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(query) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var ageInterpretation = model.getInterpretation(age); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); @@ -448,15 +448,15 @@ class FunctionalQueryTest { var store = ModelStore.builder() .symbols(person, age) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(query) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var ageInterpretation = model.getInterpretation(age); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); @@ -493,16 +493,16 @@ class FunctionalQueryTest { var store = ModelStore.builder() .symbols(person, age, friend) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .query(query) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var ageInterpretation = model.getInterpretation(age); var friendInterpretation = model.getInterpretation(friend); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); 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 a90889c6..46ce37b4 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 @@ -8,7 +8,7 @@ package tools.refinery.store.query.viatra; import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; import org.junit.jupiter.api.Test; import tools.refinery.store.model.ModelStore; -import tools.refinery.store.query.ModelQuery; +import tools.refinery.store.query.ModelQueryAdapter; import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.query.dnf.Query; import tools.refinery.store.query.term.Variable; @@ -41,15 +41,15 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, asset) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .query(predicate) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var assetInterpretation = model.getInterpretation(asset); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); @@ -81,15 +81,15 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(predicate) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); @@ -125,15 +125,15 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(predicate) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); @@ -175,16 +175,16 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, animal, friend) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(predicate) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var animalInterpretation = model.getInterpretation(animal); var friendInterpretation = model.getInterpretation(friend); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); @@ -221,14 +221,14 @@ class QueryTest { var store = ModelStore.builder() .symbols(person) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(predicate) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); @@ -262,15 +262,15 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(predicate) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); @@ -312,15 +312,15 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(predicate) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); @@ -355,15 +355,15 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(predicate) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); @@ -413,15 +413,15 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(predicate) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); @@ -461,15 +461,15 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(predicate) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); @@ -511,15 +511,15 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(predicate) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); @@ -553,15 +553,15 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(predicate) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); @@ -610,15 +610,15 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, friend) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(predicate) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var friendInterpretation = model.getInterpretation(friend); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); @@ -658,15 +658,15 @@ class QueryTest { var store = ModelStore.builder() .symbols(person, age) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(hint) - .queries(query) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(hint) + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var ageInterpretation = model.getInterpretation(age); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); @@ -691,13 +691,13 @@ class QueryTest { var store = ModelStore.builder() .symbols(person) - .with(ViatraModelQuery.ADAPTER) - .queries(predicate) + .with(ViatraModelQueryAdapter.builder() + .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); @@ -713,8 +713,7 @@ class QueryTest { var p1 = Variable.of("p1"); var predicate = Query.builder("AlwaysTrue").parameters(p1).clause().build(); - var storeBuilder = ModelStore.builder().symbols(person); - var queryBuilder = storeBuilder.with(ViatraModelQuery.ADAPTER); + var queryBuilder = ViatraModelQueryAdapter.builder(); assertThrows(IllegalArgumentException.class, () -> queryBuilder.queries(predicate)); } 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 9de2655f..6860ece9 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 @@ -9,7 +9,7 @@ import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import tools.refinery.store.model.ModelStore; -import tools.refinery.store.query.ModelQuery; +import tools.refinery.store.query.ModelQueryAdapter; import tools.refinery.store.query.dnf.Query; import tools.refinery.store.query.view.FilteredView; import tools.refinery.store.query.view.FunctionView; @@ -35,13 +35,13 @@ class QueryTransactionTest { var store = ModelStore.builder() .symbols(person) - .with(ViatraModelQuery.ADAPTER) - .queries(predicate) + .with(ViatraModelQueryAdapter.builder() + .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); assertResults(Map.of( @@ -102,14 +102,14 @@ class QueryTransactionTest { var store = ModelStore.builder() .symbols(person) - .with(ViatraModelQuery.ADAPTER) - .defaultHint(new QueryEvaluationHint(null, QueryEvaluationHint.BackendRequirement.DEFAULT_SEARCH)) - .queries(predicate) + .with(ViatraModelQueryAdapter.builder() + .defaultHint(new QueryEvaluationHint(null, QueryEvaluationHint.BackendRequirement.DEFAULT_SEARCH)) + .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); assertResults(Map.of( @@ -153,14 +153,14 @@ class QueryTransactionTest { var store = ModelStore.builder() .symbols(person, asset) - .with(ViatraModelQuery.ADAPTER) - .queries(predicate) + .with(ViatraModelQueryAdapter.builder() + .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var assetInterpretation = model.getInterpretation(asset); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); assertFalse(queryEngine.hasPendingChanges()); @@ -226,14 +226,14 @@ class QueryTransactionTest { var store = ModelStore.builder() .symbols(person, age) - .with(ViatraModelQuery.ADAPTER) - .query(query) + .with(ViatraModelQueryAdapter.builder() + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var ageInterpretation = model.getInterpretation(age); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); @@ -268,14 +268,14 @@ class QueryTransactionTest { var store = ModelStore.builder() .symbols(person, age) - .with(ViatraModelQuery.ADAPTER) - .query(query) + .with(ViatraModelQueryAdapter.builder() + .queries(query)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); var ageInterpretation = model.getInterpretation(age); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var queryResultSet = queryEngine.getResultSet(query); personInterpretation.put(Tuple.of(0), true); @@ -306,13 +306,13 @@ class QueryTransactionTest { var store = ModelStore.builder() .symbols(person) - .with(ViatraModelQuery.ADAPTER) - .queries(predicate) + .with(ViatraModelQueryAdapter.builder() + .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); @@ -360,13 +360,13 @@ class QueryTransactionTest { var store = ModelStore.builder() .symbols(person) - .with(ViatraModelQuery.ADAPTER) - .queries(predicate) + .with(ViatraModelQueryAdapter.builder() + .queries(predicate)) .build(); var model = store.createEmptyModel(); var personInterpretation = model.getInterpretation(person); - var queryEngine = model.getAdapter(ModelQuery.ADAPTER); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); var predicateResultSet = queryEngine.getResultSet(predicate); personInterpretation.put(Tuple.of(0), true); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQuery.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQuery.java deleted file mode 100644 index 60698498..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQuery.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query; - -import tools.refinery.store.adapter.ModelAdapterType; - -public final class ModelQuery extends ModelAdapterType { - public static final ModelQuery ADAPTER = new ModelQuery(); - - private ModelQuery() { - super(ModelQueryAdapter.class, ModelQueryStoreAdapter.class, ModelQueryBuilder.class); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java index 76d6c3ba..c62a95b5 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java @@ -26,5 +26,5 @@ public interface ModelQueryBuilder extends ModelAdapterBuilder { ModelQueryBuilder query(AnyQuery query); @Override - ModelQueryStoreAdapter createStoreAdapter(ModelStore store); + ModelQueryStoreAdapter build(ModelStore store); } diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/Reasoning.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/Reasoning.java deleted file mode 100644 index 3d3df2b2..00000000 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/Reasoning.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.reasoning; - -import tools.refinery.store.reasoning.internal.ReasoningBuilderImpl; -import tools.refinery.store.adapter.ModelAdapterBuilderFactory; -import tools.refinery.store.model.ModelStoreBuilder; -import tools.refinery.store.reasoning.representation.PartialRelation; - -public final class Reasoning extends ModelAdapterBuilderFactory { - public static final Reasoning ADAPTER = new Reasoning(); - - public static final PartialRelation EXISTS = new PartialRelation("exists", 1); - - public static final PartialRelation EQUALS = new PartialRelation("equals", 1); - - private Reasoning() { - super(ReasoningAdapter.class, ReasoningStoreAdapter.class, ReasoningBuilder.class); - } - - @Override - public ReasoningBuilder createBuilder(ModelStoreBuilder storeBuilder) { - return new ReasoningBuilderImpl(storeBuilder); - } -} diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java index 8dedddf7..8f319242 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java @@ -6,12 +6,15 @@ package tools.refinery.store.reasoning; import tools.refinery.store.adapter.ModelAdapter; +import tools.refinery.store.query.ResultSet; +import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.reasoning.representation.AnyPartialSymbol; +import tools.refinery.store.reasoning.representation.PartialRelation; import tools.refinery.store.reasoning.representation.PartialSymbol; -import tools.refinery.store.query.dnf.Dnf; -import tools.refinery.store.query.ResultSet; public interface ReasoningAdapter extends ModelAdapter { + PartialRelation EXISTS = new PartialRelation("exists", 1); + @Override ReasoningStoreAdapter getStoreAdapter(); @@ -23,5 +26,5 @@ public interface ReasoningAdapter extends ModelAdapter { PartialInterpretation getPartialInterpretation(PartialSymbol partialSymbol); - ResultSet getLiftedResultSet(Dnf query); + ResultSet getLiftedResultSet(Dnf query); } diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java index df7b6e4d..d3a337e8 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java @@ -29,5 +29,5 @@ public interface ReasoningBuilder extends ModelAdapterBuilder { Dnf lift(Modality modality, Dnf query); @Override - ReasoningStoreAdapter createStoreAdapter(ModelStore store); + ReasoningStoreAdapter build(ModelStore store); } diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java index 96514d36..33b6f3c6 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java @@ -37,7 +37,7 @@ public class ReasoningAdapterImpl implements ReasoningAdapter { } @Override - public ResultSet getLiftedResultSet(Dnf query) { + public ResultSet getLiftedResultSet(Dnf query) { return null; } } diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java index 49f7c7d3..aa71496c 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java @@ -7,16 +7,12 @@ package tools.refinery.store.reasoning.internal; import tools.refinery.store.adapter.AbstractModelAdapterBuilder; import tools.refinery.store.model.ModelStore; -import tools.refinery.store.model.ModelStoreBuilder; +import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.reasoning.ReasoningBuilder; import tools.refinery.store.reasoning.literal.Modality; -import tools.refinery.store.query.dnf.Dnf; - -public class ReasoningBuilderImpl extends AbstractModelAdapterBuilder implements ReasoningBuilder { - public ReasoningBuilderImpl(ModelStoreBuilder storeBuilder) { - super(storeBuilder); - } +public class ReasoningBuilderImpl extends AbstractModelAdapterBuilder + implements ReasoningBuilder { @Override public ReasoningBuilder liftedQuery(Dnf liftedQuery) { return null; @@ -24,11 +20,12 @@ public class ReasoningBuilderImpl extends AbstractModelAdapterBuilder implements @Override public Dnf lift(Modality modality, Dnf query) { + checkNotConfigured(); return null; } @Override - public ReasoningStoreAdapterImpl createStoreAdapter(ModelStore store) { + public ReasoningStoreAdapterImpl doBuild(ModelStore store) { return null; } } diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java index 157f06e8..594005f1 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java @@ -14,7 +14,7 @@ import tools.refinery.store.query.literal.CallPolarity; import tools.refinery.store.query.literal.Literal; import tools.refinery.store.query.term.DataVariable; import tools.refinery.store.query.term.Variable; -import tools.refinery.store.reasoning.Reasoning; +import tools.refinery.store.reasoning.ReasoningAdapter; import tools.refinery.store.reasoning.literal.ModalConstraint; import tools.refinery.store.reasoning.literal.Modality; import tools.refinery.store.reasoning.literal.PartialLiterals; @@ -74,8 +74,8 @@ public class DnfLifter { } for (var quantifiedVariable : quantifiedVariables) { // Quantify over data variables that are not already quantified with the expected modality. - liftedLiterals.add(new CallLiteral(CallPolarity.POSITIVE, new ModalConstraint(modality, Reasoning.EXISTS), - List.of(quantifiedVariable))); + liftedLiterals.add(new CallLiteral(CallPolarity.POSITIVE, + new ModalConstraint(modality, ReasoningAdapter.EXISTS), List.of(quantifiedVariable))); } builder.clause(liftedLiterals); return changed || !quantifiedVariables.isEmpty(); @@ -87,7 +87,7 @@ public class DnfLifter { callLiteral.getPolarity() == CallPolarity.POSITIVE && callLiteral.getTarget() instanceof ModalConstraint modalConstraint && modalConstraint.modality() == modality && - modalConstraint.constraint().equals(Reasoning.EXISTS)) { + modalConstraint.constraint().equals(ReasoningAdapter.EXISTS)) { return callLiteral.getArguments().get(0); } return null; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RelationRefinementAction.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RelationRefinementAction.java index e4c702ea..0beee248 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RelationRefinementAction.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RelationRefinementAction.java @@ -5,7 +5,7 @@ */ package tools.refinery.store.reasoning.rule; -import tools.refinery.store.reasoning.Reasoning; +import tools.refinery.store.reasoning.ReasoningAdapter; import tools.refinery.store.reasoning.representation.PartialRelation; import tools.refinery.store.model.Model; import tools.refinery.store.query.term.Variable; @@ -28,7 +28,7 @@ public record RelationRefinementAction(PartialRelation target, List ar @Override public RuleActionExecutor createExecutor(int[] argumentIndices, Model model) { - var targetInterpretation = model.getAdapter(Reasoning.ADAPTER).getPartialInterpretation(target); + var targetInterpretation = model.getAdapter(ReasoningAdapter.class).getPartialInterpretation(target); return activationTuple -> { int arity = argumentIndices.length; var arguments = new int[arity]; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslationUnit.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslationUnit.java index 7f01122b..6e44a7d7 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslationUnit.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslationUnit.java @@ -6,7 +6,6 @@ package tools.refinery.store.reasoning.translator; import tools.refinery.store.model.Model; -import tools.refinery.store.model.ModelStoreBuilder; import tools.refinery.store.reasoning.ReasoningBuilder; import java.util.Collection; @@ -23,10 +22,6 @@ public abstract class TranslationUnit { configureReasoningBuilder(); } - protected ModelStoreBuilder getModelStoreBuilder() { - return reasoningBuilder.getStoreBuilder(); - } - protected void configureReasoningBuilder() { // Nothing to configure by default. } diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionTranslationUnit.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionTranslationUnit.java index d41e11c6..405e58ac 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionTranslationUnit.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionTranslationUnit.java @@ -36,11 +36,6 @@ public class BaseDecisionTranslationUnit extends TranslationUnit { this(partialRelation, new UniformSeed<>(partialRelation.arity(), TruthValue.UNKNOWN)); } - @Override - protected void configureReasoningBuilder() { - getModelStoreBuilder().symbol(symbol); - } - @Override public Collection getTranslatedRelations() { return List.of(new TranslatedBaseDecision(getReasoningBuilder(), partialRelation, symbol)); diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java index 70602ef5..8d3e998e 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java +++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java @@ -1,32 +1,48 @@ +package tools.refinery.store.adapter; /* * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors * * SPDX-License-Identifier: EPL-2.0 */ -package tools.refinery.store.adapter; - import tools.refinery.store.model.ModelStore; import tools.refinery.store.model.ModelStoreBuilder; -public abstract class AbstractModelAdapterBuilder implements ModelAdapterBuilder { - private final ModelStoreBuilder storeBuilder; +public abstract class AbstractModelAdapterBuilder implements ModelAdapterBuilder { + private boolean configured; - protected AbstractModelAdapterBuilder(ModelStoreBuilder storeBuilder) { - this.storeBuilder = storeBuilder; + @Override + public boolean isConfigured() { + return configured; } - @Override - public T with(ModelAdapterBuilderFactory adapterBuilderFactory) { - return storeBuilder.with(adapterBuilderFactory); + protected void checkConfigured() { + if (!configured) { + throw new IllegalStateException("Model adapter builder was not configured"); + } + } + + protected void checkNotConfigured() { + if (configured) { + throw new IllegalStateException("Model adapter builder was already configured"); + } + } + + protected void doConfigure(ModelStoreBuilder storeBuilder) { + // Nothing to configure by default. } @Override - public ModelStoreBuilder getStoreBuilder() { - return storeBuilder; + public final void configure(ModelStoreBuilder storeBuilder) { + checkNotConfigured(); + doConfigure(storeBuilder); + configured = true; } + protected abstract T doBuild(ModelStore store); + @Override - public ModelStore build() { - return storeBuilder.build(); + public final T build(ModelStore store) { + checkConfigured(); + return doBuild(store); } } diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java deleted file mode 100644 index e896d8d9..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.adapter; - -import org.jetbrains.annotations.NotNull; - -import java.util.*; -import java.util.function.Consumer; - -public class AdapterList implements Iterable { - private final List adapterTypes; - private final List adapters; - - public AdapterList() { - adapterTypes = new ArrayList<>(); - adapters = new ArrayList<>(); - } - - public AdapterList(int adapterCount) { - adapterTypes = new ArrayList<>(adapterCount); - adapters = new ArrayList<>(adapterCount); - } - - public int size() { - return adapters.size(); - } - - public void add(AnyModelAdapterType adapterType, T adapter) { - adapterTypes.add(adapterType); - adapters.add(adapter); - } - - public Optional tryGet(AnyModelAdapterType adapterType, Class adapterClass) { - int size = size(); - for (int i = 0; i < size; i++) { - if (getType(i).supports(adapterType)) { - return Optional.of(adapterClass.cast(get(i))); - } - } - return Optional.empty(); - } - - public U get(AnyModelAdapterType adapterType, Class adapterClass) { - return tryGet(adapterType, adapterClass).orElseThrow(() -> new IllegalArgumentException( - "No %s was configured".formatted(adapterType))); - } - - public AnyModelAdapterType getType(int i) { - return adapterTypes.get(i); - } - - public T get(int i) { - return adapters.get(i); - } - - public Collection getAdapterTypes() { - return Collections.unmodifiableCollection(adapterTypes); - } - - public Iterable> withAdapterTypes() { - return () -> new Iterator<>() { - private int i = 0; - - @Override - public boolean hasNext() { - return i < size(); - } - - @Override - public Entry next() { - if (i >= size()) { - throw new NoSuchElementException(); - } - var entry = new Entry<>(getType(i), get(i)); - i++; - return entry; - } - }; - } - - @NotNull - @Override - public Iterator iterator() { - return adapters.iterator(); - } - - @Override - public void forEach(Consumer action) { - adapters.forEach(action); - } - - @Override - public Spliterator spliterator() { - return adapters.spliterator(); - } - - public record Entry(AnyModelAdapterType adapterType, T adapter) { - } -} diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterUtils.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterUtils.java new file mode 100644 index 00000000..556e99f0 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterUtils.java @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.adapter; + +import java.util.Collection; +import java.util.Optional; + +public class AdapterUtils { + private AdapterUtils() { + throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); + } + + public static Optional tryGetAdapter(Collection adapters, Class type) { + var iterator = adapters.stream().filter(type::isInstance).iterator(); + if (!iterator.hasNext()) { + return Optional.empty(); + } + var adapter = type.cast(iterator.next()); + if (iterator.hasNext()) { + throw new IllegalArgumentException("Ambiguous adapter: both %s and %s match %s" + .formatted(adapter.getClass().getName(), iterator.next().getClass().getName(), type.getName())); + } + return Optional.of(adapter); + } + + public static T getAdapter(Collection adapters, Class type) { + return tryGetAdapter(adapters, type).orElseThrow(() -> new IllegalArgumentException( + "No %s adapter was configured".formatted(type.getName()))); + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java deleted file mode 100644 index f161a60b..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.adapter; - -import java.util.Collection; - -public sealed interface AnyModelAdapterType permits ModelAdapterType { - Class getModelAdapterClass(); - - Class getModelStoreAdapterClass(); - - Class getModelAdapterBuilderClass(); - - Collection getSupportedAdapterTypes(); - - default boolean supports(AnyModelAdapterType targetAdapter) { - return getSupportedAdapterTypes().contains(targetAdapter); - } - - String getName(); -} diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java index 709cbb3e..75e5e07d 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java +++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java @@ -9,14 +9,9 @@ import tools.refinery.store.model.ModelStore; import tools.refinery.store.model.ModelStoreBuilder; public interface ModelAdapterBuilder { - ModelStoreAdapter createStoreAdapter(ModelStore store); + boolean isConfigured(); - T with(ModelAdapterBuilderFactory adapterBuilderFactory); + void configure(ModelStoreBuilder storeBuilder); - ModelStoreBuilder getStoreBuilder(); - - default void configure() { - } - - ModelStore build(); + ModelStoreAdapter build(ModelStore store); } diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java deleted file mode 100644 index 1d549d5b..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.adapter; - -import tools.refinery.store.model.ModelStoreBuilder; - -public abstract class ModelAdapterBuilderFactory extends ModelAdapterType { - - protected ModelAdapterBuilderFactory(Class modelAdapterClass, Class modelStoreAdapterClass, - Class modelAdapterBuilderClass) { - super(modelAdapterClass, modelStoreAdapterClass, modelAdapterBuilderClass); - } - - public abstract T3 createBuilder(ModelStoreBuilder storeBuilder); -} diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java deleted file mode 100644 index 6255fe52..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.adapter; - -import tools.refinery.store.model.Model; -import tools.refinery.store.model.ModelStore; - -import java.lang.reflect.Method; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -public abstract non-sealed class ModelAdapterType implements AnyModelAdapterType { - private final Class modelAdapterClass; - private final Class modelStoreAdapterClass; - private final Class modelAdapterBuilderClass; - private final Set supportedAdapters = new HashSet<>(); - - protected ModelAdapterType(Class modelAdapterClass, Class modelStoreAdapterClass, - Class modelAdapterBuilderClass) { - checkReturnType(modelAdapterClass, modelStoreAdapterClass, "createModelAdapter", Model.class); - checkReturnType(modelStoreAdapterClass, modelAdapterBuilderClass, "createStoreAdapter", ModelStore.class); - this.modelAdapterClass = modelAdapterClass; - this.modelStoreAdapterClass = modelStoreAdapterClass; - this.modelAdapterBuilderClass = modelAdapterBuilderClass; - supportedAdapters.add(this); - } - - private void checkReturnType(Class expectedReturnType, Class ownerClass, String methodName, - Class... argumentTypes) { - Method method; - try { - method = ownerClass.getMethod(methodName, argumentTypes); - } catch (NoSuchMethodException e) { - throw new IllegalStateException("Invalid %s: %s#%s method is required" - .formatted(this, ownerClass.getName(), methodName), e); - } - var returnType = method.getReturnType(); - if (!expectedReturnType.isAssignableFrom(returnType)) { - throw new IllegalStateException("Invalid %s: %s is not assignable from the return type %s of %s#%s" - .formatted(this, expectedReturnType.getName(), returnType.getCanonicalName(), - ownerClass.getName(), methodName)); - } - } - - protected void extendsAdapter(ModelAdapterType superAdapter) { - supportedAdapters.addAll(superAdapter.supportedAdapters); - } - - @Override - public final Class getModelAdapterClass() { - return modelAdapterClass; - } - - @Override - public final Class getModelStoreAdapterClass() { - return modelStoreAdapterClass; - } - - @Override - public final Class getModelAdapterBuilderClass() { - return modelAdapterBuilderClass; - } - - @Override - public Collection getSupportedAdapterTypes() { - return Collections.unmodifiableCollection(supportedAdapters); - } - - @Override - public String getName() { - return "%s.ADAPTER".formatted(this.getClass().getName()); - } - - @Override - public String toString() { - return getName(); - } -} diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/Model.java b/subprojects/store/src/main/java/tools/refinery/store/model/Model.java index f4131756..d58d91c3 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/Model.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/Model.java @@ -6,7 +6,6 @@ package tools.refinery.store.model; import tools.refinery.store.adapter.ModelAdapter; -import tools.refinery.store.adapter.ModelAdapterType; import tools.refinery.store.map.Versioned; import tools.refinery.store.representation.AnySymbol; import tools.refinery.store.representation.Symbol; @@ -30,9 +29,9 @@ public interface Model extends Versioned { ModelDiffCursor getDiffCursor(long to); - Optional tryGetAdapter(ModelAdapterType adapterType); + Optional tryGetAdapter(Class adapterType); - T getAdapter(ModelAdapterType adapterType); + T getAdapter(Class adapterType); void addListener(ModelListener listener); diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java index a72399f7..b10eb8a4 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java @@ -5,7 +5,6 @@ */ package tools.refinery.store.model; -import tools.refinery.store.adapter.ModelAdapterType; import tools.refinery.store.adapter.ModelStoreAdapter; import tools.refinery.store.model.internal.ModelStoreBuilderImpl; import tools.refinery.store.representation.AnySymbol; @@ -25,9 +24,9 @@ public interface ModelStore { ModelDiffCursor getDiffCursor(long from, long to); - Optional tryGetAdapter(ModelAdapterType adapterType); + Optional tryGetAdapter(Class adapterType); - T getAdapter(ModelAdapterType adapterType); + T getAdapter(Class adapterType); static ModelStoreBuilder builder() { return new ModelStoreBuilderImpl(); diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java index d9354bdb..3a4024b5 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java @@ -6,8 +6,6 @@ package tools.refinery.store.model; import tools.refinery.store.adapter.ModelAdapterBuilder; -import tools.refinery.store.adapter.ModelAdapterBuilderFactory; -import tools.refinery.store.adapter.ModelAdapterType; import tools.refinery.store.representation.AnySymbol; import tools.refinery.store.representation.Symbol; @@ -31,11 +29,11 @@ public interface ModelStoreBuilder { ModelStoreBuilder symbol(Symbol symbol); - T with(ModelAdapterBuilderFactory adapterBuilderFactory); + ModelStoreBuilder with(T adapterBuilder); - Optional tryGetAdapter(ModelAdapterType adapterType); + Optional tryGetAdapter(Class adapterType); - T getAdapter(ModelAdapterType adapterType); + T getAdapter(Class adapterType); ModelStore build(); } diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java index 50a408da..c5475a1a 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java @@ -5,10 +5,8 @@ */ package tools.refinery.store.model.internal; -import tools.refinery.store.adapter.AdapterList; -import tools.refinery.store.adapter.AnyModelAdapterType; +import tools.refinery.store.adapter.AdapterUtils; import tools.refinery.store.adapter.ModelAdapter; -import tools.refinery.store.adapter.ModelAdapterType; import tools.refinery.store.map.DiffCursor; import tools.refinery.store.model.*; import tools.refinery.store.representation.AnySymbol; @@ -21,7 +19,7 @@ public class ModelImpl implements Model { private final ModelStore store; private long state; private Map> interpretations; - private final AdapterList adapters; + private final List adapters; private final List listeners = new ArrayList<>(); private boolean uncommittedChanges; private ModelAction pendingAction = ModelAction.NONE; @@ -30,7 +28,7 @@ public class ModelImpl implements Model { ModelImpl(ModelStore store, long state, int adapterCount) { this.store = store; this.state = state; - adapters = new AdapterList<>(adapterCount); + adapters = new ArrayList<>(adapterCount); } void setInterpretations(Map> interpretations) { @@ -167,17 +165,17 @@ public class ModelImpl implements Model { } @Override - public Optional tryGetAdapter(ModelAdapterType adapterType) { - return adapters.tryGet(adapterType, adapterType.getModelAdapterClass()); + public Optional tryGetAdapter(Class adapterType) { + return AdapterUtils.tryGetAdapter(adapters, adapterType); } @Override - public T getAdapter(ModelAdapterType adapterType) { - return adapters.get(adapterType, adapterType.getModelAdapterClass()); + public T getAdapter(Class adapterType) { + return AdapterUtils.getAdapter(adapters, adapterType); } - void addAdapter(AnyModelAdapterType adapterType, ModelAdapter adapter) { - adapters.add(adapterType, adapter); + void addAdapter(ModelAdapter adapter) { + adapters.add(adapter); } @Override diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java index 70bccb96..aafbe130 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java @@ -5,10 +5,8 @@ */ package tools.refinery.store.model.internal; -import tools.refinery.store.adapter.AdapterList; +import tools.refinery.store.adapter.AdapterUtils; import tools.refinery.store.adapter.ModelAdapterBuilder; -import tools.refinery.store.adapter.ModelAdapterBuilderFactory; -import tools.refinery.store.adapter.ModelAdapterType; import tools.refinery.store.map.VersionedMapStore; import tools.refinery.store.map.VersionedMapStoreImpl; import tools.refinery.store.model.ModelStore; @@ -23,7 +21,7 @@ import java.util.*; public class ModelStoreBuilderImpl implements ModelStoreBuilder { private final Set allSymbols = new HashSet<>(); private final Map, List> equivalenceClasses = new HashMap<>(); - private final AdapterList adapters = new AdapterList<>(); + private final List adapters = new ArrayList<>(); @Override public ModelStoreBuilder symbol(Symbol symbol) { @@ -38,46 +36,25 @@ public class ModelStoreBuilderImpl implements ModelStoreBuilder { } @Override - public T with(ModelAdapterBuilderFactory adapterBuilderFactory) { - return adapters.tryGet(adapterBuilderFactory, adapterBuilderFactory.getModelAdapterBuilderClass()) - .orElseGet(() -> addAdapter(adapterBuilderFactory)); - } - - private T addAdapter(ModelAdapterBuilderFactory adapterBuilderFactory) { - for (var configuredAdapterType : adapters.getAdapterTypes()) { - var intersection = new HashSet<>(adapterBuilderFactory.getSupportedAdapterTypes()); - intersection.retainAll(configuredAdapterType.getSupportedAdapterTypes()); - if (!intersection.isEmpty()) { - if (configuredAdapterType.supports(adapterBuilderFactory)) { - // Impossible to end up here from #with, because we should have returned - // the existing adapter there instead of adding a new one. - throw new IllegalArgumentException( - "Cannot add %s, because it is already provided by configured adapter %s" - .formatted(adapterBuilderFactory, configuredAdapterType)); - } else if (adapterBuilderFactory.supports(configuredAdapterType)) { - throw new IllegalArgumentException( - "Cannot add %s, because it provides already configured adapter %s" - .formatted(adapterBuilderFactory, configuredAdapterType)); - } else { - throw new IllegalArgumentException( - "Cannot add %s, because configured adapter %s already provides %s" - .formatted(adapterBuilderFactory, configuredAdapterType, intersection)); - } + public ModelStoreBuilder with(T adapterBuilder) { + for (var existingAdapter : adapters) { + if (existingAdapter.getClass().equals(adapterBuilder.getClass())) { + throw new IllegalArgumentException("%s adapter was already configured for store builder" + .formatted(adapterBuilder.getClass().getName())); } } - var newAdapter = adapterBuilderFactory.createBuilder(this); - adapters.add(adapterBuilderFactory, newAdapter); - return newAdapter; + adapters.add(adapterBuilder); + return this; } @Override - public Optional tryGetAdapter(ModelAdapterType adapterType) { - return adapters.tryGet(adapterType, adapterType.getModelAdapterBuilderClass()); + public Optional tryGetAdapter(Class adapterType) { + return AdapterUtils.tryGetAdapter(adapters, adapterType); } @Override - public T getAdapter(ModelAdapterType adapterType) { - return adapters.get(adapterType, adapterType.getModelAdapterBuilderClass()); + public T getAdapter(Class adapterType) { + return AdapterUtils.getAdapter(adapters, adapterType); } @Override @@ -86,13 +63,13 @@ public class ModelStoreBuilderImpl implements ModelStoreBuilder { for (var entry : equivalenceClasses.entrySet()) { createStores(stores, entry.getKey(), entry.getValue()); } - var modelStore = new ModelStoreImpl(stores, adapters.size()); for (int i = adapters.size() - 1; i >= 0; i--) { - adapters.get(i).configure(); + adapters.get(i).configure(this); } - for (var entry : adapters.withAdapterTypes()) { - var adapter = entry.adapter().createStoreAdapter(modelStore); - modelStore.addAdapter(entry.adapterType(), adapter); + var modelStore = new ModelStoreImpl(stores, adapters.size()); + for (var adapterBuilder : adapters) { + var storeAdapter = adapterBuilder.build(modelStore); + modelStore.addAdapter(storeAdapter); } return modelStore; } diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java index bfae7181..60b735e6 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java @@ -5,9 +5,7 @@ */ package tools.refinery.store.model.internal; -import tools.refinery.store.adapter.AdapterList; -import tools.refinery.store.adapter.AnyModelAdapterType; -import tools.refinery.store.adapter.ModelAdapterType; +import tools.refinery.store.adapter.AdapterUtils; import tools.refinery.store.adapter.ModelStoreAdapter; import tools.refinery.store.map.DiffCursor; import tools.refinery.store.map.VersionedMapStore; @@ -21,11 +19,11 @@ import java.util.*; public class ModelStoreImpl implements ModelStore { private final Map> stores; - private final AdapterList adapters; + private final List adapters; ModelStoreImpl(Map> stores, int adapterCount) { this.stores = stores; - adapters = new AdapterList<>(adapterCount); + adapters = new ArrayList<>(adapterCount); } @Override @@ -64,9 +62,9 @@ public class ModelStoreImpl implements ModelStore { } private void adaptModel(ModelImpl model) { - for (var entry : adapters.withAdapterTypes()) { - var adapter = entry.adapter().createModelAdapter(model); - model.addAdapter(entry.adapterType(), adapter); + for (var storeAdapter : adapters) { + var adapter = storeAdapter.createModelAdapter(model); + model.addAdapter(adapter); } } @@ -91,16 +89,16 @@ public class ModelStoreImpl implements ModelStore { } @Override - public Optional tryGetAdapter(ModelAdapterType adapterType) { - return adapters.tryGet(adapterType, adapterType.getModelStoreAdapterClass()); + public Optional tryGetAdapter(Class adapterType) { + return AdapterUtils.tryGetAdapter(adapters, adapterType); } @Override - public T getAdapter(ModelAdapterType adapterType) { - return adapters.get(adapterType, adapterType.getModelStoreAdapterClass()); + public T getAdapter(Class adapterType) { + return AdapterUtils.getAdapter(adapters, adapterType); } - void addAdapter(AnyModelAdapterType adapterType, ModelStoreAdapter adapter) { - adapters.add(adapterType, adapter); + void addAdapter(ModelStoreAdapter adapter) { + adapters.add(adapter); } } -- cgit v1.2.3-70-g09d2 From 565de1cb116e5e4f116544aaa035be58336656ec Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Sun, 23 Apr 2023 23:39:39 +0200 Subject: refactor: query terms * Separate different operators into different classes to make it easier to add functionality (e.g., simplification) later. * Add UpperCardinality terms. * Move UpperCardinality aggregator and tests into refinery-store-query. --- .../UpperCardinalitySumAggregationOperator.java | 102 -------- ...ardinalitySumAggregationOperatorStreamTest.java | 56 ----- ...UpperCardinalitySumAggregationOperatorTest.java | 92 -------- .../store/query/literal/AssumeLiteral.java | 13 +- .../query/substitution/CompositeSubstitution.java | 15 -- .../store/query/substitution/Substitution.java | 9 +- .../query/substitution/SubstitutionBuilder.java | 78 +++++++ .../store/query/substitution/Substitutions.java | 38 --- .../refinery/store/query/term/AbstractTerm.java | 41 ++++ .../store/query/term/ArithmeticBinaryOperator.java | 31 --- .../store/query/term/ArithmeticBinaryTerm.java | 61 ----- .../store/query/term/ArithmeticUnaryOperator.java | 21 -- .../store/query/term/ArithmeticUnaryTerm.java | 56 ----- .../refinery/store/query/term/BinaryTerm.java | 45 ++-- .../store/query/term/ComparisonOperator.java | 25 -- .../refinery/store/query/term/ComparisonTerm.java | 68 ------ .../refinery/store/query/term/ConstantTerm.java | 42 ++-- .../refinery/store/query/term/OpaqueTerm.java | 85 ------- .../tools/refinery/store/query/term/UnaryTerm.java | 24 +- .../store/query/term/bool/BoolAndTerm.java | 31 +++ .../store/query/term/bool/BoolBinaryTerm.java | 15 ++ .../store/query/term/bool/BoolConstantTerm.java | 21 -- .../store/query/term/bool/BoolLogicBinaryTerm.java | 83 ------- .../store/query/term/bool/BoolNotTerm.java | 14 +- .../refinery/store/query/term/bool/BoolOrTerm.java | 31 +++ .../refinery/store/query/term/bool/BoolTerms.java | 18 +- .../store/query/term/bool/BoolXorTerm.java | 31 +++ .../store/query/term/bool/LogicBinaryOperator.java | 22 -- .../query/term/comparable/ComparisonTerm.java | 19 ++ .../store/query/term/comparable/EqTerm.java | 30 +++ .../store/query/term/comparable/GreaterEqTerm.java | 30 +++ .../store/query/term/comparable/GreaterTerm.java | 30 +++ .../store/query/term/comparable/LessEqTerm.java | 30 +++ .../store/query/term/comparable/LessTerm.java | 30 +++ .../store/query/term/comparable/NotEqTerm.java | 30 +++ .../refinery/store/query/term/int_/IntAddTerm.java | 31 +++ .../query/term/int_/IntArithmeticBinaryTerm.java | 53 ----- .../query/term/int_/IntArithmeticUnaryTerm.java | 35 --- .../store/query/term/int_/IntBinaryTerm.java | 15 ++ .../store/query/term/int_/IntComparisonTerm.java | 39 ---- .../refinery/store/query/term/int_/IntDivTerm.java | 31 +++ .../query/term/int_/IntExtremeValueAggregator.java | 22 -- .../refinery/store/query/term/int_/IntMaxTerm.java | 31 +++ .../refinery/store/query/term/int_/IntMinTerm.java | 31 +++ .../store/query/term/int_/IntMinusTerm.java | 30 +++ .../refinery/store/query/term/int_/IntMulTerm.java | 31 +++ .../store/query/term/int_/IntPlusTerm.java | 30 +++ .../refinery/store/query/term/int_/IntPowTerm.java | 43 ++++ .../refinery/store/query/term/int_/IntSubTerm.java | 31 +++ .../refinery/store/query/term/int_/IntTerms.java | 78 ++++--- .../store/query/term/int_/IntUnaryTerm.java | 15 ++ .../store/query/term/int_/RealToIntTerm.java | 16 +- .../store/query/term/real/IntToRealTerm.java | 14 +- .../store/query/term/real/RealAddTerm.java | 31 +++ .../query/term/real/RealArithmeticBinaryTerm.java | 41 ---- .../query/term/real/RealArithmeticUnaryTerm.java | 35 --- .../store/query/term/real/RealBinaryTerm.java | 15 ++ .../store/query/term/real/RealComparisonTerm.java | 40 ---- .../store/query/term/real/RealDivTerm.java | 31 +++ .../term/real/RealExtremeValueAggregator.java | 22 -- .../store/query/term/real/RealMaxTerm.java | 31 +++ .../store/query/term/real/RealMinTerm.java | 31 +++ .../store/query/term/real/RealMinusTerm.java | 30 +++ .../store/query/term/real/RealMulTerm.java | 31 +++ .../store/query/term/real/RealPlusTerm.java | 30 +++ .../store/query/term/real/RealPowTerm.java | 31 +++ .../store/query/term/real/RealSubTerm.java | 31 +++ .../refinery/store/query/term/real/RealTerms.java | 78 ++++--- .../store/query/term/real/RealUnaryTerm.java | 15 ++ .../uppercardinality/UpperCardinalityAddTerm.java | 31 +++ .../UpperCardinalityBinaryTerm.java | 17 ++ .../uppercardinality/UpperCardinalityMaxTerm.java | 31 +++ .../uppercardinality/UpperCardinalityMinTerm.java | 31 +++ .../uppercardinality/UpperCardinalityMulTerm.java | 31 +++ .../UpperCardinalitySumAggregator.java | 86 +++++++ .../uppercardinality/UpperCardinalityTerms.java | 73 ++++++ .../store/query/valuation/MapBasedValuation.java | 22 ++ .../refinery/store/query/valuation/Valuation.java | 9 + .../store/query/valuation/ValuationBuilder.java | 40 ++++ .../tools/refinery/store/query/DnfBuilderTest.java | 41 ++++ .../store/query/term/TermSubstitutionTest.java | 97 ++++++++ .../query/term/bool/BoolTermsEvaluateTest.java | 75 ++++++ .../query/term/int_/IntTermsEvaluateTest.java | 259 +++++++++++++++++++++ .../query/term/real/RealTermEvaluateTest.java | 238 +++++++++++++++++++ .../UpperCardinalitySumAggregatorStreamTest.java | 56 +++++ .../UpperCardinalitySumAggregatorTest.java | 80 +++++++ .../UpperCardinalityTermsEvaluateTest.java | 104 +++++++++ .../store/reasoning/translator/Advice.java | 9 +- 88 files changed, 2558 insertions(+), 1238 deletions(-) delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java delete mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java delete mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/CompositeSubstitution.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/SubstitutionBuilder.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/AbstractTerm.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryOperator.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryTerm.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryOperator.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryTerm.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonOperator.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonTerm.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/OpaqueTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolAndTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolBinaryTerm.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolConstantTerm.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolLogicBinaryTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolOrTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolXorTerm.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/LogicBinaryOperator.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/ComparisonTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/EqTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterEqTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessEqTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/NotEqTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntAddTerm.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticBinaryTerm.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticUnaryTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntBinaryTerm.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntComparisonTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntDivTerm.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntExtremeValueAggregator.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMaxTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinusTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMulTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPlusTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPowTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSubTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntUnaryTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealAddTerm.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticBinaryTerm.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticUnaryTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealBinaryTerm.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealComparisonTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealDivTerm.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealExtremeValueAggregator.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMaxTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinusTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMulTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPlusTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPowTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSubTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealUnaryTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityAddTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityBinaryTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMaxTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMinTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMulTerm.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregator.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTerms.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/MapBasedValuation.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/ValuationBuilder.java create mode 100644 subprojects/store-query/src/test/java/tools/refinery/store/query/term/TermSubstitutionTest.java create mode 100644 subprojects/store-query/src/test/java/tools/refinery/store/query/term/bool/BoolTermsEvaluateTest.java create mode 100644 subprojects/store-query/src/test/java/tools/refinery/store/query/term/int_/IntTermsEvaluateTest.java create mode 100644 subprojects/store-query/src/test/java/tools/refinery/store/query/term/real/RealTermEvaluateTest.java create mode 100644 subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorStreamTest.java create mode 100644 subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorTest.java create mode 100644 subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTermsEvaluateTest.java (limited to 'subprojects/store-query-viatra/src/main/java/tools') diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java deleted file mode 100644 index bfd4c049..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.viatra.internal.cardinality; - -import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.BoundAggregator; -import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator; -import tools.refinery.store.representation.cardinality.FiniteUpperCardinality; -import tools.refinery.store.representation.cardinality.UnboundedUpperCardinality; -import tools.refinery.store.representation.cardinality.UpperCardinalities; -import tools.refinery.store.representation.cardinality.UpperCardinality; - -import java.util.stream.Stream; - -public class UpperCardinalitySumAggregationOperator implements IMultisetAggregationOperator { - public static final UpperCardinalitySumAggregationOperator INSTANCE = new UpperCardinalitySumAggregationOperator(); - - public static final BoundAggregator BOUND_AGGREGATOR = new BoundAggregator(INSTANCE, UpperCardinality.class, - UpperCardinality.class); - - private UpperCardinalitySumAggregationOperator() { - // Singleton constructor. - } - - @Override - public String getName() { - return "sum"; - } - - @Override - public String getShortDescription() { - return "%s computes the sum of finite or unbounded upper cardinalities".formatted(getName()); - } - - @Override - public Accumulator createNeutral() { - return new Accumulator(); - } - - @Override - public boolean isNeutral(Accumulator result) { - return result.sumFiniteUpperBounds == 0 && result.countUnbounded == 0; - } - - @Override - public Accumulator update(Accumulator oldResult, UpperCardinality updateValue, boolean isInsertion) { - if (updateValue instanceof FiniteUpperCardinality finiteUpperCardinality) { - int finiteUpperBound = finiteUpperCardinality.finiteUpperBound(); - if (isInsertion) { - oldResult.sumFiniteUpperBounds += finiteUpperBound; - } else { - oldResult.sumFiniteUpperBounds -= finiteUpperBound; - } - } else if (updateValue instanceof UnboundedUpperCardinality) { - if (isInsertion) { - oldResult.countUnbounded += 1; - } else { - oldResult.countUnbounded -= 1; - } - } else { - throw new IllegalArgumentException("Unknown UpperCardinality: " + updateValue); - } - return oldResult; - } - - @Override - public UpperCardinality getAggregate(Accumulator result) { - return result.countUnbounded > 0 ? UpperCardinalities.UNBOUNDED : - UpperCardinalities.valueOf(result.sumFiniteUpperBounds); - } - - @Override - public UpperCardinality aggregateStream(Stream stream) { - var result = stream.collect(this::createNeutral, (accumulator, value) -> update(accumulator, value, true), - (left, right) -> new Accumulator(left.sumFiniteUpperBounds + right.sumFiniteUpperBounds, - left.countUnbounded + right.countUnbounded)); - return getAggregate(result); - } - - @Override - public Accumulator clone(Accumulator original) { - return new Accumulator(original.sumFiniteUpperBounds, original.countUnbounded); - } - - public static class Accumulator { - private int sumFiniteUpperBounds; - - private int countUnbounded; - - private Accumulator(int sumFiniteUpperBounds, int countUnbounded) { - this.sumFiniteUpperBounds = sumFiniteUpperBounds; - this.countUnbounded = countUnbounded; - } - - private Accumulator() { - this(0, 0); - } - } -} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java deleted file mode 100644 index 53d03cbd..00000000 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.viatra.internal.cardinality; - -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import tools.refinery.store.representation.cardinality.UpperCardinalities; -import tools.refinery.store.representation.cardinality.UpperCardinality; - -import java.util.List; -import java.util.stream.Stream; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -class UpperCardinalitySumAggregationOperatorStreamTest { - @ParameterizedTest - @MethodSource - void testStream(List list, UpperCardinality expected) { - var result = UpperCardinalitySumAggregationOperator.INSTANCE.aggregateStream(list.stream()); - assertThat(result, equalTo(expected)); - } - - static Stream testStream() { - return Stream.of( - Arguments.of(List.of(), UpperCardinalities.ZERO), - Arguments.of(List.of(UpperCardinality.of(3)), UpperCardinality.of(3)), - Arguments.of( - List.of( - UpperCardinality.of(2), - UpperCardinality.of(3) - ), - UpperCardinality.of(5) - ), - Arguments.of(List.of(UpperCardinalities.UNBOUNDED), UpperCardinalities.UNBOUNDED), - Arguments.of( - List.of( - UpperCardinalities.UNBOUNDED, - UpperCardinalities.UNBOUNDED - ), - UpperCardinalities.UNBOUNDED - ), - Arguments.of( - List.of( - UpperCardinalities.UNBOUNDED, - UpperCardinality.of(3) - ), - UpperCardinalities.UNBOUNDED - ) - ); - } -} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java deleted file mode 100644 index 677eeeac..00000000 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.viatra.internal.cardinality; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import tools.refinery.store.representation.cardinality.UpperCardinalities; -import tools.refinery.store.representation.cardinality.UpperCardinality; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -class UpperCardinalitySumAggregationOperatorTest { - private UpperCardinalitySumAggregationOperator.Accumulator accumulator; - - @BeforeEach - void beforeEach() { - accumulator = UpperCardinalitySumAggregationOperator.INSTANCE.createNeutral(); - } - - @Test - void emptyAggregationTest() { - assertResult(UpperCardinality.of(0)); - } - - @Test - void singleBoundedTest() { - insert(UpperCardinality.of(3)); - assertResult(UpperCardinality.of(3)); - } - - @Test - void multipleBoundedTest() { - insert(UpperCardinality.of(2)); - insert(UpperCardinality.of(3)); - assertResult(UpperCardinality.of(5)); - } - - @Test - void singleUnboundedTest() { - insert(UpperCardinalities.UNBOUNDED); - assertResult(UpperCardinalities.UNBOUNDED); - } - - @Test - void multipleUnboundedTest() { - insert(UpperCardinalities.UNBOUNDED); - insert(UpperCardinalities.UNBOUNDED); - assertResult(UpperCardinalities.UNBOUNDED); - } - - @Test - void removeBoundedTest() { - insert(UpperCardinality.of(2)); - insert(UpperCardinality.of(3)); - remove(UpperCardinality.of(2)); - assertResult(UpperCardinality.of(3)); - } - - @Test - void removeAllUnboundedTest() { - insert(UpperCardinalities.UNBOUNDED); - insert(UpperCardinality.of(3)); - remove(UpperCardinalities.UNBOUNDED); - assertResult(UpperCardinality.of(3)); - } - - @Test - void removeSomeUnboundedTest() { - insert(UpperCardinalities.UNBOUNDED); - insert(UpperCardinalities.UNBOUNDED); - insert(UpperCardinality.of(3)); - remove(UpperCardinalities.UNBOUNDED); - assertResult(UpperCardinalities.UNBOUNDED); - } - - private void insert(UpperCardinality value) { - accumulator = UpperCardinalitySumAggregationOperator.INSTANCE.update(accumulator, value, true); - } - - private void remove(UpperCardinality value) { - accumulator = UpperCardinalitySumAggregationOperator.INSTANCE.update(accumulator, value, false); - } - - private void assertResult(UpperCardinality expected) { - var result = UpperCardinalitySumAggregationOperator.INSTANCE.getAggregate(accumulator); - assertThat(result, equalTo(expected)); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java index 58d563da..59538831 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java @@ -7,9 +7,9 @@ package tools.refinery.store.query.literal; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.ConstantTerm; import tools.refinery.store.query.term.Term; import tools.refinery.store.query.term.Variable; -import tools.refinery.store.query.term.bool.BoolConstantTerm; import java.util.Set; @@ -42,13 +42,12 @@ public record AssumeLiteral(Term term) implements Literal { @Override public LiteralReduction getReduction() { - if (BoolConstantTerm.TRUE.equals(term)) { - return LiteralReduction.ALWAYS_TRUE; - } else if (BoolConstantTerm.FALSE.equals(term)) { - return LiteralReduction.ALWAYS_FALSE; - } else { - return LiteralReduction.NOT_REDUCIBLE; + if (term instanceof ConstantTerm constantTerm) { + // Return {@code ALWAYS_FALSE} for {@code false} or {@code null} literals. + return Boolean.TRUE.equals(constantTerm.getValue()) ? LiteralReduction.ALWAYS_TRUE : + LiteralReduction.ALWAYS_FALSE; } + return LiteralReduction.NOT_REDUCIBLE; } @Override diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/CompositeSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/CompositeSubstitution.java deleted file mode 100644 index d175130e..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/CompositeSubstitution.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.substitution; - -import tools.refinery.store.query.term.Variable; - -public record CompositeSubstitution(Substitution first, Substitution second) implements Substitution { - @Override - public Variable getSubstitute(Variable variable) { - return second.getSubstitute(first.getSubstitute(variable)); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java index 5714edf4..834fce12 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java @@ -5,7 +5,6 @@ */ package tools.refinery.store.query.substitution; -import tools.refinery.store.query.term.AnyDataVariable; import tools.refinery.store.query.term.DataVariable; import tools.refinery.store.query.term.NodeVariable; import tools.refinery.store.query.term.Variable; @@ -19,16 +18,12 @@ public interface Substitution { return substitute.asNodeVariable(); } - default AnyDataVariable getTypeSafeSubstitute(AnyDataVariable variable) { - return getTypeSafeSubstitute((DataVariable) variable); - } - default DataVariable getTypeSafeSubstitute(DataVariable variable) { var substitute = getSubstitute(variable); return substitute.asDataVariable(variable.getType()); } - default Substitution andThen(Substitution second) { - return new CompositeSubstitution(this, second); + static SubstitutionBuilder builder() { + return new SubstitutionBuilder(); } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/SubstitutionBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/SubstitutionBuilder.java new file mode 100644 index 00000000..658a26e3 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/SubstitutionBuilder.java @@ -0,0 +1,78 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.substitution; + +import tools.refinery.store.query.term.DataVariable; +import tools.refinery.store.query.term.NodeVariable; +import tools.refinery.store.query.term.Variable; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@SuppressWarnings("UnusedReturnValue") +public class SubstitutionBuilder { + private final Map map = new HashMap<>(); + private Substitution fallback; + + SubstitutionBuilder() { + total(); + } + + public SubstitutionBuilder put(NodeVariable original, NodeVariable substitute) { + return putChecked(original, substitute); + } + + public SubstitutionBuilder put(DataVariable original, DataVariable substitute) { + return putChecked(original, substitute); + } + + public SubstitutionBuilder putChecked(Variable original, Variable substitute) { + if (!original.getSort().equals(substitute.getSort())) { + throw new IllegalArgumentException("Cannot substitute variable %s of sort %s with variable %s of sort %s" + .formatted(original, original.getSort(), substitute, substitute.getSort())); + } + if (map.containsKey(original)) { + throw new IllegalArgumentException("Already has substitution for variable %s".formatted(original)); + } + map.put(original, substitute); + return this; + } + + public SubstitutionBuilder putManyChecked(List originals, List substitutes) { + int size = originals.size(); + if (size != substitutes.size()) { + throw new IllegalArgumentException("Cannot substitute %d variables %s with %d variables %s" + .formatted(size, originals, substitutes.size(), substitutes)); + } + for (int i = 0; i < size; i++) { + putChecked(originals.get(i), substitutes.get(i)); + } + return this; + } + + public SubstitutionBuilder fallback(Substitution newFallback) { + fallback = newFallback; + return this; + } + + public SubstitutionBuilder total() { + return fallback(StatelessSubstitution.FAILING); + } + + public SubstitutionBuilder partial() { + return fallback(StatelessSubstitution.IDENTITY); + } + + public SubstitutionBuilder renewing() { + return fallback(new RenewingSubstitution()); + } + + public Substitution build() { + return map.isEmpty() ? fallback : new MapBasedSubstitution(Collections.unmodifiableMap(map), fallback); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java deleted file mode 100644 index c4791bf1..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.substitution; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import tools.refinery.store.query.term.Variable; - -import java.util.Map; - -public final class Substitutions { - private Substitutions() { - throw new IllegalStateException("This is a static utility class and should not be instantiate directly"); - } - - public static Substitution total(Map map) { - return new MapBasedSubstitution(map, StatelessSubstitution.FAILING); - } - - public static Substitution partial(Map map) { - return new MapBasedSubstitution(map, StatelessSubstitution.IDENTITY); - } - - public static Substitution renewing(Map map) { - return new MapBasedSubstitution(map, renewing()); - } - - public static Substitution renewing() { - return new RenewingSubstitution(); - } - - public static Substitution compose(@Nullable Substitution first, @NotNull Substitution second) { - return first == null ? second : first.andThen(second); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AbstractTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AbstractTerm.java new file mode 100644 index 00000000..d0ae3c12 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AbstractTerm.java @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term; + +import tools.refinery.store.query.equality.LiteralEqualityHelper; + +import java.util.Objects; + +public abstract class AbstractTerm implements Term { + private final Class type; + + protected AbstractTerm(Class type) { + this.type = type; + } + + @Override + public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { + return getClass().equals(other.getClass()) && type.equals(other.getType()); + } + + @Override + public Class getType() { + return type; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AbstractTerm that = (AbstractTerm) o; + return type.equals(that.type); + } + + @Override + public int hashCode() { + return Objects.hash(getClass(), type); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryOperator.java deleted file mode 100644 index 5ff7c65c..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryOperator.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term; - -public enum ArithmeticBinaryOperator { - ADD("+", true), - SUB("-", true), - MUL("*", true), - DIV("/", true), - POW("**", true), - MIN("min", false), - MAX("max", false); - - private final String text; - private final boolean infix; - - ArithmeticBinaryOperator(String text, boolean infix) { - this.text = text; - this.infix = infix; - } - - public String formatString(String left, String right) { - if (infix) { - return "(%s) %s (%s)".formatted(left, text, right); - } - return "%s(%s, %s)".formatted(text, left, right); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryTerm.java deleted file mode 100644 index e405df00..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryTerm.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term; - -import tools.refinery.store.query.equality.LiteralEqualityHelper; - -import java.util.Objects; - -public abstract class ArithmeticBinaryTerm extends BinaryTerm { - private final ArithmeticBinaryOperator operator; - - protected ArithmeticBinaryTerm(ArithmeticBinaryOperator operator, Term left, Term right) { - super(left, right); - this.operator = operator; - } - - @Override - public Class getLeftType() { - return getType(); - } - - @Override - public Class getRightType() { - return getType(); - } - - public ArithmeticBinaryOperator getOperator() { - return operator; - } - - @Override - public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { - if (!super.equalsWithSubstitution(helper, other)) { - return false; - } - var otherArithmeticBinaryTerm = (ArithmeticBinaryTerm) other; - return operator == otherArithmeticBinaryTerm.operator; - } - - @Override - public String toString() { - return operator.formatString(getLeft().toString(), getRight().toString()); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - ArithmeticBinaryTerm that = (ArithmeticBinaryTerm) o; - return operator == that.operator; - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), operator); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryOperator.java deleted file mode 100644 index d98134f3..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryOperator.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term; - -public enum ArithmeticUnaryOperator { - PLUS("+"), - MINUS("-"); - - private final String prefix; - - ArithmeticUnaryOperator(String prefix) { - this.prefix = prefix; - } - - public String formatString(String body) { - return "%s(%s)".formatted(prefix, body); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryTerm.java deleted file mode 100644 index bdc87545..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryTerm.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term; - -import tools.refinery.store.query.equality.LiteralEqualityHelper; - -import java.util.Objects; - -public abstract class ArithmeticUnaryTerm extends UnaryTerm { - private final ArithmeticUnaryOperator operator; - - protected ArithmeticUnaryTerm(ArithmeticUnaryOperator operator, Term body) { - super(body); - this.operator = operator; - } - - @Override - public Class getBodyType() { - return getType(); - } - - public ArithmeticUnaryOperator getOperator() { - return operator; - } - - @Override - public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { - if (!super.equalsWithSubstitution(helper, other)) { - return false; - } - var otherArithmeticUnaryTerm = (ArithmeticUnaryTerm) other; - return operator == otherArithmeticUnaryTerm.operator; - } - - @Override - public String toString() { - return operator.formatString(getBody().toString()); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - ArithmeticUnaryTerm that = (ArithmeticUnaryTerm) o; - return operator == that.operator; - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), operator); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java index b2994d23..8ad17839 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java @@ -14,26 +14,35 @@ import java.util.HashSet; import java.util.Objects; import java.util.Set; -public abstract class BinaryTerm implements Term { +public abstract class BinaryTerm extends AbstractTerm { + private final Class leftType; + private final Class rightType; private final Term left; private final Term right; - protected BinaryTerm(Term left, Term right) { - if (!left.getType().equals(getLeftType())) { - throw new IllegalArgumentException("Expected left %s to be of type %s, got %s instead".formatted(left, - getLeftType().getName(), left.getType().getName())); + protected BinaryTerm(Class type, Class leftType, Class rightType, Term left, Term right) { + super(type); + if (!left.getType().equals(leftType)) { + throw new IllegalArgumentException("Expected left %s to be of type %s, got %s instead".formatted( + left, leftType.getName(), left.getType().getName())); } - if (!right.getType().equals(getRightType())) { - throw new IllegalArgumentException("Expected right %s to be of type %s, got %s instead".formatted(right, - getRightType().getName(), right.getType().getName())); + if (!right.getType().equals(rightType)) { + throw new IllegalArgumentException("Expected right %s to be of type %s, got %s instead".formatted( + right, rightType.getName(), right.getType().getName())); } + this.leftType = leftType; + this.rightType = rightType; this.left = left; this.right = right; } - public abstract Class getLeftType(); + public Class getLeftType() { + return leftType; + } - public abstract Class getRightType(); + public Class getRightType() { + return rightType; + } public Term getLeft() { return left; @@ -60,12 +69,14 @@ public abstract class BinaryTerm implements Term { @Override public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { - if (getClass() != other.getClass()) { + if (!super.equalsWithSubstitution(helper, other)) { return false; } var otherBinaryTerm = (BinaryTerm) other; - return left.equalsWithSubstitution(helper, otherBinaryTerm.left) && right.equalsWithSubstitution(helper, - otherBinaryTerm.right); + return leftType.equals(otherBinaryTerm.leftType) && + rightType.equals(otherBinaryTerm.rightType) && + left.equalsWithSubstitution(helper, otherBinaryTerm.left) && + right.equalsWithSubstitution(helper, otherBinaryTerm.right); } @Override @@ -87,12 +98,16 @@ public abstract class BinaryTerm implements Term { public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; BinaryTerm that = (BinaryTerm) o; - return left.equals(that.left) && right.equals(that.right); + return Objects.equals(leftType, that.leftType) && + Objects.equals(rightType, that.rightType) && + Objects.equals(left, that.left) && + Objects.equals(right, that.right); } @Override public int hashCode() { - return Objects.hash(getClass(), left, right); + return Objects.hash(super.hashCode(), leftType, rightType, left, right); } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonOperator.java deleted file mode 100644 index d04ae22c..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonOperator.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term; - -public enum ComparisonOperator { - EQ("=="), - NOT_EQ("!="), - LESS("<"), - LESS_EQ("<="), - GREATER(">"), - GREATER_EQ(">="); - - private final String text; - - ComparisonOperator(String text) { - this.text = text; - } - - public String formatString(String left, String right) { - return "(%s) %s (%s)".formatted(left, text, right); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonTerm.java deleted file mode 100644 index 2c304aef..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonTerm.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term; - -import tools.refinery.store.query.equality.LiteralEqualityHelper; - -import java.util.Objects; - -public abstract class ComparisonTerm extends BinaryTerm { - private final ComparisonOperator operator; - - protected ComparisonTerm(ComparisonOperator operator, Term left, Term right) { - super(left, right); - this.operator = operator; - } - - @Override - public Class getType() { - return Boolean.class; - } - - public abstract Class getOperandType(); - - @Override - public Class getLeftType() { - return getOperandType(); - } - - @Override - public Class getRightType() { - return getOperandType(); - } - - public ComparisonOperator getOperator() { - return operator; - } - - @Override - public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { - if (!super.equalsWithSubstitution(helper, other)) { - return false; - } - var otherComparisonTerm = (ComparisonTerm) other; - return operator == otherComparisonTerm.operator; - } - - @Override - public String toString() { - return operator.formatString(getLeft().toString(), getRight().toString()); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - ComparisonTerm that = (ComparisonTerm) o; - return operator == that.operator; - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), operator); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java index b03f07fd..2f6c56d1 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java @@ -9,21 +9,18 @@ import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; import tools.refinery.store.query.valuation.Valuation; +import java.util.Objects; import java.util.Set; -public record ConstantTerm(Class type, T value) implements Term { - public ConstantTerm { - if (value == null) { - throw new IllegalArgumentException("value should not be null"); - } - if (!type.isInstance(value)) { - throw new IllegalArgumentException("value %s is not an instance of %s".formatted(value, type.getName())); - } - } +public final class ConstantTerm extends AbstractTerm { + private final T value; - @Override - public Class getType() { - return type; + public ConstantTerm(Class type, T value) { + super(type); + if (value != null && !type.isInstance(value)) { + throw new IllegalArgumentException("Value %s is not an instance of %s".formatted(value, type.getName())); + } + this.value = value; } public T getValue() { @@ -42,7 +39,11 @@ public record ConstantTerm(Class type, T value) implements Term { @Override public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { - return equals(other); + if (!super.equalsWithSubstitution(helper, other)) { + return false; + } + var otherConstantTerm = (ConstantTerm) other; + return Objects.equals(value, otherConstantTerm.value); } @Override @@ -52,6 +53,19 @@ public record ConstantTerm(Class type, T value) implements Term { @Override public String toString() { - return getValue().toString(); + return value.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ConstantTerm that = (ConstantTerm) o; + return Objects.equals(value, that.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/OpaqueTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/OpaqueTerm.java deleted file mode 100644 index 6626365f..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/OpaqueTerm.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term; - -import tools.refinery.store.query.equality.LiteralEqualityHelper; -import tools.refinery.store.query.substitution.Substitution; -import tools.refinery.store.query.substitution.Substitutions; -import tools.refinery.store.query.valuation.Valuation; - -import java.util.Objects; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - -public final class OpaqueTerm implements Term { - private final Class type; - private final Function evaluator; - private final Set variables; - private final Substitution substitution; - - public OpaqueTerm(Class type, Function evaluator, - Set variables) { - this(type, evaluator, variables, null); - } - - private OpaqueTerm(Class type, Function evaluator, - Set variables, Substitution substitution) { - this.type = type; - this.evaluator = evaluator; - this.variables = Set.copyOf(variables); - this.substitution = substitution; - } - - @Override - public Class getType() { - return type; - } - - @Override - public Set getInputVariables() { - return variables; - } - - @Override - public T evaluate(Valuation valuation) { - return evaluator.apply(valuation.substitute(substitution)); - } - - @Override - public Term substitute(Substitution newSubstitution) { - var substitutedVariables = variables.stream() - .map(newSubstitution::getTypeSafeSubstitute) - .collect(Collectors.toUnmodifiableSet()); - return new OpaqueTerm<>(type, evaluator, substitutedVariables, - Substitutions.compose(substitution, newSubstitution)); - } - - @Override - public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { - // Cannot inspect the opaque evaluator for deep equality. - return equals(other); - } - - @Override - public String toString() { - return ""; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - OpaqueTerm that = (OpaqueTerm) o; - return type.equals(that.type) && evaluator.equals(that.evaluator) && Objects.equals(substitution, - that.substitution); - } - - @Override - public int hashCode() { - return Objects.hash(type, evaluator, substitution); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java index 069e0d95..a46ebe31 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java @@ -12,18 +12,23 @@ import tools.refinery.store.query.valuation.Valuation; import java.util.Objects; import java.util.Set; -public abstract class UnaryTerm implements Term { +public abstract class UnaryTerm extends AbstractTerm { + private final Class bodyType; private final Term body; - protected UnaryTerm(Term body) { - if (!body.getType().equals(getBodyType())) { + protected UnaryTerm(Class type, Class bodyType, Term body) { + super(type); + if (!body.getType().equals(bodyType)) { throw new IllegalArgumentException("Expected body %s to be of type %s, got %s instead".formatted(body, - getBodyType().getName(), body.getType().getName())); + bodyType.getName(), body.getType().getName())); } + this.bodyType = bodyType; this.body = body; } - public abstract Class getBodyType(); + public Class getBodyType() { + return bodyType; + } public Term getBody() { return body; @@ -39,11 +44,11 @@ public abstract class UnaryTerm implements Term { @Override public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { - if (getClass() != other.getClass()) { + if (!super.equalsWithSubstitution(helper, other)) { return false; } var otherUnaryTerm = (UnaryTerm) other; - return body.equalsWithSubstitution(helper, otherUnaryTerm.body); + return bodyType.equals(otherUnaryTerm.bodyType) && body.equalsWithSubstitution(helper, otherUnaryTerm.body); } @Override @@ -62,12 +67,13 @@ public abstract class UnaryTerm implements Term { public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; UnaryTerm unaryTerm = (UnaryTerm) o; - return body.equals(unaryTerm.body); + return Objects.equals(bodyType, unaryTerm.bodyType) && Objects.equals(body, unaryTerm.body); } @Override public int hashCode() { - return Objects.hash(getClass(), body); + return Objects.hash(super.hashCode(), bodyType, body); } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolAndTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolAndTerm.java new file mode 100644 index 00000000..f9e1c06f --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolAndTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.bool; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class BoolAndTerm extends BoolBinaryTerm { + public BoolAndTerm(Term left, Term right) { + super(left, right); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new BoolAndTerm(substitutedLeft, substitutedRight); + } + + @Override + protected Boolean doEvaluate(Boolean leftValue, Boolean rightValue) { + return leftValue && rightValue; + } + + @Override + public String toString() { + return "(%s && %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolBinaryTerm.java new file mode 100644 index 00000000..a85aa63a --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolBinaryTerm.java @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.bool; + +import tools.refinery.store.query.term.BinaryTerm; +import tools.refinery.store.query.term.Term; + +public abstract class BoolBinaryTerm extends BinaryTerm { + protected BoolBinaryTerm(Term left, Term right) { + super(Boolean.class, Boolean.class, Boolean.class, left, right); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolConstantTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolConstantTerm.java deleted file mode 100644 index e5690ab6..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolConstantTerm.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term.bool; - -import tools.refinery.store.query.term.ConstantTerm; - -public final class BoolConstantTerm { - public static final ConstantTerm TRUE = new ConstantTerm<>(Boolean.class, true); - public static final ConstantTerm FALSE = new ConstantTerm<>(Boolean.class, false); - - private BoolConstantTerm() { - throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); - } - - public static ConstantTerm valueOf(boolean boolValue) { - return boolValue ? TRUE : FALSE; - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolLogicBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolLogicBinaryTerm.java deleted file mode 100644 index 11e764c2..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolLogicBinaryTerm.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term.bool; - -import tools.refinery.store.query.equality.LiteralEqualityHelper; -import tools.refinery.store.query.substitution.Substitution; -import tools.refinery.store.query.term.*; - -import java.util.Objects; - -public class BoolLogicBinaryTerm extends BinaryTerm { - private final LogicBinaryOperator operator; - - protected BoolLogicBinaryTerm(LogicBinaryOperator operator, Term left, Term right) { - super(left, right); - this.operator = operator; - } - - @Override - public Class getType() { - return Boolean.class; - } - - @Override - public Class getLeftType() { - return getType(); - } - - @Override - public Class getRightType() { - return getType(); - } - - public LogicBinaryOperator getOperator() { - return operator; - } - - @Override - public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { - if (!super.equalsWithSubstitution(helper, other)) { - return false; - } - var otherBoolLogicBinaryTerm = (BoolLogicBinaryTerm) other; - return operator == otherBoolLogicBinaryTerm.operator; - } - - @Override - public Term doSubstitute(Substitution substitution, Term substitutedLeft, - Term substitutedRight) { - return new BoolLogicBinaryTerm(getOperator(), substitutedLeft, substitutedRight); - } - - @Override - protected Boolean doEvaluate(Boolean leftValue, Boolean rightValue) { - return switch (getOperator()) { - case AND -> leftValue && rightValue; - case OR -> leftValue || rightValue; - case XOR -> leftValue ^ rightValue; - }; - } - - @Override - public String toString() { - return operator.formatString(getLeft().toString(), getRight().toString()); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - BoolLogicBinaryTerm that = (BoolLogicBinaryTerm) o; - return operator == that.operator; - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), operator); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java index bb06cf8b..8d3382b3 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java @@ -11,17 +11,7 @@ import tools.refinery.store.query.term.UnaryTerm; public class BoolNotTerm extends UnaryTerm { protected BoolNotTerm(Term body) { - super(body); - } - - @Override - public Class getType() { - return Boolean.class; - } - - @Override - public Class getBodyType() { - return getType(); + super(Boolean.class, Boolean.class, body); } @Override @@ -36,6 +26,6 @@ public class BoolNotTerm extends UnaryTerm { @Override public String toString() { - return "!(%s)".formatted(getBody()); + return "(!%s)".formatted(getBody()); } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolOrTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolOrTerm.java new file mode 100644 index 00000000..b5195d52 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolOrTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.bool; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class BoolOrTerm extends BoolBinaryTerm { + public BoolOrTerm(Term left, Term right) { + super(left, right); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new BoolOrTerm(substitutedLeft, substitutedRight); + } + + @Override + protected Boolean doEvaluate(Boolean leftValue, Boolean rightValue) { + return leftValue || rightValue; + } + + @Override + public String toString() { + return "(%s || %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java index 55825952..fa54f686 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java @@ -13,23 +13,23 @@ public final class BoolTerms { throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly"); } - public static ConstantTerm constant(boolean value) { - return BoolConstantTerm.valueOf(value); + public static Term constant(Boolean value) { + return new ConstantTerm<>(Boolean.class, value); } - public static BoolNotTerm not(Term body) { + public static Term not(Term body) { return new BoolNotTerm(body); } - public static BoolLogicBinaryTerm and(Term left, Term right) { - return new BoolLogicBinaryTerm(LogicBinaryOperator.AND, left, right); + public static Term and(Term left, Term right) { + return new BoolAndTerm(left, right); } - public static BoolLogicBinaryTerm or(Term left, Term right) { - return new BoolLogicBinaryTerm(LogicBinaryOperator.OR, left, right); + public static Term or(Term left, Term right) { + return new BoolOrTerm(left, right); } - public static BoolLogicBinaryTerm xor(Term left, Term right) { - return new BoolLogicBinaryTerm(LogicBinaryOperator.XOR, left, right); + public static Term xor(Term left, Term right) { + return new BoolXorTerm(left, right); } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolXorTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolXorTerm.java new file mode 100644 index 00000000..7478b8a5 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolXorTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.bool; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class BoolXorTerm extends BoolBinaryTerm { + public BoolXorTerm(Term left, Term right) { + super(left, right); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new BoolXorTerm(substitutedLeft, substitutedRight); + } + + @Override + protected Boolean doEvaluate(Boolean leftValue, Boolean rightValue) { + return leftValue ^ rightValue; + } + + @Override + public String toString() { + return "(%s ^^ %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/LogicBinaryOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/LogicBinaryOperator.java deleted file mode 100644 index 93a72f88..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/LogicBinaryOperator.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term.bool; - -public enum LogicBinaryOperator { - AND("&&"), - OR("||"), - XOR("^^"); - - private final String text; - - LogicBinaryOperator(String text) { - this.text = text; - } - - public String formatString(String left, String right) { - return "(%s) %s (%s)".formatted(left, text, right); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/ComparisonTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/ComparisonTerm.java new file mode 100644 index 00000000..5ca5a0a1 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/ComparisonTerm.java @@ -0,0 +1,19 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.comparable; + +import tools.refinery.store.query.term.BinaryTerm; +import tools.refinery.store.query.term.Term; + +public abstract class ComparisonTerm extends BinaryTerm { + protected ComparisonTerm(Class argumentType, Term left, Term right) { + super(Boolean.class, argumentType, argumentType, left, right); + } + + public Class getArgumentType() { + return getLeftType(); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/EqTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/EqTerm.java new file mode 100644 index 00000000..b8cf36f8 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/EqTerm.java @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.comparable; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class EqTerm extends ComparisonTerm { + public EqTerm(Class argumentType, Term left, Term right) { + super(argumentType, left, right); + } + + @Override + protected Boolean doEvaluate(T leftValue, T rightValue) { + return leftValue.equals(rightValue); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, Term substitutedRight) { + return new EqTerm<>(getArgumentType(), substitutedLeft, substitutedRight); + } + + @Override + public String toString() { + return "(%s == %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterEqTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterEqTerm.java new file mode 100644 index 00000000..b109eb1a --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterEqTerm.java @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.comparable; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class GreaterEqTerm> extends ComparisonTerm { + public GreaterEqTerm(Class argumentType, Term left, Term right) { + super(argumentType, left, right); + } + + @Override + protected Boolean doEvaluate(T leftValue, T rightValue) { + return leftValue.compareTo(rightValue) >= 0; + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, Term substitutedRight) { + return new GreaterEqTerm<>(getArgumentType(), substitutedLeft, substitutedRight); + } + + @Override + public String toString() { + return "(%s >= %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterTerm.java new file mode 100644 index 00000000..1b67f8b5 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterTerm.java @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.comparable; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class GreaterTerm> extends ComparisonTerm { + public GreaterTerm(Class argumentType, Term left, Term right) { + super(argumentType, left, right); + } + + @Override + protected Boolean doEvaluate(T leftValue, T rightValue) { + return leftValue.compareTo(rightValue) > 0; + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, Term substitutedRight) { + return new GreaterTerm<>(getArgumentType(), substitutedLeft, substitutedRight); + } + + @Override + public String toString() { + return "(%s > %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessEqTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessEqTerm.java new file mode 100644 index 00000000..1b34535f --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessEqTerm.java @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.comparable; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class LessEqTerm> extends ComparisonTerm { + public LessEqTerm(Class argumentType, Term left, Term right) { + super(argumentType, left, right); + } + + @Override + protected Boolean doEvaluate(T leftValue, T rightValue) { + return leftValue.compareTo(rightValue) <= 0; + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, Term substitutedRight) { + return new LessEqTerm<>(getArgumentType(), substitutedLeft, substitutedRight); + } + + @Override + public String toString() { + return "(%s <= %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessTerm.java new file mode 100644 index 00000000..44e70902 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessTerm.java @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.comparable; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class LessTerm> extends ComparisonTerm { + public LessTerm(Class argumentType, Term left, Term right) { + super(argumentType, left, right); + } + + @Override + protected Boolean doEvaluate(T leftValue, T rightValue) { + return leftValue.compareTo(rightValue) < 0; + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, Term substitutedRight) { + return new LessTerm<>(getArgumentType(), substitutedLeft, substitutedRight); + } + + @Override + public String toString() { + return "(%s < %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/NotEqTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/NotEqTerm.java new file mode 100644 index 00000000..1f9734c4 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/NotEqTerm.java @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.comparable; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class NotEqTerm extends ComparisonTerm { + public NotEqTerm(Class argumentType, Term left, Term right) { + super(argumentType, left, right); + } + + @Override + protected Boolean doEvaluate(T leftValue, T rightValue) { + return !leftValue.equals(rightValue); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, Term substitutedRight) { + return new NotEqTerm<>(getArgumentType(), substitutedLeft, substitutedRight); + } + + @Override + public String toString() { + return "(%s != %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntAddTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntAddTerm.java new file mode 100644 index 00000000..dbea3efc --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntAddTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.int_; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class IntAddTerm extends IntBinaryTerm { + public IntAddTerm(Term left, Term right) { + super(left, right); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new IntAddTerm(substitutedLeft, substitutedRight); + } + + @Override + protected Integer doEvaluate(Integer leftValue, Integer rightValue) { + return leftValue + rightValue; + } + + @Override + public String toString() { + return "(%s + %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticBinaryTerm.java deleted file mode 100644 index 8a76ecbd..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticBinaryTerm.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term.int_; - -import tools.refinery.store.query.substitution.Substitution; -import tools.refinery.store.query.term.ArithmeticBinaryOperator; -import tools.refinery.store.query.term.ArithmeticBinaryTerm; -import tools.refinery.store.query.term.Term; - -public class IntArithmeticBinaryTerm extends ArithmeticBinaryTerm { - public IntArithmeticBinaryTerm(ArithmeticBinaryOperator operator, Term left, Term right) { - super(operator, left, right); - } - - @Override - public Class getType() { - return Integer.class; - } - - @Override - public Term doSubstitute(Substitution substitution, Term substitutedLeft, - Term substitutedRight) { - return new IntArithmeticBinaryTerm(getOperator(), substitutedLeft, substitutedRight); - } - - @Override - protected Integer doEvaluate(Integer leftValue, Integer rightValue) { - return switch (getOperator()) { - case ADD -> leftValue + rightValue; - case SUB -> leftValue - rightValue; - case MUL -> leftValue * rightValue; - case DIV -> rightValue == 0 ? null : leftValue / rightValue; - case POW -> rightValue < 0 ? null : power(leftValue, rightValue); - case MIN -> Math.min(leftValue, rightValue); - case MAX -> Math.max(leftValue, rightValue); - }; - } - - private static int power(int base, int exponent) { - int accum = 1; - while (exponent > 0) { - if (exponent % 2 == 1) { - accum = accum * base; - } - base = base * base; - exponent = exponent / 2; - } - return accum; - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticUnaryTerm.java deleted file mode 100644 index 8522f2c1..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticUnaryTerm.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term.int_; - -import tools.refinery.store.query.substitution.Substitution; -import tools.refinery.store.query.term.Term; -import tools.refinery.store.query.term.ArithmeticUnaryOperator; -import tools.refinery.store.query.term.ArithmeticUnaryTerm; - -public class IntArithmeticUnaryTerm extends ArithmeticUnaryTerm { - public IntArithmeticUnaryTerm(ArithmeticUnaryOperator operation, Term body) { - super(operation, body); - } - - @Override - public Class getType() { - return Integer.class; - } - - @Override - protected Term doSubstitute(Substitution substitution, Term substitutedBody) { - return new IntArithmeticUnaryTerm(getOperator(), substitutedBody); - } - - @Override - protected Integer doEvaluate(Integer bodyValue) { - return switch(getOperator()) { - case PLUS -> bodyValue; - case MINUS -> -bodyValue; - }; - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntBinaryTerm.java new file mode 100644 index 00000000..27ced4e4 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntBinaryTerm.java @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.int_; + +import tools.refinery.store.query.term.BinaryTerm; +import tools.refinery.store.query.term.Term; + +public abstract class IntBinaryTerm extends BinaryTerm { + protected IntBinaryTerm(Term left, Term right) { + super(Integer.class, Integer.class, Integer.class, left, right); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntComparisonTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntComparisonTerm.java deleted file mode 100644 index 2ce2b2f3..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntComparisonTerm.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term.int_; -import tools.refinery.store.query.substitution.Substitution; -import tools.refinery.store.query.term.ComparisonOperator; -import tools.refinery.store.query.term.ComparisonTerm; -import tools.refinery.store.query.term.Term; - -public class IntComparisonTerm extends ComparisonTerm { - public IntComparisonTerm(ComparisonOperator operator, Term left, Term right) { - super(operator, left, right); - } - - @Override - public Class getOperandType() { - return Integer.class; - } - - @Override - public Term doSubstitute(Substitution substitution, Term substitutedLeft, - Term substitutedRight) { - return new IntComparisonTerm(getOperator(), substitutedLeft, substitutedRight); - } - - @Override - protected Boolean doEvaluate(Integer leftValue, Integer rightValue) { - return switch (getOperator()) { - case EQ -> leftValue.equals(rightValue); - case NOT_EQ -> !leftValue.equals(rightValue); - case LESS -> leftValue < rightValue; - case LESS_EQ -> leftValue <= rightValue; - case GREATER -> leftValue > rightValue; - case GREATER_EQ -> leftValue >= rightValue; - }; - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntDivTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntDivTerm.java new file mode 100644 index 00000000..2a35058c --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntDivTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.int_; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class IntDivTerm extends IntBinaryTerm { + public IntDivTerm(Term left, Term right) { + super(left, right); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new IntDivTerm(substitutedLeft, substitutedRight); + } + + @Override + protected Integer doEvaluate(Integer leftValue, Integer rightValue) { + return rightValue == 0 ? null : leftValue / rightValue; + } + + @Override + public String toString() { + return "(%s / %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntExtremeValueAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntExtremeValueAggregator.java deleted file mode 100644 index 7982f45c..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntExtremeValueAggregator.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term.int_; - -import tools.refinery.store.query.term.ExtremeValueAggregator; - -import java.util.Comparator; - -public final class IntExtremeValueAggregator { - public static final ExtremeValueAggregator MINIMUM = new ExtremeValueAggregator<>(Integer.class, - Integer.MAX_VALUE); - - public static final ExtremeValueAggregator MAXIMUM = new ExtremeValueAggregator<>(Integer.class, - Integer.MIN_VALUE, Comparator.reverseOrder()); - - private IntExtremeValueAggregator() { - throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMaxTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMaxTerm.java new file mode 100644 index 00000000..f81fc509 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMaxTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.int_; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class IntMaxTerm extends IntBinaryTerm { + public IntMaxTerm(Term left, Term right) { + super(left, right); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new IntMaxTerm(substitutedLeft, substitutedRight); + } + + @Override + protected Integer doEvaluate(Integer leftValue, Integer rightValue) { + return Math.max(rightValue, leftValue); + } + + @Override + public String toString() { + return "max(%s, %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinTerm.java new file mode 100644 index 00000000..89182e26 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.int_; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class IntMinTerm extends IntBinaryTerm { + public IntMinTerm(Term left, Term right) { + super(left, right); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new IntMinTerm(substitutedLeft, substitutedRight); + } + + @Override + protected Integer doEvaluate(Integer leftValue, Integer rightValue) { + return Math.min(rightValue, leftValue); + } + + @Override + public String toString() { + return "min(%s, %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinusTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinusTerm.java new file mode 100644 index 00000000..709aa5ba --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinusTerm.java @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.int_; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class IntMinusTerm extends IntUnaryTerm { + public IntMinusTerm(Term body) { + super(body); + } + + @Override + protected Term doSubstitute(Substitution substitution, Term substitutedBody) { + return new IntMinusTerm(substitutedBody); + } + + @Override + protected Integer doEvaluate(Integer bodyValue) { + return -bodyValue; + } + + @Override + public String toString() { + return "(-%s)".formatted(getBody()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMulTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMulTerm.java new file mode 100644 index 00000000..89d4c5f4 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMulTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.int_; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class IntMulTerm extends IntBinaryTerm { + public IntMulTerm(Term left, Term right) { + super(left, right); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new IntMulTerm(substitutedLeft, substitutedRight); + } + + @Override + protected Integer doEvaluate(Integer leftValue, Integer rightValue) { + return leftValue * rightValue; + } + + @Override + public String toString() { + return "(%s * %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPlusTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPlusTerm.java new file mode 100644 index 00000000..aef83bb4 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPlusTerm.java @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.int_; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class IntPlusTerm extends IntUnaryTerm { + public IntPlusTerm(Term body) { + super(body); + } + + @Override + protected Term doSubstitute(Substitution substitution, Term substitutedBody) { + return new IntPlusTerm(substitutedBody); + } + + @Override + protected Integer doEvaluate(Integer bodyValue) { + return bodyValue; + } + + @Override + public String toString() { + return "(+%s)".formatted(getBody()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPowTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPowTerm.java new file mode 100644 index 00000000..d5af97a1 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPowTerm.java @@ -0,0 +1,43 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.int_; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class IntPowTerm extends IntBinaryTerm { + public IntPowTerm(Term left, Term right) { + super(left, right); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new IntPowTerm(substitutedLeft, substitutedRight); + } + + @Override + protected Integer doEvaluate(Integer leftValue, Integer rightValue) { + return rightValue < 0 ? null : power(leftValue, rightValue); + } + + private static int power(int base, int exponent) { + int accum = 1; + while (exponent > 0) { + if (exponent % 2 == 1) { + accum = accum * base; + } + base = base * base; + exponent = exponent / 2; + } + return accum; + } + + @Override + public String toString() { + return "(%s ** %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSubTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSubTerm.java new file mode 100644 index 00000000..2c27afb1 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSubTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.int_; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class IntSubTerm extends IntBinaryTerm { + public IntSubTerm(Term left, Term right) { + super(left, right); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new IntSubTerm(substitutedLeft, substitutedRight); + } + + @Override + protected Integer doEvaluate(Integer leftValue, Integer rightValue) { + return leftValue - rightValue; + } + + @Override + public String toString() { + return "(%s - %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java index 38f7f449..acb98b94 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java @@ -5,82 +5,90 @@ */ package tools.refinery.store.query.term.int_; -import tools.refinery.store.query.term.*; +import tools.refinery.store.query.term.Aggregator; +import tools.refinery.store.query.term.ConstantTerm; +import tools.refinery.store.query.term.ExtremeValueAggregator; +import tools.refinery.store.query.term.Term; +import tools.refinery.store.query.term.comparable.*; + +import java.util.Comparator; public final class IntTerms { public static final Aggregator INT_SUM = IntSumAggregator.INSTANCE; - public static final Aggregator INT_MIN = IntExtremeValueAggregator.MINIMUM; - public static final Aggregator INT_MAX = IntExtremeValueAggregator.MAXIMUM; + public static final Aggregator INT_MIN = new ExtremeValueAggregator<>(Integer.class, + Integer.MAX_VALUE); + public static final Aggregator INT_MAX = new ExtremeValueAggregator<>(Integer.class, + Integer.MIN_VALUE, Comparator.reverseOrder()); private IntTerms() { throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly"); } - public static ConstantTerm constant(int value) { + public static Term constant(Integer value) { return new ConstantTerm<>(Integer.class, value); } - public static IntArithmeticUnaryTerm plus(Term body) { - return new IntArithmeticUnaryTerm(ArithmeticUnaryOperator.PLUS, body); + public static Term plus(Term body) { + return new IntPlusTerm(body); } - public static IntArithmeticUnaryTerm minus(Term body) { - return new IntArithmeticUnaryTerm(ArithmeticUnaryOperator.MINUS, body); + public static Term minus(Term body) { + return new IntMinusTerm(body); } - public static IntArithmeticBinaryTerm add(Term left, Term right) { - return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.ADD, left, right); + public static Term add(Term left, Term right) { + return new IntAddTerm(left, right); } - public static IntArithmeticBinaryTerm sub(Term left, Term right) { - return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.SUB, left, right); + public static Term sub(Term left, Term right) { + return new IntSubTerm(left, right); } - public static IntArithmeticBinaryTerm mul(Term left, Term right) { - return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.MUL, left, right); + public static Term mul(Term left, Term right) { + return new IntMulTerm(left, right); } - public static IntArithmeticBinaryTerm div(Term left, Term right) { - return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.DIV, left, right); + public static Term div(Term left, Term right) { + return new IntDivTerm(left, right); } - public static IntArithmeticBinaryTerm pow(Term left, Term right) { - return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.POW, left, right); + public static Term pow(Term left, Term right) { + return new IntPowTerm(left, right); } - public static IntArithmeticBinaryTerm min(Term left, Term right) { - return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.MIN, left, right); + public static Term min(Term left, Term right) { + return new IntMinTerm(left, right); } - public static IntArithmeticBinaryTerm max(Term left, Term right) { - return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.MAX, left, right); + public static Term max(Term left, Term right) { + return new IntMaxTerm(left, right); } - public static IntComparisonTerm eq(Term left, Term right) { - return new IntComparisonTerm(ComparisonOperator.EQ, left, right); + public static Term eq(Term left, Term right) { + return new EqTerm<>(Integer.class, left, right); } - public static IntComparisonTerm notEq(Term left, Term right) { - return new IntComparisonTerm(ComparisonOperator.NOT_EQ, left, right); + public static Term notEq(Term left, Term right) { + return new NotEqTerm<>(Integer.class, left, right); } - public static IntComparisonTerm less(Term left, Term right) { - return new IntComparisonTerm(ComparisonOperator.LESS, left, right); + public static Term less(Term left, Term right) { + return new LessTerm<>(Integer.class, left, right); } - public static IntComparisonTerm lessEq(Term left, Term right) { - return new IntComparisonTerm(ComparisonOperator.LESS_EQ, left, right); + public static Term lessEq(Term left, Term right) { + return new LessEqTerm<>(Integer.class, left, right); } - public static IntComparisonTerm greater(Term left, Term right) { - return new IntComparisonTerm(ComparisonOperator.GREATER, left, right); + public static Term greater(Term left, Term right) { + return new GreaterTerm<>(Integer.class, left, right); } - public static IntComparisonTerm greaterEq(Term left, Term right) { - return new IntComparisonTerm(ComparisonOperator.GREATER_EQ, left, right); + public static Term greaterEq(Term left, Term right) { + return new GreaterEqTerm<>(Integer.class, left, right); } - public static RealToIntTerm asInt(Term body) { + public static Term asInt(Term body) { return new RealToIntTerm(body); } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntUnaryTerm.java new file mode 100644 index 00000000..49b4c647 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntUnaryTerm.java @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.int_; + +import tools.refinery.store.query.term.Term; +import tools.refinery.store.query.term.UnaryTerm; + +public abstract class IntUnaryTerm extends UnaryTerm { + protected IntUnaryTerm(Term body) { + super(Integer.class, Integer.class, body); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java index 399adf4a..7d383562 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java @@ -11,22 +11,12 @@ import tools.refinery.store.query.term.UnaryTerm; public class RealToIntTerm extends UnaryTerm { protected RealToIntTerm(Term body) { - super(body); - } - - @Override - public Class getType() { - return Integer.class; - } - - @Override - public Class getBodyType() { - return Double.class; + super(Integer.class, Double.class, body); } @Override protected Integer doEvaluate(Double bodyValue) { - return bodyValue.intValue(); + return bodyValue.isNaN() ? null : bodyValue.intValue(); } @Override @@ -36,6 +26,6 @@ public class RealToIntTerm extends UnaryTerm { @Override public String toString() { - return "(%s) as int".formatted(getBody()); + return "(%s as int)".formatted(getBody()); } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java index 4f7d5687..2f53117a 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java @@ -11,17 +11,7 @@ import tools.refinery.store.query.term.UnaryTerm; public class IntToRealTerm extends UnaryTerm { protected IntToRealTerm(Term body) { - super(body); - } - - @Override - public Class getType() { - return Double.class; - } - - @Override - public Class getBodyType() { - return Integer.class; + super(Double.class, Integer.class, body); } @Override @@ -36,6 +26,6 @@ public class IntToRealTerm extends UnaryTerm { @Override public String toString() { - return "(%s) as real".formatted(getBody()); + return "(%s as real)".formatted(getBody()); } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealAddTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealAddTerm.java new file mode 100644 index 00000000..33fc9e41 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealAddTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.real; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class RealAddTerm extends RealBinaryTerm { + public RealAddTerm(Term left, Term right) { + super(left, right); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new RealAddTerm(substitutedLeft, substitutedRight); + } + + @Override + protected Double doEvaluate(Double leftValue, Double rightValue) { + return leftValue + rightValue; + } + + @Override + public String toString() { + return "(%s + %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticBinaryTerm.java deleted file mode 100644 index 8d5c9242..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticBinaryTerm.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term.real; - -import tools.refinery.store.query.substitution.Substitution; -import tools.refinery.store.query.term.ArithmeticBinaryOperator; -import tools.refinery.store.query.term.ArithmeticBinaryTerm; -import tools.refinery.store.query.term.Term; - -public class RealArithmeticBinaryTerm extends ArithmeticBinaryTerm { - public RealArithmeticBinaryTerm(ArithmeticBinaryOperator operator, Term left, Term right) { - super(operator, left, right); - } - - @Override - public Class getType() { - return Double.class; - } - - @Override - public Term doSubstitute(Substitution substitution, Term substitutedLeft, - Term substitutedRight) { - return new RealArithmeticBinaryTerm(getOperator(), substitutedLeft, substitutedRight); - } - - @Override - protected Double doEvaluate(Double leftValue, Double rightValue) { - return switch (getOperator()) { - case ADD -> leftValue + rightValue; - case SUB -> leftValue - rightValue; - case MUL -> leftValue * rightValue; - case DIV -> leftValue / rightValue; - case POW -> Math.pow(leftValue, rightValue); - case MIN -> Math.min(leftValue, rightValue); - case MAX -> Math.max(leftValue, rightValue); - }; - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticUnaryTerm.java deleted file mode 100644 index 9d233dfc..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticUnaryTerm.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term.real; - -import tools.refinery.store.query.substitution.Substitution; -import tools.refinery.store.query.term.ArithmeticUnaryOperator; -import tools.refinery.store.query.term.ArithmeticUnaryTerm; -import tools.refinery.store.query.term.Term; - -public class RealArithmeticUnaryTerm extends ArithmeticUnaryTerm { - public RealArithmeticUnaryTerm(ArithmeticUnaryOperator operation, Term body) { - super(operation, body); - } - - @Override - public Class getType() { - return Double.class; - } - - @Override - protected Term doSubstitute(Substitution substitution, Term substitutedBody) { - return new RealArithmeticUnaryTerm(getOperator(), substitutedBody); - } - - @Override - protected Double doEvaluate(Double bodyValue) { - return switch(getOperator()) { - case PLUS -> bodyValue; - case MINUS -> -bodyValue; - }; - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealBinaryTerm.java new file mode 100644 index 00000000..000f3623 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealBinaryTerm.java @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.real; + +import tools.refinery.store.query.term.BinaryTerm; +import tools.refinery.store.query.term.Term; + +public abstract class RealBinaryTerm extends BinaryTerm { + protected RealBinaryTerm(Term left, Term right) { + super(Double.class, Double.class, Double.class, left, right); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealComparisonTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealComparisonTerm.java deleted file mode 100644 index 25c88f89..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealComparisonTerm.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term.real; - -import tools.refinery.store.query.substitution.Substitution; -import tools.refinery.store.query.term.ComparisonOperator; -import tools.refinery.store.query.term.ComparisonTerm; -import tools.refinery.store.query.term.Term; - -public class RealComparisonTerm extends ComparisonTerm { - public RealComparisonTerm(ComparisonOperator operator, Term left, Term right) { - super(operator, left, right); - } - - @Override - public Class getOperandType() { - return Double.class; - } - - @Override - public Term doSubstitute(Substitution substitution, Term substitutedLeft, - Term substitutedRight) { - return new RealComparisonTerm(getOperator(), substitutedLeft, substitutedRight); - } - - @Override - protected Boolean doEvaluate(Double leftValue, Double rightValue) { - return switch (getOperator()) { - case EQ -> leftValue.equals(rightValue); - case NOT_EQ -> !leftValue.equals(rightValue); - case LESS -> leftValue < rightValue; - case LESS_EQ -> leftValue <= rightValue; - case GREATER -> leftValue > rightValue; - case GREATER_EQ -> leftValue >= rightValue; - }; - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealDivTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealDivTerm.java new file mode 100644 index 00000000..1e55bf42 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealDivTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.real; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class RealDivTerm extends RealBinaryTerm { + public RealDivTerm(Term left, Term right) { + super(left, right); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new RealDivTerm(substitutedLeft, substitutedRight); + } + + @Override + protected Double doEvaluate(Double leftValue, Double rightValue) { + return leftValue / rightValue; + } + + @Override + public String toString() { + return "(%s / %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealExtremeValueAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealExtremeValueAggregator.java deleted file mode 100644 index 526e643b..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealExtremeValueAggregator.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term.real; - -import tools.refinery.store.query.term.ExtremeValueAggregator; - -import java.util.Comparator; - -public final class RealExtremeValueAggregator { - public static final ExtremeValueAggregator MINIMUM = new ExtremeValueAggregator<>(Double.class, - Double.POSITIVE_INFINITY); - - public static final ExtremeValueAggregator MAXIMUM = new ExtremeValueAggregator<>(Double.class, - Double.NEGATIVE_INFINITY, Comparator.reverseOrder()); - - private RealExtremeValueAggregator() { - throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMaxTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMaxTerm.java new file mode 100644 index 00000000..2a249496 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMaxTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.real; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class RealMaxTerm extends RealBinaryTerm { + public RealMaxTerm(Term left, Term right) { + super(left, right); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new RealMaxTerm(substitutedLeft, substitutedRight); + } + + @Override + protected Double doEvaluate(Double leftValue, Double rightValue) { + return Math.max(leftValue, rightValue); + } + + @Override + public String toString() { + return "max(%s, %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinTerm.java new file mode 100644 index 00000000..2eb4cc1e --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.real; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class RealMinTerm extends RealBinaryTerm { + public RealMinTerm(Term left, Term right) { + super(left, right); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new RealMinTerm(substitutedLeft, substitutedRight); + } + + @Override + protected Double doEvaluate(Double leftValue, Double rightValue) { + return Math.min(leftValue, rightValue); + } + + @Override + public String toString() { + return "min(%s, %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinusTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinusTerm.java new file mode 100644 index 00000000..4afec7a1 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinusTerm.java @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.real; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class RealMinusTerm extends RealUnaryTerm { + public RealMinusTerm(Term body) { + super(body); + } + + @Override + protected Term doSubstitute(Substitution substitution, Term substitutedBody) { + return new RealMinusTerm(substitutedBody); + } + + @Override + protected Double doEvaluate(Double bodyValue) { + return -bodyValue; + } + + @Override + public String toString() { + return "(-%s)".formatted(getBody()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMulTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMulTerm.java new file mode 100644 index 00000000..ec95ac6f --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMulTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.real; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class RealMulTerm extends RealBinaryTerm { + public RealMulTerm(Term left, Term right) { + super(left, right); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new RealMulTerm(substitutedLeft, substitutedRight); + } + + @Override + protected Double doEvaluate(Double leftValue, Double rightValue) { + return leftValue * rightValue; + } + + @Override + public String toString() { + return "(%s * %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPlusTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPlusTerm.java new file mode 100644 index 00000000..64dd2e70 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPlusTerm.java @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.real; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class RealPlusTerm extends RealUnaryTerm { + public RealPlusTerm(Term body) { + super(body); + } + + @Override + protected Term doSubstitute(Substitution substitution, Term substitutedBody) { + return new RealPlusTerm(substitutedBody); + } + + @Override + protected Double doEvaluate(Double bodyValue) { + return bodyValue; + } + + @Override + public String toString() { + return "(+%s)".formatted(getBody()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPowTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPowTerm.java new file mode 100644 index 00000000..11c952ea --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPowTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.real; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class RealPowTerm extends RealBinaryTerm { + public RealPowTerm(Term left, Term right) { + super(left, right); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new RealPowTerm(substitutedLeft, substitutedRight); + } + + @Override + protected Double doEvaluate(Double leftValue, Double rightValue) { + return Math.pow(leftValue, rightValue); + } + + @Override + public String toString() { + return "(%s ** %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSubTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSubTerm.java new file mode 100644 index 00000000..8cc701ed --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSubTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.real; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; + +public class RealSubTerm extends RealBinaryTerm { + public RealSubTerm(Term left, Term right) { + super(left, right); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, + Term substitutedRight) { + return new RealSubTerm(substitutedLeft, substitutedRight); + } + + @Override + protected Double doEvaluate(Double leftValue, Double rightValue) { + return leftValue - rightValue; + } + + @Override + public String toString() { + return "(%s - %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java index 1240d478..79220358 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java @@ -5,82 +5,90 @@ */ package tools.refinery.store.query.term.real; -import tools.refinery.store.query.term.*; +import tools.refinery.store.query.term.Aggregator; +import tools.refinery.store.query.term.ConstantTerm; +import tools.refinery.store.query.term.ExtremeValueAggregator; +import tools.refinery.store.query.term.Term; +import tools.refinery.store.query.term.comparable.*; + +import java.util.Comparator; public final class RealTerms { public static final Aggregator REAL_SUM = RealSumAggregator.INSTANCE; - public static final Aggregator REAL_MIN = RealExtremeValueAggregator.MINIMUM; - public static final Aggregator REAL_MAX = RealExtremeValueAggregator.MAXIMUM; + public static final Aggregator REAL_MIN = new ExtremeValueAggregator<>(Double.class, + Double.POSITIVE_INFINITY); + public static final Aggregator REAL_MAX = new ExtremeValueAggregator<>(Double.class, + Double.NEGATIVE_INFINITY, Comparator.reverseOrder()); private RealTerms() { throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly"); } - public static ConstantTerm constant(double value) { + public static Term constant(Double value) { return new ConstantTerm<>(Double.class, value); } - public static RealArithmeticUnaryTerm plus(Term body) { - return new RealArithmeticUnaryTerm(ArithmeticUnaryOperator.PLUS, body); + public static Term plus(Term body) { + return new RealPlusTerm(body); } - public static RealArithmeticUnaryTerm minus(Term body) { - return new RealArithmeticUnaryTerm(ArithmeticUnaryOperator.MINUS, body); + public static Term minus(Term body) { + return new RealMinusTerm(body); } - public static RealArithmeticBinaryTerm add(Term left, Term right) { - return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.ADD, left, right); + public static Term add(Term left, Term right) { + return new RealAddTerm(left, right); } - public static RealArithmeticBinaryTerm sub(Term left, Term right) { - return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.SUB, left, right); + public static Term sub(Term left, Term right) { + return new RealSubTerm(left, right); } - public static RealArithmeticBinaryTerm mul(Term left, Term right) { - return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.MUL, left, right); + public static Term mul(Term left, Term right) { + return new RealMulTerm(left, right); } - public static RealArithmeticBinaryTerm div(Term left, Term right) { - return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.DIV, left, right); + public static Term div(Term left, Term right) { + return new RealDivTerm(left, right); } - public static RealArithmeticBinaryTerm pow(Term left, Term right) { - return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.POW, left, right); + public static Term pow(Term left, Term right) { + return new RealPowTerm(left, right); } - public static RealArithmeticBinaryTerm min(Term left, Term right) { - return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.MIN, left, right); + public static Term min(Term left, Term right) { + return new RealMinTerm(left, right); } - public static RealArithmeticBinaryTerm max(Term left, Term right) { - return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.MAX, left, right); + public static Term max(Term left, Term right) { + return new RealMaxTerm(left, right); } - public static RealComparisonTerm eq(Term left, Term right) { - return new RealComparisonTerm(ComparisonOperator.EQ, left, right); + public static Term eq(Term left, Term right) { + return new EqTerm<>(Double.class, left, right); } - public static RealComparisonTerm notEq(Term left, Term right) { - return new RealComparisonTerm(ComparisonOperator.NOT_EQ, left, right); + public static Term notEq(Term left, Term right) { + return new NotEqTerm<>(Double.class, left, right); } - public static RealComparisonTerm less(Term left, Term right) { - return new RealComparisonTerm(ComparisonOperator.LESS, left, right); + public static Term less(Term left, Term right) { + return new LessTerm<>(Double.class, left, right); } - public static RealComparisonTerm lessEq(Term left, Term right) { - return new RealComparisonTerm(ComparisonOperator.LESS_EQ, left, right); + public static Term lessEq(Term left, Term right) { + return new LessEqTerm<>(Double.class, left, right); } - public static RealComparisonTerm greater(Term left, Term right) { - return new RealComparisonTerm(ComparisonOperator.GREATER, left, right); + public static Term greater(Term left, Term right) { + return new GreaterTerm<>(Double.class, left, right); } - public static RealComparisonTerm greaterEq(Term left, Term right) { - return new RealComparisonTerm(ComparisonOperator.GREATER_EQ, left, right); + public static Term greaterEq(Term left, Term right) { + return new GreaterEqTerm<>(Double.class, left, right); } - public static IntToRealTerm asReal(Term body) { + public static Term asReal(Term body) { return new IntToRealTerm(body); } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealUnaryTerm.java new file mode 100644 index 00000000..d41c4ed9 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealUnaryTerm.java @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.real; + +import tools.refinery.store.query.term.Term; +import tools.refinery.store.query.term.UnaryTerm; + +public abstract class RealUnaryTerm extends UnaryTerm { + protected RealUnaryTerm(Term body) { + super(Double.class, Double.class, body); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityAddTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityAddTerm.java new file mode 100644 index 00000000..68905f51 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityAddTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.uppercardinality; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; +import tools.refinery.store.representation.cardinality.UpperCardinality; + +public class UpperCardinalityAddTerm extends UpperCardinalityBinaryTerm { + protected UpperCardinalityAddTerm(Term left, Term right) { + super(left, right); + } + + @Override + protected UpperCardinality doEvaluate(UpperCardinality leftValue, UpperCardinality rightValue) { + return leftValue.add(rightValue); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, Term substitutedRight) { + return new UpperCardinalityAddTerm(substitutedLeft, substitutedRight); + } + + @Override + public String toString() { + return "(%s + %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityBinaryTerm.java new file mode 100644 index 00000000..0cf8fe44 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityBinaryTerm.java @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.uppercardinality; + +import tools.refinery.store.query.term.BinaryTerm; +import tools.refinery.store.query.term.Term; +import tools.refinery.store.representation.cardinality.UpperCardinality; + +public abstract class UpperCardinalityBinaryTerm extends BinaryTerm { + protected UpperCardinalityBinaryTerm(Term left, Term right) { + super(UpperCardinality.class, UpperCardinality.class, UpperCardinality.class, left, right); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMaxTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMaxTerm.java new file mode 100644 index 00000000..ff75f64e --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMaxTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.uppercardinality; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; +import tools.refinery.store.representation.cardinality.UpperCardinality; + +public class UpperCardinalityMaxTerm extends UpperCardinalityBinaryTerm { + protected UpperCardinalityMaxTerm(Term left, Term right) { + super(left, right); + } + + @Override + protected UpperCardinality doEvaluate(UpperCardinality leftValue, UpperCardinality rightValue) { + return leftValue.max(rightValue); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, Term substitutedRight) { + return new UpperCardinalityMaxTerm(substitutedLeft, substitutedRight); + } + + @Override + public String toString() { + return "max(%s, %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMinTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMinTerm.java new file mode 100644 index 00000000..1e89e9f4 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMinTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.uppercardinality; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; +import tools.refinery.store.representation.cardinality.UpperCardinality; + +public class UpperCardinalityMinTerm extends UpperCardinalityBinaryTerm { + protected UpperCardinalityMinTerm(Term left, Term right) { + super(left, right); + } + + @Override + protected UpperCardinality doEvaluate(UpperCardinality leftValue, UpperCardinality rightValue) { + return leftValue.min(rightValue); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, Term substitutedRight) { + return new UpperCardinalityMinTerm(substitutedLeft, substitutedRight); + } + + @Override + public String toString() { + return "min(%s, %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMulTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMulTerm.java new file mode 100644 index 00000000..3b4970f4 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMulTerm.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.uppercardinality; + +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Term; +import tools.refinery.store.representation.cardinality.UpperCardinality; + +public class UpperCardinalityMulTerm extends UpperCardinalityBinaryTerm { + protected UpperCardinalityMulTerm(Term left, Term right) { + super(left, right); + } + + @Override + protected UpperCardinality doEvaluate(UpperCardinality leftValue, UpperCardinality rightValue) { + return leftValue.multiply(rightValue); + } + + @Override + public Term doSubstitute(Substitution substitution, Term substitutedLeft, Term substitutedRight) { + return new UpperCardinalityMulTerm(substitutedLeft, substitutedRight); + } + + @Override + public String toString() { + return "(%s * %s)".formatted(getLeft(), getRight()); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregator.java new file mode 100644 index 00000000..5bbd3081 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregator.java @@ -0,0 +1,86 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.uppercardinality; + +import tools.refinery.store.query.term.StatefulAggregate; +import tools.refinery.store.query.term.StatefulAggregator; +import tools.refinery.store.representation.cardinality.FiniteUpperCardinality; +import tools.refinery.store.representation.cardinality.UnboundedUpperCardinality; +import tools.refinery.store.representation.cardinality.UpperCardinalities; +import tools.refinery.store.representation.cardinality.UpperCardinality; + +public class UpperCardinalitySumAggregator implements StatefulAggregator { + public static final UpperCardinalitySumAggregator INSTANCE = new UpperCardinalitySumAggregator(); + + private UpperCardinalitySumAggregator() { + } + + @Override + public Class getResultType() { + return UpperCardinality.class; + } + + @Override + public Class getInputType() { + return UpperCardinality.class; + } + + @Override + public StatefulAggregate createEmptyAggregate() { + return new Aggregate(); + } + + private static class Aggregate implements StatefulAggregate { + private int sumFiniteUpperBounds; + private int countUnbounded; + + public Aggregate() { + this(0, 0); + } + + private Aggregate(int sumFiniteUpperBounds, int countUnbounded) { + this.sumFiniteUpperBounds = sumFiniteUpperBounds; + this.countUnbounded = countUnbounded; + } + + @Override + public void add(UpperCardinality value) { + if (value instanceof FiniteUpperCardinality finiteUpperCardinality) { + sumFiniteUpperBounds += finiteUpperCardinality.finiteUpperBound(); + } else if (value instanceof UnboundedUpperCardinality) { + countUnbounded += 1; + } else { + throw new IllegalArgumentException("Unknown UpperCardinality: " + value); + } + } + + @Override + public void remove(UpperCardinality value) { + if (value instanceof FiniteUpperCardinality finiteUpperCardinality) { + sumFiniteUpperBounds -= finiteUpperCardinality.finiteUpperBound(); + } else if (value instanceof UnboundedUpperCardinality) { + countUnbounded -= 1; + } else { + throw new IllegalArgumentException("Unknown UpperCardinality: " + value); + } + } + + @Override + public UpperCardinality getResult() { + return countUnbounded > 0 ? UpperCardinalities.UNBOUNDED : UpperCardinalities.valueOf(sumFiniteUpperBounds); + } + + @Override + public boolean isEmpty() { + return sumFiniteUpperBounds == 0 && countUnbounded == 0; + } + + @Override + public StatefulAggregate deepCopy() { + return new Aggregate(sumFiniteUpperBounds, countUnbounded); + } + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTerms.java new file mode 100644 index 00000000..13914f2d --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTerms.java @@ -0,0 +1,73 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.uppercardinality; + +import tools.refinery.store.query.term.Aggregator; +import tools.refinery.store.query.term.ConstantTerm; +import tools.refinery.store.query.term.ExtremeValueAggregator; +import tools.refinery.store.query.term.Term; +import tools.refinery.store.query.term.comparable.*; +import tools.refinery.store.representation.cardinality.UpperCardinalities; +import tools.refinery.store.representation.cardinality.UpperCardinality; + +import java.util.Comparator; + +public final class UpperCardinalityTerms { + public static final Aggregator UPPER_CARDINALITY_SUM = + UpperCardinalitySumAggregator.INSTANCE; + public static final Aggregator UPPER_CARDINALITY_MIN = + new ExtremeValueAggregator<>(UpperCardinality.class, UpperCardinalities.UNBOUNDED); + public static final Aggregator UPPER_CARDINALITY_MAX = + new ExtremeValueAggregator<>(UpperCardinality.class, UpperCardinalities.ZERO, Comparator.reverseOrder()); + + private UpperCardinalityTerms() { + throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); + } + + public static Term constant(UpperCardinality value) { + return new ConstantTerm<>(UpperCardinality.class, value); + } + + public static Term add(Term left, Term right) { + return new UpperCardinalityAddTerm(left, right); + } + + public static Term mul(Term left, Term right) { + return new UpperCardinalityMulTerm(left, right); + } + + public static Term min(Term left, Term right) { + return new UpperCardinalityMinTerm(left, right); + } + + public static Term max(Term left, Term right) { + return new UpperCardinalityMaxTerm(left, right); + } + + public static Term eq(Term left, Term right) { + return new EqTerm<>(UpperCardinality.class, left, right); + } + + public static Term notEq(Term left, Term right) { + return new NotEqTerm<>(UpperCardinality.class, left, right); + } + + public static Term less(Term left, Term right) { + return new LessTerm<>(UpperCardinality.class, left, right); + } + + public static Term lessEq(Term left, Term right) { + return new LessEqTerm<>(UpperCardinality.class, left, right); + } + + public static Term greater(Term left, Term right) { + return new GreaterTerm<>(UpperCardinality.class, left, right); + } + + public static Term greaterEq(Term left, Term right) { + return new GreaterEqTerm<>(UpperCardinality.class, left, right); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/MapBasedValuation.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/MapBasedValuation.java new file mode 100644 index 00000000..261ceaa5 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/MapBasedValuation.java @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.valuation; + +import tools.refinery.store.query.term.AnyDataVariable; +import tools.refinery.store.query.term.DataVariable; + +import java.util.Map; + +record MapBasedValuation(Map values) implements Valuation { + @Override + public T getValue(DataVariable variable) { + if (!values.containsKey(variable)) { + throw new IllegalArgumentException("No value for variable %s".formatted(variable)); + } + var value = values.get(variable); + return variable.getType().cast(value); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java index 88fee35b..1588e957 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java @@ -10,6 +10,7 @@ import tools.refinery.store.query.substitution.Substitution; import tools.refinery.store.query.term.AnyDataVariable; import tools.refinery.store.query.term.DataVariable; +import java.util.Map; import java.util.Set; public interface Valuation { @@ -25,4 +26,12 @@ public interface Valuation { default Valuation restrict(Set allowedVariables) { return new RestrictedValuation(this, Set.copyOf(allowedVariables)); } + + static ValuationBuilder builder() { + return new ValuationBuilder(); + } + + static Valuation empty() { + return new MapBasedValuation(Map.of()); + } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/ValuationBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/ValuationBuilder.java new file mode 100644 index 00000000..7337dbc3 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/ValuationBuilder.java @@ -0,0 +1,40 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.valuation; + +import tools.refinery.store.query.term.AnyDataVariable; +import tools.refinery.store.query.term.DataVariable; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class ValuationBuilder { + private final Map values = new HashMap<>(); + + ValuationBuilder() { + } + + public ValuationBuilder put(DataVariable variable, T value) { + return putChecked(variable, value); + } + + public ValuationBuilder putChecked(AnyDataVariable variable, Object value) { + if (value != null && !variable.getType().isInstance(value)) { + throw new IllegalArgumentException("Value %s is not an instance of %s" + .formatted(value, variable.getType().getName())); + } + if (values.containsKey(variable)) { + throw new IllegalArgumentException("Already has value for variable %s".formatted(variable)); + } + values.put(variable, value); + return this; + } + + public Valuation build() { + return new MapBasedValuation(Collections.unmodifiableMap(values)); + } +} diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java index 152840f8..01e2ccf6 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java @@ -6,13 +6,17 @@ package tools.refinery.store.query; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.query.literal.BooleanLiteral; import tools.refinery.store.query.term.Variable; +import tools.refinery.store.query.term.bool.BoolTerms; import tools.refinery.store.query.view.KeyOnlyView; import tools.refinery.store.representation.Symbol; import static org.hamcrest.MatcherAssert.assertThat; +import static tools.refinery.store.query.literal.Literals.assume; import static tools.refinery.store.query.literal.Literals.not; import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo; @@ -33,6 +37,22 @@ class DnfBuilderTest { assertThat(actual, structurallyEqualTo(expected)); } + @Test + void eliminateTrueAssumptionTest() { + var p = Variable.of("p"); + var q = Variable.of("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyView<>(friend); + + var actual = Dnf.builder() + .parameters(p, q) + .clause(assume(BoolTerms.constant(true)), friendView.call(p, q)) + .build(); + var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + @Test void eliminateFalseTest() { var p = Variable.of("p"); @@ -50,6 +70,27 @@ class DnfBuilderTest { assertThat(actual, structurallyEqualTo(expected)); } + @ParameterizedTest + @CsvSource(value = { + "false", + "null" + }, nullValues = "null") + void eliminateFalseAssumptionTest(Boolean value) { + var p = Variable.of("p"); + var q = Variable.of("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyView<>(friend); + + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q)) + .clause(friendView.call(q, p), assume(BoolTerms.constant(value))) + .build(); + var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + @Test void alwaysTrueTest() { var p = Variable.of("p"); diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/TermSubstitutionTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/TermSubstitutionTest.java new file mode 100644 index 00000000..1cbc101a --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/TermSubstitutionTest.java @@ -0,0 +1,97 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import tools.refinery.store.query.dnf.Dnf; +import tools.refinery.store.query.equality.LiteralEqualityHelper; +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.bool.BoolTerms; +import tools.refinery.store.query.term.int_.IntTerms; +import tools.refinery.store.query.term.real.RealTerms; +import tools.refinery.store.query.term.uppercardinality.UpperCardinalityTerms; +import tools.refinery.store.representation.cardinality.UpperCardinality; + +import java.util.List; +import java.util.stream.Stream; + +class TermSubstitutionTest { + private final static DataVariable intA = Variable.of("intA", Integer.class); + private final static DataVariable intB = Variable.of("intB", Integer.class); + private final static DataVariable realA = Variable.of("realA", Double.class); + private final static DataVariable realB = Variable.of("realB", Double.class); + private final static DataVariable boolA = Variable.of("boolA", Boolean.class); + private final static DataVariable boolB = Variable.of("boolB", Boolean.class); + private final static DataVariable upperCardinalityA = Variable.of("upperCardinalityA", + UpperCardinality.class); + private final static DataVariable upperCardinalityB = Variable.of("upperCardinalityB", + UpperCardinality.class); + private final static Substitution substitution = Substitution.builder() + .put(intA, intB) + .put(intB, intA) + .put(realA, realB) + .put(realB, realA) + .put(boolA, boolB) + .put(boolB, boolA) + .put(upperCardinalityA, upperCardinalityB) + .put(upperCardinalityB, upperCardinalityA) + .build(); + + @ParameterizedTest + @MethodSource + void substitutionTest(AnyTerm term) { + var substitutedTerm1 = term.substitute(substitution); + Assertions.assertNotEquals(term, substitutedTerm1, "Original term is not equal to substituted term"); + var helper = new LiteralEqualityHelper(Dnf::equals, List.of(), List.of()); + Assertions.assertTrue(term.equalsWithSubstitution(helper, substitutedTerm1), "Terms are equal by helper"); + // The {@link #substitution} is its own inverse. + var substitutedTerm2 = substitutedTerm1.substitute(substitution); + Assertions.assertEquals(term, substitutedTerm2, "Original term is not equal to back-substituted term"); + } + + static Stream substitutionTest() { + return Stream.of( + Arguments.of(IntTerms.plus(intA)), + Arguments.of(IntTerms.minus(intA)), + Arguments.of(IntTerms.add(intA, intB)), + Arguments.of(IntTerms.sub(intA, intB)), + Arguments.of(IntTerms.mul(intA, intB)), + Arguments.of(IntTerms.div(intA, intB)), + Arguments.of(IntTerms.pow(intA, intB)), + Arguments.of(IntTerms.min(intA, intB)), + Arguments.of(IntTerms.max(intA, intB)), + Arguments.of(IntTerms.eq(intA, intB)), + Arguments.of(IntTerms.notEq(intA, intB)), + Arguments.of(IntTerms.less(intA, intB)), + Arguments.of(IntTerms.lessEq(intA, intB)), + Arguments.of(IntTerms.greater(intA, intB)), + Arguments.of(IntTerms.greaterEq(intA, intB)), + Arguments.of(IntTerms.asInt(realA)), + Arguments.of(RealTerms.plus(realA)), + Arguments.of(RealTerms.minus(realA)), + Arguments.of(RealTerms.add(realA, realB)), + Arguments.of(RealTerms.sub(realA, realB)), + Arguments.of(RealTerms.mul(realA, realB)), + Arguments.of(RealTerms.div(realA, realB)), + Arguments.of(RealTerms.pow(realA, realB)), + Arguments.of(RealTerms.min(realA, realB)), + Arguments.of(RealTerms.max(realA, realB)), + Arguments.of(RealTerms.asReal(intA)), + Arguments.of(BoolTerms.not(boolA)), + Arguments.of(BoolTerms.and(boolA, boolB)), + Arguments.of(BoolTerms.or(boolA, boolB)), + Arguments.of(BoolTerms.xor(boolA, boolB)), + Arguments.of(RealTerms.eq(realA, realB)), + Arguments.of(UpperCardinalityTerms.add(upperCardinalityA, upperCardinalityB)), + Arguments.of(UpperCardinalityTerms.mul(upperCardinalityA, upperCardinalityB)), + Arguments.of(UpperCardinalityTerms.min(upperCardinalityA, upperCardinalityB)), + Arguments.of(UpperCardinalityTerms.max(upperCardinalityA, upperCardinalityB)) + ); + } +} diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/bool/BoolTermsEvaluateTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/bool/BoolTermsEvaluateTest.java new file mode 100644 index 00000000..beff705e --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/bool/BoolTermsEvaluateTest.java @@ -0,0 +1,75 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.bool; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import tools.refinery.store.query.valuation.Valuation; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +class BoolTermsEvaluateTest { + @ParameterizedTest(name = "!{0} == {1}") + @CsvSource(value = { + "false, true", + "true, false", + "null, null" + }, nullValues = "null") + void notTest(Boolean a, Boolean result) { + var term = BoolTerms.not(BoolTerms.constant(a)); + assertThat(term.getType(), is(Boolean.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "{0} && {1} == {2}") + @CsvSource(value = { + "false, false, false", + "false, true, false", + "true, false, false", + "true, true, true", + "false, null, null", + "null, false, null", + "null, null, null" + }, nullValues = "null") + void andTest(Boolean a, Boolean b, Boolean result) { + var term = BoolTerms.and(BoolTerms.constant(a), BoolTerms.constant(b)); + assertThat(term.getType(), is(Boolean.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "{0} || {1} == {2}") + @CsvSource(value = { + "false, false, false", + "false, true, true", + "true, false, true", + "true, true, true", + "true, null, null", + "null, true, null", + "null, null, null" + }, nullValues = "null") + void orTest(Boolean a, Boolean b, Boolean result) { + var term = BoolTerms.or(BoolTerms.constant(a), BoolTerms.constant(b)); + assertThat(term.getType(), is(Boolean.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "{0} ^^ {1} == {2}") + @CsvSource(value = { + "false, false, false", + "false, true, true", + "true, false, true", + "true, true, false", + "false, null, null", + "null, false, null", + "null, null, null" + }, nullValues = "null") + void xorTest(Boolean a, Boolean b, Boolean result) { + var term = BoolTerms.xor(BoolTerms.constant(a), BoolTerms.constant(b)); + assertThat(term.getType(), is(Boolean.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } +} diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/int_/IntTermsEvaluateTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/int_/IntTermsEvaluateTest.java new file mode 100644 index 00000000..abe50d75 --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/int_/IntTermsEvaluateTest.java @@ -0,0 +1,259 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.int_; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.MethodSource; +import tools.refinery.store.query.term.real.RealTerms; +import tools.refinery.store.query.valuation.Valuation; + +import java.util.stream.Stream; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +class IntTermsEvaluateTest { + @ParameterizedTest(name = "+{0} == {1}") + @CsvSource(value = { + "2, 2", + "null, null" + }, nullValues = "null") + void plusTest(Integer a, Integer result) { + var term = IntTerms.plus(IntTerms.constant(a)); + assertThat(term.getType(), is(Integer.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "-{0} == {1}") + @CsvSource(value = { + "2, -2", + "null, null" + }, nullValues = "null") + void minusTest(Integer a, Integer result) { + var term = IntTerms.minus(IntTerms.constant(a)); + assertThat(term.getType(), is(Integer.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "{0} + {1} == {2}") + @CsvSource(value = { + "1, 2, 3", + "null, 2, null", + "1, null, null", + "null, null, null" + }, nullValues = "null") + void addTest(Integer a, Integer b, Integer result) { + var term = IntTerms.add(IntTerms.constant(a), IntTerms.constant(b)); + assertThat(term.getType(), is(Integer.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "{0} - {1} == {2}") + @CsvSource(value = { + "1, 3, -2", + "null, 3, null", + "1, null, null", + "null, null, null" + }, nullValues = "null") + void subTest(Integer a, Integer b, Integer result) { + var term = IntTerms.sub(IntTerms.constant(a), IntTerms.constant(b)); + assertThat(term.getType(), is(Integer.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "{0} * {1} == {2}") + @CsvSource(value = { + "2, 3, 6", + "null, 3, null", + "2, null, null", + "null, null, null" + }, nullValues = "null") + void mulTest(Integer a, Integer b, Integer result) { + var term = IntTerms.mul(IntTerms.constant(a), IntTerms.constant(b)); + assertThat(term.getType(), is(Integer.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "{0} * {1} == {2}") + @CsvSource(value = { + "6, 3, 2", + "7, 3, 2", + "6, 0, null", + "null, 3, null", + "6, null, null", + "null, null, null" + }, nullValues = "null") + void divTest(Integer a, Integer b, Integer result) { + var term = IntTerms.div(IntTerms.constant(a), IntTerms.constant(b)); + assertThat(term.getType(), is(Integer.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "{0} ** {1} == {2}") + @CsvSource(value = { + "1, 0, 1", + "1, 3, 1", + "1, -3, null", + "2, 0, 1", + "2, 2, 4", + "2, 3, 8", + "2, 4, 16", + "2, 5, 32", + "2, 6, 64", + "2, -3, null", + "null, 3, null", + "2, null, null", + "null, null, null" + }, nullValues = "null") + void powTest(Integer a, Integer b, Integer result) { + var term = IntTerms.pow(IntTerms.constant(a), IntTerms.constant(b)); + assertThat(term.getType(), is(Integer.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "min({0}, {1}) == {2}") + @CsvSource(value = { + "1, 2, 1", + "2, 1, 1", + "null, 2, null", + "1, null, null", + "null, null, null" + }, nullValues = "null") + void minTest(Integer a, Integer b, Integer result) { + var term = IntTerms.min(IntTerms.constant(a), IntTerms.constant(b)); + assertThat(term.getType(), is(Integer.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "max({0}, {1}) == {2}") + @CsvSource(value = { + "1, 2, 2", + "2, 1, 2", + "null, 2, null", + "1, null, null", + "null, null, null" + }, nullValues = "null") + void maxTest(Integer a, Integer b, Integer result) { + var term = IntTerms.max(IntTerms.constant(a), IntTerms.constant(b)); + assertThat(term.getType(), is(Integer.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "({0} == {1}) == {2}") + @CsvSource(value = { + "1, 1, true", + "1, 2, false", + "null, 1, null", + "1, null, null", + "null, null, null" + }, nullValues = "null") + void eqTest(Integer a, Integer b, Boolean result) { + var term = IntTerms.eq(IntTerms.constant(a), IntTerms.constant(b)); + assertThat(term.getType(), is(Boolean.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "({0} != {1}) == {2}") + @CsvSource(value = { + "1, 1, false", + "1, 2, true", + "null, 1, null", + "1, null, null", + "null, null, null" + }, nullValues = "null") + void notEqTest(Integer a, Integer b, Boolean result) { + var term = IntTerms.notEq(IntTerms.constant(a), IntTerms.constant(b)); + assertThat(term.getType(), is(Boolean.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "({0} < {1}) == {2}") + @CsvSource(value = { + "1, -2, false", + "1, 1, false", + "1, 2, true", + "null, 1, null", + "1, null, null", + "null, null, null" + }, nullValues = "null") + void lessTest(Integer a, Integer b, Boolean result) { + var term = IntTerms.less(IntTerms.constant(a), IntTerms.constant(b)); + assertThat(term.getType(), is(Boolean.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "({0} <= {1}) == {2}") + @CsvSource(value = { + "1, -2, false", + "1, 1, true", + "1, 2, true", + "null, 1, null", + "1, null, null", + "null, null, null" + }, nullValues = "null") + void lessEqTest(Integer a, Integer b, Boolean result) { + var term = IntTerms.lessEq(IntTerms.constant(a), IntTerms.constant(b)); + assertThat(term.getType(), is(Boolean.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "({0} > {1}) == {2}") + @CsvSource(value = { + "1, -2, true", + "1, 1, false", + "1, 2, false", + "null, 1, null", + "1, null, null", + "null, null, null" + }, nullValues = "null") + void greaterTest(Integer a, Integer b, Boolean result) { + var term = IntTerms.greater(IntTerms.constant(a), IntTerms.constant(b)); + assertThat(term.getType(), is(Boolean.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "({0} >= {1}) == {2}") + @CsvSource(value = { + "1, -2, true", + "1, 1, true", + "1, 2, false", + "null, 1, null", + "1, null, null", + "null, null, null" + }, nullValues = "null") + void greaterEqTest(Integer a, Integer b, Boolean result) { + var term = IntTerms.greaterEq(IntTerms.constant(a), IntTerms.constant(b)); + assertThat(term.getType(), is(Boolean.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "{0} as int == {1}") + @MethodSource + void asIntTest(Double a, Integer result) { + var term = IntTerms.asInt(RealTerms.constant(a)); + assertThat(term.getType(), is(Integer.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + static Stream asIntTest() { + return Stream.of( + Arguments.of(2.0, 2), + Arguments.of(2.1, 2), + Arguments.of(2.9, 2), + Arguments.of(-2.0, -2), + Arguments.of(-2.1, -2), + Arguments.of(-2.9, -2), + Arguments.of(0.0, 0), + Arguments.of(-0.0, 0), + Arguments.of(Double.POSITIVE_INFINITY, Integer.MAX_VALUE), + Arguments.of(Double.NEGATIVE_INFINITY, Integer.MIN_VALUE), + Arguments.of(Double.NaN, null), + Arguments.of(null, null) + ); + } +} diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/real/RealTermEvaluateTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/real/RealTermEvaluateTest.java new file mode 100644 index 00000000..6a8eebf1 --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/real/RealTermEvaluateTest.java @@ -0,0 +1,238 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.real; + +import org.hamcrest.Matcher; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import tools.refinery.store.query.term.int_.IntTerms; +import tools.refinery.store.query.valuation.Valuation; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +class RealTermEvaluateTest { + public static final double TOLERANCE = 1e-6; + + private static Matcher closeToOrNull(Double expected) { + return expected == null ? nullValue(Double.class) : closeTo(expected, TOLERANCE); + } + + @ParameterizedTest(name = "+{0} == {1}") + @CsvSource(value = { + "2.5, 2.5", + "null, null" + }, nullValues = "null") + void plusTest(Double a, Double result) { + var term = RealTerms.plus(RealTerms.constant(a)); + assertThat(term.getType(), is(Double.class)); + assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); + } + + @ParameterizedTest(name = "-{0} == {1}") + @CsvSource(value = { + "2.5, -2.5", + "null, null" + }, nullValues = "null") + void minusTest(Double a, Double result) { + var term = RealTerms.minus(RealTerms.constant(a)); + assertThat(term.getType(), is(Double.class)); + assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); + } + + @ParameterizedTest(name = "{0} + {1} == {2}") + @CsvSource(value = { + "1.2, 2.3, 3.5", + "null, 2.3, null", + "1.2, null, null", + "null, null, null" + }, nullValues = "null") + void addTest(Double a, Double b, Double result) { + var term = RealTerms.add(RealTerms.constant(a), RealTerms.constant(b)); + assertThat(term.getType(), is(Double.class)); + assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); + } + + @ParameterizedTest(name = "{0} - {1} == {2}") + @CsvSource(value = { + "1.2, 3.4, -2.2", + "null, 3.4, null", + "1.2, null, null", + "null, null, null" + }, nullValues = "null") + void subTest(Double a, Double b, Double result) { + var term = RealTerms.sub(RealTerms.constant(a), RealTerms.constant(b)); + assertThat(term.getType(), is(Double.class)); + assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); + } + + @ParameterizedTest(name = "{0} * {1} == {2}") + @CsvSource(value = { + "2.3, 3.4, 7.82", + "null, 3.4, null", + "2.3, null, null", + "null, null, null" + }, nullValues = "null") + void mulTest(Double a, Double b, Double result) { + var term = RealTerms.mul(RealTerms.constant(a), RealTerms.constant(b)); + assertThat(term.getType(), is(Double.class)); + assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); + } + + @ParameterizedTest(name = "{0} * {1} == {2}") + @CsvSource(value = { + "7.82, 3.4, 2.3", + "null, 3.4, null", + "7.82, null, null", + "null, null, null" + }, nullValues = "null") + void divTest(Double a, Double b, Double result) { + var term = RealTerms.div(RealTerms.constant(a), RealTerms.constant(b)); + assertThat(term.getType(), is(Double.class)); + assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); + } + + @ParameterizedTest(name = "{0} ** {1} == {2}") + @CsvSource(value = { + "2.0, 6.0, 64.0", + "null, 6.0, null", + "2.0, null, null", + "null, null, null" + }, nullValues = "null") + void powTest(Double a, Double b, Double result) { + var term = RealTerms.pow(RealTerms.constant(a), RealTerms.constant(b)); + assertThat(term.getType(), is(Double.class)); + assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); + } + + @ParameterizedTest(name = "min({0}, {1}) == {2}") + @CsvSource(value = { + "1.5, 2.7, 1.5", + "2.7, 1.5, 1.5", + "null, 2.7, null", + "1.5, null, null", + "null, null, null" + }, nullValues = "null") + void minTest(Double a, Double b, Double result) { + var term = RealTerms.min(RealTerms.constant(a), RealTerms.constant(b)); + assertThat(term.getType(), is(Double.class)); + assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); + } + + @ParameterizedTest(name = "max({0}, {1}) == {2}") + @CsvSource(value = { + "1.5, 2.7, 2.7", + "2.7, 1.7, 2.7", + "null, 2.7, null", + "1.5, null, null", + "null, null, null" + }, nullValues = "null") + void maxTest(Double a, Double b, Double result) { + var term = RealTerms.max(RealTerms.constant(a), RealTerms.constant(b)); + assertThat(term.getType(), is(Double.class)); + assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); + } + + @ParameterizedTest(name = "({0} == {1}) == {2}") + @CsvSource(value = { + "1.5, 1.5, true", + "1.5, 2.7, false", + "null, 1.5, null", + "1.5, null, null", + "null, null, null" + }, nullValues = "null") + void eqTest(Double a, Double b, Boolean result) { + var term = RealTerms.eq(RealTerms.constant(a), RealTerms.constant(b)); + assertThat(term.getType(), is(Boolean.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "({0} != {1}) == {2}") + @CsvSource(value = { + "1.5, 1.5, false", + "1.5, 2.7, true", + "null, 1.5, null", + "1.5, null, null", + "null, null, null" + }, nullValues = "null") + void notEqTest(Double a, Double b, Boolean result) { + var term = RealTerms.notEq(RealTerms.constant(a), RealTerms.constant(b)); + assertThat(term.getType(), is(Boolean.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "({0} < {1}) == {2}") + @CsvSource(value = { + "1.5, -2.7, false", + "1.5, 1.5, false", + "1.5, 2.7, true", + "null, 1.5, null", + "1.5, null, null", + "null, null, null" + }, nullValues = "null") + void lessTest(Double a, Double b, Boolean result) { + var term = RealTerms.less(RealTerms.constant(a), RealTerms.constant(b)); + assertThat(term.getType(), is(Boolean.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "({0} <= {1}) == {2}") + @CsvSource(value = { + "1.5, -2.7, false", + "1.5, 1.5, true", + "1.5, 2.7, true", + "null, 1.5, null", + "1.5, null, null", + "null, null, null" + }, nullValues = "null") + void lessEqTest(Double a, Double b, Boolean result) { + var term = RealTerms.lessEq(RealTerms.constant(a), RealTerms.constant(b)); + assertThat(term.getType(), is(Boolean.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "({0} > {1}) == {2}") + @CsvSource(value = { + "1.5, -2.7, true", + "1.5, 1.5, false", + "1.5, 2.7, false", + "null, 1.5, null", + "1.5, null, null", + "null, null, null" + }, nullValues = "null") + void greaterTest(Double a, Double b, Boolean result) { + var term = RealTerms.greater(RealTerms.constant(a), RealTerms.constant(b)); + assertThat(term.getType(), is(Boolean.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "({0} >= {1}) == {2}") + @CsvSource(value = { + "1.5, -2.7, true", + "1.5, 1.5, true", + "1.5, 2.7, false", + "null, 1.5, null", + "1.5, null, null", + "null, null, null" + }, nullValues = "null") + void greaterEqTest(Double a, Double b, Boolean result) { + var term = RealTerms.greaterEq(RealTerms.constant(a), RealTerms.constant(b)); + assertThat(term.getType(), is(Boolean.class)); + assertThat(term.evaluate(Valuation.empty()), is(result)); + } + + @ParameterizedTest(name = "{0} as real == {1}") + @CsvSource(value = { + "0, 0.0", + "5, 5.0", + "null, null" + }, nullValues = "null") + void asRealTest(Integer a, Double result) { + var term = RealTerms.asReal(IntTerms.constant(a)); + assertThat(term.getType(), is(Double.class)); + assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result)); + } +} diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorStreamTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorStreamTest.java new file mode 100644 index 00000000..31baf36e --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorStreamTest.java @@ -0,0 +1,56 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.uppercardinality; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import tools.refinery.store.representation.cardinality.UpperCardinalities; +import tools.refinery.store.representation.cardinality.UpperCardinality; + +import java.util.List; +import java.util.stream.Stream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +class UpperCardinalitySumAggregatorStreamTest { + @ParameterizedTest + @MethodSource + void testStream(List list, UpperCardinality expected) { + var result = UpperCardinalitySumAggregator.INSTANCE.aggregateStream(list.stream()); + assertThat(result, is(expected)); + } + + static Stream testStream() { + return Stream.of( + Arguments.of(List.of(), UpperCardinalities.ZERO), + Arguments.of(List.of(UpperCardinality.of(3)), UpperCardinality.of(3)), + Arguments.of( + List.of( + UpperCardinality.of(2), + UpperCardinality.of(3) + ), + UpperCardinality.of(5) + ), + Arguments.of(List.of(UpperCardinalities.UNBOUNDED), UpperCardinalities.UNBOUNDED), + Arguments.of( + List.of( + UpperCardinalities.UNBOUNDED, + UpperCardinalities.UNBOUNDED + ), + UpperCardinalities.UNBOUNDED + ), + Arguments.of( + List.of( + UpperCardinalities.UNBOUNDED, + UpperCardinality.of(3) + ), + UpperCardinalities.UNBOUNDED + ) + ); + } +} diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorTest.java new file mode 100644 index 00000000..780cd0ab --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorTest.java @@ -0,0 +1,80 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.uppercardinality; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import tools.refinery.store.query.term.StatefulAggregate; +import tools.refinery.store.representation.cardinality.UpperCardinalities; +import tools.refinery.store.representation.cardinality.UpperCardinality; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +class UpperCardinalitySumAggregatorTest { + private StatefulAggregate accumulator; + + @BeforeEach + void beforeEach() { + accumulator = UpperCardinalitySumAggregator.INSTANCE.createEmptyAggregate(); + } + + @Test + void emptyAggregationTest() { + assertThat(accumulator.getResult(), is(UpperCardinality.of(0))); + } + + @Test + void singleBoundedTest() { + accumulator.add(UpperCardinality.of(3)); + assertThat(accumulator.getResult(), is(UpperCardinality.of(3))); + } + + @Test + void multipleBoundedTest() { + accumulator.add(UpperCardinality.of(2)); + accumulator.add(UpperCardinality.of(3)); + assertThat(accumulator.getResult(), is(UpperCardinality.of(5))); + } + + @Test + void singleUnboundedTest() { + accumulator.add(UpperCardinalities.UNBOUNDED); + assertThat(accumulator.getResult(), is(UpperCardinalities.UNBOUNDED)); + } + + @Test + void multipleUnboundedTest() { + accumulator.add(UpperCardinalities.UNBOUNDED); + accumulator.add(UpperCardinalities.UNBOUNDED); + assertThat(accumulator.getResult(), is(UpperCardinalities.UNBOUNDED)); + } + + @Test + void removeBoundedTest() { + accumulator.add(UpperCardinality.of(2)); + accumulator.add(UpperCardinality.of(3)); + accumulator.remove(UpperCardinality.of(2)); + assertThat(accumulator.getResult(), is(UpperCardinality.of(3))); + } + + @Test + void removeAllUnboundedTest() { + accumulator.add(UpperCardinalities.UNBOUNDED); + accumulator.add(UpperCardinality.of(3)); + accumulator.remove(UpperCardinalities.UNBOUNDED); + assertThat(accumulator.getResult(), is(UpperCardinality.of(3))); + } + + @Test + void removeSomeUnboundedTest() { + accumulator.add(UpperCardinalities.UNBOUNDED); + accumulator.add(UpperCardinalities.UNBOUNDED); + accumulator.add(UpperCardinality.of(3)); + accumulator.remove(UpperCardinalities.UNBOUNDED); + assertThat(accumulator.getResult(), is(UpperCardinalities.UNBOUNDED)); + } +} diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTermsEvaluateTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTermsEvaluateTest.java new file mode 100644 index 00000000..9d0f3bde --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTermsEvaluateTest.java @@ -0,0 +1,104 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term.uppercardinality; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import tools.refinery.store.query.valuation.Valuation; +import tools.refinery.store.representation.cardinality.UpperCardinalities; +import tools.refinery.store.representation.cardinality.UpperCardinality; + +import java.util.stream.Stream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +class UpperCardinalityTermsEvaluateTest { + @ParameterizedTest(name = "min({0}, {1}) == {2}") + @MethodSource + void minTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) { + var term = UpperCardinalityTerms.min(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b)); + assertThat(term.getType(), is(UpperCardinality.class)); + assertThat(term.evaluate(Valuation.empty()), is(expected)); + } + + static Stream minTest() { + return Stream.of( + Arguments.of(UpperCardinality.of(0), UpperCardinality.of(0), UpperCardinality.of(0)), + Arguments.of(UpperCardinality.of(0), UpperCardinality.of(1), UpperCardinality.of(0)), + Arguments.of(UpperCardinality.of(1), UpperCardinality.of(0), UpperCardinality.of(0)), + Arguments.of(UpperCardinality.of(0), UpperCardinalities.UNBOUNDED, UpperCardinality.of(0)), + Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(0), UpperCardinality.of(0)), + Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED), + Arguments.of(UpperCardinality.of(1), null, null), + Arguments.of(null, UpperCardinality.of(1), null), + Arguments.of(null, null, null) + ); + } + + @ParameterizedTest(name = "max({0}, {1}) == {2}") + @MethodSource + void maxTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) { + var term = UpperCardinalityTerms.max(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b)); + assertThat(term.getType(), is(UpperCardinality.class)); + assertThat(term.evaluate(Valuation.empty()), is(expected)); + } + + static Stream maxTest() { + return Stream.of( + Arguments.of(UpperCardinality.of(0), UpperCardinality.of(0), UpperCardinality.of(0)), + Arguments.of(UpperCardinality.of(0), UpperCardinality.of(1), UpperCardinality.of(1)), + Arguments.of(UpperCardinality.of(1), UpperCardinality.of(0), UpperCardinality.of(1)), + Arguments.of(UpperCardinality.of(0), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED), + Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(0), UpperCardinalities.UNBOUNDED), + Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED), + Arguments.of(UpperCardinality.of(1), null, null), + Arguments.of(null, UpperCardinality.of(1), null), + Arguments.of(null, null, null) + ); + } + + @ParameterizedTest(name = "{0} + {1} == {2}") + @MethodSource + void addTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) { + var term = UpperCardinalityTerms.add(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b)); + assertThat(term.getType(), is(UpperCardinality.class)); + assertThat(term.evaluate(Valuation.empty()), is(expected)); + } + + static Stream addTest() { + return Stream.of( + Arguments.of(UpperCardinality.of(2), UpperCardinality.of(3), UpperCardinality.of(5)), + Arguments.of(UpperCardinality.of(2), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED), + Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(2), UpperCardinalities.UNBOUNDED), + Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED), + Arguments.of(UpperCardinality.of(1), null, null), + Arguments.of(null, UpperCardinality.of(1), null), + Arguments.of(null, null, null) + ); + } + + @ParameterizedTest(name = "{0} * {1} == {2}") + @MethodSource + void mulTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) { + var term = UpperCardinalityTerms.mul(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b)); + assertThat(term.getType(), is(UpperCardinality.class)); + assertThat(term.evaluate(Valuation.empty()), is(expected)); + } + + static Stream mulTest() { + return Stream.of( + Arguments.of(UpperCardinality.of(2), UpperCardinality.of(3), UpperCardinality.of(6)), + Arguments.of(UpperCardinality.of(2), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED), + Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(2), UpperCardinalities.UNBOUNDED), + Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED), + Arguments.of(UpperCardinality.of(1), null, null), + Arguments.of(null, UpperCardinality.of(1), null), + Arguments.of(null, null, null) + ); + } +} diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java index dd7a018d..d6a9e02c 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java @@ -5,11 +5,11 @@ */ package tools.refinery.store.reasoning.translator; +import tools.refinery.store.query.substitution.Substitution; import tools.refinery.store.reasoning.representation.AnyPartialSymbol; import tools.refinery.store.reasoning.representation.PartialRelation; import tools.refinery.store.query.term.Variable; import tools.refinery.store.query.literal.Literal; -import tools.refinery.store.query.substitution.Substitutions; import java.util.*; @@ -66,14 +66,9 @@ public final class Advice { public List substitute(List substituteParameters) { checkArity(substituteParameters); markProcessed(); - int arity = parameters.size(); - var variableMap = new HashMap(arity); - for (int i = 0; i < arity; i++) { - variableMap.put(parameters.get(i), substituteParameters.get(i)); - } // Use a renewing substitution to remove any non-parameter variables and avoid clashed between variables // coming from different advice in the same clause. - var substitution = Substitutions.renewing(variableMap); + var substitution = Substitution.builder().putManyChecked(parameters, substituteParameters).renewing().build(); return literals.stream().map(literal -> literal.substitute(substitution)).toList(); } -- cgit v1.2.3-70-g09d2 From 4e698774925468062974b990143c1091e23ed63b Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Mon, 1 May 2023 02:07:23 +0200 Subject: feat: query parameter binding validation * Introduce parameter directions for constraints and DNF * Introduce variable directions for literals * Infer and check variable directions in DNF and topologically sort literals by their input variables --- .../context/RelationalQueryMetaContext.java | 13 +- .../query/viatra/internal/pquery/Dnf2PQuery.java | 70 +++-- .../internal/pquery/QueryWrapperFactory.java | 35 ++- .../store/query/viatra/DiagonalQueryTest.java | 6 +- .../tools/refinery/store/query/Constraint.java | 4 +- .../store/query/dnf/AbstractQueryBuilder.java | 24 ++ .../store/query/dnf/ClausePostProcessor.java | 321 +++++++++++++++++++++ .../java/tools/refinery/store/query/dnf/Dnf.java | 56 ++-- .../tools/refinery/store/query/dnf/DnfBuilder.java | 183 +++++++++--- .../tools/refinery/store/query/dnf/DnfClause.java | 2 +- .../refinery/store/query/dnf/FunctionalQuery.java | 17 +- .../refinery/store/query/dnf/RelationalQuery.java | 11 +- .../store/query/dnf/SymbolicParameter.java | 48 +++ .../query/equality/LiteralEqualityHelper.java | 7 +- .../IncompatibleParameterDirectionException.java | 16 + .../store/query/literal/AbstractCallLiteral.java | 12 +- .../store/query/literal/AggregationLiteral.java | 18 +- .../store/query/literal/AssignLiteral.java | 49 +++- .../store/query/literal/AssumeLiteral.java | 35 ++- .../store/query/literal/BooleanLiteral.java | 7 +- .../refinery/store/query/literal/CallLiteral.java | 17 +- .../store/query/literal/ConstantLiteral.java | 42 ++- .../refinery/store/query/literal/CountLiteral.java | 10 +- .../store/query/literal/EquivalenceLiteral.java | 55 +++- .../refinery/store/query/literal/Literal.java | 5 +- .../store/query/literal/VariableBinder.java | 64 ++++ .../store/query/literal/VariableBinderBuilder.java | 96 ++++++ .../store/query/literal/VariableDirection.java | 101 +++++++ .../query/substitution/SubstitutionBuilder.java | 5 +- .../refinery/store/query/term/AnyDataVariable.java | 6 + .../tools/refinery/store/query/term/DataSort.java | 34 --- .../refinery/store/query/term/DataVariable.java | 5 - .../tools/refinery/store/query/term/NodeSort.java | 35 --- .../refinery/store/query/term/NodeVariable.java | 6 +- .../tools/refinery/store/query/term/Parameter.java | 63 ++++ .../store/query/term/ParameterDirection.java | 23 ++ .../java/tools/refinery/store/query/term/Sort.java | 16 - .../tools/refinery/store/query/term/Variable.java | 3 +- .../store/query/view/AbstractFunctionView.java | 36 +-- .../refinery/store/query/view/FunctionView.java | 11 +- .../store/query/view/NodeFunctionView.java | 10 +- .../store/query/view/TuplePreservingView.java | 35 ++- .../tools/refinery/store/query/DnfBuilderTest.java | 266 ----------------- .../store/query/DnfToDefinitionStringTest.java | 179 ------------ .../dnf/DnfBuilderLiteralEliminationTest.java | 209 ++++++++++++++ .../dnf/DnfBuilderVariableUnificationTest.java | 273 ++++++++++++++++++ .../store/query/dnf/DnfToDefinitionStringTest.java | 178 ++++++++++++ .../MismatchDescribingDnfEqualityChecker.java | 4 +- .../store/reasoning/lifting/DnfLifter.java | 25 +- .../store/reasoning/literal/ModalConstraint.java | 6 +- .../reasoning/representation/PartialRelation.java | 11 +- 51 files changed, 1956 insertions(+), 807 deletions(-) create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/exceptions/IncompatibleParameterDirectionException.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableBinder.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableBinderBuilder.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableDirection.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataSort.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeSort.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/Parameter.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/ParameterDirection.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/term/Sort.java delete mode 100644 subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java delete mode 100644 subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToDefinitionStringTest.java create mode 100644 subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderLiteralEliminationTest.java create mode 100644 subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderVariableUnificationTest.java create mode 100644 subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfToDefinitionStringTest.java (limited to 'subprojects/store-query-viatra/src/main/java/tools') diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java index cf96b7fd..211eacb4 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java @@ -9,7 +9,6 @@ import org.eclipse.viatra.query.runtime.matchers.context.AbstractQueryMetaContex import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; import org.eclipse.viatra.query.runtime.matchers.context.InputKeyImplication; import org.eclipse.viatra.query.runtime.matchers.context.common.JavaTransitiveInstancesKey; -import tools.refinery.store.query.term.DataSort; import tools.refinery.store.query.viatra.internal.pquery.SymbolViewWrapper; import tools.refinery.store.query.view.AnySymbolView; @@ -62,14 +61,14 @@ public class RelationalQueryMetaContext extends AbstractQueryMetaContext { relationViewImplication.impliedIndices())); } } - var sorts = symbolView.getSorts(); + var parameters = symbolView.getParameters(); int arity = symbolView.arity(); for (int i = 0; i < arity; i++) { - var sort = sorts.get(i); - if (sort instanceof DataSort dataSort) { - var javaTransitiveInstancesKey = new JavaTransitiveInstancesKey(dataSort.type()); - var javaImplication = new InputKeyImplication(implyingKey, javaTransitiveInstancesKey, - List.of(i)); + var parameter = parameters.get(i); + var parameterType = parameter.tryGetType(); + if (parameterType.isPresent()) { + var javaTransitiveInstancesKey = new JavaTransitiveInstancesKey(parameterType.get()); + var javaImplication = new InputKeyImplication(implyingKey, javaTransitiveInstancesKey, List.of(i)); inputKeyImplications.add(javaImplication); } } 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 index b511a5c7..ec880435 100644 --- 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 @@ -19,11 +19,13 @@ import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.Consta 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.PParameterDirection; import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery; import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.query.dnf.DnfClause; +import tools.refinery.store.query.dnf.SymbolicParameter; import tools.refinery.store.query.literal.*; import tools.refinery.store.query.term.ConstantTerm; import tools.refinery.store.query.term.StatefulAggregator; @@ -82,15 +84,20 @@ public class Dnf2PQuery { var pQuery = new RawPQuery(dnfQuery.getUniqueName()); pQuery.setEvaluationHints(consumeHint(dnfQuery)); - Map parameters = new HashMap<>(); - for (Variable variable : dnfQuery.getParameters()) { - parameters.put(variable, new PParameter(variable.getUniqueName())); - } - + Map parameters = new HashMap<>(); List parameterList = new ArrayList<>(); - for (var param : dnfQuery.getParameters()) { - parameterList.add(parameters.get(param)); + for (var parameter : dnfQuery.getSymbolicParameters()) { + var direction = switch (parameter.getDirection()) { + case IN_OUT -> PParameterDirection.INOUT; + case OUT -> PParameterDirection.OUT; + case IN -> throw new IllegalArgumentException("Query %s with input parameter %s is not supported" + .formatted(dnfQuery, parameter.getVariable())); + }; + var pParameter = new PParameter(parameter.getVariable().getUniqueName(), null, null, direction); + parameters.put(parameter, pParameter); + parameterList.add(pParameter); } + pQuery.setParameters(parameterList); for (var functionalDependency : dnfQuery.getFunctionalDependencies()) { @@ -110,15 +117,15 @@ public class Dnf2PQuery { 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))); + List parameterExports = new ArrayList<>(); + for (var parameter : dnfQuery.getSymbolicParameters()) { + PVariable pVar = body.getOrCreateVariableByName(parameter.getVariable().getUniqueName()); + parameterExports.add(new ExportedParameter(body, pVar, parameters.get(parameter))); } - body.setSymbolicParameters(symbolicParameters); + body.setSymbolicParameters(parameterExports); pQuery.addBody(body); for (Literal literal : clause.literals()) { - translateLiteral(literal, clause, body); + translateLiteral(literal, body); } } } @@ -126,11 +133,11 @@ public class Dnf2PQuery { return pQuery; } - private void translateLiteral(Literal literal, DnfClause clause, PBody body) { + private void translateLiteral(Literal literal, PBody body) { if (literal instanceof EquivalenceLiteral equivalenceLiteral) { translateEquivalenceLiteral(equivalenceLiteral, body); } else if (literal instanceof CallLiteral callLiteral) { - translateCallLiteral(callLiteral, clause, body); + translateCallLiteral(callLiteral, body); } else if (literal instanceof ConstantLiteral constantLiteral) { translateConstantLiteral(constantLiteral, body); } else if (literal instanceof AssignLiteral assignLiteral) { @@ -138,25 +145,25 @@ public class Dnf2PQuery { } else if (literal instanceof AssumeLiteral assumeLiteral) { translateAssumeLiteral(assumeLiteral, body); } else if (literal instanceof CountLiteral countLiteral) { - translateCountLiteral(countLiteral, clause, body); + translateCountLiteral(countLiteral, body); } else if (literal instanceof AggregationLiteral aggregationLiteral) { - translateAggregationLiteral(aggregationLiteral, clause, body); + translateAggregationLiteral(aggregationLiteral, 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()) { + PVariable varSource = body.getOrCreateVariableByName(equivalenceLiteral.getLeft().getUniqueName()); + PVariable varTarget = body.getOrCreateVariableByName(equivalenceLiteral.getRight().getUniqueName()); + if (equivalenceLiteral.isPositive()) { new Equality(body, varSource, varTarget); } else { new Inequality(body, varSource, varTarget); } } - private void translateCallLiteral(CallLiteral callLiteral, DnfClause clause, PBody body) { + private void translateCallLiteral(CallLiteral callLiteral, PBody body) { var polarity = callLiteral.getPolarity(); switch (polarity) { case POSITIVE -> { @@ -186,7 +193,7 @@ public class Dnf2PQuery { new BinaryTransitiveClosure(body, substitution, pattern); } case NEGATIVE -> { - var wrappedCall = wrapperFactory.maybeWrapConstraint(callLiteral, clause); + var wrappedCall = wrapperFactory.maybeWrapConstraint(callLiteral); var substitution = translateSubstitution(wrappedCall.remappedArguments(), body); var pattern = wrappedCall.pattern(); new NegativePatternCall(body, substitution, pattern); @@ -206,13 +213,13 @@ public class Dnf2PQuery { } private void translateConstantLiteral(ConstantLiteral constantLiteral, PBody body) { - var variable = body.getOrCreateVariableByName(constantLiteral.variable().getUniqueName()); - new ConstantValue(body, variable, constantLiteral.nodeId()); + var variable = body.getOrCreateVariableByName(constantLiteral.getVariable().getUniqueName()); + new ConstantValue(body, variable, constantLiteral.getNodeId()); } private void translateAssignLiteral(AssignLiteral assignLiteral, PBody body) { - var variable = body.getOrCreateVariableByName(assignLiteral.variable().getUniqueName()); - var term = assignLiteral.term(); + var variable = body.getOrCreateVariableByName(assignLiteral.getTargetVariable().getUniqueName()); + var term = assignLiteral.getTerm(); if (term instanceof ConstantTerm constantTerm) { new ConstantValue(body, variable, constantTerm.getValue()); } else { @@ -222,19 +229,18 @@ public class Dnf2PQuery { } private void translateAssumeLiteral(AssumeLiteral assumeLiteral, PBody body) { - var evaluator = new AssumptionEvaluator(assumeLiteral.term()); + var evaluator = new AssumptionEvaluator(assumeLiteral.getTerm()); new ExpressionEvaluation(body, evaluator, null); } - private void translateCountLiteral(CountLiteral countLiteral, DnfClause clause, PBody body) { - var wrappedCall = wrapperFactory.maybeWrapConstraint(countLiteral, clause); + private void translateCountLiteral(CountLiteral countLiteral, PBody body) { + var wrappedCall = wrapperFactory.maybeWrapConstraint(countLiteral); var substitution = translateSubstitution(wrappedCall.remappedArguments(), body); var resultVariable = body.getOrCreateVariableByName(countLiteral.getResultVariable().getUniqueName()); new PatternMatchCounter(body, substitution, wrappedCall.pattern(), resultVariable); } - private void translateAggregationLiteral(AggregationLiteral aggregationLiteral, DnfClause clause, - PBody body) { + private void translateAggregationLiteral(AggregationLiteral aggregationLiteral, PBody body) { var aggregator = aggregationLiteral.getAggregator(); IMultisetAggregationOperator aggregationOperator; if (aggregator instanceof StatelessAggregator statelessAggregator) { @@ -244,7 +250,7 @@ public class Dnf2PQuery { } else { throw new IllegalArgumentException("Unknown aggregator: " + aggregator); } - var wrappedCall = wrapperFactory.maybeWrapConstraint(aggregationLiteral, clause); + var wrappedCall = wrapperFactory.maybeWrapConstraint(aggregationLiteral); var substitution = translateSubstitution(wrappedCall.remappedArguments(), body); var inputVariable = body.getOrCreateVariableByName(aggregationLiteral.getInputVariable().getUniqueName()); var aggregatedColumn = substitution.invertIndex().get(inputVariable); diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java index 0d046455..2b7280f2 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java @@ -14,12 +14,13 @@ import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.TypeCo import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery; 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.Constraint; import tools.refinery.store.query.dnf.Dnf; -import tools.refinery.store.query.dnf.DnfClause; import tools.refinery.store.query.dnf.DnfUtils; import tools.refinery.store.query.literal.AbstractCallLiteral; +import tools.refinery.store.query.term.ParameterDirection; import tools.refinery.store.query.term.Variable; import tools.refinery.store.query.view.AnySymbolView; import tools.refinery.store.query.view.SymbolView; @@ -45,21 +46,17 @@ class QueryWrapperFactory { } return maybeWrapConstraint(symbolView, identity); } - public WrappedCall maybeWrapConstraint(AbstractCallLiteral callLiteral, DnfClause clause) { + + public WrappedCall maybeWrapConstraint(AbstractCallLiteral callLiteral) { var arguments = callLiteral.getArguments(); int arity = arguments.size(); var remappedParameters = new int[arity]; - var boundVariables = clause.boundVariables(); var unboundVariableIndices = new HashMap(); var appendVariable = new VariableAppender(); for (int i = 0; i < arity; i++) { var variable = arguments.get(i); - if (boundVariables.contains(variable)) { - // Do not join bound variable to make sure that the embedded pattern stays as general as possible. - remappedParameters[i] = appendVariable.applyAsInt(variable); - } else { - remappedParameters[i] = unboundVariableIndices.computeIfAbsent(variable, appendVariable::applyAsInt); - } + // Unify all variables to avoid VIATRA bugs, even if they're bound in the containing clause. + remappedParameters[i] = unboundVariableIndices.computeIfAbsent(variable, appendVariable::applyAsInt); } var pattern = maybeWrapConstraint(callLiteral.getTarget(), remappedParameters); return new WrappedCall(pattern, appendVariable.getRemappedArguments()); @@ -89,6 +86,8 @@ class QueryWrapperFactory { var constraint = remappedConstraint.constraint(); var remappedParameters = remappedConstraint.remappedParameters(); + checkNoInputParameters(constraint); + var embeddedPQuery = new RawPQuery(DnfUtils.generateUniqueName(constraint.name()), PVisibility.EMBEDDED); var body = new PBody(embeddedPQuery); int arity = Arrays.stream(remappedParameters).max().orElse(-1) + 1; @@ -112,6 +111,21 @@ class QueryWrapperFactory { } var argumentTuple = Tuples.flatTupleOf(arguments); + addPositiveConstraint(constraint, body, argumentTuple); + embeddedPQuery.addBody(body); + return embeddedPQuery; + } + + private static void checkNoInputParameters(Constraint constraint) { + for (var constraintParameter : constraint.getParameters()) { + if (constraintParameter.getDirection() == ParameterDirection.IN) { + throw new IllegalArgumentException("Input parameter %s of %s is not supported" + .formatted(constraintParameter, constraint)); + } + } + } + + private void addPositiveConstraint(Constraint constraint, PBody body, Tuple argumentTuple) { if (constraint instanceof SymbolView view) { new TypeConstraint(body, argumentTuple, getInputKey(view)); } else if (constraint instanceof Dnf dnf) { @@ -120,9 +134,6 @@ class QueryWrapperFactory { } else { throw new IllegalArgumentException("Unknown Constraint: " + constraint); } - - embeddedPQuery.addBody(body); - return embeddedPQuery; } public IInputKey getInputKey(AnySymbolView symbolView) { diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java index 56ddb9b4..86a27f5b 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java @@ -298,10 +298,10 @@ class DiagonalQueryTest { y.assign(x) ); }); - var query = Query.of("Diagonal", Integer.class, (builder, p1, output) -> builder.clause(Integer.class, - (p2, y) -> List.of( + var query = Query.of("Diagonal", Integer.class, (builder, p1, output) -> builder.clause( + Integer.class, Integer.class, (p2, y, z) -> List.of( personView.call(p1), - output.assign(subQuery.aggregate(y, INT_SUM, p1, p1, p2, p2, y, y)) + output.assign(subQuery.aggregate(y, INT_SUM, p1, p1, p2, p2, y, z)) ))); var store = ModelStore.builder() diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java index 10d8a579..207c627c 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java @@ -14,10 +14,10 @@ import java.util.List; public interface Constraint { String name(); - List getSorts(); + List getParameters(); default int arity() { - return getSorts().size(); + return getParameters().size(); } default boolean invalidIndex(int i) { diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AbstractQueryBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AbstractQueryBuilder.java index ddd69b9f..2a3e3ce0 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AbstractQueryBuilder.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AbstractQueryBuilder.java @@ -8,6 +8,7 @@ package tools.refinery.store.query.dnf; import tools.refinery.store.query.dnf.callback.*; import tools.refinery.store.query.literal.Literal; import tools.refinery.store.query.term.NodeVariable; +import tools.refinery.store.query.term.ParameterDirection; import tools.refinery.store.query.term.Variable; import java.util.Collection; @@ -31,11 +32,24 @@ public abstract class AbstractQueryBuilder> { return dnfBuilder.parameter(name); } + public NodeVariable parameter(ParameterDirection direction) { + return dnfBuilder.parameter(direction); + } + + public NodeVariable parameter(String name, ParameterDirection direction) { + return dnfBuilder.parameter(name, direction); + } + public T parameter(NodeVariable variable) { dnfBuilder.parameter(variable); return self(); } + public T parameter(NodeVariable variable, ParameterDirection direction) { + dnfBuilder.parameter(variable, direction); + return self(); + } + public T parameters(NodeVariable... variables) { dnfBuilder.parameters(variables); return self(); @@ -46,6 +60,16 @@ public abstract class AbstractQueryBuilder> { return self(); } + public T parameters(List variables, ParameterDirection direction) { + dnfBuilder.parameters(variables, direction); + return self(); + } + + public T symbolicParameters(List parameters) { + dnfBuilder.symbolicParameters(parameters); + return self(); + } + public T functionalDependencies(Collection> functionalDependencies) { dnfBuilder.functionalDependencies(functionalDependencies); return self(); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java new file mode 100644 index 00000000..7a56145c --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java @@ -0,0 +1,321 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.dnf; + +import org.jetbrains.annotations.NotNull; +import tools.refinery.store.query.literal.EquivalenceLiteral; +import tools.refinery.store.query.literal.Literal; +import tools.refinery.store.query.literal.VariableDirection; +import tools.refinery.store.query.substitution.MapBasedSubstitution; +import tools.refinery.store.query.substitution.StatelessSubstitution; +import tools.refinery.store.query.term.NodeVariable; +import tools.refinery.store.query.term.Variable; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +class ClausePostProcessor { + private final Set parameters; + private final Map parameterWeights; + private final List literals; + private final Map representatives = new LinkedHashMap<>(); + private final Map> equivalencePartition = new HashMap<>(); + private List substitutedLiterals; + private final Set existentiallyQuantifiedVariables = new LinkedHashSet<>(); + private Set inputParameters; + private Set positiveVariables; + private Map> variableToLiteralInputMap; + private PriorityQueue literalsWithAllInputsBound; + private LinkedHashSet topologicallySortedLiterals; + + public ClausePostProcessor(Set parameters, Map parameterWeights, + List literals) { + this.parameters = parameters; + this.parameterWeights = parameterWeights; + this.literals = literals; + } + + public Result postProcessClause() { + mergeEquivalentNodeVariables(); + substitutedLiterals = new ArrayList<>(literals.size()); + keepParameterEquivalences(); + substituteLiterals(); + computePositiveVariables(); + validatePositiveRepresentatives(); + validateClosureVariables(); + topologicallySortLiterals(); + var filteredLiterals = new ArrayList(topologicallySortedLiterals.size()); + for (var literal : topologicallySortedLiterals) { + var reduction = literal.getReduction(); + switch (reduction) { + case NOT_REDUCIBLE -> filteredLiterals.add(literal); + case ALWAYS_TRUE -> { + // Literals reducible to {@code true} can be omitted, because the model is always assumed to have at + // least on object. + } + case ALWAYS_FALSE -> { + // Clauses with {@code false} literals can be omitted entirely. + return ConstantResult.ALWAYS_FALSE; + } + default -> throw new IllegalArgumentException("Invalid reduction: " + reduction); + } + } + if (filteredLiterals.isEmpty()) { + return ConstantResult.ALWAYS_TRUE; + } + var clause = new DnfClause(Collections.unmodifiableSet(positiveVariables), + Collections.unmodifiableList(filteredLiterals)); + return new ClauseResult(clause); + } + + private void mergeEquivalentNodeVariables() { + for (var literal : literals) { + if (isPositiveEquivalence(literal)) { + var equivalenceLiteral = (EquivalenceLiteral) literal; + mergeVariables(equivalenceLiteral.getLeft(), equivalenceLiteral.getRight()); + } + } + } + + private static boolean isPositiveEquivalence(Literal literal) { + return literal instanceof EquivalenceLiteral equivalenceLiteral && equivalenceLiteral.isPositive(); + } + + private void mergeVariables(NodeVariable left, NodeVariable right) { + var leftRepresentative = getRepresentative(left); + var rightRepresentative = getRepresentative(right); + if (parameters.contains(leftRepresentative) && (!parameters.contains(rightRepresentative) || + parameterWeights.get(leftRepresentative).compareTo(parameterWeights.get(rightRepresentative)) <= 0)) { + // Prefer the variable occurring earlier in the parameter list as a representative. + doMergeVariables(leftRepresentative, rightRepresentative); + } else { + doMergeVariables(rightRepresentative, leftRepresentative); + } + } + + private void doMergeVariables(NodeVariable parentRepresentative, NodeVariable newChildRepresentative) { + var parentSet = getEquivalentVariables(parentRepresentative); + var childSet = getEquivalentVariables(newChildRepresentative); + parentSet.addAll(childSet); + equivalencePartition.remove(newChildRepresentative); + for (var childEquivalentNodeVariable : childSet) { + representatives.put(childEquivalentNodeVariable, parentRepresentative); + } + } + + private NodeVariable getRepresentative(NodeVariable variable) { + return representatives.computeIfAbsent(variable, Function.identity()); + } + + private Set getEquivalentVariables(NodeVariable variable) { + var representative = getRepresentative(variable); + if (!representative.equals(variable)) { + throw new IllegalStateException("NodeVariable %s already has a representative %s" + .formatted(variable, representative)); + } + return equivalencePartition.computeIfAbsent(variable, key -> { + var set = new HashSet(1); + set.add(key); + return set; + }); + } + + private void keepParameterEquivalences() { + for (var pair : representatives.entrySet()) { + var left = pair.getKey(); + var right = pair.getValue(); + if (!left.equals(right) && parameters.contains(left) && parameters.contains(right)) { + substitutedLiterals.add(left.isEquivalent(right)); + } + } + } + + private void substituteLiterals() { + var substitution = new MapBasedSubstitution(Collections.unmodifiableMap(representatives), + StatelessSubstitution.IDENTITY); + for (var literal : literals) { + if (isPositiveEquivalence(literal)) { + // We already retained all equivalences that cannot be replaced with substitutions in + // {@link#keepParameterEquivalences()}. + continue; + } + var substitutedLiteral = literal.substitute(substitution); + substitutedLiterals.add(substitutedLiteral); + } + } + + private void computePositiveVariables() { + for (var literal : substitutedLiterals) { + var variableBinder = literal.getVariableBinder(); + variableBinder.getVariablesWithDirection(VariableDirection.IN_OUT) + .forEach(existentiallyQuantifiedVariables::add); + variableBinder.getVariablesWithDirection(VariableDirection.OUT).forEach(variable -> { + boolean added = existentiallyQuantifiedVariables.add(variable); + if (!added) { + throw new IllegalArgumentException("Variable %s has multiple %s bindings" + .formatted(variable, VariableDirection.OUT)); + } + }); + } + // Input parameters are parameters not bound by any positive literal. + inputParameters = new LinkedHashSet<>(parameters); + inputParameters.removeAll(existentiallyQuantifiedVariables); + // Existentially quantified variables are variables appearing in positive literals that aren't parameters. + existentiallyQuantifiedVariables.removeAll(parameters); + // Positive variables are parameters (including input parameters) and variables bound by positive literals. + positiveVariables = new LinkedHashSet<>(parameters.size() + existentiallyQuantifiedVariables.size()); + positiveVariables.addAll(parameters); + positiveVariables.addAll(existentiallyQuantifiedVariables); + } + + private void validatePositiveRepresentatives() { + for (var pair : equivalencePartition.entrySet()) { + var representative = pair.getKey(); + if (!positiveVariables.contains(representative)) { + var variableSet = pair.getValue(); + throw new IllegalArgumentException("Variables %s were merged by equivalence but are not bound" + .formatted(variableSet)); + } + } + } + + private void validateClosureVariables() { + var negativeVariablesMap = new HashMap(); + for (var literal : substitutedLiterals) { + var variableBinder = literal.getVariableBinder(); + variableBinder.getVariablesWithDirection(VariableDirection.CLOSURE, positiveVariables) + .forEach(variable -> { + var oldLiteral = negativeVariablesMap.put(variable, literal); + if (oldLiteral != null) { + throw new IllegalArgumentException( + "Unbound variable %s appears in multiple literals %s and %s" + .formatted(variable, oldLiteral, literal)); + } + }); + } + } + + private void topologicallySortLiterals() { + topologicallySortedLiterals = new LinkedHashSet<>(substitutedLiterals.size()); + variableToLiteralInputMap = new HashMap<>(); + literalsWithAllInputsBound = new PriorityQueue<>(); + int size = substitutedLiterals.size(); + for (int i = 0; i < size; i++) { + var literal = substitutedLiterals.get(i); + var sortableLiteral = new SortableLiteral(i, literal); + sortableLiteral.enqueue(); + } + while (!literalsWithAllInputsBound.isEmpty()) { + var variable = literalsWithAllInputsBound.remove(); + variable.addToSortedLiterals(); + } + if (!variableToLiteralInputMap.isEmpty()) { + throw new IllegalArgumentException("Unbound input variables %s" + .formatted(variableToLiteralInputMap.keySet())); + } + } + + private void topologicallySortVariable(Variable variable) { + var literalSetForInput = variableToLiteralInputMap.remove(variable); + if (literalSetForInput == null) { + return; + } + for (var targetSortableLiteral : literalSetForInput) { + targetSortableLiteral.bindVariable(variable); + } + } + + private class SortableLiteral implements Comparable { + private final int index; + private final Literal literal; + private final Set remainingInputs; + + private SortableLiteral(int index, Literal literal) { + this.index = index; + this.literal = literal; + remainingInputs = literal.getVariableBinder() + .getVariablesWithDirection(VariableDirection.IN, positiveVariables) + .collect(Collectors.toCollection(HashSet::new)); + remainingInputs.removeAll(inputParameters); + } + + public void enqueue() { + if (allInputsBound()) { + addToAllInputsBoundQueue(); + } else { + addToVariableToLiteralInputMap(); + } + } + + private void bindVariable(Variable input) { + if (!remainingInputs.remove(input)) { + throw new IllegalStateException("Already processed input %s of literal %s".formatted(input, literal)); + } + if (allInputsBound()) { + addToAllInputsBoundQueue(); + } + } + + private boolean allInputsBound() { + return remainingInputs.isEmpty(); + } + + private void addToVariableToLiteralInputMap() { + for (var inputVariable : remainingInputs) { + var literalSetForInput = variableToLiteralInputMap.computeIfAbsent( + inputVariable, key -> new HashSet<>()); + literalSetForInput.add(this); + } + } + + private void addToAllInputsBoundQueue() { + literalsWithAllInputsBound.add(this); + } + + public void addToSortedLiterals() { + if (!allInputsBound()) { + throw new AssertionError("Inputs %s of %s are not yet bound".formatted(remainingInputs, literal)); + } + // Add literal if we haven't yet added a duplicate of this literal. + topologicallySortedLiterals.add(literal); + var variableBinder = literal.getVariableBinder(); + variableBinder.getVariablesWithDirection(VariableDirection.IN_OUT) + .forEach(ClausePostProcessor.this::topologicallySortVariable); + variableBinder.getVariablesWithDirection(VariableDirection.OUT) + .forEach(ClausePostProcessor.this::topologicallySortVariable); + } + + @Override + public int compareTo(@NotNull ClausePostProcessor.SortableLiteral other) { + return Integer.compare(index, other.index); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SortableLiteral that = (SortableLiteral) o; + return index == that.index && Objects.equals(literal, that.literal); + } + + @Override + public int hashCode() { + return Objects.hash(index, literal); + } + } + + public sealed interface Result permits ClauseResult, ConstantResult { + } + + public record ClauseResult(DnfClause clause) implements Result { + } + + public enum ConstantResult implements Result { + ALWAYS_TRUE, + ALWAYS_FALSE + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java index 8de5079d..7e68d4a0 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java @@ -5,59 +5,57 @@ */ package tools.refinery.store.query.dnf; +import tools.refinery.store.query.Constraint; import tools.refinery.store.query.equality.DnfEqualityChecker; import tools.refinery.store.query.equality.LiteralEqualityHelper; -import tools.refinery.store.query.Constraint; import tools.refinery.store.query.literal.LiteralReduction; -import tools.refinery.store.query.term.Sort; +import tools.refinery.store.query.term.Parameter; import tools.refinery.store.query.term.Variable; import java.util.Collection; -import java.util.HashSet; +import java.util.Collections; import java.util.List; import java.util.Set; import java.util.function.Consumer; +import java.util.stream.Collectors; public final class Dnf implements Constraint { private static final String INDENTATION = " "; private final String name; - private final String uniqueName; - - private final List parameters; - + private final List symbolicParameters; private final List> functionalDependencies; - private final List clauses; - Dnf(String name, List parameters, List> functionalDependencies, - List clauses) { - validateFunctionalDependencies(parameters, functionalDependencies); + Dnf(String name, List symbolicParameters, + List> functionalDependencies, List clauses) { + validateFunctionalDependencies(symbolicParameters, functionalDependencies); this.name = name; this.uniqueName = DnfUtils.generateUniqueName(name); - this.parameters = parameters; + this.symbolicParameters = symbolicParameters; this.functionalDependencies = functionalDependencies; this.clauses = clauses; } private static void validateFunctionalDependencies( - Collection parameters, Collection> functionalDependencies) { - var parameterSet = new HashSet<>(parameters); + Collection symbolicParameters, + Collection> functionalDependencies) { + var parameterSet = symbolicParameters.stream().map(SymbolicParameter::getVariable).collect(Collectors.toSet()); for (var functionalDependency : functionalDependencies) { - validateParameters(parameters, parameterSet, functionalDependency.forEach(), functionalDependency); - validateParameters(parameters, parameterSet, functionalDependency.unique(), functionalDependency); + validateParameters(symbolicParameters, parameterSet, functionalDependency.forEach(), functionalDependency); + validateParameters(symbolicParameters, parameterSet, functionalDependency.unique(), functionalDependency); } } - private static void validateParameters(Collection parameters, Set parameterSet, - Collection toValidate, + private static void validateParameters(Collection symbolicParameters, + 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)); + .formatted(variable, functionalDependency, symbolicParameters)); } } } @@ -75,13 +73,12 @@ public final class Dnf implements Constraint { return uniqueName; } - public List getParameters() { - return parameters; + public List getSymbolicParameters() { + return symbolicParameters; } - @Override - public List getSorts() { - return parameters.stream().map(Variable::getSort).toList(); + public List getParameters() { + return Collections.unmodifiableList(symbolicParameters); } public List> getFunctionalDependencies() { @@ -90,7 +87,7 @@ public final class Dnf implements Constraint { @Override public int arity() { - return parameters.size(); + return symbolicParameters.size(); } public List getClauses() { @@ -127,7 +124,8 @@ public final class Dnf implements Constraint { return false; } for (int i = 0; i < numClauses; i++) { - var literalEqualityHelper = new LiteralEqualityHelper(callEqualityChecker, parameters, other.parameters); + var literalEqualityHelper = new LiteralEqualityHelper(callEqualityChecker, symbolicParameters, + other.symbolicParameters); if (!clauses.get(i).equalsWithSubstitution(literalEqualityHelper, other.clauses.get(i))) { return false; } @@ -145,18 +143,18 @@ public final class Dnf implements Constraint { @Override public String toString() { - return "%s/%d".formatted(name, arity()); + return "%s/%d".formatted(name(), arity()); } @Override public String toReferenceString() { - return "@Dnf " + name; + return "@Dnf " + name(); } public String toDefinitionString() { var builder = new StringBuilder(); builder.append("pred ").append(name()).append("("); - var parameterIterator = parameters.iterator(); + var parameterIterator = symbolicParameters.iterator(); if (parameterIterator.hasNext()) { builder.append(parameterIterator.next()); while (parameterIterator.hasNext()) { diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java index a42ae558..3fac4627 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java @@ -7,20 +7,16 @@ package tools.refinery.store.query.dnf; import tools.refinery.store.query.dnf.callback.*; import tools.refinery.store.query.literal.Literal; -import tools.refinery.store.query.term.DataVariable; -import tools.refinery.store.query.term.NodeVariable; -import tools.refinery.store.query.term.Variable; +import tools.refinery.store.query.term.*; import java.util.*; @SuppressWarnings("UnusedReturnValue") public final class DnfBuilder { private final String name; - private final List parameters = new ArrayList<>(); - + private final Map directions = new HashMap<>(); private final List> functionalDependencies = new ArrayList<>(); - private final List> clauses = new ArrayList<>(); DnfBuilder(String name) { @@ -37,6 +33,18 @@ public final class DnfBuilder { return variable; } + public NodeVariable parameter(ParameterDirection direction) { + var variable = parameter(); + putDirection(variable, direction); + return variable; + } + + public NodeVariable parameter(String name, ParameterDirection direction) { + var variable = parameter(name); + putDirection(variable, direction); + return variable; + } + public DataVariable parameter(Class type) { return parameter(null, type); } @@ -47,6 +55,18 @@ public final class DnfBuilder { return variable; } + public DataVariable parameter(Class type, ParameterDirection direction) { + var variable = parameter(type); + putDirection(variable, direction); + return variable; + } + + public DataVariable parameter(String name, Class type, ParameterDirection direction) { + var variable = parameter(name, type); + putDirection(variable, direction); + return variable; + } + public DnfBuilder parameter(Variable variable) { if (parameters.contains(variable)) { throw new IllegalArgumentException("Duplicate parameter: " + variable); @@ -55,12 +75,49 @@ public final class DnfBuilder { return this; } + public DnfBuilder parameter(Variable variable, ParameterDirection direction) { + parameter(variable); + putDirection(variable, direction); + return this; + } + + private void putDirection(Variable variable, ParameterDirection direction) { + if (variable.tryGetType().isPresent()) { + if (direction == ParameterDirection.IN_OUT) { + throw new IllegalArgumentException("%s direction is forbidden for data variable %s" + .formatted(direction, variable)); + } + } else { + if (direction == ParameterDirection.OUT) { + throw new IllegalArgumentException("%s direction is forbidden for node variable %s" + .formatted(direction, variable)); + } + } + directions.put(variable, direction); + } + public DnfBuilder parameters(Variable... variables) { return parameters(List.of(variables)); } public DnfBuilder parameters(Collection variables) { - parameters.addAll(variables); + for (var variable : variables) { + parameter(variable); + } + return this; + } + + public DnfBuilder parameters(Collection variables, ParameterDirection direction) { + for (var variable : variables) { + parameter(variable, direction); + } + return this; + } + + public DnfBuilder symbolicParameters(Collection parameters) { + for (var parameter : parameters) { + parameter(parameter.getVariable(), parameter.getDirection()); + } return this; } @@ -152,54 +209,98 @@ public final class DnfBuilder { } public DnfBuilder clause(Collection literals) { - // Remove duplicates by using a hashed data structure. - var filteredLiterals = new LinkedHashSet(literals.size()); - for (var literal : literals) { - var reduction = literal.getReduction(); - switch (reduction) { - case NOT_REDUCIBLE -> filteredLiterals.add(literal); - case ALWAYS_TRUE -> { - // Literals reducible to {@code true} can be omitted, because the model is always assumed to have at - // least on object. - } - case ALWAYS_FALSE -> { - // Clauses with {@code false} literals can be omitted entirely. - return this; - } - default -> throw new IllegalArgumentException("Invalid reduction: " + reduction); - } - } - clauses.add(List.copyOf(filteredLiterals)); + clauses.add(List.copyOf(literals)); return this; } + void output(DataVariable outputVariable) { + var fromParameters = Set.copyOf(parameters); + parameter(outputVariable, ParameterDirection.OUT); + functionalDependency(fromParameters, Set.of(outputVariable)); + } + public Dnf build() { var postProcessedClauses = postProcessClauses(); - return new Dnf(name, Collections.unmodifiableList(parameters), + return new Dnf(name, createParameterList(postProcessedClauses), Collections.unmodifiableList(functionalDependencies), Collections.unmodifiableList(postProcessedClauses)); } - void output(DataVariable outputVariable) { - functionalDependency(Set.copyOf(parameters), Set.of(outputVariable)); - parameter(outputVariable); - } - private List postProcessClauses() { + var parameterSet = Collections.unmodifiableSet(new LinkedHashSet<>(parameters)); + var parameterWeights = getParameterWeights(); var postProcessedClauses = new ArrayList(clauses.size()); for (var literals : clauses) { - if (literals.isEmpty()) { - // Predicate will always match, the other clauses are irrelevant. - return List.of(new DnfClause(Set.of(), List.of())); - } - var variables = new HashSet(); - for (var literal : literals) { - variables.addAll(literal.getBoundVariables()); + var postProcessor = new ClausePostProcessor(parameterSet, parameterWeights, literals); + var result = postProcessor.postProcessClause(); + if (result instanceof ClausePostProcessor.ClauseResult clauseResult) { + postProcessedClauses.add(clauseResult.clause()); + } else if (result instanceof ClausePostProcessor.ConstantResult constantResult) { + switch (constantResult) { + case ALWAYS_TRUE -> { + return List.of(new DnfClause(Set.of(), List.of())); + } + case ALWAYS_FALSE -> { + // Skip this clause because it can never match. + } + default -> throw new IllegalStateException("Unexpected ClausePostProcessor.ConstantResult: " + + constantResult); + } + } else { + throw new IllegalStateException("Unexpected ClausePostProcessor.Result: " + result); } - parameters.forEach(variables::remove); - postProcessedClauses.add(new DnfClause(Collections.unmodifiableSet(variables), - Collections.unmodifiableList(literals))); } return postProcessedClauses; } + + private Map getParameterWeights() { + var mutableParameterWeights = new HashMap(); + int arity = parameters.size(); + for (int i = 0; i < arity; i++) { + mutableParameterWeights.put(parameters.get(i), i); + } + return Collections.unmodifiableMap(mutableParameterWeights); + } + + private List createParameterList(List postProcessedClauses) { + var outputParameterVariables = new HashSet<>(parameters); + for (var clause : postProcessedClauses) { + outputParameterVariables.retainAll(clause.positiveVariables()); + } + var parameterList = new ArrayList(parameters.size()); + for (var parameter : parameters) { + ParameterDirection direction = getDirection(outputParameterVariables, parameter); + parameterList.add(new SymbolicParameter(parameter, direction)); + } + return Collections.unmodifiableList(parameterList); + } + + private ParameterDirection getDirection(HashSet outputParameterVariables, Variable parameter) { + var direction = getInferredDirection(outputParameterVariables, parameter); + var expectedDirection = directions.get(parameter); + if (expectedDirection == ParameterDirection.IN && direction == ParameterDirection.IN_OUT) { + // Parameters may be explicitly marked as {@code @In} even if they are bound in all clauses. + return expectedDirection; + } + if (expectedDirection != null && expectedDirection != direction) { + throw new IllegalArgumentException("Expected parameter %s to have direction %s, but got %s instead" + .formatted(parameter, expectedDirection, direction)); + } + return direction; + } + + private static ParameterDirection getInferredDirection(HashSet outputParameterVariables, + Variable parameter) { + if (outputParameterVariables.contains(parameter)) { + if (parameter instanceof NodeVariable) { + return ParameterDirection.IN_OUT; + } else if (parameter instanceof AnyDataVariable) { + return ParameterDirection.OUT; + } else { + throw new IllegalArgumentException("Unknown parameter: " + parameter); + } + } else { + return ParameterDirection.IN; + } + } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java index a01d7d55..fdd0d47c 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java @@ -12,7 +12,7 @@ import tools.refinery.store.query.term.Variable; import java.util.List; import java.util.Set; -public record DnfClause(Set boundVariables, List literals) { +public record DnfClause(Set positiveVariables, List literals) { public boolean equalsWithSubstitution(LiteralEqualityHelper helper, DnfClause other) { int size = literals.size(); if (size != other.literals.size()) { diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java index 680fa631..57cb8baf 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java @@ -17,20 +17,21 @@ public final class FunctionalQuery implements Query { private final Class type; FunctionalQuery(Dnf dnf, Class type) { - var parameters = dnf.getParameters(); + var parameters = dnf.getSymbolicParameters(); int outputIndex = dnf.arity() - 1; for (int i = 0; i < outputIndex; i++) { var parameter = parameters.get(i); - if (!(parameter instanceof NodeVariable)) { - throw new IllegalArgumentException("Expected parameter %s of %s to be of sort %s, but got %s instead" - .formatted(parameter, dnf, NodeSort.INSTANCE, parameter.getSort())); + var parameterType = parameter.tryGetType(); + if (parameterType.isPresent()) { + throw new IllegalArgumentException("Expected parameter %s of %s to be a node variable, got %s instead" + .formatted(parameter, dnf, parameterType.get().getName())); } } var outputParameter = parameters.get(outputIndex); - if (!(outputParameter instanceof DataVariable dataOutputParameter) || - !dataOutputParameter.getType().equals(type)) { - throw new IllegalArgumentException("Expected parameter %s of %s to be of sort %s, but got %s instead" - .formatted(outputParameter, dnf, type, outputParameter.getSort())); + var outputParameterType = outputParameter.tryGetType(); + if (outputParameterType.isEmpty() || !outputParameterType.get().equals(type)) { + throw new IllegalArgumentException("Expected parameter %s of %s to be %s, but got %s instead".formatted( + outputParameter, dnf, type, outputParameterType.map(Class::getName).orElse("node"))); } this.dnf = dnf; this.type = type; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java index 0741d8d9..c043a285 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java @@ -8,7 +8,6 @@ package tools.refinery.store.query.dnf; import tools.refinery.store.query.literal.CallLiteral; import tools.refinery.store.query.literal.CallPolarity; import tools.refinery.store.query.term.AssignedValue; -import tools.refinery.store.query.term.NodeSort; import tools.refinery.store.query.term.NodeVariable; import java.util.Collections; @@ -19,10 +18,11 @@ public final class RelationalQuery implements Query { private final Dnf dnf; RelationalQuery(Dnf dnf) { - for (var parameter : dnf.getParameters()) { - if (!(parameter instanceof NodeVariable)) { - throw new IllegalArgumentException("Expected parameter %s of %s to be of sort %s, but got %s instead" - .formatted(parameter, dnf, NodeSort.INSTANCE, parameter.getSort())); + for (var parameter : dnf.getSymbolicParameters()) { + var parameterType = parameter.tryGetType(); + if (parameterType.isPresent()) { + throw new IllegalArgumentException("Expected parameter %s of %s to be a node variable, got %s instead" + .formatted(parameter, dnf, parameterType.get().getName())); } } this.dnf = dnf; @@ -77,7 +77,6 @@ public final class RelationalQuery implements Query { return dnf.count(arguments); } - @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java new file mode 100644 index 00000000..e2f05bde --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.dnf; + +import tools.refinery.store.query.term.Parameter; +import tools.refinery.store.query.term.ParameterDirection; +import tools.refinery.store.query.term.Variable; + +import java.util.Objects; + +public final class SymbolicParameter extends Parameter { + private final Variable variable; + + public SymbolicParameter(Variable variable, ParameterDirection direction) { + super(variable.tryGetType().orElse(null), direction); + this.variable = variable; + } + + public Variable getVariable() { + return variable; + } + + @Override + public String toString() { + var direction = getDirection(); + if (direction == ParameterDirection.IN_OUT) { + return variable.toString(); + } + return "%s %s".formatted(getDirection(), variable); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + SymbolicParameter that = (SymbolicParameter) o; + return Objects.equals(variable, that.variable); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), variable); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java index 0f6ee6c2..9315fb30 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java @@ -6,6 +6,7 @@ package tools.refinery.store.query.equality; import tools.refinery.store.query.dnf.Dnf; +import tools.refinery.store.query.dnf.SymbolicParameter; import tools.refinery.store.query.term.Variable; import java.util.HashMap; @@ -17,8 +18,8 @@ public class LiteralEqualityHelper { private final Map leftToRight; private final Map rightToLeft; - public LiteralEqualityHelper(DnfEqualityChecker dnfEqualityChecker, List leftParameters, - List rightParameters) { + public LiteralEqualityHelper(DnfEqualityChecker dnfEqualityChecker, List leftParameters, + List rightParameters) { this.dnfEqualityChecker = dnfEqualityChecker; var arity = leftParameters.size(); if (arity != rightParameters.size()) { @@ -27,7 +28,7 @@ public class LiteralEqualityHelper { leftToRight = new HashMap<>(arity); rightToLeft = new HashMap<>(arity); for (int i = 0; i < arity; i++) { - if (!variableEqual(leftParameters.get(i), rightParameters.get(i))) { + if (!variableEqual(leftParameters.get(i).getVariable(), rightParameters.get(i).getVariable())) { throw new IllegalArgumentException("Parameter lists cannot be unified: duplicate parameter " + i); } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/exceptions/IncompatibleParameterDirectionException.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/exceptions/IncompatibleParameterDirectionException.java new file mode 100644 index 00000000..52da20ae --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/exceptions/IncompatibleParameterDirectionException.java @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.exceptions; + +public class IncompatibleParameterDirectionException extends RuntimeException { + public IncompatibleParameterDirectionException(String message) { + super(message); + } + + public IncompatibleParameterDirectionException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java index b08c1037..55db04e0 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java @@ -25,13 +25,13 @@ public abstract class AbstractCallLiteral implements Literal { } this.target = target; this.arguments = arguments; - var sorts = target.getSorts(); + var parameters = target.getParameters(); for (int i = 0; i < arity; i++) { var argument = arguments.get(i); - var sort = sorts.get(i); - if (!sort.isInstance(argument)) { - throw new IllegalArgumentException("Required argument %d of %s to be of sort %s, but got %s instead" - .formatted(i, target, sort, argument.getSort())); + var parameter = parameters.get(i); + if (!parameter.isAssignable(argument)) { + throw new IllegalArgumentException("Argument %d of %s is not assignable to parameter %s" + .formatted(i, target, parameter)); } } } @@ -80,6 +80,6 @@ public abstract class AbstractCallLiteral implements Literal { @Override public int hashCode() { - return Objects.hash(target, arguments); + return Objects.hash(getClass(), target, arguments); } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java index 93e59291..2aa0a0d5 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java @@ -14,12 +14,12 @@ import tools.refinery.store.query.term.Variable; import java.util.List; import java.util.Objects; -import java.util.Set; public class AggregationLiteral extends AbstractCallLiteral { private final DataVariable resultVariable; private final DataVariable inputVariable; private final Aggregator aggregator; + private final VariableBinder variableBinder; public AggregationLiteral(DataVariable resultVariable, Aggregator aggregator, DataVariable inputVariable, Constraint target, List arguments) { @@ -32,10 +32,6 @@ public class AggregationLiteral extends AbstractCallLiteral { throw new IllegalArgumentException("Result variable %s must of type %s, got %s instead".formatted( resultVariable, aggregator.getResultType().getName(), resultVariable.getType().getName())); } - if (!arguments.contains(inputVariable)) { - throw new IllegalArgumentException("Input variable %s must appear in the argument list".formatted( - inputVariable)); - } if (arguments.contains(resultVariable)) { throw new IllegalArgumentException("Result variable %s must not appear in the argument list".formatted( resultVariable)); @@ -43,6 +39,14 @@ public class AggregationLiteral extends AbstractCallLiteral { this.resultVariable = resultVariable; this.inputVariable = inputVariable; this.aggregator = aggregator; + variableBinder = VariableBinder.builder() + .variable(resultVariable, VariableDirection.OUT) + .parameterList(false, target.getParameters(), arguments) + .build(); + if (variableBinder.getDirection(inputVariable) != VariableDirection.CLOSURE) { + throw new IllegalArgumentException("Input variable %s must appear in the argument list".formatted( + inputVariable)); + } } public DataVariable getResultVariable() { @@ -58,8 +62,8 @@ public class AggregationLiteral extends AbstractCallLiteral { } @Override - public Set getBoundVariables() { - return Set.of(resultVariable); + public VariableBinder getVariableBinder() { + return variableBinder; } @Override diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java index 8cc3fae6..4da92b90 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java @@ -9,21 +9,43 @@ import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; import tools.refinery.store.query.term.DataVariable; import tools.refinery.store.query.term.Term; -import tools.refinery.store.query.term.Variable; -import java.util.Set; +import java.util.Objects; -public record AssignLiteral(DataVariable variable, Term term) implements Literal { - public AssignLiteral { +public final class AssignLiteral implements Literal { + private final DataVariable variable; + private final Term term; + private final VariableBinder variableBinder; + + public AssignLiteral(DataVariable variable, Term term) { if (!term.getType().equals(variable.getType())) { throw new IllegalArgumentException("Term %s must be of type %s, got %s instead".formatted( term, variable.getType().getName(), term.getType().getName())); } + this.variable = variable; + this.term = term; + var inputVariables = term.getInputVariables(); + if (inputVariables.contains(variable)) { + throw new IllegalArgumentException("Result variable %s must not appear in the term %s".formatted( + variable, term)); + } + variableBinder = VariableBinder.builder() + .variable(variable, VariableDirection.OUT) + .variables(inputVariables, VariableDirection.IN) + .build(); + } + + public DataVariable getTargetVariable() { + return variable; + } + + public Term getTerm() { + return term; } @Override - public Set getBoundVariables() { - return Set.of(variable); + public VariableBinder getVariableBinder() { + return variableBinder; } @Override @@ -41,9 +63,22 @@ public record AssignLiteral(DataVariable variable, Term term) implement otherLetLiteral.term); } - @Override public String toString() { return "%s is (%s)".formatted(variable, term); } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || obj.getClass() != this.getClass()) return false; + var that = (AssignLiteral) obj; + return Objects.equals(this.variable, that.variable) && + Objects.equals(this.term, that.term); + } + + @Override + public int hashCode() { + return Objects.hash(getClass(), variable, term); + } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java index 59538831..61486e4c 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java @@ -9,21 +9,31 @@ import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; import tools.refinery.store.query.term.ConstantTerm; import tools.refinery.store.query.term.Term; -import tools.refinery.store.query.term.Variable; -import java.util.Set; +import java.util.Objects; -public record AssumeLiteral(Term term) implements Literal { - public AssumeLiteral { +public final class AssumeLiteral implements Literal { + private final Term term; + private final VariableBinder variableBinder; + + public AssumeLiteral(Term term) { if (!term.getType().equals(Boolean.class)) { throw new IllegalArgumentException("Term %s must be of type %s, got %s instead".formatted( term, Boolean.class.getName(), term.getType().getName())); } + this.term = term; + variableBinder = VariableBinder.builder() + .variables(term.getInputVariables(), VariableDirection.IN) + .build(); + } + + public Term getTerm() { + return term; } @Override - public Set getBoundVariables() { - return Set.of(); + public VariableBinder getVariableBinder() { + return variableBinder; } @Override @@ -54,4 +64,17 @@ public record AssumeLiteral(Term term) implements Literal { public String toString() { return "(%s)".formatted(term); } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || obj.getClass() != this.getClass()) return false; + var that = (AssumeLiteral) obj; + return Objects.equals(this.term, that.term); + } + + @Override + public int hashCode() { + return Objects.hash(getClass(), term); + } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java index a32cfd80..e61f0535 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java @@ -5,12 +5,9 @@ */ package tools.refinery.store.query.literal; -import tools.refinery.store.query.term.Variable; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; -import java.util.Set; - public enum BooleanLiteral implements CanNegate { TRUE(true), FALSE(false); @@ -22,8 +19,8 @@ public enum BooleanLiteral implements CanNegate { } @Override - public Set getBoundVariables() { - return Set.of(); + public VariableBinder getVariableBinder() { + return VariableBinder.EMPTY; } @Override diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java index 82088c8b..dc6098a8 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java @@ -8,28 +8,31 @@ package tools.refinery.store.query.literal; import tools.refinery.store.query.Constraint; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; -import tools.refinery.store.query.term.NodeSort; import tools.refinery.store.query.term.Variable; import java.util.List; import java.util.Objects; -import java.util.Set; public final class CallLiteral extends AbstractCallLiteral implements CanNegate { private final CallPolarity polarity; + private final VariableBinder variableBinder; public CallLiteral(CallPolarity polarity, Constraint target, List arguments) { super(target, arguments); + var parameters = target.getParameters(); + int arity = target.arity(); if (polarity.isTransitive()) { - if (target.arity() != 2) { + if (arity != 2) { throw new IllegalArgumentException("Transitive closures can only take binary relations"); } - var sorts = target.getSorts(); - if (!sorts.get(0).equals(NodeSort.INSTANCE) || !sorts.get(1).equals(NodeSort.INSTANCE)) { + if (parameters.get(0).isDataVariable() || parameters.get(1).isDataVariable()) { throw new IllegalArgumentException("Transitive closures can only be computed over nodes"); } } this.polarity = polarity; + variableBinder = VariableBinder.builder() + .parameterList(polarity.isPositive(), parameters, arguments) + .build(); } public CallPolarity getPolarity() { @@ -37,8 +40,8 @@ public final class CallLiteral extends AbstractCallLiteral implements CanNegate< } @Override - public Set getBoundVariables() { - return polarity.isPositive() ? Set.copyOf(getArguments()) : Set.of(); + public VariableBinder getVariableBinder() { + return variableBinder; } @Override diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java index fa7979d1..7466cb1d 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java @@ -8,14 +8,31 @@ package tools.refinery.store.query.literal; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; import tools.refinery.store.query.term.NodeVariable; -import tools.refinery.store.query.term.Variable; -import java.util.Set; +import java.util.Objects; + +public final class ConstantLiteral implements Literal { + private final NodeVariable variable; + private final int nodeId; + private final VariableBinder variableBinder; + + public ConstantLiteral(NodeVariable variable, int nodeId) { + this.variable = variable; + this.nodeId = nodeId; + variableBinder = VariableBinder.builder().variable(variable, VariableDirection.IN_OUT).build(); + } + + public NodeVariable getVariable() { + return variable; + } + + public int getNodeId() { + return nodeId; + } -public record ConstantLiteral(NodeVariable variable, int nodeId) implements Literal { @Override - public Set getBoundVariables() { - return Set.of(variable); + public VariableBinder getVariableBinder() { + return variableBinder; } @Override @@ -32,8 +49,23 @@ public record ConstantLiteral(NodeVariable variable, int nodeId) implements Lite return helper.variableEqual(variable, otherConstantLiteral.variable) && nodeId == otherConstantLiteral.nodeId; } + @Override public String toString() { return "%s === @Constant %d".formatted(variable, nodeId); } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || obj.getClass() != this.getClass()) return false; + var that = (ConstantLiteral) obj; + return Objects.equals(this.variable, that.variable) && + this.nodeId == that.nodeId; + } + + @Override + public int hashCode() { + return Objects.hash(getClass(), variable, nodeId); + } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java index 11f78fa8..a602d982 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java @@ -13,10 +13,10 @@ import tools.refinery.store.query.term.Variable; import java.util.List; import java.util.Objects; -import java.util.Set; public class CountLiteral extends AbstractCallLiteral { private final DataVariable resultVariable; + private final VariableBinder variableBinder; public CountLiteral(DataVariable resultVariable, Constraint target, List arguments) { super(target, arguments); @@ -29,6 +29,10 @@ public class CountLiteral extends AbstractCallLiteral { .formatted(resultVariable)); } this.resultVariable = resultVariable; + variableBinder = VariableBinder.builder() + .variable(resultVariable, VariableDirection.OUT) + .parameterList(false, target.getParameters(), arguments) + .build(); } public DataVariable getResultVariable() { @@ -36,8 +40,8 @@ public class CountLiteral extends AbstractCallLiteral { } @Override - public Set getBoundVariables() { - return Set.of(resultVariable); + public VariableBinder getVariableBinder() { + return variableBinder; } @Override diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java index 3876574c..794cee0d 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java @@ -5,20 +5,44 @@ */ package tools.refinery.store.query.literal; -import tools.refinery.store.query.term.NodeVariable; -import tools.refinery.store.query.term.Variable; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.NodeVariable; -import java.util.Set; +import java.util.Objects; -public record EquivalenceLiteral(boolean positive, NodeVariable left, NodeVariable right) +public final class EquivalenceLiteral implements CanNegate { + private final boolean positive; + private final NodeVariable left; + private final NodeVariable right; + private final VariableBinder variableBinder; + + public EquivalenceLiteral(boolean positive, NodeVariable left, NodeVariable right) { + this.positive = positive; + this.left = left; + this.right = right; + variableBinder = VariableBinder.builder() + .variable(left, positive ? VariableDirection.IN_OUT : VariableDirection.IN) + .variable(right, VariableDirection.IN) + .build(); + } + + public boolean isPositive() { + return positive; + } + + public NodeVariable getLeft() { + return left; + } + + public NodeVariable getRight() { + return right; + } + @Override - public Set getBoundVariables() { - // If one side of a {@code positive} equivalence is bound, it may bind its other side, but we under-approximate - // this behavior by not binding any of the sides by default. - return Set.of(); + public VariableBinder getVariableBinder() { + return variableBinder; } @Override @@ -54,4 +78,19 @@ public record EquivalenceLiteral(boolean positive, NodeVariable left, NodeVariab public String toString() { return "%s %s %s".formatted(left, positive ? "===" : "!==", right); } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || obj.getClass() != this.getClass()) return false; + var that = (EquivalenceLiteral) obj; + return this.positive == that.positive && + Objects.equals(this.left, that.left) && + Objects.equals(this.right, that.right); + } + + @Override + public int hashCode() { + return Objects.hash(getClass(), positive, left, right); + } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java index 52411ee8..c3c111a4 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java @@ -5,14 +5,11 @@ */ package tools.refinery.store.query.literal; -import tools.refinery.store.query.term.Variable; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; -import java.util.Set; - public interface Literal { - Set getBoundVariables(); + VariableBinder getVariableBinder(); Literal substitute(Substitution substitution); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableBinder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableBinder.java new file mode 100644 index 00000000..5f43d07d --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableBinder.java @@ -0,0 +1,64 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.literal; + +import tools.refinery.store.query.term.Variable; + +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; + +public final class VariableBinder { + public static final VariableBinder EMPTY = new VariableBinder(Map.of()); + + private final Map directionMap; + + VariableBinder(Map directionMap) { + this.directionMap = directionMap; + } + + public VariableDirection getDirection(Variable variable) { + var direction = directionMap.get(variable); + if (direction == null) { + throw new IllegalArgumentException("No such variable " + variable); + } + return direction; + } + + public VariableDirection getDirection(Variable variable, Set positiveVariables) { + var direction = getDirection(variable); + return disambiguateDirection(direction, variable, positiveVariables); + } + + public Stream getVariablesWithDirection(VariableDirection direction) { + return directionMap.entrySet().stream() + .filter(pair -> pair.getValue() == direction) + .map(Map.Entry::getKey); + } + + public Stream getVariablesWithDirection(VariableDirection direction, + Set positiveVariables) { + if (direction == VariableDirection.NEGATIVE) { + throw new IllegalArgumentException("Use #getVariablesWithDirection(VariableDirection) if disambiguation " + + "of VariableDirection#NEGATIVE variables according to the containing DnfClose is not desired"); + } + return directionMap.entrySet().stream() + .filter(pair -> disambiguateDirection(pair.getValue(), pair.getKey(), positiveVariables) == direction) + .map(Map.Entry::getKey); + } + + private VariableDirection disambiguateDirection(VariableDirection direction, Variable variable, + Set positiveVariables) { + if (direction != VariableDirection.NEGATIVE) { + return direction; + } + return positiveVariables.contains(variable) ? VariableDirection.IN : VariableDirection.CLOSURE; + } + + public static VariableBinderBuilder builder() { + return new VariableBinderBuilder(); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableBinderBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableBinderBuilder.java new file mode 100644 index 00000000..b0d47240 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableBinderBuilder.java @@ -0,0 +1,96 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.literal; + +import tools.refinery.store.query.exceptions.IncompatibleParameterDirectionException; +import tools.refinery.store.query.term.*; + +import java.util.*; + +public final class VariableBinderBuilder { + private final Map directionMap = new LinkedHashMap<>(); + private final Set uniqueVariables = new HashSet<>(); + + VariableBinderBuilder() { + } + + public VariableBinderBuilder variable(Variable variable, VariableDirection direction) { + return variable(variable, direction, direction == VariableDirection.OUT); + } + + private VariableBinderBuilder variable(Variable variable, VariableDirection direction, boolean markAsUnique) { + validateDirection(variable, direction); + boolean unique = shouldBeUnique(variable, markAsUnique); + directionMap.compute(variable, (ignored, oldValue) -> { + if (oldValue == null) { + return direction; + } + if (unique) { + throw new IllegalArgumentException("Duplicate binding for variable " + variable); + } + try { + return oldValue.merge(direction); + } catch (IncompatibleParameterDirectionException e) { + var message = "%s for variable %s".formatted(e.getMessage(), variable); + throw new IncompatibleParameterDirectionException(message, e); + } + }); + return this; + } + + private static void validateDirection(Variable variable, VariableDirection direction) { + if (variable instanceof AnyDataVariable) { + if (direction == VariableDirection.IN_OUT) { + throw new IllegalArgumentException("%s direction is not supported for data variable %s" + .formatted(direction, variable)); + } + } else if (variable instanceof NodeVariable) { + if (direction == VariableDirection.OUT) { + throw new IllegalArgumentException("%s direction is not supported for node variable %s" + .formatted(direction, variable)); + } + } else { + throw new IllegalArgumentException("Unknown variable " + variable); + } + } + + private boolean shouldBeUnique(Variable variable, boolean markAsUnique) { + if (markAsUnique) { + uniqueVariables.add(variable); + return true; + } else { + return uniqueVariables.contains(variable); + } + } + + public VariableBinderBuilder variables(Collection variables, VariableDirection direction) { + for (var variable : variables) { + variable(variable, direction); + } + return this; + } + + public VariableBinderBuilder parameterList(boolean positive, List parameters, + List arguments) { + int arity = parameters.size(); + if (arity != arguments.size()) { + throw new IllegalArgumentException("Got %d arguments for %d parameters" + .formatted(arguments.size(), arity)); + } + for (int i = 0; i < arity; i++) { + var argument = arguments.get(i); + var parameter = parameters.get(i); + var parameterDirection = parameter.getDirection(); + var direction = VariableDirection.from(positive, parameterDirection); + variable(argument, direction, parameterDirection == ParameterDirection.OUT); + } + return this; + } + + public VariableBinder build() { + return new VariableBinder(directionMap); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableDirection.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableDirection.java new file mode 100644 index 00000000..444dcbbf --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableDirection.java @@ -0,0 +1,101 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.literal; + +import tools.refinery.store.query.exceptions.IncompatibleParameterDirectionException; +import tools.refinery.store.query.term.ParameterDirection; + +public enum VariableDirection { + /** + * Binds a node variable or check equality with a node variable. + *

+ * This is the usual direction for positive constraints on nodes. A data variable may have multiple {@code InOut} + * bindings, even on the same parameter list. + *

+ * Cannot be used for data variables. + */ + IN_OUT("@InOut"), + + /** + * Binds a data variable. + *

+ * A single variable must have at most one {@code @Out} binding. A variable with a {@code @Out} binding cannot + * appear in any other place in a parameter list. + *

+ * Cannot be used for node variables. + */ + OUT("@Out"), + + /** + * Either takes a bound data variable or enumerates all possible data variable bindings. + *

+ * Cannot be used for data variables. + */ + NEGATIVE("@Negative"), + + /** + * Takes an already bound variable. + *

+ * May be used with node or data variables. An {@code @InOut} or {@code @Out} binding on the same parameter list + * cannot satisfy the {@code @In} binding, because it might introduce a (non-monotonic) circular dependency. + */ + IN("@In"), + + /** + * Enumerates over all possible data variable bindings. + *

+ * May be used with node or data variables. The variable may not appear in any other parameter list. A data + * variable may only appear once in the parameter list, but node variables can appear multiple times to form + * diagonal constraints. + */ + CLOSURE("@Closure"); + + private final String name; + + VariableDirection(String name) { + this.name = name; + } + + public VariableDirection merge(VariableDirection other) { + switch (this) { + case IN_OUT -> { + if (other == IN_OUT) { + return this; + } + } + case OUT -> { + if (other == OUT) { + throw new IncompatibleParameterDirectionException("Multiple %s bindings".formatted(this)); + } + } + case NEGATIVE -> { + if (other == NEGATIVE || other == IN || other == CLOSURE) { + return other; + } + } + case IN, CLOSURE -> { + if (other == NEGATIVE || other == this) { + return this; + } + } + } + throw new IncompatibleParameterDirectionException("Incompatible variable directions %s and %s" + .formatted(this, other)); + } + + @Override + public String toString() { + return name; + } + + public static VariableDirection from(boolean positive, ParameterDirection parameterDirection) { + return switch (parameterDirection) { + case IN_OUT -> positive ? IN_OUT : NEGATIVE; + case OUT -> positive ? OUT : CLOSURE; + case IN -> IN; + }; + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/SubstitutionBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/SubstitutionBuilder.java index 658a26e3..37fb6908 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/SubstitutionBuilder.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/SubstitutionBuilder.java @@ -32,9 +32,10 @@ public class SubstitutionBuilder { } public SubstitutionBuilder putChecked(Variable original, Variable substitute) { - if (!original.getSort().equals(substitute.getSort())) { + if (!original.tryGetType().equals(substitute.tryGetType())) { throw new IllegalArgumentException("Cannot substitute variable %s of sort %s with variable %s of sort %s" - .formatted(original, original.getSort(), substitute, substitute.getSort())); + .formatted(original, original.tryGetType().map(Class::getName).orElse("node"), substitute, + substitute.tryGetType().map(Class::getName).orElse("node"))); } if (map.containsKey(original)) { throw new IllegalArgumentException("Already has substitution for variable %s".formatted(original)); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java index ccc063af..5864ee56 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java @@ -8,6 +8,7 @@ package tools.refinery.store.query.term; import org.jetbrains.annotations.Nullable; import tools.refinery.store.query.equality.LiteralEqualityHelper; +import java.util.Optional; import java.util.Set; public abstract sealed class AnyDataVariable extends Variable implements AnyTerm permits DataVariable { @@ -15,6 +16,11 @@ public abstract sealed class AnyDataVariable extends Variable implements AnyTerm super(name); } + @Override + public Optional> tryGetType() { + return Optional.of(getType()); + } + @Override public NodeVariable asNodeVariable() { throw new IllegalStateException("%s is a data variable".formatted(this)); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataSort.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataSort.java deleted file mode 100644 index 6b8669ee..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataSort.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term; - -import org.jetbrains.annotations.Nullable; - -public record DataSort(Class type) implements Sort { - public static final DataSort INT = new DataSort<>(Integer.class); - - public static final DataSort BOOL = new DataSort<>(Boolean.class); - - @Override - public boolean isInstance(Variable variable) { - return variable instanceof DataVariable dataVariable && type.equals(dataVariable.getType()); - } - - @Override - public DataVariable newInstance(@Nullable String name) { - return Variable.of(name, type); - } - - @Override - public DataVariable newInstance() { - return newInstance(null); - } - - @Override - public String toString() { - return type.getName(); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java index db160f68..00950360 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java @@ -21,11 +21,6 @@ public final class DataVariable extends AnyDataVariable implements Term { this.type = type; } - @Override - public DataSort getSort() { - return new DataSort<>(getType()); - } - @Override public Class getType() { return type; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeSort.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeSort.java deleted file mode 100644 index b9be03f7..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeSort.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term; - -import org.jetbrains.annotations.Nullable; - -public final class NodeSort implements Sort { - public static final NodeSort INSTANCE = new NodeSort(); - - private NodeSort() { - } - - @Override - public boolean isInstance(Variable variable) { - return variable instanceof NodeVariable; - } - - @Override - public NodeVariable newInstance(@Nullable String name) { - return new NodeVariable(name); - } - - @Override - public NodeVariable newInstance() { - return newInstance(null); - } - - @Override - public String toString() { - return ""; - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java index de2f945a..37f9d477 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java @@ -9,14 +9,16 @@ import org.jetbrains.annotations.Nullable; import tools.refinery.store.query.literal.ConstantLiteral; import tools.refinery.store.query.literal.EquivalenceLiteral; +import java.util.Optional; + public final class NodeVariable extends Variable { NodeVariable(@Nullable String name) { super(name); } @Override - public NodeSort getSort() { - return NodeSort.INSTANCE; + public Optional> tryGetType() { + return Optional.empty(); } @Override diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Parameter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Parameter.java new file mode 100644 index 00000000..29aedbef --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Parameter.java @@ -0,0 +1,63 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term; + +import java.util.Objects; +import java.util.Optional; + +public class Parameter { + public static final Parameter NODE_IN_OUT = new Parameter(null, ParameterDirection.IN_OUT); + + private final Class dataType; + private final ParameterDirection direction; + + public Parameter(Class dataType, ParameterDirection direction) { + this.dataType = dataType; + this.direction = direction; + if (isDataVariable()) { + if (direction == ParameterDirection.IN_OUT) { + throw new IllegalArgumentException("IN_OUT direction is not supported for data parameters"); + } + } else if (direction == ParameterDirection.OUT) { + throw new IllegalArgumentException("OUT direction is not supported for node parameters"); + } + } + + public boolean isDataVariable() { + return dataType != null; + } + + public Optional> tryGetType() { + return Optional.ofNullable(dataType); + } + + public ParameterDirection getDirection() { + return direction; + } + + public boolean isAssignable(Variable variable) { + if (variable instanceof AnyDataVariable dataVariable) { + return dataVariable.getType().equals(dataType); + } else if (variable instanceof NodeVariable) { + return !isDataVariable(); + } else { + throw new IllegalArgumentException("Unknown variable " + variable); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Parameter parameter = (Parameter) o; + return Objects.equals(dataType, parameter.dataType) && direction == parameter.direction; + } + + @Override + public int hashCode() { + return Objects.hash(dataType, direction); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ParameterDirection.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ParameterDirection.java new file mode 100644 index 00000000..652208aa --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ParameterDirection.java @@ -0,0 +1,23 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.term; + +public enum ParameterDirection { + IN_OUT("@InOut"), + OUT("@Out"), + IN("@In"); + + private final String name; + + ParameterDirection(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Sort.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Sort.java deleted file mode 100644 index 2b3345f9..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Sort.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.term; - -import org.jetbrains.annotations.Nullable; - -public sealed interface Sort permits DataSort, NodeSort { - boolean isInstance(Variable variable); - - Variable newInstance(@Nullable String name); - - Variable newInstance(); -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java index c4ca6f77..869120fa 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java @@ -9,6 +9,7 @@ import org.jetbrains.annotations.Nullable; import tools.refinery.store.query.dnf.DnfUtils; import java.util.Objects; +import java.util.Optional; public abstract sealed class Variable permits AnyDataVariable, NodeVariable { private final String explicitName; @@ -19,7 +20,7 @@ public abstract sealed class Variable permits AnyDataVariable, NodeVariable { uniqueName = DnfUtils.generateUniqueName(name); } - public abstract Sort getSort(); + public abstract Optional> tryGetType(); public String getName() { return explicitName == null ? uniqueName : explicitName; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java index c0aa35bf..c6f3dd43 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java @@ -7,12 +7,12 @@ package tools.refinery.store.query.view; import tools.refinery.store.model.Model; import tools.refinery.store.query.dnf.FunctionalDependency; -import tools.refinery.store.query.term.NodeSort; -import tools.refinery.store.query.term.Sort; +import tools.refinery.store.query.term.Parameter; import tools.refinery.store.representation.Symbol; import tools.refinery.store.tuple.Tuple; import tools.refinery.store.tuple.Tuple1; +import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Set; @@ -21,10 +21,12 @@ import java.util.stream.IntStream; public abstract class AbstractFunctionView extends SymbolView { private final T defaultValue; + private final List parameters; - protected AbstractFunctionView(Symbol symbol, String name) { + protected AbstractFunctionView(Symbol symbol, String name, Parameter outParameter) { super(symbol, name); defaultValue = symbol.defaultValue(); + parameters = createParameters(symbol.arity(), outParameter); } @Override @@ -48,8 +50,6 @@ public abstract class AbstractFunctionView extends SymbolView { return !Objects.equals(defaultValue, value); } - protected abstract Sort getForwardMappedValueSort(); - protected Object forwardMapValue(Tuple key, T value) { return value; } @@ -85,19 +85,8 @@ public abstract class AbstractFunctionView extends SymbolView { } @Override - public int arity() { - return getSymbol().arity() + 1; - } - - @Override - public List getSorts() { - var sorts = new Sort[arity()]; - int valueIndex = sorts.length - 1; - for (int i = 0; i < valueIndex; i++) { - sorts[i] = NodeSort.INSTANCE; - } - sorts[valueIndex] = getForwardMappedValueSort(); - return List.of(sorts); + public List getParameters() { + return parameters; } @Override @@ -106,11 +95,18 @@ public abstract class AbstractFunctionView extends SymbolView { if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; AbstractFunctionView that = (AbstractFunctionView) o; - return Objects.equals(defaultValue, that.defaultValue); + return Objects.equals(defaultValue, that.defaultValue) && Objects.equals(parameters, that.parameters); } @Override public int hashCode() { - return Objects.hash(super.hashCode(), defaultValue); + return Objects.hash(super.hashCode(), defaultValue, parameters); + } + + private static List createParameters(int symbolArity, Parameter outParameter) { + var parameters = new Parameter[symbolArity + 1]; + Arrays.fill(parameters, Parameter.NODE_IN_OUT); + parameters[symbolArity] = outParameter; + return List.of(parameters); } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionView.java index cf946d54..1b89e77c 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionView.java @@ -5,21 +5,16 @@ */ package tools.refinery.store.query.view; -import tools.refinery.store.query.term.DataSort; -import tools.refinery.store.query.term.Sort; +import tools.refinery.store.query.term.Parameter; +import tools.refinery.store.query.term.ParameterDirection; import tools.refinery.store.representation.Symbol; public final class FunctionView extends AbstractFunctionView { public FunctionView(Symbol symbol, String name) { - super(symbol, name); + super(symbol, name, new Parameter(symbol.valueType(), ParameterDirection.OUT)); } public FunctionView(Symbol symbol) { this(symbol, "function"); } - - @Override - protected Sort getForwardMappedValueSort() { - return new DataSort<>(getSymbol().valueType()); - } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/NodeFunctionView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/NodeFunctionView.java index 73c296e0..e9785c67 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/NodeFunctionView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/NodeFunctionView.java @@ -5,22 +5,16 @@ */ package tools.refinery.store.query.view; -import tools.refinery.store.query.term.NodeSort; -import tools.refinery.store.query.term.Sort; +import tools.refinery.store.query.term.Parameter; import tools.refinery.store.representation.Symbol; import tools.refinery.store.tuple.Tuple1; public final class NodeFunctionView extends AbstractFunctionView { public NodeFunctionView(Symbol symbol, String name) { - super(symbol, name); + super(symbol, name, Parameter.NODE_IN_OUT); } public NodeFunctionView(Symbol symbol) { this(symbol, "function"); } - - @Override - protected Sort getForwardMappedValueSort() { - return NodeSort.INSTANCE; - } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingView.java index 19862e3a..7e5b7788 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingView.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingView.java @@ -6,22 +6,26 @@ package tools.refinery.store.query.view; import tools.refinery.store.model.Model; -import tools.refinery.store.query.term.NodeSort; -import tools.refinery.store.query.term.Sort; +import tools.refinery.store.query.term.Parameter; +import tools.refinery.store.representation.Symbol; import tools.refinery.store.tuple.Tuple; import tools.refinery.store.tuple.Tuple1; -import tools.refinery.store.representation.Symbol; import java.util.Arrays; import java.util.List; +import java.util.Objects; public abstract class TuplePreservingView extends SymbolView { + private final List parameters; + protected TuplePreservingView(Symbol symbol, String name) { super(symbol, name); + this.parameters = createParameters(symbol.arity()); } protected TuplePreservingView(Symbol symbol) { super(symbol); + this.parameters = createParameters(symbol.arity()); } public Object[] forwardMap(Tuple key) { @@ -52,14 +56,27 @@ public abstract class TuplePreservingView extends SymbolView { } @Override - public int arity() { - return this.getSymbol().arity(); + public List getParameters() { + return parameters; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + TuplePreservingView that = (TuplePreservingView) o; + return Objects.equals(parameters, that.parameters); } @Override - public List getSorts() { - var sorts = new Sort[arity()]; - Arrays.fill(sorts, NodeSort.INSTANCE); - return List.of(sorts); + public int hashCode() { + return Objects.hash(super.hashCode(), parameters); + } + + private static List createParameters(int arity) { + var parameters = new Parameter[arity]; + Arrays.fill(parameters, Parameter.NODE_IN_OUT); + return List.of(parameters); } } diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java deleted file mode 100644 index 01e2ccf6..00000000 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java +++ /dev/null @@ -1,266 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; -import tools.refinery.store.query.dnf.Dnf; -import tools.refinery.store.query.literal.BooleanLiteral; -import tools.refinery.store.query.term.Variable; -import tools.refinery.store.query.term.bool.BoolTerms; -import tools.refinery.store.query.view.KeyOnlyView; -import tools.refinery.store.representation.Symbol; - -import static org.hamcrest.MatcherAssert.assertThat; -import static tools.refinery.store.query.literal.Literals.assume; -import static tools.refinery.store.query.literal.Literals.not; -import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo; - -class DnfBuilderTest { - @Test - void eliminateTrueTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - - var actual = Dnf.builder() - .parameters(p, q) - .clause(BooleanLiteral.TRUE, friendView.call(p, q)) - .build(); - var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); - - assertThat(actual, structurallyEqualTo(expected)); - } - - @Test - void eliminateTrueAssumptionTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - - var actual = Dnf.builder() - .parameters(p, q) - .clause(assume(BoolTerms.constant(true)), friendView.call(p, q)) - .build(); - var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); - - assertThat(actual, structurallyEqualTo(expected)); - } - - @Test - void eliminateFalseTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - - var actual = Dnf.builder() - .parameters(p, q) - .clause(friendView.call(p, q)) - .clause(friendView.call(q, p), BooleanLiteral.FALSE) - .build(); - var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); - - assertThat(actual, structurallyEqualTo(expected)); - } - - @ParameterizedTest - @CsvSource(value = { - "false", - "null" - }, nullValues = "null") - void eliminateFalseAssumptionTest(Boolean value) { - var p = Variable.of("p"); - var q = Variable.of("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - - var actual = Dnf.builder() - .parameters(p, q) - .clause(friendView.call(p, q)) - .clause(friendView.call(q, p), assume(BoolTerms.constant(value))) - .build(); - var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); - - assertThat(actual, structurallyEqualTo(expected)); - } - - @Test - void alwaysTrueTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - - var actual = Dnf.builder() - .parameters(p, q) - .clause(friendView.call(p, q)) - .clause(BooleanLiteral.TRUE) - .build(); - var expected = Dnf.builder().parameters(p, q).clause().build(); - - assertThat(actual, structurallyEqualTo(expected)); - } - - @Test - void alwaysFalseTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - - var actual = Dnf.builder() - .parameters(p, q) - .clause(friendView.call(p, q), BooleanLiteral.FALSE) - .build(); - var expected = Dnf.builder().parameters(p, q).build(); - - assertThat(actual, structurallyEqualTo(expected)); - } - - @Test - void eliminateTrueDnfTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - var trueDnf = Dnf.builder().parameter(p).clause().build(); - - var actual = Dnf.builder() - .parameters(p, q) - .clause(trueDnf.call(q), friendView.call(p, q)) - .build(); - var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); - - assertThat(actual, structurallyEqualTo(expected)); - } - - @Test - void eliminateFalseDnfTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - var falseDnf = Dnf.builder().parameter(p).build(); - - var actual = Dnf.builder() - .parameters(p, q) - .clause(friendView.call(p, q)) - .clause(friendView.call(q, p), falseDnf.call(q)) - .build(); - var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); - - assertThat(actual, structurallyEqualTo(expected)); - } - - @Test - void alwaysTrueDnfTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - var trueDnf = Dnf.builder().parameter(p).clause().build(); - - var actual = Dnf.builder() - .parameters(p, q) - .clause(friendView.call(p, q)) - .clause(trueDnf.call(q)) - .build(); - var expected = Dnf.builder().parameters(p, q).clause().build(); - - assertThat(actual, structurallyEqualTo(expected)); - } - - @Test - void alwaysFalseDnfTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - var falseDnf = Dnf.builder().parameter(p).build(); - - var actual = Dnf.builder() - .parameters(p, q) - .clause(friendView.call(p, q), falseDnf.call(q)) - .build(); - var expected = Dnf.builder().parameters(p, q).build(); - - assertThat(actual, structurallyEqualTo(expected)); - } - - @Test - void eliminateNotFalseDnfTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - var falseDnf = Dnf.builder().parameter(p).build(); - - var actual = Dnf.builder() - .parameters(p, q) - .clause(not(falseDnf.call(q)), friendView.call(p, q)) - .build(); - var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); - - assertThat(actual, structurallyEqualTo(expected)); - } - - @Test - void eliminateNotTrueDnfTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - var trueDnf = Dnf.builder().parameter(p).clause().build(); - - var actual = Dnf.builder() - .parameters(p, q) - .clause(friendView.call(p, q)) - .clause(friendView.call(q, p), not(trueDnf.call(q))) - .build(); - var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); - - assertThat(actual, structurallyEqualTo(expected)); - } - - @Test - void alwaysNotFalseDnfTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - var falseDnf = Dnf.builder().parameter(p).build(); - - var actual = Dnf.builder() - .parameters(p, q) - .clause(friendView.call(p, q)) - .clause(not(falseDnf.call(q))) - .build(); - var expected = Dnf.builder().parameters(p, q).clause().build(); - - assertThat(actual, structurallyEqualTo(expected)); - } - - @Test - void alwaysNotTrueDnfTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - var trueDnf = Dnf.builder().parameter(p).clause().build(); - - var actual = Dnf.builder() - .parameters(p, q) - .clause(friendView.call(p, q), not(trueDnf.call(q))) - .build(); - var expected = Dnf.builder().parameters(p, q).build(); - - assertThat(actual, structurallyEqualTo(expected)); - } -} diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToDefinitionStringTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToDefinitionStringTest.java deleted file mode 100644 index e89ab682..00000000 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToDefinitionStringTest.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query; - -import org.junit.jupiter.api.Test; -import tools.refinery.store.query.dnf.Dnf; -import tools.refinery.store.query.term.Variable; -import tools.refinery.store.query.view.KeyOnlyView; -import tools.refinery.store.representation.Symbol; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static tools.refinery.store.query.literal.Literals.not; - -class DnfToDefinitionStringTest { - @Test - void noClausesTest() { - var p = Variable.of("p"); - var dnf = Dnf.builder("Example").parameter(p).build(); - - assertThat(dnf.toDefinitionString(), is(""" - pred Example(p) <-> - . - """)); - } - - @Test - void noParametersTest() { - var dnf = Dnf.builder("Example").build(); - - assertThat(dnf.toDefinitionString(), is(""" - pred Example() <-> - . - """)); - } - - @Test - void emptyClauseTest() { - var p = Variable.of("p"); - var dnf = Dnf.builder("Example").parameter(p).clause().build(); - - assertThat(dnf.toDefinitionString(), is(""" - pred Example(p) <-> - . - """)); - } - - @Test - void relationViewPositiveTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - var dnf = Dnf.builder("Example").parameter(p).clause(friendView.call(p, q)).build(); - - assertThat(dnf.toDefinitionString(), is(""" - pred Example(p) <-> - @RelationView("key") friend(p, q). - """)); - } - - @Test - void relationViewNegativeTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - var dnf = Dnf.builder("Example").parameter(p).clause(not(friendView.call(p, q))).build(); - - assertThat(dnf.toDefinitionString(), is(""" - pred Example(p) <-> - !(@RelationView("key") friend(p, q)). - """)); - } - - @Test - void relationViewTransitiveTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - var dnf = Dnf.builder("Example").parameter(p).clause(friendView.callTransitive(p, q)).build(); - - assertThat(dnf.toDefinitionString(), is(""" - pred Example(p) <-> - @RelationView("key") friend+(p, q). - """)); - } - - @Test - void multipleParametersTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - var dnf = Dnf.builder("Example").parameters(p, q).clause(friendView.call(p, q)).build(); - - assertThat(dnf.toDefinitionString(), is(""" - pred Example(p, q) <-> - @RelationView("key") friend(p, q). - """)); - } - - @Test - void multipleLiteralsTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var person = new Symbol<>("person", 1, Boolean.class, false); - var personView = new KeyOnlyView<>(person); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - var dnf = Dnf.builder("Example") - .parameter(p) - .clause( - personView.call(p), - personView.call(q), - friendView.call(p, q) - ) - .build(); - - assertThat(dnf.toDefinitionString(), is(""" - pred Example(p) <-> - @RelationView("key") person(p), - @RelationView("key") person(q), - @RelationView("key") friend(p, q). - """)); - } - - @Test - void multipleClausesTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - var dnf = Dnf.builder("Example") - .parameter(p) - .clause(friendView.call(p, q)) - .clause(friendView.call(q, p)) - .build(); - - assertThat(dnf.toDefinitionString(), is(""" - pred Example(p) <-> - @RelationView("key") friend(p, q) - ; - @RelationView("key") friend(q, p). - """)); - } - - @Test - void dnfTest() { - var p = Variable.of("p"); - var q = Variable.of("q"); - var r = Variable.of("r"); - var s = Variable.of("s"); - var person = new Symbol<>("person", 1, Boolean.class, false); - var personView = new KeyOnlyView<>(person); - var friend = new Symbol<>("friend", 2, Boolean.class, false); - var friendView = new KeyOnlyView<>(friend); - var called = Dnf.builder("Called").parameters(r, s).clause(friendView.call(r, s)).build(); - var dnf = Dnf.builder("Example") - .parameter(p) - .clause( - personView.call(p), - personView.call(q), - not(called.call(p, q)) - ) - .build(); - - assertThat(dnf.toDefinitionString(), is(""" - pred Example(p) <-> - @RelationView("key") person(p), - @RelationView("key") person(q), - !(@Dnf Called(p, q)). - """)); - } -} diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderLiteralEliminationTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderLiteralEliminationTest.java new file mode 100644 index 00000000..4edea401 --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderLiteralEliminationTest.java @@ -0,0 +1,209 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.dnf; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import tools.refinery.store.query.literal.BooleanLiteral; +import tools.refinery.store.query.term.NodeVariable; +import tools.refinery.store.query.term.Variable; +import tools.refinery.store.query.term.bool.BoolTerms; +import tools.refinery.store.query.view.KeyOnlyView; +import tools.refinery.store.query.view.SymbolView; +import tools.refinery.store.representation.Symbol; + +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static tools.refinery.store.query.literal.Literals.assume; +import static tools.refinery.store.query.literal.Literals.not; +import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo; + +class DnfBuilderLiteralEliminationTest { + private final Symbol friend = new Symbol<>("friend", 2, Boolean.class, false); + private final SymbolView friendView = new KeyOnlyView<>(friend); + private final NodeVariable p = Variable.of("p"); + private final NodeVariable q = Variable.of("q"); + private final Dnf trueDnf = Dnf.builder().parameter(p).clause().build(); + private final Dnf falseDnf = Dnf.builder().parameter(p).build(); + + @Test + void eliminateTrueTest() { + var actual = Dnf.builder() + .parameters(p, q) + .clause(BooleanLiteral.TRUE, friendView.call(p, q)) + .build(); + var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void eliminateTrueAssumptionTest() { + var actual = Dnf.builder() + .parameters(p, q) + .clause(assume(BoolTerms.constant(true)), friendView.call(p, q)) + .build(); + var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void eliminateFalseTest() { + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q)) + .clause(friendView.call(q, p), BooleanLiteral.FALSE) + .build(); + var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @ParameterizedTest + @CsvSource(value = { + "false", + "null" + }, nullValues = "null") + void eliminateFalseAssumptionTest(Boolean value) { + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q)) + .clause(friendView.call(q, p), assume(BoolTerms.constant(value))) + .build(); + var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void alwaysTrueTest() { + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q)) + .clause(BooleanLiteral.TRUE) + .build(); + var expected = Dnf.builder().parameters(p, q).clause().build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void alwaysFalseTest() { + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q), BooleanLiteral.FALSE) + .build(); + var expected = Dnf.builder().parameters(p, q).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void eliminateTrueDnfTest() { + var actual = Dnf.builder() + .parameters(p, q) + .clause(trueDnf.call(q), friendView.call(p, q)) + .build(); + var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void eliminateFalseDnfTest() { + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q)) + .clause(friendView.call(q, p), falseDnf.call(q)) + .build(); + var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void alwaysTrueDnfTest() { + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q)) + .clause(trueDnf.call(q)) + .build(); + var expected = Dnf.builder().parameters(p, q).clause().build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void alwaysFalseDnfTest() { + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q), falseDnf.call(q)) + .build(); + var expected = Dnf.builder().parameters(p, q).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void eliminateNotFalseDnfTest() { + var actual = Dnf.builder() + .parameters(p, q) + .clause(not(falseDnf.call(q)), friendView.call(p, q)) + .build(); + var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void eliminateNotTrueDnfTest() { + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q)) + .clause(friendView.call(q, p), not(trueDnf.call(q))) + .build(); + var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void alwaysNotFalseDnfTest() { + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q)) + .clause(not(falseDnf.call(q))) + .build(); + var expected = Dnf.builder().parameters(p, q).clause().build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void alwaysNotTrueDnfTest() { + var actual = Dnf.builder() + .parameters(p, q) + .clause(friendView.call(p, q), not(trueDnf.call(q))) + .build(); + var expected = Dnf.builder().parameters(p, q).build(); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void removeDuplicateTest() { + var actual = Dnf.of(builder -> builder.clause((p, q) -> List.of( + friendView.call(p, q), + friendView.call(p, q) + ))); + var expected = Dnf.of(builder -> builder.clause((p, q) -> List.of(friendView.call(p, q)))); + + assertThat(actual, structurallyEqualTo(expected)); + } +} diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderVariableUnificationTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderVariableUnificationTest.java new file mode 100644 index 00000000..a54ad4d6 --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderVariableUnificationTest.java @@ -0,0 +1,273 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.dnf; + +import org.junit.jupiter.api.Test; +import tools.refinery.store.query.view.KeyOnlyView; +import tools.refinery.store.query.view.SymbolView; +import tools.refinery.store.representation.Symbol; + +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo; + +class DnfBuilderVariableUnificationTest { + private final Symbol friend = new Symbol<>("friend", 2, Boolean.class, false); + private final Symbol children = new Symbol<>("friend", 2, Boolean.class, false); + private final SymbolView friendView = new KeyOnlyView<>(friend); + private final SymbolView childrenView = new KeyOnlyView<>(children); + + @Test + void equalToParameterTest() { + var actual = Dnf.of(builder -> { + var p = builder.parameter("p"); + builder.clause(q -> List.of( + friendView.call(p, q), + p.isEquivalent(q) + )); + }); + var expected = Dnf.of(builder -> { + var p = builder.parameter("p"); + builder.clause(friendView.call(p, p)); + }); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void equalToParameterReverseTest() { + var actual = Dnf.of(builder -> { + var p = builder.parameter("p"); + builder.clause(q -> List.of( + friendView.call(p, q), + q.isEquivalent(p) + )); + }); + var expected = Dnf.of(builder -> { + var p = builder.parameter("p"); + builder.clause(friendView.call(p, p)); + }); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void equalQuantifiedTest() { + var actual = Dnf.of(builder -> builder.clause((p, q) -> List.of( + friendView.call(p, q), + p.isEquivalent(q) + ))); + var expected = Dnf.of(builder -> builder.clause(p -> List.of(friendView.call(p, p)))); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void equalQuantifiedTransitiveTest() { + var actual = Dnf.of(builder -> builder.clause((p, q, r) -> List.of( + friendView.call(p, q), + p.isEquivalent(q), + childrenView.call(p, r), + q.isEquivalent(r) + ))); + var expected = Dnf.of(builder -> builder.clause(p -> List.of( + friendView.call(p, p), + childrenView.call(p, p) + ))); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void equalQuantifiedTransitiveRemoveDuplicateTest() { + var actual = Dnf.of(builder -> builder.clause((p, q, r) -> List.of( + friendView.call(p, q), + p.isEquivalent(q), + friendView.call(p, r), + q.isEquivalent(r) + ))); + var expected = Dnf.of(builder -> builder.clause(p -> List.of(friendView.call(p, p)))); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void parametersEqualTest() { + var actual = Dnf.of(builder -> { + var p = builder.parameter("p"); + var q = builder.parameter("q"); + builder.clause( + friendView.call(p, q), + p.isEquivalent(q) + ); + }); + var expected = Dnf.of(builder -> { + var p = builder.parameter("p"); + var q = builder.parameter("q"); + builder.clause( + q.isEquivalent(p), + friendView.call(p, p) + ); + }); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void parametersEqualTransitiveTest() { + var actual = Dnf.of(builder -> { + var p = builder.parameter("p"); + var q = builder.parameter("q"); + var r = builder.parameter("r"); + builder.clause( + friendView.call(p, q), + childrenView.call(p, r), + p.isEquivalent(q), + r.isEquivalent(q) + ); + }); + var expected = Dnf.of(builder -> { + var p = builder.parameter("p"); + var q = builder.parameter("q"); + var r = builder.parameter("r"); + builder.clause( + q.isEquivalent(p), + r.isEquivalent(p), + friendView.call(p, p), + childrenView.call(p, p) + ); + }); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void parameterAndQuantifiedEqualsTest() { + var actual = Dnf.of(builder -> { + var p = builder.parameter("p"); + var q = builder.parameter("q"); + builder.clause((r) -> List.of( + friendView.call(p, r), + p.isEquivalent(r), + childrenView.call(q, r), + q.isEquivalent(r) + )); + }); + var expected = Dnf.of(builder -> { + var p = builder.parameter("p"); + var q = builder.parameter("q"); + builder.clause( + q.isEquivalent(p), + friendView.call(p, p), + childrenView.call(p, p) + ); + }); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void parameterAndQuantifiedEqualsReverseFirstTest() { + var actual = Dnf.of(builder -> { + var p = builder.parameter("p"); + var q = builder.parameter("q"); + builder.clause((r) -> List.of( + friendView.call(p, r), + r.isEquivalent(p), + childrenView.call(q, r), + q.isEquivalent(r) + )); + }); + var expected = Dnf.of(builder -> { + var p = builder.parameter("p"); + var q = builder.parameter("q"); + builder.clause( + q.isEquivalent(p), + friendView.call(p, p), + childrenView.call(p, p) + ); + }); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void parameterAndQuantifiedEqualsReverseSecondTest() { + var actual = Dnf.of(builder -> { + var p = builder.parameter("p"); + var q = builder.parameter("q"); + builder.clause((r) -> List.of( + friendView.call(p, r), + p.isEquivalent(r), + childrenView.call(q, r), + r.isEquivalent(q) + )); + }); + var expected = Dnf.of(builder -> { + var p = builder.parameter("p"); + var q = builder.parameter("q"); + builder.clause( + q.isEquivalent(p), + friendView.call(p, p), + childrenView.call(p, p) + ); + }); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void parameterAndQuantifiedEqualsReverseBoth() { + var actual = Dnf.of(builder -> { + var p = builder.parameter("p"); + var q = builder.parameter("q"); + builder.clause((r) -> List.of( + friendView.call(p, r), + p.isEquivalent(r), + childrenView.call(q, r), + r.isEquivalent(q) + )); + }); + var expected = Dnf.of(builder -> { + var p = builder.parameter("p"); + var q = builder.parameter("q"); + builder.clause( + q.isEquivalent(p), + friendView.call(p, p), + childrenView.call(p, p) + ); + }); + + assertThat(actual, structurallyEqualTo(expected)); + } + + @Test + void parameterAndTwoQuantifiedEqualsTest() { + var actual = Dnf.of(builder -> { + var p = builder.parameter("p"); + var q = builder.parameter("q"); + builder.clause((r, s) -> List.of( + r.isEquivalent(s), + friendView.call(p, r), + p.isEquivalent(r), + childrenView.call(q, s), + q.isEquivalent(s) + )); + }); + var expected = Dnf.of(builder -> { + var p = builder.parameter("p"); + var q = builder.parameter("q"); + builder.clause( + q.isEquivalent(p), + friendView.call(p, p), + childrenView.call(p, p) + ); + }); + + assertThat(actual, structurallyEqualTo(expected)); + } +} diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfToDefinitionStringTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfToDefinitionStringTest.java new file mode 100644 index 00000000..2e93d78a --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfToDefinitionStringTest.java @@ -0,0 +1,178 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.dnf; + +import org.junit.jupiter.api.Test; +import tools.refinery.store.query.term.Variable; +import tools.refinery.store.query.view.KeyOnlyView; +import tools.refinery.store.representation.Symbol; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static tools.refinery.store.query.literal.Literals.not; + +class DnfToDefinitionStringTest { + @Test + void noClausesTest() { + var p = Variable.of("p"); + var dnf = Dnf.builder("Example").parameter(p).build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example(p) <-> + . + """)); + } + + @Test + void noParametersTest() { + var dnf = Dnf.builder("Example").build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example() <-> + . + """)); + } + + @Test + void emptyClauseTest() { + var p = Variable.of("p"); + var dnf = Dnf.builder("Example").parameter(p).clause().build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example(@In p) <-> + . + """)); + } + + @Test + void relationViewPositiveTest() { + var p = Variable.of("p"); + var q = Variable.of("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyView<>(friend); + var dnf = Dnf.builder("Example").parameter(p).clause(friendView.call(p, q)).build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example(p) <-> + @RelationView("key") friend(p, q). + """)); + } + + @Test + void relationViewNegativeTest() { + var p = Variable.of("p"); + var q = Variable.of("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyView<>(friend); + var dnf = Dnf.builder("Example").parameter(p).clause(not(friendView.call(p, q))).build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example(p) <-> + !(@RelationView("key") friend(p, q)). + """)); + } + + @Test + void relationViewTransitiveTest() { + var p = Variable.of("p"); + var q = Variable.of("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyView<>(friend); + var dnf = Dnf.builder("Example").parameter(p).clause(friendView.callTransitive(p, q)).build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example(p) <-> + @RelationView("key") friend+(p, q). + """)); + } + + @Test + void multipleParametersTest() { + var p = Variable.of("p"); + var q = Variable.of("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyView<>(friend); + var dnf = Dnf.builder("Example").parameters(p, q).clause(friendView.call(p, q)).build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example(p, q) <-> + @RelationView("key") friend(p, q). + """)); + } + + @Test + void multipleLiteralsTest() { + var p = Variable.of("p"); + var q = Variable.of("q"); + var person = new Symbol<>("person", 1, Boolean.class, false); + var personView = new KeyOnlyView<>(person); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyView<>(friend); + var dnf = Dnf.builder("Example") + .parameter(p) + .clause( + personView.call(p), + personView.call(q), + friendView.call(p, q) + ) + .build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example(p) <-> + @RelationView("key") person(p), + @RelationView("key") person(q), + @RelationView("key") friend(p, q). + """)); + } + + @Test + void multipleClausesTest() { + var p = Variable.of("p"); + var q = Variable.of("q"); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyView<>(friend); + var dnf = Dnf.builder("Example") + .parameter(p) + .clause(friendView.call(p, q)) + .clause(friendView.call(q, p)) + .build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example(p) <-> + @RelationView("key") friend(p, q) + ; + @RelationView("key") friend(q, p). + """)); + } + + @Test + void dnfTest() { + var p = Variable.of("p"); + var q = Variable.of("q"); + var r = Variable.of("r"); + var s = Variable.of("s"); + var person = new Symbol<>("person", 1, Boolean.class, false); + var personView = new KeyOnlyView<>(person); + var friend = new Symbol<>("friend", 2, Boolean.class, false); + var friendView = new KeyOnlyView<>(friend); + var called = Dnf.builder("Called").parameters(r, s).clause(friendView.call(r, s)).build(); + var dnf = Dnf.builder("Example") + .parameter(p) + .clause( + personView.call(p), + personView.call(q), + not(called.call(p, q)) + ) + .build(); + + assertThat(dnf.toDefinitionString(), is(""" + pred Example(p) <-> + @RelationView("key") person(p), + @RelationView("key") person(q), + !(@Dnf Called(p, q)). + """)); + } +} diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java index 526832c4..a5b7f85a 100644 --- a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java +++ b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java @@ -35,11 +35,11 @@ class MismatchDescribingDnfEqualityChecker extends DeepDnfEqualityChecker { var inProgress = getInProgress(); int size = inProgress.size(); if (size <= 1) { - description.appendText("was ").appendText(pair.left().toDefinitionString()); + description.appendText("was ").appendText(pair.right().toDefinitionString()); return; } var last = inProgress.get(size - 1); - description.appendText("expected ").appendText(last.right().toDefinitionString()); + description.appendText("expected ").appendText(last.left().toDefinitionString()); for (int i = size - 2; i >= 0; i--) { description.appendText(" called from ").appendText(inProgress.get(i).left().toString()); } diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java index 594005f1..ac41d170 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java @@ -12,7 +12,7 @@ import tools.refinery.store.query.dnf.DnfClause; import tools.refinery.store.query.literal.CallLiteral; import tools.refinery.store.query.literal.CallPolarity; import tools.refinery.store.query.literal.Literal; -import tools.refinery.store.query.term.DataVariable; +import tools.refinery.store.query.term.NodeVariable; import tools.refinery.store.query.term.Variable; import tools.refinery.store.reasoning.ReasoningAdapter; import tools.refinery.store.reasoning.literal.ModalConstraint; @@ -21,7 +21,7 @@ import tools.refinery.store.reasoning.literal.PartialLiterals; import tools.refinery.store.util.CycleDetectingMapper; import java.util.ArrayList; -import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; public class DnfLifter { @@ -36,10 +36,10 @@ public class DnfLifter { var modality = modalDnf.modality(); var dnf = modalDnf.dnf(); var builder = Dnf.builder(); - builder.parameters(dnf.getParameters()); + builder.symbolicParameters(dnf.getSymbolicParameters()); boolean changed = false; for (var clause : dnf.getClauses()) { - if (liftClause(modality, clause, builder)) { + if (liftClause(modality, dnf, clause, builder)) { changed = true; } } @@ -49,12 +49,9 @@ public class DnfLifter { return dnf; } - private boolean liftClause(Modality modality, DnfClause clause, DnfBuilder builder) { + private boolean liftClause(Modality modality, Dnf originalDnf, DnfClause clause, DnfBuilder builder) { boolean changed = false; - var quantifiedVariables = new HashSet<>(clause.boundVariables() - .stream() - .filter(DataVariable.class::isInstance) - .toList()); + var quantifiedVariables = getQuantifiedDataVariables(originalDnf, clause); var literals = clause.literals(); var liftedLiterals = new ArrayList(literals.size()); for (var literal : literals) { @@ -81,6 +78,16 @@ public class DnfLifter { return changed || !quantifiedVariables.isEmpty(); } + private static LinkedHashSet getQuantifiedDataVariables(Dnf originalDnf, DnfClause clause) { + var quantifiedVariables = new LinkedHashSet<>(clause.positiveVariables()); + for (var symbolicParameter : originalDnf.getSymbolicParameters()) { + // The existence of parameters will be checked outside this DNF. + quantifiedVariables.remove(symbolicParameter.getVariable()); + } + quantifiedVariables.removeIf(variable -> !(variable instanceof NodeVariable)); + return quantifiedVariables; + } + @Nullable private Variable isExistsLiteralForVariable(Modality modality, Literal literal) { if (literal instanceof CallLiteral callLiteral && diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java index 7fa98104..ce557d82 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java @@ -8,7 +8,7 @@ package tools.refinery.store.reasoning.literal; import tools.refinery.store.query.Constraint; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.literal.LiteralReduction; -import tools.refinery.store.query.term.Sort; +import tools.refinery.store.query.term.Parameter; import java.util.List; @@ -21,8 +21,8 @@ public record ModalConstraint(Modality modality, Constraint constraint) implemen } @Override - public List getSorts() { - return constraint.getSorts(); + public List getParameters() { + return constraint.getParameters(); } @Override diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialRelation.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialRelation.java index fc3dc074..1f74ce38 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialRelation.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialRelation.java @@ -6,8 +6,7 @@ package tools.refinery.store.reasoning.representation; import tools.refinery.store.query.Constraint; -import tools.refinery.store.query.term.NodeSort; -import tools.refinery.store.query.term.Sort; +import tools.refinery.store.query.term.Parameter; import tools.refinery.store.representation.AbstractDomain; import tools.refinery.store.representation.TruthValue; import tools.refinery.store.representation.TruthValueDomain; @@ -32,10 +31,10 @@ public record PartialRelation(String name, int arity) implements PartialSymbol getSorts() { - var sorts = new Sort[arity()]; - Arrays.fill(sorts, NodeSort.INSTANCE); - return List.of(sorts); + public List getParameters() { + var parameters = new Parameter[arity]; + Arrays.fill(parameters, Parameter.NODE_IN_OUT); + return List.of(parameters); } @Override -- cgit v1.2.3-70-g09d2 From d2348a15846ad861fc58b018f50a502a288bfcec Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Fri, 26 May 2023 22:24:40 +0200 Subject: refactor: simplified Dnf parameter directions --- .../query/viatra/internal/pquery/Dnf2PQuery.java | 19 ++- .../refinery/store/query/viatra/QueryTest.java | 11 -- .../store/query/dnf/ClausePostProcessor.java | 125 +++++++++--------- .../tools/refinery/store/query/dnf/DnfBuilder.java | 145 +++++++-------------- .../refinery/store/query/dnf/FunctionalQuery.java | 38 ++---- .../java/tools/refinery/store/query/dnf/Query.java | 97 ++++++++++---- .../refinery/store/query/dnf/RelationalQuery.java | 49 ++----- .../store/query/dnf/SymbolicParameter.java | 6 +- .../store/query/literal/AbstractCallLiteral.java | 55 +++++++- .../store/query/literal/AggregationLiteral.java | 23 ++-- .../store/query/literal/AssignLiteral.java | 31 ++--- .../store/query/literal/AssumeLiteral.java | 29 +++-- .../store/query/literal/BooleanLiteral.java | 17 ++- .../refinery/store/query/literal/CallLiteral.java | 19 ++- .../store/query/literal/ConstantLiteral.java | 28 ++-- .../refinery/store/query/literal/CountLiteral.java | 10 +- .../store/query/literal/EquivalenceLiteral.java | 37 ++---- .../refinery/store/query/literal/Literal.java | 9 +- .../store/query/literal/VariableBindingSite.java | 64 --------- .../query/literal/VariableBindingSiteBuilder.java | 137 ------------------- .../store/query/literal/VariableDirection.java | 82 ------------ .../refinery/store/query/term/AnyDataVariable.java | 5 + .../refinery/store/query/term/NodeVariable.java | 5 + .../tools/refinery/store/query/term/Parameter.java | 9 +- .../store/query/term/ParameterDirection.java | 1 - .../tools/refinery/store/query/term/Variable.java | 2 + .../dnf/DnfBuilderLiteralEliminationTest.java | 15 ++- .../store/query/dnf/DnfToDefinitionStringTest.java | 10 +- 28 files changed, 392 insertions(+), 686 deletions(-) delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableBindingSite.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableBindingSiteBuilder.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableDirection.java (limited to 'subprojects/store-query-viatra/src/main/java/tools') 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 index ec880435..5b0ea61d 100644 --- 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 @@ -88,8 +88,7 @@ public class Dnf2PQuery { List parameterList = new ArrayList<>(); for (var parameter : dnfQuery.getSymbolicParameters()) { var direction = switch (parameter.getDirection()) { - case IN_OUT -> PParameterDirection.INOUT; - case OUT -> PParameterDirection.OUT; + case OUT -> parameter.isUnifiable() ? PParameterDirection.INOUT : PParameterDirection.OUT; case IN -> throw new IllegalArgumentException("Query %s with input parameter %s is not supported" .formatted(dnfQuery, parameter.getVariable())); }; @@ -154,9 +153,9 @@ public class Dnf2PQuery { } private void translateEquivalenceLiteral(EquivalenceLiteral equivalenceLiteral, PBody body) { - PVariable varSource = body.getOrCreateVariableByName(equivalenceLiteral.getLeft().getUniqueName()); - PVariable varTarget = body.getOrCreateVariableByName(equivalenceLiteral.getRight().getUniqueName()); - if (equivalenceLiteral.isPositive()) { + 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); @@ -213,13 +212,13 @@ public class Dnf2PQuery { } private void translateConstantLiteral(ConstantLiteral constantLiteral, PBody body) { - var variable = body.getOrCreateVariableByName(constantLiteral.getVariable().getUniqueName()); - new ConstantValue(body, variable, constantLiteral.getNodeId()); + var variable = body.getOrCreateVariableByName(constantLiteral.variable().getUniqueName()); + new ConstantValue(body, variable, constantLiteral.nodeId()); } private void translateAssignLiteral(AssignLiteral assignLiteral, PBody body) { - var variable = body.getOrCreateVariableByName(assignLiteral.getTargetVariable().getUniqueName()); - var term = assignLiteral.getTerm(); + var variable = body.getOrCreateVariableByName(assignLiteral.variable().getUniqueName()); + var term = assignLiteral.term(); if (term instanceof ConstantTerm constantTerm) { new ConstantValue(body, variable, constantTerm.getValue()); } else { @@ -229,7 +228,7 @@ public class Dnf2PQuery { } private void translateAssumeLiteral(AssumeLiteral assumeLiteral, PBody body) { - var evaluator = new AssumptionEvaluator(assumeLiteral.getTerm()); + var evaluator = new AssumptionEvaluator(assumeLiteral.term()); new ExpressionEvaluation(body, evaluator, null); } 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 46ce37b4..a9a2f71c 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 @@ -23,7 +23,6 @@ import tools.refinery.store.tuple.Tuple; import java.util.List; import java.util.Map; -import static org.junit.jupiter.api.Assertions.assertThrows; import static tools.refinery.store.query.literal.Literals.assume; import static tools.refinery.store.query.literal.Literals.not; import static tools.refinery.store.query.term.int_.IntTerms.constant; @@ -707,14 +706,4 @@ class QueryTest { queryEngine.flushChanges(); assertResults(Map.of(), predicateResultSet); } - - @Test - void alwaysTrueTest() { - var p1 = Variable.of("p1"); - var predicate = Query.builder("AlwaysTrue").parameters(p1).clause().build(); - - var queryBuilder = ViatraModelQueryAdapter.builder(); - - assertThrows(IllegalArgumentException.class, () -> queryBuilder.queries(predicate)); - } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java index 467b8d52..dd45ecd4 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java @@ -9,35 +9,30 @@ import org.jetbrains.annotations.NotNull; import tools.refinery.store.query.literal.BooleanLiteral; import tools.refinery.store.query.literal.EquivalenceLiteral; import tools.refinery.store.query.literal.Literal; -import tools.refinery.store.query.literal.VariableDirection; import tools.refinery.store.query.substitution.MapBasedSubstitution; import tools.refinery.store.query.substitution.StatelessSubstitution; import tools.refinery.store.query.substitution.Substitution; import tools.refinery.store.query.term.NodeVariable; +import tools.refinery.store.query.term.ParameterDirection; import tools.refinery.store.query.term.Variable; import java.util.*; import java.util.function.Function; -import java.util.stream.Collectors; class ClausePostProcessor { - private final Set parameters; - private final Map parameterWeights; + private final Map parameters; private final List literals; private final Map representatives = new LinkedHashMap<>(); private final Map> equivalencePartition = new HashMap<>(); private List substitutedLiterals; private final Set existentiallyQuantifiedVariables = new LinkedHashSet<>(); - private Set inputParameters; private Set positiveVariables; private Map> variableToLiteralInputMap; private PriorityQueue literalsWithAllInputsBound; private LinkedHashSet topologicallySortedLiterals; - public ClausePostProcessor(Set parameters, Map parameterWeights, - List literals) { + public ClausePostProcessor(Map parameters, List literals) { this.parameters = parameters; - this.parameterWeights = parameterWeights; this.literals = literals; } @@ -46,9 +41,10 @@ class ClausePostProcessor { substitutedLiterals = new ArrayList<>(literals.size()); keepParameterEquivalences(); substituteLiterals(); + computeExistentiallyQuantifiedVariables(); computePositiveVariables(); validatePositiveRepresentatives(); - validateClosureVariables(); + validatePrivateVariables(); topologicallySortLiterals(); var filteredLiterals = new ArrayList(topologicallySortedLiterals.size()); for (var literal : topologicallySortedLiterals) { @@ -71,20 +67,21 @@ class ClausePostProcessor { for (var literal : literals) { if (isPositiveEquivalence(literal)) { var equivalenceLiteral = (EquivalenceLiteral) literal; - mergeVariables(equivalenceLiteral.getLeft(), equivalenceLiteral.getRight()); + mergeVariables(equivalenceLiteral.left(), equivalenceLiteral.right()); } } } private static boolean isPositiveEquivalence(Literal literal) { - return literal instanceof EquivalenceLiteral equivalenceLiteral && equivalenceLiteral.isPositive(); + return literal instanceof EquivalenceLiteral equivalenceLiteral && equivalenceLiteral.positive(); } private void mergeVariables(NodeVariable left, NodeVariable right) { var leftRepresentative = getRepresentative(left); var rightRepresentative = getRepresentative(right); - if (parameters.contains(leftRepresentative) && (!parameters.contains(rightRepresentative) || - parameterWeights.get(leftRepresentative).compareTo(parameterWeights.get(rightRepresentative)) <= 0)) { + var leftInfo = parameters.get(leftRepresentative); + var rightInfo = parameters.get(rightRepresentative); + if (leftInfo != null && (rightInfo == null || leftInfo.index() <= rightInfo.index())) { // Prefer the variable occurring earlier in the parameter list as a representative. doMergeVariables(leftRepresentative, rightRepresentative); } else { @@ -123,7 +120,7 @@ class ClausePostProcessor { for (var pair : representatives.entrySet()) { var left = pair.getKey(); var right = pair.getValue(); - if (!left.equals(right) && parameters.contains(left) && parameters.contains(right)) { + if (!left.equals(right) && parameters.containsKey(left) && parameters.containsKey(right)) { substitutedLiterals.add(left.isEquivalent(right)); } } @@ -148,27 +145,37 @@ class ClausePostProcessor { } } - private void computePositiveVariables() { + private void computeExistentiallyQuantifiedVariables() { for (var literal : substitutedLiterals) { - var variableBinder = literal.getVariableBindingSite(); - variableBinder.getVariablesWithDirection(VariableDirection.IN_OUT) - .forEach(existentiallyQuantifiedVariables::add); - variableBinder.getVariablesWithDirection(VariableDirection.OUT).forEach(variable -> { + for (var variable : literal.getOutputVariables()) { boolean added = existentiallyQuantifiedVariables.add(variable); - if (!added) { - throw new IllegalArgumentException("Variable %s has multiple %s bindings" - .formatted(variable, VariableDirection.OUT)); + if (!variable.isUnifiable()) { + var parameterInfo = parameters.get(variable); + if (parameterInfo != null && parameterInfo.direction() == ParameterDirection.IN) { + throw new IllegalArgumentException("Trying to bind %s parameter %s" + .formatted(ParameterDirection.IN, variable)); + } + if (!added) { + throw new IllegalArgumentException("Variable %s has multiple assigned values" + .formatted(variable)); + } } - }); + } + } + } + + private void computePositiveVariables() { + positiveVariables = new LinkedHashSet<>(); + for (var pair : parameters.entrySet()) { + var variable = pair.getKey(); + if (pair.getValue().direction() == ParameterDirection.IN) { + // Inputs count as positive, because they are already bound when we evaluate literals. + positiveVariables.add(variable); + } else if (!existentiallyQuantifiedVariables.contains(variable)) { + throw new IllegalArgumentException("Unbound %s parameter %s" + .formatted(ParameterDirection.OUT, variable)); + } } - // Input parameters are parameters not bound by any positive literal. - inputParameters = new LinkedHashSet<>(parameters); - inputParameters.removeAll(existentiallyQuantifiedVariables); - // Existentially quantified variables are variables appearing in positive literals that aren't parameters. - existentiallyQuantifiedVariables.removeAll(parameters); - // Positive variables are parameters (including input parameters) and variables bound by positive literals. - positiveVariables = new LinkedHashSet<>(parameters.size() + existentiallyQuantifiedVariables.size()); - positiveVariables.addAll(parameters); positiveVariables.addAll(existentiallyQuantifiedVariables); } @@ -183,19 +190,16 @@ class ClausePostProcessor { } } - private void validateClosureVariables() { + private void validatePrivateVariables() { var negativeVariablesMap = new HashMap(); for (var literal : substitutedLiterals) { - var variableBinder = literal.getVariableBindingSite(); - variableBinder.getVariablesWithDirection(VariableDirection.CLOSURE, positiveVariables) - .forEach(variable -> { - var oldLiteral = negativeVariablesMap.put(variable, literal); - if (oldLiteral != null) { - throw new IllegalArgumentException( - "Unbound variable %s appears in multiple literals %s and %s" - .formatted(variable, oldLiteral, literal)); - } - }); + for (var variable : literal.getPrivateVariables(positiveVariables)) { + var oldLiteral = negativeVariablesMap.put(variable, literal); + if (oldLiteral != null) { + throw new IllegalArgumentException("Unbound variable %s appears in multiple literals %s and %s" + .formatted(variable, oldLiteral, literal)); + } + } } } @@ -219,16 +223,6 @@ class ClausePostProcessor { } } - private void topologicallySortVariable(Variable variable) { - var literalSetForInput = variableToLiteralInputMap.remove(variable); - if (literalSetForInput == null) { - return; - } - for (var targetSortableLiteral : literalSetForInput) { - targetSortableLiteral.bindVariable(variable); - } - } - private class SortableLiteral implements Comparable { private final int index; private final Literal literal; @@ -237,10 +231,12 @@ class ClausePostProcessor { private SortableLiteral(int index, Literal literal) { this.index = index; this.literal = literal; - remainingInputs = literal.getVariableBindingSite() - .getVariablesWithDirection(VariableDirection.IN, positiveVariables) - .collect(Collectors.toCollection(HashSet::new)); - remainingInputs.removeAll(inputParameters); + remainingInputs = new HashSet<>(literal.getInputVariables(positiveVariables)); + for (var pair : parameters.entrySet()) { + if (pair.getValue().direction() == ParameterDirection.IN) { + remainingInputs.remove(pair.getKey()); + } + } } public void enqueue() { @@ -282,11 +278,15 @@ class ClausePostProcessor { } // Add literal if we haven't yet added a duplicate of this literal. topologicallySortedLiterals.add(literal); - var variableBinder = literal.getVariableBindingSite(); - variableBinder.getVariablesWithDirection(VariableDirection.IN_OUT) - .forEach(ClausePostProcessor.this::topologicallySortVariable); - variableBinder.getVariablesWithDirection(VariableDirection.OUT) - .forEach(ClausePostProcessor.this::topologicallySortVariable); + for (var variable : literal.getOutputVariables()) { + var literalSetForInput = variableToLiteralInputMap.remove(variable); + if (literalSetForInput == null) { + continue; + } + for (var targetSortableLiteral : literalSetForInput) { + targetSortableLiteral.bindVariable(variable); + } + } } @Override @@ -318,4 +318,7 @@ class ClausePostProcessor { ALWAYS_TRUE, ALWAYS_FALSE } + + public record ParameterInfo(ParameterDirection direction, int index) { + } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java index 3fac4627..dcf7611d 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java @@ -7,15 +7,18 @@ package tools.refinery.store.query.dnf; import tools.refinery.store.query.dnf.callback.*; import tools.refinery.store.query.literal.Literal; -import tools.refinery.store.query.term.*; +import tools.refinery.store.query.term.DataVariable; +import tools.refinery.store.query.term.NodeVariable; +import tools.refinery.store.query.term.ParameterDirection; +import tools.refinery.store.query.term.Variable; import java.util.*; @SuppressWarnings("UnusedReturnValue") public final class DnfBuilder { private final String name; - private final List parameters = new ArrayList<>(); - private final Map directions = new HashMap<>(); + private final Set parameterVariables = new LinkedHashSet<>(); + private final List parameters = new ArrayList<>(); private final List> functionalDependencies = new ArrayList<>(); private final List> clauses = new ArrayList<>(); @@ -28,20 +31,16 @@ public final class DnfBuilder { } public NodeVariable parameter(String name) { - var variable = Variable.of(name); - parameter(variable); - return variable; + return parameter(name, ParameterDirection.OUT); } public NodeVariable parameter(ParameterDirection direction) { - var variable = parameter(); - putDirection(variable, direction); - return variable; + return parameter((String) null, direction); } public NodeVariable parameter(String name, ParameterDirection direction) { - var variable = parameter(name); - putDirection(variable, direction); + var variable = Variable.of(name); + parameter(variable, direction); return variable; } @@ -50,50 +49,25 @@ public final class DnfBuilder { } public DataVariable parameter(String name, Class type) { - var variable = Variable.of(name, type); - parameter(variable); - return variable; + return parameter(name, type, ParameterDirection.OUT); } public DataVariable parameter(Class type, ParameterDirection direction) { - var variable = parameter(type); - putDirection(variable, direction); - return variable; + return parameter(null, type, direction); } public DataVariable parameter(String name, Class type, ParameterDirection direction) { - var variable = parameter(name, type); - putDirection(variable, direction); + var variable = Variable.of(name, type); + parameter(variable, direction); return variable; } public DnfBuilder parameter(Variable variable) { - if (parameters.contains(variable)) { - throw new IllegalArgumentException("Duplicate parameter: " + variable); - } - parameters.add(variable); - return this; + return parameter(variable, ParameterDirection.OUT); } public DnfBuilder parameter(Variable variable, ParameterDirection direction) { - parameter(variable); - putDirection(variable, direction); - return this; - } - - private void putDirection(Variable variable, ParameterDirection direction) { - if (variable.tryGetType().isPresent()) { - if (direction == ParameterDirection.IN_OUT) { - throw new IllegalArgumentException("%s direction is forbidden for data variable %s" - .formatted(direction, variable)); - } - } else { - if (direction == ParameterDirection.OUT) { - throw new IllegalArgumentException("%s direction is forbidden for node variable %s" - .formatted(direction, variable)); - } - } - directions.put(variable, direction); + return symbolicParameter(new SymbolicParameter(variable, direction)); } public DnfBuilder parameters(Variable... variables) { @@ -101,10 +75,7 @@ public final class DnfBuilder { } public DnfBuilder parameters(Collection variables) { - for (var variable : variables) { - parameter(variable); - } - return this; + return parameters(variables, ParameterDirection.OUT); } public DnfBuilder parameters(Collection variables, ParameterDirection direction) { @@ -114,9 +85,23 @@ public final class DnfBuilder { return this; } - public DnfBuilder symbolicParameters(Collection parameters) { - for (var parameter : parameters) { - parameter(parameter.getVariable(), parameter.getDirection()); + public DnfBuilder symbolicParameter(SymbolicParameter symbolicParameter) { + var variable = symbolicParameter.getVariable(); + if (!parameterVariables.add(variable)) { + throw new IllegalArgumentException("Variable %s is already on the parameter list %s" + .formatted(variable, parameters)); + } + parameters.add(symbolicParameter); + return this; + } + + public DnfBuilder symbolicParameters(SymbolicParameter... symbolicParameters) { + return symbolicParameters(List.of(symbolicParameters)); + } + + public DnfBuilder symbolicParameters(Collection symbolicParameters) { + for (var symbolicParameter : symbolicParameters) { + symbolicParameter(symbolicParameter); } return this; } @@ -214,24 +199,24 @@ public final class DnfBuilder { } void output(DataVariable outputVariable) { - var fromParameters = Set.copyOf(parameters); + // Copy parameter variables to exclude the newly added {@code outputVariable}. + var fromParameters = Set.copyOf(parameterVariables); parameter(outputVariable, ParameterDirection.OUT); functionalDependency(fromParameters, Set.of(outputVariable)); } public Dnf build() { var postProcessedClauses = postProcessClauses(); - return new Dnf(name, createParameterList(postProcessedClauses), + return new Dnf(name, Collections.unmodifiableList(parameters), Collections.unmodifiableList(functionalDependencies), Collections.unmodifiableList(postProcessedClauses)); } private List postProcessClauses() { - var parameterSet = Collections.unmodifiableSet(new LinkedHashSet<>(parameters)); - var parameterWeights = getParameterWeights(); + var parameterInfoMap = getParameterInfoMap(); var postProcessedClauses = new ArrayList(clauses.size()); for (var literals : clauses) { - var postProcessor = new ClausePostProcessor(parameterSet, parameterWeights, literals); + var postProcessor = new ClausePostProcessor(parameterInfoMap, literals); var result = postProcessor.postProcessClause(); if (result instanceof ClausePostProcessor.ClauseResult clauseResult) { postProcessedClauses.add(clauseResult.clause()); @@ -253,54 +238,14 @@ public final class DnfBuilder { return postProcessedClauses; } - private Map getParameterWeights() { - var mutableParameterWeights = new HashMap(); + private Map getParameterInfoMap() { + var mutableParameterInfoMap = new LinkedHashMap(); int arity = parameters.size(); for (int i = 0; i < arity; i++) { - mutableParameterWeights.put(parameters.get(i), i); - } - return Collections.unmodifiableMap(mutableParameterWeights); - } - - private List createParameterList(List postProcessedClauses) { - var outputParameterVariables = new HashSet<>(parameters); - for (var clause : postProcessedClauses) { - outputParameterVariables.retainAll(clause.positiveVariables()); - } - var parameterList = new ArrayList(parameters.size()); - for (var parameter : parameters) { - ParameterDirection direction = getDirection(outputParameterVariables, parameter); - parameterList.add(new SymbolicParameter(parameter, direction)); - } - return Collections.unmodifiableList(parameterList); - } - - private ParameterDirection getDirection(HashSet outputParameterVariables, Variable parameter) { - var direction = getInferredDirection(outputParameterVariables, parameter); - var expectedDirection = directions.get(parameter); - if (expectedDirection == ParameterDirection.IN && direction == ParameterDirection.IN_OUT) { - // Parameters may be explicitly marked as {@code @In} even if they are bound in all clauses. - return expectedDirection; - } - if (expectedDirection != null && expectedDirection != direction) { - throw new IllegalArgumentException("Expected parameter %s to have direction %s, but got %s instead" - .formatted(parameter, expectedDirection, direction)); - } - return direction; - } - - private static ParameterDirection getInferredDirection(HashSet outputParameterVariables, - Variable parameter) { - if (outputParameterVariables.contains(parameter)) { - if (parameter instanceof NodeVariable) { - return ParameterDirection.IN_OUT; - } else if (parameter instanceof AnyDataVariable) { - return ParameterDirection.OUT; - } else { - throw new IllegalArgumentException("Unknown parameter: " + parameter); - } - } else { - return ParameterDirection.IN; + var parameter = parameters.get(i); + mutableParameterInfoMap.put(parameter.getVariable(), + new ClausePostProcessor.ParameterInfo(parameter.getDirection(), i)); } + return Collections.unmodifiableMap(mutableParameterInfoMap); } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java index 57cb8baf..6f253012 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java @@ -6,17 +6,20 @@ package tools.refinery.store.query.dnf; import tools.refinery.store.query.literal.CallPolarity; -import tools.refinery.store.query.term.*; +import tools.refinery.store.query.term.Aggregator; +import tools.refinery.store.query.term.AssignedValue; +import tools.refinery.store.query.term.NodeVariable; +import tools.refinery.store.query.term.Variable; import java.util.ArrayList; import java.util.List; import java.util.Objects; -public final class FunctionalQuery implements Query { - private final Dnf dnf; +public final class FunctionalQuery extends Query { private final Class type; FunctionalQuery(Dnf dnf, Class type) { + super(dnf); var parameters = dnf.getSymbolicParameters(); int outputIndex = dnf.arity() - 1; for (int i = 0; i < outputIndex; i++) { @@ -33,18 +36,12 @@ public final class FunctionalQuery implements Query { throw new IllegalArgumentException("Expected parameter %s of %s to be %s, but got %s instead".formatted( outputParameter, dnf, type, outputParameterType.map(Class::getName).orElse("node"))); } - this.dnf = dnf; this.type = type; } - @Override - public String name() { - return dnf.name(); - } - @Override public int arity() { - return dnf.arity() - 1; + return getDnf().arity() - 1; } @Override @@ -57,17 +54,12 @@ public final class FunctionalQuery implements Query { return null; } - @Override - public Dnf getDnf() { - return dnf; - } - public AssignedValue call(List arguments) { return targetVariable -> { var argumentsWithTarget = new ArrayList(arguments.size() + 1); argumentsWithTarget.addAll(arguments); argumentsWithTarget.add(targetVariable); - return dnf.call(CallPolarity.POSITIVE, argumentsWithTarget); + return getDnf().call(CallPolarity.POSITIVE, argumentsWithTarget); }; } @@ -81,7 +73,9 @@ public final class FunctionalQuery implements Query { var argumentsWithPlaceholder = new ArrayList(arguments.size() + 1); argumentsWithPlaceholder.addAll(arguments); argumentsWithPlaceholder.add(placeholderVariable); - return dnf.aggregate(placeholderVariable, aggregator, argumentsWithPlaceholder).toLiteral(targetVariable); + return getDnf() + .aggregate(placeholderVariable, aggregator, argumentsWithPlaceholder) + .toLiteral(targetVariable); }; } @@ -93,17 +87,13 @@ public final class FunctionalQuery implements Query { public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; FunctionalQuery that = (FunctionalQuery) o; - return dnf.equals(that.dnf) && type.equals(that.type); + return Objects.equals(type, that.type); } @Override public int hashCode() { - return Objects.hash(dnf, type); - } - - @Override - public String toString() { - return dnf.toString(); + return Objects.hash(super.hashCode(), type); } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java index e94c0c6b..aaa52ce6 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java @@ -6,113 +6,158 @@ package tools.refinery.store.query.dnf; import tools.refinery.store.query.dnf.callback.*; +import tools.refinery.store.query.term.ParameterDirection; import tools.refinery.store.query.term.Variable; -public sealed interface Query extends AnyQuery permits RelationalQuery, FunctionalQuery { - String OUTPUT_VARIABLE_NAME = "output"; +import java.util.Objects; +public abstract sealed class Query implements AnyQuery permits FunctionalQuery, RelationalQuery { + private static final String OUTPUT_VARIABLE_NAME = "output"; + + private final Dnf dnf; + + protected Query(Dnf dnf) { + for (var parameter : dnf.getSymbolicParameters()) { + if (parameter.getDirection() != ParameterDirection.OUT) { + throw new IllegalArgumentException("Query parameter %s with direction %s is not allowed" + .formatted(parameter.getVariable(), parameter.getDirection())); + } + } + this.dnf = dnf; + } + + @Override + public String name() { + return dnf.name(); + } + + @Override + public Dnf getDnf() { + return dnf; + } + + // Allow redeclaration of the method with refined return type. + @SuppressWarnings("squid:S3038") @Override - Class valueType(); + public abstract Class valueType(); - T defaultValue(); + public abstract T defaultValue(); + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Query that = (Query) o; + return Objects.equals(dnf, that.dnf); + } + + @Override + public int hashCode() { + return Objects.hash(dnf); + } + + @Override + public String toString() { + return dnf.toString(); + } - static QueryBuilder builder() { + public static QueryBuilder builder() { return builder(null); } - static QueryBuilder builder(String name) { + public static QueryBuilder builder(String name) { return new QueryBuilder(name); } - static RelationalQuery of(QueryCallback0 callback) { + public static RelationalQuery of(QueryCallback0 callback) { return of(null, callback); } - static RelationalQuery of(String name, QueryCallback0 callback) { + public static RelationalQuery of(String name, QueryCallback0 callback) { var builder = builder(name); callback.accept(builder); return builder.build(); } - static RelationalQuery of(QueryCallback1 callback) { + public static RelationalQuery of(QueryCallback1 callback) { return of(null, callback); } - static RelationalQuery of(String name, QueryCallback1 callback) { + public static RelationalQuery of(String name, QueryCallback1 callback) { var builder = builder(name); callback.accept(builder, builder.parameter("p1")); return builder.build(); } - static RelationalQuery of(QueryCallback2 callback) { + public static RelationalQuery of(QueryCallback2 callback) { return of(null, callback); } - static RelationalQuery of(String name, QueryCallback2 callback) { + public static RelationalQuery of(String name, QueryCallback2 callback) { var builder = builder(name); callback.accept(builder, builder.parameter("p1"), builder.parameter("p2")); return builder.build(); } - static RelationalQuery of(QueryCallback3 callback) { + public static RelationalQuery of(QueryCallback3 callback) { return of(null, callback); } - static RelationalQuery of(String name, QueryCallback3 callback) { + public static RelationalQuery of(String name, QueryCallback3 callback) { var builder = builder(name); callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"), builder.parameter("p3")); return builder.build(); } - static RelationalQuery of(QueryCallback4 callback) { + public static RelationalQuery of(QueryCallback4 callback) { return of(null, callback); } - static RelationalQuery of(String name, QueryCallback4 callback) { + public static RelationalQuery of(String name, QueryCallback4 callback) { var builder = builder(name); callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"), builder.parameter("p3"), builder.parameter("p4")); return builder.build(); } - static FunctionalQuery of(Class type, FunctionalQueryCallback0 callback) { + public static FunctionalQuery of(Class type, FunctionalQueryCallback0 callback) { return of(null, type, callback); } - static FunctionalQuery of(String name, Class type, FunctionalQueryCallback0 callback) { + public static FunctionalQuery of(String name, Class type, FunctionalQueryCallback0 callback) { var outputVariable = Variable.of(OUTPUT_VARIABLE_NAME, type); var builder = builder(name).output(outputVariable); callback.accept(builder, outputVariable); return builder.build(); } - static FunctionalQuery of(Class type, FunctionalQueryCallback1 callback) { + public static FunctionalQuery of(Class type, FunctionalQueryCallback1 callback) { return of(null, type, callback); } - static FunctionalQuery of(String name, Class type, FunctionalQueryCallback1 callback) { + public static FunctionalQuery of(String name, Class type, FunctionalQueryCallback1 callback) { var outputVariable = Variable.of(OUTPUT_VARIABLE_NAME, type); var builder = builder(name).output(outputVariable); callback.accept(builder, builder.parameter("p1"), outputVariable); return builder.build(); } - static FunctionalQuery of(Class type, FunctionalQueryCallback2 callback) { + public static FunctionalQuery of(Class type, FunctionalQueryCallback2 callback) { return of(null, type, callback); } - static FunctionalQuery of(String name, Class type, FunctionalQueryCallback2 callback) { + public static FunctionalQuery of(String name, Class type, FunctionalQueryCallback2 callback) { var outputVariable = Variable.of(OUTPUT_VARIABLE_NAME, type); var builder = builder(name).output(outputVariable); callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"), outputVariable); return builder.build(); } - static FunctionalQuery of(Class type, FunctionalQueryCallback3 callback) { + public static FunctionalQuery of(Class type, FunctionalQueryCallback3 callback) { return of(null, type, callback); } - static FunctionalQuery of(String name, Class type, FunctionalQueryCallback3 callback) { + public static FunctionalQuery of(String name, Class type, FunctionalQueryCallback3 callback) { var outputVariable = Variable.of(OUTPUT_VARIABLE_NAME, type); var builder = builder(name).output(outputVariable); callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"), builder.parameter("p3"), @@ -120,11 +165,11 @@ public sealed interface Query extends AnyQuery permits RelationalQuery, Funct return builder.build(); } - static FunctionalQuery of(Class type, FunctionalQueryCallback4 callback) { + public static FunctionalQuery of(Class type, FunctionalQueryCallback4 callback) { return of(null, type, callback); } - static FunctionalQuery of(String name, Class type, FunctionalQueryCallback4 callback) { + public static FunctionalQuery of(String name, Class type, FunctionalQueryCallback4 callback) { var outputVariable = Variable.of(OUTPUT_VARIABLE_NAME, type); var builder = builder(name).output(outputVariable); callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"), builder.parameter("p3"), diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java index c043a285..d34a7ace 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java @@ -12,12 +12,10 @@ import tools.refinery.store.query.term.NodeVariable; import java.util.Collections; import java.util.List; -import java.util.Objects; - -public final class RelationalQuery implements Query { - private final Dnf dnf; +public final class RelationalQuery extends Query { RelationalQuery(Dnf dnf) { + super(dnf); for (var parameter : dnf.getSymbolicParameters()) { var parameterType = parameter.tryGetType(); if (parameterType.isPresent()) { @@ -25,17 +23,11 @@ public final class RelationalQuery implements Query { .formatted(parameter, dnf, parameterType.get().getName())); } } - this.dnf = dnf; - } - - @Override - public String name() { - return dnf.name(); } @Override public int arity() { - return dnf.arity(); + return getDnf().arity(); } @Override @@ -48,50 +40,27 @@ public final class RelationalQuery implements Query { return false; } - @Override - public Dnf getDnf() { - return dnf; - } - public CallLiteral call(CallPolarity polarity, List arguments) { - return dnf.call(polarity, Collections.unmodifiableList(arguments)); + return getDnf().call(polarity, Collections.unmodifiableList(arguments)); } public CallLiteral call(CallPolarity polarity, NodeVariable... arguments) { - return dnf.call(polarity, arguments); + return getDnf().call(polarity, arguments); } public CallLiteral call(NodeVariable... arguments) { - return dnf.call(arguments); + return getDnf().call(arguments); } public CallLiteral callTransitive(NodeVariable left, NodeVariable right) { - return dnf.callTransitive(left, right); + return getDnf().callTransitive(left, right); } public AssignedValue count(List arguments) { - return dnf.count(Collections.unmodifiableList(arguments)); + return getDnf().count(Collections.unmodifiableList(arguments)); } public AssignedValue count(NodeVariable... arguments) { - return dnf.count(arguments); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - RelationalQuery that = (RelationalQuery) o; - return dnf.equals(that.dnf); - } - - @Override - public int hashCode() { - return Objects.hash(dnf); - } - - @Override - public String toString() { - return dnf.toString(); + return getDnf().count(arguments); } } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java index e2f05bde..e0d3ba1f 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java @@ -23,10 +23,14 @@ public final class SymbolicParameter extends Parameter { return variable; } + public boolean isUnifiable() { + return variable.isUnifiable(); + } + @Override public String toString() { var direction = getDirection(); - if (direction == ParameterDirection.IN_OUT) { + if (direction == ParameterDirection.OUT) { return variable.toString(); } return "%s %s".formatted(getDirection(), variable); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java index 55db04e0..ed7d3401 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java @@ -8,14 +8,16 @@ package tools.refinery.store.query.literal; import tools.refinery.store.query.Constraint; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.ParameterDirection; import tools.refinery.store.query.term.Variable; -import java.util.List; -import java.util.Objects; +import java.util.*; public abstract class AbstractCallLiteral implements Literal { private final Constraint target; private final List arguments; + private final Set inArguments; + private final Set outArguments; protected AbstractCallLiteral(Constraint target, List arguments) { int arity = target.arity(); @@ -25,6 +27,8 @@ public abstract class AbstractCallLiteral implements Literal { } this.target = target; this.arguments = arguments; + var mutableInArguments = new LinkedHashSet(); + var mutableOutArguments = new LinkedHashSet(); var parameters = target.getParameters(); for (int i = 0; i < arity; i++) { var argument = arguments.get(i); @@ -33,6 +37,36 @@ public abstract class AbstractCallLiteral implements Literal { throw new IllegalArgumentException("Argument %d of %s is not assignable to parameter %s" .formatted(i, target, parameter)); } + switch (parameter.getDirection()) { + case IN -> { + if (mutableOutArguments.remove(argument)) { + checkInOutUnifiable(argument); + } + mutableInArguments.add(argument); + } + case OUT -> { + if (mutableInArguments.contains(argument)) { + checkInOutUnifiable(argument); + } else if (!mutableOutArguments.add(argument)) { + checkDuplicateOutUnifiable(argument); + } + } + } + } + inArguments = Collections.unmodifiableSet(mutableInArguments); + outArguments = Collections.unmodifiableSet(mutableOutArguments); + } + + private static void checkInOutUnifiable(Variable argument) { + if (!argument.isUnifiable()) { + throw new IllegalArgumentException("Arguments %s cannot appear with both %s and %s direction" + .formatted(argument, ParameterDirection.IN, ParameterDirection.OUT)); + } + } + + private static void checkDuplicateOutUnifiable(Variable argument) { + if (!argument.isUnifiable()) { + throw new IllegalArgumentException("Arguments %s cannot be bound multiple times".formatted(argument)); } } @@ -44,6 +78,23 @@ public abstract class AbstractCallLiteral implements Literal { return arguments; } + protected Set getArgumentsOfDirection(ParameterDirection direction) { + return switch (direction) { + case IN -> inArguments; + case OUT -> outArguments; + }; + } + + @Override + public Set getInputVariables(Set positiveVariablesInClause) { + return getArgumentsOfDirection(ParameterDirection.IN); + } + + @Override + public Set getPrivateVariables(Set positiveVariablesInClause) { + return Set.of(); + } + @Override public Literal substitute(Substitution substitution) { var substitutedArguments = arguments.stream().map(substitution::getSubstitute).toList(); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java index 51a33c1f..b2fec430 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java @@ -8,19 +8,16 @@ package tools.refinery.store.query.literal; import tools.refinery.store.query.Constraint; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; -import tools.refinery.store.query.term.Aggregator; -import tools.refinery.store.query.term.ConstantTerm; -import tools.refinery.store.query.term.DataVariable; -import tools.refinery.store.query.term.Variable; +import tools.refinery.store.query.term.*; import java.util.List; import java.util.Objects; +import java.util.Set; public class AggregationLiteral extends AbstractCallLiteral { private final DataVariable resultVariable; private final DataVariable inputVariable; private final Aggregator aggregator; - private final VariableBindingSite variableBindingSite; public AggregationLiteral(DataVariable resultVariable, Aggregator aggregator, DataVariable inputVariable, Constraint target, List arguments) { @@ -29,6 +26,10 @@ public class AggregationLiteral extends AbstractCallLiteral { throw new IllegalArgumentException("Input variable %s must of type %s, got %s instead".formatted( inputVariable, aggregator.getInputType().getName(), inputVariable.getType().getName())); } + if (!getArgumentsOfDirection(ParameterDirection.OUT).contains(inputVariable)) { + throw new IllegalArgumentException("Input variable %s must be bound with direction %s in the argument list" + .formatted(inputVariable, ParameterDirection.OUT)); + } if (!resultVariable.getType().equals(aggregator.getResultType())) { throw new IllegalArgumentException("Result variable %s must of type %s, got %s instead".formatted( resultVariable, aggregator.getResultType().getName(), resultVariable.getType().getName())); @@ -40,14 +41,6 @@ public class AggregationLiteral extends AbstractCallLiteral { this.resultVariable = resultVariable; this.inputVariable = inputVariable; this.aggregator = aggregator; - variableBindingSite = VariableBindingSite.builder() - .variable(resultVariable, VariableDirection.OUT) - .parameterList(false, target.getParameters(), arguments) - .build(); - if (variableBindingSite.getDirection(inputVariable) != VariableDirection.CLOSURE) { - throw new IllegalArgumentException(("Input variable %s must appear in the argument list as an output " + - "variable and should not be bound anywhere else").formatted(inputVariable)); - } } public DataVariable getResultVariable() { @@ -63,8 +56,8 @@ public class AggregationLiteral extends AbstractCallLiteral { } @Override - public VariableBindingSite getVariableBindingSite() { - return variableBindingSite; + public Set getOutputVariables() { + return Set.of(resultVariable); } @Override diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java index 079ba6bb..dbf999a2 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java @@ -9,43 +9,38 @@ import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; import tools.refinery.store.query.term.DataVariable; import tools.refinery.store.query.term.Term; +import tools.refinery.store.query.term.Variable; +import java.util.Collections; import java.util.Objects; +import java.util.Set; -public final class AssignLiteral implements Literal { - private final DataVariable variable; - private final Term term; - private final VariableBindingSite variableBindingSite; - - public AssignLiteral(DataVariable variable, Term term) { +public record AssignLiteral(DataVariable variable, Term term) implements Literal { + public AssignLiteral { if (!term.getType().equals(variable.getType())) { throw new IllegalArgumentException("Term %s must be of type %s, got %s instead".formatted( term, variable.getType().getName(), term.getType().getName())); } - this.variable = variable; - this.term = term; var inputVariables = term.getInputVariables(); if (inputVariables.contains(variable)) { throw new IllegalArgumentException("Result variable %s must not appear in the term %s".formatted( variable, term)); } - variableBindingSite = VariableBindingSite.builder() - .variable(variable, VariableDirection.OUT) - .variables(inputVariables, VariableDirection.IN) - .build(); } - public DataVariable getTargetVariable() { - return variable; + @Override + public Set getOutputVariables() { + return Set.of(variable); } - public Term getTerm() { - return term; + @Override + public Set getInputVariables(Set positiveVariablesInClause) { + return Collections.unmodifiableSet(term.getInputVariables()); } @Override - public VariableBindingSite getVariableBindingSite() { - return variableBindingSite; + public Set getPrivateVariables(Set positiveVariablesInClause) { + return Set.of(); } @Override diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java index 3dfb8902..1ca04c77 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java @@ -9,33 +9,36 @@ import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; import tools.refinery.store.query.term.ConstantTerm; import tools.refinery.store.query.term.Term; +import tools.refinery.store.query.term.Variable; +import java.util.Collections; import java.util.Objects; +import java.util.Set; -public final class AssumeLiteral implements Literal { - private final Term term; - private final VariableBindingSite variableBindingSite; - - public AssumeLiteral(Term term) { +public record AssumeLiteral(Term term) implements Literal { + public AssumeLiteral { if (!term.getType().equals(Boolean.class)) { throw new IllegalArgumentException("Term %s must be of type %s, got %s instead".formatted( term, Boolean.class.getName(), term.getType().getName())); } - this.term = term; - variableBindingSite = VariableBindingSite.builder() - .variables(term.getInputVariables(), VariableDirection.IN) - .build(); } - public Term getTerm() { - return term; + @Override + public Set getOutputVariables() { + return Set.of(); + } + + @Override + public Set getInputVariables(Set positiveVariablesInClause) { + return Collections.unmodifiableSet(term.getInputVariables()); } @Override - public VariableBindingSite getVariableBindingSite() { - return variableBindingSite; + public Set getPrivateVariables(Set positiveVariablesInClause) { + return Set.of(); } + @Override public Literal substitute(Substitution substitution) { return new AssumeLiteral(term.substitute(substitution)); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java index 736b3537..f312d202 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java @@ -7,6 +7,9 @@ package tools.refinery.store.query.literal; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Variable; + +import java.util.Set; public enum BooleanLiteral implements CanNegate { TRUE(true), @@ -19,8 +22,18 @@ public enum BooleanLiteral implements CanNegate { } @Override - public VariableBindingSite getVariableBindingSite() { - return VariableBindingSite.EMPTY; + public Set getOutputVariables() { + return Set.of(); + } + + @Override + public Set getInputVariables(Set positiveVariablesInClause) { + return Set.of(); + } + + @Override + public Set getPrivateVariables(Set positiveVariablesInClause) { + return Set.of(); } @Override diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java index 4f755e95..27d8ad60 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java @@ -8,14 +8,13 @@ package tools.refinery.store.query.literal; import tools.refinery.store.query.Constraint; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.ParameterDirection; import tools.refinery.store.query.term.Variable; -import java.util.List; -import java.util.Objects; +import java.util.*; public final class CallLiteral extends AbstractCallLiteral implements CanNegate { private final CallPolarity polarity; - private final VariableBindingSite variableBindingSite; public CallLiteral(CallPolarity polarity, Constraint target, List arguments) { super(target, arguments); @@ -30,9 +29,6 @@ public final class CallLiteral extends AbstractCallLiteral implements CanNegate< } } this.polarity = polarity; - variableBindingSite = VariableBindingSite.builder() - .parameterList(polarity.isPositive(), parameters, arguments) - .build(); } public CallPolarity getPolarity() { @@ -40,13 +36,16 @@ public final class CallLiteral extends AbstractCallLiteral implements CanNegate< } @Override - public VariableBindingSite getVariableBindingSite() { - return variableBindingSite; + protected Literal doSubstitute(Substitution substitution, List substitutedArguments) { + return new CallLiteral(polarity, getTarget(), substitutedArguments); } @Override - protected Literal doSubstitute(Substitution substitution, List substitutedArguments) { - return new CallLiteral(polarity, getTarget(), substitutedArguments); + public Set getOutputVariables() { + if (polarity.isPositive()) { + return getArgumentsOfDirection(ParameterDirection.OUT); + } + return Set.of(); } @Override diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java index 1bc14bab..73545620 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java @@ -8,31 +8,25 @@ package tools.refinery.store.query.literal; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; import tools.refinery.store.query.term.NodeVariable; +import tools.refinery.store.query.term.Variable; import java.util.Objects; +import java.util.Set; -public final class ConstantLiteral implements Literal { - private final NodeVariable variable; - private final int nodeId; - private final VariableBindingSite variableBindingSite; - - public ConstantLiteral(NodeVariable variable, int nodeId) { - this.variable = variable; - this.nodeId = nodeId; - variableBindingSite = VariableBindingSite.builder().variable(variable, VariableDirection.IN_OUT).build(); - } - - public NodeVariable getVariable() { - return variable; +public record ConstantLiteral(NodeVariable variable, int nodeId) implements Literal { + @Override + public Set getOutputVariables() { + return Set.of(variable); } - public int getNodeId() { - return nodeId; + @Override + public Set getInputVariables(Set positiveVariablesInClause) { + return Set.of(); } @Override - public VariableBindingSite getVariableBindingSite() { - return variableBindingSite; + public Set getPrivateVariables(Set positiveVariablesInClause) { + return Set.of(); } @Override diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java index 0a47aa66..4d4749c8 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java @@ -14,10 +14,10 @@ import tools.refinery.store.query.term.int_.IntTerms; import java.util.List; import java.util.Objects; +import java.util.Set; public class CountLiteral extends AbstractCallLiteral { private final DataVariable resultVariable; - private final VariableBindingSite variableBindingSite; public CountLiteral(DataVariable resultVariable, Constraint target, List arguments) { super(target, arguments); @@ -30,10 +30,6 @@ public class CountLiteral extends AbstractCallLiteral { .formatted(resultVariable)); } this.resultVariable = resultVariable; - variableBindingSite = VariableBindingSite.builder() - .variable(resultVariable, VariableDirection.OUT) - .parameterList(false, target.getParameters(), arguments) - .build(); } public DataVariable getResultVariable() { @@ -41,8 +37,8 @@ public class CountLiteral extends AbstractCallLiteral { } @Override - public VariableBindingSite getVariableBindingSite() { - return variableBindingSite; + public Set getOutputVariables() { + return Set.of(resultVariable); } @Override diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java index b36c0e40..28ba7625 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java @@ -8,41 +8,26 @@ package tools.refinery.store.query.literal; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; import tools.refinery.store.query.term.NodeVariable; +import tools.refinery.store.query.term.Variable; import java.util.Objects; +import java.util.Set; -public final class EquivalenceLiteral +public record EquivalenceLiteral(boolean positive, NodeVariable left, NodeVariable right) implements CanNegate { - private final boolean positive; - private final NodeVariable left; - private final NodeVariable right; - private final VariableBindingSite variableBindingSite; - - public EquivalenceLiteral(boolean positive, NodeVariable left, NodeVariable right) { - this.positive = positive; - this.left = left; - this.right = right; - variableBindingSite = VariableBindingSite.builder() - .variable(left, positive ? VariableDirection.IN_OUT : VariableDirection.IN) - .variable(right, VariableDirection.IN) - .build(); - } - - public boolean isPositive() { - return positive; - } - - public NodeVariable getLeft() { - return left; + @Override + public Set getOutputVariables() { + return Set.of(left); } - public NodeVariable getRight() { - return right; + @Override + public Set getInputVariables(Set positiveVariablesInClause) { + return Set.of(right); } @Override - public VariableBindingSite getVariableBindingSite() { - return variableBindingSite; + public Set getPrivateVariables(Set positiveVariablesInClause) { + return Set.of(); } @Override diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java index 10e4cffd..ce6c11fe 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java @@ -7,9 +7,16 @@ package tools.refinery.store.query.literal; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.Variable; + +import java.util.Set; public interface Literal { - VariableBindingSite getVariableBindingSite(); + Set getOutputVariables(); + + Set getInputVariables(Set positiveVariablesInClause); + + Set getPrivateVariables(Set positiveVariablesInClause); Literal substitute(Substitution substitution); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableBindingSite.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableBindingSite.java deleted file mode 100644 index 624af045..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableBindingSite.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.literal; - -import tools.refinery.store.query.term.Variable; - -import java.util.Map; -import java.util.Set; -import java.util.stream.Stream; - -public final class VariableBindingSite { - public static final VariableBindingSite EMPTY = new VariableBindingSite(Map.of()); - - private final Map directionMap; - - VariableBindingSite(Map directionMap) { - this.directionMap = directionMap; - } - - public VariableDirection getDirection(Variable variable) { - var direction = directionMap.get(variable); - if (direction == null) { - throw new IllegalArgumentException("No such variable " + variable); - } - return direction; - } - - public VariableDirection getDirection(Variable variable, Set positiveVariables) { - var direction = getDirection(variable); - return disambiguateDirection(direction, variable, positiveVariables); - } - - public Stream getVariablesWithDirection(VariableDirection direction) { - return directionMap.entrySet().stream() - .filter(pair -> pair.getValue() == direction) - .map(Map.Entry::getKey); - } - - public Stream getVariablesWithDirection(VariableDirection direction, - Set positiveVariables) { - if (direction == VariableDirection.NEUTRAL) { - throw new IllegalArgumentException("Use #getVariablesWithDirection(VariableDirection) if disambiguation " + - "of VariableDirection#NEUTRAL variables according to the containing DnfClose is not desired"); - } - return directionMap.entrySet().stream() - .filter(pair -> disambiguateDirection(pair.getValue(), pair.getKey(), positiveVariables) == direction) - .map(Map.Entry::getKey); - } - - private VariableDirection disambiguateDirection(VariableDirection direction, Variable variable, - Set positiveVariables) { - if (direction != VariableDirection.NEUTRAL) { - return direction; - } - return positiveVariables.contains(variable) ? VariableDirection.IN : VariableDirection.CLOSURE; - } - - public static VariableBindingSiteBuilder builder() { - return new VariableBindingSiteBuilder(); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableBindingSiteBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableBindingSiteBuilder.java deleted file mode 100644 index 873db1ec..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableBindingSiteBuilder.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.literal; - -import tools.refinery.store.query.exceptions.IncompatibleParameterDirectionException; -import tools.refinery.store.query.term.*; - -import java.util.*; - -public final class VariableBindingSiteBuilder { - private final Map directionMap = new LinkedHashMap<>(); - private final Set nonUnifiableVariables = new HashSet<>(); - - VariableBindingSiteBuilder() { - } - - public VariableBindingSiteBuilder variable(Variable variable, VariableDirection direction) { - return variable(variable, direction, direction == VariableDirection.OUT); - } - - public VariableBindingSiteBuilder variable(Variable variable, VariableDirection direction, boolean markAsUnique) { - validateUnique(direction, markAsUnique); - validateDirection(variable, direction); - boolean unique; - if (markAsUnique) { - nonUnifiableVariables.add(variable); - unique = true; - } else { - unique = nonUnifiableVariables.contains(variable); - } - directionMap.compute(variable, (ignored, oldValue) -> { - if (oldValue == null) { - return direction; - } - if (unique) { - throw new IllegalArgumentException("Duplicate binding for variable " + variable); - } - try { - return merge(oldValue, direction); - } catch (IncompatibleParameterDirectionException e) { - var message = "%s for variable %s".formatted(e.getMessage(), variable); - throw new IncompatibleParameterDirectionException(message, e); - } - }); - return this; - } - - private static void validateUnique(VariableDirection direction, boolean markAsUnique) { - if (direction == VariableDirection.OUT && !markAsUnique) { - throw new IllegalArgumentException("OUT binding must be marked as non-unifiable"); - } - if (markAsUnique && (direction != VariableDirection.OUT && direction != VariableDirection.CLOSURE)) { - throw new IllegalArgumentException("Only OUT or CLOSURE binding may be marked as non-unifiable"); - } - } - - private static void validateDirection(Variable variable, VariableDirection direction) { - if (variable instanceof AnyDataVariable) { - if (direction == VariableDirection.IN_OUT) { - throw new IllegalArgumentException("%s direction is not supported for data variable %s" - .formatted(direction, variable)); - } - } else if (variable instanceof NodeVariable) { - if (direction == VariableDirection.OUT) { - throw new IllegalArgumentException("%s direction is not supported for node variable %s" - .formatted(direction, variable)); - } - } else { - throw new IllegalArgumentException("Unknown variable " + variable); - } - } - - private static VariableDirection merge(VariableDirection left, VariableDirection right) { - return switch (left) { - case IN_OUT -> switch (right) { - case IN_OUT -> VariableDirection.IN_OUT; - case OUT -> VariableDirection.OUT; - case IN, NEUTRAL -> VariableDirection.IN; - case CLOSURE -> throw incompatibleDirections(left, right); - }; - case OUT -> switch (right) { - case IN_OUT, OUT -> VariableDirection.OUT; - case IN, NEUTRAL, CLOSURE -> throw incompatibleDirections(left, right); - }; - case IN -> switch (right) { - case IN_OUT, NEUTRAL, IN -> VariableDirection.IN; - case OUT, CLOSURE -> throw incompatibleDirections(left, right); - }; - case NEUTRAL -> switch (right) { - case IN_OUT, IN -> VariableDirection.IN; - case NEUTRAL -> VariableDirection.NEUTRAL; - case CLOSURE -> VariableDirection.CLOSURE; - case OUT -> throw incompatibleDirections(left, right); - }; - case CLOSURE -> switch (right) { - case NEUTRAL, CLOSURE -> VariableDirection.CLOSURE; - case IN_OUT, IN, OUT -> throw incompatibleDirections(left, right); - }; - }; - } - - private static RuntimeException incompatibleDirections(VariableDirection left, VariableDirection right) { - return new IncompatibleParameterDirectionException("Incompatible variable directions %s and %s" - .formatted(left, right)); - } - - public VariableBindingSiteBuilder variables(Collection variables, VariableDirection direction) { - for (var variable : variables) { - variable(variable, direction); - } - return this; - } - - public VariableBindingSiteBuilder parameterList(boolean positive, List parameters, - List arguments) { - int arity = parameters.size(); - if (arity != arguments.size()) { - throw new IllegalArgumentException("Got %d arguments for %d parameters" - .formatted(arguments.size(), arity)); - } - for (int i = 0; i < arity; i++) { - var argument = arguments.get(i); - var parameter = parameters.get(i); - var parameterDirection = parameter.getDirection(); - var direction = VariableDirection.from(positive, parameterDirection); - variable(argument, direction, parameterDirection == ParameterDirection.OUT); - } - return this; - } - - public VariableBindingSite build() { - return new VariableBindingSite(directionMap); - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableDirection.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableDirection.java deleted file mode 100644 index 0b7a2960..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/VariableDirection.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query.literal; - -import tools.refinery.store.query.term.ParameterDirection; - -/** - * Directions of the flow of a variable to ro from a clause. - *

- * During the evaluation of a clause - *

    - *
  1. reads already bound {@code IN} variables,
  2. - *
  3. enumerates over all possible bindings of {@code CLOSURE} variables, and
  4. - *
  5. - * produces bindings for - *
      - *
    • {@code IN_OUT} variables that may already be bound in clause (if they already have a binding, - * the existing values are compared to the new binding by {@link Object#equals(Object)}), and
    • - *
    • {@code OUT} variables that must not be already bound in the clause (because comparison by - * equality wouldn't produce an appropriate join).
    • - *
    - *
  6. - *
- * Variables marked as {@code NEUTRAL} may act as {@code IN} or {@code CLOSURE} depending on whether they have an - * existing binding that can be read. - */ -public enum VariableDirection { - /** - * Binds a node variable or check equality with a node variable. - *

- * This is the usual direction for positive constraints on nodes. A data variable may have multiple {@code IN_OUT} - * bindings, even on the same parameter list. - *

- * Cannot be used for data variables. - */ - IN_OUT, - - /** - * Binds a data variable. - *

- * A single variable must have at most one {@code OUT} binding. A variable with a {@code OUT} binding cannot - * appear in any other place in a parameter list. - *

- * Cannot be used for node variables. - */ - OUT, - - /** - * Takes an already bound variable. - *

- * May be used with node or data variables. An {@code IN_OUT} or {@code OUT} binding on the same parameter list - * cannot satisfy the {@code IN} binding, because it might introduce a (non-monotonic) circular dependency. - */ - IN, - - /** - * Either takes a bound data variable or enumerates all possible data variable bindings. - *

- * Cannot be used for data variables. - */ - NEUTRAL, - - /** - * Enumerates over all possible data variable bindings. - *

- * May be used with node or data variables. The variable may not appear in any other parameter list. A data - * variable may only appear once in the parameter list, but node variables can appear multiple times to form - * diagonal constraints. - */ - CLOSURE; - - public static VariableDirection from(boolean positive, ParameterDirection parameterDirection) { - return switch (parameterDirection) { - case IN_OUT -> positive ? IN_OUT : NEUTRAL; - case OUT -> positive ? OUT : CLOSURE; - case IN -> IN; - }; - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java index 5864ee56..192c39c5 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java @@ -36,6 +36,11 @@ public abstract sealed class AnyDataVariable extends Variable implements AnyTerm return Set.of(this); } + @Override + public boolean isUnifiable() { + return false; + } + @Override public abstract AnyDataVariable renew(@Nullable String name); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java index 37f9d477..a2f3261f 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java @@ -21,6 +21,11 @@ public final class NodeVariable extends Variable { return Optional.empty(); } + @Override + public boolean isUnifiable() { + return true; + } + @Override public NodeVariable renew(@Nullable String name) { return Variable.of(name); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Parameter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Parameter.java index 351a353d..0fe297ab 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Parameter.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Parameter.java @@ -9,7 +9,7 @@ import java.util.Objects; import java.util.Optional; public class Parameter { - public static final Parameter NODE_IN_OUT = new Parameter(null, ParameterDirection.IN_OUT); + public static final Parameter NODE_IN_OUT = new Parameter(null, ParameterDirection.OUT); private final Class dataType; private final ParameterDirection direction; @@ -17,13 +17,6 @@ public class Parameter { public Parameter(Class dataType, ParameterDirection direction) { this.dataType = dataType; this.direction = direction; - if (isDataVariable()) { - if (direction == ParameterDirection.IN_OUT) { - throw new IllegalArgumentException("IN_OUT direction is not supported for data parameters"); - } - } else if (direction == ParameterDirection.OUT) { - throw new IllegalArgumentException("OUT direction is not supported for node parameters"); - } } public boolean isNodeVariable() { diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ParameterDirection.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ParameterDirection.java index 652208aa..cd0739be 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ParameterDirection.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ParameterDirection.java @@ -6,7 +6,6 @@ package tools.refinery.store.query.term; public enum ParameterDirection { - IN_OUT("@InOut"), OUT("@Out"), IN("@In"); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java index 869120fa..a0268c8e 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java @@ -38,6 +38,8 @@ public abstract sealed class Variable permits AnyDataVariable, NodeVariable { return uniqueName; } + public abstract boolean isUnifiable(); + public abstract Variable renew(@Nullable String name); public abstract Variable renew(); diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderLiteralEliminationTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderLiteralEliminationTest.java index 4edea401..687b06db 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderLiteralEliminationTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderLiteralEliminationTest.java @@ -10,6 +10,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import tools.refinery.store.query.literal.BooleanLiteral; import tools.refinery.store.query.term.NodeVariable; +import tools.refinery.store.query.term.ParameterDirection; import tools.refinery.store.query.term.Variable; import tools.refinery.store.query.term.bool.BoolTerms; import tools.refinery.store.query.view.KeyOnlyView; @@ -28,7 +29,7 @@ class DnfBuilderLiteralEliminationTest { private final SymbolView friendView = new KeyOnlyView<>(friend); private final NodeVariable p = Variable.of("p"); private final NodeVariable q = Variable.of("q"); - private final Dnf trueDnf = Dnf.builder().parameter(p).clause().build(); + private final Dnf trueDnf = Dnf.builder().parameter(p, ParameterDirection.IN).clause().build(); private final Dnf falseDnf = Dnf.builder().parameter(p).build(); @Test @@ -84,11 +85,11 @@ class DnfBuilderLiteralEliminationTest { @Test void alwaysTrueTest() { var actual = Dnf.builder() - .parameters(p, q) + .parameters(List.of(p, q), ParameterDirection.IN) .clause(friendView.call(p, q)) .clause(BooleanLiteral.TRUE) .build(); - var expected = Dnf.builder().parameters(p, q).clause().build(); + var expected = Dnf.builder().parameters(List.of(p, q), ParameterDirection.IN).clause().build(); assertThat(actual, structurallyEqualTo(expected)); } @@ -130,11 +131,11 @@ class DnfBuilderLiteralEliminationTest { @Test void alwaysTrueDnfTest() { var actual = Dnf.builder() - .parameters(p, q) + .parameters(List.of(p, q), ParameterDirection.IN) .clause(friendView.call(p, q)) .clause(trueDnf.call(q)) .build(); - var expected = Dnf.builder().parameters(p, q).clause().build(); + var expected = Dnf.builder().parameters(List.of(p, q), ParameterDirection.IN).clause().build(); assertThat(actual, structurallyEqualTo(expected)); } @@ -176,11 +177,11 @@ class DnfBuilderLiteralEliminationTest { @Test void alwaysNotFalseDnfTest() { var actual = Dnf.builder() - .parameters(p, q) + .parameters(List.of(p, q), ParameterDirection.IN) .clause(friendView.call(p, q)) .clause(not(falseDnf.call(q))) .build(); - var expected = Dnf.builder().parameters(p, q).clause().build(); + var expected = Dnf.builder().parameters(List.of(p, q), ParameterDirection.IN).clause().build(); assertThat(actual, structurallyEqualTo(expected)); } diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfToDefinitionStringTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfToDefinitionStringTest.java index 2e93d78a..63310a78 100644 --- a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfToDefinitionStringTest.java +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfToDefinitionStringTest.java @@ -6,6 +6,7 @@ package tools.refinery.store.query.dnf; import org.junit.jupiter.api.Test; +import tools.refinery.store.query.term.ParameterDirection; import tools.refinery.store.query.term.Variable; import tools.refinery.store.query.view.KeyOnlyView; import tools.refinery.store.representation.Symbol; @@ -39,7 +40,7 @@ class DnfToDefinitionStringTest { @Test void emptyClauseTest() { var p = Variable.of("p"); - var dnf = Dnf.builder("Example").parameter(p).clause().build(); + var dnf = Dnf.builder("Example").parameter(p, ParameterDirection.IN).clause().build(); assertThat(dnf.toDefinitionString(), is(""" pred Example(@In p) <-> @@ -67,10 +68,13 @@ class DnfToDefinitionStringTest { var q = Variable.of("q"); var friend = new Symbol<>("friend", 2, Boolean.class, false); var friendView = new KeyOnlyView<>(friend); - var dnf = Dnf.builder("Example").parameter(p).clause(not(friendView.call(p, q))).build(); + var dnf = Dnf.builder("Example") + .parameter(p, ParameterDirection.IN) + .clause(not(friendView.call(p, q))) + .build(); assertThat(dnf.toDefinitionString(), is(""" - pred Example(p) <-> + pred Example(@In p) <-> !(@RelationView("key") friend(p, q)). """)); } -- cgit v1.2.3-70-g09d2 From 8d79e7f39df0fde9b4f0ba8e6264f2900e9024c6 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Thu, 29 Jun 2023 02:08:40 +0200 Subject: feat: ordered query ResultSet Enable deterministic state-space exploration by ordering activations in lexicographic order. This preliminary implementation adds oredering as a wrapper for ResultSet instances, but more sophisticated support could be built directly into query engine adapters if a query engine supports deterministic output by default. * Implements Comparable for tuples with loops unrolled for small tuples by hand. * Cleans up the contents of the (root of the) tools.refinery.query package. * Adds ResultSetListener to notify clients about ResultSet changes. * Adds OrderStatisticTree data structure for determinisitc ordering of keys. --- .../internal/ViatraModelQueryAdapterImpl.java | 6 +- .../internal/matcher/AbstractViatraMatcher.java | 32 + .../internal/matcher/FunctionalViatraMatcher.java | 34 +- .../viatra/internal/matcher/MatcherUtils.java | 10 +- .../internal/matcher/RelationalViatraMatcher.java | 29 +- .../internal/matcher/UnsafeFunctionalCursor.java | 4 +- .../store/query/viatra/OrderedResultSetTest.java | 117 ++++ .../store/query/viatra/tests/QueryAssertions.java | 2 +- .../tools/refinery/store/query/AnyResultSet.java | 16 - .../tools/refinery/store/query/EmptyResultSet.java | 38 -- .../refinery/store/query/ModelQueryAdapter.java | 2 + .../java/tools/refinery/store/query/Reduction.java | 31 - .../java/tools/refinery/store/query/ResultSet.java | 18 - .../java/tools/refinery/store/query/dnf/Dnf.java | 2 +- .../refinery/store/query/literal/Reduction.java | 31 + .../store/query/resultset/AbstractResultSet.java | 63 ++ .../store/query/resultset/AnyResultSet.java | 17 + .../store/query/resultset/EmptyResultSet.java | 49 ++ .../store/query/resultset/OrderedResultSet.java | 80 +++ .../refinery/store/query/resultset/ResultSet.java | 22 + .../store/query/resultset/ResultSetListener.java | 13 + .../store/query/utils/OrderStatisticTree.java | 754 +++++++++++++++++++++ .../store/query/utils/OrderStatisticTreeTest.java | 634 +++++++++++++++++ .../refinery/store/reasoning/ReasoningAdapter.java | 2 +- .../reasoning/internal/ReasoningAdapterImpl.java | 2 +- .../store/reasoning/literal/ModalConstraint.java | 2 +- .../base/BaseDecisionInterpretation.java | 2 +- .../java/tools/refinery/store/tuple/Tuple.java | 20 +- .../java/tools/refinery/store/tuple/Tuple0.java | 4 + .../java/tools/refinery/store/tuple/Tuple1.java | 13 + .../java/tools/refinery/store/tuple/Tuple2.java | 14 + .../java/tools/refinery/store/tuple/Tuple3.java | 18 + .../java/tools/refinery/store/tuple/Tuple4.java | 22 + 33 files changed, 1943 insertions(+), 160 deletions(-) create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/AbstractViatraMatcher.java create mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/OrderedResultSetTest.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/AnyResultSet.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/Reduction.java delete mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Reduction.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AbstractResultSet.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AnyResultSet.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/EmptyResultSet.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/OrderedResultSet.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/ResultSet.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/ResultSetListener.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/utils/OrderStatisticTree.java create mode 100644 subprojects/store-query/src/test/java/tools/refinery/store/query/utils/OrderStatisticTreeTest.java (limited to 'subprojects/store-query-viatra/src/main/java/tools') 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 7103a561..5f3e86b4 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 @@ -13,9 +13,9 @@ 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.model.ModelListener; -import tools.refinery.store.query.AnyResultSet; -import tools.refinery.store.query.EmptyResultSet; -import tools.refinery.store.query.ResultSet; +import tools.refinery.store.query.resultset.AnyResultSet; +import tools.refinery.store.query.resultset.EmptyResultSet; +import tools.refinery.store.query.resultset.ResultSet; import tools.refinery.store.query.dnf.AnyQuery; import tools.refinery.store.query.dnf.FunctionalQuery; import tools.refinery.store.query.dnf.Query; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/AbstractViatraMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/AbstractViatraMatcher.java new file mode 100644 index 00000000..99b0a3d8 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/AbstractViatraMatcher.java @@ -0,0 +1,32 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.viatra.internal.matcher; + +import org.eclipse.viatra.query.runtime.matchers.backend.IQueryResultProvider; +import org.eclipse.viatra.query.runtime.matchers.backend.IUpdateable; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.query.resultset.AbstractResultSet; +import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; + +public abstract class AbstractViatraMatcher extends AbstractResultSet implements IUpdateable { + protected final IQueryResultProvider backend; + + protected AbstractViatraMatcher(ViatraModelQueryAdapterImpl adapter, Query query, + RawPatternMatcher rawPatternMatcher) { + super(adapter, query); + backend = rawPatternMatcher.getBackend(); + } + + @Override + protected void startListeningForChanges() { + backend.addUpdateListener(this, this, false); + } + + @Override + protected void stopListeningForChanges() { + backend.removeUpdateListener(this); + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java index f018288b..db4740cd 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java @@ -5,16 +5,12 @@ */ package tools.refinery.store.query.viatra.internal.matcher; -import org.eclipse.viatra.query.runtime.matchers.backend.IQueryResultProvider; import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; import org.eclipse.viatra.query.runtime.rete.index.IterableIndexer; import org.eclipse.viatra.query.runtime.rete.matcher.RetePatternMatcher; import tools.refinery.store.map.Cursor; -import tools.refinery.store.query.ModelQueryAdapter; -import tools.refinery.store.query.ResultSet; import tools.refinery.store.query.dnf.FunctionalQuery; -import tools.refinery.store.query.dnf.Query; import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; import tools.refinery.store.tuple.Tuple; @@ -28,23 +24,18 @@ import tools.refinery.store.tuple.Tuple; * implementation for these methods. * Using this class with any other runtime context may lead to undefined behavior. */ -public class FunctionalViatraMatcher implements ResultSet { - private final ViatraModelQueryAdapterImpl adapter; - private final FunctionalQuery query; +public class FunctionalViatraMatcher extends AbstractViatraMatcher { private final TupleMask emptyMask; private final TupleMask omitOutputMask; - private final IQueryResultProvider backend; private final IterableIndexer omitOutputIndexer; public FunctionalViatraMatcher(ViatraModelQueryAdapterImpl adapter, FunctionalQuery query, RawPatternMatcher rawPatternMatcher) { - this.adapter = adapter; - this.query = query; + super(adapter, query, rawPatternMatcher); int arity = query.arity(); int arityWithOutput = arity + 1; emptyMask = TupleMask.empty(arityWithOutput); omitOutputMask = TupleMask.omit(arity, arityWithOutput); - backend = rawPatternMatcher.getBackend(); if (backend instanceof RetePatternMatcher reteBackend) { var maybeIterableOmitOutputIndexer = IndexerUtils.getIndexer(reteBackend, omitOutputMask); if (maybeIterableOmitOutputIndexer instanceof IterableIndexer iterableOmitOutputIndexer) { @@ -57,16 +48,6 @@ public class FunctionalViatraMatcher implements ResultSet { } } - @Override - public ModelQueryAdapter getAdapter() { - return adapter; - } - - @Override - public Query getQuery() { - return query; - } - @Override public T get(Tuple parameters) { var tuple = MatcherUtils.toViatraTuple(parameters); @@ -93,4 +74,15 @@ public class FunctionalViatraMatcher implements ResultSet { } return omitOutputIndexer.getBucketCount(); } + + @Override + public void update(org.eclipse.viatra.query.runtime.matchers.tuple.Tuple updateElement, boolean isInsertion) { + var key = MatcherUtils.keyToRefineryTuple(updateElement); + var value = MatcherUtils.getValue(updateElement); + if (isInsertion) { + notifyChange(key, null, value); + } else { + notifyChange(key, value, null); + } + } } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java index 1c784492..6e24812a 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java @@ -86,6 +86,13 @@ final class MatcherUtils { return getWrapper(viatraTuple, index).value0(); } + public static T getValue(ITuple match) { + // This is only safe if we know for sure that match came from a functional query of type {@code T}. + @SuppressWarnings("unchecked") + var result = (T) match.get(match.getSize() - 1); + return result; + } + public static T getSingleValue(@Nullable Iterable viatraTuples) { if (viatraTuples == null) { return null; @@ -98,8 +105,7 @@ final class MatcherUtils { return null; } var match = iterator.next(); - @SuppressWarnings("unchecked") - var result = (T) match.get(match.getSize() - 1); + var result = MatcherUtils.getValue(match); if (iterator.hasNext()) { var input = keyToRefineryTuple(match); throw new IllegalStateException("Query is not functional for input tuple: " + input); diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java index d1476920..ac95dcc0 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java @@ -5,16 +5,12 @@ */ package tools.refinery.store.query.viatra.internal.matcher; -import org.eclipse.viatra.query.runtime.matchers.backend.IQueryResultProvider; import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; import org.eclipse.viatra.query.runtime.rete.index.Indexer; import org.eclipse.viatra.query.runtime.rete.matcher.RetePatternMatcher; import tools.refinery.store.map.Cursor; import tools.refinery.store.map.Cursors; -import tools.refinery.store.query.ModelQueryAdapter; -import tools.refinery.store.query.ResultSet; -import tools.refinery.store.query.dnf.Query; import tools.refinery.store.query.dnf.RelationalQuery; import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; import tools.refinery.store.tuple.Tuple; @@ -29,22 +25,17 @@ import tools.refinery.store.tuple.Tuple; * implementation for these methods. * Using this class with any other runtime context may lead to undefined behavior. */ -public class RelationalViatraMatcher implements ResultSet { - private final ViatraModelQueryAdapterImpl adapter; - private final RelationalQuery query; +public class RelationalViatraMatcher extends AbstractViatraMatcher { private final TupleMask emptyMask; private final TupleMask identityMask; - private final IQueryResultProvider backend; private final Indexer emptyMaskIndexer; public RelationalViatraMatcher(ViatraModelQueryAdapterImpl adapter, RelationalQuery query, RawPatternMatcher rawPatternMatcher) { - this.adapter = adapter; - this.query = query; + super(adapter, query, rawPatternMatcher); int arity = query.arity(); emptyMask = TupleMask.empty(arity); identityMask = TupleMask.identity(arity); - backend = rawPatternMatcher.getBackend(); if (backend instanceof RetePatternMatcher reteBackend) { emptyMaskIndexer = IndexerUtils.getIndexer(reteBackend, emptyMask); } else { @@ -52,16 +43,6 @@ public class RelationalViatraMatcher implements ResultSet { } } - @Override - public ModelQueryAdapter getAdapter() { - return adapter; - } - - @Override - public Query getQuery() { - return query; - } - @Override public Boolean get(Tuple parameters) { var tuple = MatcherUtils.toViatraTuple(parameters); @@ -90,4 +71,10 @@ public class RelationalViatraMatcher implements ResultSet { var matches = emptyMaskIndexer.get(Tuples.staticArityFlatTupleOf()); return matches == null ? 0 : matches.size(); } + + @Override + public void update(org.eclipse.viatra.query.runtime.matchers.tuple.Tuple updateElement, boolean isInsertion) { + var key = MatcherUtils.toRefineryTuple(updateElement); + notifyChange(key, !isInsertion, isInsertion); + } } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java index 4a41d724..b0b507fe 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java @@ -46,9 +46,7 @@ class UnsafeFunctionalCursor implements Cursor { if (!terminated && tuplesIterator.hasNext()) { var match = tuplesIterator.next(); key = MatcherUtils.keyToRefineryTuple(match); - @SuppressWarnings("unchecked") - var typedValue = (T) match.get(match.getSize() - 1); - value = typedValue; + value = MatcherUtils.getValue(match); return true; } terminated = true; diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/OrderedResultSetTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/OrderedResultSetTest.java new file mode 100644 index 00000000..8ede6c80 --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/OrderedResultSetTest.java @@ -0,0 +1,117 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.viatra; + +import org.junit.jupiter.api.Test; +import tools.refinery.store.model.ModelStore; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.query.resultset.OrderedResultSet; +import tools.refinery.store.query.term.Variable; +import tools.refinery.store.query.view.AnySymbolView; +import tools.refinery.store.query.view.KeyOnlyView; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.tuple.Tuple; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +class OrderedResultSetTest { + private static final Symbol friend = Symbol.of("friend", 2); + private static final AnySymbolView friendView = new KeyOnlyView<>(friend); + + @Test + void relationalFlushTest() { + var query = Query.of("Relation", (builder, p1, p2) -> builder.clause( + friendView.call(p1, p2) + )); + + var store = ModelStore.builder() + .symbols(friend) + .with(ViatraModelQueryAdapter.builder() + .queries(query)) + .build(); + + var model = store.createEmptyModel(); + var friendInterpretation = model.getInterpretation(friend); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + var resultSet = queryEngine.getResultSet(query); + + friendInterpretation.put(Tuple.of(0, 1), true); + friendInterpretation.put(Tuple.of(1, 2), true); + friendInterpretation.put(Tuple.of(1, 1), true); + queryEngine.flushChanges(); + + try (var orderedResultSet = new OrderedResultSet<>(resultSet)) { + assertThat(orderedResultSet.size(), is(3)); + assertThat(orderedResultSet.getKey(0), is(Tuple.of(0, 1))); + assertThat(orderedResultSet.getKey(1), is(Tuple.of(1, 1))); + assertThat(orderedResultSet.getKey(2), is(Tuple.of(1, 2))); + + friendInterpretation.put(Tuple.of(1, 2), false); + friendInterpretation.put(Tuple.of(0, 2), true); + queryEngine.flushChanges(); + + assertThat(orderedResultSet.size(), is(3)); + assertThat(orderedResultSet.getKey(0), is(Tuple.of(0, 1))); + assertThat(orderedResultSet.getKey(1), is(Tuple.of(0, 2))); + assertThat(orderedResultSet.getKey(2), is(Tuple.of(1, 1))); + } + } + + @Test + void functionalFlushTest() { + var query = Query.of("Function", Integer.class, (builder, p1, output) -> builder.clause( + friendView.call(p1, Variable.of()), + output.assign(friendView.count(p1, Variable.of())) + )); + + var store = ModelStore.builder() + .symbols(friend) + .with(ViatraModelQueryAdapter.builder() + .queries(query)) + .build(); + + var model = store.createEmptyModel(); + var friendInterpretation = model.getInterpretation(friend); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + var resultSet = queryEngine.getResultSet(query); + + friendInterpretation.put(Tuple.of(0, 1), true); + friendInterpretation.put(Tuple.of(1, 2), true); + friendInterpretation.put(Tuple.of(1, 1), true); + queryEngine.flushChanges(); + + try (var orderedResultSet = new OrderedResultSet<>(resultSet)) { + assertThat(orderedResultSet.size(), is(2)); + assertThat(orderedResultSet.getKey(0), is(Tuple.of(0))); + assertThat(orderedResultSet.getKey(1), is(Tuple.of(1))); + + friendInterpretation.put(Tuple.of(0, 1), false); + friendInterpretation.put(Tuple.of(2, 1), true); + queryEngine.flushChanges(); + + assertThat(orderedResultSet.size(), is(2)); + assertThat(orderedResultSet.getKey(0), is(Tuple.of(1))); + assertThat(orderedResultSet.getKey(1), is(Tuple.of(2))); + + friendInterpretation.put(Tuple.of(1, 1), false); + queryEngine.flushChanges(); + + assertThat(orderedResultSet.size(), is(2)); + assertThat(orderedResultSet.getKey(0), is(Tuple.of(1))); + assertThat(orderedResultSet.getKey(1), is(Tuple.of(2))); + + friendInterpretation.put(Tuple.of(1, 2), false); + friendInterpretation.put(Tuple.of(1, 0), true); + queryEngine.flushChanges(); + + assertThat(orderedResultSet.size(), is(2)); + assertThat(orderedResultSet.getKey(0), is(Tuple.of(1))); + assertThat(orderedResultSet.getKey(1), is(Tuple.of(2))); + } + } +} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java index 7a25cfdc..ca089a9d 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java @@ -6,7 +6,7 @@ package tools.refinery.store.query.viatra.tests; import org.junit.jupiter.api.function.Executable; -import tools.refinery.store.query.ResultSet; +import tools.refinery.store.query.resultset.ResultSet; import tools.refinery.store.tuple.Tuple; import java.util.*; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/AnyResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/AnyResultSet.java deleted file mode 100644 index f29bb278..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/AnyResultSet.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query; - -import tools.refinery.store.query.dnf.AnyQuery; - -public sealed interface AnyResultSet permits ResultSet { - ModelQueryAdapter getAdapter(); - - AnyQuery getQuery(); - - int size(); -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java deleted file mode 100644 index 5361f645..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query; - -import tools.refinery.store.map.Cursor; -import tools.refinery.store.map.Cursors; -import tools.refinery.store.query.dnf.Query; -import tools.refinery.store.tuple.Tuple; - -public record EmptyResultSet(ModelQueryAdapter adapter, Query query) implements ResultSet { - @Override - public ModelQueryAdapter getAdapter() { - return adapter; - } - - @Override - public Query getQuery() { - return query; - } - - @Override - public T get(Tuple parameters) { - return query.defaultValue(); - } - - @Override - public Cursor getAll() { - return Cursors.empty(); - } - - @Override - public int size() { - return 0; - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java index ae3bbcbb..1fa96a07 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java @@ -8,6 +8,8 @@ package tools.refinery.store.query; import tools.refinery.store.adapter.ModelAdapter; import tools.refinery.store.query.dnf.AnyQuery; import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.query.resultset.AnyResultSet; +import tools.refinery.store.query.resultset.ResultSet; public interface ModelQueryAdapter extends ModelAdapter { ModelQueryStoreAdapter getStoreAdapter(); diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/Reduction.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/Reduction.java deleted file mode 100644 index 82c52b04..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/Reduction.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query; - -public enum Reduction { - /** - * Signifies that a literal should be preserved in the clause. - */ - NOT_REDUCIBLE, - - /** - * Signifies that the literal may be omitted from the cause (if the model being queried is nonempty). - */ - ALWAYS_TRUE, - - /** - * Signifies that the clause with the literal may be omitted entirely. - */ - ALWAYS_FALSE; - - public Reduction negate() { - return switch (this) { - case NOT_REDUCIBLE -> NOT_REDUCIBLE; - case ALWAYS_TRUE -> ALWAYS_FALSE; - case ALWAYS_FALSE -> ALWAYS_TRUE; - }; - } -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java deleted file mode 100644 index 9ab83172..00000000 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.query; - -import tools.refinery.store.map.Cursor; -import tools.refinery.store.query.dnf.Query; -import tools.refinery.store.tuple.Tuple; - -public non-sealed interface ResultSet extends AnyResultSet { - Query getQuery(); - - T get(Tuple parameters); - - Cursor getAll(); -} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java index c5b51b81..50b245f7 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java @@ -6,7 +6,7 @@ package tools.refinery.store.query.dnf; import tools.refinery.store.query.Constraint; -import tools.refinery.store.query.Reduction; +import tools.refinery.store.query.literal.Reduction; import tools.refinery.store.query.equality.DnfEqualityChecker; import tools.refinery.store.query.equality.LiteralEqualityHelper; import tools.refinery.store.query.term.Parameter; diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Reduction.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Reduction.java new file mode 100644 index 00000000..ee155a9a --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Reduction.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.literal; + +public enum Reduction { + /** + * Signifies that a literal should be preserved in the clause. + */ + NOT_REDUCIBLE, + + /** + * Signifies that the literal may be omitted from the cause (if the model being queried is nonempty). + */ + ALWAYS_TRUE, + + /** + * Signifies that the clause with the literal may be omitted entirely. + */ + ALWAYS_FALSE; + + public Reduction negate() { + return switch (this) { + case NOT_REDUCIBLE -> NOT_REDUCIBLE; + case ALWAYS_TRUE -> ALWAYS_FALSE; + case ALWAYS_FALSE -> ALWAYS_TRUE; + }; + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AbstractResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AbstractResultSet.java new file mode 100644 index 00000000..a710c64d --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AbstractResultSet.java @@ -0,0 +1,63 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.resultset; + +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.tuple.Tuple; + +import java.util.ArrayList; +import java.util.List; + +public abstract class AbstractResultSet implements ResultSet { + private final ModelQueryAdapter adapter; + private final Query query; + private final List> listeners = new ArrayList<>(); + + protected AbstractResultSet(ModelQueryAdapter adapter, Query query) { + this.adapter = adapter; + this.query = query; + } + + @Override + public ModelQueryAdapter getAdapter() { + return adapter; + } + + @Override + public Query getQuery() { + return query; + } + + @Override + public void addListener(ResultSetListener listener) { + if (listeners.isEmpty()) { + startListeningForChanges(); + } + listeners.add(listener); + } + + @Override + public void removeListener(ResultSetListener listener) { + listeners.remove(listener); + if (listeners.isEmpty()) { + stopListeningForChanges(); + } + } + + protected abstract void startListeningForChanges(); + + protected abstract void stopListeningForChanges(); + + protected void notifyChange(Tuple key, T oldValue, T newValue) { + int listenerCount = listeners.size(); + // Use a for loop instead of a for-each loop to avoid {@code Iterator} allocation overhead. + //noinspection ForLoopReplaceableByForEach + for (int i = 0; i < listenerCount; i++) { + listeners.get(i).put(key, oldValue, newValue); + } + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AnyResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AnyResultSet.java new file mode 100644 index 00000000..02809477 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AnyResultSet.java @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.resultset; + +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.dnf.AnyQuery; + +public sealed interface AnyResultSet permits ResultSet { + ModelQueryAdapter getAdapter(); + + AnyQuery getQuery(); + + int size(); +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/EmptyResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/EmptyResultSet.java new file mode 100644 index 00000000..2795a44b --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/EmptyResultSet.java @@ -0,0 +1,49 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.resultset; + +import tools.refinery.store.map.Cursor; +import tools.refinery.store.map.Cursors; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.tuple.Tuple; + +public record EmptyResultSet(ModelQueryAdapter adapter, Query query) implements ResultSet { + @Override + public ModelQueryAdapter getAdapter() { + return adapter; + } + + @Override + public Query getQuery() { + return query; + } + + @Override + public T get(Tuple parameters) { + return query.defaultValue(); + } + + @Override + public Cursor getAll() { + return Cursors.empty(); + } + + @Override + public int size() { + return 0; + } + + @Override + public void addListener(ResultSetListener listener) { + // No need to store the listener, because the empty result set will never change. + } + + @Override + public void removeListener(ResultSetListener listener) { + // No need to remove the listener, because we never stored it. + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/OrderedResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/OrderedResultSet.java new file mode 100644 index 00000000..39006d65 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/OrderedResultSet.java @@ -0,0 +1,80 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.resultset; + +import tools.refinery.store.map.Cursor; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.query.utils.OrderStatisticTree; +import tools.refinery.store.tuple.Tuple; + +import java.util.Objects; + +public class OrderedResultSet implements AutoCloseable, ResultSet { + private final ResultSet resultSet; + private final OrderStatisticTree tree = new OrderStatisticTree<>(); + private final ResultSetListener listener = (key, fromValue, toValue) -> { + var defaultValue = getQuery().defaultValue(); + if (Objects.equals(defaultValue, toValue)) { + tree.remove(key); + } else { + tree.add(key); + } + }; + + public OrderedResultSet(ResultSet resultSet) { + this.resultSet = resultSet; + resultSet.addListener(listener); + var cursor = resultSet.getAll(); + while (cursor.move()) { + tree.add(cursor.getKey()); + } + } + + @Override + public ModelQueryAdapter getAdapter() { + return resultSet.getAdapter(); + } + + @Override + public int size() { + return resultSet.size(); + } + + @Override + public Query getQuery() { + return resultSet.getQuery(); + } + + @Override + public T get(Tuple parameters) { + return resultSet.get(parameters); + } + + public Tuple getKey(int index) { + return tree.get(index); + } + + @Override + public Cursor getAll() { + return resultSet.getAll(); + } + + @Override + public void addListener(ResultSetListener listener) { + resultSet.addListener(listener); + } + + @Override + public void removeListener(ResultSetListener listener) { + resultSet.removeListener(listener); + } + + @Override + public void close() { + resultSet.removeListener(listener); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/ResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/ResultSet.java new file mode 100644 index 00000000..33d1ea95 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/ResultSet.java @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.resultset; + +import tools.refinery.store.map.Cursor; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.tuple.Tuple; + +public non-sealed interface ResultSet extends AnyResultSet { + Query getQuery(); + + T get(Tuple parameters); + + Cursor getAll(); + + void addListener(ResultSetListener listener); + + void removeListener(ResultSetListener listener); +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/ResultSetListener.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/ResultSetListener.java new file mode 100644 index 00000000..fd8a503e --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/ResultSetListener.java @@ -0,0 +1,13 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.resultset; + +import tools.refinery.store.tuple.Tuple; + +@FunctionalInterface +public interface ResultSetListener { + void put(Tuple key, T fromValue, T toValue); +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/utils/OrderStatisticTree.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/utils/OrderStatisticTree.java new file mode 100644 index 00000000..b568b99d --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/utils/OrderStatisticTree.java @@ -0,0 +1,754 @@ +/* + * Copyright (c) 2021 Rodion Efremov + * Copyright (c) 2023 The Refinery Authors + * + * SPDX-License-Identifier: MIT OR EPL-2.0 + */ +package tools.refinery.store.query.utils; + +import java.util.*; + +/** + * This class implements an order statistic tree which is based on AVL-trees. + *

+ * This class was copied into Refinery from + * https://github.com/coderodde/OrderStatisticTree + * and is available under the + * MIT License. + * We also incorporated changes by Eugene Schava + * and cleaned up some linter warnings. + * + * @param the actual element type. + * @author Rodion "rodde" Efremov + * @version based on 1.6 (Feb 11, 2016) + */ +public class OrderStatisticTree> implements Set { + + @Override + public Iterator iterator() { + return new TreeIterator(); + } + + private final class TreeIterator implements Iterator { + + private Node previousNode; + private Node nextNode; + private int expectedModCount = modCount; + + TreeIterator() { + if (root == null) { + nextNode = null; + } else { + nextNode = minimumNode(root); + } + } + + @Override + public boolean hasNext() { + return nextNode != null; + } + + @Override + public T next() { + if (nextNode == null) { + throw new NoSuchElementException("Iteration exceeded."); + } + + checkConcurrentModification(); + T datum = nextNode.key; + previousNode = nextNode; + nextNode = successorOf(nextNode); + return datum; + } + + @Override + public void remove() { + if (previousNode == null) { + throw new IllegalStateException( + nextNode == null ? + "Not a single call to next(); nothing to remove." : + "Removing the same element twice." + ); + } + + checkConcurrentModification(); + + Node x = deleteNode(previousNode); + fixAfterModification(x, false); + + if (x == nextNode) { + nextNode = previousNode; + } + + expectedModCount = ++modCount; + size--; + previousNode = null; + } + + private void checkConcurrentModification() { + if (expectedModCount != modCount) { + throw new ConcurrentModificationException( + "The set was modified while iterating."); + } + } + + private Node successorOf(Node node) { + if (node.right != null) { + node = node.right; + + while (node.left != null) { + node = node.left; + } + + return node; + } + + Node parent = node.parent; + + while (parent != null && parent.right == node) { + node = parent; + parent = parent.parent; + } + + return parent; + } + } + + @Override + public Object[] toArray() { + Object[] array = new Object[size]; + Iterator iterator = iterator(); + int index = 0; + + while (iterator.hasNext()) { + array[index++] = iterator.next(); + } + + return array; + } + + @Override + public U[] toArray(U[] a) { + Iterator iterator = iterator(); + + if (size > a.length) { + a = Arrays.copyOf(a, size); + } + + int index = 0; + + for (; index < size; ++index) { + @SuppressWarnings("unchecked") + var convertedValue = (U) iterator.next(); + a[index] = convertedValue; + } + + if (index < a.length) { + a[index] = null; + } + + return a; + } + + @Override + public boolean containsAll(Collection c) { + for (Object element : c) { + if (!contains(element)) { + return false; + } + } + + return true; + } + + @Override + public boolean addAll(Collection c) { + boolean modified = false; + + for (T element : c) { + if (add(element)) { + modified = true; + } + } + + return modified; + } + + @Override + public boolean retainAll(Collection c) { + if (!c.getClass().equals(HashSet.class)) { + c = new HashSet<>(c); + } + + Iterator iterator = iterator(); + boolean modified = false; + + while (iterator.hasNext()) { + T element = iterator.next(); + + if (!c.contains(element)) { + iterator.remove(); + modified = true; + } + } + + return modified; + } + + @Override + public boolean removeAll(Collection c) { + boolean modified = false; + + for (Object element : c) { + if (remove(element)) { + modified = true; + } + } + + return modified; + } + + private static final class Node { + T key; + + Node parent; + Node left; + Node right; + + int height; + int count; + + Node(T key) { + this.key = key; + } + } + + private Node root; + private int size; + private int modCount; + + @Override + public boolean add(T element) { + Objects.requireNonNull(element, "The input element is null."); + + if (root == null) { + root = new Node<>(element); + size = 1; + modCount++; + return true; + } + + Node parent = null; + Node node = root; + int cmp; + + while (node != null) { + cmp = element.compareTo(node.key); + + if (cmp == 0) { + // The element is already in this tree. + return false; + } + + parent = node; + + if (cmp < 0) { + node = node.left; + } else { + node = node.right; + } + } + + Node newnode = new Node<>(element); + + if (element.compareTo(parent.key) < 0) { + parent.left = newnode; + } else { + parent.right = newnode; + } + + newnode.parent = parent; + size++; + modCount++; + Node hi = parent; + Node lo = newnode; + + while (hi != null) { + if (hi.left == lo) { + hi.count++; + } + + lo = hi; + hi = hi.parent; + } + + fixAfterModification(newnode, true); + return true; + } + + @Override + public boolean contains(Object o) { + @SuppressWarnings("unchecked") + T element = (T) o; + Node x = root; + int cmp; + + while (x != null && (cmp = element.compareTo(x.key)) != 0) { + if (cmp < 0) { + x = x.left; + } else { + x = x.right; + } + } + + return x != null; + } + + @Override + public boolean remove(Object o) { + @SuppressWarnings("unchecked") + T element = (T) o; + Node x = root; + int cmp; + + while (x != null && (cmp = element.compareTo(x.key)) != 0) { + if (cmp < 0) { + x = x.left; + } else { + x = x.right; + } + } + + if (x == null) { + return false; + } + + x = deleteNode(x); + fixAfterModification(x, false); + size--; + modCount++; + return true; + } + + public T get(int index) { + checkIndex(index); + Node node = root; + + while (true) { + if (index > node.count) { + index -= node.count + 1; + node = node.right; + } else if (index < node.count) { + node = node.left; + } else { + return node.key; + } + } + } + + public int indexOf(T element) { + Node node = root; + + if (root == null) { + return -1; + } + + int rank = root.count; + int cmp; + + while (true) { + if ((cmp = element.compareTo(node.key)) < 0) { + if (node.left == null) { + return -1; + } + + rank -= (node.count - node.left.count); + node = node.left; + } else if (cmp > 0) { + if (node.right == null) { + return -1; + } + + rank += 1 + node.right.count; + node = node.right; + } else { + return rank; + } + } + } + + @Override + public int size() { + return size; + } + + @Override + public boolean isEmpty() { + return size == 0; + } + + @Override + public void clear() { + modCount += size; + root = null; + size = 0; + } + + + private void checkIndex(int index) { + if (index < 0) { + throw new IndexOutOfBoundsException( + "The input index is negative: " + index); + } + + if (index >= size) { + throw new IndexOutOfBoundsException( + "The input index is too large: " + index + + ", the size of this tree is " + size); + } + } + + @SuppressWarnings("squid:S3776") + private Node deleteNode(Node node) { + if (node.left == null && node.right == null) { + // 'node' has no children. + Node parent = node.parent; + + if (parent == null) { + // 'node' is the root node of this tree. + root = null; + ++modCount; + return node; + } + + Node lo = node; + Node hi = parent; + + while (hi != null) { + if (hi.left == lo) { + hi.count--; + } + + lo = hi; + hi = hi.parent; + } + + if (node == parent.left) { + parent.left = null; + } else { + parent.right = null; + } + + return node; + } + + if (node.left != null && node.right != null) { + // 'node' has both children. + Node successor = minimumNode(node.right); + node.key = successor.key; + Node child = successor.right; + Node parent = successor.parent; + + if (parent.left == successor) { + parent.left = child; + } else { + parent.right = child; + } + + if (child != null) { + child.parent = parent; + } + + Node lo = child; + Node hi = parent; + + while (hi != null) { + if (hi.left == lo) { + hi.count--; + } + + lo = hi; + hi = hi.parent; + } + + return successor; + } + + Node child; + + // 'node' has only one child. + if (node.left != null) { + child = node.left; + } else { + child = node.right; + } + + Node parent = node.parent; + child.parent = parent; + + if (parent == null) { + root = child; + return node; + } + + if (node == parent.left) { + parent.left = child; + } else { + parent.right = child; + } + + Node hi = parent; + Node lo = child; + + while (hi != null) { + if (hi.left == lo) { + hi.count--; + } + + lo = hi; + hi = hi.parent; + } + + return node; + + } + + private Node minimumNode(Node node) { + while (node.left != null) { + node = node.left; + } + + return node; + } + + private int height(Node node) { + return node == null ? -1 : node.height; + } + + private Node leftRotate(Node node1) { + Node node2 = node1.right; + node2.parent = node1.parent; + node1.parent = node2; + node1.right = node2.left; + node2.left = node1; + + if (node1.right != null) { + node1.right.parent = node1; + } + + node1.height = Math.max(height(node1.left), height(node1.right)) + 1; + node2.height = Math.max(height(node2.left), height(node2.right)) + 1; + node2.count += node1.count + 1; + return node2; + } + + private Node rightRotate(Node node1) { + Node node2 = node1.left; + node2.parent = node1.parent; + node1.parent = node2; + node1.left = node2.right; + node2.right = node1; + + if (node1.left != null) { + node1.left.parent = node1; + } + + node1.height = Math.max(height(node1.left), height(node1.right)) + 1; + node2.height = Math.max(height(node2.left), height(node2.right)) + 1; + node1.count -= node2.count + 1; + return node2; + } + + private Node rightLeftRotate(Node node1) { + Node node2 = node1.right; + node1.right = rightRotate(node2); + return leftRotate(node1); + } + + private Node leftRightRotate(Node node1) { + Node node2 = node1.left; + node1.left = leftRotate(node2); + return rightRotate(node1); + } + + // Fixing an insertion: use insertionMode = true. + // Fixing a deletion: use insertionMode = false. + @SuppressWarnings("squid:S3776") + private void fixAfterModification(Node node, boolean insertionMode) { + Node parent = node.parent; + Node grandParent; + Node subTree; + + while (parent != null) { + if (height(parent.left) == height(parent.right) + 2) { + grandParent = parent.parent; + + if (height(parent.left.left) >= height(parent.left.right)) { + subTree = rightRotate(parent); + } else { + subTree = leftRightRotate(parent); + } + + if (grandParent == null) { + root = subTree; + } else if (grandParent.left == parent) { + grandParent.left = subTree; + } else { + grandParent.right = subTree; + } + + if (grandParent != null) { + grandParent.height = Math.max( + height(grandParent.left), + height(grandParent.right)) + 1; + } + + if (insertionMode) { + // Whenever fixing after insertion, at most one rotation is + // required in order to maintain the balance. + return; + } + } else if (height(parent.right) == height(parent.left) + 2) { + grandParent = parent.parent; + + if (height(parent.right.right) >= height(parent.right.left)) { + subTree = leftRotate(parent); + } else { + subTree = rightLeftRotate(parent); + } + + if (grandParent == null) { + root = subTree; + } else if (grandParent.left == parent) { + grandParent.left = subTree; + } else { + grandParent.right = subTree; + } + + if (grandParent != null) { + grandParent.height = + Math.max(height(grandParent.left), + height(grandParent.right)) + 1; + } + + if (insertionMode) { + return; + } + } + + parent.height = Math.max(height(parent.left), + height(parent.right)) + 1; + parent = parent.parent; + } + } + + boolean isHealthy() { + if (root == null) { + return true; + } + + return !containsCycles() + && heightsAreCorrect() + && isBalanced() + && isWellIndexed(); + } + + private boolean containsCycles() { + Set> visitedNodes = new HashSet<>(); + return containsCycles(root, visitedNodes); + } + + private boolean containsCycles(Node current, Set> visitedNodes) { + if (current == null) { + return false; + } + + if (visitedNodes.contains(current)) { + return true; + } + + visitedNodes.add(current); + + return containsCycles(current.left, visitedNodes) + || containsCycles(current.right, visitedNodes); + } + + private boolean heightsAreCorrect() { + return getHeight(root) == root.height; + } + + private int getHeight(Node node) { + if (node == null) { + return -1; + } + + int leftTreeHeight = getHeight(node.left); + + if (leftTreeHeight == Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } + + int rightTreeHeight = getHeight(node.right); + + if (rightTreeHeight == Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } + + if (node.height == Math.max(leftTreeHeight, rightTreeHeight) + 1) { + return node.height; + } + + return Integer.MIN_VALUE; + } + + private boolean isBalanced() { + return isBalanced(root); + } + + private boolean isBalanced(Node node) { + if (node == null) { + return true; + } + + if (!isBalanced(node.left)) { + return false; + } + + if (!isBalanced(node.right)) { + return false; + } + + int leftHeight = height(node.left); + int rightHeight = height(node.right); + + return Math.abs(leftHeight - rightHeight) < 2; + } + + private boolean isWellIndexed() { + return size == count(root); + } + + private int count(Node node) { + if (node == null) { + return 0; + } + + int leftTreeSize = count(node.left); + + if (leftTreeSize == Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } + + if (node.count != leftTreeSize) { + return Integer.MIN_VALUE; + } + + int rightTreeSize = count(node.right); + + if (rightTreeSize == Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } + + return leftTreeSize + 1 + rightTreeSize; + } +} diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/utils/OrderStatisticTreeTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/utils/OrderStatisticTreeTest.java new file mode 100644 index 00000000..cbb48603 --- /dev/null +++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/utils/OrderStatisticTreeTest.java @@ -0,0 +1,634 @@ +/* + * Copyright (c) 2021 Rodion Efremov + * Copyright (c) 2023 The Refinery Authors + * + * SPDX-License-Identifier: MIT OR EPL-2.0 + */ +package tools.refinery.store.query.utils; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.*; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Tests for an order statistic tree which is based on AVL-trees. + *

+ * This class was copied into Refinery from + * https://github.com/coderodde/OrderStatisticTree + * and is available under the + * MIT License. + * We also migrated the code to Junit 5, cleaned up some linter warnings, and made the tests deterministic by fixing + * the random seeds. + * + * @author Rodion "rodde" Efremov + * @version based on 1.6 (Feb 11, 2016) + */ +class OrderStatisticTreeTest { + private final OrderStatisticTree tree = new OrderStatisticTree<>(); + + private final TreeSet set = new TreeSet<>(); + + @BeforeEach + void before() { + tree.clear(); + set.clear(); + } + + @Test + void testAdd() { + assertEquals(set.isEmpty(), tree.isEmpty()); + + for (int i = 10; i < 30; i += 2) { + assertTrue(tree.isHealthy()); + assertEquals(set.contains(i), tree.contains(i)); + assertEquals(set.add(i), tree.add(i)); + assertEquals(set.add(i), tree.add(i)); + assertEquals(set.contains(i), tree.contains(i)); + assertTrue(tree.isHealthy()); + } + + assertEquals(set.isEmpty(), tree.isEmpty()); + } + + @Test + void testAddAll() { + for (int i = 0; i < 10; ++i) { + assertEquals(set.add(i), tree.add(i)); + } + + Collection coll = Arrays.asList(10, 9, 7, 11, 12); + + assertEquals(set.addAll(coll), tree.addAll(coll)); + assertEquals(set.size(), tree.size()); + + for (int i = -10; i < 20; ++i) { + assertEquals(set.contains(i), tree.contains(i)); + } + } + + @Test + void testClear() { + for (int i = 0; i < 2000; ++i) { + set.add(i); + tree.add(i); + } + + assertEquals(set.size(), tree.size()); + set.clear(); + tree.clear(); + // We expect {@code tree.size()} to always be 0, but we also test for it. + //noinspection ConstantValue + assertEquals(0, tree.size()); + } + + @Test + void testContains() { + for (int i = 100; i < 200; i += 3) { + assertTrue(tree.isHealthy()); + assertEquals(set.add(i), tree.add(i)); + assertTrue(tree.isHealthy()); + } + + assertEquals(set.size(), tree.size()); + + for (int i = 0; i < 300; ++i) { + assertEquals(set.contains(i), tree.contains(i)); + } + } + + @Test + void testContainsAll() { + for (int i = 0; i < 50; ++i) { + set.add(i); + tree.add(i); + } + + Collection coll = new HashSet<>(); + + for (int i = 10; i < 20; ++i) { + coll.add(i); + } + + assertEquals(set.containsAll(coll), tree.containsAll(coll)); + coll.add(100); + assertEquals(set.containsAll(coll), tree.containsAll(coll)); + } + + @Test + void testRemove() { + for (int i = 0; i < 200; ++i) { + assertEquals(set.add(i), tree.add(i)); + } + + for (int i = 50; i < 150; i += 2) { + assertEquals(set.remove(i), tree.remove(i)); + assertTrue(tree.isHealthy()); + } + + for (int i = -100; i < 300; ++i) { + assertEquals(set.contains(i), tree.contains(i)); + } + } + + @Test + void testRemoveLast() { + tree.add(1); + tree.remove(1); + assertEquals(0, tree.size()); + } + + @Test + void testRemoveAll() { + for (int i = 0; i < 40; ++i) { + set.add(i); + tree.add(i); + } + + Collection coll = new HashSet<>(); + + for (int i = 10; i < 20; ++i) { + coll.add(i); + } + + assertEquals(set.removeAll(coll), tree.removeAll(coll)); + + for (int i = -10; i < 50; ++i) { + assertEquals(set.contains(i), tree.contains(i)); + } + + assertEquals(set.removeAll(coll), tree.removeAll(coll)); + + for (int i = -10; i < 50; ++i) { + assertEquals(set.contains(i), tree.contains(i)); + } + } + + @Test + void testSize() { + for (int i = 0; i < 200; ++i) { + assertEquals(set.size(), tree.size()); + assertEquals(set.add(i), tree.add(i)); + assertEquals(set.size(), tree.size()); + } + } + + @Test + void testIndexOf() { + for (int i = 0; i < 100; ++i) { + assertTrue(tree.add(i * 2)); + } + + for (int i = 0; i < 100; ++i) { + assertEquals(i, tree.indexOf(2 * i)); + } + + for (int i = 100; i < 150; ++i) { + assertEquals(-1, tree.indexOf(2 * i)); + } + } + + @Test + void testEmpty() { + assertEquals(set.isEmpty(), tree.isEmpty()); + set.add(0); + tree.add(0); + assertEquals(set.isEmpty(), tree.isEmpty()); + } + + @Test + void testEmptyTreeGetThrowsOnNegativeIndex() { + assertThrows(IndexOutOfBoundsException.class, () -> tree.get(-1)); + } + + @Test + void testEmptyTreeSelectThrowsOnTooLargeIndex() { + assertThrows(IndexOutOfBoundsException.class, () -> tree.get(0)); + } + + @Test + void testSelectThrowsOnNegativeIndex() { + for (int i = 0; i < 5; ++i) { + tree.add(i); + } + + assertThrows(IndexOutOfBoundsException.class, () -> tree.get(-1)); + } + + @Test + void testSelectThrowsOnTooLargeIndex() { + for (int i = 0; i < 5; ++i) { + tree.add(i); + } + + assertThrows(IndexOutOfBoundsException.class, () -> tree.get(5)); + } + + @Test + void testGet() { + for (int i = 0; i < 100; i += 3) { + tree.add(i); + } + + for (int i = 0; i < tree.size(); ++i) { + assertEquals(Integer.valueOf(3 * i), tree.get(i)); + } + } + + @Test + void findBug() { + tree.add(0); + assertTrue(tree.isHealthy()); + + tree.add(-1); + tree.remove(-1); + assertTrue(tree.isHealthy()); + + tree.add(1); + tree.remove(1); + assertTrue(tree.isHealthy()); + + tree.add(-1); + tree.add(1); + tree.remove(0); + assertTrue(tree.isHealthy()); + + tree.clear(); + tree.add(0); + tree.add(-1); + tree.add(10); + tree.add(5); + tree.add(15); + tree.add(11); + tree.add(30); + tree.add(7); + + tree.remove(-1); + + assertTrue(tree.isHealthy()); + } + + @ParameterizedTest(name = "seed = {0}") + @MethodSource("seedSource") + void tryReproduceTheCounterBug(long seed) { + Random random = new Random(seed); + List list = new ArrayList<>(); + + for (int i = 0; i < 10; ++i) { + int number = random.nextInt(1000); + list.add(number); + tree.add(number); + assertTrue(tree.isHealthy()); + } + + for (Integer i : list) { + tree.remove(i); + boolean healthy = tree.isHealthy(); + assertTrue(healthy); + } + } + + @Test + void testEmptyIterator() { + var iterator = tree.iterator(); + assertThrows(NoSuchElementException.class, iterator::next); + } + + @Test + void testIteratorThrowsOnDoubleRemove() { + for (int i = 10; i < 20; ++i) { + set.add(i); + tree.add(i); + } + + Iterator iterator1 = set.iterator(); + Iterator iterator2 = tree.iterator(); + + for (int i = 0; i < 3; ++i) { + assertEquals(iterator1.next(), iterator2.next()); + } + + iterator1.remove(); + iterator2.remove(); + + assertThrows(IllegalStateException.class, iterator1::remove); + assertThrows(IllegalStateException.class, iterator2::remove); + } + + @Test + void testIterator() { + for (int i = 0; i < 5; ++i) { + tree.add(i); + set.add(i); + } + + Iterator iterator1 = set.iterator(); + Iterator iterator2 = tree.iterator(); + + for (int i = 0; i < 5; ++i) { + assertEquals(iterator1.hasNext(), iterator2.hasNext()); + assertEquals(iterator1.next(), iterator2.next()); + } + + assertEquals(iterator1.hasNext(), iterator2.hasNext()); + + assertThrows(NoSuchElementException.class, iterator1::next); + assertThrows(NoSuchElementException.class, iterator2::next); + } + + @Test + void testRemoveBeforeNextThrowsEmpty() { + var setIterator = set.iterator(); + assertThrows(IllegalStateException.class, setIterator::remove); + + var treeIterator = tree.iterator(); + assertThrows(IllegalStateException.class, treeIterator::remove); + } + + @Test + void testRemoveThrowsWithoutNext() { + for (int i = 0; i < 10; ++i) { + tree.add(i); + set.add(i); + } + + Iterator iterator1 = set.iterator(); + Iterator iterator2 = tree.iterator(); + + for (int i = 0; i < 4; ++i) { + assertEquals(iterator1.hasNext(), iterator2.hasNext()); + assertEquals(iterator1.next(), iterator2.next()); + } + + iterator1.remove(); + iterator2.remove(); + + assertThrows(IllegalStateException.class, iterator1::remove); + assertThrows(IllegalStateException.class, iterator2::remove); + } + + @Test + void testRetainAll() { + for (int i = 0; i < 100; ++i) { + set.add(i); + tree.add(i); + } + + Collection coll = Arrays.asList(26, 29, 25); + + assertEquals(set.retainAll(coll), tree.retainAll(coll)); + assertEquals(set.size(), tree.size()); + + assertTrue(set.containsAll(tree)); + assertTrue(tree.containsAll(set)); + } + + @Test + void testIteratorRemove() { + for (int i = 10; i < 16; ++i) { + assertEquals(set.add(i), tree.add(i)); + } + + Iterator iterator1 = set.iterator(); + Iterator iterator2 = tree.iterator(); + + assertEquals(iterator1.hasNext(), iterator2.hasNext()); + assertEquals(iterator1.next(), iterator2.next()); + + assertEquals(iterator1.hasNext(), iterator2.hasNext()); + assertEquals(iterator1.next(), iterator2.next()); + + iterator1.remove(); // remove 11 + iterator2.remove(); + + assertEquals(iterator1.hasNext(), iterator2.hasNext()); + assertEquals(iterator1.next(), iterator2.next()); + + assertEquals(iterator1.hasNext(), iterator2.hasNext()); + assertEquals(iterator1.next(), iterator2.next()); + + iterator1.remove(); // remove 13 + iterator2.remove(); + + assertEquals(set.size(), tree.size()); + + for (int i = 10; i < 16; ++i) { + assertEquals(set.contains(i), tree.contains(i)); + } + } + + @ParameterizedTest(name = "seed = {0}") + @MethodSource("seedSource") + void testIteratorBruteForce(long seed) { + for (int i = 0; i < 1000; ++i) { + assertEquals(set.add(i), tree.add(i)); + } + + Iterator iterator1 = set.iterator(); + Iterator iterator2 = tree.iterator(); + + Random random = new Random(seed); + + while (true) { + if (!iterator1.hasNext()) { + assertFalse(iterator2.hasNext()); + break; + } + + boolean toRemove = random.nextBoolean(); + + if (toRemove) { + boolean thrown = false; + + try { + iterator1.remove(); + } catch (IllegalStateException ex) { + thrown = true; + } + + if (thrown) { + assertThrows(IllegalStateException.class, iterator2::remove); + } else { + iterator2.remove(); + } + } else { + assertEquals(iterator1.hasNext(), iterator2.hasNext()); + + if (iterator1.hasNext()) { + assertEquals(iterator1.next(), iterator2.next()); + } else { + break; + } + } + } + + assertEquals(set.size(), tree.size()); + assertTrue(tree.isHealthy()); + assertTrue(set.containsAll(tree)); + assertTrue(tree.containsAll(set)); + } + + @Test + void testIteratorConcurrentModification() { + for (int i = 0; i < 100; ++i) { + set.add(i); + tree.add(i); + } + + Iterator iterator1 = set.iterator(); + Iterator iterator2 = tree.iterator(); + + set.remove(10); + tree.remove(10); + + assertEquals(iterator1.hasNext(), iterator2.hasNext()); + + boolean thrown = false; + + try { + iterator1.next(); + } catch (ConcurrentModificationException ex) { + thrown = true; + } + + if (thrown) { + assertThrows(ConcurrentModificationException.class, iterator2::next); + } else { + iterator2.next(); + } + } + + @Test + void testIteratorConcurrentRemove() { + for (int i = 10; i < 20; ++i) { + set.add(i); + tree.add(i); + } + + Iterator iterator1 = set.iterator(); + Iterator iterator2 = tree.iterator(); + + for (int i = 0; i < 4; ++i) { + iterator1.next(); + iterator2.next(); + } + + // None of them contains 2, should not change the modification count. + set.remove(2); + tree.remove(2); + + iterator1.remove(); + iterator2.remove(); + + iterator1.next(); + iterator2.next(); + + set.remove(12); + tree.remove(12); + + // Both of them should throw. + assertThrows(ConcurrentModificationException.class, iterator1::remove); + assertThrows(ConcurrentModificationException.class, iterator2::remove); + } + + @Test + void testConcurrentOrIllegalStateOnRemove() { + for (int i = 0; i < 10; ++i) { + set.add(i); + tree.add(i); + } + + Iterator iterator1 = set.iterator(); + Iterator iterator2 = tree.iterator(); + + set.add(100); + tree.add(100); + + assertThrows(IllegalStateException.class, iterator1::remove); + assertThrows(IllegalStateException.class, iterator2::remove); + } + + @Test + void testConcurrentIterators() { + for (int i = 0; i < 10; ++i) { + set.add(i); + tree.add(i); + } + + Iterator iterator1a = set.iterator(); + Iterator iterator1b = set.iterator(); + Iterator iterator2a = tree.iterator(); + Iterator iterator2b = tree.iterator(); + + for (int i = 0; i < 3; ++i) { + iterator1a.next(); + iterator2a.next(); + } + + iterator1a.remove(); + iterator2a.remove(); + + assertEquals(iterator1b.hasNext(), iterator2b.hasNext()); + + assertThrows(ConcurrentModificationException.class, iterator1b::next); + assertThrows(ConcurrentModificationException.class, iterator2b::next); + } + + @ParameterizedTest(name = "seed = {0}") + @MethodSource("seedSource") + void testToArray(long seed) { + Random r = new Random(seed); + + for (int i = 0; i < 50; ++i) { + int num = r.nextInt(); + set.add(num); + tree.add(num); + } + + assertArrayEquals(set.toArray(), tree.toArray()); + } + + @Test + void testToArrayGeneric() { + for (int i = 0; i < 100; ++i) { + set.add(i); + tree.add(i); + } + + Integer[] array1before = new Integer[99]; + Integer[] array2before = new Integer[99]; + + Integer[] array1after = set.toArray(array1before); + Integer[] array2after = tree.toArray(array2before); + + assertNotSame(array1before, array1after); + assertNotSame(array2before, array2after); + assertArrayEquals(array1after, array2after); + + set.remove(1); + tree.remove(1); + + array1after = set.toArray(array1before); + array2after = tree.toArray(array2before); + + assertSame(array1before, array1after); + assertSame(array2before, array2after); + assertArrayEquals(array1after, array2after); + } + + static Stream seedSource() { + return Stream.of( + Arguments.of(0L), + Arguments.of(1L), + Arguments.of(2L), + Arguments.of(3L), + Arguments.of(4L) + ); + } +} diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java index 8f319242..6d5d6f89 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java @@ -6,7 +6,7 @@ package tools.refinery.store.reasoning; import tools.refinery.store.adapter.ModelAdapter; -import tools.refinery.store.query.ResultSet; +import tools.refinery.store.query.resultset.ResultSet; import tools.refinery.store.query.dnf.Dnf; import tools.refinery.store.reasoning.representation.AnyPartialSymbol; import tools.refinery.store.reasoning.representation.PartialRelation; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java index 33b6f3c6..1bd3ad2e 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java @@ -10,7 +10,7 @@ import tools.refinery.store.reasoning.ReasoningAdapter; import tools.refinery.store.reasoning.PartialInterpretation; import tools.refinery.store.reasoning.representation.PartialSymbol; import tools.refinery.store.query.dnf.Dnf; -import tools.refinery.store.query.ResultSet; +import tools.refinery.store.query.resultset.ResultSet; public class ReasoningAdapterImpl implements ReasoningAdapter { private final Model model; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java index 5ad1d5f8..4e5a6099 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java @@ -7,7 +7,7 @@ package tools.refinery.store.reasoning.literal; import tools.refinery.store.query.Constraint; import tools.refinery.store.query.equality.LiteralEqualityHelper; -import tools.refinery.store.query.Reduction; +import tools.refinery.store.query.literal.Reduction; import tools.refinery.store.query.term.Parameter; import java.util.List; diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionInterpretation.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionInterpretation.java index e7b67ae4..2a151aa2 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionInterpretation.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionInterpretation.java @@ -7,7 +7,7 @@ package tools.refinery.store.reasoning.translator.base; import tools.refinery.store.map.Cursor; import tools.refinery.store.model.Interpretation; -import tools.refinery.store.query.ResultSet; +import tools.refinery.store.query.resultset.ResultSet; import tools.refinery.store.reasoning.MergeResult; import tools.refinery.store.reasoning.PartialInterpretation; import tools.refinery.store.reasoning.ReasoningAdapter; diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java index 6700417a..aae7b344 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java @@ -5,11 +5,29 @@ */ package tools.refinery.store.tuple; -public sealed interface Tuple permits Tuple0, Tuple1, Tuple2, Tuple3, Tuple4, TupleN { +import org.jetbrains.annotations.NotNull; + +public sealed interface Tuple extends Comparable permits Tuple0, Tuple1, Tuple2, Tuple3, Tuple4, TupleN { int getSize(); int get(int element); + @Override + default int compareTo(@NotNull Tuple other) { + int size = getSize(); + int compareSize = Integer.compare(size, other.getSize()); + if (compareSize != 0) { + return compareSize; + } + for (int i = 0; i < size; i++) { + int compareElement = Integer.compare(get(i), other.get(i)); + if (compareElement != 0) { + return compareElement; + } + } + return 0; + } + static Tuple0 of() { return Tuple0.INSTANCE; } diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java index 1451099c..a9aa9bf2 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java @@ -8,6 +8,10 @@ package tools.refinery.store.tuple; import static tools.refinery.store.tuple.TupleConstants.TUPLE_BEGIN; import static tools.refinery.store.tuple.TupleConstants.TUPLE_END; +/** + * Singleton implementation to ensure only a single empty tuple exists. + */ +@SuppressWarnings("squid:S6548") public final class Tuple0 implements Tuple { public static final Tuple0 INSTANCE = new Tuple0(); diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java index cda145d7..388ee3a9 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java @@ -5,6 +5,7 @@ */ package tools.refinery.store.tuple; +import org.jetbrains.annotations.NotNull; import tools.refinery.store.model.TupleHashProvider; import java.util.Arrays; @@ -54,11 +55,23 @@ public final class Tuple1 implements Tuple { return 31 + value0; } + @Override + public int compareTo(@NotNull Tuple other) { + if (other instanceof Tuple1 other1) { + return Integer.compare(value0, other1.value0); + } + return Tuple.super.compareTo(other); + } + /** * This class uses safe double-checked locking, see * Safe Publication and Safe Initialization in * Java for details. + *

+ * This class implements the singleton pattern to ensure only a single cache exists. This is thread-safe because + * of the locking of the cache. */ + @SuppressWarnings("squid:S6548") public static class Cache { private static final int MIN_CACHE_SIZE = 256; diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java index b669674b..6d886fd3 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java @@ -5,6 +5,8 @@ */ package tools.refinery.store.tuple; +import org.jetbrains.annotations.NotNull; + import static tools.refinery.store.tuple.TupleConstants.*; public record Tuple2(int value0, int value1) implements Tuple { @@ -41,4 +43,16 @@ public record Tuple2(int value0, int value1) implements Tuple { hash = 31 * hash + value1; return hash; } + + @Override + public int compareTo(@NotNull Tuple other) { + if (other instanceof Tuple2 other2) { + int compare0 = Integer.compare(value0, other2.value0); + if (compare0 != 0) { + return compare0; + } + return Integer.compare(value1, other2.value1); + } + return Tuple.super.compareTo(other); + } } diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java index 542ed328..734e45c2 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java @@ -5,6 +5,8 @@ */ package tools.refinery.store.tuple; +import org.jetbrains.annotations.NotNull; + import static tools.refinery.store.tuple.TupleConstants.*; public record Tuple3(int value0, int value1, int value2) implements Tuple { @@ -43,4 +45,20 @@ public record Tuple3(int value0, int value1, int value2) implements Tuple { hash = 31 * hash + value2; return hash; } + + @Override + public int compareTo(@NotNull Tuple other) { + if (other instanceof Tuple3 other3) { + int compare0 = Integer.compare(value0, other3.value0); + if (compare0 != 0) { + return compare0; + } + int compare1 = Integer.compare(value1, other3.value1); + if (compare1 != 0) { + return compare1; + } + return Integer.compare(value2, other3.value2); + } + return Tuple.super.compareTo(other); + } } diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java index 121a15f6..e1b93e7b 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java @@ -5,6 +5,8 @@ */ package tools.refinery.store.tuple; +import org.jetbrains.annotations.NotNull; + import static tools.refinery.store.tuple.TupleConstants.*; public record Tuple4(int value0, int value1, int value2, int value3) implements Tuple { @@ -46,4 +48,24 @@ public record Tuple4(int value0, int value1, int value2, int value3) implements hash = 31 * hash + value3; return hash; } + + @Override + public int compareTo(@NotNull Tuple other) { + if (other instanceof Tuple4 other4) { + int compare0 = Integer.compare(value0, other4.value0); + if (compare0 != 0) { + return compare0; + } + int compare1 = Integer.compare(value1, other4.value1); + if (compare1 != 0) { + return compare1; + } + int compare2 = Integer.compare(value2, other4.value2); + if (compare2 != 0) { + return compare2; + } + return Integer.compare(value3, other4.value3); + } + return Tuple.super.compareTo(other); + } } -- cgit v1.2.3-70-g09d2