Skip to content

Commit efd7f44

Browse files
authored
Optimize is_strongly_connected
1 parent 5180124 commit efd7f44

1 file changed

Lines changed: 34 additions & 8 deletions

File tree

aalpy/base/Automaton.py

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -237,14 +237,40 @@ def is_strongly_connected(self) -> bool:
237237
238238
True if strongly connected, False otherwise
239239
240-
"""
241-
import itertools
240+
"""
241+
if not self.states:
242+
return True
243+
244+
# strongly connected iff some state reaches all states and is reached by
245+
# all states; two linear traversals instead of one search per state pair
246+
all_states = set(self.states)
247+
root = self.states[0]
248+
249+
visited = {root}
250+
stack = [root]
251+
while stack:
252+
for successor in stack.pop().transitions.values():
253+
if successor not in visited and successor in all_states:
254+
visited.add(successor)
255+
stack.append(successor)
256+
if visited != all_states:
257+
return False
242258

243-
state_comb_list = itertools.permutations(self.states, 2)
244-
for state_comb in state_comb_list:
245-
if self.get_shortest_path(state_comb[0], state_comb[1]) is None:
246-
return False
247-
return True
259+
predecessors = {state: [] for state in self.states}
260+
for state in self.states:
261+
for successor in state.transitions.values():
262+
if successor in all_states:
263+
predecessors[successor].append(state)
264+
265+
visited = {root}
266+
stack = [root]
267+
while stack:
268+
for predecessor in predecessors[stack.pop()]:
269+
if predecessor not in visited:
270+
visited.add(predecessor)
271+
stack.append(predecessor)
272+
273+
return visited == all_states
248274

249275
def output_step(self, state, letter):
250276
"""
@@ -453,4 +479,4 @@ def minimize(self):
453479

454480
def __eq__(self, other):
455481
from aalpy.utils import bisimilar
456-
return bisimilar(self, other)
482+
return bisimilar(self, other)

0 commit comments

Comments
 (0)