@@ -17,7 +17,7 @@ class Set::Implementation {
17
17
18
18
// Determines the limiting conditions for the evaluation.
19
19
StepSpecification stepSpec_ = {0 , 0 , 0 , 0 , 0 }; // don't evolve unless asked to.
20
- const SystemType systemType_ ;
20
+ const uint64_t maxDestroyerEvents_ ;
21
21
TerminationReason terminationReason_ = TerminationReason::NotTerminated;
22
22
23
23
std::unordered_map<ExpressionID, AtomsVector> expressions_;
@@ -40,14 +40,14 @@ class Set::Implementation {
40
40
public:
41
41
Implementation (const std::vector<Rule>& rules,
42
42
const std::vector<AtomsVector>& initialExpressions,
43
- const SystemType& systemType ,
43
+ const uint64_t maxDestroyerEvents ,
44
44
const Matcher::OrderingSpec& orderingSpec,
45
45
const Matcher::EventDeduplication& eventDeduplication,
46
46
const unsigned int randomSeed)
47
47
: Implementation(
48
48
rules,
49
49
initialExpressions,
50
- systemType ,
50
+ maxDestroyerEvents ,
51
51
orderingSpec,
52
52
eventDeduplication,
53
53
randomSeed,
@@ -98,18 +98,6 @@ class Set::Implementation {
98
98
99
99
// At this point, we are committed to modifying the set.
100
100
101
- // This goes first, as if the system type is invalid, we want to fail before modifying anything else.
102
- if (systemType_ == SystemType::Singleway) {
103
- matcher_.removeMatchesInvolvingExpressions (match->inputExpressions );
104
- atomsIndex_.removeExpressions (match->inputExpressions );
105
- destroyedExpressionsCount_ += match->inputExpressions .size ();
106
- updateAtomDegrees (&atomDegrees_, match->inputExpressions , -1 );
107
- } else if (systemType_ == SystemType::Multiway) {
108
- matcher_.deleteMatch (match);
109
- } else {
110
- throw Error::InvalidSystemType;
111
- }
112
-
113
101
// Name newly created atoms as well, now all atoms in the output are explicitly named.
114
102
const auto namedRuleOutputs = nameAnonymousAtoms (explicitRuleOutputs);
115
103
@@ -118,12 +106,36 @@ class Set::Implementation {
118
106
119
107
addExpressions (outputExpressionIDs, namedRuleOutputs);
120
108
109
+ if (maxDestroyerEvents_ == 1 ) {
110
+ matcher_.removeMatchesInvolvingExpressions (match->inputExpressions );
111
+ atomsIndex_.removeExpressions (match->inputExpressions );
112
+ // The following only make sense for singleway systems.
113
+ destroyedExpressionsCount_ += match->inputExpressions .size ();
114
+ updateAtomDegrees (&atomDegrees_, match->inputExpressions , -1 );
115
+ } else if (maxDestroyerEvents_ == static_cast <uint64_t >(std::numeric_limits<int64_t >::max ())) {
116
+ matcher_.deleteMatch (match);
117
+ } else {
118
+ // Only remove expressions whose destroyer events count reached the maximum.
119
+ matcher_.deleteMatch (match);
120
+ std::vector<ExpressionID> inputExpressionsToRemove;
121
+ for (const auto & id : match->inputExpressions ) {
122
+ if (causalGraph_.destroyerEventsCount (id) >= maxDestroyerEvents_) {
123
+ inputExpressionsToRemove.push_back (id);
124
+ }
125
+ }
126
+ matcher_.removeMatchesInvolvingExpressions (inputExpressionsToRemove);
127
+ atomsIndex_.removeExpressions (inputExpressionsToRemove);
128
+ }
129
+
121
130
return 1 ;
122
131
}
123
132
124
133
int64_t replace (const StepSpecification stepSpec, const std::function<bool ()>& shouldAbort) {
125
134
updateStepSpec (stepSpec);
126
135
int64_t count = 0 ;
136
+ if (maxDestroyerEvents_ == 0 ) {
137
+ return count;
138
+ }
127
139
while (true ) {
128
140
if (replaceOnce (shouldAbort)) {
129
141
++count;
@@ -156,17 +168,17 @@ class Set::Implementation {
156
168
const std::vector<Event>& events () const { return causalGraph_.events (); }
157
169
158
170
private:
159
- Implementation (std::vector<Rule> rules,
171
+ Implementation (const std::vector<Rule>& rules,
160
172
const std::vector<AtomsVector>& initialExpressions,
161
- const SystemType& systemType ,
173
+ const uint64_t maxDestroyerEvents ,
162
174
const Matcher::OrderingSpec& orderingSpec,
163
175
const Matcher::EventDeduplication& eventDeduplication,
164
176
const unsigned int randomSeed,
165
177
const GetAtomsVectorFunc& getAtomsVector,
166
178
const GetExpressionsSeparationFunc& getExpressionsSeparation)
167
- : rules_(rules),
168
- systemType_ (systemType ),
169
- causalGraph_(static_cast <int >(initialExpressions.size()), separationTrackingMethod(systemType , rules)),
179
+ : rules_(optimizeRules( rules, maxDestroyerEvents) ),
180
+ maxDestroyerEvents_ (maxDestroyerEvents ),
181
+ causalGraph_(static_cast <int >(initialExpressions.size()), separationTrackingMethod(maxDestroyerEvents , rules)),
170
182
atomsIndex_(getAtomsVector),
171
183
matcher_(rules_,
172
184
&atomsIndex_,
@@ -185,6 +197,24 @@ class Set::Implementation {
185
197
addExpressions (causalGraph_.allExpressionIDs (), initialExpressions);
186
198
}
187
199
200
+ std::vector<Rule> optimizeRules (const std::vector<Rule>& rules, uint64_t maxDestroyerEvents) {
201
+ if (maxDestroyerEvents == 1 ) {
202
+ // The real optimization happens later when we call separationTrackingMethod(1, rules) by setting
203
+ // SeparationTrackingMethod to None.
204
+ // EventSelectionFunction is set to All in each rule to prevent breaking: SeparationTrackingMethod::None causes
205
+ // isSpacelikeSeparated(...) to be always false for any expression pair, thus no new event whose rule is only
206
+ // applied when expressions are spacelike separated would occur.
207
+ std::vector<Rule> newRules;
208
+ newRules.reserve (rules.size ());
209
+ for (const auto & rule : rules) {
210
+ newRules.push_back (Rule{rule.inputs , rule.outputs , EventSelectionFunction::All});
211
+ }
212
+ return newRules;
213
+ } else {
214
+ return rules;
215
+ }
216
+ }
217
+
188
218
Atom incrementNextAtom () {
189
219
if (nextAtom_ == std::numeric_limits<Atom>::max ()) {
190
220
throw Error::AtomCountOverflow;
@@ -223,7 +253,7 @@ class Set::Implementation {
223
253
unindexedExpressions_.clear ();
224
254
}
225
255
226
- bool isMultiway () const { return systemType_ != SystemType::Singleway ; }
256
+ bool isMultiway () const { return maxDestroyerEvents_ > 1 ; }
227
257
228
258
TerminationReason willExceedAtomLimits (const std::vector<AtomsVector>& explicitRuleInputs,
229
259
const std::vector<AtomsVector>& explicitRuleOutputs) const {
@@ -349,9 +379,10 @@ class Set::Implementation {
349
379
return smallestSoFar;
350
380
}
351
381
352
- static CausalGraph::SeparationTrackingMethod separationTrackingMethod (const SystemType systemType ,
382
+ static CausalGraph::SeparationTrackingMethod separationTrackingMethod (const uint64_t maxDestroyerEvents ,
353
383
const std::vector<Rule>& rules) {
354
- if (systemType == SystemType::Singleway) {
384
+ if (maxDestroyerEvents == 1 ) {
385
+ // No need of tracking the separation between expressions if these are removed after each destroyer event.
355
386
return CausalGraph::SeparationTrackingMethod::None;
356
387
}
357
388
for (const auto & rule : rules) {
@@ -365,12 +396,12 @@ class Set::Implementation {
365
396
366
397
Set::Set (const std::vector<Rule>& rules,
367
398
const std::vector<AtomsVector>& initialExpressions,
368
- const SystemType& eventSelectionFunction ,
399
+ uint64_t maxDestroyerEvents ,
369
400
const Matcher::OrderingSpec& orderingSpec,
370
401
const Matcher::EventDeduplication& eventDeduplication,
371
402
unsigned int randomSeed)
372
403
: implementation_(std::make_shared<Implementation>(
373
- rules, initialExpressions, eventSelectionFunction , orderingSpec, eventDeduplication, randomSeed)) {}
404
+ rules, initialExpressions, maxDestroyerEvents , orderingSpec, eventDeduplication, randomSeed)) {}
374
405
375
406
int64_t Set::replaceOnce (const std::function<bool ()>& shouldAbort) {
376
407
return implementation_->replaceOnce (shouldAbort, true );
0 commit comments