Chris@16
|
1 // Copyright 2005 The Trustees of Indiana University.
|
Chris@16
|
2
|
Chris@16
|
3 // Use, modification and distribution is subject to the Boost Software
|
Chris@16
|
4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
5 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
6
|
Chris@16
|
7 // Authors: Alex Breuer
|
Chris@16
|
8 // Andrew Lumsdaine
|
Chris@16
|
9 #ifndef BOOST_GRAPH_DIMACS_HPP
|
Chris@16
|
10 #define BOOST_GRAPH_DIMACS_HPP
|
Chris@16
|
11
|
Chris@16
|
12 #include <string>
|
Chris@16
|
13 #include <sstream>
|
Chris@16
|
14 #include <iostream>
|
Chris@16
|
15 #include <fstream>
|
Chris@16
|
16 #include <iterator>
|
Chris@16
|
17 #include <exception>
|
Chris@16
|
18 #include <vector>
|
Chris@16
|
19 #include <queue>
|
Chris@16
|
20 #include <boost/assert.hpp>
|
Chris@16
|
21
|
Chris@16
|
22 namespace boost { namespace graph {
|
Chris@16
|
23
|
Chris@16
|
24 class dimacs_exception : public std::exception {};
|
Chris@16
|
25
|
Chris@16
|
26 class dimacs_basic_reader {
|
Chris@16
|
27 public:
|
Chris@16
|
28 typedef std::size_t vertices_size_type;
|
Chris@16
|
29 typedef std::size_t edges_size_type;
|
Chris@16
|
30 typedef double vertex_weight_type;
|
Chris@16
|
31 typedef double edge_weight_type;
|
Chris@16
|
32 typedef std::pair<vertices_size_type,
|
Chris@16
|
33 vertices_size_type> edge_type;
|
Chris@16
|
34 enum incr_mode {edge, edge_weight};
|
Chris@16
|
35
|
Chris@16
|
36 dimacs_basic_reader( std::istream& in, bool want_weights = true ) :
|
Chris@16
|
37 inpt( in ), seen_edges( 0 ), want_weights(want_weights)
|
Chris@16
|
38 {
|
Chris@16
|
39 while( getline( inpt, buf ) && !buf.empty() && buf[0] == 'c' );
|
Chris@16
|
40
|
Chris@16
|
41 if( buf[0] != 'p' ) {
|
Chris@16
|
42 boost::throw_exception(dimacs_exception());
|
Chris@16
|
43 }
|
Chris@16
|
44
|
Chris@16
|
45 std::stringstream instr( buf );
|
Chris@16
|
46 std::string junk;
|
Chris@16
|
47
|
Chris@16
|
48 instr >> junk >> junk >> num_vertices >> num_edges;
|
Chris@16
|
49 read_edge_weights.push( -1 );
|
Chris@16
|
50 incr( edge_weight );
|
Chris@16
|
51 }
|
Chris@16
|
52
|
Chris@16
|
53 //for a past the end iterator
|
Chris@16
|
54 dimacs_basic_reader() : inpt( std::cin ), num_vertices( 0 ),
|
Chris@16
|
55 num_edges( 0 ), seen_edges( 0 ), want_weights(false) {}
|
Chris@16
|
56
|
Chris@16
|
57 edge_type edge_deref() {
|
Chris@16
|
58 BOOST_ASSERT( !read_edges.empty() );
|
Chris@16
|
59 return read_edges.front();
|
Chris@16
|
60 }
|
Chris@16
|
61
|
Chris@16
|
62 inline edge_type* edge_ref() {
|
Chris@16
|
63 BOOST_ASSERT( !read_edges.empty() );
|
Chris@16
|
64 return &read_edges.front();
|
Chris@16
|
65 }
|
Chris@16
|
66
|
Chris@16
|
67 inline edge_weight_type edge_weight_deref() {
|
Chris@16
|
68 BOOST_ASSERT( !read_edge_weights.empty() );
|
Chris@16
|
69 return read_edge_weights.front();
|
Chris@16
|
70 }
|
Chris@16
|
71
|
Chris@16
|
72 inline dimacs_basic_reader incr( incr_mode mode ) {
|
Chris@16
|
73 if( mode == edge ) {
|
Chris@16
|
74 BOOST_ASSERT( !read_edges.empty() );
|
Chris@16
|
75 read_edges.pop();
|
Chris@16
|
76 }
|
Chris@16
|
77 else if( mode == edge_weight ) {
|
Chris@16
|
78 BOOST_ASSERT( !read_edge_weights.empty() );
|
Chris@16
|
79 read_edge_weights.pop();
|
Chris@16
|
80 }
|
Chris@16
|
81
|
Chris@16
|
82 if( (mode == edge && read_edges.empty()) ||
|
Chris@16
|
83 (mode == edge_weight && read_edge_weights.empty() )) {
|
Chris@16
|
84
|
Chris@16
|
85 if( seen_edges > num_edges ) {
|
Chris@16
|
86 boost::throw_exception(dimacs_exception());
|
Chris@16
|
87 }
|
Chris@16
|
88
|
Chris@16
|
89 while( getline( inpt, buf ) && !buf.empty() && buf[0] == 'c' );
|
Chris@16
|
90
|
Chris@16
|
91 if( !inpt.eof() ) {
|
Chris@16
|
92 int source, dest, weight;
|
Chris@16
|
93 read_edge_line((char*) buf.c_str(), source, dest, weight);
|
Chris@16
|
94
|
Chris@16
|
95 seen_edges++;
|
Chris@16
|
96 source--;
|
Chris@16
|
97 dest--;
|
Chris@16
|
98
|
Chris@16
|
99 read_edges.push( edge_type( source, dest ) );
|
Chris@16
|
100 if (want_weights) {
|
Chris@16
|
101 read_edge_weights.push( weight );
|
Chris@16
|
102 }
|
Chris@16
|
103 }
|
Chris@16
|
104 BOOST_ASSERT( read_edges.size() < 100 );
|
Chris@16
|
105 BOOST_ASSERT( read_edge_weights.size() < 100 );
|
Chris@16
|
106 }
|
Chris@16
|
107
|
Chris@16
|
108 // the 1000000 just happens to be about how many edges can be read in
|
Chris@16
|
109 // 10s
|
Chris@16
|
110 // if( !(seen_edges % 1000000) && !process_id( pg ) && mode == edge ) {
|
Chris@16
|
111 // std::cout << "read " << seen_edges << " edges" << std::endl;
|
Chris@16
|
112 // }
|
Chris@16
|
113 return *this;
|
Chris@16
|
114 }
|
Chris@16
|
115
|
Chris@16
|
116 inline bool done_edges() {
|
Chris@16
|
117 return inpt.eof() && read_edges.size() == 0;
|
Chris@16
|
118 }
|
Chris@16
|
119
|
Chris@16
|
120 inline bool done_edge_weights() {
|
Chris@16
|
121 return inpt.eof() && read_edge_weights.size() == 0;
|
Chris@16
|
122 }
|
Chris@16
|
123
|
Chris@16
|
124 inline vertices_size_type n_vertices() {
|
Chris@16
|
125 return num_vertices;
|
Chris@16
|
126 }
|
Chris@16
|
127
|
Chris@16
|
128 inline vertices_size_type processed_edges() {
|
Chris@16
|
129 return seen_edges - read_edges.size();
|
Chris@16
|
130 }
|
Chris@16
|
131
|
Chris@16
|
132 inline vertices_size_type processed_edge_weights() {
|
Chris@16
|
133 return seen_edges - read_edge_weights.size();
|
Chris@16
|
134 }
|
Chris@16
|
135
|
Chris@16
|
136 inline vertices_size_type n_edges() {
|
Chris@16
|
137 return num_edges;
|
Chris@16
|
138 }
|
Chris@16
|
139
|
Chris@16
|
140 protected:
|
Chris@16
|
141 bool read_edge_line(char *linebuf, int &from, int &to, int &weight)
|
Chris@16
|
142 {
|
Chris@16
|
143 char *fs = NULL, *ts = NULL, *ws = NULL;
|
Chris@16
|
144 char *tmp = linebuf + 2;
|
Chris@16
|
145
|
Chris@16
|
146 fs = tmp;
|
Chris@16
|
147 if ('e' == linebuf[0]) {
|
Chris@16
|
148 while (*tmp != '\n' && *tmp != '\0') {
|
Chris@16
|
149 if (*tmp == ' ') {
|
Chris@16
|
150 *tmp = '\0';
|
Chris@16
|
151 ts = ++tmp;
|
Chris@16
|
152 break;
|
Chris@16
|
153 }
|
Chris@16
|
154 tmp++;
|
Chris@16
|
155 }
|
Chris@16
|
156 *tmp = '\0';
|
Chris@16
|
157 if (NULL == fs || NULL == ts) return false;
|
Chris@16
|
158 from = atoi(fs); to = atoi(ts); weight = 0;
|
Chris@16
|
159
|
Chris@16
|
160 } else if ('a' == linebuf[0]) {
|
Chris@16
|
161 while (*tmp != '\n' && *tmp != '\0') {
|
Chris@16
|
162 if (*tmp == ' ') {
|
Chris@16
|
163 *tmp = '\0';
|
Chris@16
|
164 ts = ++tmp;
|
Chris@16
|
165 break;
|
Chris@16
|
166 }
|
Chris@16
|
167 tmp++;
|
Chris@16
|
168 }
|
Chris@16
|
169 while (*tmp != '\n' && *tmp != '\0') {
|
Chris@16
|
170 if (*tmp == ' ') {
|
Chris@16
|
171 *tmp = '\0';
|
Chris@16
|
172 ws = ++tmp;
|
Chris@16
|
173 break;
|
Chris@16
|
174 }
|
Chris@16
|
175 tmp++;
|
Chris@16
|
176 }
|
Chris@16
|
177 while (*tmp != '\n' && *tmp != '\0') tmp++;
|
Chris@16
|
178 *tmp = '\0';
|
Chris@16
|
179 if (fs == NULL || ts == NULL || ws == NULL) return false;
|
Chris@16
|
180 from = atoi(fs); to = atoi(ts) ;
|
Chris@16
|
181 if (want_weights) weight = atoi(ws); else weight = 0;
|
Chris@16
|
182
|
Chris@16
|
183 } else {
|
Chris@16
|
184 return false;
|
Chris@16
|
185 }
|
Chris@16
|
186
|
Chris@16
|
187 return true;
|
Chris@16
|
188 }
|
Chris@16
|
189
|
Chris@16
|
190 std::queue<edge_type> read_edges;
|
Chris@16
|
191 std::queue<edge_weight_type> read_edge_weights;
|
Chris@16
|
192
|
Chris@16
|
193 std::istream& inpt;
|
Chris@16
|
194 std::string buf;
|
Chris@16
|
195 vertices_size_type num_vertices, num_edges, seen_edges;
|
Chris@16
|
196 bool want_weights;
|
Chris@16
|
197 };
|
Chris@16
|
198
|
Chris@16
|
199 template<typename T>
|
Chris@16
|
200 class dimacs_edge_iterator {
|
Chris@16
|
201 public:
|
Chris@16
|
202 typedef dimacs_basic_reader::edge_type edge_type;
|
Chris@16
|
203 typedef dimacs_basic_reader::incr_mode incr_mode;
|
Chris@16
|
204
|
Chris@16
|
205 typedef std::input_iterator_tag iterator_category;
|
Chris@16
|
206 typedef edge_type value_type;
|
Chris@16
|
207 typedef value_type reference;
|
Chris@16
|
208 typedef edge_type* pointer;
|
Chris@16
|
209 typedef std::ptrdiff_t difference_type;
|
Chris@16
|
210
|
Chris@16
|
211 dimacs_edge_iterator( T& reader ) :
|
Chris@16
|
212 reader( reader ) {}
|
Chris@16
|
213
|
Chris@16
|
214 inline dimacs_edge_iterator& operator++() {
|
Chris@16
|
215 reader.incr( dimacs_basic_reader::edge );
|
Chris@16
|
216 return *this;
|
Chris@16
|
217 }
|
Chris@16
|
218
|
Chris@16
|
219 inline edge_type operator*() {
|
Chris@16
|
220 return reader.edge_deref();
|
Chris@16
|
221 }
|
Chris@16
|
222
|
Chris@16
|
223 inline edge_type* operator->() {
|
Chris@16
|
224 return reader.edge_ref();
|
Chris@16
|
225 }
|
Chris@16
|
226
|
Chris@16
|
227 // don't expect this to do the right thing if you're not comparing against a
|
Chris@16
|
228 // general past-the-end-iterator made with the default constructor for
|
Chris@16
|
229 // dimacs_basic_reader
|
Chris@16
|
230 inline bool operator==( dimacs_edge_iterator arg ) {
|
Chris@16
|
231 if( reader.n_vertices() == 0 ) {
|
Chris@16
|
232 return arg.reader.done_edges();
|
Chris@16
|
233 }
|
Chris@16
|
234 else if( arg.reader.n_vertices() == 0 ) {
|
Chris@16
|
235 return reader.done_edges();
|
Chris@16
|
236 }
|
Chris@16
|
237 else {
|
Chris@16
|
238 return false;
|
Chris@16
|
239 }
|
Chris@16
|
240 return false;
|
Chris@16
|
241 }
|
Chris@16
|
242
|
Chris@16
|
243 inline bool operator!=( dimacs_edge_iterator arg ) {
|
Chris@16
|
244 if( reader.n_vertices() == 0 ) {
|
Chris@16
|
245 return !arg.reader.done_edges();
|
Chris@16
|
246 }
|
Chris@16
|
247 else if( arg.reader.n_vertices() == 0 ) {
|
Chris@16
|
248 return !reader.done_edges();
|
Chris@16
|
249 }
|
Chris@16
|
250 else {
|
Chris@16
|
251 return true;
|
Chris@16
|
252 }
|
Chris@16
|
253 return true;
|
Chris@16
|
254 }
|
Chris@16
|
255
|
Chris@16
|
256 private:
|
Chris@16
|
257 T& reader;
|
Chris@16
|
258 };
|
Chris@16
|
259
|
Chris@16
|
260 template<typename T>
|
Chris@16
|
261 class dimacs_edge_weight_iterator {
|
Chris@16
|
262 public:
|
Chris@16
|
263 typedef dimacs_basic_reader::edge_weight_type edge_weight_type;
|
Chris@16
|
264 typedef dimacs_basic_reader::incr_mode incr_mode;
|
Chris@16
|
265
|
Chris@16
|
266 dimacs_edge_weight_iterator( T& reader ) : reader( reader ) {}
|
Chris@16
|
267
|
Chris@16
|
268 inline dimacs_edge_weight_iterator& operator++() {
|
Chris@16
|
269 reader.incr( dimacs_basic_reader::edge_weight );
|
Chris@16
|
270 return *this;
|
Chris@16
|
271 }
|
Chris@16
|
272
|
Chris@16
|
273 inline edge_weight_type operator*() {
|
Chris@16
|
274 return reader.edge_weight_deref();
|
Chris@16
|
275 }
|
Chris@16
|
276
|
Chris@16
|
277 // don't expect this to do the right thing if you're not comparing against a
|
Chris@16
|
278 // general past-the-end-iterator made with the default constructor for
|
Chris@16
|
279 // dimacs_basic_reader
|
Chris@16
|
280 inline bool operator==( dimacs_edge_weight_iterator arg ) {
|
Chris@16
|
281 if( reader.n_vertices() == 0 ) {
|
Chris@16
|
282 return arg.reader.done_edge_weights();
|
Chris@16
|
283 }
|
Chris@16
|
284 else if( arg.reader.n_vertices() == 0 ) {
|
Chris@16
|
285 return reader.done_edge_weights();
|
Chris@16
|
286 }
|
Chris@16
|
287 else {
|
Chris@16
|
288 return false;
|
Chris@16
|
289 }
|
Chris@16
|
290 return false;
|
Chris@16
|
291 }
|
Chris@16
|
292
|
Chris@16
|
293 inline bool operator!=( dimacs_edge_weight_iterator arg ) {
|
Chris@16
|
294 if( reader.n_vertices() == 0 ) {
|
Chris@16
|
295 return !arg.reader.done_edge_weights();
|
Chris@16
|
296 }
|
Chris@16
|
297 else if( arg.reader.n_vertices() == 0 ) {
|
Chris@16
|
298 return !reader.done_edge_weights();
|
Chris@16
|
299 }
|
Chris@16
|
300 else {
|
Chris@16
|
301 return true;
|
Chris@16
|
302 }
|
Chris@16
|
303 return true;
|
Chris@16
|
304 }
|
Chris@16
|
305 private:
|
Chris@16
|
306 T& reader;
|
Chris@16
|
307 };
|
Chris@16
|
308
|
Chris@16
|
309 } } // end namespace boost::graph
|
Chris@16
|
310 #endif
|