Mercurial > hg > vamp-build-and-test
diff DEPENDENCIES/generic/include/boost/graph/is_kuratowski_subgraph.hpp @ 16:2665513ce2d3
Add boost headers
author | Chris Cannam |
---|---|
date | Tue, 05 Aug 2014 11:11:38 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DEPENDENCIES/generic/include/boost/graph/is_kuratowski_subgraph.hpp Tue Aug 05 11:11:38 2014 +0100 @@ -0,0 +1,331 @@ +//======================================================================= +// Copyright 2007 Aaron Windsor +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= +#ifndef __IS_KURATOWSKI_SUBGRAPH_HPP__ +#define __IS_KURATOWSKI_SUBGRAPH_HPP__ + +#include <boost/config.hpp> +#include <boost/tuple/tuple.hpp> //for tie +#include <boost/property_map/property_map.hpp> +#include <boost/graph/properties.hpp> +#include <boost/graph/isomorphism.hpp> +#include <boost/graph/adjacency_list.hpp> + +#include <algorithm> +#include <vector> +#include <set> + + + +namespace boost +{ + + namespace detail + { + + template <typename Graph> + Graph make_K_5() + { + typename graph_traits<Graph>::vertex_iterator vi, vi_end, inner_vi; + Graph K_5(5); + for(boost::tie(vi,vi_end) = vertices(K_5); vi != vi_end; ++vi) + for(inner_vi = next(vi); inner_vi != vi_end; ++inner_vi) + add_edge(*vi, *inner_vi, K_5); + return K_5; + } + + + template <typename Graph> + Graph make_K_3_3() + { + typename graph_traits<Graph>::vertex_iterator + vi, vi_end, bipartition_start, inner_vi; + Graph K_3_3(6); + bipartition_start = next(next(next(vertices(K_3_3).first))); + for(boost::tie(vi, vi_end) = vertices(K_3_3); vi != bipartition_start; ++vi) + for(inner_vi= bipartition_start; inner_vi != vi_end; ++inner_vi) + add_edge(*vi, *inner_vi, K_3_3); + return K_3_3; + } + + + template <typename AdjacencyList, typename Vertex> + void contract_edge(AdjacencyList& neighbors, Vertex u, Vertex v) + { + // Remove u from v's neighbor list + neighbors[v].erase(std::remove(neighbors[v].begin(), + neighbors[v].end(), u + ), + neighbors[v].end() + ); + + // Replace any references to u with references to v + typedef typename AdjacencyList::value_type::iterator + adjacency_iterator_t; + + adjacency_iterator_t u_neighbor_end = neighbors[u].end(); + for(adjacency_iterator_t u_neighbor_itr = neighbors[u].begin(); + u_neighbor_itr != u_neighbor_end; ++u_neighbor_itr + ) + { + Vertex u_neighbor(*u_neighbor_itr); + std::replace(neighbors[u_neighbor].begin(), + neighbors[u_neighbor].end(), u, v + ); + } + + // Remove v from u's neighbor list + neighbors[u].erase(std::remove(neighbors[u].begin(), + neighbors[u].end(), v + ), + neighbors[u].end() + ); + + // Add everything in u's neighbor list to v's neighbor list + std::copy(neighbors[u].begin(), + neighbors[u].end(), + std::back_inserter(neighbors[v]) + ); + + // Clear u's neighbor list + neighbors[u].clear(); + + } + + enum target_graph_t { tg_k_3_3, tg_k_5}; + + } // namespace detail + + + + + template <typename Graph, typename ForwardIterator, typename VertexIndexMap> + bool is_kuratowski_subgraph(const Graph& g, + ForwardIterator begin, + ForwardIterator end, + VertexIndexMap vm + ) + { + + typedef typename graph_traits<Graph>::vertex_descriptor vertex_t; + typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator_t; + typedef typename graph_traits<Graph>::edge_descriptor edge_t; + typedef typename graph_traits<Graph>::edges_size_type e_size_t; + typedef typename graph_traits<Graph>::vertices_size_type v_size_t; + typedef typename std::vector<vertex_t> v_list_t; + typedef typename v_list_t::iterator v_list_iterator_t; + typedef iterator_property_map + <typename std::vector<v_list_t>::iterator, VertexIndexMap> + vertex_to_v_list_map_t; + + typedef adjacency_list<vecS, vecS, undirectedS> small_graph_t; + + detail::target_graph_t target_graph = detail::tg_k_3_3; //unless we decide otherwise later + + static small_graph_t K_5(detail::make_K_5<small_graph_t>()); + + static small_graph_t K_3_3(detail::make_K_3_3<small_graph_t>()); + + v_size_t n_vertices(num_vertices(g)); + v_size_t max_num_edges(3*n_vertices - 5); + + std::vector<v_list_t> neighbors_vector(n_vertices); + vertex_to_v_list_map_t neighbors(neighbors_vector.begin(), vm); + + e_size_t count = 0; + for(ForwardIterator itr = begin; itr != end; ++itr) + { + + if (count++ > max_num_edges) + return false; + + edge_t e(*itr); + vertex_t u(source(e,g)); + vertex_t v(target(e,g)); + + neighbors[u].push_back(v); + neighbors[v].push_back(u); + + } + + + for(v_size_t max_size = 2; max_size < 5; ++max_size) + { + + vertex_iterator_t vi, vi_end; + for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) + { + vertex_t v(*vi); + + //a hack to make sure we don't contract the middle edge of a path + //of four degree-3 vertices + if (max_size == 4 && neighbors[v].size() == 3) + { + if (neighbors[neighbors[v][0]].size() + + neighbors[neighbors[v][1]].size() + + neighbors[neighbors[v][2]].size() + < 11 // so, it has two degree-3 neighbors + ) + continue; + } + + while (neighbors[v].size() > 0 && neighbors[v].size() < max_size) + { + // Find one of v's neighbors u such that v and u + // have no neighbors in common. We'll look for such a + // neighbor with a naive cubic-time algorithm since the + // max size of any of the neighbor sets we'll consider + // merging is 3 + + bool neighbor_sets_intersect = false; + + vertex_t min_u = graph_traits<Graph>::null_vertex(); + vertex_t u; + v_list_iterator_t v_neighbor_end = neighbors[v].end(); + for(v_list_iterator_t v_neighbor_itr = neighbors[v].begin(); + v_neighbor_itr != v_neighbor_end; + ++v_neighbor_itr + ) + { + neighbor_sets_intersect = false; + u = *v_neighbor_itr; + v_list_iterator_t u_neighbor_end = neighbors[u].end(); + for(v_list_iterator_t u_neighbor_itr = + neighbors[u].begin(); + u_neighbor_itr != u_neighbor_end && + !neighbor_sets_intersect; + ++u_neighbor_itr + ) + { + for(v_list_iterator_t inner_v_neighbor_itr = + neighbors[v].begin(); + inner_v_neighbor_itr != v_neighbor_end; + ++inner_v_neighbor_itr + ) + { + if (*u_neighbor_itr == *inner_v_neighbor_itr) + { + neighbor_sets_intersect = true; + break; + } + } + + } + if (!neighbor_sets_intersect && + (min_u == graph_traits<Graph>::null_vertex() || + neighbors[u].size() < neighbors[min_u].size()) + ) + { + min_u = u; + } + + } + + if (min_u == graph_traits<Graph>::null_vertex()) + // Exited the loop without finding an appropriate neighbor of + // v, so v must be a lost cause. Move on to other vertices. + break; + else + u = min_u; + + detail::contract_edge(neighbors, u, v); + + }//end iteration over v's neighbors + + }//end iteration through vertices v + + if (max_size == 3) + { + // check to see whether we should go on to find a K_5 + for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) + if (neighbors[*vi].size() == 4) + { + target_graph = detail::tg_k_5; + break; + } + + if (target_graph == detail::tg_k_3_3) + break; + } + + }//end iteration through max degree 2,3, and 4 + + + //Now, there should only be 5 or 6 vertices with any neighbors. Find them. + + v_list_t main_vertices; + vertex_iterator_t vi, vi_end; + + for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) + { + if (!neighbors[*vi].empty()) + main_vertices.push_back(*vi); + } + + // create a graph isomorphic to the contracted graph to test + // against K_5 and K_3_3 + small_graph_t contracted_graph(main_vertices.size()); + std::map<vertex_t,typename graph_traits<small_graph_t>::vertex_descriptor> + contracted_vertex_map; + + typename v_list_t::iterator itr, itr_end; + itr_end = main_vertices.end(); + typename graph_traits<small_graph_t>::vertex_iterator + si = vertices(contracted_graph).first; + + for(itr = main_vertices.begin(); itr != itr_end; ++itr, ++si) + { + contracted_vertex_map[*itr] = *si; + } + + typename v_list_t::iterator jtr, jtr_end; + for(itr = main_vertices.begin(); itr != itr_end; ++itr) + { + jtr_end = neighbors[*itr].end(); + for(jtr = neighbors[*itr].begin(); jtr != jtr_end; ++jtr) + { + if (get(vm,*itr) < get(vm,*jtr)) + { + add_edge(contracted_vertex_map[*itr], + contracted_vertex_map[*jtr], + contracted_graph + ); + } + } + } + + if (target_graph == detail::tg_k_5) + { + return boost::isomorphism(K_5,contracted_graph); + } + else //target_graph == tg_k_3_3 + { + return boost::isomorphism(K_3_3,contracted_graph); + } + + + } + + + + + + template <typename Graph, typename ForwardIterator> + bool is_kuratowski_subgraph(const Graph& g, + ForwardIterator begin, + ForwardIterator end + ) + { + return is_kuratowski_subgraph(g, begin, end, get(vertex_index,g)); + } + + + + +} + +#endif //__IS_KURATOWSKI_SUBGRAPH_HPP__