aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-query/src/main/java/tools
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/store-query/src/main/java/tools')
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java12
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java6
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfPostProcessor.java4
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java18
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java9
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/LeftJoinLiteral.java140
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionView.java16
7 files changed, 195 insertions, 10 deletions
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 916fb35c..375c582a 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,5 +1,5 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> 2 * SPDX-FileCopyrightText: 2021-2024 The Refinery Authors <https://refinery.tools/>
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
@@ -69,4 +69,14 @@ public interface Constraint {
69 Variable... arguments) { 69 Variable... arguments) {
70 return aggregateBy(inputVariable, aggregator, List.of(arguments)); 70 return aggregateBy(inputVariable, aggregator, List.of(arguments));
71 } 71 }
72
73 default <T> AssignedValue<T> leftJoinBy(DataVariable<T> placeholderVariable, T defaultValue,
74 List<Variable> arguments) {
75 return targetVariable -> new LeftJoinLiteral<>(targetVariable, placeholderVariable, defaultValue, this,
76 arguments);
77 }
78
79 default <T> AssignedValue<T> leftJoinBy(DataVariable<T> inputVariable, T defaultValue, Variable... arguments) {
80 return leftJoinBy(inputVariable, defaultValue, List.of(arguments));
81 }
72} 82}
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 8800a155..7cd05364 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
@@ -1,5 +1,5 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> 2 * SPDX-FileCopyrightText: 2021-2024 The Refinery Authors <https://refinery.tools/>
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
@@ -112,7 +112,7 @@ class ClausePostProcessor {
112 .formatted(variable, representative)); 112 .formatted(variable, representative));
113 } 113 }
114 return equivalencePartition.computeIfAbsent(variable, key -> { 114 return equivalencePartition.computeIfAbsent(variable, key -> {
115 var set = new HashSet<Variable>(1); 115 var set = HashSet.<Variable>newHashSet(1);
116 set.add(key); 116 set.add(key);
117 return set; 117 return set;
118 }); 118 });
@@ -193,7 +193,7 @@ class ClausePostProcessor {
193 } 193 }
194 194
195 private void topologicallySortLiterals() { 195 private void topologicallySortLiterals() {
196 topologicallySortedLiterals = new LinkedHashSet<>(substitutedLiterals.size()); 196 topologicallySortedLiterals = LinkedHashSet.newLinkedHashSet(substitutedLiterals.size());
197 variableToLiteralInputMap = new HashMap<>(); 197 variableToLiteralInputMap = new HashMap<>();
198 literalsWithAllInputsBound = new PriorityQueue<>(); 198 literalsWithAllInputsBound = new PriorityQueue<>();
199 int size = substitutedLiterals.size(); 199 int size = substitutedLiterals.size();
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfPostProcessor.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfPostProcessor.java
index 50236642..01344b59 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfPostProcessor.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfPostProcessor.java
@@ -1,5 +1,5 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> 2 * SPDX-FileCopyrightText: 2023-2024 The Refinery Authors <https://refinery.tools/>
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
@@ -26,7 +26,7 @@ class DnfPostProcessor {
26 26
27 public List<DnfClause> postProcessClauses() { 27 public List<DnfClause> postProcessClauses() {
28 var parameterInfoMap = getParameterInfoMap(); 28 var parameterInfoMap = getParameterInfoMap();
29 var postProcessedClauses = new LinkedHashSet<CanonicalClause>(clauses.size()); 29 var postProcessedClauses = LinkedHashSet.<CanonicalClause>newLinkedHashSet(clauses.size());
30 int index = 0; 30 int index = 0;
31 for (var literals : clauses) { 31 for (var literals : clauses) {
32 var postProcessor = new ClausePostProcessor(parameterInfoMap, literals); 32 var postProcessor = new ClausePostProcessor(parameterInfoMap, literals);
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 225f6844..b0a03c7d 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,5 +1,5 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> 2 * SPDX-FileCopyrightText: 2021-2024 The Refinery Authors <https://refinery.tools/>
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
@@ -94,6 +94,22 @@ public final class FunctionalQuery<T> extends Query<T> {
94 return aggregate(aggregator, List.of(arguments)); 94 return aggregate(aggregator, List.of(arguments));
95 } 95 }
96 96
97 public AssignedValue<T> leftJoin(T defaultValue, List<NodeVariable> arguments) {
98 return targetVariable -> {
99 var placeholderVariable = Variable.of(type);
100 var argumentsWithPlaceholder = new ArrayList<Variable>(arguments.size() + 1);
101 argumentsWithPlaceholder.addAll(arguments);
102 argumentsWithPlaceholder.add(placeholderVariable);
103 return getDnf()
104 .leftJoinBy(placeholderVariable, defaultValue, argumentsWithPlaceholder)
105 .toLiteral(targetVariable);
106 };
107 }
108
109 public AssignedValue<T> leftJoin(T defaultValue, NodeVariable... arguments) {
110 return leftJoin(defaultValue, List.of(arguments));
111 }
112
97 @Override 113 @Override
98 public boolean equals(Object o) { 114 public boolean equals(Object o) {
99 if (this == o) return true; 115 if (this == o) return true;
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 e3acfacc..b6861de0 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,5 +1,5 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> 2 * SPDX-FileCopyrightText: 2021-2024 The Refinery Authors <https://refinery.tools/>
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
@@ -129,7 +129,12 @@ public class AggregationLiteral<R, T> extends AbstractCallLiteral {
129 } 129 }
130 builder.append(argument); 130 builder.append(argument);
131 while (argumentIterator.hasNext()) { 131 while (argumentIterator.hasNext()) {
132 builder.append(", ").append(argumentIterator.next()); 132 builder.append(", ");
133 argument = argumentIterator.next();
134 if (inputVariable.equals(argument)) {
135 builder.append("@Aggregate(\"").append(aggregator).append("\") ");
136 }
137 builder.append(argument);
133 } 138 }
134 } 139 }
135 builder.append(")"); 140 builder.append(")");
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/LeftJoinLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/LeftJoinLiteral.java
new file mode 100644
index 00000000..bdddf120
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/LeftJoinLiteral.java
@@ -0,0 +1,140 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import tools.refinery.store.query.Constraint;
9import tools.refinery.store.query.InvalidQueryException;
10import tools.refinery.store.query.equality.LiteralEqualityHelper;
11import tools.refinery.store.query.equality.LiteralHashCodeHelper;
12import tools.refinery.store.query.substitution.Substitution;
13import tools.refinery.store.query.term.ConstantTerm;
14import tools.refinery.store.query.term.DataVariable;
15import tools.refinery.store.query.term.ParameterDirection;
16import tools.refinery.store.query.term.Variable;
17
18import java.util.*;
19
20// {@link Object#equals(Object)} is implemented by {@link AbstractLiteral}.
21@SuppressWarnings("squid:S2160")
22public class LeftJoinLiteral<T> extends AbstractCallLiteral {
23 private final DataVariable<T> resultVariable;
24 private final DataVariable<T> placeholderVariable;
25 private final T defaultValue;
26
27 public LeftJoinLiteral(DataVariable<T> resultVariable, DataVariable<T> placeholderVariable,
28 T defaultValue, Constraint target, List<Variable> arguments) {
29 super(target, arguments);
30 this.resultVariable = resultVariable;
31 this.placeholderVariable = placeholderVariable;
32 this.defaultValue = defaultValue;
33 if (defaultValue == null) {
34 throw new InvalidQueryException("Default value must not be null");
35 }
36 if (!resultVariable.getType().isInstance(defaultValue)) {
37 throw new InvalidQueryException("Default value %s must be assignable to result variable %s type %s"
38 .formatted(defaultValue, resultVariable, resultVariable.getType().getName()));
39 }
40 if (!getArgumentsOfDirection(ParameterDirection.OUT).contains(placeholderVariable)) {
41 throw new InvalidQueryException(
42 "Placeholder variable %s must be bound with direction %s in the argument list"
43 .formatted(resultVariable, ParameterDirection.OUT));
44 }
45 if (arguments.contains(resultVariable)) {
46 throw new InvalidQueryException("Result variable must not appear in the argument list");
47 }
48 }
49
50 public DataVariable<T> getResultVariable() {
51 return resultVariable;
52 }
53
54 public DataVariable<T> getPlaceholderVariable() {
55 return placeholderVariable;
56 }
57
58 public T getDefaultValue() {
59 return defaultValue;
60 }
61
62 @Override
63 public Set<Variable> getOutputVariables() {
64 return Set.of(resultVariable);
65 }
66
67 @Override
68 public Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause) {
69 var inputVariables = new LinkedHashSet<>(getArguments());
70 inputVariables.remove(placeholderVariable);
71 return Collections.unmodifiableSet(inputVariables);
72 }
73
74 @Override
75 public Set<Variable> getPrivateVariables(Set<? extends Variable> positiveVariablesInClause) {
76 return Set.of(placeholderVariable);
77 }
78
79 @Override
80 public Literal reduce() {
81 var reduction = getTarget().getReduction();
82 return switch (reduction) {
83 case ALWAYS_FALSE -> resultVariable.assign(new ConstantTerm<>(resultVariable.getType(), defaultValue));
84 case ALWAYS_TRUE -> throw new InvalidQueryException("Trying to left join an infinite set");
85 case NOT_REDUCIBLE -> this;
86 };
87 }
88
89 @Override
90 protected Literal doSubstitute(Substitution substitution, List<Variable> substitutedArguments) {
91 return new LeftJoinLiteral<>(substitution.getTypeSafeSubstitute(resultVariable),
92 substitution.getTypeSafeSubstitute(placeholderVariable), defaultValue, getTarget(),
93 substitutedArguments);
94 }
95
96 @Override
97 public AbstractCallLiteral withArguments(Constraint newTarget, List<Variable> newArguments) {
98 return new LeftJoinLiteral<>(resultVariable, placeholderVariable, defaultValue, newTarget, newArguments);
99 }
100
101 @Override
102 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) {
103 if (!super.equalsWithSubstitution(helper, other)) {
104 return false;
105 }
106 var otherLeftJoinLiteral = (LeftJoinLiteral<?>) other;
107 return helper.variableEqual(resultVariable, otherLeftJoinLiteral.resultVariable) &&
108 helper.variableEqual(placeholderVariable, otherLeftJoinLiteral.placeholderVariable) &&
109 Objects.equals(defaultValue, otherLeftJoinLiteral.defaultValue);
110 }
111
112 @Override
113 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
114 return Objects.hash(super.hashCodeWithSubstitution(helper), helper.getVariableHashCode(resultVariable),
115 helper.getVariableHashCode(placeholderVariable), defaultValue);
116 }
117
118 @Override
119 public String toString() {
120 var builder = new StringBuilder();
121 var argumentIterator = getArguments().iterator();
122 if (argumentIterator.hasNext()) {
123 appendArgument(builder, argumentIterator.next());
124 while (argumentIterator.hasNext()) {
125 builder.append(", ");
126 appendArgument(builder, argumentIterator.next());
127 }
128 }
129 builder.append(")");
130 return builder.toString();
131 }
132
133 private void appendArgument(StringBuilder builder, Variable argument) {
134 if (placeholderVariable.equals(argument)) {
135 builder.append("@Default(").append(defaultValue).append(") ");
136 argument = resultVariable;
137 }
138 builder.append(argument);
139 }
140}
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 74a5be07..3dfb6777 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
@@ -1,5 +1,5 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> 2 * SPDX-FileCopyrightText: 2021-2024 The Refinery Authors <https://refinery.tools/>
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
@@ -33,4 +33,18 @@ public final class FunctionView<T> extends AbstractFunctionView<T> {
33 public <R> AssignedValue<R> aggregate(Aggregator<R, T> aggregator, NodeVariable... arguments) { 33 public <R> AssignedValue<R> aggregate(Aggregator<R, T> aggregator, NodeVariable... arguments) {
34 return aggregate(aggregator, List.of(arguments)); 34 return aggregate(aggregator, List.of(arguments));
35 } 35 }
36
37 public AssignedValue<T> leftJoin(T defaultValue, List<NodeVariable> arguments) {
38 return targetVariable -> {
39 var placeholderVariable = Variable.of(getSymbol().valueType());
40 var argumentsWithPlaceholder = new ArrayList<Variable>(arguments.size() + 1);
41 argumentsWithPlaceholder.addAll(arguments);
42 argumentsWithPlaceholder.add(placeholderVariable);
43 return leftJoinBy(placeholderVariable, defaultValue, argumentsWithPlaceholder).toLiteral(targetVariable);
44 };
45 }
46
47 public AssignedValue<T> leftJoin(T defaultValue, NodeVariable... arguments) {
48 return leftJoin(defaultValue, List.of(arguments));
49 }
36} 50}