Skip to content

Commit 0b71e90

Browse files
authored
refactor(sapere): simplify execution logic in SAPEREReaction (#5317)
1 parent d2571fd commit 0b71e90

1 file changed

Lines changed: 71 additions & 53 deletions

File tree

  • alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/reactions

alchemist-incarnation-sapere/src/main/java/it/unibo/alchemist/model/sapere/reactions/SAPEREReaction.java

Lines changed: 71 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -136,81 +136,99 @@ private List<ILsaCondition> getSAPEREConditions() {
136136
@Override
137137
public void execute() {
138138
if (possibleMatches.isEmpty()) {
139-
for (final ILsaAction a : getSAPEREActions()) {
140-
a.setExecutionContext(null, validNodes);
141-
a.execute();
142-
}
139+
executeActions(null);
143140
return;
144141
}
145142
final Position<?> nodePosCache = modifiesOnlyLocally ? environment.getPosition(getNode()) : null;
146143
final List<? extends ILsaMolecule> localContentCache = modifiesOnlyLocally
147144
? new ArrayList<>(getLsaNode().getLsaSpace())
148145
: null;
149-
Map<HashString, ITreeNode<?>> matches = null;
150-
Map<ILsaNode, List<ILsaMolecule>> toRemove = null;
151-
/*
152-
* If there is infinite propensity, the last match added is the one to
153-
* choose, since it is the one which generated the "infinity" value.
154-
*/
155-
if (totalPropensity == Double.POSITIVE_INFINITY) {
156-
final int index = possibleMatches.size() - 1;
157-
matches = possibleMatches.get(index);
158-
toRemove = possibleRemove.get(index);
159-
} else if (numericRate()) {
160-
/*
161-
* If the rate is numeric, the choice is just random
162-
*/
163-
final int index = Math.abs(rng.nextInt()) % possibleMatches.size();
164-
matches = possibleMatches.get(index);
165-
toRemove = possibleRemove.get(index);
166-
} else {
167-
/*
168-
* Otherwise, the matches must be chosen randomly using their
169-
* propensities
170-
*/
171-
final double index = rng.nextDouble() * totalPropensity;
172-
double sum = 0;
173-
for (int i = 0; matches == null; i++) {
174-
sum += propensities.get(i);
175-
if (sum > index) {
176-
matches = possibleMatches.get(i);
177-
toRemove = possibleRemove.get(i);
178-
}
179-
}
180-
}
146+
final int selectedMatchIndex = selectMatchIndex();
147+
final Map<HashString, ITreeNode<?>> matches = possibleMatches.get(selectedMatchIndex);
181148
/*
182149
* The matched LSAs must be removed from the local space, if no action
183150
* added them back.
184151
*/
185-
for (final Entry<ILsaNode, List<ILsaMolecule>> entry : toRemove.entrySet()) {
186-
final ILsaNode n = entry.getKey();
187-
for (final ILsaMolecule m : entry.getValue()) {
188-
n.removeConcentration(m);
189-
}
190-
}
152+
removeMatchedMolecules(possibleRemove.get(selectedMatchIndex));
191153
/*
192154
* #T Must be loaded by the reaction, which is the only structure aware
193155
* of the time. Other special values (#NEIG, #O, #D) will be allocated
194156
* inside the actions.
195157
*/
196158
matches.put(LsaMolecule.SYN_T, new NumTreeNode(getTau().toDouble()));
197-
for (final ILsaAction a : getSAPEREActions()) {
198-
a.setExecutionContext(matches, validNodes);
199-
a.execute();
159+
executeActions(matches);
160+
/*
161+
* Empty action optimization
162+
*/
163+
updateEmptyExecutionStatus(nodePosCache, localContentCache);
164+
}
165+
166+
private void executeActions(final Map<HashString, ITreeNode<?>> matches) {
167+
for (final ILsaAction action : getSAPEREActions()) {
168+
action.setExecutionContext(matches, validNodes);
169+
action.execute();
200170
}
171+
}
201172

173+
private void removeMatchedMolecules(final Map<ILsaNode, List<ILsaMolecule>> toRemove) {
174+
for (final Entry<ILsaNode, List<ILsaMolecule>> entry : toRemove.entrySet()) {
175+
final ILsaNode node = entry.getKey();
176+
for (final ILsaMolecule molecule : entry.getValue()) {
177+
node.removeConcentration(molecule);
178+
}
179+
}
180+
}
181+
182+
private int selectMatchIndex() {
202183
/*
203-
* Empty action optimization
184+
* If there is infinite propensity, the last match added is the one to
185+
* choose, since it is the one which generated the "infinity" value.
204186
*/
205-
if (modifiesOnlyLocally) {
206-
final ILsaNode n = getLsaNode();
207-
if (Objects.requireNonNull(nodePosCache).equals(environment.getPosition(getNode()))) {
208-
final List<? extends ILsaMolecule> contents = n.getLsaSpace();
209-
if (contents.size() == Objects.requireNonNull(localContentCache).size()) {
210-
emptyExecution = localContentCache.containsAll(contents);
211-
}
187+
if (totalPropensity == Double.POSITIVE_INFINITY) {
188+
return possibleMatches.size() - 1;
189+
}
190+
/*
191+
* If the rate is numeric, the choice is just random
192+
*/
193+
if (numericRate()) {
194+
return rng.nextInt(possibleMatches.size());
195+
}
196+
/*
197+
* Otherwise, the matches must be chosen randomly using their
198+
* propensities
199+
*/
200+
return selectWeightedMatchIndex();
201+
}
202+
203+
private int selectWeightedMatchIndex() {
204+
final double selectedPropensity = rng.nextDouble() * totalPropensity;
205+
double cumulativePropensity = 0;
206+
for (int i = 0; i < propensities.size(); i++) {
207+
cumulativePropensity += propensities.get(i);
208+
if (cumulativePropensity > selectedPropensity) {
209+
return i;
212210
}
213211
}
212+
// Floating-point rounding can cause selectedPropensity == totalPropensity;
213+
// fall back to the last bucket in that case.
214+
return propensities.size() - 1;
215+
}
216+
217+
private void updateEmptyExecutionStatus(
218+
final Position<?> nodePositionBeforeExecution,
219+
final List<? extends ILsaMolecule> localContentBeforeExecution
220+
) {
221+
if (!modifiesOnlyLocally || nodePositionChanged(nodePositionBeforeExecution)) {
222+
return;
223+
}
224+
final List<? extends ILsaMolecule> contents = getLsaNode().getLsaSpace();
225+
if (contents.size() == Objects.requireNonNull(localContentBeforeExecution).size()) {
226+
emptyExecution = localContentBeforeExecution.containsAll(contents);
227+
}
228+
}
229+
230+
private boolean nodePositionChanged(final Position<?> nodePositionBeforeExecution) {
231+
return !Objects.requireNonNull(nodePositionBeforeExecution).equals(environment.getPosition(getNode()));
214232
}
215233

216234
/**

0 commit comments

Comments
 (0)