Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:37:30

0001 //=======================================================================
0002 // Copyright 2007 Aaron Windsor
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See
0005 // accompanying file LICENSE_1_0.txt or copy at
0006 // http://www.boost.org/LICENSE_1_0.txt)
0007 //=======================================================================
0008 #ifndef __IS_KURATOWSKI_SUBGRAPH_HPP__
0009 #define __IS_KURATOWSKI_SUBGRAPH_HPP__
0010 
0011 #include <boost/config.hpp>
0012 #include <boost/tuple/tuple.hpp> //for tie
0013 #include <boost/property_map/property_map.hpp>
0014 #include <boost/graph/properties.hpp>
0015 #include <boost/graph/isomorphism.hpp>
0016 #include <boost/graph/adjacency_list.hpp>
0017 
0018 #include <algorithm>
0019 #include <vector>
0020 #include <set>
0021 
0022 namespace boost
0023 {
0024 
0025 namespace detail
0026 {
0027 
0028     template < typename Graph > Graph make_K_5()
0029     {
0030         typename graph_traits< Graph >::vertex_iterator vi, vi_end, inner_vi;
0031         Graph K_5(5);
0032         for (boost::tie(vi, vi_end) = vertices(K_5); vi != vi_end; ++vi)
0033             for (inner_vi = next(vi); inner_vi != vi_end; ++inner_vi)
0034                 add_edge(*vi, *inner_vi, K_5);
0035         return K_5;
0036     }
0037 
0038     template < typename Graph > Graph make_K_3_3()
0039     {
0040         typename graph_traits< Graph >::vertex_iterator vi, vi_end,
0041             bipartition_start, inner_vi;
0042         Graph K_3_3(6);
0043         bipartition_start = next(next(next(vertices(K_3_3).first)));
0044         for (boost::tie(vi, vi_end) = vertices(K_3_3); vi != bipartition_start;
0045              ++vi)
0046             for (inner_vi = bipartition_start; inner_vi != vi_end; ++inner_vi)
0047                 add_edge(*vi, *inner_vi, K_3_3);
0048         return K_3_3;
0049     }
0050 
0051     template < typename AdjacencyList, typename Vertex >
0052     void contract_edge(AdjacencyList& neighbors, Vertex u, Vertex v)
0053     {
0054         // Remove u from v's neighbor list
0055         neighbors[v].erase(
0056             std::remove(neighbors[v].begin(), neighbors[v].end(), u),
0057             neighbors[v].end());
0058 
0059         // Replace any references to u with references to v
0060         typedef
0061             typename AdjacencyList::value_type::iterator adjacency_iterator_t;
0062 
0063         adjacency_iterator_t u_neighbor_end = neighbors[u].end();
0064         for (adjacency_iterator_t u_neighbor_itr = neighbors[u].begin();
0065              u_neighbor_itr != u_neighbor_end; ++u_neighbor_itr)
0066         {
0067             Vertex u_neighbor(*u_neighbor_itr);
0068             std::replace(neighbors[u_neighbor].begin(),
0069                 neighbors[u_neighbor].end(), u, v);
0070         }
0071 
0072         // Remove v from u's neighbor list
0073         neighbors[u].erase(
0074             std::remove(neighbors[u].begin(), neighbors[u].end(), v),
0075             neighbors[u].end());
0076 
0077         // Add everything in u's neighbor list to v's neighbor list
0078         std::copy(neighbors[u].begin(), neighbors[u].end(),
0079             std::back_inserter(neighbors[v]));
0080 
0081         // Clear u's neighbor list
0082         neighbors[u].clear();
0083     }
0084 
0085     enum target_graph_t
0086     {
0087         tg_k_3_3,
0088         tg_k_5
0089     };
0090 
0091 } // namespace detail
0092 
0093 template < typename Graph, typename ForwardIterator, typename VertexIndexMap >
0094 bool is_kuratowski_subgraph(const Graph& g, ForwardIterator begin,
0095     ForwardIterator end, VertexIndexMap vm)
0096 {
0097 
0098     typedef typename graph_traits< Graph >::vertex_descriptor vertex_t;
0099     typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t;
0100     typedef typename graph_traits< Graph >::edge_descriptor edge_t;
0101     typedef typename graph_traits< Graph >::edges_size_type e_size_t;
0102     typedef typename graph_traits< Graph >::vertices_size_type v_size_t;
0103     typedef typename std::vector< vertex_t > v_list_t;
0104     typedef typename v_list_t::iterator v_list_iterator_t;
0105     typedef iterator_property_map< typename std::vector< v_list_t >::iterator,
0106         VertexIndexMap >
0107         vertex_to_v_list_map_t;
0108 
0109     typedef adjacency_list< vecS, vecS, undirectedS > small_graph_t;
0110 
0111     detail::target_graph_t target_graph
0112         = detail::tg_k_3_3; // unless we decide otherwise later
0113 
0114     static small_graph_t K_5(detail::make_K_5< small_graph_t >());
0115 
0116     static small_graph_t K_3_3(detail::make_K_3_3< small_graph_t >());
0117 
0118     v_size_t n_vertices(num_vertices(g));
0119     v_size_t max_num_edges(3 * n_vertices - 5);
0120 
0121     std::vector< v_list_t > neighbors_vector(n_vertices);
0122     vertex_to_v_list_map_t neighbors(neighbors_vector.begin(), vm);
0123 
0124     e_size_t count = 0;
0125     for (ForwardIterator itr = begin; itr != end; ++itr)
0126     {
0127 
0128         if (count++ > max_num_edges)
0129             return false;
0130 
0131         edge_t e(*itr);
0132         vertex_t u(source(e, g));
0133         vertex_t v(target(e, g));
0134 
0135         neighbors[u].push_back(v);
0136         neighbors[v].push_back(u);
0137     }
0138 
0139     for (v_size_t max_size = 2; max_size < 5; ++max_size)
0140     {
0141 
0142         vertex_iterator_t vi, vi_end;
0143         for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
0144         {
0145             vertex_t v(*vi);
0146 
0147             // a hack to make sure we don't contract the middle edge of a path
0148             // of four degree-3 vertices
0149             if (max_size == 4 && neighbors[v].size() == 3)
0150             {
0151                 if (neighbors[neighbors[v][0]].size()
0152                         + neighbors[neighbors[v][1]].size()
0153                         + neighbors[neighbors[v][2]].size()
0154                     < 11 // so, it has two degree-3 neighbors
0155                 )
0156                     continue;
0157             }
0158 
0159             while (neighbors[v].size() > 0 && neighbors[v].size() < max_size)
0160             {
0161                 // Find one of v's neighbors u such that v and u
0162                 // have no neighbors in common. We'll look for such a
0163                 // neighbor with a naive cubic-time algorithm since the
0164                 // max size of any of the neighbor sets we'll consider
0165                 // merging is 3
0166 
0167                 bool neighbor_sets_intersect = false;
0168 
0169                 vertex_t min_u = graph_traits< Graph >::null_vertex();
0170                 vertex_t u;
0171                 v_list_iterator_t v_neighbor_end = neighbors[v].end();
0172                 for (v_list_iterator_t v_neighbor_itr = neighbors[v].begin();
0173                      v_neighbor_itr != v_neighbor_end; ++v_neighbor_itr)
0174                 {
0175                     neighbor_sets_intersect = false;
0176                     u = *v_neighbor_itr;
0177                     v_list_iterator_t u_neighbor_end = neighbors[u].end();
0178                     for (v_list_iterator_t u_neighbor_itr
0179                          = neighbors[u].begin();
0180                          u_neighbor_itr != u_neighbor_end
0181                          && !neighbor_sets_intersect;
0182                          ++u_neighbor_itr)
0183                     {
0184                         for (v_list_iterator_t inner_v_neighbor_itr
0185                              = neighbors[v].begin();
0186                              inner_v_neighbor_itr != v_neighbor_end;
0187                              ++inner_v_neighbor_itr)
0188                         {
0189                             if (*u_neighbor_itr == *inner_v_neighbor_itr)
0190                             {
0191                                 neighbor_sets_intersect = true;
0192                                 break;
0193                             }
0194                         }
0195                     }
0196                     if (!neighbor_sets_intersect
0197                         && (min_u == graph_traits< Graph >::null_vertex()
0198                             || neighbors[u].size() < neighbors[min_u].size()))
0199                     {
0200                         min_u = u;
0201                     }
0202                 }
0203 
0204                 if (min_u == graph_traits< Graph >::null_vertex())
0205                     // Exited the loop without finding an appropriate neighbor
0206                     // of v, so v must be a lost cause. Move on to other
0207                     // vertices.
0208                     break;
0209                 else
0210                     u = min_u;
0211 
0212                 detail::contract_edge(neighbors, u, v);
0213 
0214             } // end iteration over v's neighbors
0215 
0216         } // end iteration through vertices v
0217 
0218         if (max_size == 3)
0219         {
0220             // check to see whether we should go on to find a K_5
0221             for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
0222                 if (neighbors[*vi].size() == 4)
0223                 {
0224                     target_graph = detail::tg_k_5;
0225                     break;
0226                 }
0227 
0228             if (target_graph == detail::tg_k_3_3)
0229                 break;
0230         }
0231 
0232     } // end iteration through max degree 2,3, and 4
0233 
0234     // Now, there should only be 5 or 6 vertices with any neighbors. Find them.
0235 
0236     v_list_t main_vertices;
0237     vertex_iterator_t vi, vi_end;
0238 
0239     for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
0240     {
0241         if (!neighbors[*vi].empty())
0242             main_vertices.push_back(*vi);
0243     }
0244 
0245     // create a graph isomorphic to the contracted graph to test
0246     // against K_5 and K_3_3
0247     small_graph_t contracted_graph(main_vertices.size());
0248     std::map< vertex_t,
0249         typename graph_traits< small_graph_t >::vertex_descriptor >
0250         contracted_vertex_map;
0251 
0252     typename v_list_t::iterator itr, itr_end;
0253     itr_end = main_vertices.end();
0254     typename graph_traits< small_graph_t >::vertex_iterator si
0255         = vertices(contracted_graph).first;
0256 
0257     for (itr = main_vertices.begin(); itr != itr_end; ++itr, ++si)
0258     {
0259         contracted_vertex_map[*itr] = *si;
0260     }
0261 
0262     typename v_list_t::iterator jtr, jtr_end;
0263     for (itr = main_vertices.begin(); itr != itr_end; ++itr)
0264     {
0265         jtr_end = neighbors[*itr].end();
0266         for (jtr = neighbors[*itr].begin(); jtr != jtr_end; ++jtr)
0267         {
0268             if (get(vm, *itr) < get(vm, *jtr))
0269             {
0270                 add_edge(contracted_vertex_map[*itr],
0271                     contracted_vertex_map[*jtr], contracted_graph);
0272             }
0273         }
0274     }
0275 
0276     if (target_graph == detail::tg_k_5)
0277     {
0278         return boost::isomorphism(K_5, contracted_graph);
0279     }
0280     else // target_graph == tg_k_3_3
0281     {
0282         return boost::isomorphism(K_3_3, contracted_graph);
0283     }
0284 }
0285 
0286 template < typename Graph, typename ForwardIterator >
0287 bool is_kuratowski_subgraph(
0288     const Graph& g, ForwardIterator begin, ForwardIterator end)
0289 {
0290     return is_kuratowski_subgraph(g, begin, end, get(vertex_index, g));
0291 }
0292 
0293 }
0294 
0295 #endif //__IS_KURATOWSKI_SUBGRAPH_HPP__