mCRL2
Loading...
Searching...
No Matches
SCC_impl.h
Go to the documentation of this file.
1// Copyright (c) 2009-2013 University of Twente
2// Copyright (c) 2009-2013 Michael Weber <michaelw@cs.utwente.nl>
3// Copyright (c) 2009-2013 Maks Verver <maksverver@geocities.com>
4// Copyright (c) 2009-2013 Eindhoven University of Technology
5//
6// Distributed under the Boost Software License, Version 1.0.
7// (See accompanying file LICENSE_1_0.txt or copy at
8// http://www.boost.org/LICENSE_1_0.txt)
9
10// Don't include this directly; include SCC.h instead!
11
12
13#ifndef MCRL2_PG_SCC_IMPL_H
14#define MCRL2_PG_SCC_IMPL_H
15
16#include "mcrl2/pg/Graph.h"
17
18
19/*! Implements Tarjan's algorithm for finding strongly connected components in
20 a directed graph.
21
22 Visits each vertex and edge in the graph once, so it has a run-time
23 complexity O(V + E). For each vertex, two items are stored: the vertex index
24 (which denotes the order in which vertices are visited) and a lowest link
25 index, which gives the lowest index of a vertex that is reachable from the
26 current vertex.
27
28 When a vertex has not yet been visited, its index is set to NO_VERTEX.
29 Furthermore, the lowest link index is set to NO_VERTEX if the vertex is not
30 part of the current component.
31
32 Worst-case memory use: 5*sizeof(verti) + c.
33*/
34template<class Callback>
35class SCC
36{
37public:
38 SCC(const StaticGraph &graph, Callback &callback)
39 : graph_(graph), callback_(callback)
40 {
41 }
42
43 int run()
44 {
45 // Initialize data structures used in the algorithm
46 next_index = 0;
47 info.clear();
48 info.insert( info.end(), graph_.V(),
49 std::make_pair(NO_VERTEX, NO_VERTEX) );
50 stack.clear();
51
52 // Process all vertices
53 for (verti v = 0; v < graph_.V();++v)
54 {
55 if (info[v].first == NO_VERTEX)
56 {
57 assert(stack.empty());
58 add(v);
59 int res = dfs();
60 if (res != 0)
61 {
62 return res;
63 }
64 }
65 }
66 assert(stack.empty());
67 return 0;
68 }
69
70private:
71 void add(verti v)
72 {
73 // Mark vertex as visited and part of the current component
74 info[v].first = info[v].second = next_index++;
75 component.push_back(v);
76
77 // Add to stack to be processed in depth-first-search
78 stack.emplace_back(v, 0);
79 }
80
81 /* This implements depth-first-search using a stack, which is a bit more
82 complicated but allows us to process arbitrarily large graphs limited
83 by available heap space only (instead of being limited by the call
84 stack size) as well as conserving some memory. */
85 int dfs()
86 {
87 int res = 0;
88
89 while (res == 0 && !stack.empty())
90 {
91 verti v = stack.back().first;
92 StaticGraph::const_iterator edge_it =
93 graph_.succ_begin(v) + stack.back().second++;
94
95 if (edge_it != graph_.succ_end(v))
96 {
97 // Find next successor `w` of `v`
98 verti w = *edge_it;
99
100 if (info[w].first == NO_VERTEX) // unvisited?
101 {
102 add(w);
103 }
104 else
105 if (info[w].second != NO_VERTEX) // part of current component?
106 {
107 /* Check if w's index is lower than v's lowest link, if so,
108 set it to be our lowest link index. */
109 info[v].second = std::min(info[v].second, info[w].first);
110 }
111 }
112 else
113 {
114 // We're done with this vertex
115 stack.pop_back();
116
117 if (!stack.empty())
118 {
119 /* Push my lower link index to parent vertex `u`, if it
120 is lower than the parent's current lower link index. */
121 int u = stack.back().first;
122 info[u].second = std::min(info[u].second, info[v].second);
123 }
124
125 // Check if v is the component's root (idx == lowest link idx)
126 if (info[v].first == info[v].second)
127 {
128 // Find v in the current component
129 std::vector<verti>::iterator it = component.end();
130 do {
131 assert(it != component.begin());
132 info[*--it].second = NO_VERTEX; // mark as removed
133 } while (*it != v);
134
135 // Call callback functor to handle this component
136 res = callback_((const verti*)&*it, component.end() - it);
137
138 // Remove vertices from current component
139 component.erase(it, component.end());
140 }
141 }
142 }
143
144 return res;
145 }
146
147public:
149 Callback &callback_;
150
151private:
152 //! Index of next vertex to be labelled by inorder traversal.
153 verti next_index = 0UL;
154
155 //! Inorder index and lowest link index of each vertex.
157
158 //! Vertex indices of the current component.
160
161 /*! The depth-first-search stack.
162
163 Each entry consists of a vertex index and an index into its successor
164 list. When a new unvisited vertex `v` is discovered, a pair (`v`, 0)
165 is appened at the end of the stack. The top element is popped off the
166 stack when its successor index points to the end of the successor list.
167 */
169};
170
171#endif // MCRL2_PG_SCC_IMPL_H
void swap(StaticGraph &a, StaticGraph &b) noexcept
Definition Graph.h:304
#define NO_VERTEX
Definition Graph.h:27
void merge_strategies(std::vector< verti > &strategy, const std::vector< verti > &substrat, const std::vector< verti > &vertex_map)
void merge_vertex_maps(ForwardIterator begin, ForwardIterator end, const verti *old_map, verti old_map_size)
void swap(ParityGame &a, ParityGame &b) noexcept
Definition ParityGame.h:327
player_t opponent(const player_t p)
Definition ParityGame.h:42
player_t
Definition ParityGame.h:36
@ PLAYER_ODD
Odd (1)
@ PLAYER_EVEN
Even (0)
bool operator==(const ParityGameVertex &a, const ParityGameVertex &b)
Definition ParityGame.h:70
bool operator!=(const ParityGameVertex &a, const ParityGameVertex &b)
Definition ParityGame.h:75
Factory class for ComponentSolver instances.
const int max_depth_
Maximum recursion depth.
~ComponentSolverFactory() override
ParityGameSolver * create(const ParityGame &game, const verti *vertex_map, verti vertex_map_size) override
Return a new ComponentSolver instance.
ParityGameSolverFactory & pgsf_
Factory used to create subsolvers.
ComponentSolverFactory(ParityGameSolverFactory &pgsf, int max_depth=10)
ParityGame::Strategy solve() override
const verti vmap_size_
Size of vertex map.
const int max_depth_
Max. recusion depth.
std::array< DenseSet< verti > *, 2 > winning_
Resulting winning sets.
ParityGameSolverFactory & pgsf_
Solver factory to use.
~ComponentSolver() override
ComponentSolver(const ParityGame &game, ParityGameSolverFactory &pgsf, int max_depth, const verti *vmap=nullptr, verti vmap_size=0)
const verti * vmap_
Current vertex map.
int operator()(const verti *vertices, std::size_t num_vertices)
ParityGame::Strategy strategy_
Resulting strategy.
void set_vec_to_top(verti v) override
const verti * vec(verti v) const override
void set_vec(verti v, const verti *src, bool carry) override
verti * spm_
array storing the SPM vector data
DenseSPM(const ParityGame &game, ParityGame::Player player, LiftingStatistics *stats=nullptr, const verti *vertex_map=nullptr, verti vertex_map_size=0)
bool operator>(const Iterator &other) const
Definition DenseSet.h:67
const DenseSet * set_
Definition DenseSet.h:43
Iterator & operator++()
Definition DenseSet.h:73
bool operator<=(const Iterator &other) const
Definition DenseSet.h:68
Iterator(const Iterator &it)
Definition DenseSet.h:57
bool operator!=(const Iterator &other) const
Definition DenseSet.h:65
Iterator & operator=(const Iterator &it)=default
bool operator==(const Iterator &other) const
Definition DenseSet.h:64
value_type operator*()
Definition DenseSet.h:71
Iterator & operator++(int)
Definition DenseSet.h:82
bool operator>=(const Iterator &other) const
Definition DenseSet.h:69
Iterator(const DenseSet *set, Key key)
Definition DenseSet.h:53
bool operator<(const Iterator &other) const
Definition DenseSet.h:66
const_iterator end() const
Definition DenseSet.h:154
const Key range_end
Definition DenseSet.h:207
bool * used_
Definition DenseSet.h:212
iterator begin()
Definition DenseSet.h:134
DenseSet(Key begin, Key end, const Alloc &alloc=Alloc())
Definition DenseSet.h:95
DenseSet(const DenseSet &)=delete
~DenseSet()
Definition DenseSet.h:107
bool empty() const
Definition DenseSet.h:117
const Key range_begin
Definition DenseSet.h:207
const_iterator begin() const
Definition DenseSet.h:149
size_type count(const Key &k) const
Definition DenseSet.h:176
iterator find(const Key &k)
Definition DenseSet.h:159
std::pair< iterator, bool > insert(const Key &k)
Definition DenseSet.h:181
const size_type range_size_
Definition DenseSet.h:210
void insert(InputIterator it, InputIterator end)
Definition DenseSet.h:197
std::size_t num_used_
Definition DenseSet.h:213
Alloc alloc_
Definition DenseSet.h:211
size_type size() const
Definition DenseSet.h:112
const_iterator find(const Key &k) const
Definition DenseSet.h:171
DenseSet & operator=(const DenseSet &)=delete
void clear()
Definition DenseSet.h:122
iterator end()
Definition DenseSet.h:144
long long lifts_attempted() const
LiftingStatistics(const ParityGame &game, long long max_lifts=-1)
void add_lifts_succeeded(long long count)
void add_lifts_attempted(long long count)
void add_lifts_succeeded(verti v, long long count)
long long lifts_attempted(verti v) const
void record_lift(verti v, bool success)
long long lifts_succeeded() const
long long lifts_succeeded(verti v) const
void add_lifts_attempted(verti v, long long count)
virtual void push(verti vertex)=0
virtual verti pop()=0
virtual void bump(verti vertex)=0
virtual ~LiftingStrategy2()=default
~LiftingStrategyFactory() override
virtual LiftingStrategy * create(const ParityGame &game, const SmallProgressMeasures &spm)=0
static LiftingStrategyFactory * create(const std::string &description)
static const char * usage()
virtual bool supports_version(int version)
virtual LiftingStrategy2 * create2(const ParityGame &, const SmallProgressMeasures &)
virtual void lifted(verti vertex)=0
virtual ~LiftingStrategy()=default
virtual verti next()=0
virtual ParityGameSolver * create(const ParityGame &game, const verti *vertex_map=nullptr, verti vertex_map_size=0)=0
~ParityGameSolverFactory() override=default
const ParityGame & game() const
~ParityGameSolver() override=default
const ParityGame & game_
Game being solved.
ParityGameSolver(const ParityGame &game)
virtual ParityGame::Strategy solve()=0
priority_t priority(verti v) const
Definition ParityGame.h:257
ParityGame()=default
void compress_priorities(const verti *cardinality=nullptr, bool preserve_parity=true)
void read_pbes(const std::string &file_path, verti *goal_vertex=nullptr, StaticGraph::EdgeDirection edge_dir=StaticGraph::EdgeDirection::EDGE_BIDIRECTIONAL, const std::string &rewrite_strategy="jitty")
void read_pgsolver(std::istream &is, StaticGraph::EdgeDirection edge_dir=StaticGraph::EdgeDirection::EDGE_BIDIRECTIONAL)
verti cardinality(int p) const
Definition ParityGame.h:264
priority_t d() const
Definition ParityGame.h:251
void clear()
void make_subgame(const ParityGame &game, ForwardIterator vertices_begin, ForwardIterator vertices_end, bool proper, StaticGraph::EdgeDirection edge_dir=StaticGraph::EdgeDirection::EDGE_NONE)
Player player(verti v) const
Definition ParityGame.h:260
bool empty() const
Definition ParityGame.h:117
ParityGame(const ParityGame &game)
void swap(ParityGame &pg) noexcept
void reset(verti V, int d)
long long propagate_priorities()
ParityGame & operator=(const ParityGame &game)
void write_pgsolver(std::ostream &os) const
StaticGraph graph_
Definition ParityGame.h:317
void assign(const ParityGame &game)
verti * cardinality_
Definition ParityGame.h:324
bool proper() const
void write_dot(std::ostream &os) const
void shuffle(const std::vector< verti > &perm)
void assign_pbes(mcrl2::pbes_system::pbes &pbes, verti *goal_vertex=nullptr, StaticGraph::EdgeDirection edge_dir=StaticGraph::EdgeDirection::EDGE_BIDIRECTIONAL, const std::string &rewrite_strategy="jitty")
void read_raw(std::istream &is)
void write_debug(const Strategy &s=Strategy(), std::ostream &os=std::cerr) const
void write_raw(std::ostream &os) const
void recalculate_cardinalities(verti num_vertices)
bool verify(const Strategy &s, verti *error) const
Player winner(const StrategyT &s, verti v) const
int propagate_priority(verti v, StaticGraph::const_iterator it, StaticGraph::const_iterator end)
void make_dual()
ParityGameVertex * vertex_
Definition ParityGame.h:320
void assign(const StaticGraph &g, ParityGameVertex *na)
const StaticGraph & graph() const
Definition ParityGame.h:254
void make_random(verti V, unsigned clustersize, unsigned outdeg, StaticGraph::EdgeDirection edge_dir, int d)
Definition SCC_impl.h:36
verti next_index
Index of next vertex to be labelled by inorder traversal.
Definition SCC_impl.h:153
const StaticGraph & graph_
Definition SCC_impl.h:148
int dfs()
Definition SCC_impl.h:85
void add(verti v)
Definition SCC_impl.h:71
Callback & callback_
Definition SCC_impl.h:149
SCC(const StaticGraph &graph, Callback &callback)
Definition SCC_impl.h:38
std::vector< verti > component
Vertex indices of the current component.
Definition SCC_impl.h:159
int run()
Definition SCC_impl.h:43
Definition SCC.h:54
int operator()(const verti *scc, std::size_t size)
Definition SCC.h:74
const std::vector< verti > & operator[](std::size_t i) const
Definition SCC.h:68
std::vector< verti > & operator[](std::size_t i)
Definition SCC.h:65
std::size_t size() const
Definition SCC.h:62
void clear()
Clear the list of collected SCCs.
Definition SCC.h:59
ParityGame::Strategy solve_normal() override
ParityGame::Strategy solve_alternate() override
SmallProgressMeasuresSolver2 & operator=(const SmallProgressMeasuresSolver2 &)=delete
SmallProgressMeasuresSolver2(const ParityGame &game, std::shared_ptr< LiftingStrategyFactory > lsf, bool alternate=false, LiftingStatistics *stats=nullptr, const verti *vmap=nullptr, verti vmap_size=0)
SmallProgressMeasuresSolver2(const SmallProgressMeasuresSolver2 &)=delete
std::shared_ptr< LiftingStrategyFactory > lsf_
ParityGameSolver * create(const ParityGame &game, const verti *vmap, verti vmap_size) override
SmallProgressMeasuresSolverFactory(std::shared_ptr< LiftingStrategyFactory > lsf, int version=1, bool alt=false, LiftingStatistics *stats=nullptr)
bool alternate_
whether to use the alternate algorithm
ParityGame::Strategy solve() override
const verti vmap_size_
size of vertex map
virtual ParityGame::Strategy solve_normal()
std::shared_ptr< LiftingStrategyFactory > lsf_
factory used to create lifting strategy
SmallProgressMeasuresSolver(const ParityGame &game, std::shared_ptr< LiftingStrategyFactory > lsf, bool alternate=false, LiftingStatistics *stats=nullptr, const verti *vmap=nullptr, verti vmap_size=0)
SmallProgressMeasuresSolver & operator=(const SmallProgressMeasuresSolver &)=delete
virtual ParityGame::Strategy solve_alternate()
LiftingStatistics * stats_
object to record lifting statistics
const verti * vmap_
current vertex map
static void preprocess_game(ParityGame &game)
SmallProgressMeasuresSolver(const SmallProgressMeasuresSolver &)=delete
void debug_print_vertex(int v) const
long long solve_some(LiftingStrategy2 &ls, long long attempts=work_size)
long long solve_some(LiftingStrategy &ls, long long attempts=work_size)
bool less_than(verti v, const verti *vec2, bool carry=false)
const verti * vmap_
active vertex map (if any)
LiftingStatistics * stats_
statistics object to record lifts
const std::size_t p_
the player to solve for
verti solve_one(LiftingStrategy2 &ls)
SmallProgressMeasures & operator=(const SmallProgressMeasures &)
bool is_top(const verti *vec) const
void get_strategy(ParityGame::Strategy &strat) const
verti * M_
bounds on the SPM vector components
virtual void set_vec(verti v, const verti *src, bool carry)=0
bool take_max(verti v) const
verti get_max_succ(verti v) const
void set_M(const verti *new_M)
std::size_t len_
length of SPM vectors
SmallProgressMeasures(const ParityGame &game, ParityGame::Player player, LiftingStatistics *stats=nullptr, const verti *vmap=nullptr, verti vmap_size=0)
virtual void set_vec_to_top(verti v)=0
verti get_min_succ(verti v) const
const verti * M() const
SmallProgressMeasures(const SmallProgressMeasures &)
void debug_print() const
bool compare_strict(verti v) const
int vector_cmp(verti v, verti w, int N) const
verti get_ext_succ(verti v) const
bool is_dirty(verti v) const
int vector_cmp(const verti *vec1, const verti *vec2, int N) const
void get_winning_set(ParityGame::Player player, OutputIterator result)
const ParityGame & game() const
bool * dirty_
marks unstable vertices
ParityGame::Player player() const
std::pair< verti, bool > solve_one(LiftingStrategy &ls)
verti vmap_size_
size of vertex map
static const int work_size
Maximum number of lifting attempts in a row before checking timer.
verti get_successor(verti v) const
verti get_strategy(verti v) const
void initialize_lifting_strategy(LiftingStrategy2 &ls)
const ParityGame & game_
the game being solved
verti get_ext_succ(verti v, bool take_max) const
bool lift_to(verti v, const verti *vec2, bool carry=false)
ParityGame::Strategy strategy_
current strategy
virtual const verti * vec(verti v) const =0
StaticGraph(const StaticGraph &graph)=delete
void make_random(verti V, unsigned outdeg, EdgeDirection edge_dir, bool scc)
Definition Graph.cpp:146
void swap(StaticGraph &g) noexcept
Definition Graph.cpp:554
verti * successors_
Definition Graph.h:286
edgei degree(verti v) const
Definition Graph.h:226
const_iterator succ_end(verti v) const
Definition Graph.h:201
~StaticGraph()
Definition Graph.cpp:21
void reset(verti V, edgei E, EdgeDirection edge_dir)
Definition Graph.cpp:34
edgei indegree(verti v) const
Definition Graph.h:236
EdgeDirection edge_dir() const
Definition Graph.h:193
void make_subgraph_threads(const StaticGraph &graph, const verti *verts, verti nvert, bool proper, EdgeDirection edge_dir=EdgeDirection::EDGE_NONE)
edgei * predecessor_index_
Definition Graph.h:291
verti V_
Definition Graph.h:279
void make_random_clustered(verti cluster_size, verti V, unsigned outdeg, EdgeDirection edge_dir)
Definition Graph.cpp:205
void read_raw(std::istream &is)
Definition Graph.cpp:530
const_iterator succ_begin(verti v) const
Definition Graph.h:196
void assign(edge_list edges, EdgeDirection edge_dir)
Definition Graph.cpp:325
void make_subgraph(const StaticGraph &graph, ForwardIterator vertices_begin, ForwardIterator vertices_end, VertexMapT &vertex_map, bool proper, EdgeDirection edge_dir=EdgeDirection::EDGE_NONE)
Definition Graph_impl.h:76
void make_random_scc(edge_list &edges)
Definition Graph.cpp:88
bool has_succ(verti v, verti w) const
Definition Graph.h:216
edgei * successor_index_
Definition Graph.h:291
void write_raw(std::ostream &os) const
Definition Graph.cpp:513
verti V() const
Definition Graph.h:187
friend constexpr bool operator&(EdgeDirection a, EdgeDirection b)
Definition Graph.h:94
edge_list get_edges() const
Definition Graph.cpp:493
void assign(const StaticGraph &graph)
Definition Graph.cpp:302
verti * predecessors_
Definition Graph.h:286
void remove_edges(edge_list &edges)
Definition Graph.cpp:400
StaticGraph & operator=(const StaticGraph &graph)=delete
void make_subgraph(const StaticGraph &graph, ForwardIterator vertices_begin, ForwardIterator vertices_end, bool proper, EdgeDirection edge_dir=EdgeDirection::EDGE_NONE)
Definition Graph_impl.h:52
void shuffle_vertices(const std::vector< verti > &perm)
Definition Graph.cpp:291
const_iterator pred_begin(verti v) const
Definition Graph.h:206
void shuffle_vertices()
Definition Graph.cpp:280
EdgeDirection
Definition Graph.h:84
void clear()
Definition Graph.cpp:29
bool has_pred(verti w, verti v) const
Definition Graph.h:221
const_iterator pred_end(verti v) const
Definition Graph.h:211
edgei outdegree(verti v) const
Definition Graph.h:231
bool empty() const
Definition Graph.h:184
EdgeDirection edge_dir_
Definition Graph.h:294
edgei E_
Definition Graph.h:280
StaticGraph()
Definition Graph.cpp:16
edgei E() const
Definition Graph.h:190
parameterized boolean equation system
Definition pbes.h:54
int decompose_graph(const StaticGraph &graph, Callback &callback)
Definition SCC.h:32
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:435
player_t player
the vertex owner (i.e. next player to move)
Definition ParityGame.h:64
priority_t priority
the priority of the vertex between 0 and d (exclusive).
Definition ParityGame.h:67
std::size_t operator()(const std::vector< X > &v) const