diff options
Diffstat (limited to 'subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/Action.java')
-rw-r--r-- | subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/Action.java | 132 |
1 files changed, 132 insertions, 0 deletions
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 new file mode 100644 index 00000000..d63ddfdd --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/Action.java | |||
@@ -0,0 +1,132 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 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 org.eclipse.collections.api.factory.primitive.ObjectIntMaps; | ||
9 | import org.eclipse.collections.api.map.primitive.MutableObjectIntMap; | ||
10 | import org.jetbrains.annotations.Nullable; | ||
11 | import tools.refinery.store.model.Model; | ||
12 | import tools.refinery.store.query.dnf.RelationalQuery; | ||
13 | import tools.refinery.store.query.dnf.SymbolicParameter; | ||
14 | import tools.refinery.store.query.term.NodeVariable; | ||
15 | |||
16 | import java.util.*; | ||
17 | |||
18 | public class Action { | ||
19 | private final List<NodeVariable> parameters; | ||
20 | private final Set<NodeVariable> localVariables; | ||
21 | private final List<ActionLiteral> actionLiterals; | ||
22 | private final int[] @Nullable [] inputAllocations; | ||
23 | private final int[] @Nullable [] outputAllocations; | ||
24 | |||
25 | public Action(List<NodeVariable> parameters, List<? extends ActionLiteral> actionLiterals) { | ||
26 | this.parameters = List.copyOf(parameters); | ||
27 | this.actionLiterals = List.copyOf(actionLiterals); | ||
28 | var allocation = ObjectIntMaps.mutable.<NodeVariable>empty(); | ||
29 | int arity = parameters.size(); | ||
30 | for (int i = 0; i < arity; i++) { | ||
31 | allocation.put(parameters.get(i), i); | ||
32 | } | ||
33 | var mutableLocalVariables = new LinkedHashSet<NodeVariable>(); | ||
34 | int size = actionLiterals.size(); | ||
35 | inputAllocations = new int[size][]; | ||
36 | outputAllocations = new int[size][]; | ||
37 | for (int i = 0; i < size; i++) { | ||
38 | computeInputAllocation(i, parameters, allocation); | ||
39 | computeOutputAllocation(i, mutableLocalVariables, allocation); | ||
40 | } | ||
41 | this.localVariables = Collections.unmodifiableSet(mutableLocalVariables); | ||
42 | } | ||
43 | |||
44 | private void computeInputAllocation(int actionIndex, List<NodeVariable> parameters, | ||
45 | MutableObjectIntMap<NodeVariable> allocation) { | ||
46 | var actionLiteral = actionLiterals.get(actionIndex); | ||
47 | var inputVariables = actionLiteral.getInputVariables(); | ||
48 | if (inputVariables.equals(parameters)) { | ||
49 | // Identity mappings use a {@code null} allocation to pass the activation tuple unchanged. | ||
50 | return; | ||
51 | } | ||
52 | var inputs = new int[inputVariables.size()]; | ||
53 | for (int i = 0; i < inputs.length; i++) { | ||
54 | var variable = inputVariables.get(i); | ||
55 | if (!allocation.containsKey(variable)) { | ||
56 | throw new IllegalArgumentException("Unbound input variable %s of action literal %s" | ||
57 | .formatted(variable, actionLiteral)); | ||
58 | } | ||
59 | inputs[i] = allocation.get(variable); | ||
60 | } | ||
61 | inputAllocations[actionIndex] = inputs; | ||
62 | } | ||
63 | |||
64 | private void computeOutputAllocation(int actionIndex, Set<NodeVariable> mutableLocalVariable, | ||
65 | MutableObjectIntMap<NodeVariable> allocation) { | ||
66 | var actionLiteral = actionLiterals.get(actionIndex); | ||
67 | var outputVariables = actionLiteral.getOutputVariables(); | ||
68 | int size = outputVariables.size(); | ||
69 | if (size == 0) { | ||
70 | // Identity mappings use a {@code null} allocation to avoid iterating over the output tuple. | ||
71 | return; | ||
72 | } | ||
73 | if (size >= 2 && new HashSet<>(outputVariables).size() != size) { | ||
74 | throw new IllegalArgumentException("Action literal %s has duplicate output variables %s" | ||
75 | .formatted(actionLiteral, outputVariables)); | ||
76 | } | ||
77 | int arity = parameters.size(); | ||
78 | var outputs = new int[size]; | ||
79 | for (int i = 0; i < size; i++) { | ||
80 | var variable = outputVariables.get(i); | ||
81 | if (allocation.containsKey(variable)) { | ||
82 | throw new IllegalArgumentException("Output variable %s of action literal %s was already assigned" | ||
83 | .formatted(variable, actionLiteral)); | ||
84 | } | ||
85 | int variableId = mutableLocalVariable.size(); | ||
86 | allocation.put(variable, arity + variableId); | ||
87 | outputs[i] = variableId; | ||
88 | mutableLocalVariable.add(variable); | ||
89 | } | ||
90 | outputAllocations[actionIndex] = outputs; | ||
91 | } | ||
92 | |||
93 | public List<NodeVariable> getParameters() { | ||
94 | return parameters; | ||
95 | } | ||
96 | |||
97 | public int getArity() { | ||
98 | return parameters.size(); | ||
99 | } | ||
100 | |||
101 | public Set<NodeVariable> getLocalVariables() { | ||
102 | return localVariables; | ||
103 | } | ||
104 | |||
105 | public List<ActionLiteral> getActionLiterals() { | ||
106 | return actionLiterals; | ||
107 | } | ||
108 | |||
109 | int @Nullable [] getInputAllocation(int actionIndex) { | ||
110 | return inputAllocations[actionIndex]; | ||
111 | } | ||
112 | |||
113 | int @Nullable [] getOutputAllocation(int actionIndex) { | ||
114 | return outputAllocations[actionIndex]; | ||
115 | } | ||
116 | |||
117 | public BoundAction bindToModel(Model model) { | ||
118 | return new BoundAction(this, model); | ||
119 | } | ||
120 | |||
121 | public static Action ofSymbolicParameters(List<SymbolicParameter> symbolicParameters, | ||
122 | List<? extends ActionLiteral> actionLiterals) { | ||
123 | var nodeVariables = symbolicParameters.stream() | ||
124 | .map(symbolicParameter -> symbolicParameter.getVariable().asNodeVariable()) | ||
125 | .toList(); | ||
126 | return new Action(nodeVariables, actionLiterals); | ||
127 | } | ||
128 | |||
129 | public static Action ofPrecondition(RelationalQuery precondition, List<? extends ActionLiteral> actionLiterals) { | ||
130 | return ofSymbolicParameters(precondition.getDnf().getSymbolicParameters(), actionLiterals); | ||
131 | } | ||
132 | } | ||