1 | //======================================================================= |
---|
2 | // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. |
---|
3 | // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek |
---|
4 | // |
---|
5 | // Distributed under the Boost Software License, Version 1.0. (See |
---|
6 | // accompanying file LICENSE_1_0.txt or copy at |
---|
7 | // http://www.boost.org/LICENSE_1_0.txt) |
---|
8 | //======================================================================= |
---|
9 | /* |
---|
10 | |
---|
11 | Paul Moore's request: |
---|
12 | |
---|
13 | As an example of a practical problem which is not restricted to graph |
---|
14 | "experts", consider file dependencies. It's basically graph construction, |
---|
15 | plus topological sort, but it might make a nice "tutorial" example. Build a |
---|
16 | dependency graph of files, then use the algorithms to do things like |
---|
17 | |
---|
18 | 1. Produce a full recompilation order (topological sort, by modified date) |
---|
19 | 2. Produce a "parallel" recompilation order (same as above, but group files |
---|
20 | which can be built in parallel) |
---|
21 | 3. Change analysis (if I change file x, which others need recompiling) |
---|
22 | 4. Dependency changes (if I add a dependency between file x and file y, what |
---|
23 | are the effects) |
---|
24 | |
---|
25 | */ |
---|
26 | |
---|
27 | #include <boost/config.hpp> // put this first to suppress some VC++ warnings |
---|
28 | |
---|
29 | #include <iostream> |
---|
30 | #include <iterator> |
---|
31 | #include <algorithm> |
---|
32 | #include <time.h> |
---|
33 | |
---|
34 | #include <boost/utility.hpp> |
---|
35 | #include <boost/graph/adjacency_list.hpp> |
---|
36 | #include <boost/graph/topological_sort.hpp> |
---|
37 | #include <boost/graph/depth_first_search.hpp> |
---|
38 | #include <boost/graph/dijkstra_shortest_paths.hpp> |
---|
39 | #include <boost/graph/visitors.hpp> |
---|
40 | |
---|
41 | using namespace std; |
---|
42 | using namespace boost; |
---|
43 | |
---|
44 | enum files_e { dax_h, yow_h, boz_h, zow_h, foo_cpp, |
---|
45 | foo_o, bar_cpp, bar_o, libfoobar_a, |
---|
46 | zig_cpp, zig_o, zag_cpp, zag_o, |
---|
47 | libzigzag_a, killerapp, N }; |
---|
48 | const char* name[] = { "dax.h", "yow.h", "boz.h", "zow.h", "foo.cpp", |
---|
49 | "foo.o", "bar.cpp", "bar.o", "libfoobar.a", |
---|
50 | "zig.cpp", "zig.o", "zag.cpp", "zag.o", |
---|
51 | "libzigzag.a", "killerapp" }; |
---|
52 | |
---|
53 | |
---|
54 | struct print_visitor : public bfs_visitor<> { |
---|
55 | template <class Vertex, class Graph> |
---|
56 | void discover_vertex(Vertex v, Graph&) { |
---|
57 | cout << name[v] << " "; |
---|
58 | } |
---|
59 | }; |
---|
60 | |
---|
61 | |
---|
62 | struct cycle_detector : public dfs_visitor<> |
---|
63 | { |
---|
64 | cycle_detector(bool& has_cycle) |
---|
65 | : m_has_cycle(has_cycle) { } |
---|
66 | |
---|
67 | template <class Edge, class Graph> |
---|
68 | void back_edge(Edge, Graph&) { m_has_cycle = true; } |
---|
69 | protected: |
---|
70 | bool& m_has_cycle; |
---|
71 | }; |
---|
72 | |
---|
73 | |
---|
74 | |
---|
75 | |
---|
76 | int main(int,char*[]) |
---|
77 | { |
---|
78 | |
---|
79 | typedef pair<int,int> Edge; |
---|
80 | Edge used_by[] = { |
---|
81 | Edge(dax_h, foo_cpp), Edge(dax_h, bar_cpp), Edge(dax_h, yow_h), |
---|
82 | Edge(yow_h, bar_cpp), Edge(yow_h, zag_cpp), |
---|
83 | Edge(boz_h, bar_cpp), Edge(boz_h, zig_cpp), Edge(boz_h, zag_cpp), |
---|
84 | Edge(zow_h, foo_cpp), |
---|
85 | Edge(foo_cpp, foo_o), |
---|
86 | Edge(foo_o, libfoobar_a), |
---|
87 | Edge(bar_cpp, bar_o), |
---|
88 | Edge(bar_o, libfoobar_a), |
---|
89 | Edge(libfoobar_a, libzigzag_a), |
---|
90 | Edge(zig_cpp, zig_o), |
---|
91 | Edge(zig_o, libzigzag_a), |
---|
92 | Edge(zag_cpp, zag_o), |
---|
93 | Edge(zag_o, libzigzag_a), |
---|
94 | Edge(libzigzag_a, killerapp) |
---|
95 | }; |
---|
96 | const std::size_t nedges = sizeof(used_by)/sizeof(Edge); |
---|
97 | int weights[nedges]; |
---|
98 | std::fill(weights, weights + nedges, 1); |
---|
99 | |
---|
100 | typedef adjacency_list<vecS, vecS, directedS, |
---|
101 | property<vertex_color_t, default_color_type>, |
---|
102 | property<edge_weight_t, int> |
---|
103 | > Graph; |
---|
104 | #if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 |
---|
105 | // VC++ can't handle the iterator constructor |
---|
106 | Graph g(N); |
---|
107 | property_map<Graph, edge_weight_t>::type weightmap = get(edge_weight, g); |
---|
108 | for (std::size_t j = 0; j < nedges; ++j) { |
---|
109 | graph_traits<Graph>::edge_descriptor e; bool inserted; |
---|
110 | tie(e, inserted) = add_edge(used_by[j].first, used_by[j].second, g); |
---|
111 | weightmap[e] = weights[j]; |
---|
112 | } |
---|
113 | #else |
---|
114 | Graph g(used_by, used_by + nedges, weights, N); |
---|
115 | #endif |
---|
116 | typedef graph_traits<Graph>::vertex_descriptor Vertex; |
---|
117 | |
---|
118 | // Determine ordering for a full recompilation |
---|
119 | { |
---|
120 | typedef list<Vertex> MakeOrder; |
---|
121 | MakeOrder make_order; |
---|
122 | topological_sort(g, std::front_inserter(make_order)); |
---|
123 | |
---|
124 | cout << "make ordering: "; |
---|
125 | for (MakeOrder::iterator i = make_order.begin(); |
---|
126 | i != make_order.end(); ++i) |
---|
127 | cout << name[*i] << " "; |
---|
128 | cout << endl; |
---|
129 | } |
---|
130 | cout << endl; |
---|
131 | |
---|
132 | // Recompilation order with files that can be compiled in parallel |
---|
133 | // grouped together |
---|
134 | { |
---|
135 | // Set up the necessary graph properties. |
---|
136 | vector<int> time(N); |
---|
137 | typedef vector<int>::iterator Time; |
---|
138 | property_map<Graph, edge_weight_t>::type weight = get(edge_weight, g); |
---|
139 | |
---|
140 | // Calculate the in_degree for each vertex. |
---|
141 | vector<int> in_degree(N, 0); |
---|
142 | graph_traits<Graph>::vertex_iterator i, iend; |
---|
143 | graph_traits<Graph>::out_edge_iterator j, jend; |
---|
144 | for (tie(i, iend) = vertices(g); i != iend; ++i) |
---|
145 | for (tie(j, jend) = out_edges(*i,g); j != jend; ++j) |
---|
146 | in_degree[target(*j,g)] += 1; |
---|
147 | |
---|
148 | std::greater<int> compare; |
---|
149 | closed_plus<int> combine; |
---|
150 | |
---|
151 | // Run best-first-search from each vertex with zero in-degree. |
---|
152 | for (tie(i, iend) = vertices(g); i != iend; ++i) { |
---|
153 | if (in_degree[*i] == 0) { |
---|
154 | std::vector<graph_traits<Graph>::vertex_descriptor> |
---|
155 | pred(num_vertices(g)); |
---|
156 | property_map<Graph, vertex_index_t>::type |
---|
157 | indexmap = get(vertex_index, g); |
---|
158 | dijkstra_shortest_paths_no_init |
---|
159 | (g, *i, &pred[0], &time[0], weight, indexmap, |
---|
160 | compare, combine, 0, // Since we are using > instead of >, we |
---|
161 | (std::numeric_limits<int>::max)(), // flip 0 and inf. |
---|
162 | default_dijkstra_visitor()); |
---|
163 | } |
---|
164 | } |
---|
165 | |
---|
166 | cout << "parallel make ordering, " << endl |
---|
167 | << "vertices with same group number can be made in parallel" << endl; |
---|
168 | for (tie(i,iend) = vertices(g); i != iend; ++i) |
---|
169 | cout << "time_slot[" << name[*i] << "] = " << time[*i] << endl; |
---|
170 | } |
---|
171 | cout << endl; |
---|
172 | |
---|
173 | // if I change yow.h what files need to be re-made? |
---|
174 | { |
---|
175 | cout << "A change to yow.h will cause what to be re-made?" << endl; |
---|
176 | print_visitor vis; |
---|
177 | breadth_first_search(g, vertex(yow_h, g), visitor(vis)); |
---|
178 | cout << endl; |
---|
179 | } |
---|
180 | cout << endl; |
---|
181 | |
---|
182 | // are there any cycles in the graph? |
---|
183 | { |
---|
184 | bool has_cycle = false; |
---|
185 | cycle_detector vis(has_cycle); |
---|
186 | depth_first_search(g, visitor(vis)); |
---|
187 | cout << "The graph has a cycle? " << has_cycle << endl; |
---|
188 | } |
---|
189 | cout << endl; |
---|
190 | |
---|
191 | // add a dependency going from bar.cpp to dax.h |
---|
192 | { |
---|
193 | cout << "adding edge bar_cpp -> dax_h" << endl; |
---|
194 | add_edge(bar_cpp, dax_h, g); |
---|
195 | } |
---|
196 | cout << endl; |
---|
197 | |
---|
198 | // are there any cycles in the graph? |
---|
199 | { |
---|
200 | bool has_cycle = false; |
---|
201 | cycle_detector vis(has_cycle); |
---|
202 | depth_first_search(g, visitor(vis)); |
---|
203 | cout << "The graph has a cycle now? " << has_cycle << endl; |
---|
204 | } |
---|
205 | |
---|
206 | return 0; |
---|
207 | } |
---|