| 1 | // graph-tool -- a general graph modification and manipulation thingy |
|---|
| 2 | // |
|---|
| 3 | // Copyright (C) 2007-2011 Tiago de Paula Peixoto <tiago@skewed.de> |
|---|
| 4 | // |
|---|
| 5 | // This program is free software; you can redistribute it and/or |
|---|
| 6 | // modify it under the terms of the GNU General Public License |
|---|
| 7 | // as published by the Free Software Foundation; either version 3 |
|---|
| 8 | // of the License, or (at your option) any later version. |
|---|
| 9 | // |
|---|
| 10 | // This program is distributed in the hope that it will be useful, |
|---|
| 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | // GNU General Public License for more details. |
|---|
| 14 | // |
|---|
| 15 | // You should have received a copy of the GNU General Public License |
|---|
| 16 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 17 | |
|---|
| 18 | #ifndef FILTERING_HH |
|---|
| 19 | #define FILTERING_HH |
|---|
| 20 | |
|---|
| 21 | #include <boost/version.hpp> |
|---|
| 22 | #include <boost/graph/graph_traits.hpp> |
|---|
| 23 | #include <boost/graph/filtered_graph.hpp> |
|---|
| 24 | #if (BOOST_VERSION / 100 % 1000 >= 48) |
|---|
| 25 | #include <boost/graph/reverse_graph_alt.hpp> |
|---|
| 26 | #else |
|---|
| 27 | #include <boost/graph/reverse_graph.hpp> |
|---|
| 28 | #endif |
|---|
| 29 | #include <boost/mpl/vector.hpp> |
|---|
| 30 | #include <boost/mpl/erase.hpp> |
|---|
| 31 | #include <boost/mpl/clear.hpp> |
|---|
| 32 | #include <boost/mpl/map.hpp> |
|---|
| 33 | #include <boost/mpl/for_each.hpp> |
|---|
| 34 | #include <boost/mpl/at.hpp> |
|---|
| 35 | #include <boost/mpl/or.hpp> |
|---|
| 36 | #include <boost/mpl/if.hpp> |
|---|
| 37 | #include <boost/mpl/logical.hpp> |
|---|
| 38 | #include <boost/mpl/inserter.hpp> |
|---|
| 39 | #include <boost/mpl/insert_range.hpp> |
|---|
| 40 | #include <boost/mpl/assert.hpp> |
|---|
| 41 | #include <boost/mpl/plus.hpp> |
|---|
| 42 | #include <boost/mpl/divides.hpp> |
|---|
| 43 | #include <boost/mpl/arithmetic.hpp> |
|---|
| 44 | #include <boost/mpl/greater_equal.hpp> |
|---|
| 45 | #include <boost/mpl/comparison.hpp> |
|---|
| 46 | #include <boost/mpl/transform_view.hpp> |
|---|
| 47 | #include <boost/mpl/quote.hpp> |
|---|
| 48 | #include <boost/mpl/range_c.hpp> |
|---|
| 49 | |
|---|
| 50 | #include "graph.hh" |
|---|
| 51 | #include "graph_adaptor.hh" |
|---|
| 52 | #include "graph_selectors.hh" |
|---|
| 53 | #include "graph_util.hh" |
|---|
| 54 | #include "graph_wrap.hh" |
|---|
| 55 | #include "mpl_nested_loop.hh" |
|---|
| 56 | |
|---|
| 57 | namespace graph_tool |
|---|
| 58 | { |
|---|
| 59 | |
|---|
| 60 | using namespace boost; |
|---|
| 61 | |
|---|
| 62 | // Graph filtering |
|---|
| 63 | // --------------- |
|---|
| 64 | // |
|---|
| 65 | // We want to generate versions of a template algorithm for every possible type |
|---|
| 66 | // of graph views. The types of graph views are the following: |
|---|
| 67 | // |
|---|
| 68 | // - The original directed multigraph |
|---|
| 69 | // |
|---|
| 70 | // - Filtered graphs, based on MaskFilter below. This amounts to a |
|---|
| 71 | // filtered_graph for every combination of filtered and unfiltered vertex |
|---|
| 72 | // or edge, i.e., 3. |
|---|
| 73 | // |
|---|
| 74 | // - A reversed view of each directed graph (original + filtered) |
|---|
| 75 | // |
|---|
| 76 | // - An undirected view of each directed (unreversed) graph (original + |
|---|
| 77 | // filtered) |
|---|
| 78 | // |
|---|
| 79 | // The total number of graph views is then: 3 * 4 = 12 |
|---|
| 80 | // |
|---|
| 81 | // The specific specialization can be called at run time (and generated at |
|---|
| 82 | // compile time) with the run_action() function, which takes as arguments the |
|---|
| 83 | // GraphInterface worked on, and the template functor to be specialized, which |
|---|
| 84 | // must take as first argument a pointer to a graph type, which itself must be a |
|---|
| 85 | // template parameter. Additionally, the function can be called optionally with |
|---|
| 86 | // up to 4 extra arguments, which must be MPL sequence instances corresponding |
|---|
| 87 | // to the type range of the extra arguments which must be passed to the template |
|---|
| 88 | // functor. The run_action() will not run the algorithm itself, but will instead |
|---|
| 89 | // return a functor (graph_action) which must be called either with no |
|---|
| 90 | // arguments, or with parameters of type boost::any which hold internally the |
|---|
| 91 | // type and values of the extra parameters to be passed to the action functor, |
|---|
| 92 | // and which will define the specialization to be chosen. |
|---|
| 93 | // |
|---|
| 94 | // Example: |
|---|
| 95 | // |
|---|
| 96 | // struct my_algorithm |
|---|
| 97 | // { |
|---|
| 98 | // template <class Graph, class ValueType> |
|---|
| 99 | // void operator()(Graph& g, ValueType val) const |
|---|
| 100 | // { |
|---|
| 101 | // ... do something ... |
|---|
| 102 | // } |
|---|
| 103 | // }; |
|---|
| 104 | // |
|---|
| 105 | // ... |
|---|
| 106 | // |
|---|
| 107 | // GraphInterface g; |
|---|
| 108 | // typedef mpl::vector<int, double, string> value_types; |
|---|
| 109 | // double foo = 42.0; |
|---|
| 110 | // run_action(g, my_algorithm(), value_types)(boost::any(foo)); |
|---|
| 111 | // |
|---|
| 112 | // The above line will run my_algorithm::operator() with Graph being the |
|---|
| 113 | // appropriate graph view type and ValueType being 'double' and val = 42.0. |
|---|
| 114 | |
|---|
| 115 | // Whenever no implementation is called, the following exception is thrown |
|---|
| 116 | class ActionNotFound: public GraphException |
|---|
| 117 | { |
|---|
| 118 | public: |
|---|
| 119 | ActionNotFound(const boost::any& graph_view, const std::type_info& action, |
|---|
| 120 | const vector<const std::type_info*>& args); |
|---|
| 121 | virtual const char * what () const throw (); |
|---|
| 122 | virtual ~ActionNotFound() throw () {} |
|---|
| 123 | private: |
|---|
| 124 | boost::any _graph_view; |
|---|
| 125 | const std::type_info& _action; |
|---|
| 126 | vector<const std::type_info*> _args; |
|---|
| 127 | }; |
|---|
| 128 | |
|---|
| 129 | namespace detail |
|---|
| 130 | { |
|---|
| 131 | |
|---|
| 132 | // Implementation |
|---|
| 133 | // -------------- |
|---|
| 134 | // |
|---|
| 135 | // The class MaskFilter below is the main filter predicate for the filtered |
|---|
| 136 | // graph view, based on descriptor property maps. It filters out edges or |
|---|
| 137 | // vertices which are masked according to a property map with bool (actually |
|---|
| 138 | // uint8_t) value type. |
|---|
| 139 | |
|---|
| 140 | template <class DescriptorProperty> |
|---|
| 141 | class MaskFilter |
|---|
| 142 | { |
|---|
| 143 | public: |
|---|
| 144 | typedef typename property_traits<DescriptorProperty>::value_type value_t; |
|---|
| 145 | MaskFilter(){} |
|---|
| 146 | MaskFilter(DescriptorProperty filtered_property, bool invert) |
|---|
| 147 | : _filtered_property(filtered_property), _invert(invert) {} |
|---|
| 148 | |
|---|
| 149 | template <class Descriptor> |
|---|
| 150 | inline bool operator() (Descriptor d) const |
|---|
| 151 | { |
|---|
| 152 | // ignore if masked |
|---|
| 153 | |
|---|
| 154 | return get(_filtered_property, d) ^ _invert; |
|---|
| 155 | |
|---|
| 156 | // TODO: This is a critical section. It will be called for every vertex |
|---|
| 157 | // or edge in the graph, every time they're iterated |
|---|
| 158 | // through. Therefore, it must be guaranteed this is as optimized |
|---|
| 159 | // as possible. |
|---|
| 160 | } |
|---|
| 161 | |
|---|
| 162 | private: |
|---|
| 163 | DescriptorProperty _filtered_property; |
|---|
| 164 | bool _invert; |
|---|
| 165 | }; |
|---|
| 166 | |
|---|
| 167 | |
|---|
| 168 | // Metaprogramming |
|---|
| 169 | // --------------- |
|---|
| 170 | // |
|---|
| 171 | // We need to generate a type sequence with all the filtered graph views, which |
|---|
| 172 | // will be called all_graph_views. |
|---|
| 173 | |
|---|
| 174 | // metafunction class to get the correct filter predicate |
|---|
| 175 | template <class Property> |
|---|
| 176 | struct get_predicate |
|---|
| 177 | { |
|---|
| 178 | typedef MaskFilter<Property> type; |
|---|
| 179 | }; |
|---|
| 180 | |
|---|
| 181 | template <> |
|---|
| 182 | struct get_predicate<keep_all> |
|---|
| 183 | { |
|---|
| 184 | typedef keep_all type; |
|---|
| 185 | }; |
|---|
| 186 | |
|---|
| 187 | // metafunction to get the filtered graph type |
|---|
| 188 | struct graph_filter |
|---|
| 189 | { |
|---|
| 190 | template <class Graph, class EdgeProperty, class VertexProperty> |
|---|
| 191 | struct apply |
|---|
| 192 | { |
|---|
| 193 | |
|---|
| 194 | typedef typename get_predicate<EdgeProperty>::type edge_predicate; |
|---|
| 195 | typedef typename get_predicate<VertexProperty>::type vertex_predicate; |
|---|
| 196 | |
|---|
| 197 | typedef filtered_graph<Graph, |
|---|
| 198 | edge_predicate, |
|---|
| 199 | vertex_predicate> filtered_graph_t; |
|---|
| 200 | |
|---|
| 201 | // If both predicates are keep_all, then return the original graph |
|---|
| 202 | // type. Otherwise return the filtered_graph type. |
|---|
| 203 | typedef typename mpl::if_< |
|---|
| 204 | typename mpl::and_< |
|---|
| 205 | is_same<edge_predicate, |
|---|
| 206 | keep_all>, |
|---|
| 207 | is_same<vertex_predicate, |
|---|
| 208 | keep_all> |
|---|
| 209 | >::type, |
|---|
| 210 | Graph, |
|---|
| 211 | filtered_graph_t>::type type; |
|---|
| 212 | }; |
|---|
| 213 | }; |
|---|
| 214 | |
|---|
| 215 | // metafunction to get the undirected graph type |
|---|
| 216 | struct graph_undirect |
|---|
| 217 | { |
|---|
| 218 | template <class Graph> |
|---|
| 219 | struct apply |
|---|
| 220 | { |
|---|
| 221 | typedef UndirectedAdaptor<Graph> type; |
|---|
| 222 | }; |
|---|
| 223 | }; |
|---|
| 224 | |
|---|
| 225 | // metafunction to get the reversed graph type |
|---|
| 226 | struct graph_reverse |
|---|
| 227 | { |
|---|
| 228 | template <class Graph> |
|---|
| 229 | struct apply |
|---|
| 230 | { |
|---|
| 231 | typedef reverse_graph<Graph> type; |
|---|
| 232 | }; |
|---|
| 233 | }; |
|---|
| 234 | |
|---|
| 235 | // this wraps an unary metafunction class Bind into a unary metafunction, |
|---|
| 236 | // i.e., it is an identity operation. I'm not sure why it's necessary, but |
|---|
| 237 | // using pure unary bind expressions below didn't work for me, and this |
|---|
| 238 | // fixed it. |
|---|
| 239 | template <class Bind> |
|---|
| 240 | struct bind_wrap1 |
|---|
| 241 | { |
|---|
| 242 | template <class T1> struct apply |
|---|
| 243 | { typedef typename Bind::template apply<T1>::type type; }; |
|---|
| 244 | }; |
|---|
| 245 | |
|---|
| 246 | // metafunction which returns a mpl::vector containing all the pair combinations |
|---|
| 247 | // of two given type sequences |
|---|
| 248 | struct get_all_pairs |
|---|
| 249 | { |
|---|
| 250 | struct make_pair |
|---|
| 251 | { |
|---|
| 252 | template <class T1, class T2> |
|---|
| 253 | struct apply |
|---|
| 254 | { |
|---|
| 255 | typedef mpl::pair<T1,T2> type; |
|---|
| 256 | }; |
|---|
| 257 | }; |
|---|
| 258 | |
|---|
| 259 | template <class TR1, class TR2> |
|---|
| 260 | struct apply |
|---|
| 261 | { |
|---|
| 262 | struct get_second_types |
|---|
| 263 | { |
|---|
| 264 | template <class T1> |
|---|
| 265 | struct apply |
|---|
| 266 | { |
|---|
| 267 | typedef typename mpl::transform< |
|---|
| 268 | TR2, |
|---|
| 269 | bind_wrap1< |
|---|
| 270 | mpl::bind2<make_pair, T1, mpl::_1> |
|---|
| 271 | > >::type type; |
|---|
| 272 | }; |
|---|
| 273 | }; |
|---|
| 274 | |
|---|
| 275 | typedef typename mpl::transform< |
|---|
| 276 | TR1, |
|---|
| 277 | get_second_types, |
|---|
| 278 | mpl::back_inserter<mpl::vector<> > |
|---|
| 279 | >::type pair_combinations; // nested sequence (vector of vectors) of |
|---|
| 280 | // pair combinations |
|---|
| 281 | |
|---|
| 282 | // joins two sequences |
|---|
| 283 | struct join |
|---|
| 284 | { |
|---|
| 285 | template <class Seq1, class Seq2> |
|---|
| 286 | struct apply |
|---|
| 287 | { |
|---|
| 288 | typedef typename boost::mpl::copy< |
|---|
| 289 | Seq2, |
|---|
| 290 | boost::mpl::back_inserter<Seq1> |
|---|
| 291 | >::type type; |
|---|
| 292 | }; |
|---|
| 293 | }; |
|---|
| 294 | |
|---|
| 295 | // flattens a nested sequence |
|---|
| 296 | template<class Sequence> |
|---|
| 297 | struct flatten |
|---|
| 298 | { |
|---|
| 299 | typedef typename boost::mpl::fold< |
|---|
| 300 | Sequence, |
|---|
| 301 | typename boost::mpl::clear<Sequence>::type, |
|---|
| 302 | join |
|---|
| 303 | >::type type; |
|---|
| 304 | }; |
|---|
| 305 | |
|---|
| 306 | // the complete list of combinations |
|---|
| 307 | typedef typename flatten<pair_combinations>::type type; |
|---|
| 308 | }; |
|---|
| 309 | }; |
|---|
| 310 | |
|---|
| 311 | // metafunction class to get the correct property map type |
|---|
| 312 | template <class Scalar, class IndexMap> |
|---|
| 313 | struct get_property_map_type |
|---|
| 314 | { |
|---|
| 315 | typedef typename property_map_type::apply<Scalar, IndexMap> |
|---|
| 316 | ::type::unchecked_t type; |
|---|
| 317 | }; |
|---|
| 318 | |
|---|
| 319 | template <class IndexMap> |
|---|
| 320 | struct get_property_map_type<keep_all, IndexMap> |
|---|
| 321 | { |
|---|
| 322 | typedef keep_all type; |
|---|
| 323 | }; |
|---|
| 324 | |
|---|
| 325 | // this metafunction returns a filtered graph type, given the scalar types to be |
|---|
| 326 | // used in the property maps |
|---|
| 327 | struct get_graph_filtered |
|---|
| 328 | { |
|---|
| 329 | template <class TypePair> |
|---|
| 330 | struct apply |
|---|
| 331 | { |
|---|
| 332 | typedef typename TypePair::first edge_scalar; |
|---|
| 333 | typedef typename TypePair::second vertex_scalar; |
|---|
| 334 | |
|---|
| 335 | // if the 'scalar' is the index map itself, use simply that, otherwise |
|---|
| 336 | // get the specific property map |
|---|
| 337 | typedef typename mpl::if_< |
|---|
| 338 | is_same<edge_scalar, |
|---|
| 339 | GraphInterface::edge_index_map_t>, |
|---|
| 340 | GraphInterface::edge_index_map_t, |
|---|
| 341 | typename get_property_map_type< |
|---|
| 342 | edge_scalar, |
|---|
| 343 | GraphInterface::edge_index_map_t>::type |
|---|
| 344 | >::type edge_property_map; |
|---|
| 345 | |
|---|
| 346 | typedef typename mpl::if_< |
|---|
| 347 | is_same<vertex_scalar, |
|---|
| 348 | GraphInterface::vertex_index_map_t>, |
|---|
| 349 | GraphInterface::vertex_index_map_t, |
|---|
| 350 | typename get_property_map_type< |
|---|
| 351 | vertex_scalar, |
|---|
| 352 | GraphInterface::vertex_index_map_t>::type |
|---|
| 353 | >::type vertex_property_map; |
|---|
| 354 | |
|---|
| 355 | typedef typename graph_filter::apply<GraphInterface::multigraph_t, |
|---|
| 356 | edge_property_map, |
|---|
| 357 | vertex_property_map>::type type; |
|---|
| 358 | }; |
|---|
| 359 | }; |
|---|
| 360 | |
|---|
| 361 | // this metafunction returns all the possible graph views |
|---|
| 362 | struct get_all_graph_views |
|---|
| 363 | { |
|---|
| 364 | template <class TypePairs, |
|---|
| 365 | class AlwaysDirected = mpl::bool_<false>, |
|---|
| 366 | class NeverDirected = mpl::bool_<false>, |
|---|
| 367 | class AlwaysReversed = mpl::bool_<false>, |
|---|
| 368 | class NeverReversed = mpl::bool_<false>, |
|---|
| 369 | class NeverFiltered = mpl::bool_<false> > |
|---|
| 370 | struct apply |
|---|
| 371 | { |
|---|
| 372 | // filtered graphs |
|---|
| 373 | struct filtered_graphs: |
|---|
| 374 | mpl::if_ |
|---|
| 375 | <NeverFiltered, |
|---|
| 376 | mpl::vector<GraphInterface::multigraph_t>, |
|---|
| 377 | typename mpl::transform<TypePairs, |
|---|
| 378 | get_graph_filtered>::type>::type {}; |
|---|
| 379 | |
|---|
| 380 | // filtered + reversed graphs |
|---|
| 381 | struct reversed_graphs: |
|---|
| 382 | mpl::if_<AlwaysReversed, |
|---|
| 383 | typename mpl::transform<filtered_graphs, |
|---|
| 384 | graph_reverse>::type, |
|---|
| 385 | typename mpl::if_< |
|---|
| 386 | NeverReversed, |
|---|
| 387 | filtered_graphs, |
|---|
| 388 | typename mpl::transform< |
|---|
| 389 | filtered_graphs, |
|---|
| 390 | graph_reverse, |
|---|
| 391 | mpl::back_inserter<filtered_graphs> |
|---|
| 392 | >::type |
|---|
| 393 | >::type |
|---|
| 394 | >::type {}; |
|---|
| 395 | |
|---|
| 396 | // undirected + filtereed + reversed graphs |
|---|
| 397 | struct undirected_graphs: |
|---|
| 398 | mpl::if_<AlwaysDirected, |
|---|
| 399 | reversed_graphs, |
|---|
| 400 | typename mpl::if_< |
|---|
| 401 | NeverDirected, |
|---|
| 402 | typename mpl::transform<filtered_graphs, |
|---|
| 403 | graph_undirect>::type, |
|---|
| 404 | typename mpl::transform< |
|---|
| 405 | filtered_graphs, |
|---|
| 406 | graph_undirect, |
|---|
| 407 | mpl::back_inserter<reversed_graphs> |
|---|
| 408 | >::type |
|---|
| 409 | >::type |
|---|
| 410 | >::type {}; |
|---|
| 411 | typedef undirected_graphs type; |
|---|
| 412 | }; |
|---|
| 413 | }; |
|---|
| 414 | |
|---|
| 415 | // useful metafunction to split sequences in half |
|---|
| 416 | struct split |
|---|
| 417 | { |
|---|
| 418 | template <class Sequence> |
|---|
| 419 | struct get_element |
|---|
| 420 | { |
|---|
| 421 | template <class Index> |
|---|
| 422 | struct apply |
|---|
| 423 | { |
|---|
| 424 | typedef typename mpl::at<Sequence,Index>::type type; |
|---|
| 425 | }; |
|---|
| 426 | }; |
|---|
| 427 | |
|---|
| 428 | template <class Sequence> |
|---|
| 429 | struct apply |
|---|
| 430 | { |
|---|
| 431 | typedef typename mpl::size<Sequence>::type size; |
|---|
| 432 | typedef typename mpl::divides<size, mpl::int_<2> >::type half_size; |
|---|
| 433 | typedef typename mpl::transform<mpl::range_c<int, 0, half_size::value>, |
|---|
| 434 | get_element<Sequence>, |
|---|
| 435 | mpl::back_inserter<mpl::vector<> > > |
|---|
| 436 | ::type first_part; |
|---|
| 437 | typedef typename mpl::transform<mpl::range_c<int, half_size::value, |
|---|
| 438 | size::value>, |
|---|
| 439 | get_element<Sequence>, |
|---|
| 440 | mpl::back_inserter<mpl::vector<> > > |
|---|
| 441 | ::type second_part; |
|---|
| 442 | typedef typename mpl::pair<first_part,second_part> type; |
|---|
| 443 | }; |
|---|
| 444 | }; |
|---|
| 445 | |
|---|
| 446 | |
|---|
| 447 | |
|---|
| 448 | // all scalar types plus edge and vertex index property (we actually only use |
|---|
| 449 | // bool) |
|---|
| 450 | |
|---|
| 451 | #ifndef NO_GRAPH_FILTERING |
|---|
| 452 | struct edge_scalars: |
|---|
| 453 | mpl::vector<keep_all, uint8_t> {}; |
|---|
| 454 | struct vertex_scalars: |
|---|
| 455 | mpl::vector<keep_all, uint8_t> {}; |
|---|
| 456 | #else |
|---|
| 457 | struct edge_scalars: |
|---|
| 458 | mpl::vector<keep_all> {}; |
|---|
| 459 | struct vertex_scalars: |
|---|
| 460 | mpl::vector<keep_all> {}; |
|---|
| 461 | #endif |
|---|
| 462 | |
|---|
| 463 | // all scalar pairs |
|---|
| 464 | struct scalar_pairs: get_all_pairs::apply<edge_scalars,vertex_scalars>::type {}; |
|---|
| 465 | |
|---|
| 466 | // finally, this type should hold all the possible graph views |
|---|
| 467 | struct all_graph_views: |
|---|
| 468 | get_all_graph_views::apply<scalar_pairs>::type {}; |
|---|
| 469 | |
|---|
| 470 | // restricted graph views |
|---|
| 471 | struct always_directed: |
|---|
| 472 | get_all_graph_views::apply<scalar_pairs,mpl::bool_<true> >::type {}; |
|---|
| 473 | |
|---|
| 474 | struct never_directed: |
|---|
| 475 | get_all_graph_views::apply<scalar_pairs,mpl::bool_<false>, |
|---|
| 476 | mpl::bool_<true> >::type {}; |
|---|
| 477 | |
|---|
| 478 | struct always_reversed: |
|---|
| 479 | get_all_graph_views::apply<scalar_pairs,mpl::bool_<true>, |
|---|
| 480 | mpl::bool_<false>,mpl::bool_<true> >::type {}; |
|---|
| 481 | |
|---|
| 482 | struct never_reversed: |
|---|
| 483 | get_all_graph_views::apply<scalar_pairs,mpl::bool_<false>, |
|---|
| 484 | mpl::bool_<false>,mpl::bool_<false>, |
|---|
| 485 | mpl::bool_<true> >::type {}; |
|---|
| 486 | |
|---|
| 487 | struct always_directed_never_reversed: |
|---|
| 488 | get_all_graph_views::apply<scalar_pairs,mpl::bool_<true>, |
|---|
| 489 | mpl::bool_<false>,mpl::bool_<false>, |
|---|
| 490 | mpl::bool_<true> >::type {}; |
|---|
| 491 | |
|---|
| 492 | struct never_filtered: |
|---|
| 493 | get_all_graph_views::apply<scalar_pairs,mpl::bool_<false>, |
|---|
| 494 | mpl::bool_<false>,mpl::bool_<false>, |
|---|
| 495 | mpl::bool_<false>,mpl::bool_<true> >::type {}; |
|---|
| 496 | |
|---|
| 497 | // sanity check |
|---|
| 498 | typedef mpl::size<all_graph_views>::type n_views; |
|---|
| 499 | #ifndef NO_GRAPH_FILTERING |
|---|
| 500 | BOOST_MPL_ASSERT_RELATION(n_views::value, == , mpl::int_<12>::value); |
|---|
| 501 | #else |
|---|
| 502 | BOOST_MPL_ASSERT_RELATION(n_views::value, == , mpl::int_<3>::value); |
|---|
| 503 | #endif |
|---|
| 504 | |
|---|
| 505 | // run_action() implementation |
|---|
| 506 | // =========================== |
|---|
| 507 | |
|---|
| 508 | // wrap action to be called, to deal with property maps, i.e., return version |
|---|
| 509 | // with no bounds checking. |
|---|
| 510 | template <class Action, class Wrap> |
|---|
| 511 | struct action_wrap |
|---|
| 512 | { |
|---|
| 513 | action_wrap(Action a, GraphInterface& g, size_t max_v, size_t max_e) |
|---|
| 514 | : _a(a), _g(g), _max_v(max_v), _max_e(max_e) {} |
|---|
| 515 | |
|---|
| 516 | template <class Type> |
|---|
| 517 | checked_vector_property_map<Type,GraphInterface::vertex_index_map_t> |
|---|
| 518 | uncheck(checked_vector_property_map |
|---|
| 519 | <Type,GraphInterface::vertex_index_map_t> a, mpl::true_) const |
|---|
| 520 | { |
|---|
| 521 | return a; |
|---|
| 522 | } |
|---|
| 523 | |
|---|
| 524 | template <class Type> |
|---|
| 525 | unchecked_vector_property_map<Type,GraphInterface::vertex_index_map_t> |
|---|
| 526 | uncheck(checked_vector_property_map |
|---|
| 527 | <Type,GraphInterface::vertex_index_map_t> a, mpl::false_) const |
|---|
| 528 | { |
|---|
| 529 | return a.get_unchecked(_max_v); |
|---|
| 530 | } |
|---|
| 531 | |
|---|
| 532 | template <class Type> |
|---|
| 533 | checked_vector_property_map<Type,GraphInterface::edge_index_map_t> |
|---|
| 534 | uncheck(checked_vector_property_map |
|---|
| 535 | <Type,GraphInterface::edge_index_map_t> a, mpl::true_) const |
|---|
| 536 | { |
|---|
| 537 | return a; |
|---|
| 538 | } |
|---|
| 539 | |
|---|
| 540 | template <class Type> |
|---|
| 541 | unchecked_vector_property_map<Type,GraphInterface::edge_index_map_t> |
|---|
| 542 | uncheck(checked_vector_property_map |
|---|
| 543 | <Type,GraphInterface::edge_index_map_t> a, mpl::false_) const |
|---|
| 544 | { |
|---|
| 545 | return a.get_unchecked(_max_e); |
|---|
| 546 | } |
|---|
| 547 | |
|---|
| 548 | template <class Type> |
|---|
| 549 | scalarS<typename Type::unchecked_t> |
|---|
| 550 | uncheck(scalarS<Type> a, mpl::false_) const |
|---|
| 551 | { |
|---|
| 552 | return scalarS<typename Type::unchecked_t>(uncheck(a._pmap, |
|---|
| 553 | mpl::false_())); |
|---|
| 554 | } |
|---|
| 555 | |
|---|
| 556 | //no op |
|---|
| 557 | template <class Type, class DoWrap> |
|---|
| 558 | Type uncheck(Type a, DoWrap) const { return a; } |
|---|
| 559 | |
|---|
| 560 | template <class Graph> |
|---|
| 561 | GraphWrap<Graph> wrap(Graph* g, mpl::true_) const |
|---|
| 562 | { |
|---|
| 563 | return graph_wrap(*g, _g); |
|---|
| 564 | } |
|---|
| 565 | |
|---|
| 566 | template <class Graph> |
|---|
| 567 | Graph& wrap(Graph* g, mpl::false_) const |
|---|
| 568 | { |
|---|
| 569 | return *g; |
|---|
| 570 | } |
|---|
| 571 | |
|---|
| 572 | void operator()() const {}; |
|---|
| 573 | template <class T1> void operator()(const T1& a1) const |
|---|
| 574 | { _a(wrap(a1, Wrap())); } |
|---|
| 575 | template <class T1, class T2> |
|---|
| 576 | void operator()(const T1& a1, const T2& a2) const |
|---|
| 577 | { _a(wrap(a1,Wrap()), uncheck(a2, Wrap())); } |
|---|
| 578 | template <class T1, class T2, class T3> |
|---|
| 579 | void operator()(const T1& a1, const T2& a2, const T3& a3) const |
|---|
| 580 | { _a(wrap(a1,Wrap()), uncheck(a2, Wrap()), uncheck(a3, Wrap()));} |
|---|
| 581 | template <class T1, class T2, class T3, class T4> |
|---|
| 582 | void operator()(const T1& a1, const T2& a2, const T3& a3, const T4& a4) |
|---|
| 583 | const |
|---|
| 584 | { _a(wrap(a1,Wrap()), uncheck(a2, Wrap()), uncheck(a3, Wrap()), |
|---|
| 585 | uncheck(a4, Wrap())); } |
|---|
| 586 | template <class T1, class T2, class T3, class T4, class T5> |
|---|
| 587 | void operator()(const T1& a1, const T2& a2, const T3& a3, const T4& a4, |
|---|
| 588 | const T5& a5) const |
|---|
| 589 | { _a(wrap(a1,Wrap()), uncheck(a2, Wrap()), uncheck(a3, Wrap()), |
|---|
| 590 | uncheck(a4, Wrap()), uncheck(a5, Wrap())); } |
|---|
| 591 | |
|---|
| 592 | Action _a; |
|---|
| 593 | reference_wrapper<GraphInterface> _g; |
|---|
| 594 | size_t _max_v, _max_e; |
|---|
| 595 | }; |
|---|
| 596 | |
|---|
| 597 | // this functor encapsulates another functor Action, which takes a pointer to a |
|---|
| 598 | // graph view as first argument |
|---|
| 599 | template <class Action, class GraphViews, class Wrap, class TR1, class TR2, |
|---|
| 600 | class TR3, class TR4 > |
|---|
| 601 | struct graph_action |
|---|
| 602 | { |
|---|
| 603 | struct graph_view_pointers: |
|---|
| 604 | mpl::transform<GraphViews, mpl::quote1<add_pointer> >::type {}; |
|---|
| 605 | |
|---|
| 606 | graph_action(GraphInterface& g, Action a) |
|---|
| 607 | : _g(g), _a(a, g, num_vertices(g._state->_mg), |
|---|
| 608 | g._state->_max_edge_index + 1) {} |
|---|
| 609 | |
|---|
| 610 | void operator()() const |
|---|
| 611 | { |
|---|
| 612 | bool found = false; |
|---|
| 613 | boost::any gview = _g.GetGraphView(); |
|---|
| 614 | boost::mpl::for_each<graph_view_pointers> |
|---|
| 615 | (boost::mpl::select_types(_a, found, gview)); |
|---|
| 616 | if (!found) |
|---|
| 617 | { |
|---|
| 618 | throw ActionNotFound(gview, typeid(Action), |
|---|
| 619 | vector<const std::type_info*>()); |
|---|
| 620 | } |
|---|
| 621 | } |
|---|
| 622 | |
|---|
| 623 | void operator()(boost::any a1) const |
|---|
| 624 | { |
|---|
| 625 | bool found = false; |
|---|
| 626 | boost::any gview = _g.GetGraphView(); |
|---|
| 627 | boost::mpl::nested_for_each<graph_view_pointers,TR1>() |
|---|
| 628 | (boost::mpl::select_types(_a, found, gview, a1)); |
|---|
| 629 | if (!found) |
|---|
| 630 | { |
|---|
| 631 | vector<const std::type_info*> args; |
|---|
| 632 | args.push_back(&a1.type()); |
|---|
| 633 | throw ActionNotFound(gview, typeid(Action), args); |
|---|
| 634 | } |
|---|
| 635 | } |
|---|
| 636 | |
|---|
| 637 | void operator()(boost::any a1, boost::any a2) const |
|---|
| 638 | { |
|---|
| 639 | bool found = false; |
|---|
| 640 | boost::any gview = _g.GetGraphView(); |
|---|
| 641 | boost::mpl::nested_for_each<graph_view_pointers,TR1,TR2>() |
|---|
| 642 | (boost::mpl::select_types(_a, found, gview, a1, a2)); |
|---|
| 643 | if (!found) |
|---|
| 644 | { |
|---|
| 645 | vector<const std::type_info*> args; |
|---|
| 646 | args.push_back(&a1.type()); |
|---|
| 647 | args.push_back(&a2.type()); |
|---|
| 648 | throw ActionNotFound(gview, typeid(Action), args); |
|---|
| 649 | } |
|---|
| 650 | } |
|---|
| 651 | |
|---|
| 652 | void operator()(boost::any a1, boost::any a2, boost::any a3) const |
|---|
| 653 | { |
|---|
| 654 | bool found = false; |
|---|
| 655 | boost::any gview = _g.GetGraphView(); |
|---|
| 656 | boost::mpl::nested_for_each<graph_view_pointers,TR1,TR2,TR3>() |
|---|
| 657 | (boost::mpl::select_types(_a, found, gview, a1, a2, a3)); |
|---|
| 658 | if (!found) |
|---|
| 659 | { |
|---|
| 660 | vector<const std::type_info*> args; |
|---|
| 661 | args.push_back(&a1.type()); |
|---|
| 662 | args.push_back(&a2.type()); |
|---|
| 663 | args.push_back(&a3.type()); |
|---|
| 664 | throw ActionNotFound(gview, typeid(Action), args); |
|---|
| 665 | } |
|---|
| 666 | } |
|---|
| 667 | |
|---|
| 668 | void operator()(boost::any a1, boost::any a2, boost::any a3, |
|---|
| 669 | boost::any a4) const |
|---|
| 670 | { |
|---|
| 671 | bool found = false; |
|---|
| 672 | boost::any gview = _g.GetGraphView(); |
|---|
| 673 | boost::mpl::nested_for_each<graph_view_pointers,TR1,TR2,TR3,TR4>() |
|---|
| 674 | (boost::mpl::select_types(_a, found, gview, a1, a2, a3,a4)); |
|---|
| 675 | if (!found) |
|---|
| 676 | { |
|---|
| 677 | vector<const std::type_info*> args; |
|---|
| 678 | args.push_back(&a1.type()); |
|---|
| 679 | args.push_back(&a2.type()); |
|---|
| 680 | args.push_back(&a3.type()); |
|---|
| 681 | args.push_back(&a4.type()); |
|---|
| 682 | throw ActionNotFound(gview, typeid(Action), args); |
|---|
| 683 | } |
|---|
| 684 | } |
|---|
| 685 | |
|---|
| 686 | const GraphInterface &_g; |
|---|
| 687 | action_wrap<Action, Wrap> _a; |
|---|
| 688 | }; |
|---|
| 689 | } // details namespace |
|---|
| 690 | |
|---|
| 691 | |
|---|
| 692 | // all definitions of run_action with different arity |
|---|
| 693 | template <class GraphViews = detail::all_graph_views, class Wrap = mpl::false_> |
|---|
| 694 | struct run_action |
|---|
| 695 | { |
|---|
| 696 | template <class Action> |
|---|
| 697 | detail::graph_action<Action,GraphViews,Wrap> |
|---|
| 698 | operator()(GraphInterface &g, Action a) |
|---|
| 699 | { |
|---|
| 700 | return detail::graph_action<Action,GraphViews,Wrap>(g, a); |
|---|
| 701 | } |
|---|
| 702 | |
|---|
| 703 | template <class Action, class TR1> |
|---|
| 704 | detail::graph_action<Action,GraphViews,Wrap,TR1> |
|---|
| 705 | operator()(GraphInterface &g, Action a, TR1) |
|---|
| 706 | { |
|---|
| 707 | return detail::graph_action<Action,GraphViews,Wrap,TR1>(g, a); |
|---|
| 708 | } |
|---|
| 709 | |
|---|
| 710 | template <class Action, class TR1, class TR2> |
|---|
| 711 | detail::graph_action<Action,GraphViews,Wrap,TR1,TR2> |
|---|
| 712 | operator()(GraphInterface &g, Action a, TR1, TR2) |
|---|
| 713 | { |
|---|
| 714 | return detail::graph_action<Action,GraphViews,Wrap,TR1,TR2>(g, a); |
|---|
| 715 | } |
|---|
| 716 | |
|---|
| 717 | template <class Action, class TR1, class TR2, class TR3> |
|---|
| 718 | detail::graph_action<Action,GraphViews,Wrap,TR1,TR2,TR3> |
|---|
| 719 | operator()(GraphInterface &g, Action a, TR1, TR2, TR3) |
|---|
| 720 | { |
|---|
| 721 | return detail::graph_action<Action,GraphViews,Wrap,TR1,TR2,TR3>(g, a); |
|---|
| 722 | } |
|---|
| 723 | |
|---|
| 724 | template <class Action, class TR1, class TR2, class TR3, class TR4> |
|---|
| 725 | detail::graph_action<Action,GraphViews,Wrap,TR1,TR2,TR3,TR4> |
|---|
| 726 | operator()(GraphInterface &g, Action a, TR1, TR2, TR3, TR4) |
|---|
| 727 | { |
|---|
| 728 | return detail::graph_action<Action,GraphViews,Wrap,TR1,TR2,TR3,TR4>(g, a); |
|---|
| 729 | } |
|---|
| 730 | }; |
|---|
| 731 | |
|---|
| 732 | // returns true if graph filtering was enabled at compile time |
|---|
| 733 | bool graph_filtering_enabled(); |
|---|
| 734 | |
|---|
| 735 | } //graph_tool namespace |
|---|
| 736 | |
|---|
| 737 | #endif // FILTERING_HH |
|---|