Skip to content

Commit 6a83122

Browse files
committed
improved cycle detection efficiency
1 parent 0f16a3f commit 6a83122

File tree

1 file changed

+44
-26
lines changed
  • include/maxplus/base/fsm

1 file changed

+44
-26
lines changed

include/maxplus/base/fsm/fsm.h

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ class FiniteStateMachine {
210210
[[nodiscard]] virtual const SetOfStateRefs &getInitialStates() const = 0;
211211
[[nodiscard]] virtual const SetOfStateRefs &getFinalStates() const = 0;
212212
[[nodiscard]] virtual const SetOfStates &getStates() const = 0;
213+
[[nodiscard]] virtual SetOfStateRefs getStateRefs() const = 0;
213214
[[nodiscard]] virtual const SetOfEdges &getEdges() const = 0;
214215
};
215216

@@ -266,19 +267,29 @@ class DepthFirstSearch {
266267

267268
virtual void onSimpleCycle(DfsStack &stack){};
268269

269-
explicit DepthFirstSearch(const FiniteStateMachine &targetFsm) : fsm(targetFsm){};
270+
const FiniteStateMachine& getFSM(){
271+
return this->fsm;
272+
}
273+
274+
explicit DepthFirstSearch(const FiniteStateMachine &targetFsm) :
275+
fsm(targetFsm)
276+
{};
270277

271278
// Execute the depth first search
272-
void DoDepthFirstSearch(const StateRef &startingState, bool fullDFS = false) {
279+
void DoDepthFirstSearch(const SetOfStateRefs &startingStates, bool fullDFS = false) {
273280
// store visited states
274281
SetOfStateRefs visitedStates;
275282
SetOfStateRefs statesOnStack;
276283

284+
this->_abort = false;
285+
277286
// put initial state on the stack
278-
dfsStack.emplace_back(startingState);
279-
this->onEnterState(startingState);
287+
for (const auto& s: startingStates) {
288+
dfsStack.emplace_back(s);
289+
this->onEnterState(s);
290+
}
280291

281-
while (!(dfsStack.empty())) {
292+
while (!this->_abort && !(dfsStack.empty())) {
282293
DFSStackItem &si = dfsStack.back();
283294

284295
// current item complete?
@@ -313,21 +324,34 @@ class DepthFirstSearch {
313324
}
314325
}
315326

327+
void DoDepthFirstSearch(const StateRef &startingState, bool fullDFS = false){
328+
SetOfStateRefs stateSet;
329+
stateSet.insert(startingState);
330+
return this->DoDepthFirstSearch(stateSet, fullDFS);
331+
}
332+
316333
// Execute the depth first search
317334
void DoDepthFirstSearch(bool fullDFS = false) {
318-
this->DoDepthFirstSearch(this->fsm.getInitialState(), fullDFS);
335+
this->DoDepthFirstSearch(this->fsm.getInitialStates(), fullDFS);
319336
}
320337

321-
protected:
338+
void abortDFS() {
339+
this->_abort = true;
340+
}
341+
342+
private:
322343
const FiniteStateMachine &fsm;
344+
bool _abort{};
345+
323346
};
324347

325348
// Check for cycles
326349
class DetectCycle : public DepthFirstSearch {
327350
public:
328351
bool hasCycle = false;
329352

330-
explicit DetectCycle(const FiniteStateMachine &targetFsm) : DepthFirstSearch(targetFsm){};
353+
explicit DetectCycle(const FiniteStateMachine &targetFsm) : DepthFirstSearch(targetFsm){
354+
};
331355

332356
~DetectCycle() override = default;
333357

@@ -339,30 +363,15 @@ class DetectCycle : public DepthFirstSearch {
339363
bool checkForCycles() { return this->checkForCycles(nullptr); }
340364

341365
bool checkForCycles(ListOfStateRefs *cycle) {
342-
this->visitedStates.clear();
343366
this->cycle = cycle;
344-
const SetOfStates &states = this->fsm.getStates();
345-
auto nextStartingState = states.begin();
346-
while (nextStartingState != states.end()) {
347-
this->DoDepthFirstSearch((*nextStartingState).second->getReference());
348-
if (this->hasCycle) {
349-
return true;
350-
}
351-
while (nextStartingState != states.end()
352-
&& this->visitedStates.includesState(
353-
(*nextStartingState).second->getReference())) {
354-
nextStartingState++;
355-
}
356-
}
357-
return false;
367+
const SetOfStateRefs states = this->getFSM().getStateRefs();
368+
this->DoDepthFirstSearch(states);
369+
return this->hasCycle;
358370
}
359371

360372
private:
361-
SetOfStateRefs visitedStates;
362373
ListOfStateRefs *cycle = nullptr;
363374

364-
void onEnterState(StateRef s) override { this->visitedStates.insert(s); }
365-
366375
void onSimpleCycle(DfsStack &stack) override {
367376
if (!this->hasCycle) {
368377
if (this->cycle != nullptr) {
@@ -371,6 +380,7 @@ class DetectCycle : public DepthFirstSearch {
371380
}
372381
}
373382
this->hasCycle = true;
383+
this->abortDFS();
374384
}
375385
}
376386
};
@@ -657,6 +667,14 @@ class FiniteStateMachine : public Abstract::FiniteStateMachine {
657667
return this->states;
658668
};
659669

670+
[[nodiscard]] FSM::Abstract::SetOfStateRefs getStateRefs() const override {
671+
FSM::Abstract::SetOfStateRefs result;
672+
for (const auto& s: this->states) {
673+
result.insert(s.second->getReference());
674+
}
675+
return result;
676+
};
677+
660678
[[nodiscard]] const SetOfEdges<StateLabelType, EdgeLabelType> &getEdges() const override {
661679
return this->edges;
662680
};

0 commit comments

Comments
 (0)