/* Copyright (C) 2007-2013 Arjen G Lentz & Antony T Curtis for Open Query This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /* ====================================================================== Open Query Graph Computation Engine, based on a concept by Arjen Lentz v3 implementation by Antony Curtis, Arjen Lentz, Andrew McDonnell For more information, documentation, support, enhancement engineering, see http://openquery.com/graph or contact graph@openquery.com ====================================================================== */ #pragma once #include "oqgraph_judy.h" #include "oqgraph_thunk.h" #include #include namespace open_query { struct OQGraphTraversalCategory : public boost::bidirectional_graph_tag , public boost::adjacency_graph_tag , public boost::edge_list_graph_tag { }; } namespace oqgraph3 { struct traversal_category : public boost::adjacency_graph_tag , public boost::bidirectional_graph_tag , public boost::edge_list_graph_tag { }; struct edge_iterator { typedef edge_iterator self; typedef edge_info value_type; typedef edge_info& reference; typedef edge_info pointer; typedef std::ptrdiff_t difference_type; typedef std::input_iterator_tag iterator_category; edge_iterator() { } edge_iterator(const graph_ptr& graph, size_t offset=0) : _graph(graph) , _offset(offset) { } value_type operator*(); self& operator+=(size_t n) { _offset+= n; return *this; } self& operator++() { ++_offset; return *this; } self operator++(int) { size_t temp= _offset++; return edge_iterator(_graph, temp); } bool seek(); bool operator==(const self& x); bool operator!=(const self& x); graph_ptr _graph; size_t _offset; }; struct vertex_iterator { typedef vertex_iterator self; typedef vertex_id value_type; typedef vertex_id& reference; typedef vertex_id pointer; typedef std::ptrdiff_t difference_type; typedef std::input_iterator_tag iterator_category; vertex_iterator() { } vertex_iterator(const cursor_ptr& pos) : _cursor(pos.operator->()) { } vertex_id operator*() const { edge_info edge(*_cursor); if (!_seen.test(edge.origid())) return edge.origid(); else return edge.destid(); } self& operator++() { edge_info edge(*_cursor); if (!_seen.test(edge.origid())) { _seen.set(edge.origid()); } else { _seen.set(edge.destid()); } while (_seen.test(edge.origid()) && _seen.test(edge.destid())) { if (_cursor->seek_next()) break; edge= _cursor; } return *this; } self operator++(int) { cursor* t(new cursor(*_cursor)); ++(*this); return vertex_iterator(t); } bool operator==(const self& x) { return *_cursor == *x._cursor; } bool operator!=(const self& x) { return *_cursor != *x._cursor; } cursor_ptr _cursor; open_query::judy_bitset _seen; }; struct out_edge_iterator { typedef out_edge_iterator self; typedef edge_info value_type; typedef edge_info& reference; typedef edge_info pointer; typedef std::ptrdiff_t difference_type; typedef std::input_iterator_tag iterator_category; out_edge_iterator() { } out_edge_iterator(const cursor_ptr& cursor) : _cursor(cursor) { } value_type operator*() { return value_type(_cursor); } self& operator++() { _cursor->seek_next(); return *this; } self operator++(int) { cursor_ptr t(new cursor(*_cursor)); ++(*this); return out_edge_iterator(t); } bool operator==(const self& x) { return _cursor == x._cursor; } bool operator!=(const self& x) { return _cursor != x._cursor; } cursor_ptr _cursor; }; struct in_edge_iterator { typedef in_edge_iterator self; typedef edge_info value_type; typedef edge_info& reference; typedef edge_info pointer; typedef std::ptrdiff_t difference_type; typedef std::input_iterator_tag iterator_category; in_edge_iterator() { } in_edge_iterator(const cursor_ptr& cursor) : _cursor(cursor) { } value_type operator*() const { return value_type(_cursor); } self& operator++() { _cursor->seek_next(); return *this; } self operator++(int) { cursor_ptr t(new cursor(*_cursor)); ++(*this); return in_edge_iterator(t); } bool operator==(const self& x) const { return _cursor == x._cursor; } bool operator!=(const self& x) const { return _cursor != x._cursor; } cursor_ptr _cursor; }; struct vertex_index_property_map { typedef vertex_id value_type; typedef value_type reference; typedef vertex_id key_type; typedef boost::readable_property_map_tag category; vertex_index_property_map(const graph& g) : _g(g) { } const graph& _g; friend inline reference get(const vertex_index_property_map&, key_type key) { return key; } }; struct edge_weight_property_map { typedef weight_t value_type; typedef value_type reference; typedef edge_info key_type; typedef boost::readable_property_map_tag category; edge_weight_property_map(const graph& g) : _g(g) { } friend inline reference get(const edge_weight_property_map& p, const key_type& key) { return key.weight(); } const graph& _g; }; struct edge_index_property_map { typedef cursor_ptr value_type; typedef cursor_ptr reference; typedef edge_info key_type; typedef boost::readable_property_map_tag category; edge_index_property_map(const graph& g) : _g(g) { } const graph& _g; }; } namespace boost { template<> struct graph_traits { typedef oqgraph3::vertex_id vertex_descriptor; typedef oqgraph3::edge_info edge_descriptor; typedef boost::adjacency_iterator_generator< oqgraph3::graph, oqgraph3::vertex_id, oqgraph3::out_edge_iterator>::type adjacency_iterator; typedef oqgraph3::out_edge_iterator out_edge_iterator; typedef oqgraph3::in_edge_iterator in_edge_iterator; typedef oqgraph3::vertex_iterator vertex_iterator; typedef oqgraph3::edge_iterator edge_iterator; typedef boost::directed_tag directed_category; typedef boost::allow_parallel_edge_tag edge_parallel_category; typedef oqgraph3::traversal_category traversal_category; typedef oqgraph3::vertices_size_type vertices_size_type; typedef oqgraph3::edges_size_type edges_size_type; typedef oqgraph3::degree_size_type degree_size_type; static inline oqgraph3::vertex_id null_vertex() { return oqgraph3::vertex_id(-1); } }; template<> struct graph_traits : public graph_traits { }; template <> struct graph_property_type { typedef no_property type; }; template <> struct vertex_property_type { typedef no_property type; }; template <> struct edge_property_type { typedef no_property type; }; #if BOOST_VERSION < 106000 && BOOST_VERSION >= 104601 template <> struct graph_bundle_type { typedef no_graph_bundle type; }; template <> struct vertex_bundle_type { typedef no_vertex_bundle type; }; template <> struct edge_bundle_type { typedef no_edge_bundle type; }; #endif template<> struct property_map { typedef void type; typedef oqgraph3::edge_weight_property_map const_type; }; template<> struct property_map { typedef void type; typedef oqgraph3::vertex_index_property_map const_type; }; template<> struct property_map { typedef void type; typedef oqgraph3::edge_index_property_map const_type; }; } namespace oqgraph3 { using namespace boost; inline graph_traits::vertex_descriptor source( const graph_traits::edge_descriptor& e, const oqgraph3::graph&) { return e.origid(); } inline graph_traits::vertex_descriptor target( const graph_traits::edge_descriptor& e, const oqgraph3::graph&) { return e.destid(); } inline std::pair< graph_traits::out_edge_iterator, graph_traits::out_edge_iterator> out_edges( graph_traits::vertex_descriptor v, const oqgraph3::graph& g) { oqgraph3::cursor* end= new oqgraph3::cursor(const_cast(&g)); oqgraph3::cursor* start= new oqgraph3::cursor(const_cast(&g)); start->seek_to(v, boost::none); return std::make_pair( graph_traits::out_edge_iterator(start), graph_traits::out_edge_iterator(end)); } inline graph_traits::degree_size_type out_degree( graph_traits::vertex_descriptor v, const oqgraph3::graph& g) { std::size_t count = 0; for (std::pair< graph_traits::out_edge_iterator, graph_traits::out_edge_iterator> i= out_edges(v, g); i.first != i.second; ++i.first) { ++count; } return count; } inline std::pair< graph_traits::in_edge_iterator, graph_traits::in_edge_iterator> in_edges( graph_traits::vertex_descriptor v, const oqgraph3::graph& g) { oqgraph3::cursor* end= new oqgraph3::cursor(const_cast(&g)); oqgraph3::cursor* start= new oqgraph3::cursor(const_cast(&g)); start->seek_to(boost::none, v); return std::make_pair( graph_traits::in_edge_iterator(start), graph_traits::in_edge_iterator(end)); } inline graph_traits::degree_size_type in_degree( graph_traits::vertex_descriptor v, const oqgraph3::graph& g) { std::size_t count = 0; for (std::pair< graph_traits::in_edge_iterator, graph_traits::in_edge_iterator> it= in_edges(v, g); it.first != it.second; ++it.first) { ++count; } return count; } // EdgeListGraph concepts inline std::pair< graph_traits::edge_iterator, graph_traits::edge_iterator> edges(const oqgraph3::graph& g) { std::size_t end= std::size_t(-1); std::size_t start= end; if (g.num_edges()) start= 0; return std::make_pair( graph_traits::edge_iterator( const_cast(&g), start), graph_traits::edge_iterator( const_cast(&g), end)); } inline std::pair< graph_traits::vertex_iterator, graph_traits::vertex_iterator> vertices(const oqgraph3::graph& g) { oqgraph3::cursor* start= new oqgraph3::cursor(const_cast(&g)); start->seek_to(boost::none, boost::none); return std::make_pair( graph_traits::vertex_iterator(start), graph_traits::vertex_iterator( new oqgraph3::cursor(const_cast(&g)))); } inline graph_traits::vertices_size_type num_vertices(const oqgraph3::graph& g) { std::size_t count = 0; for (std::pair< graph_traits::vertex_iterator, graph_traits::vertex_iterator> i= vertices(g); i.first != i.second; ++i.first) { ++count; } return count; } inline property_map< oqgraph3::graph, edge_weight_t>::const_type::reference get( edge_weight_t, const oqgraph3::graph& g, const property_map< oqgraph3::graph, edge_weight_t>::const_type::key_type& key) { return key.weight(); } inline property_map< oqgraph3::graph, edge_weight_t>::const_type get(edge_weight_t, const oqgraph3::graph& g) { return property_map::const_type(g); } inline property_map< oqgraph3::graph, edge_index_t>::const_type::reference get(edge_index_t, const oqgraph3::graph&, const property_map< oqgraph3::graph, edge_index_t>::const_type::key_type& key) { return key._cursor; } inline property_map::const_type get(edge_index_t, const oqgraph3::graph& g) { return property_map::const_type(g); } inline property_map::const_type::reference get(const property_map::const_type&, const property_map::const_type::key_type& key) { return key._cursor; } inline property_map::const_type::reference get(vertex_index_t, const oqgraph3::graph&, const property_map::const_type::key_type& key) { return key; } inline property_map::const_type get(vertex_index_t, const oqgraph3::graph& g) { return property_map::const_type(g); } inline optional::vertex_descriptor> find_vertex(oqgraph3::vertex_id id, const oqgraph3::graph& g) { // Fix for https://bugs.launchpad.net/oqgraph/+bug/1196020 returning vertex even when not in graph // Psuedocode for fix: // if count(*) from g->TABLE where source=id or target=id > 0 then return id else return null oqgraph3::cursor* found_cursor = new oqgraph3::cursor(const_cast(&g)); bool found = (found_cursor->seek_to(id, boost::none) && found_cursor->seek_to(boost::none, id)); delete found_cursor; if (found) { // id is neither a from or a to in a link return optional::vertex_descriptor>(); } return id; } }