├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md └── graph ├── CMakeLists.txt ├── common.cpp ├── common.hpp ├── dfs.cpp ├── dfs.hpp ├── dfs.test ├── CMakeLists.txt ├── directed.cpp └── undirected.cpp ├── digraph.cpp ├── digraph.hpp ├── digraph.test ├── CMakeLists.txt └── general.cpp ├── graph.cpp ├── graph.hpp ├── graph.test ├── CMakeLists.txt └── general.cpp ├── output.cpp ├── output.hpp ├── queue.cpp ├── queue.hpp ├── queue.test ├── CMakeLists.txt └── insertion.cpp ├── utility.cpp └── utility.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | *.smod 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | *.lib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2008-2016 Andrew Sutton 2 | # All rights reserved 3 | 4 | cmake_minimum_required(VERSION 3.0) 5 | project(cxx14.graph CXX) 6 | 7 | enable_testing() 8 | 9 | set(CMAKE_CXX_FLAGS "-std=c++1z -fconcepts") 10 | 11 | include_directories(.) 12 | 13 | macro(add_unit_test target) 14 | add_executable(${target} ${ARGN}) 15 | target_link_libraries(${target} graph) 16 | add_test(${target} ${target}) 17 | endmacro() 18 | 19 | add_subdirectory(graph) 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Andrew Sutton 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cxx14-graph 2 | A C++ 14 implementation of graph data structures 3 | -------------------------------------------------------------------------------- /graph/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Andrew Sutton 2 | # All rights reserved 3 | 4 | cmake_minimum_required(VERSION 3.0) 5 | project(graph CXX) 6 | 7 | enable_testing() 8 | 9 | set(CMAKE_CXX_FLAGS "-std=c++1z -fconcepts") 10 | 11 | add_library(graph 12 | utility.cpp 13 | common.cpp 14 | graph.cpp 15 | digraph.cpp 16 | output.cpp 17 | dfs.cpp 18 | queue.cpp 19 | ) 20 | 21 | 22 | macro(add_unit_test target) 23 | add_executable(${target} ${ARGN}) 24 | target_link_libraries(${target} graph) 25 | add_test(${target} ${target}) 26 | endmacro() 27 | 28 | 29 | add_subdirectory(graph.test) 30 | add_subdirectory(digraph.test) 31 | add_subdirectory(dfs.test) 32 | add_subdirectory(queue.test) 33 | -------------------------------------------------------------------------------- /graph/common.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Andrew Sutton 2 | // All rights reserved 3 | 4 | #include "common.hpp" 5 | -------------------------------------------------------------------------------- /graph/common.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Andrew Sutton 2 | // All rights reserved 3 | 4 | #ifndef GRAPH_COMMON_HPP 5 | #define GRAPH_COMMON_HPP 6 | 7 | #include "utility.hpp" 8 | 9 | #include 10 | #include 11 | 12 | 13 | namespace origin { 14 | 15 | // Used to indicate the absence of labels on graphs and edges. 16 | struct empty { }; 17 | 18 | // Represents a vertex within a graph. 19 | using vertex_t = std::size_t; 20 | 21 | // Represents an edge within a graph. 22 | using edge_t = std::size_t; 23 | 24 | // A list of incident edges. 25 | using edge_list = std::vector; 26 | 27 | 28 | // Construct a label over a vector. 29 | template 30 | auto vertex_label(std::vector& vec) { 31 | return [&vec](vertex_t v) -> T& { return vec[v]; }; 32 | } 33 | 34 | // Construct a label over a vector. 35 | template 36 | auto edge_label(std::vector& vec) { 37 | return [&vec](edge_t e) -> T& { return vec[e]; }; 38 | } 39 | 40 | 41 | } // namespace origin 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /graph/dfs.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Andrew Sutton 2 | // All rights reserved 3 | 4 | #include "dfs.hpp" 5 | -------------------------------------------------------------------------------- /graph/dfs.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Andrew Sutton 2 | // All rights reserved 3 | 4 | #ifndef GRAPH_DFS_HPP 5 | #define GRAPH_DFS_HPP 6 | 7 | #include "common.hpp" 8 | 9 | 10 | namespace origin { 11 | 12 | // A basic DFS implementation for directed graphs. 13 | template 14 | struct directed_dfs 15 | { 16 | directed_dfs(G& g) 17 | : graph(g), 18 | colors(graph.num_vertices(), 0), 19 | pre_times(graph.num_vertices(), -1), 20 | post_times(graph.num_vertices(), -1), 21 | parents(graph.num_vertices()), 22 | clock(0) 23 | { } 24 | 25 | void operator()() 26 | { 27 | auto color = vertex_label(colors); 28 | auto pre = vertex_label(pre_times); 29 | auto post = vertex_label(post_times); 30 | auto parent = vertex_label(parents); 31 | 32 | // Extra initialization. 33 | for (vertex_t v : graph.vertices()) 34 | parent(v) = v; 35 | 36 | search(color, pre, post, parent); 37 | } 38 | 39 | template 40 | void search(L1 color, L1 pre, L1 post, L2 parent) 41 | { 42 | for (vertex_t v : graph.vertices()) { 43 | if (color(v) == 0) 44 | explore(v, color, pre, post, parent); 45 | } 46 | } 47 | 48 | template 49 | void explore(vertex_t u, L1 color, L1 pre, L1 post, L2 parent) 50 | { 51 | color(u) = 1; // color u gray (on stack) 52 | pre(u) = clock++; 53 | 54 | for (edge_t e : graph.out_edges(u)) { 55 | vertex_t v = graph.target(e); 56 | if (color(v) == 0) { 57 | // (u, v) is a tree edge 58 | parent(v) = u; 59 | explore(v, color, pre, post, parent); 60 | } 61 | else if (color(v) == 1) { 62 | // (u, v) is a back edge 63 | } 64 | else { 65 | // (u, v) is a cross or forward edge 66 | } 67 | } 68 | 69 | post(u) = clock++; 70 | color(u) = 2; // color u black (done). 71 | } 72 | 73 | G& graph; 74 | std::vector colors; 75 | std::vector pre_times; 76 | std::vector post_times; 77 | std::vector parents; 78 | int clock; 79 | }; 80 | 81 | 82 | // A basic DFS implementation for undirected graphs. 83 | // 84 | // TODO: If undirected graphs don't have forward or cross edges, then 85 | // what's the purpose of maintaining an extra state in order to recover 86 | // that information? Consider reducing colors to a simple 87 | template 88 | struct undirected_dfs 89 | { 90 | undirected_dfs(G& g) 91 | : graph(g), 92 | colors(graph.num_vertices(), 0), 93 | pre_times(graph.num_vertices(), -1), 94 | post_times(graph.num_vertices(), -1), 95 | parents(graph.num_vertices()), 96 | clock(0) 97 | { } 98 | 99 | void operator()() 100 | { 101 | auto color = vertex_label(colors); 102 | auto pre = vertex_label(pre_times); 103 | auto post = vertex_label(post_times); 104 | auto parent = vertex_label(parents); 105 | 106 | // Extra initialization. 107 | for (vertex_t v : graph.vertices()) 108 | parent(v) = v; 109 | 110 | search(color, pre, post, parent); 111 | } 112 | 113 | template 114 | void search(L1 color, L1 pre, L1 post, L2 parent) 115 | { 116 | for (vertex_t v : graph.vertices()) { 117 | if (color(v) == 0) 118 | explore(v, color, pre, post, parent); 119 | } 120 | } 121 | 122 | template 123 | void explore(vertex_t u, L1 color, L1 pre, L1 post, L2 parent) 124 | { 125 | color(u) = 1; // color u gray (on stack) 126 | pre(u) = clock++; 127 | 128 | for (edge_t e : graph.edges(u)) { 129 | vertex_t v = graph.opposite(e, u); 130 | if (color(v) == 0) { 131 | // (u, v) is a tree edge 132 | parent(v) = u; 133 | explore(v, color, pre, post, parent); 134 | } 135 | else { 136 | // (u, v) is a back edge 137 | } 138 | } 139 | 140 | post(u) = clock++; 141 | color(u) = 2; // color u black (done) 142 | } 143 | 144 | G& graph; 145 | std::vector colors; 146 | std::vector pre_times; 147 | std::vector post_times; 148 | std::vector parents; 149 | int clock; 150 | }; 151 | 152 | 153 | 154 | } // namespace origin 155 | 156 | #endif 157 | -------------------------------------------------------------------------------- /graph/dfs.test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Andrew Sutton 2 | # All rights reserved 3 | 4 | add_unit_test(test-dfs-undirected undirected.cpp) 5 | add_unit_test(test-dfs-directed directed.cpp) 6 | -------------------------------------------------------------------------------- /graph/dfs.test/directed.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Andrew Sutton 2 | // All rights reserved 3 | 4 | #include "../digraph.hpp" 5 | #include "../dfs.hpp" 6 | 7 | #include 8 | #include 9 | 10 | 11 | using namespace origin; 12 | 13 | 14 | int 15 | main() 16 | { 17 | using G = digraph; 18 | G g; 19 | vertex_t v[] { 20 | g.add_vertex('a'), // 0 21 | g.add_vertex('b'), // 1 22 | g.add_vertex('c'), // 2 23 | g.add_vertex('d'), // 3 24 | g.add_vertex('e'), // 4 25 | g.add_vertex('f') // 5 26 | }; 27 | edge_t e[] { 28 | g.add_edge(v[0], v[1], 0), // a -> b 29 | g.add_edge(v[0], v[3], 1), // a -> d 30 | g.add_edge(v[1], v[2], 2), // b -> c 31 | g.add_edge(v[1], v[3], 3), // b -> d 32 | g.add_edge(v[2], v[0], 4), // c -> a 33 | g.add_edge(v[3], v[2], 5), // d -> c 34 | g.add_edge(v[4], v[5], 6), // e -> f 35 | }; 36 | 37 | directed_dfs dfs(g); 38 | dfs(); 39 | 40 | // TODO: Actually verify properties of the search. 41 | for (vertex_t v : g.vertices()) 42 | std::cout << v << ": " << dfs.parents[v] << '\n'; 43 | } 44 | -------------------------------------------------------------------------------- /graph/dfs.test/undirected.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Andrew Sutton 2 | // All rights reserved 3 | 4 | #include "../graph.hpp" 5 | #include "../dfs.hpp" 6 | 7 | #include 8 | #include 9 | 10 | 11 | using namespace origin; 12 | 13 | 14 | int 15 | main() 16 | { 17 | using G = graph; 18 | G g; 19 | vertex_t v[] { 20 | g.add_vertex('a'), // 0 21 | g.add_vertex('b'), // 1 22 | g.add_vertex('c'), // 2 23 | g.add_vertex('d'), // 3 24 | g.add_vertex('e'), // 4 25 | g.add_vertex('f') // 5 26 | }; 27 | edge_t e[] { 28 | g.add_edge(v[0], v[1], 0), // a -- b 29 | g.add_edge(v[0], v[3], 1), // a -- d 30 | g.add_edge(v[1], v[2], 2), // b -- c 31 | g.add_edge(v[1], v[3], 3), // b -- d 32 | g.add_edge(v[2], v[0], 4), // c -- a 33 | g.add_edge(v[3], v[2], 5), // d -- c 34 | g.add_edge(v[4], v[5], 6), // e -- f 35 | }; 36 | 37 | undirected_dfs dfs(g); 38 | dfs(); 39 | 40 | // TODO: Actually verify properties of the search. 41 | for (vertex_t v : g.vertices()) 42 | std::cout << v << ": " << dfs.parents[v] << '\n'; 43 | } 44 | -------------------------------------------------------------------------------- /graph/digraph.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Andrew Sutton 2 | // All rights reserved 3 | 4 | #include "digraph.hpp" 5 | -------------------------------------------------------------------------------- /graph/digraph.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Andrew Sutton 2 | // All rights reserved 3 | 4 | #ifndef GRAPH_DIRECTED_LIST_HPP 5 | #define GRAPH_DIRECTED_LIST_HPP 6 | 7 | #include "utility.hpp" 8 | #include "common.hpp" 9 | 10 | #include 11 | 12 | 13 | namespace origin { 14 | 15 | // A labeled vertex with source and target edges. This is specialized for the 16 | // empty case, which associates no label. 17 | template 18 | struct directed_vertex 19 | { 20 | directed_vertex() = default; 21 | 22 | directed_vertex(T const& t) 23 | : out_(), in_(), data(t) 24 | { } 25 | 26 | bool is_source() const { return in_degree() == 0; } 27 | bool is_sing() const { return out_degree() == 0; } 28 | 29 | edge_list const& out_edges() const { return out_; } 30 | edge_list const& in_edges() const { return in_; } 31 | 32 | std::size_t out_degree() const { return out_.size(); } 33 | std::size_t in_degree() const { return in_.size(); } 34 | std::size_t degree() const { return out_degree() + in_degree(); } 35 | 36 | edge_list out_; 37 | edge_list in_; 38 | T data; 39 | }; 40 | 41 | 42 | // Edges 43 | 44 | // An labeled edge with source and target vertexes. This is specialized for the 45 | // empty case, which associates no label. 46 | template 47 | struct directed_edge 48 | { 49 | // TODO: Value-initialize the data element or not? We currently do not. 50 | directed_edge(vertex_t u, vertex_t v) 51 | : ends_{u, v} 52 | { } 53 | 54 | directed_edge(vertex_t u, vertex_t v, T const& t) 55 | : ends_{u, v}, data(t) 56 | { } 57 | 58 | vertex_t source() const { return ends_[0]; } 59 | vertex_t target() const { return ends_[1]; } 60 | 61 | vertex_t ends_[2]; 62 | T data; 63 | }; 64 | 65 | 66 | // Graph 67 | 68 | // A directed graph that is parameterized by the edge labels for vertexes (V) 69 | // and edges (U). Both arguments default to empty, indicating that no labels 70 | // are associated with U or V. 71 | // 72 | // TODO: Support vertex and edge removal by keeping a free-list of unused 73 | // indexes and clever used of in-place allocation/deletion. Note that 74 | // supporting removal makes vertex traversal more complex (forward only). 75 | // 76 | // TODO: Implement const iterators and ranges. 77 | template 78 | struct digraph 79 | { 80 | using vertex_type = directed_vertex; 81 | using vertex_set = std::vector; 82 | using vertex_iterator = counted_iterator; 83 | using vertex_range = counted_range; 84 | 85 | using edge_type = directed_edge; 86 | using edge_set = std::vector; 87 | using edge_iterator = counted_iterator; 88 | using edge_range = counted_range; 89 | 90 | // Vertex list 91 | bool is_null() const; 92 | std::size_t num_vertices() const; 93 | 94 | vertex_range vertices() const; 95 | vertex_iterator begin_vertices() const; 96 | vertex_iterator end_vertices() const; 97 | 98 | // Edge list 99 | bool is_empty() const; 100 | std::size_t num_edges() const; 101 | 102 | edge_range edges() const; 103 | edge_iterator begin_edges() const; 104 | edge_iterator end_edges() const; 105 | 106 | // Incidence list 107 | edge_list out_edges(vertex_t) const; 108 | edge_list in_edges(vertex_t) const; 109 | 110 | std::size_t out_degree(vertex_t) const; 111 | std::size_t in_degree(vertex_t) const; 112 | std::size_t degree(vertex_t) const; 113 | 114 | edge_iterator find_edge(vertex_t, vertex_t) const; 115 | bool has_edge(vertex_t, vertex_t) const; 116 | edge_t edge(vertex_t, vertex_t) const; 117 | 118 | vertex_t source(edge_t) const; 119 | vertex_t target(edge_t) const; 120 | 121 | // Incremental construction 122 | vertex_t add_vertex(); 123 | vertex_t add_vertex(V const&); 124 | 125 | edge_t add_edge(vertex_t, vertex_t); 126 | edge_t add_edge(vertex_t, vertex_t, E const&); 127 | 128 | vertex_set verts_; 129 | edge_set edges_; 130 | }; 131 | 132 | // Vertex list 133 | 134 | // Returns true if the graph has no vertices. 135 | template 136 | bool 137 | digraph::is_null() const 138 | { 139 | return num_vertices() == 0; 140 | } 141 | 142 | // Returns the number of vertices in the graph. 143 | template 144 | std::size_t 145 | digraph::num_vertices() const 146 | { 147 | return verts_.size(); 148 | } 149 | 150 | // Returns the list of vertices in the graph. 151 | template 152 | auto 153 | digraph::vertices() const -> vertex_range 154 | { 155 | return vertex_range(num_vertices()); 156 | } 157 | 158 | // Returns an iterator to the first vertex in the graph. 159 | template 160 | auto 161 | digraph::begin_vertices() const -> vertex_iterator 162 | { 163 | return vertex_iterator(0); 164 | } 165 | 166 | // Returns an iterator past the last vertex in the graph. 167 | template 168 | auto 169 | digraph::end_vertices() const -> vertex_iterator 170 | { 171 | return vertex_iterator(num_vertices()); 172 | } 173 | 174 | // Edge list 175 | 176 | // Returns true if the graph has no edges. 177 | template 178 | bool 179 | digraph::is_empty() const 180 | { 181 | return num_edges() == 0; 182 | } 183 | 184 | // Returns the number of edges in the graph. 185 | template 186 | std::size_t 187 | digraph::num_edges() const 188 | { 189 | return edges_.size(); 190 | } 191 | 192 | // Returns the list of edges in the graph. 193 | template 194 | auto 195 | digraph::edges() const -> edge_range 196 | { 197 | return edge_range(num_edges()); 198 | } 199 | 200 | // Returns an iterator to the first edge in the graph. 201 | template 202 | auto 203 | digraph::begin_edges() const -> edge_iterator 204 | { 205 | return edge_iterator(0); 206 | } 207 | 208 | // Returns an iterator past the last edge in the graph. 209 | template 210 | auto 211 | digraph::end_edges() const -> edge_iterator 212 | { 213 | return edge_iterator(num_edges()); 214 | } 215 | 216 | // Incidence 217 | 218 | // Returns the list of outgoing edges for v. 219 | template 220 | edge_list 221 | digraph::out_edges(vertex_t v) const 222 | { 223 | return verts_[v].out_edges(); 224 | } 225 | 226 | // Returns the list incoming edges to v. 227 | template 228 | edge_list 229 | digraph::in_edges(vertex_t v) const 230 | { 231 | return verts_[v].in_edges(); 232 | } 233 | 234 | // Returns the out degree of v. 235 | template 236 | std::size_t 237 | digraph::out_degree(vertex_t v) const 238 | { 239 | return verts_[v].out_degree(); 240 | } 241 | 242 | // Returns the in degree of v. 243 | template 244 | std::size_t 245 | digraph::in_degree(vertex_t v) const 246 | { 247 | return verts_[v].in_degree(); 248 | } 249 | 250 | // Returns the (total) degree of v. 251 | template 252 | std::size_t 253 | digraph::degree(vertex_t v) const 254 | { 255 | return verts_[v].degree(); 256 | } 257 | 258 | // Returns an iterator to the edge (u, v) if it exists. Otherwise, returns 259 | // end_edges(). 260 | template 261 | auto 262 | digraph::find_edge(vertex_t u, vertex_t v) const -> edge_iterator 263 | { 264 | // Search the shortest list for the corresponding edge. 265 | if (out_degree(u) < in_degree(v)) { 266 | edge_list const& out = verts_[u].out_; 267 | for (edge_t e : out) { 268 | if (target(e) == v) 269 | return begin_edges() + e; 270 | } 271 | } 272 | else { 273 | edge_list const& in = verts_[v].in_; 274 | for (edge_t e : in) { 275 | if (source(e) == u) 276 | return begin_edges() + e; 277 | } 278 | } 279 | return end_edges(); 280 | } 281 | 282 | // Returns true if the edge (u, v) exists. 283 | template 284 | bool 285 | digraph::has_edge(vertex_t u, vertex_t v) const 286 | { 287 | return find_edge(u, v) != end_edges(); 288 | } 289 | 290 | // Assuming (u, v) exists, returns that edge. 291 | template 292 | edge_t 293 | digraph::edge(vertex_t u, vertex_t v) const 294 | { 295 | assert(has_edge(u, v)); 296 | return *find_edge(u, v); 297 | } 298 | 299 | // In the edge (u, v), returns u. 300 | template 301 | vertex_t 302 | digraph::source(edge_t e) const 303 | { 304 | return edges_[e].source(); 305 | } 306 | 307 | // In the edge (u, v), returns v. 308 | template 309 | vertex_t 310 | digraph::target(edge_t e) const 311 | { 312 | return edges_[e].target(); 313 | } 314 | 315 | // Incremental construction 316 | 317 | template 318 | vertex_t 319 | digraph::add_vertex() 320 | { 321 | verts_.emplace_back(); 322 | return verts_.size() - 1; 323 | } 324 | 325 | template 326 | vertex_t 327 | digraph::add_vertex(V const& v) 328 | { 329 | verts_.emplace_back(v); 330 | return verts_.size() - 1; 331 | } 332 | 333 | template 334 | edge_t 335 | digraph::add_edge(vertex_t u, vertex_t v) 336 | { 337 | assert(!has_edge(u, v)); 338 | edges_.emplace_back(u, v); 339 | edge_t e = edges_.size() - 1; 340 | verts_[u].out_.push_back(e); 341 | verts_[v].in_.push_back(e); 342 | return e; 343 | } 344 | 345 | template 346 | edge_t 347 | digraph::add_edge(vertex_t u, vertex_t v, E const& x) 348 | { 349 | assert(!has_edge(u, v)); 350 | edges_.emplace_back(u, v, x); 351 | edge_t e = edges_.size() - 1; 352 | verts_[u].out_.push_back(e); 353 | verts_[v].in_.push_back(e); 354 | return e; 355 | } 356 | 357 | } // namespace origin 358 | 359 | #endif 360 | -------------------------------------------------------------------------------- /graph/digraph.test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | add_unit_test(test-digraph-general general.cpp) 4 | -------------------------------------------------------------------------------- /graph/digraph.test/general.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Andrew Sutton 2 | // All rights reserved 3 | 4 | #include "../digraph.hpp" 5 | #include "../output.hpp" 6 | 7 | #include 8 | #include 9 | 10 | 11 | using namespace origin; 12 | 13 | 14 | int 15 | main() 16 | { 17 | using G = digraph; 18 | G g; 19 | vertex_t v[] { 20 | g.add_vertex('a'), // 0 21 | g.add_vertex('b'), // 1 22 | g.add_vertex('c'), // 2 23 | g.add_vertex('d'), // 3 24 | g.add_vertex('e'), // 4 25 | g.add_vertex('f') // 5 26 | }; 27 | edge_t e[] { 28 | g.add_edge(v[0], v[1], 0), // a -> b 29 | g.add_edge(v[0], v[3], 1), // a -> d 30 | g.add_edge(v[1], v[2], 2), // b -> c 31 | g.add_edge(v[1], v[3], 3), // b -> d 32 | g.add_edge(v[2], v[0], 4), // c -> a 33 | g.add_edge(v[3], v[2], 5), // d -> c 34 | g.add_edge(v[4], v[5], 6), // e -> f 35 | }; 36 | 37 | assert(g.num_vertices() == 6); 38 | assert(g.num_edges() == 7); 39 | 40 | assert(g.out_degree(0) == 2); 41 | assert(g.in_degree(0) == 1); 42 | 43 | assert(g.out_degree(1) == 2); 44 | assert(g.in_degree(1) == 1); 45 | 46 | assert(g.out_degree(2) == 1); 47 | assert(g.in_degree(2) == 2); 48 | 49 | assert(g.out_degree(3) == 1); 50 | assert(g.in_degree(3) == 2); 51 | 52 | assert(g.out_degree(4) == 1); 53 | assert(g.in_degree(4) == 0); 54 | 55 | assert(g.out_degree(5) == 0); 56 | assert(g.in_degree(5) == 1); 57 | 58 | // TODO: Verify out- and in-edge lists for the graph. 59 | 60 | assert(g.has_edge(0, 1)); 61 | assert(g.source(0) == 0); 62 | assert(g.target(0) == 1); 63 | 64 | assert(g.has_edge(0, 3)); 65 | assert(g.source(1) == 0); 66 | assert(g.target(1) == 3); 67 | 68 | assert(g.has_edge(1, 2)); 69 | assert(g.source(2) == 1); 70 | assert(g.target(2) == 2); 71 | 72 | assert(g.has_edge(1, 3)); 73 | assert(g.source(3) == 1); 74 | assert(g.target(3) == 3); 75 | 76 | assert(g.has_edge(2, 0)); 77 | assert(g.source(4) == 2); 78 | assert(g.target(4) == 0); 79 | 80 | assert(g.has_edge(3, 2)); 81 | assert(g.source(5) == 3); 82 | assert(g.target(5) == 2); 83 | 84 | assert(g.has_edge(4, 5)); 85 | assert(g.source(6) == 4); 86 | assert(g.target(6) == 5); 87 | 88 | print_digraph print(std::cout, g); 89 | print(); 90 | } 91 | -------------------------------------------------------------------------------- /graph/graph.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Andrew Sutton 2 | // All rights reserved 3 | 4 | #include "graph.hpp" 5 | -------------------------------------------------------------------------------- /graph/graph.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Andrew Sutton 2 | // All rights reserved 3 | 4 | #ifndef GRAPH_UNDIRECTED_LIST_HPP 5 | #define GRAPH_UNDIRECTED_LIST_HPP 6 | 7 | #include "utility.hpp" 8 | #include "common.hpp" 9 | 10 | #include 11 | 12 | 13 | namespace origin { 14 | 15 | // A labeled vertex with source and target edges. This is specialized for the 16 | // empty case, which associates no label. 17 | template 18 | struct undirected_vertex 19 | { 20 | undirected_vertex() = default; 21 | 22 | undirected_vertex(T const& t) 23 | : edges_(), data(t) 24 | { } 25 | 26 | edge_list const& edges() const { return edges_; } 27 | 28 | std::size_t degree() const { return edges_.size(); } 29 | 30 | edge_list edges_; 31 | T data; 32 | }; 33 | 34 | 35 | // Edges 36 | 37 | // An labeled edge with source and target vertexes. This is specialized for the 38 | // empty case, which associates no label. 39 | template 40 | struct undirected_edge 41 | { 42 | // TODO: Value-initialize the data element or not? We currently do not. 43 | undirected_edge(vertex_t u, vertex_t v) 44 | : ends_{u, v} 45 | { } 46 | 47 | undirected_edge(vertex_t u, vertex_t v, T const& t) 48 | : ends_{u, v}, data(t) 49 | { } 50 | 51 | vertex_t first() const { return ends_[0]; } 52 | vertex_t second() const { return ends_[1]; } 53 | 54 | vertex_t ends_[2]; 55 | T data; 56 | }; 57 | 58 | 59 | // Graph 60 | 61 | // A directed graph that is parameterized by the edge labels for vertexes (V) 62 | // and edges (U). Both arguments default to empty, indicating that no labels 63 | // are associated with U or V. 64 | // 65 | // TODO: Support vertex and edge removal by keeping a free-list of unused 66 | // indexes and clever used of in-place allocation/deletion. Note that 67 | // supporting removal makes vertex traversal more complex (forward only). 68 | // 69 | // TODO: Implement const iterators and ranges. 70 | template 71 | struct graph 72 | { 73 | using vertex_type = undirected_vertex; 74 | using vertex_set = std::vector; 75 | using vertex_iterator = counted_iterator; 76 | using vertex_range = counted_range; 77 | 78 | using edge_type = undirected_edge; 79 | using edge_set = std::vector; 80 | using edge_iterator = counted_iterator; 81 | using edge_range = counted_range; 82 | 83 | // Vertex list 84 | bool is_null() const; 85 | std::size_t num_vertices() const; 86 | 87 | vertex_range vertices() const; 88 | vertex_iterator begin_vertices() const; 89 | vertex_iterator end_vertices() const; 90 | 91 | // Edge list 92 | bool is_empty() const; 93 | std::size_t num_edges() const; 94 | 95 | edge_range edges() const; 96 | edge_iterator begin_edges() const; 97 | edge_iterator end_edges() const; 98 | 99 | // Incidence 100 | edge_list edges(vertex_t v) const; 101 | std::size_t degree(vertex_t v) const; 102 | 103 | edge_iterator find_edge(vertex_t, vertex_t) const; 104 | bool has_edge(vertex_t, vertex_t) const; 105 | edge_t edge(vertex_t, vertex_t) const; 106 | 107 | vertex_t first(edge_t e) const; 108 | vertex_t second(edge_t e) const; 109 | vertex_t opposite(edge_t e, vertex_t v) const; 110 | 111 | // Incremental construction 112 | vertex_t add_vertex(); 113 | vertex_t add_vertex(V const&); 114 | 115 | edge_t add_edge(vertex_t, vertex_t); 116 | edge_t add_edge(vertex_t, vertex_t, E const&); 117 | 118 | vertex_set verts_; 119 | edge_set edges_; 120 | }; 121 | 122 | // Vertex list 123 | 124 | // Returns true if this is the null graph (having no vertices). 125 | template 126 | bool 127 | graph::is_null() const 128 | { 129 | return num_vertices() == 0; 130 | } 131 | 132 | // Returns the number of vertices in the graph. 133 | template 134 | std::size_t 135 | graph::num_vertices() const 136 | { 137 | return verts_.size(); 138 | } 139 | 140 | // Returns the list of vertices in the graph. 141 | template 142 | auto 143 | graph::vertices() const -> vertex_range 144 | { 145 | return vertex_range(num_vertices()); 146 | } 147 | 148 | // Returns an iterator for the first vertex in the graph. 149 | template 150 | auto 151 | graph::begin_vertices() const -> vertex_iterator 152 | { 153 | return vertex_iterator(0); 154 | } 155 | 156 | // Returns an iterator past the last vertex in the graph. 157 | template 158 | auto 159 | graph::end_vertices() const -> vertex_iterator 160 | { 161 | return vertex_iterator(num_vertices()); 162 | } 163 | 164 | // Edge list 165 | 166 | // Returns true if the graph has empty (no edges). 167 | template 168 | bool 169 | graph::is_empty() const 170 | { 171 | return num_edges() == 0; 172 | } 173 | 174 | // Returns the number of edges in the graph. 175 | template 176 | std::size_t 177 | graph::num_edges() const { return edges_.size(); } 178 | 179 | // Returns the list of edges in the graph. 180 | template 181 | auto 182 | graph::edges() const -> edge_range 183 | { 184 | return edge_range(num_edges()); 185 | } 186 | 187 | template 188 | auto 189 | graph::begin_edges() const -> edge_iterator 190 | { 191 | return edge_iterator(0); 192 | } 193 | 194 | template 195 | auto 196 | graph::end_edges() const -> edge_iterator 197 | { 198 | return edge_iterator(num_edges()); 199 | } 200 | 201 | // Incidence 202 | 203 | // Returns the list of edges incident to v. 204 | template 205 | edge_list 206 | graph::edges(vertex_t v) const 207 | { 208 | return verts_[v].edges(); 209 | } 210 | 211 | // Returns the degree of v. 212 | template 213 | std::size_t 214 | graph::degree(vertex_t v) const 215 | { 216 | return verts_[v].degree(); 217 | } 218 | 219 | // Returns an iterator referring to the edge {u, v} if such an edge 220 | // exists. Returns end_edges() otherwise. 221 | template 222 | auto 223 | graph::find_edge(vertex_t u, vertex_t v) const -> edge_iterator 224 | { 225 | if (degree(u) < degree(v)) 226 | std::swap(u, v); 227 | edge_list const& edges = verts_[u].edges_; 228 | for (edge_t e : edges) { 229 | if (opposite(e, u) == v) 230 | return begin_edges() + e; 231 | } 232 | return end_edges(); 233 | } 234 | 235 | // Returns true if the edge {u, v} is in the graph. 236 | template 237 | bool 238 | graph::has_edge(vertex_t u, vertex_t v) const 239 | { 240 | return find_edge(u, v) != end_edges(); 241 | } 242 | 243 | // Returns the edge {u, v}, assuming that it is in the graph. 244 | template 245 | edge_t 246 | graph::edge(vertex_t u, vertex_t v) const 247 | { 248 | assert(has_edge(u, v)); 249 | return *find_edge(u, v); 250 | } 251 | 252 | // In the edge {u, v}, returns u. 253 | // 254 | // TODO: I don't like this function. An undirected edge doesn't really 255 | // have positional ends. It would be better if this function didn't 256 | // actually exist (or maybe the vertices were canonically ordered?). 257 | template 258 | vertex_t 259 | graph::first(edge_t e) const 260 | { 261 | return edges_[e].first(); 262 | } 263 | 264 | // In the edge {u, v}, returns v. 265 | // 266 | // TODO: See comments above. 267 | template 268 | vertex_t 269 | graph::second(edge_t e) const 270 | { 271 | return edges_[e].second(); 272 | } 273 | 274 | // Assuming v is an end of e, returns the opposite end. 275 | template 276 | vertex_t 277 | graph::opposite(edge_t e, vertex_t v) const 278 | { 279 | assert(v == first(e) || v == second(e)); 280 | if (v == first(e)) 281 | return second(e); 282 | else // v == second(e) 283 | return first(e); 284 | } 285 | 286 | 287 | // Incremental construction 288 | 289 | template 290 | vertex_t 291 | graph::add_vertex() 292 | { 293 | verts_.emplace_back(); 294 | return verts_.size() - 1; 295 | } 296 | 297 | template 298 | vertex_t 299 | graph::add_vertex(V const& v) 300 | { 301 | verts_.emplace_back(v); 302 | return verts_.size() - 1; 303 | } 304 | 305 | template 306 | edge_t 307 | graph::add_edge(vertex_t u, vertex_t v) 308 | { 309 | assert(!has_edge(u, v)); 310 | edges_.emplace_back(u, v); 311 | edge_t e = edges_.size() - 1; 312 | verts_[u].edges_.push_back(e); 313 | verts_[v].edges_.push_back(e); 314 | return e; 315 | } 316 | 317 | template 318 | edge_t 319 | graph::add_edge(vertex_t u, vertex_t v, E const& x) 320 | { 321 | assert(!has_edge(u, v)); 322 | edges_.emplace_back(u, v, x); 323 | edge_t e = edges_.size() - 1; 324 | verts_[u].edges_.push_back(e); 325 | verts_[v].edges_.push_back(e); 326 | return e; 327 | } 328 | 329 | } // namespace origin 330 | 331 | #endif 332 | -------------------------------------------------------------------------------- /graph/graph.test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Andrew Sutton 2 | # All rights reserved 3 | 4 | add_unit_test(test-graph-general general.cpp) 5 | -------------------------------------------------------------------------------- /graph/graph.test/general.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Andrew Sutton 2 | // All rights reserved 3 | 4 | #include "../graph.hpp" 5 | #include "../output.hpp" 6 | 7 | #include 8 | #include 9 | 10 | 11 | using namespace origin; 12 | 13 | 14 | int 15 | main() 16 | { 17 | using G = graph; 18 | G g; 19 | vertex_t v[] { 20 | g.add_vertex('a'), // 0 21 | g.add_vertex('b'), // 1 22 | g.add_vertex('c'), // 2 23 | g.add_vertex('d'), // 3 24 | g.add_vertex('e'), // 4 25 | g.add_vertex('f') // 5 26 | }; 27 | edge_t e[] { 28 | g.add_edge(v[0], v[1], 0), // a -- b 29 | g.add_edge(v[0], v[3], 1), // a -- d 30 | g.add_edge(v[1], v[2], 2), // b -- c 31 | g.add_edge(v[1], v[3], 3), // b -- d 32 | g.add_edge(v[2], v[0], 4), // c -- a 33 | g.add_edge(v[3], v[2], 5), // d -- c 34 | g.add_edge(v[4], v[5], 6), // e -- f 35 | }; 36 | 37 | assert(g.num_vertices() == 6); 38 | assert(g.num_edges() == 7); 39 | 40 | assert(g.degree(0) == 3); 41 | assert(g.degree(1) == 3); 42 | assert(g.degree(2) == 3); 43 | assert(g.degree(3) == 3); 44 | assert(g.degree(4) == 1); 45 | assert(g.degree(5) == 1); 46 | 47 | // TODO: Verify out- and in-edge lists for the graph. 48 | 49 | assert(g.has_edge(0, 1)); 50 | assert(g.has_edge(1, 0)); 51 | assert(g.first(0) == 0); 52 | assert(g.second(0) == 1); 53 | assert(g.opposite(0, 0) == 1); 54 | assert(g.opposite(0, 1) == 0); 55 | 56 | assert(g.has_edge(0, 3)); 57 | assert(g.has_edge(3, 0)); 58 | assert(g.first(1) == 0); 59 | assert(g.second(1) == 3); 60 | assert(g.opposite(1, 0) == 3); 61 | assert(g.opposite(1, 3) == 0); 62 | 63 | assert(g.has_edge(1, 2)); 64 | assert(g.has_edge(2, 1)); 65 | assert(g.first(2) == 1); 66 | assert(g.second(2) == 2); 67 | assert(g.opposite(2, 1) == 2); 68 | assert(g.opposite(2, 2) == 1); 69 | 70 | assert(g.has_edge(1, 3)); 71 | assert(g.has_edge(3, 1)); 72 | assert(g.first(3) == 1); 73 | assert(g.second(3) == 3); 74 | assert(g.opposite(3, 1) == 3); 75 | assert(g.opposite(3, 3) == 1); 76 | 77 | assert(g.has_edge(2, 0)); 78 | assert(g.has_edge(0, 2)); 79 | assert(g.first(4) == 2); 80 | assert(g.second(4) == 0); 81 | assert(g.opposite(4, 2) == 0); 82 | assert(g.opposite(4, 0) == 2); 83 | 84 | assert(g.has_edge(3, 2)); 85 | assert(g.has_edge(2, 3)); 86 | assert(g.first(5) == 3); 87 | assert(g.second(5) == 2); 88 | assert(g.opposite(5, 3) == 2); 89 | assert(g.opposite(5, 2) == 3); 90 | 91 | assert(g.has_edge(4, 5)); 92 | assert(g.has_edge(5, 4)); 93 | assert(g.first(6) == 4); 94 | assert(g.second(6) == 5); 95 | assert(g.opposite(6, 4) == 5); 96 | assert(g.opposite(6, 5) == 4); 97 | 98 | // Make sure non-existent edges don't exist. 99 | assert(!g.has_edge(0, 5)); 100 | 101 | print_graph print(std::cout, g); 102 | print(); 103 | } 104 | -------------------------------------------------------------------------------- /graph/output.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Andrew Sutton 2 | // All rights reserved 3 | 4 | #include "output.hpp" 5 | -------------------------------------------------------------------------------- /graph/output.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Andrew Sutton 2 | // All rights reserved 3 | 4 | #ifndef GRAPH_OUTPUT_HPP 5 | #define GRAPH_OUTPUT_HPP 6 | 7 | #include "common.hpp" 8 | 9 | #include 10 | 11 | 12 | namespace origin 13 | { 14 | 15 | template 16 | struct print_digraph 17 | { 18 | print_digraph(std::ostream& os, G const& g) 19 | : os(os), graph(g) 20 | { } 21 | 22 | void operator()() { 23 | os << "digraph {\n"; 24 | 25 | // TODO: Factor vertex printing into a template parameter. 26 | for (vertex_t v : graph.vertices()) 27 | print_vertex(v); 28 | 29 | // TODO: Factor edge printing into a template parameter. 30 | for (edge_t e : graph.edges()) 31 | print_edge(e); 32 | 33 | os << "}\n"; 34 | } 35 | 36 | void print_vertex(vertex_t v) { 37 | os << v << '\n'; 38 | } 39 | 40 | void print_edge(edge_t e) { 41 | os << graph.source(e) << " -> " << graph.target(e) << '\n'; 42 | } 43 | 44 | std::ostream& os; 45 | G const& graph; 46 | }; 47 | 48 | 49 | template 50 | struct print_graph 51 | { 52 | print_graph(std::ostream& os, G const& g) 53 | : os(os), graph(g) 54 | { } 55 | 56 | void operator()() { 57 | os << "graph {\n"; 58 | 59 | // TODO: Factor vertex printing into a template parameter. 60 | for (vertex_t v : graph.vertices()) 61 | print_vertex(v); 62 | 63 | // TODO: Factor edge printing into a template parameter. 64 | for (edge_t e : graph.edges()) 65 | print_edge(e); 66 | 67 | os << "}\n"; 68 | } 69 | 70 | void print_vertex(vertex_t v) { 71 | os << v << '\n'; 72 | } 73 | 74 | void print_edge(edge_t e) { 75 | os << graph.first(e) << " -- " << graph.second(e) << '\n'; 76 | } 77 | 78 | std::ostream& os; 79 | G const& graph; 80 | }; 81 | 82 | 83 | } // namespace origin 84 | 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /graph/queue.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Andrew Sutton 2 | // All rights reserved 3 | 4 | #include "queue.hpp" 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /graph/queue.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Andrew Sutton 2 | // All rights reserved 3 | 4 | #ifndef GRAPH_QUEUE_HPP 5 | #define GRAPH_QUEUE_HPP 6 | 7 | #include "common.hpp" 8 | 9 | #include 10 | #include 11 | 12 | 13 | namespace origin 14 | { 15 | 16 | // A function object used to compare the label values of vertices. This 17 | // is a relation on the value of the label. 18 | template 19 | struct compare_vertex_label 20 | { 21 | compare_vertex_label(L label) 22 | : label(label), comp() 23 | { } 24 | 25 | compare_vertex_label(L label, C comp) 26 | : label(label), comp(comp) 27 | { } 28 | 29 | bool operator()(vertex_t u, vertex_t v) const 30 | { 31 | return comp(label(u), label(v)); 32 | } 33 | 34 | L label; // Value associated with vertices. 35 | C comp; // Comparison function for vertices. 36 | }; 37 | 38 | 39 | // A priority queue whose values are sorted on insertion. The order of 40 | // elements in the key is determined by a a comparison parameter. 41 | // 42 | // Note that insertion is linear in the size of the queue. 43 | template> 44 | struct insertion_queue : std::queue 45 | { 46 | using container_type = typename std::queue::container_type; 47 | 48 | insertion_queue(); 49 | insertion_queue(C comp); 50 | 51 | container_type const& data() const { return this->c; } 52 | 53 | void push(T const&); 54 | void push(T&&); 55 | 56 | C comp; 57 | }; 58 | 59 | template 60 | insertion_queue::insertion_queue() 61 | : std::queue(), comp() 62 | { } 63 | 64 | template 65 | insertion_queue::insertion_queue(C comp) 66 | : std::queue(), comp(comp) 67 | { } 68 | 69 | template 70 | void 71 | insertion_queue::push(T const& key) 72 | { 73 | // FIXME: Use a standard algorithm? 74 | auto iter = this->c.begin(); 75 | auto limit = this->c.end(); 76 | while (iter != limit && comp(key, *iter)) 77 | ++iter; 78 | this->c.insert(iter, key); 79 | } 80 | 81 | template 82 | void 83 | insertion_queue::push(T&& key) 84 | { 85 | // FIXME: Use a standard algorithm? 86 | auto iter = this->c.begin(); 87 | auto limit = this->c.end(); 88 | while (iter != limit && comp(key, *iter)) 89 | ++iter; 90 | this->c.insert(iter, std::move(key)); 91 | } 92 | 93 | 94 | #if 0 95 | // TODO: Currently we assume that T is an integer type whose values 96 | // are dense (0..n). In full generality, that won't hold water. We 97 | // should really parameterize the queue by the index to better lookup. 98 | template> 99 | struct mutable_binary_heap 100 | { 101 | using std::vector index_map; 102 | using std::vector key_list; 103 | 104 | bool is_empty() const; 105 | int size() const; 106 | 107 | T const& top(); 108 | void push(T const&); 109 | void pop(); 110 | 111 | template 112 | void update(T const&, U const&); 113 | 114 | index_map index; 115 | key_list order; 116 | L pri; 117 | C comp; 118 | }; 119 | 120 | 121 | // Returns true if the binary heap is emmpty. 122 | template 123 | bool 124 | mutable_binary_heap::is_empty() const 125 | { 126 | return order.empty(); 127 | } 128 | 129 | // Returns the number of elements in the heap. 130 | template 131 | int 132 | mutable_binary_heap::size() const 133 | { 134 | return order.size(); 135 | } 136 | 137 | // Returns the element at the top of the heap. 138 | template 139 | T const& 140 | mutable_binary_heap::top() const 141 | { 142 | 143 | } 144 | 145 | // Insert a new element into the heap. 146 | template 147 | void 148 | mutable_binary_heap::push(T const& k) 149 | { 150 | 151 | } 152 | 153 | // Remove the top element from the heap. 154 | template 155 | void 156 | mutable_binary_heap::pop() 157 | { 158 | 159 | } 160 | 161 | // Update the position of k within the heap as a result of changing its 162 | // priority to the given value. 163 | // 164 | // NOTE: This function is only defined if the key is mutable. 165 | template 166 | template 167 | void 168 | mutable_binary_heap::update(T const& key, U const& value) 169 | { 170 | 171 | } 172 | #endif 173 | 174 | 175 | } // namespace origin 176 | 177 | 178 | #endif 179 | -------------------------------------------------------------------------------- /graph/queue.test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 Andrew Sutton 2 | # All rights reserved 3 | 4 | add_unit_test(test-queue-insertion insertion.cpp) 5 | -------------------------------------------------------------------------------- /graph/queue.test/insertion.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Andrew Sutton 2 | // All rights reserved 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | using namespace origin; 13 | 14 | 15 | int 16 | main() 17 | { 18 | // Randomize a list of weights. 19 | std::vector distance(10); 20 | std::iota(distance.begin(), distance.end(), 0); 21 | std::random_shuffle(distance.begin(), distance.end()); 22 | 23 | std::cout << "distances: "; 24 | for (int d : distance) 25 | std::cout << d << ' '; 26 | std::cout << '\n'; 27 | 28 | // Make a label for the vector. 29 | auto dist = vertex_label(distance); 30 | 31 | // FIXME: Can we do this without decltype? 32 | using C = compare_vertex_label>; 33 | using Q = insertion_queue; 34 | 35 | C comp(dist); 36 | Q queue(comp); 37 | 38 | for (int i = 0; i < 10; ++i) { 39 | queue.push(i); 40 | std::cout << "insert " << i << " (" << dist(i) << ")\n"; 41 | for (int n : queue.data()) 42 | std::cout << n << " (" << dist(n) << ") "; 43 | std::cout << '\n'; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /graph/utility.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Andrew Sutton 2 | // All rights reserved 3 | 4 | #include "utility.hpp" 5 | -------------------------------------------------------------------------------- /graph/utility.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Andrew Sutton 2 | // All rights reserved 3 | 4 | #ifndef GRAPH_UTILITY_HPP 5 | #define GRAPH_UTILITY_HPP 6 | 7 | #include 8 | #include 9 | 10 | 11 | namespace origin { 12 | 13 | // An iterator whose values are increasing integer values. 14 | template 15 | struct counted_iterator 16 | { 17 | using value_type = T; 18 | using reference = T; 19 | using pointer = void; 20 | using difference_type = std::ptrdiff_t; 21 | using iterator_category = std::random_access_iterator_tag; 22 | 23 | counted_iterator(T n) 24 | : num_(n) 25 | { } 26 | 27 | T operator*() const { return num_; } 28 | T operator[](std::ptrdiff_t n) const { return num_ + n; } 29 | 30 | void operator->() const = delete; 31 | 32 | counted_iterator& operator++() { ++num_; return *this; } 33 | counted_iterator& operator++(int) { auto x = *this; ++num_; return x; } 34 | 35 | counted_iterator& operator--() { --num_; return *this; } 36 | counted_iterator& operator--(int) { auto x = *this; --num_; return x; } 37 | 38 | counted_iterator& operator+=(std::ptrdiff_t n) { num_ += n; return *this; } 39 | counted_iterator& operator-=(std::ptrdiff_t n) { num_ += n; return *this; } 40 | 41 | bool operator==(counted_iterator i) { return num_ == i.num_; } 42 | bool operator!=(counted_iterator i) { return num_ != i.num_; } 43 | 44 | T num_; 45 | }; 46 | 47 | template 48 | inline counted_iterator 49 | operator+(counted_iterator i, std::ptrdiff_t n) 50 | { 51 | return i += n; 52 | } 53 | 54 | template 55 | inline counted_iterator 56 | operator+(std::ptrdiff_t n, counted_iterator i) 57 | { 58 | return i += n; 59 | } 60 | 61 | template 62 | inline counted_iterator 63 | operator-(counted_iterator i, std::ptrdiff_t n) 64 | { 65 | return i -= n; 66 | } 67 | 68 | template 69 | inline std::ptrdiff_t 70 | operator-(counted_iterator i, counted_iterator j) 71 | { 72 | return i.num_ - j.num_; 73 | } 74 | 75 | 76 | // A range of counted iterators. 77 | template 78 | struct counted_range 79 | { 80 | counted_range(T b) 81 | : first(0), limit(b) 82 | { } 83 | 84 | counted_range(T a, T b) 85 | : first(a), limit(b) 86 | { } 87 | 88 | counted_iterator begin() const { return first; } 89 | counted_iterator end() const { return limit; } 90 | 91 | std::size_t size() const { return limit.count - first.count; } 92 | 93 | counted_iterator first; 94 | counted_iterator limit; 95 | }; 96 | 97 | 98 | } // namespace origin 99 | 100 | #endif 101 | --------------------------------------------------------------------------------