diff options
author | Kristóf Marussy <kristof@marussy.com> | 2024-05-20 17:29:07 +0200 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2024-05-26 17:22:33 +0200 |
commit | 42214746edac8bdc992a52ca8624f996871e2842 (patch) | |
tree | 2e8cf18ab0a9b12fcba96b2eb7511cd84131cb57 | |
parent | feat(dse): detect stuch propagation rules (diff) | |
download | refinery-42214746edac8bdc992a52ca8624f996871e2842.tar.gz refinery-42214746edac8bdc992a52ca8624f996871e2842.tar.zst refinery-42214746edac8bdc992a52ca8624f996871e2842.zip |
feat(language): node constants in rule actions
7 files changed, 89 insertions, 16 deletions
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 06f0e758..58d6748a 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 | |||
@@ -125,7 +125,7 @@ public class ProblemSemanticHighlightingCalculator extends DefaultSemanticHighli | |||
125 | classesBuilder.add(ERROR_CLASS); | 125 | classesBuilder.add(ERROR_CLASS); |
126 | } | 126 | } |
127 | if (eObject instanceof Node node) { | 127 | if (eObject instanceof Node node) { |
128 | highlightNode(node, reference, classesBuilder); | 128 | highlightNode(node, classesBuilder); |
129 | } | 129 | } |
130 | if (eObject instanceof Relation relation) { | 130 | if (eObject instanceof Relation relation) { |
131 | var typeHash = typeHashProvider.getTypeHash(relation); | 131 | var typeHash = typeHashProvider.getTypeHash(relation); |
@@ -137,10 +137,8 @@ public class ProblemSemanticHighlightingCalculator extends DefaultSemanticHighli | |||
137 | return classes.toArray(new String[0]); | 137 | return classes.toArray(new String[0]); |
138 | } | 138 | } |
139 | 139 | ||
140 | private static void highlightNode(Node node, EReference reference, ImmutableList.Builder<String> classesBuilder) { | 140 | private static void highlightNode(Node node, ImmutableList.Builder<String> classesBuilder) { |
141 | if (reference == ProblemPackage.Literals.VARIABLE_OR_NODE_EXPR__VARIABLE_OR_NODE) { | 141 | classesBuilder.add(NODE_CLASS); |
142 | classesBuilder.add(NODE_CLASS); | ||
143 | } | ||
144 | if (ProblemUtil.isAtomNode(node)) { | 142 | if (ProblemUtil.isAtomNode(node)) { |
145 | classesBuilder.add(ATOM_NODE_CLASS); | 143 | classesBuilder.add(ATOM_NODE_CLASS); |
146 | } | 144 | } |
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ModelInitializer.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ModelInitializer.java index a86e2c47..02b2f920 100644 --- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ModelInitializer.java +++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ModelInitializer.java | |||
@@ -31,6 +31,7 @@ import tools.refinery.store.dse.transition.DesignSpaceExplorationBuilder; | |||
31 | import tools.refinery.store.dse.transition.Rule; | 31 | import tools.refinery.store.dse.transition.Rule; |
32 | import tools.refinery.store.dse.transition.RuleBuilder; | 32 | import tools.refinery.store.dse.transition.RuleBuilder; |
33 | import tools.refinery.store.dse.transition.actions.ActionLiteral; | 33 | import tools.refinery.store.dse.transition.actions.ActionLiteral; |
34 | import tools.refinery.store.dse.transition.actions.ActionLiterals; | ||
34 | import tools.refinery.store.model.ModelStoreBuilder; | 35 | import tools.refinery.store.model.ModelStoreBuilder; |
35 | import tools.refinery.store.reasoning.ReasoningAdapter; | 36 | import tools.refinery.store.reasoning.ReasoningAdapter; |
36 | import tools.refinery.store.reasoning.actions.PartialActionLiterals; | 37 | import tools.refinery.store.reasoning.actions.PartialActionLiterals; |
@@ -968,7 +969,7 @@ public class ModelInitializer { | |||
968 | } | 969 | } |
969 | } | 970 | } |
970 | for (var action : body.getActions()) { | 971 | for (var action : body.getActions()) { |
971 | actionLiterals.add(toActionLiteral(action, localScope)); | 972 | toActionLiterals(action, localScope, actionLiterals); |
972 | } | 973 | } |
973 | builder.action(actionLiterals); | 974 | builder.action(actionLiterals); |
974 | } catch (RuntimeException e) { | 975 | } catch (RuntimeException e) { |
@@ -976,8 +977,9 @@ public class ModelInitializer { | |||
976 | } | 977 | } |
977 | } | 978 | } |
978 | 979 | ||
979 | private ActionLiteral toActionLiteral( | 980 | private void toActionLiterals( |
980 | Action action, HashMap<tools.refinery.language.model.problem.Variable, NodeVariable> localScope) { | 981 | Action action, HashMap<tools.refinery.language.model.problem.Variable, NodeVariable> localScope, |
982 | List<ActionLiteral> actionLiterals) { | ||
981 | if (!(action instanceof AssertionAction assertionAction)) { | 983 | if (!(action instanceof AssertionAction assertionAction)) { |
982 | throw new TracedException(action, "Unknown action"); | 984 | throw new TracedException(action, "Unknown action"); |
983 | } | 985 | } |
@@ -991,11 +993,18 @@ public class ModelInitializer { | |||
991 | throw new TracedException(problemArgument, "Invalid argument"); | 993 | throw new TracedException(problemArgument, "Invalid argument"); |
992 | } | 994 | } |
993 | var variableOrNode = nodeAssertionArgument.getNode(); | 995 | var variableOrNode = nodeAssertionArgument.getNode(); |
994 | if (!(variableOrNode instanceof tools.refinery.language.model.problem.Variable problemVariable)) { | 996 | switch (variableOrNode) { |
995 | throw new TracedException(problemArgument, "Invalid argument"); | 997 | case tools.refinery.language.model.problem.Variable problemVariable -> |
998 | arguments[i] = localScope.get(problemVariable); | ||
999 | case Node node -> { | ||
1000 | int nodeId = getNodeId(node); | ||
1001 | var tempVariable = Variable.of(semanticsUtils.getNameWithoutRootPrefix(node).orElse("_" + nodeId)); | ||
1002 | actionLiterals.add(ActionLiterals.constant(tempVariable, nodeId)); | ||
1003 | arguments[i] = tempVariable; | ||
1004 | } | ||
1005 | default -> throw new TracedException(problemArgument, "Invalid argument"); | ||
996 | } | 1006 | } |
997 | arguments[i] = localScope.get(problemVariable); | ||
998 | } | 1007 | } |
999 | return PartialActionLiterals.merge(partialRelation, truthValue, arguments); | 1008 | actionLiterals.add(PartialActionLiterals.merge(partialRelation, truthValue, arguments)); |
1000 | } | 1009 | } |
1001 | } | 1010 | } |
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 7b392182..84af4ee6 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 | |||
@@ -153,6 +153,22 @@ public class ProblemValidator extends AbstractProblemValidator { | |||
153 | } | 153 | } |
154 | 154 | ||
155 | @Check | 155 | @Check |
156 | public void checkNodeAssertionArgumentConstants(NodeAssertionArgument argument) { | ||
157 | var rule = EcoreUtil2.getContainerOfType(argument, RuleDefinition.class); | ||
158 | if (rule == null) { | ||
159 | return; | ||
160 | } | ||
161 | var variableOrNode = argument.getNode(); | ||
162 | if (variableOrNode instanceof Node node && !ProblemUtil.isAtomNode(node)) { | ||
163 | var name = node.getName(); | ||
164 | var message = ("Only atoms can be referenced in rule actions. " + | ||
165 | "Mark '%s' as an atom with the declaration 'atom %s.'").formatted(name, name); | ||
166 | error(message, argument, ProblemPackage.Literals.NODE_ASSERTION_ARGUMENT__NODE, | ||
167 | INSIGNIFICANT_INDEX, NODE_CONSTANT_ISSUE); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | @Check | ||
156 | public void checkUniqueDeclarations(Problem problem) { | 172 | public void checkUniqueDeclarations(Problem problem) { |
157 | var relations = new ArrayList<Relation>(); | 173 | var relations = new ArrayList<Relation>(); |
158 | var nodes = new ArrayList<Node>(); | 174 | var nodes = new ArrayList<Node>(); |
@@ -360,7 +376,7 @@ public class ProblemValidator extends AbstractProblemValidator { | |||
360 | INVALID_MODALITY_ISSUE); | 376 | INVALID_MODALITY_ISSUE); |
361 | } | 377 | } |
362 | if (parameter.getBinding() != ParameterBinding.SINGLE) { | 378 | if (parameter.getBinding() != ParameterBinding.SINGLE) { |
363 | acceptError("Parameter binding annotations are only supported in rule definitions.", parameter, | 379 | acceptError("Parameter binding annotations are only supported in decision rules.", parameter, |
364 | ProblemPackage.PARAMETER__BINDING, 0, INVALID_MODALITY_ISSUE); | 380 | ProblemPackage.PARAMETER__BINDING, 0, INVALID_MODALITY_ISSUE); |
365 | } | 381 | } |
366 | } | 382 | } |
diff --git a/subprojects/logic/src/main/java/tools/refinery/logic/literal/ConstantLiteral.java b/subprojects/logic/src/main/java/tools/refinery/logic/literal/ConstantLiteral.java index 688ddfa0..36cf4226 100644 --- a/subprojects/logic/src/main/java/tools/refinery/logic/literal/ConstantLiteral.java +++ b/subprojects/logic/src/main/java/tools/refinery/logic/literal/ConstantLiteral.java | |||
@@ -14,6 +14,8 @@ import tools.refinery.logic.term.Variable; | |||
14 | import java.util.Objects; | 14 | import java.util.Objects; |
15 | import java.util.Set; | 15 | import java.util.Set; |
16 | 16 | ||
17 | // {@link Object#equals(Object)} is implemented by {@link AbstractLiteral}. | ||
18 | @SuppressWarnings("squid:S2160") | ||
17 | public class ConstantLiteral extends AbstractLiteral { | 19 | public class ConstantLiteral extends AbstractLiteral { |
18 | private final NodeVariable variable; | 20 | private final NodeVariable variable; |
19 | private final int nodeId; | 21 | private final int nodeId; |
@@ -31,7 +33,6 @@ public class ConstantLiteral extends AbstractLiteral { | |||
31 | return nodeId; | 33 | return nodeId; |
32 | } | 34 | } |
33 | 35 | ||
34 | |||
35 | @Override | 36 | @Override |
36 | public Set<Variable> getOutputVariables() { | 37 | public Set<Variable> getOutputVariables() { |
37 | return Set.of(variable); | 38 | return Set.of(variable); |
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/Action.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/Action.java index 0ce0c3a4..edcf9526 100644 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/Action.java +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/Action.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 | */ |
@@ -67,7 +67,7 @@ public class Action { | |||
67 | var outputVariables = actionLiteral.getOutputVariables(); | 67 | var outputVariables = actionLiteral.getOutputVariables(); |
68 | int size = outputVariables.size(); | 68 | int size = outputVariables.size(); |
69 | if (size == 0) { | 69 | if (size == 0) { |
70 | // Identity mappings use a {@code null} allocation to avoid iterating over the output tuple. | 70 | // Empty mappings use a {@code null} allocation to avoid iterating over the output tuple. |
71 | return; | 71 | return; |
72 | } | 72 | } |
73 | if (size >= 2 && new HashSet<>(outputVariables).size() != size) { | 73 | if (size >= 2 && new HashSet<>(outputVariables).size() != size) { |
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/ActionLiterals.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/ActionLiterals.java index d06e2479..6bd5075b 100644 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/ActionLiterals.java +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/ActionLiterals.java | |||
@@ -16,6 +16,10 @@ public final class ActionLiterals { | |||
16 | throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly"); | 16 | throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly"); |
17 | } | 17 | } |
18 | 18 | ||
19 | public static ConstantActionLiteral constant(NodeVariable variable, int nodeId) { | ||
20 | return new ConstantActionLiteral(variable, nodeId); | ||
21 | } | ||
22 | |||
19 | public static <T> PutActionLiteral<T> put(Symbol<T> symbol, T value, NodeVariable... parameters) { | 23 | public static <T> PutActionLiteral<T> put(Symbol<T> symbol, T value, NodeVariable... parameters) { |
20 | return new PutActionLiteral<>(symbol, value, List.of(parameters)); | 24 | return new PutActionLiteral<>(symbol, value, List.of(parameters)); |
21 | } | 25 | } |
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/ConstantActionLiteral.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/ConstantActionLiteral.java new file mode 100644 index 00000000..fecb2960 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/ConstantActionLiteral.java | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.dse.transition.actions; | ||
7 | |||
8 | import tools.refinery.logic.term.NodeVariable; | ||
9 | import tools.refinery.store.model.Model; | ||
10 | import tools.refinery.store.tuple.Tuple; | ||
11 | |||
12 | import java.util.List; | ||
13 | |||
14 | public class ConstantActionLiteral extends AbstractActionLiteral { | ||
15 | private final NodeVariable variable; | ||
16 | private final int nodeId; | ||
17 | |||
18 | public ConstantActionLiteral(NodeVariable variable, int nodeId) { | ||
19 | this.variable = variable; | ||
20 | this.nodeId = nodeId; | ||
21 | } | ||
22 | |||
23 | public NodeVariable getVariable() { | ||
24 | return variable; | ||
25 | } | ||
26 | |||
27 | public int getNodeId() { | ||
28 | return nodeId; | ||
29 | } | ||
30 | |||
31 | @Override | ||
32 | public List<NodeVariable> getInputVariables() { | ||
33 | return List.of(); | ||
34 | } | ||
35 | |||
36 | @Override | ||
37 | public List<NodeVariable> getOutputVariables() { | ||
38 | return List.of(variable); | ||
39 | } | ||
40 | |||
41 | @Override | ||
42 | public BoundActionLiteral bindToModel(Model model) { | ||
43 | return ignoredTuple -> Tuple.of(nodeId); | ||
44 | } | ||
45 | } | ||