diff options
Diffstat (limited to 'subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PlanState.java')
-rw-r--r-- | subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PlanState.java | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PlanState.java b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PlanState.java new file mode 100644 index 00000000..e93b07bc --- /dev/null +++ b/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/PlanState.java | |||
@@ -0,0 +1,283 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2015, Marton Bur, Zoltan Ujhelyi, Akos Horvath, Istvan Rath and Daniel Varro | ||
3 | * This program and the accompanying materials are made available under the | ||
4 | * terms of the Eclipse Public License v. 2.0 which is available at | ||
5 | * http://www.eclipse.org/legal/epl-v20.html. | ||
6 | * | ||
7 | * SPDX-License-Identifier: EPL-2.0 | ||
8 | *******************************************************************************/ | ||
9 | package tools.refinery.viatra.runtime.localsearch.planner; | ||
10 | |||
11 | import java.util.ArrayList; | ||
12 | import java.util.Collection; | ||
13 | import java.util.Collections; | ||
14 | import java.util.Comparator; | ||
15 | import java.util.HashSet; | ||
16 | import java.util.List; | ||
17 | import java.util.Map; | ||
18 | import java.util.Set; | ||
19 | |||
20 | import tools.refinery.viatra.runtime.localsearch.planner.util.OperationCostComparator; | ||
21 | import tools.refinery.viatra.runtime.matchers.algorithms.OrderedIterableMerge; | ||
22 | import tools.refinery.viatra.runtime.matchers.psystem.PBody; | ||
23 | import tools.refinery.viatra.runtime.matchers.psystem.PConstraint; | ||
24 | import tools.refinery.viatra.runtime.matchers.psystem.PVariable; | ||
25 | |||
26 | /** | ||
27 | * This class represents the state of the plan during planning. | ||
28 | * | ||
29 | * <p> A PlanState represents a sequence of operations (operationsList) and caches the computed cost | ||
30 | * for this operation sequence. The list and the cost are initialized in the constructor. | ||
31 | * However, #categorizeChecks() also updates the operations list (by suffixing checks) | ||
32 | * | ||
33 | * @author Marton Bur | ||
34 | * @noreference This class is not intended to be referenced by clients. | ||
35 | */ | ||
36 | public class PlanState { | ||
37 | |||
38 | private final PBody pBody; | ||
39 | private final List<PConstraintInfo> operationsList; | ||
40 | private final Set<PVariable> boundVariables; | ||
41 | private final Collection<PVariable> deltaVariables; /* bound since ancestor plan */ | ||
42 | private final Set<PConstraint> enforcedConstraints; | ||
43 | |||
44 | private double cummulativeProduct; | ||
45 | private double cost; | ||
46 | |||
47 | private static Comparator<PConstraintInfo> infoComparator = new OperationCostComparator(); | ||
48 | |||
49 | /* | ||
50 | * For a short explanation of past, present and future operations, | ||
51 | * see class | ||
52 | */ | ||
53 | private List<PConstraintInfo> presentExtends; | ||
54 | |||
55 | /** | ||
56 | * Creates an initial state | ||
57 | */ | ||
58 | public PlanState(PBody pBody, Set<PVariable> boundVariables) { | ||
59 | |||
60 | this(pBody, new ArrayList<>(), boundVariables, boundVariables /* also the delta */, | ||
61 | 0.0 /* initial cost */, 1.0 /*initial branch count */); | ||
62 | } | ||
63 | |||
64 | public PlanState cloneWithApplied(PConstraintInfo op) { | ||
65 | // Create operation list based on the current state | ||
66 | ArrayList<PConstraintInfo> newOperationsList = | ||
67 | // pre-reserve excess capacity for later addition of CHECK ops | ||
68 | new ArrayList<>(pBody.getConstraints().size()); | ||
69 | newOperationsList.addAll(this.getOperations()); | ||
70 | newOperationsList.add(op); | ||
71 | |||
72 | // Bind the variables of the op | ||
73 | Collection<PVariable> deltaVariables = op.getFreeVariables(); | ||
74 | Set<PVariable> allBoundVariables = | ||
75 | // pre-reserve exact capacity as variables are known | ||
76 | // (will not be affected by adding CHECK ops later) | ||
77 | new HashSet<>(this.getBoundVariables().size() + deltaVariables.size()); | ||
78 | allBoundVariables.addAll(this.getBoundVariables()); | ||
79 | allBoundVariables.addAll(deltaVariables); | ||
80 | |||
81 | PlanState newState = new PlanState(getAssociatedPBody(), newOperationsList, allBoundVariables, deltaVariables, | ||
82 | cost, cummulativeProduct); | ||
83 | newState.accountNewOperation(op); | ||
84 | return newState; | ||
85 | } | ||
86 | |||
87 | private PlanState(PBody pBody, List<PConstraintInfo> operationsList, | ||
88 | Set<PVariable> boundVariables, Collection<PVariable> deltaVariables, | ||
89 | double cost, double cummulativeProduct) | ||
90 | { | ||
91 | this.pBody = pBody; | ||
92 | this.operationsList = operationsList; | ||
93 | this.boundVariables = boundVariables; | ||
94 | this.enforcedConstraints = new HashSet<>(); | ||
95 | this.deltaVariables = deltaVariables; | ||
96 | this.cost = cost; | ||
97 | this.cummulativeProduct = cummulativeProduct; | ||
98 | } | ||
99 | |||
100 | // NOT included for EXTEND: bind all variables of op | ||
101 | private void accountNewOperation(PConstraintInfo constraintInfo) { | ||
102 | this.enforcedConstraints.add(constraintInfo.getConstraint()); | ||
103 | accountCost(constraintInfo); | ||
104 | } | ||
105 | |||
106 | private void accountCost(PConstraintInfo constraintInfo) { | ||
107 | double constraintCost = constraintInfo.getCost(); | ||
108 | double branchFactor = constraintCost; | ||
109 | if (constraintCost > 0){ | ||
110 | cost += cummulativeProduct * constraintCost; | ||
111 | cummulativeProduct *= branchFactor; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | |||
116 | public Set<PConstraint> getEnforcedConstraints() { | ||
117 | return enforcedConstraints; | ||
118 | } | ||
119 | |||
120 | /** | ||
121 | * Re-categorizes given extend operations into already applied or no longer applicable ones (discarded), | ||
122 | * immediately applicable ones (saved as presently viable extends), | ||
123 | * and not yet applicable ones (discarded). | ||
124 | * | ||
125 | * @param allPotentialExtendInfos all other extends that may be applicable | ||
126 | * to this plan state now or in the future; | ||
127 | * MUST consist of "extend" constraint applications only (at least one free variable) | ||
128 | */ | ||
129 | public void updateExtends(Iterable<PConstraintInfo> allPotentialExtendInfos) { | ||
130 | presentExtends = new ArrayList<>(); | ||
131 | |||
132 | |||
133 | // categorize future/present extend constraint infos | ||
134 | for (PConstraintInfo op : allPotentialExtendInfos) { | ||
135 | updateExtendInternal(op); | ||
136 | } | ||
137 | } | ||
138 | |||
139 | /** | ||
140 | * Re-categorizes given extend operations into already applied or no longer applicable ones (discarded), | ||
141 | * immediately applicable ones (saved as presently viable extends), | ||
142 | * and not yet applicable ones (discarded). | ||
143 | * | ||
144 | * @param extendOpsByBoundVariables all EXTEND operations indexed by affected <i>bound</i> variables | ||
145 | * MUST consist of "extend" constraint applications only (at least one free variable) | ||
146 | */ | ||
147 | public void updateExtendsBasedOnDelta( | ||
148 | Iterable<PConstraintInfo> previousPresentExtends, | ||
149 | Map<PVariable, ? extends Collection<PConstraintInfo>> extendOpsByBoundVariables) | ||
150 | { | ||
151 | presentExtends = new ArrayList<>(); | ||
152 | if (operationsList.isEmpty()) | ||
153 | throw new IllegalStateException("Not applicable as starting step"); | ||
154 | |||
155 | for (PConstraintInfo extend: previousPresentExtends) { | ||
156 | updateExtendInternal(extend); | ||
157 | } | ||
158 | |||
159 | Set<PConstraintInfo> affectedExtends = new HashSet<>(); | ||
160 | for (PVariable variable : deltaVariables) { | ||
161 | // only those check ops may become applicable that have an affected variable in the delta | ||
162 | Collection<PConstraintInfo> extendsForVariable = extendOpsByBoundVariables.get(variable); | ||
163 | if (null != extendsForVariable) { | ||
164 | affectedExtends.addAll(extendsForVariable); | ||
165 | } | ||
166 | } | ||
167 | for (PConstraintInfo extend: affectedExtends) { | ||
168 | updateExtendInternal(extend); | ||
169 | } | ||
170 | } | ||
171 | |||
172 | private void updateExtendInternal(PConstraintInfo op) { | ||
173 | if(!enforcedConstraints.contains(op.getConstraint())) { | ||
174 | categorizeExtend(op); | ||
175 | } | ||
176 | } | ||
177 | |||
178 | /** | ||
179 | * Check operations that newly became applicable (see {@link #getDeltaVariables()}) | ||
180 | * are appended to operations lists. | ||
181 | * | ||
182 | * <p> Will never discover degenerate checks (of PConstraints with zero variables), | ||
183 | * so must not use on initial state. | ||
184 | * | ||
185 | * @param allPotentialCheckInfos all CHECK operations | ||
186 | * MUST consist of "check" constraint applications only (no free variables) | ||
187 | * and must be iterable in decreasing order of cost | ||
188 | * | ||
189 | * | ||
190 | */ | ||
191 | public void applyChecks(List<PConstraintInfo> allPotentialCheckInfos) { | ||
192 | applyChecksInternal(allPotentialCheckInfos); | ||
193 | } | ||
194 | |||
195 | /** | ||
196 | * Immediately applicable checks are appended to operations lists. | ||
197 | * | ||
198 | * @param checkOpsByVariables all CHECK operations indexed by affected variables | ||
199 | * MUST consist of "check" constraint applications only (no free variables) | ||
200 | * and each bucket must be iterable in decreasing order of cost | ||
201 | */ | ||
202 | public void applyChecksBasedOnDelta(Map<PVariable, List<PConstraintInfo>> checkOpsByVariables) { | ||
203 | if (operationsList.isEmpty()) | ||
204 | throw new IllegalStateException("Not applicable as starting step"); | ||
205 | |||
206 | Iterable<PConstraintInfo> affectedChecks = Collections.emptyList(); | ||
207 | |||
208 | for (PVariable variable : deltaVariables) { | ||
209 | // only those check ops may become applicable that have an affected variable in the delta | ||
210 | List<PConstraintInfo> checksForVariable = checkOpsByVariables.get(variable); | ||
211 | if (null != checksForVariable) { | ||
212 | affectedChecks = OrderedIterableMerge.mergeUniques(affectedChecks, checksForVariable, infoComparator); | ||
213 | } | ||
214 | } | ||
215 | |||
216 | // checks retain their order, no re-sorting needed | ||
217 | applyChecksInternal(affectedChecks); | ||
218 | } | ||
219 | |||
220 | private void applyChecksInternal(Iterable<PConstraintInfo> checks) { | ||
221 | for (PConstraintInfo checkInfo : checks) { | ||
222 | if (this.boundVariables.containsAll(checkInfo.getBoundVariables()) && | ||
223 | !enforcedConstraints.contains(checkInfo.getConstraint())) | ||
224 | { | ||
225 | operationsList.add(checkInfo); | ||
226 | accountNewOperation(checkInfo); | ||
227 | } | ||
228 | } | ||
229 | } | ||
230 | |||
231 | |||
232 | private void categorizeExtend(PConstraintInfo constraintInfo) { | ||
233 | PConstraintCategory category = constraintInfo.getCategory(pBody, boundVariables); | ||
234 | if (category == PConstraintCategory.PRESENT) { | ||
235 | presentExtends.add(constraintInfo); | ||
236 | } else { | ||
237 | // do not categorize past/future operations | ||
238 | } | ||
239 | } | ||
240 | |||
241 | |||
242 | public PBody getAssociatedPBody() { | ||
243 | return pBody; | ||
244 | } | ||
245 | |||
246 | public List<PConstraintInfo> getOperations() { | ||
247 | return operationsList; | ||
248 | } | ||
249 | |||
250 | public Set<PVariable> getBoundVariables() { | ||
251 | return boundVariables; | ||
252 | } | ||
253 | |||
254 | /** | ||
255 | * @return the derived cost of the plan contained in the state | ||
256 | */ | ||
257 | public double getCost() { | ||
258 | return cost; | ||
259 | } | ||
260 | |||
261 | |||
262 | /** | ||
263 | * @return cumulative branching factor | ||
264 | * @since 2.1 | ||
265 | */ | ||
266 | public double getCummulativeProduct() { | ||
267 | return cummulativeProduct; | ||
268 | } | ||
269 | |||
270 | public List<PConstraintInfo> getPresentExtends() { | ||
271 | return presentExtends; | ||
272 | } | ||
273 | |||
274 | /** | ||
275 | * Contains only those variables that are added by the newest extend | ||
276 | * (or the initially bound ones if no extend yet) | ||
277 | */ | ||
278 | public Collection<PVariable> getDeltaVariables() { | ||
279 | return deltaVariables; | ||
280 | } | ||
281 | |||
282 | |||
283 | } | ||