├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── Vagrantfile ├── Vagrantfile.config.yml ├── note ├── publish.txt └── testing.txt ├── rockspecs ├── luagraphs-1.0-1.rockspec ├── luagraphs-1.0-2.rockspec ├── luagraphs-1.0-3.rockspec ├── luagraphs-1.0-4.rockspec └── luagraphs-1.0-5.rockspec ├── spec ├── BellmanFord_spec.lua ├── BreadthFirstSearch_spec.lua ├── ConnectedComponents_spec.lua ├── DepthFirstSearch_spec.lua ├── Dijkstra_spec.lua ├── EagerPrimMST_spec.lua ├── FordFulkerson_spec.lua ├── IndexedMinPQ_spec.lua ├── KruskalMST_spec.lua ├── MinPQ_spec.lua ├── PrimMST_spec.lua ├── StrongConnectedComponents_spec.lua ├── TopoSortShortestPath_spec.lua ├── TopologicalSort_spec.lua ├── UnionFind_spec.lua ├── graph_spec.lua ├── list_spec.lua ├── queue_spec.lua └── stack_spec.lua └── src └── luagraphs ├── connectivity ├── ConnectedComponents.lua └── StronglyConnectedComponents.lua ├── data ├── IndexedMinPQ.lua ├── MinPQ.lua ├── UnionFind.lua ├── graph.lua ├── list.lua ├── network.lua ├── queue.lua └── stack.lua ├── flow └── FordFulkerson.lua ├── mst ├── EagerPrimMST.lua ├── KruskalMST.lua └── PrimMST.lua ├── search ├── BreadthFirstSearch.lua └── DepthFirstSearch.lua ├── shortest_paths ├── BellmanFord.lua ├── Dijkstra.lua └── TopoSortShortestPath.lua └── sort └── TopologicalSort.lua /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | target/ 3 | *.iml 4 | .vagrant/ 5 | 6 | # Compiled Lua sources 7 | luac.out 8 | 9 | # luarocks build files 10 | *.src.rock 11 | *.zip 12 | *.tar.gz 13 | 14 | # Object files 15 | *.o 16 | *.os 17 | *.ko 18 | *.obj 19 | *.elf 20 | 21 | # Precompiled Headers 22 | *.gch 23 | *.pch 24 | 25 | # Libraries 26 | *.lib 27 | *.a 28 | *.la 29 | *.lo 30 | *.def 31 | *.exp 32 | 33 | # Shared objects (inc. Windows DLLs) 34 | *.dll 35 | *.so 36 | *.so.* 37 | *.dylib 38 | 39 | # Executables 40 | *.exe 41 | *.out 42 | *.app 43 | *.i*86 44 | *.x86_64 45 | *.hex 46 | 47 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | sudo: false 3 | 4 | env: 5 | - LUA="lua=5.1" 6 | - LUA="lua=5.2" 7 | - LUA="lua=5.3" 8 | - LUA="luajit=2.0" 9 | - LUA="luajit=2.1" 10 | 11 | before_install: 12 | - pip install hererocks 13 | - hererocks lua_install -r^ --$LUA 14 | - export PATH=$PATH:$PWD/lua_install/bin # Add directory with all installed binaries to PATH 15 | 16 | install: 17 | - luarocks install luacheck 18 | - luarocks install busted 19 | - luarocks install luacov 20 | - luarocks install luacov-coveralls 21 | - luarocks install lua-path 22 | 23 | script: 24 | - luacheck --no-unused-args --std max+busted spec 25 | - busted --verbose --coverage 26 | - echo $TRAVIS_BUILD_DIR 27 | 28 | after_success: 29 | - luacov-coveralls --exclude $TRAVIS_BUILD_DIR/lua_install 30 | 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Xianshun Chen 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 | # lua-graph 2 | 3 | Graph algorithms in lua 4 | 5 | # Features 6 | 7 | The graph algorithms covered: 8 | 9 | * Graph data structure (directed / undirected / weighted / unweighted) 10 | * Depth first search 11 | * Breadth first search 12 | * Connected components 13 | * Strongly connected components 14 | * Topological sort 15 | * Minimum spanning tree (Kruskal) 16 | * Minimum spanning tree (Prim) 17 | * Max flow min cut 18 | * Dijkstra shortest paths 19 | * Topogical sort shortest paths 20 | * Bellman Ford shortest paths 21 | 22 | # Notes 23 | 24 | For developers who have been using library 1.0.2, the main changes are: 25 | 26 | * graph.V is removed and replaced with graph:vertexCount() and graph:vertexAt(index) method for iterating all vertices: this change was introduced so that graph vertices do not need to start with vertex 0 and do not need to be consecutive integer (can be any label). 27 | * graph:addVertexIfNotExists: allows user to add vertices later after the graph is created 28 | * graph:removeVertex: allows user to delete a vertex and its edges 29 | * graph:addEdge: Now if the vertices on which the edge is to be added does not exists in the graph, they will be automatically added 30 | 31 | # Install 32 | 33 | ```bash 34 | luarocks install luagraphs 35 | ``` 36 | 37 | # Usage 38 | 39 | ### Create an undirected unweighted graph 40 | 41 | ```lua 42 | local g = require('luagraphs.data.graph').create(6) 43 | g:addEdge(0, 5) -- bidirectional edge connecting 0 and 5 44 | g:addEdge(2, 4) 45 | g:addEdge(2, 3) 46 | g:addEdge(1, 2) 47 | g:addEdge(0, 1) 48 | g:addEdge(3, 4) 49 | g:addEdge(3, 5) 50 | g:addEdge(0, 2) 51 | 52 | print(g:vertexCount()) -- return 6 53 | 54 | -- code below prints the adjacency list 55 | for k = 0, g:vertexCount() -1 do -- iterate through all the vertices in g 56 | local v = g:vertexAt(k) 57 | local adj_v = g:adj(v) -- adjacency list for vertex v 58 | local text = '' 59 | for i = 0, adj_v:size()-1 do 60 | text = text .. ', ' .. adj_v:get(i):other(v) 61 | end 62 | print(text) 63 | end 64 | ``` 65 | 66 | ### Create an undirected unweighted graph and add / remove vertices later 67 | 68 | ```lua 69 | local g = require('luagraphs.data.graph').create(6) 70 | g:addEdge(0, 5) -- bidirectional edge connecting 0 and 5 71 | g:addEdge(2, 4) 72 | g:addEdge(2, 3) 73 | g:addEdge(1, 2) 74 | g:addEdge(0, 1) 75 | g:addEdge(3, 4) 76 | g:addEdge(3, 5) 77 | g:addEdge(0, 2) 78 | 79 | -- expand the graph by another 3 vertices: -1, 9, and 10 80 | -- if you want to add a vertex without adding an edge, can just call g:addVertexIfNotExists(vertexId) instead 81 | g:addEdge(-1, 10) 82 | g:addEdge(9, 2) 83 | g:addEdge(-1, 0) 84 | 85 | print(g:containsVertex(9)) -- return true 86 | print(g:containsVertex(-1)) -- return true 87 | print(g:containsVertex(8)) -- return false 88 | 89 | print(g:vertexCount()) -- return 9 90 | 91 | -- to remove a vertex, can just call g:removeVertex(vertexId) 92 | 93 | -- code below prints the adjacency list 94 | for k = 0, g:vertexCount() -1 do -- iterate through all the vertices in g 95 | local v = g:vertexAt(k) 96 | local adj_v = g:adj(v) -- adjacency list for vertex v 97 | local text = '' 98 | for i = 0, adj_v:size()-1 do 99 | text = text .. ', ' .. adj_v:get(i):other(v) 100 | end 101 | print(text) 102 | end 103 | ``` 104 | 105 | ### Create an undirected unweighted graph from a list of vertices and expand or shrink it 106 | 107 | ```lua 108 | local vertices = require('luagraphs.data.list').create() 109 | vertices:add(3) 110 | vertices:add(5) 111 | vertices:add(10) 112 | 113 | local g = require('luagraphs.data.graph').createFromVertexList(vertices) 114 | 115 | print(g:vertexCount()) -- return 3 116 | 117 | g:addVertexIfNotExists(4) 118 | g:addVertexIfNotExists(5) 119 | 120 | print(g:vertexCount()) -- return 4 121 | 122 | g:addEdge(0, 5) -- add a new vertex 0 and a bidirectional edge connecting 0 and 5 123 | 124 | print(g:vertexCount()) -- return 5 125 | 126 | g:removeVertex(10) 127 | 128 | print(g:vertexCount()) -- return 4 129 | 130 | 131 | -- code below prints the adjacency list 132 | for k = 0, g:vertexCount() -1 do -- iterate through all the vertices in g 133 | local v = g:vertexAt(k) 134 | local adj_v = g:adj(v) -- adjacency list for vertex v 135 | local text = '' 136 | for i = 0, adj_v:size()-1 do 137 | text = text .. ', ' .. adj_v:get(i):other(v) 138 | end 139 | print(text) 140 | end 141 | ``` 142 | 143 | ### Create an directed unweighted graph 144 | 145 | ```lua 146 | local g = require('luagraphs.data.graph').create(6, true) -- true means it is directed 147 | g:addEdge(0, 5) -- edge directed from 0 to 5 148 | g:addEdge(2, 4) 149 | g:addEdge(2, 3) 150 | g:addEdge(1, 2) 151 | g:addEdge(0, 1) 152 | g:addEdge(3, 4) 153 | g:addEdge(3, 5) 154 | g:addEdge(0, 2) 155 | 156 | print(g:vertexCount()) -- return 6 157 | 158 | -- code below prints the adjacency list 159 | for k = 0, g:vertexCount() -1 do -- iterate through all vertices in g 160 | local v = g:vertexAt(k) 161 | local adj_v = g:adj(v) -- adjacency list for vertex v 162 | local text = '' 163 | for i = 0, adj_v:size()-1 do 164 | local e = adj_v:get(i) 165 | text = text .. ', ' .. e:other(v) 166 | end 167 | print(text) 168 | end 169 | ``` 170 | 171 | ### Create an undirected weighted graph 172 | 173 | ```lua 174 | local g = require('luagraphs.data.graph').create(6) 175 | g:addEdge(0, 5, 1.2) -- bidirectional edge with weight equal to 1.2 and connecting between 0 and 5 176 | g:addEdge(2, 4, 2.2) 177 | g:addEdge(2, 3, 1.2) 178 | g:addEdge(1, 2, 1.2) 179 | g:addEdge(0, 1, 2.2) 180 | g:addEdge(3, 4, 1.2) 181 | g:addEdge(3, 5, 2.2) 182 | g:addEdge(0, 2, 2.2) 183 | 184 | print(g:vertexCount()) -- return 6 185 | 186 | -- code below prints the adjacency list 187 | for k = 0, g:vertexCount() -1 do -- iterate through all vertices in g 188 | local v = g:vertexAt(k) 189 | local adj_v = g:adj(v) -- adjacency list for vertex v 190 | local text = '' 191 | for i = 0, adj_v:size()-1 do 192 | local e = adj_v:get(i) 193 | text = text .. ', ' .. e:other(v) .. '(' .. e.weight .. ')' 194 | end 195 | print(text) 196 | end 197 | ``` 198 | 199 | ### Create an directed weighted graph 200 | 201 | ```lua 202 | local g = require('luagraphs.data.graph').create(6, true) -- true means directed 203 | g:addEdge(0, 5, 1.2) -- bidirectional edge with weight equal to 1.2 and connecting between 0 and 5 204 | g:addEdge(2, 4, 2.2) 205 | g:addEdge(2, 3, 1.2) 206 | g:addEdge(1, 2, 1.2) 207 | g:addEdge(0, 1, 2.2) 208 | g:addEdge(3, 4, 1.2) 209 | g:addEdge(3, 5, 2.2) 210 | g:addEdge(0, 2, 2.2) 211 | 212 | print(g:vertexCount()) -- return 6 213 | 214 | -- code below prints the adjacency list 215 | for k = 0, g:vertexCount() -1 do -- iterate through all vertices in g 216 | local v = g:vertexAt(k) 217 | local adj_v = g:adj(v) -- adjacency list for vertex v 218 | local text = '' 219 | for i = 0, adj_v:size()-1 do 220 | local e = adj_v:get(i) 221 | text = text .. ', ' .. e:other(v) .. '(' .. e.weight .. ')' 222 | end 223 | print(text) 224 | end 225 | ``` 226 | 227 | ### Depth First Search 228 | 229 | ```lua 230 | local g = require('luagraphs.data.graph').create(6) 231 | g:addEdge(0, 5) 232 | g:addEdge(2, 4) 233 | g:addEdge(2, 3) 234 | g:addEdge(1, 2) 235 | g:addEdge(0, 1) 236 | g:addEdge(3, 4) 237 | g:addEdge(3, 5) 238 | g:addEdge(0, 2) 239 | local dfs = require('luagraphs.search.DepthFirstSearch').create() 240 | local s = 0 241 | dfs:run(g, s) 242 | 243 | for k = 0, g:vertexCount()-1 do 244 | local v = g:vertexAt(k) 245 | if v ~= s and dfs:hasPathTo(v) then 246 | print('has path to ' .. v) 247 | local path = dfs:getPathTo(v) 248 | local pathText = '' 249 | while path:isEmpty() == false do 250 | local x = path:pop() 251 | if pathText == '' then 252 | pathText = pathText .. x 253 | else 254 | pathText = pathText .. ' -> ' .. x 255 | end 256 | end 257 | print(pathText) 258 | 259 | end 260 | end 261 | ``` 262 | 263 | ### Breadth First Search 264 | 265 | ```lua 266 | local g = require('luagraphs.data.graph').create(6) 267 | g:addEdge(0, 5) 268 | g:addEdge(2, 4) 269 | g:addEdge(2, 3) 270 | g:addEdge(1, 2) 271 | g:addEdge(0, 1) 272 | g:addEdge(3, 4) 273 | g:addEdge(3, 5) 274 | g:addEdge(0, 2) 275 | local bfs = require('luagraphs.search.BreadthFirstSearch').create() 276 | local s = 0 277 | bfs:run(g, s) 278 | 279 | for k = 0, g:vertexCount()-1 do 280 | local v = g:vertexAt(k) 281 | if v ~= s and bfs:hasPathTo(v) then 282 | local path = bfs:getPathTo(v) 283 | local pathText = '' 284 | while path:isEmpty() == false do 285 | local x = path:pop() 286 | if pathText == '' then 287 | pathText = pathText .. x 288 | else 289 | pathText = pathText .. ' -> ' .. x 290 | end 291 | end 292 | print(pathText) 293 | 294 | end 295 | end 296 | ``` 297 | 298 | ### Connected Components 299 | 300 | ```lua 301 | local g = require('luagraphs.data.graph').create(13) -- undirected graph 302 | g:addEdge(0, 5) 303 | g:addEdge(4, 3) 304 | g:addEdge(0, 1) 305 | g:addEdge(9, 12) 306 | g:addEdge(6, 4) 307 | g:addEdge(5, 4) 308 | g:addEdge(0, 2) 309 | g:addEdge(11, 12) 310 | g:addEdge(9,10) 311 | g:addEdge(0, 6) 312 | g:addEdge(7, 8) 313 | g:addEdge(9, 11) 314 | g:addEdge(5, 3) 315 | 316 | local cc = require('luagraphs.connectivity.ConnectedComponents').create() 317 | cc:run(g) 318 | 319 | print('count: ' .. cc.count) 320 | print(cc.count) -- return 3 connected components 321 | for k = 0,g:vertexCount()-1 do 322 | local v = g:vertexAt(k) 323 | print('id[' .. v .. ']: ' .. cc:component(v)) 324 | end 325 | ``` 326 | 327 | ### Strongly Connected Components 328 | 329 | ```lua 330 | local graph = require('luagraphs.data.graph').create(13, true) -- directed graph 331 | graph:addEdge(4, 2) 332 | graph:addEdge(2, 3) 333 | graph:addEdge(3, 2) 334 | graph:addEdge(6, 0) 335 | graph:addEdge(0, 1) 336 | graph:addEdge(2, 0) 337 | graph:addEdge(11, 12) 338 | graph:addEdge(12, 9) 339 | graph:addEdge(9, 10) 340 | graph:addEdge(9, 11) 341 | graph:addEdge(8, 9) 342 | graph:addEdge(10, 12) 343 | graph:addEdge(11, 4) 344 | graph:addEdge(4, 3) 345 | graph:addEdge(3, 5) 346 | graph:addEdge(7, 8) 347 | graph:addEdge(8, 7) 348 | graph:addEdge(5, 4) 349 | graph:addEdge(0, 5) 350 | graph:addEdge(6, 4) 351 | graph:addEdge(6, 9) 352 | graph:addEdge(7, 6) 353 | 354 | local scc = require('luagraphs.connectivity.StronglyConnectedComponents').create() 355 | scc:run(graph) 356 | print(scc.count) -- return 5 components 357 | 358 | for k = 0,graph:vertexCount()-1 do 359 | local v = graph:vertexAt(k) 360 | print('id[' .. v .. ']: ' .. scc:component(v)) 361 | end 362 | ``` 363 | 364 | ### Topological Sort 365 | 366 | ```lua 367 | local dag = require('luagraphs.data.graph').create(7, true) -- directed acyclic graph 368 | 369 | dag:addEdge(0, 5) 370 | dag:addEdge(0, 2) 371 | dag:addEdge(0, 1) 372 | dag:addEdge(3, 6) 373 | dag:addEdge(3, 5) 374 | dag:addEdge(3, 4) 375 | dag:addEdge(5, 4) 376 | dag:addEdge(6, 4) 377 | dag:addEdge(6, 0) 378 | dag:addEdge(3, 2) 379 | dag:addEdge(1, 4) 380 | 381 | local ts = require('luagraphs.sort.TopologicalSort').create() 382 | ts:run(dag) 383 | 384 | local path = ts:path() 385 | for i=0, path:size()-1 do 386 | print('sort #' .. i .. ': ' .. path:get(i)) 387 | end 388 | ``` 389 | 390 | ### Minimum Spanning Tree (Kruskal) 391 | 392 | ```lua 393 | local mst = require('luagraphs.mst.KruskalMST').create() 394 | local g = require('luagraphs.data.graph').create(8) -- undirected graph with weighted edges 395 | g:addEdge(0, 7, 0.16) -- 0.16 is the weight of the edge between 0 and 7 396 | g:addEdge(2, 3, 0.17) 397 | g:addEdge(1, 7, 0.19) 398 | g:addEdge(0, 2, 0.26) 399 | g:addEdge(5, 7, 0.28) 400 | g:addEdge(1, 3, 0.29) 401 | g:addEdge(1, 5, 0.32) 402 | g:addEdge(2, 7, 0.34) 403 | g:addEdge(4, 5, 0.35) 404 | g:addEdge(1, 2, 0.36) 405 | g:addEdge(4, 7, 0.37) 406 | g:addEdge(0, 4, 0.38) 407 | g:addEdge(6, 2, 0.4) 408 | g:addEdge(3, 6, 0.52) 409 | g:addEdge(6, 0, 0.58) 410 | g:addEdge(6, 4, 0.93) 411 | 412 | mst:run(g) 413 | 414 | local path = mst.path 415 | 416 | print(path:size()) -- return 7 417 | for i=0,path:size()-1 do 418 | local e = path:get(i) 419 | print(e:from() .. ' -> ' .. e:to() .. ' (' .. e.weight .. ')') 420 | end 421 | ``` 422 | 423 | ### Minimum Spanning Tree (Prim) 424 | 425 | ```lua 426 | local mst = require('luagraphs.mst.PrimMST').create() 427 | local g = require('luagraphs.data.graph').create(8) -- undirected graph with weighted edges 428 | g:addEdge(0, 7, 0.16) -- 0.16 is the weight of the edge between 0 and 7 429 | g:addEdge(2, 3, 0.17) 430 | g:addEdge(1, 7, 0.19) 431 | g:addEdge(0, 2, 0.26) 432 | g:addEdge(5, 7, 0.28) 433 | g:addEdge(1, 3, 0.29) 434 | g:addEdge(1, 5, 0.32) 435 | g:addEdge(2, 7, 0.34) 436 | g:addEdge(4, 5, 0.35) 437 | g:addEdge(1, 2, 0.36) 438 | g:addEdge(4, 7, 0.37) 439 | g:addEdge(0, 4, 0.38) 440 | g:addEdge(6, 2, 0.4) 441 | g:addEdge(3, 6, 0.52) 442 | g:addEdge(6, 0, 0.58) 443 | g:addEdge(6, 4, 0.93) 444 | 445 | mst:run(g) 446 | 447 | local path = mst.path 448 | 449 | print(path:size()) -- return 7 450 | for i=0,path:size()-1 do 451 | local e = path:get(i) 452 | print(e:from() .. ' -> ' .. e:to() .. ' (' .. e.weight .. ')') 453 | end 454 | ``` 455 | 456 | ### Minimum Spanning Tree (Eager Prim) 457 | 458 | ```lua 459 | local mst = require('luagraphs.mst.EagerPrimMST').create() 460 | local g = require('luagraphs.data.graph').create(8) -- undirected graph with weighted edges 461 | g:addEdge(0, 7, 0.16) -- 0.16 is the weight of the edge between 0 and 7 462 | g:addEdge(2, 3, 0.17) 463 | g:addEdge(1, 7, 0.19) 464 | g:addEdge(0, 2, 0.26) 465 | g:addEdge(5, 7, 0.28) 466 | g:addEdge(1, 3, 0.29) 467 | g:addEdge(1, 5, 0.32) 468 | g:addEdge(2, 7, 0.34) 469 | g:addEdge(4, 5, 0.35) 470 | g:addEdge(1, 2, 0.36) 471 | g:addEdge(4, 7, 0.37) 472 | g:addEdge(0, 4, 0.38) 473 | g:addEdge(6, 2, 0.4) 474 | g:addEdge(3, 6, 0.52) 475 | g:addEdge(6, 0, 0.58) 476 | g:addEdge(6, 4, 0.93) 477 | 478 | mst:run(g) 479 | 480 | local path = mst.path 481 | 482 | print(path:size()) -- return 7 483 | for i=0,path:size()-1 do 484 | local e = path:get(i) 485 | print(e:from() .. ' -> ' .. e:to() .. ' (' .. e.weight .. ')') 486 | end 487 | ``` 488 | 489 | ### Shortest Paths (Dijkstra) 490 | 491 | ```lua 492 | local g = require('luagraphs.data.graph').create(8, true); -- directed weighted graph 493 | 494 | g:addEdge(0, 1, 5.0) -- edge from 0 to 1 is 5.0 in distance 495 | g:addEdge(0, 4, 9.0) 496 | g:addEdge(0, 7, 8.0) 497 | g:addEdge(1, 2, 12.0) 498 | g:addEdge(1, 3, 15.0) 499 | g:addEdge(1, 7, 4.0) 500 | g:addEdge(2, 3, 3.0) 501 | g:addEdge(2, 6, 11.0) 502 | g:addEdge(3, 6, 9.0) 503 | g:addEdge(4, 5, 5.0) 504 | g:addEdge(4, 6, 20.0) 505 | g:addEdge(4, 7, 5.0) 506 | g:addEdge(5, 2, 1.0) 507 | g:addEdge(5, 6, 13.0) 508 | g:addEdge(7, 5, 6.0) 509 | g:addEdge(7, 2, 7.0) 510 | 511 | local source = 0 512 | local dijkstra = require('luagraphs.shortest_paths.Dijkstra').create() 513 | dijkstra:run(g, source) -- 0 is the id of the source node in the path search 514 | for k = 0,g:vertexCount()-1 do 515 | local v = g:vertexAt(k) 516 | if v ~= source and dijkstra:hasPathTo(v) then 517 | print('path from 0 to ' .. v .. ' ( cost: ' .. dijkstra:getPathLength(v) .. ' )') 518 | local path = dijkstra:getPathTo(v) 519 | for i = 0,path:size()-1 do 520 | print('# from ' .. path:get(i):from() .. ' to ' .. path:get(i):to() .. ' ( distance: ' .. path:get(i).weight .. ' )') 521 | end 522 | end 523 | end 524 | ``` 525 | 526 | ### Shortest Paths (Topological Sort) 527 | 528 | ```lua 529 | local g = require('luagraphs.data.graph').create(8, true); -- directed weighted graph 530 | 531 | g:addEdge(0, 1, 5.0) -- edge from 0 to 1 is 5.0 in distance 532 | g:addEdge(0, 4, 9.0) 533 | g:addEdge(0, 7, 8.0) 534 | g:addEdge(1, 2, 12.0) 535 | g:addEdge(1, 3, 15.0) 536 | g:addEdge(1, 7, 4.0) 537 | g:addEdge(2, 3, 3.0) 538 | g:addEdge(2, 6, 11.0) 539 | g:addEdge(3, 6, 9.0) 540 | g:addEdge(4, 5, 5.0) 541 | g:addEdge(4, 6, 20.0) 542 | g:addEdge(4, 7, 5.0) 543 | g:addEdge(5, 2, 1.0) 544 | g:addEdge(5, 6, 13.0) 545 | g:addEdge(7, 5, 6.0) 546 | g:addEdge(7, 2, 7.0) 547 | 548 | local source = 0 549 | local finder = require('luagraphs.shortest_paths.Dijkstra').create() 550 | finder:run(g, source) -- 0 is the source node in the path search 551 | for k = 0,g:vertexCount()-1 do 552 | local v= g:vertexAt(k) 553 | if v ~= source and finder:hasPathTo(v) then 554 | print('path from 0 to ' .. v .. ' ( cost: ' .. finder:getPathLength(v) .. ' )') 555 | local path = finder:getPathTo(v) 556 | for i = 0,path:size()-1 do 557 | print('# from ' .. path:get(i):from() .. ' to ' .. path:get(i):to() .. ' ( distance: ' .. path:get(i).weight .. ' )') 558 | end 559 | end 560 | end 561 | ``` 562 | 563 | ### MinCut-MaxFlow (Ford Fulkerson implementation) 564 | 565 | ```lua 566 | local g = require('luagraphs.data.network').FlowNetwork.create(8); 567 | 568 | g:addEdge(0, 1, 10); -- capacity from vertex 0 to vertex 1 is 10 569 | g:addEdge(0, 2, 5); 570 | g:addEdge(0, 3, 15); 571 | g:addEdge(1, 4, 9); 572 | g:addEdge(1, 5, 15); 573 | g:addEdge(1, 2, 4); 574 | g:addEdge(2, 5, 8); 575 | g:addEdge(2, 3, 4); 576 | g:addEdge(3, 6, 16); 577 | g:addEdge(4, 5, 15); 578 | g:addEdge(4, 7, 10); 579 | g:addEdge(5, 7, 10); 580 | g:addEdge(5, 6, 15); 581 | g:addEdge(6, 2, 6); 582 | g:addEdge(6, 7, 10); 583 | 584 | local method = require('luagraphs.flow.FordFulkerson').create() 585 | local maxFlow = method:run(g, 0, 7) 586 | print('FordFulkerson max flow: ' .. maxFlow) 587 | 588 | 589 | local minCuts = method:minCuts() 590 | 591 | for i = 0,minCuts:size()-1 do 592 | local e =minCuts:get(i) 593 | print('min cut: ' .. e:toString()) 594 | end 595 | ``` 596 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*# vi: set ft=ruby : 2 | require 'yaml' 3 | vagrantConfig = YAML.load_file 'Vagrantfile.config.yml' 4 | Vagrant.configure(2) do |config| 5 | config.vm.box = "bento/ubuntu-16.10" 6 | config.vm.network "private_network", ip: vagrantConfig['ip'] 7 | 8 | config.vm.synced_folder "src/", "/home/vagrant/src", owner:"vagrant", group: "vagrant" 9 | config.vm.synced_folder "spec/", "/home/vagrant/spec", owner:"vagrant", group: "vagrant" 10 | config.vm.synced_folder "rockspecs/", "/home/vagrant/rockspecs", owner:"vagrant", group: "vagrant" 11 | 12 | # VirtualBox specific settings 13 | config.vm.provider "virtualbox" do |vb| 14 | vb.gui = false 15 | vb.memory = "1024" 16 | vb.cpus = 1 17 | end 18 | 19 | # provisioning os 20 | config.vm.provision "shell", inline: "sudo apt-get install python-pip -y" 21 | config.vm.provision "shell", inline: "sudo apt-get install libncurses5-dev -y" 22 | config.vm.provision "shell", inline: "sudo apt-get install zip -y" 23 | config.vm.provision "shell", inline: "sudo apt-get install unzip -y" 24 | config.vm.provision "shell", inline: "sudo apt-get install wget -y" 25 | config.vm.provision "shell", inline: "sudo apt-get install git -y" 26 | config.vm.provision "shell", inline: "sudo pip install hererocks" 27 | config.vm.provision "shell", inline: "hererocks lua_install -r^ --lua=5.3" 28 | config.vm.provision "shell", inline: "echo 'PATH=$PATH:/home/vagrant/lua_install/bin' >> .bashrc" 29 | config.vm.provision "shell", inline: "source .bashrc" 30 | config.vm.provision "shell", inline: "lua_install/bin/luarocks install luacheck" 31 | config.vm.provision "shell", inline: "lua_install/bin/luarocks install busted" 32 | config.vm.provision "shell", inline: "lua_install/bin/luarocks install luacov" 33 | config.vm.provision "shell", inline: "lua_install/bin/luarocks install lua-path" 34 | config.vm.provision "shell", inline: "lua_install/bin/luarocks install luacov-coveralls" 35 | end 36 | -------------------------------------------------------------------------------- /Vagrantfile.config.yml: -------------------------------------------------------------------------------- 1 | ip: 192.168.10.11 2 | synced_folder: 3 | host_path: "/vagrant/lua" 4 | guest_path: "./" 5 | 6 | -------------------------------------------------------------------------------- /note/publish.txt: -------------------------------------------------------------------------------- 1 | # follow this link: https://github.com/luarocks/luarocks/wiki/creating-a-rock 2 | 3 | git tag v1.0.5 4 | git push --tags 5 | 6 | luarocks upload rockspecs/luagraphs-1.0-5.rockspec --api-key= 7 | -------------------------------------------------------------------------------- /note/testing.txt: -------------------------------------------------------------------------------- 1 | busted spec --verbose 2 | -------------------------------------------------------------------------------- /rockspecs/luagraphs-1.0-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "luagraphs" 2 | version = "1.0-1" 3 | source = { 4 | url = "git://github.com/chen0040/lua-graph.git", 5 | tag = "v1.0.1", 6 | } 7 | description = { 8 | summary = "Lua Graph Algorithms Library", 9 | detailed = [[ 10 | Lua implementation for algorithms and data structures 11 | for Graph processing 12 | ]], 13 | homepage = "https://github.com/chen0040/lua-graph", 14 | license = "MIT/X11" 15 | } 16 | dependencies = { 17 | "lua >= 5.1, < 5.4" 18 | } 19 | build = { 20 | type = "builtin", 21 | modules = { 22 | -- Note the required Lua syntax when listing submodules as keys 23 | ["luagraphs.data.stack"] = "src/data/stack.lua", 24 | ["luagraphs.data.graph"] = "src/data/graph.lua", 25 | ["luagraphs.data.list"] = "src/data/list.lua", 26 | ["luagraphs.data.queue"] = "src/data/queue.lua", 27 | ["luagraphs.data.UnionFind"] = "src/data/UnionFind.lua", 28 | ["luagraphs.data.MinPQ"] = "src/data/MinPQ.lua", 29 | ["luagraphs.data.IndexedMinPQ"] = "src/data/IndexedMinPQ.lua", 30 | ["luagraphs.search.DepthFirstSearch"] = "src/search/DepthFirstSearch.lua", 31 | ["luagraphs.search.BreadthFirstSearch"] = "src/search/BreadthFirstSearch.lua", 32 | ["luagraphs.sort.TopologicalSort"] = "src/sort/TopologicalSort.lua", 33 | ["luagraphs.connectivity.ConnectedComponents"] = "src/connectivity/ConnectedComponents", 34 | ["luagraphs.connectivity.StronglyConnectedComponents"] = "src/connectivity/StronglyConnectedComponents", 35 | ["luagraphs.mst.KruskalMST"] = "src/mst/KruskalMST", 36 | ["luagraphs.mst.PrimMST"] = "src/mst/PrimMST", 37 | ["luagraphs.mst.EagerPrimMST"] = "src/mst/EagerPrimMST", 38 | ["luagraphs.shortest_paths.Dijkstra"] = "src/shortest_paths/Dijkstra", 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /rockspecs/luagraphs-1.0-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "luagraphs" 2 | version = "1.0-2" 3 | source = { 4 | url = "git://github.com/chen0040/lua-graph.git", 5 | tag = "v1.0.2", 6 | } 7 | description = { 8 | summary = "Lua Graph Algorithms Library", 9 | detailed = [[ 10 | Lua implementation for algorithms and data structures 11 | for Graph processing 12 | ]], 13 | homepage = "https://github.com/chen0040/lua-graph", 14 | license = "MIT/X11" 15 | } 16 | dependencies = { 17 | "lua >= 5.1, < 5.4" 18 | } 19 | build = { 20 | type = "builtin", 21 | modules = { 22 | -- Note the required Lua syntax when listing submodules as keys 23 | ["luagraphs.data.stack"] = "src/data/stack.lua", 24 | ["luagraphs.data.graph"] = "src/data/graph.lua", 25 | ["luagraphs.data.network"] = "src/data/network.lua", 26 | ["luagraphs.data.list"] = "src/data/list.lua", 27 | ["luagraphs.data.queue"] = "src/data/queue.lua", 28 | ["luagraphs.data.UnionFind"] = "src/data/UnionFind.lua", 29 | ["luagraphs.data.MinPQ"] = "src/data/MinPQ.lua", 30 | ["luagraphs.data.IndexedMinPQ"] = "src/data/IndexedMinPQ.lua", 31 | ["luagraphs.search.DepthFirstSearch"] = "src/search/DepthFirstSearch.lua", 32 | ["luagraphs.search.BreadthFirstSearch"] = "src/search/BreadthFirstSearch.lua", 33 | ["luagraphs.sort.TopologicalSort"] = "src/sort/TopologicalSort.lua", 34 | ["luagraphs.connectivity.ConnectedComponents"] = "src/connectivity/ConnectedComponents.lua", 35 | ["luagraphs.connectivity.StronglyConnectedComponents"] = "src/connectivity/StronglyConnectedComponents.lua", 36 | ["luagraphs.mst.KruskalMST"] = "src/mst/KruskalMST.lua", 37 | ["luagraphs.mst.PrimMST"] = "src/mst/PrimMST.lua", 38 | ["luagraphs.mst.EagerPrimMST"] = "src/mst/EagerPrimMST.lua", 39 | ["luagraphs.shortest_paths.Dijkstra"] = "src/shortest_paths/Dijkstra.lua", 40 | ["luagraphs.shortest_paths.TopoSortShortestPath"] = "src/shortest_paths/TopoSortShortestPath.lua", 41 | ["luagraphs.shortest_paths.BellmanFord"] = "src/shortest_paths/BellmanFord.lua", 42 | ["luagraphs.flow.FordFulkerson"] = "src/flow/FordFulkerson.lua", 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /rockspecs/luagraphs-1.0-3.rockspec: -------------------------------------------------------------------------------- 1 | package = "luagraphs" 2 | version = "1.0-3" 3 | source = { 4 | url = "git://github.com/chen0040/lua-graph.git", 5 | tag = "v1.0.3", 6 | } 7 | description = { 8 | summary = "Lua Graph Algorithms Library", 9 | detailed = [[ 10 | Lua implementation for algorithms and data structures 11 | for Graph processing 12 | ]], 13 | homepage = "https://github.com/chen0040/lua-graph", 14 | license = "MIT/X11" 15 | } 16 | dependencies = { 17 | "lua >= 5.1, < 5.4" 18 | } 19 | build = { 20 | type = "builtin", 21 | modules = { 22 | -- Note the required Lua syntax when listing submodules as keys 23 | ["luagraphs.data.stack"] = "src/data/stack.lua", 24 | ["luagraphs.data.graph"] = "src/data/graph.lua", 25 | ["luagraphs.data.network"] = "src/data/network.lua", 26 | ["luagraphs.data.list"] = "src/data/list.lua", 27 | ["luagraphs.data.queue"] = "src/data/queue.lua", 28 | ["luagraphs.data.UnionFind"] = "src/data/UnionFind.lua", 29 | ["luagraphs.data.MinPQ"] = "src/data/MinPQ.lua", 30 | ["luagraphs.data.IndexedMinPQ"] = "src/data/IndexedMinPQ.lua", 31 | ["luagraphs.search.DepthFirstSearch"] = "src/search/DepthFirstSearch.lua", 32 | ["luagraphs.search.BreadthFirstSearch"] = "src/search/BreadthFirstSearch.lua", 33 | ["luagraphs.sort.TopologicalSort"] = "src/sort/TopologicalSort.lua", 34 | ["luagraphs.connectivity.ConnectedComponents"] = "src/connectivity/ConnectedComponents.lua", 35 | ["luagraphs.connectivity.StronglyConnectedComponents"] = "src/connectivity/StronglyConnectedComponents.lua", 36 | ["luagraphs.mst.KruskalMST"] = "src/mst/KruskalMST.lua", 37 | ["luagraphs.mst.PrimMST"] = "src/mst/PrimMST.lua", 38 | ["luagraphs.mst.EagerPrimMST"] = "src/mst/EagerPrimMST.lua", 39 | ["luagraphs.shortest_paths.Dijkstra"] = "src/shortest_paths/Dijkstra.lua", 40 | ["luagraphs.shortest_paths.TopoSortShortestPath"] = "src/shortest_paths/TopoSortShortestPath.lua", 41 | ["luagraphs.shortest_paths.BellmanFord"] = "src/shortest_paths/BellmanFord.lua", 42 | ["luagraphs.flow.FordFulkerson"] = "src/flow/FordFulkerson.lua", 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /rockspecs/luagraphs-1.0-4.rockspec: -------------------------------------------------------------------------------- 1 | package = "luagraphs" 2 | version = "1.0-4" 3 | source = { 4 | url = "git://github.com/chen0040/lua-graph.git", 5 | tag = "v1.0.4", 6 | } 7 | description = { 8 | summary = "Lua Graph Algorithms Library", 9 | detailed = [[ 10 | Lua implementation for algorithms and data structures 11 | for Graph processing 12 | ]], 13 | homepage = "https://github.com/chen0040/lua-graph", 14 | license = "MIT/X11" 15 | } 16 | dependencies = { 17 | "lua >= 5.1, < 5.4" 18 | } 19 | build = { 20 | type = "builtin", 21 | modules = { 22 | -- Note the required Lua syntax when listing submodules as keys 23 | ["luagraphs.data.stack"] = "src/data/stack.lua", 24 | ["luagraphs.data.graph"] = "src/data/graph.lua", 25 | ["luagraphs.data.network"] = "src/data/network.lua", 26 | ["luagraphs.data.list"] = "src/data/list.lua", 27 | ["luagraphs.data.queue"] = "src/data/queue.lua", 28 | ["luagraphs.data.UnionFind"] = "src/data/UnionFind.lua", 29 | ["luagraphs.data.MinPQ"] = "src/data/MinPQ.lua", 30 | ["luagraphs.data.IndexedMinPQ"] = "src/data/IndexedMinPQ.lua", 31 | ["luagraphs.search.DepthFirstSearch"] = "src/search/DepthFirstSearch.lua", 32 | ["luagraphs.search.BreadthFirstSearch"] = "src/search/BreadthFirstSearch.lua", 33 | ["luagraphs.sort.TopologicalSort"] = "src/sort/TopologicalSort.lua", 34 | ["luagraphs.connectivity.ConnectedComponents"] = "src/connectivity/ConnectedComponents.lua", 35 | ["luagraphs.connectivity.StronglyConnectedComponents"] = "src/connectivity/StronglyConnectedComponents.lua", 36 | ["luagraphs.mst.KruskalMST"] = "src/mst/KruskalMST.lua", 37 | ["luagraphs.mst.PrimMST"] = "src/mst/PrimMST.lua", 38 | ["luagraphs.mst.EagerPrimMST"] = "src/mst/EagerPrimMST.lua", 39 | ["luagraphs.shortest_paths.Dijkstra"] = "src/shortest_paths/Dijkstra.lua", 40 | ["luagraphs.shortest_paths.TopoSortShortestPath"] = "src/shortest_paths/TopoSortShortestPath.lua", 41 | ["luagraphs.shortest_paths.BellmanFord"] = "src/shortest_paths/BellmanFord.lua", 42 | ["luagraphs.flow.FordFulkerson"] = "src/flow/FordFulkerson.lua", 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /rockspecs/luagraphs-1.0-5.rockspec: -------------------------------------------------------------------------------- 1 | package = "luagraphs" 2 | version = "1.0-5" 3 | source = { 4 | url = "git://github.com/chen0040/lua-graph.git", 5 | tag = "v1.0.5", 6 | } 7 | description = { 8 | summary = "Lua Graph Algorithms Library", 9 | detailed = [[ 10 | Lua implementation for algorithms and data structures 11 | for Graph processing 12 | ]], 13 | homepage = "https://github.com/chen0040/lua-graph", 14 | license = "MIT/X11" 15 | } 16 | dependencies = { 17 | "lua >= 5.1, < 5.4" 18 | } 19 | build = { 20 | type = "builtin", 21 | modules = { 22 | -- Note the required Lua syntax when listing submodules as keys 23 | ["luagraphs.data.stack"] = "src/luagraphs/data/stack.lua", 24 | ["luagraphs.data.graph"] = "src/luagraphs/data/graph.lua", 25 | ["luagraphs.data.network"] = "src/luagraphs/data/network.lua", 26 | ["luagraphs.data.list"] = "src/luagraphs/data/list.lua", 27 | ["luagraphs.data.queue"] = "src/luagraphs/data/queue.lua", 28 | ["luagraphs.data.UnionFind"] = "src/luagraphs/data/UnionFind.lua", 29 | ["luagraphs.data.MinPQ"] = "src/luagraphs/data/MinPQ.lua", 30 | ["luagraphs.data.IndexedMinPQ"] = "src/luagraphs/data/IndexedMinPQ.lua", 31 | ["luagraphs.search.DepthFirstSearch"] = "src/luagraphs/search/DepthFirstSearch.lua", 32 | ["luagraphs.search.BreadthFirstSearch"] = "src/luagraphs/search/BreadthFirstSearch.lua", 33 | ["luagraphs.sort.TopologicalSort"] = "src/luagraphs/sort/TopologicalSort.lua", 34 | ["luagraphs.connectivity.ConnectedComponents"] = "src/luagraphs/connectivity/ConnectedComponents.lua", 35 | ["luagraphs.connectivity.StronglyConnectedComponents"] = "src/luagraphs/connectivity/StronglyConnectedComponents.lua", 36 | ["luagraphs.mst.KruskalMST"] = "src/luagraphs/mst/KruskalMST.lua", 37 | ["luagraphs.mst.PrimMST"] = "src/luagraphs/mst/PrimMST.lua", 38 | ["luagraphs.mst.EagerPrimMST"] = "src/luagraphs/mst/EagerPrimMST.lua", 39 | ["luagraphs.shortest_paths.Dijkstra"] = "src/luagraphs/shortest_paths/Dijkstra.lua", 40 | ["luagraphs.shortest_paths.TopoSortShortestPath"] = "src/luagraphs/shortest_paths/TopoSortShortestPath.lua", 41 | ["luagraphs.shortest_paths.BellmanFord"] = "src/luagraphs/shortest_paths/BellmanFord.lua", 42 | ["luagraphs.flow.FordFulkerson"] = "src/luagraphs/flow/FordFulkerson.lua", 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /spec/BellmanFord_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 28/7/2017 5 | -- Time: 11:32 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | describe("BellmanFord", function() 10 | it('should be able to find all the shortest paths from the source node', function() 11 | local g = require('luagraphs.data.graph').create(8, true); 12 | 13 | g:addEdge(0, 1, 5.0) 14 | g:addEdge(0, 4, 9.0) 15 | g:addEdge(0, 7, 8.0) 16 | g:addEdge(1, 2, 12.0) 17 | g:addEdge(1, 3, 15.0) 18 | g:addEdge(1, 7, 4.0) 19 | g:addEdge(2, 3, 3.0) 20 | g:addEdge(2, 6, 11.0) 21 | g:addEdge(3, 6, 9.0) 22 | g:addEdge(4, 5, 5.0) 23 | g:addEdge(4, 6, 20.0) 24 | g:addEdge(4, 7, 5.0) 25 | g:addEdge(5, 2, 1.0) 26 | g:addEdge(5, 6, 13.0) 27 | g:addEdge(7, 5, 6.0) 28 | g:addEdge(7, 2, 7.0) 29 | 30 | local source = 0 31 | 32 | local method = require('luagraphs.shortest_paths.BellmanFord').create() 33 | method:run(g, source) 34 | print('BellmanFord shortest path') 35 | for i = 0,g:vertexCount()-1 do 36 | local v = g:vertexAt(i) 37 | if v ~= source and method:hasPathTo(v) then 38 | print('path from 0 to ' .. v .. ' ( cost: ' .. method:getPathLength(v) .. ' )') 39 | local path = method:getPathTo(v) 40 | for i = 0,path:size()-1 do 41 | print('# from ' .. path:get(i):from() .. ' to ' .. path:get(i):to() .. ' ( distance: ' .. path:get(i).weight .. ' )') 42 | end 43 | end 44 | end 45 | 46 | end) 47 | end) 48 | 49 | -------------------------------------------------------------------------------- /spec/BreadthFirstSearch_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 9/7/2017 5 | -- Time: 10:12 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | describe('BreadthFirstSearch()', function() 10 | local g = require('luagraphs.data.graph').create(6) 11 | g:addEdge(0, 5); 12 | g:addEdge(2, 4); 13 | g:addEdge(2, 3); 14 | g:addEdge(1, 2); 15 | g:addEdge(0, 1); 16 | g:addEdge(3, 4); 17 | g:addEdge(3, 5); 18 | g:addEdge(0, 2); 19 | local bfs = require('luagraphs.search.BreadthFirstSearch').create() 20 | local s = 0 21 | bfs:run(g, s) 22 | 23 | for i = 0, g:vertexCount()-1 do 24 | local v = g:vertexAt(i) 25 | if v ~= s and bfs:hasPathTo(v) then 26 | local path = bfs:getPathTo(v) 27 | local pathText = '' 28 | while path:isEmpty() == false do 29 | local x = path:pop() 30 | if pathText == '' then 31 | pathText = pathText .. x 32 | else 33 | pathText = pathText .. ' -> ' .. x 34 | end 35 | end 36 | print(pathText) 37 | 38 | end 39 | end 40 | 41 | 42 | end) 43 | 44 | -------------------------------------------------------------------------------- /spec/ConnectedComponents_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 11/7/2017 5 | -- Time: 8:33 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | describe('ConnectedComponents()', function() 10 | it('should list the connected components in the graph', function() 11 | local g = require('luagraphs.data.graph').create(13) 12 | g:addEdge(0, 5) 13 | g:addEdge(4, 3) 14 | g:addEdge(0, 1) 15 | g:addEdge(9, 12) 16 | g:addEdge(6, 4) 17 | g:addEdge(5, 4) 18 | g:addEdge(0, 2) 19 | g:addEdge(11, 12) 20 | g:addEdge(9,10) 21 | g:addEdge(0, 6) 22 | g:addEdge(7, 8) 23 | g:addEdge(9, 11) 24 | g:addEdge(5, 3) 25 | 26 | local cc = require('luagraphs.connectivity.ConnectedComponents').create() 27 | cc:run(g) 28 | 29 | print('count: ' .. cc.count) 30 | assert.equal(cc.count, 3) 31 | for i = 0,g:vertexCount()-1 do 32 | local v = g:vertexAt(i) 33 | print('id[' .. v .. ']: ' .. cc:component(v)) 34 | end 35 | 36 | end) 37 | end) 38 | 39 | -------------------------------------------------------------------------------- /spec/DepthFirstSearch_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 9/7/2017 5 | -- Time: 10:12 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | describe('DepthFirstSearch()', function() 10 | local g = require('luagraphs.data.graph').create(6) 11 | g:addEdge(0, 5); 12 | g:addEdge(2, 4); 13 | g:addEdge(2, 3); 14 | g:addEdge(1, 2); 15 | g:addEdge(0, 1); 16 | g:addEdge(3, 4); 17 | g:addEdge(3, 5); 18 | g:addEdge(0, 2); 19 | local dfs = require('luagraphs.search.DepthFirstSearch').create() 20 | local s = 0 21 | dfs:run(g, s) 22 | 23 | for i = 0, g:vertexCount()-1 do 24 | local v = g:vertexAt(i) 25 | if v ~= s and dfs:hasPathTo(v) then 26 | print('has path to ' .. v) 27 | local path = dfs:getPathTo(v) 28 | local pathText = '' 29 | while path:isEmpty() == false do 30 | local x = path:pop() 31 | if pathText == '' then 32 | pathText = pathText .. x 33 | else 34 | pathText = pathText .. ' -> ' .. x 35 | end 36 | end 37 | print(pathText) 38 | 39 | end 40 | end 41 | 42 | 43 | end) 44 | 45 | -------------------------------------------------------------------------------- /spec/Dijkstra_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 28/7/2017 5 | -- Time: 11:32 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | describe("Dijkstra", function() 10 | it('should be able to find all the shortest paths from the source node', function() 11 | local g = require('luagraphs.data.graph').create(8, true); 12 | 13 | g:addEdge(0, 1, 5.0) 14 | g:addEdge(0, 4, 9.0) 15 | g:addEdge(0, 7, 8.0) 16 | g:addEdge(1, 2, 12.0) 17 | g:addEdge(1, 3, 15.0) 18 | g:addEdge(1, 7, 4.0) 19 | g:addEdge(2, 3, 3.0) 20 | g:addEdge(2, 6, 11.0) 21 | g:addEdge(3, 6, 9.0) 22 | g:addEdge(4, 5, 5.0) 23 | g:addEdge(4, 6, 20.0) 24 | g:addEdge(4, 7, 5.0) 25 | g:addEdge(5, 2, 1.0) 26 | g:addEdge(5, 6, 13.0) 27 | g:addEdge(7, 5, 6.0) 28 | g:addEdge(7, 2, 7.0) 29 | 30 | local source = 0 31 | 32 | local dijkstra = require('luagraphs.shortest_paths.Dijkstra').create() 33 | dijkstra:run(g, source) 34 | print('Dijkstra shortest path') 35 | for i = 0,g:vertexCount()-1 do 36 | local v = g:vertexAt(i) 37 | if v ~= source and dijkstra:hasPathTo(v) then 38 | print('path from 0 to ' .. v .. ' ( cost: ' .. dijkstra:getPathLength(v) .. ' )') 39 | local path = dijkstra:getPathTo(v) 40 | for i = 0,path:size()-1 do 41 | print('# from ' .. path:get(i):from() .. ' to ' .. path:get(i):to() .. ' ( distance: ' .. path:get(i).weight .. ' )') 42 | end 43 | end 44 | end 45 | 46 | end) 47 | end) 48 | 49 | -------------------------------------------------------------------------------- /spec/EagerPrimMST_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 26/7/2017 5 | -- Time: 11:52 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | describe('EagerPrimMST', function() 10 | it('should find the minimum spanning tree', function() 11 | local mst = require('luagraphs.mst.EagerPrimMST').create() 12 | local g = require('luagraphs.data.graph').create(8) 13 | g:addEdge(0, 7, 0.16) 14 | g:addEdge(2, 3, 0.17) 15 | g:addEdge(1, 7, 0.19) 16 | g:addEdge(0, 2, 0.26) 17 | g:addEdge(5, 7, 0.28) 18 | g:addEdge(1, 3, 0.29) 19 | g:addEdge(1, 5, 0.32) 20 | g:addEdge(2, 7, 0.34) 21 | g:addEdge(4, 5, 0.35) 22 | g:addEdge(1, 2, 0.36) 23 | g:addEdge(4, 7, 0.37) 24 | g:addEdge(0, 4, 0.38) 25 | g:addEdge(6, 2, 0.4) 26 | g:addEdge(3, 6, 0.52) 27 | g:addEdge(6, 0, 0.58) 28 | g:addEdge(6, 4, 0.93) 29 | 30 | mst:run(g) 31 | 32 | local path = mst.path 33 | 34 | assert.equal(path:size(), g:vertexCount()-1) 35 | print('Eager Prim') 36 | for i=0,path:size()-1 do 37 | local e = path:get(i) 38 | print(e:from() .. ' -> ' .. e:to() .. ' (' .. e.weight .. ')') 39 | end 40 | 41 | end) 42 | end) 43 | 44 | -------------------------------------------------------------------------------- /spec/FordFulkerson_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 28/7/2017 5 | -- Time: 11:32 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | describe("FordFulkerson", function() 10 | it('should be able to find max flow of 28', function() 11 | local g = require('luagraphs.data.network').FlowNetwork.create(8); 12 | 13 | g:addEdge(0, 1, 10); -- capacity from vertex 0 to vertex 1 is 10 14 | g:addEdge(0, 2, 5); 15 | g:addEdge(0, 3, 15); 16 | g:addEdge(1, 4, 9); 17 | g:addEdge(1, 5, 15); 18 | g:addEdge(1, 2, 4); 19 | g:addEdge(2, 5, 8); 20 | g:addEdge(2, 3, 4); 21 | g:addEdge(3, 6, 16); 22 | g:addEdge(4, 5, 15); 23 | g:addEdge(4, 7, 10); 24 | g:addEdge(5, 7, 10); 25 | g:addEdge(5, 6, 15); 26 | g:addEdge(6, 2, 6); 27 | g:addEdge(6, 7, 10); 28 | 29 | local method = require('luagraphs.flow.FordFulkerson').create() 30 | local maxFlow = method:run(g, 0, 7) 31 | print('FordFulkerson max flow: ' .. maxFlow) 32 | 33 | assert.equals(maxFlow, 28); 34 | 35 | local minCuts = method:minCuts() 36 | 37 | for i = 0,minCuts:size()-1 do 38 | local e =minCuts:get(i) 39 | print('min cut: ' .. e:toString()) 40 | end 41 | 42 | 43 | end) 44 | end) 45 | 46 | -------------------------------------------------------------------------------- /spec/IndexedMinPQ_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 28/7/2017 5 | -- Time: 10:01 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | describe('IndexedMinPQ', function() 10 | it('should be store indexed keys in a priority queue', function() 11 | local pq = require('luagraphs.data.IndexedMinPQ').create() 12 | 13 | pq:add(0, 10) 14 | pq:add(1, 1) 15 | pq:add(2, 20) 16 | pq:add(6, 2) 17 | 18 | assert.equals(pq:size(), 4) 19 | assert.equals(pq:isEmpty(), false) 20 | assert.equals(pq:contains(0), true) 21 | assert.equals(pq:contains(1), true) 22 | assert.equals(pq:contains(2), true) 23 | assert.equals(pq:contains(3), false) 24 | assert.equals(pq:contains(6), true) 25 | 26 | pq:decreaseKey(2, 0.5) 27 | assert.equals(pq:minKey(), 0.5) 28 | assert.equals(pq:minIndex(), 2) 29 | assert.equals(pq:delMin(), 0.5) 30 | assert.equals(pq:delMin(), 1) 31 | assert.equals(pq:delMin(), 2) 32 | assert.equals(pq:delMin(), 10) 33 | end) 34 | end) 35 | 36 | -------------------------------------------------------------------------------- /spec/KruskalMST_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 26/7/2017 5 | -- Time: 11:52 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | describe('KruskalMST', function() 10 | it('should find the minimum spanning tree', function() 11 | local mst = require('luagraphs.mst.KruskalMST').create() 12 | local g = require('luagraphs.data.graph').create(8) 13 | g:addEdge(0, 7, 0.16) 14 | g:addEdge(2, 3, 0.17) 15 | g:addEdge(1, 7, 0.19) 16 | g:addEdge(0, 2, 0.26) 17 | g:addEdge(5, 7, 0.28) 18 | g:addEdge(1, 3, 0.29) 19 | g:addEdge(1, 5, 0.32) 20 | g:addEdge(2, 7, 0.34) 21 | g:addEdge(4, 5, 0.35) 22 | g:addEdge(1, 2, 0.36) 23 | g:addEdge(4, 7, 0.37) 24 | g:addEdge(0, 4, 0.38) 25 | g:addEdge(6, 2, 0.4) 26 | g:addEdge(3, 6, 0.52) 27 | g:addEdge(6, 0, 0.58) 28 | g:addEdge(6, 4, 0.93) 29 | 30 | mst:run(g) 31 | 32 | local path = mst.path 33 | print('Kruskal') 34 | assert.equal(path:size(), g:vertexCount()-1) 35 | for i=0,path:size()-1 do 36 | local e = path:get(i) 37 | print(e:from() .. ' -> ' .. e:to() .. ' (' .. e.weight .. ')') 38 | end 39 | 40 | end) 41 | end) 42 | 43 | -------------------------------------------------------------------------------- /spec/MinPQ_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 26/7/2017 5 | -- Time: 11:32 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | describe('MinPQ', function() 10 | it('should add and remove the min item first', function() 11 | local pq = require('luagraphs.data.MinPQ').create(function(a1, a2) return a1 - a2 end) 12 | pq:add(2) 13 | pq:add(4) 14 | pq:add(1) 15 | pq:add(20) 16 | 17 | assert(pq:size(), 4) 18 | assert.equal(pq:delMin(), 1) 19 | assert.equal(pq:delMin(), 2) 20 | assert.equal(pq:delMin(), 4) 21 | assert.equal(pq:delMin(), 20) 22 | assert(pq:isEmpty(), true) 23 | 24 | end) 25 | end) 26 | 27 | -------------------------------------------------------------------------------- /spec/PrimMST_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 26/7/2017 5 | -- Time: 11:52 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | describe('PrimMST', function() 10 | it('should find the minimum spanning tree', function() 11 | local mst = require('luagraphs.mst.PrimMST').create() 12 | local g = require('luagraphs.data.graph').create(8) 13 | g:addEdge(0, 7, 0.16) 14 | g:addEdge(2, 3, 0.17) 15 | g:addEdge(1, 7, 0.19) 16 | g:addEdge(0, 2, 0.26) 17 | g:addEdge(5, 7, 0.28) 18 | g:addEdge(1, 3, 0.29) 19 | g:addEdge(1, 5, 0.32) 20 | g:addEdge(2, 7, 0.34) 21 | g:addEdge(4, 5, 0.35) 22 | g:addEdge(1, 2, 0.36) 23 | g:addEdge(4, 7, 0.37) 24 | g:addEdge(0, 4, 0.38) 25 | g:addEdge(6, 2, 0.4) 26 | g:addEdge(3, 6, 0.52) 27 | g:addEdge(6, 0, 0.58) 28 | g:addEdge(6, 4, 0.93) 29 | 30 | mst:run(g) 31 | 32 | local path = mst.path 33 | 34 | assert.equal(path:size(), g:vertexCount()-1) 35 | print('Lazy Prim') 36 | for i=0,path:size()-1 do 37 | local e = path:get(i) 38 | print(e:from() .. ' -> ' .. e:to() .. ' (' .. e.weight .. ')') 39 | end 40 | 41 | end) 42 | end) 43 | 44 | -------------------------------------------------------------------------------- /spec/StrongConnectedComponents_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 25/7/2017 5 | -- Time: 9:37 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | describe('StronglyConnectedComponents', function() 10 | it('should return the components that are strongly connected', function() 11 | local graph = require('luagraphs.data.graph').create(13, true) 12 | graph:addEdge(4, 2) 13 | graph:addEdge(2, 3) 14 | graph:addEdge(3, 2) 15 | graph:addEdge(6, 0) 16 | graph:addEdge(0, 1) 17 | graph:addEdge(2, 0) 18 | graph:addEdge(11, 12) 19 | graph:addEdge(12, 9) 20 | graph:addEdge(9, 10) 21 | graph:addEdge(9, 11) 22 | graph:addEdge(8, 9) 23 | graph:addEdge(10, 12) 24 | graph:addEdge(11, 4) 25 | graph:addEdge(4, 3) 26 | graph:addEdge(3, 5) 27 | graph:addEdge(7, 8) 28 | graph:addEdge(8, 7) 29 | graph:addEdge(5, 4) 30 | graph:addEdge(0, 5) 31 | graph:addEdge(6, 4) 32 | graph:addEdge(6, 9) 33 | graph:addEdge(7, 6) 34 | 35 | local scc = require('luagraphs.connectivity.StronglyConnectedComponents').create() 36 | scc:run(graph) 37 | assert.equal(scc.count, 5) 38 | 39 | for i = 0,graph:vertexCount()-1 do 40 | local v = graph:vertexAt(i) 41 | print('id[' .. v .. ']: ' .. scc:component(v)) 42 | end 43 | 44 | end) 45 | end) 46 | 47 | -------------------------------------------------------------------------------- /spec/TopoSortShortestPath_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 28/7/2017 5 | -- Time: 11:32 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | describe("TopoSortShortestPath", function() 10 | it('should be able to find all the shortest paths from the source node', function() 11 | local g = require('luagraphs.data.graph').create(8, true); 12 | 13 | g:addEdge(0, 1, 5.0) 14 | g:addEdge(0, 4, 9.0) 15 | g:addEdge(0, 7, 8.0) 16 | g:addEdge(1, 2, 12.0) 17 | g:addEdge(1, 3, 15.0) 18 | g:addEdge(1, 7, 4.0) 19 | g:addEdge(2, 3, 3.0) 20 | g:addEdge(2, 6, 11.0) 21 | g:addEdge(3, 6, 9.0) 22 | g:addEdge(4, 5, 5.0) 23 | g:addEdge(4, 6, 20.0) 24 | g:addEdge(4, 7, 5.0) 25 | g:addEdge(5, 2, 1.0) 26 | g:addEdge(5, 6, 13.0) 27 | g:addEdge(7, 5, 6.0) 28 | g:addEdge(7, 2, 7.0) 29 | 30 | local source = 0 31 | local finder = require('luagraphs.shortest_paths.TopoSortShortestPath').create() 32 | finder:run(g, source) 33 | print('topological sort shortest paths'); 34 | for i = 0,g:vertexCount()-1 do 35 | local v = g:vertexAt(i) 36 | if v ~= source and finder:hasPathTo(v) then 37 | print('path from 0 to ' .. v .. ' ( cost: ' .. finder:getPathLength(v) .. ' )') 38 | local path = finder:getPathTo(v) 39 | for i = 0,path:size()-1 do 40 | print('# from ' .. path:get(i):from() .. ' to ' .. path:get(i):to() .. ' ( distance: ' .. path:get(i).weight .. ' )') 41 | end 42 | end 43 | end 44 | 45 | end) 46 | end) 47 | 48 | -------------------------------------------------------------------------------- /spec/TopologicalSort_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 11/7/2017 5 | -- Time: 8:48 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | describe('TopoloicalSort()', function() 10 | it('should topo sort', function() 11 | local dag = require('luagraphs.data.graph').create(7, true) 12 | 13 | local edges = { --from, to 14 | {0, 5}, 15 | {0, 2}, 16 | {0, 1}, 17 | {3, 6}, 18 | {3, 5}, 19 | {3, 4}, 20 | {5, 4}, 21 | {6, 4}, 22 | {6, 0}, 23 | {3, 2}, 24 | {1, 4}, 25 | } 26 | 27 | for edgenum=1,#edges do 28 | dag:addEdge(edges[edgenum][1], edges[edgenum][2]) 29 | end 30 | 31 | local ts = require('luagraphs.sort.TopologicalSort').create() 32 | ts:run(dag) 33 | 34 | local path = ts:path() 35 | local vorder={} -- map from vertex to order visited 36 | 37 | -- Show the order, and collect it to check 38 | for i=0, path:size()-1 do 39 | print('sort #' .. i .. ': ' .. path:get(i)) 40 | vorder[path:get(i)] = i 41 | end 42 | 43 | -- Make sure the to-node comes after the from-node along every edge. 44 | for edgenum=1,#edges do 45 | local from, to = edges[edgenum][1], edges[edgenum][2] 46 | assert.is_true(vorder[from] < vorder[to]) 47 | end 48 | end) 49 | end) 50 | 51 | -------------------------------------------------------------------------------- /spec/UnionFind_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 26/7/2017 5 | -- Time: 11:36 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | describe('UnionFind', function() 10 | it('should connect vertices that are union', function() 11 | local uf = require('luagraphs.data.UnionFind').create(10) 12 | 13 | uf:union(2, 4) 14 | uf:union(1, 2) 15 | uf:union(5, 6) 16 | 17 | assert.equal(uf:connected(1, 2), true) 18 | assert.equal(uf:connected(1, 4), true) 19 | assert.equal(uf:connected(1, 5), false) 20 | assert.equal(uf:connected(1, 6), false) 21 | end) 22 | end) 23 | 24 | -------------------------------------------------------------------------------- /spec/graph_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 28/6/2017 5 | -- Time: 9:16 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | describe("Graph", function() 10 | describe("Undirected Unweighted Graph", function() 11 | it("should create an undirected unweighted graph", function() 12 | local g = require('luagraphs.data.graph').create(6); 13 | g:addEdge(0, 5); 14 | g:addEdge(2, 4); 15 | g:addEdge(2, 3); 16 | g:addEdge(1, 2); 17 | g:addEdge(0, 1); 18 | g:addEdge(3, 4); 19 | g:addEdge(3, 5); 20 | g:addEdge(0, 2); 21 | 22 | assert.equal(g:vertexCount(), 6) 23 | 24 | for i = 0, g:vertexCount() -1 do 25 | local v = g:vertexAt(i) 26 | local adj_v = g:adj(v) 27 | local text = '' 28 | for i = 0, adj_v:size()-1 do 29 | text = text .. ', ' .. adj_v:get(i):other(v) 30 | end 31 | print(text) 32 | end 33 | 34 | end) 35 | end) 36 | 37 | describe("Undirected Unweighted Graph With Vertices added later", function() 38 | it("should automatically expand the graph", function() 39 | local g = require('luagraphs.data.graph').create(6); 40 | g:addEdge(0, 5); 41 | g:addEdge(2, 4); 42 | g:addEdge(2, 3); 43 | g:addEdge(1, 2); 44 | g:addEdge(0, 1); 45 | g:addEdge(3, 4); 46 | g:addEdge(3, 5); 47 | g:addEdge(0, 2); 48 | 49 | g:addEdge(-1, 10) 50 | g:addEdge(9, 2) 51 | g:addEdge(-1, 0) 52 | 53 | assert.equal(g:containsVertex(9), true) 54 | assert.equal(g:containsVertex(-1), true) 55 | assert.equal(g:containsVertex(8), false) 56 | 57 | assert.equal(g:vertexCount(), 9) 58 | 59 | for i = 0, g:vertexCount() -1 do 60 | local v = g:vertexAt(i) 61 | local adj_v = g:adj(v) 62 | local text = '' 63 | for i = 0, adj_v:size()-1 do 64 | text = text .. ', ' .. adj_v:get(i):other(v) 65 | end 66 | print(text) 67 | end 68 | 69 | end) 70 | end) 71 | 72 | describe('Dynamically expand and shrink a graph', function() 73 | it("should dynamically adjust teh graph size", function() 74 | local vertices = require('luagraphs.data.list').create() 75 | vertices:add(3) 76 | vertices:add(5) 77 | vertices:add(10) 78 | 79 | local g = require('luagraphs.data.graph').createFromVertexList(vertices) 80 | 81 | assert.equal(g:vertexCount(), 3) 82 | 83 | g:addVertexIfNotExists(4) 84 | g:addVertexIfNotExists(5) 85 | 86 | assert.equal(g:vertexCount(), 4) 87 | 88 | g:addEdge(0, 5) -- add a new vertex 0 and a bidirectional edge connecting 0 and 5 89 | 90 | assert.equal(g:vertexCount(), 5) 91 | 92 | g:removeVertex(10) 93 | 94 | assert.equal(g:vertexCount(), 4) 95 | 96 | 97 | -- code below prints the adjacency list 98 | for k = 0, g:vertexCount() -1 do -- iterate through all the vertices in g 99 | local v = g:vertexAt(k) 100 | local adj_v = g:adj(v) -- adjacency list for vertex v 101 | local text = '' 102 | for i = 0, adj_v:size()-1 do 103 | text = text .. ', ' .. adj_v:get(i):other(v) 104 | end 105 | print(text) 106 | end 107 | end) 108 | end) 109 | 110 | describe("reverse()", function() 111 | it("should reverse the graph", function() 112 | local g = require('luagraphs.data.graph').create(5, false) 113 | g:addEdge(0, 4) 114 | g:addEdge(2, 1) 115 | 116 | local g_reversed = g:reverse() 117 | assert.equal(g_reversed:hasEdge(4, 0), true) 118 | assert.equal(g_reversed:hasEdge(1, 2), true) 119 | assert.equal(g_reversed:hasEdge(0, 4), false) 120 | 121 | end) 122 | end) 123 | 124 | 125 | end) 126 | 127 | -------------------------------------------------------------------------------- /spec/list_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 9/7/2017 5 | -- Time: 10:32 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local list = require('luagraphs.data.list') 10 | 11 | describe('list', function() 12 | 13 | describe('list()', function() 14 | it('should add and remove item', function() 15 | local s = list.create() 16 | s:add(1) 17 | s:add(2) 18 | s:add(3) 19 | for index,val in pairs(s:enumerate()) do 20 | print(index, val) 21 | end 22 | for i = 0,s:size()-1 do 23 | print(s:get(i)) 24 | end 25 | s:set(2, 4) 26 | print(s:size()) 27 | assert.equal(s:size(), 3) 28 | assert.equal(s:isEmpty(), false) 29 | s:removeAt(0) 30 | s:remove(2) 31 | s:removeAt(0) 32 | assert.equal(s:size(), 0) 33 | assert.equal(s:isEmpty(), true) 34 | end) 35 | end) 36 | 37 | describe('makeCopy()', function() 38 | it('should create a separate copy', function() 39 | local s = list.create() 40 | for i = 0,9 do 41 | s:add(i) 42 | end 43 | local s2 = s:makeCopy() 44 | assert.equal(s:size(), s2:size()) 45 | for i = 0,9 do 46 | assert.equal(s:get(i), s2:get(i)) 47 | end 48 | 49 | 50 | end) 51 | end) 52 | end) 53 | 54 | -------------------------------------------------------------------------------- /spec/queue_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 9/7/2017 5 | -- Time: 10:41 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | describe('queue()', function() 10 | it('should enqueue and dequeue', function() 11 | local queue = require('luagraphs.data.queue').create() 12 | queue:enqueue(10) 13 | queue:enqueue(30) 14 | queue:enqueue(20) 15 | queue:enqueue(40) 16 | 17 | assert.equal(queue:size(), 4) 18 | assert.equal(queue:isEmpty(), false) 19 | assert.equal(queue:dequeue(), 10) 20 | assert.equal(queue:dequeue(), 30) 21 | assert.equal(queue:dequeue(), 20) 22 | assert.equal(queue:dequeue(), 40) 23 | assert.equal(queue:isEmpty(), true) 24 | end) 25 | end) 26 | 27 | -------------------------------------------------------------------------------- /spec/stack_spec.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 8/7/2017 5 | -- Time: 9:47 PM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | describe("stack()", function() 10 | it("should push and pop correctly", function() 11 | local stack = require('luagraphs.data.stack') 12 | local s = stack.create() 13 | 14 | s:push(10) 15 | s:push(9) 16 | s:push(13) 17 | s:push(14) 18 | 19 | assert.equal(s:size(), 4) 20 | end) 21 | end) 22 | 23 | -------------------------------------------------------------------------------- /src/luagraphs/connectivity/ConnectedComponents.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 11/7/2017 5 | -- Time: 8:28 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local ConnectedComponents = {} 10 | ConnectedComponents.__index = ConnectedComponents 11 | 12 | function ConnectedComponents.create() 13 | local s = {} 14 | setmetatable(s, ConnectedComponents) 15 | 16 | s.marked = {} 17 | s.count = 0 18 | s.id = {} 19 | 20 | return s 21 | end 22 | 23 | function ConnectedComponents:run(G) 24 | 25 | self.marked = {} 26 | self.id = {} 27 | for i = 0, G:vertexCount()-1 do 28 | local v = G:vertexAt(i) 29 | self.marked[v] = false 30 | self.id[v] = -1 31 | end 32 | 33 | self.count = 0 34 | for i = 0, G:vertexCount()-1 do 35 | local v = G:vertexAt(i) 36 | if self.marked[v] == false then 37 | self:dfs(G, v) 38 | self.count = self.count + 1 39 | end 40 | end 41 | 42 | end 43 | 44 | function ConnectedComponents:dfs(G, v) 45 | self.marked[v] = true 46 | self.id[v] = self.count 47 | 48 | local adj_v = G:adj(v) 49 | for i = 0,adj_v:size()-1 do 50 | local e = adj_v:get(i) 51 | local w = e:other(v) 52 | if self.marked[w] == false then 53 | self:dfs(G, w) 54 | end 55 | end 56 | 57 | end 58 | 59 | function ConnectedComponents:component(v) 60 | return self.id[v] 61 | end 62 | 63 | return ConnectedComponents 64 | 65 | -------------------------------------------------------------------------------- /src/luagraphs/connectivity/StronglyConnectedComponents.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 25/7/2017 5 | -- Time: 9:29 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local StronglyConnectedComponents = {} 10 | StronglyConnectedComponents.__index = StronglyConnectedComponents 11 | 12 | function StronglyConnectedComponents.create() 13 | local s = {} 14 | setmetatable(s, StronglyConnectedComponents) 15 | 16 | s.id = {} 17 | s.marked = {} 18 | s.count = 0 19 | return s 20 | end 21 | 22 | function StronglyConnectedComponents:run(G) 23 | self.marked = {} 24 | self.id = {} 25 | self.count = 0 26 | for i = 0,G:vertexCount()-1 do 27 | local v = G:vertexAt(i) 28 | self.marked[v] = false 29 | self.id[v] = -1 30 | end 31 | 32 | local g_prime = G:reverse() 33 | local topo_sort = require('luagraphs.sort.TopologicalSort').create() 34 | topo_sort:run(g_prime) 35 | local order = topo_sort:path() 36 | 37 | for i=0,order:size()-1 do 38 | local v = order:get(i) 39 | if self.marked[v] == false then 40 | self:dfs(G, v) 41 | self.count = self.count + 1 42 | end 43 | end 44 | end 45 | 46 | function StronglyConnectedComponents:dfs(G, v) 47 | local adj_v = G:adj(v) 48 | self.marked[v] = true 49 | self.id[v] = self.count 50 | for i=0,adj_v:size()-1 do 51 | local e = adj_v:get(i) 52 | local w = e:other(v) 53 | if self.marked[w] == false then 54 | self:dfs(G, w) 55 | end 56 | end 57 | end 58 | 59 | function StronglyConnectedComponents:component(v) 60 | return self.id[v] 61 | end 62 | 63 | return StronglyConnectedComponents 64 | 65 | -------------------------------------------------------------------------------- /src/luagraphs/data/IndexedMinPQ.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 28/7/2017 5 | -- Time: 9:39 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local IndexedMinPQ = {} 10 | IndexedMinPQ.__index = IndexedMinPQ 11 | 12 | function IndexedMinPQ.create(comparator) 13 | local s = {} 14 | setmetatable(s, IndexedMinPQ) 15 | 16 | if comparator == nil then 17 | comparator = function(a1, a2) return a1 - a2 end 18 | end 19 | 20 | s.keys = {} 21 | s.pq = {} 22 | s.qp = {} 23 | s.N = 0 24 | s.comparator = comparator 25 | return s; 26 | end 27 | 28 | function IndexedMinPQ:less(a1, a2) 29 | return self.comparator(a1, a2) < 0 30 | end 31 | 32 | function IndexedMinPQ:exchange(a, i, j) 33 | local temp = a[i] 34 | a[i] = a[j] 35 | a[j] = temp 36 | end 37 | 38 | function IndexedMinPQ:add(index, key) 39 | self.keys[index] = key 40 | self.N = self.N + 1 41 | self.pq[self.N] = index 42 | self.qp[index] = self.N 43 | 44 | self:swim(self.N) 45 | end 46 | 47 | function IndexedMinPQ:swim(k) 48 | while k > 1 do 49 | local parent = math.floor(k / 2) 50 | if self:less(self.keys[self.pq[k]], self.keys[self.pq[parent]]) then 51 | self:exchange(self.pq, k, parent) 52 | self.qp[self.pq[k]] = k 53 | self.qp[self.pq[parent]] = parent 54 | else 55 | break 56 | end 57 | end 58 | 59 | end 60 | 61 | function IndexedMinPQ:minKey() 62 | return self.keys[self.pq[1]] 63 | end 64 | 65 | function IndexedMinPQ:minIndex() 66 | return self.pq[1] 67 | end 68 | 69 | function IndexedMinPQ:delMin() 70 | if self.N == 0 then 71 | return nil 72 | end 73 | 74 | local key = self.keys[self.pq[1]] 75 | self:exchange(self.pq, 1, self.N) 76 | self.qp[self.pq[1]]=1 77 | self.qp[self.pq[self.N]]= self.N 78 | self.N = self.N - 1 79 | 80 | self:sink(1) 81 | 82 | return key 83 | end 84 | 85 | function IndexedMinPQ:sink(k) 86 | while k * 2 <= self.N do 87 | local child = k * 2 88 | if child < self.N and self:less(self.keys[self.pq[child+1]], self.keys[self.pq[child]]) then 89 | child = child + 1 90 | end 91 | 92 | if self:less(self.keys[self.pq[child]], self.keys[self.pq[k]]) then 93 | self:exchange(self.pq, child, k) 94 | self.qp[self.pq[child]] = child 95 | self.qp[self.pq[k]] = k 96 | else 97 | break 98 | end 99 | end 100 | end 101 | 102 | function IndexedMinPQ:decreaseKey(index, key) 103 | if self:less(key, self.keys[index]) then 104 | local position = self.qp[index] 105 | self.keys[index] = key 106 | self:swim(position) 107 | end 108 | end 109 | 110 | function IndexedMinPQ:contains(index) 111 | return self.keys[index] ~= nil 112 | end 113 | 114 | function IndexedMinPQ:size() 115 | return self.N 116 | end 117 | 118 | function IndexedMinPQ:isEmpty() 119 | return self.N == 0 120 | end 121 | 122 | return IndexedMinPQ 123 | 124 | -------------------------------------------------------------------------------- /src/luagraphs/data/MinPQ.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 26/7/2017 5 | -- Time: 10:05 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local MinPQ = {} 10 | MinPQ.__index = MinPQ 11 | 12 | function MinPQ.create(comparator) 13 | local s = {} 14 | setmetatable(s, MinPQ) 15 | 16 | if comparator == nil then 17 | comparator = function(a1, a2) return a1 - a2 end 18 | end 19 | 20 | 21 | s.a = {} 22 | s.N = 0 23 | s.comparator = comparator 24 | return s 25 | end 26 | 27 | function MinPQ:add(item) 28 | self.N = self.N + 1 29 | self.a[self.N] = item 30 | 31 | self:swim(self.N) 32 | end 33 | 34 | function MinPQ:delMin() 35 | if self.N == 0 then 36 | return nil 37 | end 38 | 39 | local item = self.a[1] 40 | 41 | self:exchange(self.a, 1, self.N) 42 | self.N = self.N - 1 43 | self:sink(1) 44 | 45 | return item 46 | end 47 | 48 | function MinPQ:sink(k) 49 | while k * 2 <= self.N do 50 | local child = k * 2 51 | if child < self.N and self:less(self.a[child+1], self.a[child]) then 52 | child = child + 1 53 | end 54 | if self:less(self.a[child], self.a[k]) then 55 | self:exchange(self.a, child, k) 56 | k = child 57 | else 58 | break 59 | end 60 | end 61 | 62 | end 63 | 64 | function MinPQ:size() 65 | return self.N 66 | end 67 | 68 | function MinPQ:isEmpty() 69 | return self.N == 0 70 | end 71 | 72 | function MinPQ:swim(k) 73 | while k > 1 do 74 | local parent = math.floor(k / 2) 75 | if self:less(self.a[k], self.a[parent]) then 76 | self:exchange(self.a, k, parent) 77 | else 78 | break 79 | end 80 | end 81 | end 82 | 83 | function MinPQ:less(a1, a2) 84 | return self.comparator(a1, a2) < 0 85 | end 86 | 87 | function MinPQ:exchange(a, i, j) 88 | local temp = a[i] 89 | a[i] = a[j] 90 | a[j] = temp 91 | end 92 | 93 | return MinPQ 94 | 95 | -------------------------------------------------------------------------------- /src/luagraphs/data/UnionFind.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 26/7/2017 5 | -- Time: 9:34 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local UnionFind = {} 10 | UnionFind.__index = UnionFind 11 | 12 | function UnionFind.create(V) 13 | local s = {} 14 | setmetatable(s, UnionFind) 15 | 16 | s.id = {} 17 | s.count = {} 18 | for v=0, V-1 do 19 | s.id[v] = v 20 | s.count[v] = 1 21 | end 22 | return s 23 | end 24 | 25 | function UnionFind.createFromVertexList(vertices) 26 | local s = {} 27 | setmetatable(s, UnionFind) 28 | 29 | s.id = {} 30 | s.count = {} 31 | for i=0, vertices:size()-1 do 32 | local v = vertices:get(i) 33 | s.id[v] = v 34 | s.count[v] = 1 35 | end 36 | return s 37 | end 38 | 39 | function UnionFind:root(v) 40 | local x = v 41 | while self.id[x] ~= x do 42 | x = self.id[x] 43 | self.id[x] = self.id[self.id[x]] 44 | end 45 | return x 46 | end 47 | 48 | function UnionFind:union(v, w) 49 | local v_root = self:root(v) 50 | local w_root = self:root(w) 51 | 52 | if v_root ~= w_root then 53 | if self.count[v_root] > self.count[w_root] then 54 | self.id[w_root] = v_root 55 | self.count[v_root] = self.count[w_root] + self.count[v_root] 56 | else 57 | self.id[v_root] = w_root 58 | self.count[w_root] = self.count[w_root] + self.count[v_root] 59 | end 60 | end 61 | 62 | end 63 | 64 | function UnionFind:connected(v, w) 65 | return self:root(v) == self:root(w) 66 | end 67 | 68 | return UnionFind 69 | 70 | -------------------------------------------------------------------------------- /src/luagraphs/data/graph.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 26/6/2017 5 | -- Time: 12:48 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local graph = {} 10 | 11 | graph.__index = graph 12 | 13 | graph.Edge = {} 14 | graph.Edge.__index = graph.Edge 15 | 16 | function graph.Edge.create(v, w, weight) 17 | local s = {} 18 | setmetatable(s, graph.Edge) 19 | 20 | if weight == nil then 21 | weight = 1.0 22 | end 23 | 24 | s.v = v 25 | s.w = w 26 | s.weight = weight 27 | 28 | return s 29 | end 30 | 31 | function graph.Edge:from() 32 | return self.v 33 | end 34 | 35 | function graph.Edge:to() 36 | return self.w; 37 | end 38 | 39 | function graph.Edge:either() 40 | return self.v 41 | end 42 | 43 | function graph.Edge:other(x) 44 | if x == self.v then 45 | return self.w 46 | else 47 | return self.v 48 | end 49 | 50 | end 51 | 52 | function graph.create(V, directed) 53 | local g = {} 54 | setmetatable(g, graph) 55 | 56 | if directed == nil then 57 | directed = false 58 | end 59 | 60 | g.vertexList = require('luagraphs.data.list').create() 61 | g.adjList = {} 62 | for v = 0,V-1 do 63 | g.vertexList:add(v) 64 | g.adjList[v] = require('luagraphs.data.list').create() 65 | end 66 | g.directed = directed 67 | 68 | return g 69 | end 70 | 71 | function graph:vertexCount() 72 | return self.vertexList:size() 73 | end 74 | 75 | function graph:vertices() 76 | return self.vertexList 77 | end 78 | 79 | function graph.createFromVertexList(vertices, directed) 80 | local g = {} 81 | setmetatable(g, graph) 82 | 83 | if directed == nil then 84 | directed = false 85 | end 86 | 87 | g.vertexList = vertices 88 | g.adjList = {} 89 | for i = 0,g.vertexList:size()-1 do 90 | local v = g.vertexList:get(i) 91 | g.adjList[v] = require('luagraphs.data.list').create() 92 | end 93 | g.directed = directed 94 | 95 | return g 96 | end 97 | 98 | function graph:addVertexIfNotExists(v) 99 | if self.vertexList:contains(v) then 100 | return false 101 | else 102 | self.vertexList:add(v) 103 | self.adjList[v] = require('luagraphs.data.list').create() 104 | return true 105 | end 106 | end 107 | 108 | function graph:removeVertex(v) 109 | if self.vertexList:contains(v) then 110 | self.vertexList:remove(v) 111 | self.adjList[v] = nil 112 | for i=0,self.vertexList:size()-1 do 113 | local w = self.vertexList:get(i) 114 | local adj_w = self.adjList[w] 115 | for k = 0,adj_w:size()-1 do 116 | local e = adj_w:get(k) 117 | if e:other(w) == v then 118 | adj_w:removeAt(k) 119 | break 120 | end 121 | 122 | end 123 | 124 | end 125 | 126 | end 127 | end 128 | 129 | function graph:containsVertex(v) 130 | return self.vertexList:contains(v) 131 | end 132 | 133 | function graph:adj(v) 134 | return self.adjList[v] 135 | end 136 | 137 | function graph:addEdge(v, w, weight) 138 | local e = graph.Edge.create(v, w, weight) 139 | self:addVertexIfNotExists(v) 140 | self:addVertexIfNotExists(w) 141 | if self.directed then 142 | self.adjList[e:from()]:add(e) 143 | else 144 | self.adjList[e:from()]:add(e) 145 | self.adjList[e:to()]:add(e) 146 | end 147 | 148 | end 149 | 150 | function graph:reverse() 151 | local g = graph.createFromVertexList(self.vertexList, self.directed) 152 | for k=0,self:vertexCount()-1 do 153 | local v = self:vertexAt(k) 154 | local adj_v = self:adj(v) 155 | for i=0,adj_v:size()-1 do 156 | local e = adj_v:get(i) 157 | g:addEdge(e:to(), e:from(), e.weight) 158 | end 159 | 160 | end 161 | 162 | return g 163 | end 164 | 165 | function graph:vertexAt(i) 166 | return self.vertexList:get(i) 167 | end 168 | 169 | function graph:edges() 170 | local list = require('luagraphs.data.list').create() 171 | 172 | for i=0,self.vertexList:size()-1 do 173 | local v = self.vertexList:get(i) 174 | local adj_v = self:adj(v) 175 | for i=0,adj_v:size()-1 do 176 | local e = adj_v:get(i) 177 | local w = e:other(v) 178 | if self.directed == true or w > v then 179 | list:add(e) 180 | end 181 | 182 | end 183 | 184 | end 185 | 186 | return list 187 | end 188 | 189 | function graph:hasEdge(v, w) 190 | local adj_v = self:adj(v) 191 | for i=0,adj_v:size()-1 do 192 | local e = adj_v:get(i) 193 | if e:to() == w then 194 | return true 195 | end 196 | end 197 | return false 198 | end 199 | 200 | return graph 201 | 202 | -------------------------------------------------------------------------------- /src/luagraphs/data/list.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 9/7/2017 5 | -- Time: 10:31 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | local list = {} 9 | 10 | list.ArrayList = {} 11 | list.ArrayList.__index = list.ArrayList 12 | 13 | function list.ArrayList.create() 14 | local s = {} 15 | setmetatable(s, list.ArrayList) 16 | 17 | s.a = { nil } 18 | s.aLen = 1 19 | s.N = 0 20 | return s 21 | end 22 | 23 | function list.ArrayList.createWith(a, aLen, N) 24 | local s = {} 25 | setmetatable(s, list.ArrayList) 26 | 27 | s.a = a 28 | s.aLen = aLen 29 | s.N = N 30 | return s 31 | end 32 | 33 | function list.create() 34 | return list.ArrayList.create() 35 | end 36 | 37 | function list.createWith(a, aLen, N) 38 | return list.ArrayList.createWith(a, aLen, N) 39 | end 40 | 41 | function list.ArrayList:makeCopy() 42 | local temp = {} 43 | for key,val in pairs(self.a) do 44 | temp[key] = val 45 | end 46 | return list.ArrayList.createWith(temp, self.aLen, self.N) 47 | end 48 | 49 | function list.ArrayList:add(value) 50 | self.a[self.N] = value 51 | self.N = self.N + 1 52 | if self.N == self.aLen then 53 | self:resize(self.aLen * 2) 54 | end 55 | end 56 | 57 | function list.ArrayList:set(index,value) 58 | self.a[index] = value 59 | end 60 | 61 | function list.ArrayList:get(index) 62 | local temp = self.a[index] 63 | return temp 64 | end 65 | 66 | function list.ArrayList:removeAt(index) 67 | if index == self.N-1 then 68 | self.N = self.N - 1 69 | return 70 | end 71 | for i = index+1,self.N-1 do 72 | self.a[i-1]=self.a[i] 73 | end 74 | self.N = self.N - 1 75 | if self.N == math.floor(self.aLen / 4) then 76 | self:resize(math.floor(self.aLen / 2)) 77 | end 78 | 79 | end 80 | 81 | function list.ArrayList:indexOf(value) 82 | if self.N == 0 then 83 | return -1 84 | end 85 | for i=0,self.N-1 do 86 | if self.a[i] == value then 87 | return i 88 | end 89 | end 90 | return -1 91 | end 92 | 93 | function list.ArrayList:contains(value) 94 | return self:indexOf(value) ~= -1 95 | end 96 | 97 | function list.ArrayList:remove(value) 98 | local index = self:indexOf(value) 99 | self:removeAt(index) 100 | end 101 | 102 | function list.ArrayList:resize(newSize) 103 | local temp = {} 104 | for i = 0,(newSize-1) do 105 | temp[i] = self.a[i] 106 | end 107 | 108 | self.a = temp 109 | self.aLen = newSize 110 | end 111 | 112 | function list.ArrayList:size() 113 | return self.N 114 | end 115 | 116 | function list.ArrayList:isEmpty() 117 | return self.N == 0 118 | end 119 | 120 | function list.ArrayList:enumerate() 121 | local temp = {} 122 | for i = 0,(self.N-1) do 123 | temp[i] = self.a[i] 124 | end 125 | return temp 126 | end 127 | 128 | function list.ArrayList:isSortedAscendingly(comparator) 129 | for i=0,(self:size()-2) do 130 | if comparator(a:get(i), a:get(i+1)) > 0 then 131 | return false 132 | end 133 | 134 | end 135 | return true 136 | end 137 | 138 | function list.ArrayList:isSortedDescendingly(comparator) 139 | for i=0,(self:size()-2) do 140 | if comparator(a:get(i), a:get(i+1)) < 0 then 141 | return false 142 | end 143 | 144 | end 145 | return true 146 | end 147 | 148 | return list 149 | 150 | -------------------------------------------------------------------------------- /src/luagraphs/data/network.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 20/8/2017 5 | -- Time: 3:02 PM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local network = {} 10 | network.__index = network 11 | 12 | network.FlowEdge = {} 13 | network.FlowEdge.__index = network.FlowEdge 14 | 15 | network.FlowNetwork = {} 16 | network.FlowNetwork.__index = network.FlowNetwork 17 | 18 | function network.FlowEdge.create(v, w, capacity) 19 | local s = {} 20 | setmetatable(s, network.FlowEdge) 21 | 22 | s.v = v 23 | s.w = w 24 | s.capacity = capacity 25 | s.flow = 0 26 | return s 27 | end 28 | 29 | function network.FlowNetwork.create(V) 30 | local s = {} 31 | setmetatable(s, network.FlowNetwork) 32 | 33 | s.vertexList = require('luagraphs.data.list').create() 34 | s.adjList = {} 35 | for v = 0,V-1 do 36 | s.vertexList:add(v) 37 | s.adjList[v] = require('luagraphs.data.list').create() 38 | end 39 | return s 40 | end 41 | 42 | function network.FlowNetwork:vertexCount() 43 | return self.vertexList:size() 44 | end 45 | 46 | function network.FlowNetwork:vertexAt(i) 47 | return self.vertexList:get(i) 48 | end 49 | 50 | function network.FlowNetwork:addVertexIfNotExists(v) 51 | if self.vertexList:contains(v) then 52 | return false 53 | else 54 | self.vertexList:add(v) 55 | self.adjList[v] = require('luagraphs.data.list').create() 56 | return true 57 | end 58 | end 59 | 60 | function network.FlowNetwork:removeVertex(v) 61 | if self.vertexList:contains(v) then 62 | self.vertexList:remove(v) 63 | self.adjList[v] = nil 64 | end 65 | end 66 | 67 | function network.FlowNetwork:containsVertex(v) 68 | return self.vertexList:contains(v) 69 | end 70 | 71 | function network.FlowNetwork:vertices() 72 | return self.vertexList 73 | end 74 | 75 | function network.FlowNetwork:addEdge(v, w, capacity) 76 | local e = network.FlowEdge.create(v, w, capacity) 77 | self.adjList[e.v]:add(e) 78 | self.adjList[e.w]:add(e) 79 | end 80 | 81 | function network.FlowNetwork:adj(v) 82 | return self.adjList[v] 83 | end 84 | 85 | function network.FlowEdge:residualCapacityTo(x) 86 | if x == self.v then 87 | return self.flow 88 | else 89 | return self.capacity - self.flow 90 | end 91 | end 92 | 93 | function network.FlowEdge:other(x) 94 | if x == self.v then 95 | return self.w 96 | else 97 | return self.v 98 | end 99 | 100 | 101 | end 102 | 103 | function network.FlowEdge:toString() 104 | return self.v .. ' to ' .. self.w .. ' with capacity ' .. self.capacity 105 | end 106 | 107 | function network.FlowEdge:addResidualFlowTo(x, inc) 108 | if x == self.v then 109 | self.flow = self.flow - inc 110 | else 111 | self.flow = self.flow + inc 112 | end 113 | 114 | end 115 | 116 | return network 117 | 118 | -------------------------------------------------------------------------------- /src/luagraphs/data/queue.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 9/7/2017 5 | -- Time: 10:37 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local queue = {} 10 | queue.__index = queue 11 | 12 | queue.Node = {} 13 | queue.Node.__index = queue.Node 14 | 15 | function queue.Node.create(value) 16 | local s = {} 17 | setmetatable(s, queue.Node) 18 | 19 | s.value = value 20 | s.next = nil 21 | return s 22 | end 23 | 24 | function queue.create() 25 | local s = {} 26 | setmetatable(s, queue) 27 | 28 | s.first = nil 29 | s.last = nil 30 | s.N = 0 31 | 32 | return s 33 | end 34 | 35 | function queue:enqueue(value) 36 | local oldLast = self.last 37 | self.last = queue.Node.create(value) 38 | if oldLast ~= nil then 39 | oldLast.next = self.last 40 | end 41 | if self.first == nil then 42 | self.first = self.last 43 | end 44 | 45 | self.N = self.N + 1 46 | end 47 | 48 | function queue:dequeue() 49 | local oldFirst = self.first 50 | if oldFirst == nil then 51 | return nil 52 | end 53 | 54 | local value = oldFirst.value 55 | self.first = oldFirst.next 56 | self.N = self.N - 1 57 | if self.first == nil then 58 | self.last = nil 59 | end 60 | return value 61 | end 62 | 63 | function queue:size() 64 | return self.N 65 | end 66 | 67 | function queue:isEmpty() 68 | return self.N == 0 69 | end 70 | 71 | return queue 72 | 73 | -------------------------------------------------------------------------------- /src/luagraphs/data/stack.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 8/7/2017 5 | -- Time: 9:23 PM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local stack = {} 10 | stack.__index = stack 11 | 12 | stack.Node = {} 13 | stack.Node.__index = stack.Node 14 | 15 | function stack.Node.create(value) 16 | local s = {} 17 | setmetatable(s, stack.Node) 18 | 19 | s.value = value 20 | s.next = nil 21 | 22 | return s 23 | end 24 | 25 | function stack.create() 26 | local s = {}; 27 | setmetatable(s, stack) 28 | 29 | s.first = nil 30 | s.N = 0 31 | 32 | return s 33 | end 34 | 35 | function stack:push(val) 36 | local oldFirst = self.first 37 | self.first = stack.Node.create(val) 38 | self.first.next = oldFirst 39 | self.N = self.N + 1 40 | end 41 | 42 | function stack:size() 43 | return self.N 44 | end 45 | 46 | function stack:isEmpty() 47 | return self.N == 0 48 | end 49 | 50 | function stack:pop() 51 | if self.N == 0 then 52 | return nil 53 | end 54 | 55 | self.N = self.N - 1 56 | 57 | local oldFirst = self.first 58 | 59 | local val = oldFirst.value 60 | self.first = oldFirst.next 61 | 62 | return val 63 | end 64 | 65 | function stack:toList() 66 | local result = require('luagraphs.data.list').create() 67 | local x = self.first 68 | while x ~= nil do 69 | result:add(x.value) 70 | x = x.next 71 | end 72 | return result 73 | end 74 | 75 | return stack 76 | -------------------------------------------------------------------------------- /src/luagraphs/flow/FordFulkerson.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 11/9/2017 5 | -- Time: 8:35 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local FordFulkerson = {} 10 | FordFulkerson.__index = FordFulkerson 11 | FordFulkerson.MAX_VALUE = 100000000000.0 12 | 13 | function FordFulkerson.create() 14 | local s = {} 15 | setmetatable(s, FordFulkerson) 16 | 17 | s.value = 0 18 | s.edgeTo = {} 19 | s.source = -1 20 | s.target = -1 21 | s.network = nil 22 | s.marked = {} 23 | return s 24 | end 25 | 26 | function FordFulkerson:run(network, s, t) 27 | self.value = 0 28 | self.edgeTo = {} 29 | self.source = s 30 | self.target = t 31 | self.network = network 32 | self.marked = {} 33 | 34 | while self:hasPath() do 35 | local maxFlow = FordFulkerson.MAX_VALUE 36 | local x = self.target 37 | while x ~= self.source do 38 | local e = self.edgeTo[x] 39 | maxFlow = math.min(maxFlow, e:residualCapacityTo(x)) 40 | x = e:other(x) 41 | end 42 | local x = self.target 43 | while x ~= self.source do 44 | local e = self.edgeTo[x] 45 | e:addResidualFlowTo(x, maxFlow) 46 | x = e:other(x) 47 | end 48 | 49 | self.value = self.value + maxFlow 50 | end 51 | return self.value 52 | end 53 | 54 | function FordFulkerson:hasPath() 55 | self.edgeTo = {} 56 | self.marked = {} 57 | for i = 0,self.network:vertexCount()-1 do 58 | local v = self.network:vertexAt(i) 59 | self.marked[v] = false 60 | end 61 | 62 | local queue = require('luagraphs.data.queue').create() 63 | queue:enqueue(self.source) 64 | while queue:isEmpty() == false do 65 | local x = queue:dequeue() 66 | self.marked[x] = true 67 | if x == self.target then 68 | return true 69 | end 70 | 71 | local adj_x = self.network:adj(x) 72 | for i = 0,adj_x:size()-1 do 73 | local e = adj_x:get(i) 74 | local w = e:other(x) 75 | if self.marked[w] == false and e:residualCapacityTo(w) > 0 then 76 | self.edgeTo[w] = e 77 | queue:enqueue(w) 78 | end 79 | 80 | end 81 | 82 | end 83 | 84 | return false 85 | end 86 | 87 | function FordFulkerson:minCuts() 88 | local result = require('luagraphs.data.list').create() 89 | for i = 0,self.network:vertexCount()-1 do 90 | local v = self.network:vertexAt(i) 91 | local adj_v = self.network:adj(v) 92 | for i = 0,adj_v:size()-1 do 93 | local e = adj_v:get(i) 94 | if e.v == v and e:residualCapacityTo(e:other(v)) == 0 then 95 | result:add(e) 96 | end 97 | end 98 | end 99 | return result 100 | end 101 | 102 | return FordFulkerson 103 | 104 | -------------------------------------------------------------------------------- /src/luagraphs/mst/EagerPrimMST.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 28/7/2017 5 | -- Time: 10:11 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local EagerPrimMST = {} 10 | EagerPrimMST.__index = EagerPrimMST 11 | 12 | function EagerPrimMST.create() 13 | local s = {} 14 | setmetatable(s, EagerPrimMST) 15 | 16 | s.path = require('luagraphs.data.list').create() 17 | s.marked = {} 18 | 19 | return s 20 | end 21 | 22 | function EagerPrimMST:run(G) 23 | self.path = require('luagraphs.data.list').create() 24 | self.marked = {} 25 | 26 | for i = 0, G:vertexCount()-1 do 27 | local v = G:vertexAt(i) 28 | self.marked[v] = false 29 | end 30 | 31 | local pq = require('luagraphs.data.IndexedMinPQ').create(function(e1, e2) return e1.weight - e2.weight end) 32 | self:visit(G, 0, pq) 33 | 34 | while self.path:size() < G:vertexCount() -1 and pq:isEmpty() == false do 35 | local w = pq:minIndex() 36 | local e = pq:delMin() 37 | self.path:add(e) 38 | self:visit(G, w, pq) 39 | end 40 | end 41 | 42 | function EagerPrimMST:visit(G, v, pq) 43 | self.marked[v] = true 44 | local adj_v = G:adj(v) 45 | for i=0,adj_v:size()-1 do 46 | local e = adj_v:get(i) 47 | local w = e:other(v) 48 | if self.marked[w] == false then 49 | if pq:contains(w) then 50 | pq:decreaseKey(w, e) 51 | else 52 | pq:add(w, e) 53 | end 54 | end 55 | end 56 | 57 | end 58 | 59 | return EagerPrimMST 60 | 61 | -------------------------------------------------------------------------------- /src/luagraphs/mst/KruskalMST.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 26/7/2017 5 | -- Time: 9:29 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local KruskalMST = {} 10 | KruskalMST.__index = KruskalMST 11 | 12 | function KruskalMST.create() 13 | local s = {} 14 | setmetatable(s, KruskalMST) 15 | 16 | s.marked = {} 17 | s.path = require('luagraphs.data.list').create() 18 | return s 19 | end 20 | 21 | function KruskalMST:run(G) 22 | self.marked = {} 23 | self.path = require('luagraphs.data.list').create() 24 | local pq = require('luagraphs.data.MinPQ').create(function(e1, e2) 25 | return e1.weight - e2.weight 26 | end) 27 | 28 | for i = 0, G:vertexCount()-1 do 29 | local v = G:vertexAt(i) 30 | self.marked[v] = false 31 | end 32 | 33 | local edges = G:edges() 34 | for i = 0, edges:size()-1 do 35 | local e = edges:get(i) 36 | pq:add(e) 37 | end 38 | 39 | local uf = require('luagraphs.data.UnionFind').createFromVertexList(G:vertices()) 40 | while pq:isEmpty() == false and self.path:size() < G:vertexCount() - 1 do 41 | local e = pq:delMin() 42 | local v = e:either() 43 | local w = e:other(v) 44 | if uf:connected(w, v) == false then 45 | uf:union(w, v) 46 | self.path:add(e) 47 | end 48 | end 49 | end 50 | 51 | return KruskalMST 52 | 53 | -------------------------------------------------------------------------------- /src/luagraphs/mst/PrimMST.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 26/7/2017 5 | -- Time: 9:29 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local PrimMST = {} 10 | PrimMST.__index = PrimMST 11 | 12 | function PrimMST.create() 13 | local s = {} 14 | setmetatable(s, PrimMST) 15 | 16 | s.marked = {} 17 | s.path = require('luagraphs.data.list').create() 18 | return s 19 | end 20 | 21 | function PrimMST:run(G) 22 | self.marked = {} 23 | self.path = require('luagraphs.data.list').create() 24 | local pq = require('luagraphs.data.MinPQ').create(function(e1, e2) 25 | return e1.weight - e2.weight 26 | end) 27 | 28 | for i = 0, G:vertexCount()-1 do 29 | local v = G:vertexAt(i) 30 | self.marked[v] = false 31 | end 32 | 33 | local source = G:vertexAt(0) 34 | local adj_s = G:adj(source) 35 | self.marked[source] = true 36 | for i = 0, adj_s:size()-1 do 37 | local e = adj_s:get(i) 38 | pq:add(e) 39 | end 40 | 41 | while pq:isEmpty() == false and self.path:size() < G:vertexCount() - 1 do 42 | local e = pq:delMin() 43 | local v = e:either() 44 | local w = e:other(v) 45 | if self.marked[v] == false or self.marked[w] == false then 46 | self.path:add(e) 47 | 48 | if self.marked[v] == false then 49 | self.marked[v] = true 50 | local adj_v = G:adj(v) 51 | for i = 0, adj_v:size()-1 do 52 | local e_v = adj_v:get(i) 53 | pq:add(e_v) 54 | end 55 | end 56 | 57 | if self.marked[w] == false then 58 | self.marked[w] = true 59 | local adj_w = G:adj(w) 60 | for i = 0, adj_w:size()-1 do 61 | local e_w = adj_w:get(i) 62 | pq:add(e_w) 63 | end 64 | end 65 | end 66 | end 67 | end 68 | 69 | return PrimMST 70 | 71 | -------------------------------------------------------------------------------- /src/luagraphs/search/BreadthFirstSearch.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 9/7/2017 5 | -- Time: 10:35 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local BreadthFirstSearch = {} 10 | BreadthFirstSearch.__index = BreadthFirstSearch 11 | 12 | function BreadthFirstSearch.create() 13 | local s = {} 14 | setmetatable(s, BreadthFirstSearch) 15 | 16 | s.marked = {} 17 | s.pathTo = {} 18 | return s 19 | end 20 | 21 | function BreadthFirstSearch:run(G, s) 22 | self.s = s 23 | 24 | for i = 0, G:vertexCount()-1 do 25 | local v = G:vertexAt(i) 26 | self.marked[v] = false 27 | self.pathTo[v] = -1 28 | end 29 | 30 | local queue = require('luagraphs.data.queue').create() 31 | 32 | queue:enqueue(s) 33 | while queue:isEmpty() == false do 34 | local v = queue:dequeue() 35 | self.marked[v] = true 36 | local adj_v = G:adj(v) 37 | for i = 0, adj_v:size()-1 do 38 | local e = adj_v:get(i) 39 | local w = e:other(v) 40 | if self.marked[w] == false then 41 | self.pathTo[w] = v 42 | queue:enqueue(w) 43 | end 44 | end 45 | 46 | end 47 | end 48 | 49 | 50 | function BreadthFirstSearch:hasPathTo(v) 51 | return self.marked[v] 52 | end 53 | 54 | function BreadthFirstSearch:getPathTo(v) 55 | local stack = require('luagraphs.data.stack') 56 | local path = stack.create() 57 | local x = v 58 | while x ~= self.s do 59 | path:push(x) 60 | x = self.pathTo[x] 61 | end 62 | path:push(self.s) 63 | return path 64 | end 65 | 66 | 67 | return BreadthFirstSearch 68 | -------------------------------------------------------------------------------- /src/luagraphs/search/DepthFirstSearch.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 6/7/2017 5 | -- Time: 3:06 PM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local DepthFirstSearch = {}; 10 | DepthFirstSearch.__index = DepthFirstSearch 11 | 12 | function DepthFirstSearch.create() 13 | local s = {} 14 | setmetatable(s, DepthFirstSearch) 15 | 16 | s.marked = {} 17 | s.pathTo = {} 18 | 19 | return s 20 | end 21 | 22 | function DepthFirstSearch:run(G, s) 23 | self.s = s 24 | for i = 0,G:vertexCount()-1 do 25 | local v = G:vertexAt(i) 26 | self.marked[v] = false 27 | self.pathTo[v] = -1 28 | end 29 | 30 | self:dfs(G, s) 31 | end 32 | 33 | function DepthFirstSearch:dfs(G, v) 34 | self.marked[v] = true 35 | local adj_v = G:adj(v) 36 | for i = 0,adj_v:size()-1 do 37 | local e = adj_v:get(i) 38 | local w = e:other(v) 39 | if self.marked[w] == false then 40 | self.pathTo[w] = v 41 | self:dfs(G, w) 42 | end 43 | end 44 | end 45 | 46 | function DepthFirstSearch:hasPathTo(v) 47 | return self.marked[v] 48 | end 49 | 50 | function DepthFirstSearch:getPathTo(v) 51 | local stack = require('luagraphs.data.stack') 52 | local path = stack.create() 53 | local x = v 54 | while x ~= self.s do 55 | path:push(x) 56 | x = self.pathTo[x] 57 | end 58 | path:push(self.s) 59 | return path 60 | end 61 | 62 | return DepthFirstSearch 63 | 64 | -------------------------------------------------------------------------------- /src/luagraphs/shortest_paths/BellmanFord.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 31/7/2017 5 | -- Time: 9:36 PM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local BellmanFord = {} 10 | BellmanFord.__index = BellmanFord 11 | BellmanFord.MAX_VALUE = 100000000000.0 12 | 13 | function BellmanFord.create() 14 | local s = {} 15 | setmetatable(s, BellmanFord) 16 | 17 | s.edgeTo = {} 18 | s.source = nil 19 | s.costs = {} 20 | s.negativeCycle = false 21 | return s 22 | end 23 | 24 | function BellmanFord:run(g, s) 25 | self.source = s 26 | self.edgeTo = {} 27 | self.costs = {} 28 | self.negativeCycle = false 29 | 30 | for i = 0, g:vertexCount()-1 do 31 | local v = g:vertexAt(i) 32 | self.edgeTo[v] = -1 33 | self.costs[v] = BellmanFord.MAX_VALUE 34 | end 35 | 36 | self.costs[s] = 0 37 | 38 | for i = 0,g:vertexCount()-1 do 39 | for k = 0, g:vertexCount()-1 do 40 | local v = g:vertexAt(k) 41 | local adj_v = g:adj(v) 42 | for j = 0, adj_v:size()-1 do 43 | local e = adj_v:get(j) 44 | self:relax(g, e) 45 | end 46 | end 47 | end 48 | 49 | for i = 0, g:vertexCount()-1 do 50 | local v = g:vertexAt(i) 51 | local adj_v = g:adj(v) 52 | for j = 0, adj_v:size()-1 do 53 | local e = adj_v:get(j) 54 | if self:relax(g, e) then 55 | self.negativeCycle = true 56 | end 57 | 58 | end 59 | 60 | end 61 | 62 | end 63 | 64 | function BellmanFord:relax(g, e) 65 | local w = e:to() 66 | local v = e:from() 67 | if self.costs[w] > self.costs[v] + e.weight then 68 | self.costs[w] = self.costs[v] + e.weight 69 | self.edgeTo[w] = e 70 | end 71 | end 72 | 73 | 74 | function BellmanFord:hasPathTo(v) 75 | return self.costs[v] < BellmanFord.MAX_VALUE 76 | end 77 | 78 | function BellmanFord:hasNegativeCycle() 79 | return self.negativeCycle 80 | end 81 | 82 | function BellmanFord:getPathLength(v) 83 | return self.costs[v] 84 | end 85 | 86 | function BellmanFord:getPathTo(v) 87 | local stack = require('luagraphs.data.stack').create() 88 | local x = v 89 | while x ~= self.source do 90 | local e = self.edgeTo[x] 91 | stack:push(e) 92 | x = e:other(x) 93 | end 94 | return stack:toList() 95 | end 96 | 97 | 98 | return BellmanFord 99 | 100 | -------------------------------------------------------------------------------- /src/luagraphs/shortest_paths/Dijkstra.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 28/7/2017 5 | -- Time: 10:30 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local Dijkstra = {} 10 | Dijkstra.__index = Dijkstra 11 | Dijkstra.MAX_VALUE = 100000000000.0 12 | 13 | function Dijkstra.create() 14 | local s = {} 15 | setmetatable(s, Dijkstra) 16 | 17 | s.edgeTo = {} 18 | s.cost = {} 19 | s.source = -1 20 | s.marked = {} 21 | return s 22 | end 23 | 24 | function Dijkstra:run(G, s) 25 | self.edgeTo = {} 26 | self.cost = {} 27 | self.marked = {} 28 | self.source = s 29 | 30 | for i = 0, G:vertexCount()-1 do 31 | local v = G:vertexAt(i) 32 | self.marked[v] = false 33 | self.edgeTo[v] = -1 34 | self.cost[v] = Dijkstra.MAX_VALUE 35 | end 36 | 37 | local pq = require('luagraphs.data.IndexedMinPQ').create() 38 | self.cost[s] = 0 39 | pq:add(s, self.cost[s]) 40 | 41 | while pq:isEmpty() == false do 42 | local v = pq:minIndex() 43 | pq:delMin() 44 | self.marked[v] = true 45 | local adj_v = G:adj(v) 46 | for i=0,adj_v:size()-1 do 47 | local e = adj_v:get(i) 48 | self:relax(G, e, pq) 49 | end 50 | 51 | end 52 | end 53 | 54 | function Dijkstra:relax(G, e, pq) 55 | local v = e:from() 56 | local w = e:to() 57 | 58 | if self.marked[w] then 59 | return 60 | end 61 | 62 | if self.cost[w] > self.cost[v] + e.weight then 63 | self.cost[w] = self.cost[v] + e.weight 64 | self.edgeTo[w] = e 65 | if pq:contains(w) then 66 | pq:decreaseKey(w, self.cost[w]) 67 | else 68 | pq:add(w, self.cost[w]) 69 | end 70 | end 71 | 72 | end 73 | 74 | function Dijkstra:hasPathTo(v) 75 | return self.marked[v] 76 | end 77 | 78 | function Dijkstra:getPathLength(v) 79 | return self.cost[v] 80 | end 81 | 82 | function Dijkstra:getPathTo(v) 83 | local stack = require('luagraphs.data.stack').create() 84 | local x = v 85 | while x ~= self.source do 86 | local e = self.edgeTo[x] 87 | stack:push(e) 88 | x = e:other(x) 89 | end 90 | return stack:toList() 91 | end 92 | 93 | 94 | return Dijkstra 95 | 96 | -------------------------------------------------------------------------------- /src/luagraphs/shortest_paths/TopoSortShortestPath.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 29/7/2017 5 | -- Time: 7:01 PM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local TopoSortShortestPath = {} 10 | TopoSortShortestPath.__index = TopoSortShortestPath 11 | TopoSortShortestPath.MAX_VALUE = 100000000000.0 12 | 13 | function TopoSortShortestPath.create() 14 | local s = {} 15 | setmetatable(s, TopoSortShortestPath) 16 | 17 | s.edgeTo = {} 18 | s.cost = {} 19 | s.source = -1 20 | return s 21 | end 22 | 23 | function TopoSortShortestPath:run(G, s) 24 | self.edgeTo = {} 25 | self.cost = {} 26 | self.source = s 27 | 28 | for i = 0, G:vertexCount()-1 do 29 | local v = G:vertexAt(i) 30 | self.edgeTo[v] = -1 31 | self.cost[v] = TopoSortShortestPath.MAX_VALUE 32 | end 33 | 34 | self.cost[s] = 0 35 | 36 | local topoSort = require('luagraphs.sort.TopologicalSort').create() 37 | topoSort:run(G) 38 | local order = topoSort:path() 39 | 40 | for i=0, order:size()-1 do 41 | local v = order:get(i) 42 | local adj_v = G:adj(v) 43 | for j=0, adj_v:size()-1 do 44 | local e = adj_v:get(j) 45 | self:relax(e) 46 | end 47 | end 48 | end 49 | 50 | function TopoSortShortestPath:relax(e) 51 | local v = e:from() 52 | local w = e:to() 53 | 54 | if(self.cost[w] > self.cost[v] + e.weight) then 55 | self.cost[w] = self.cost[v] + e.weight 56 | self.edgeTo[w] = e 57 | end 58 | 59 | end 60 | 61 | function TopoSortShortestPath:hasPathTo(v) 62 | return self.edgeTo[v] ~= -1 63 | end 64 | 65 | function TopoSortShortestPath:getPathLength(v) 66 | return self.cost[v] 67 | end 68 | 69 | function TopoSortShortestPath:getPathTo(v) 70 | local stack = require('luagraphs.data.stack').create() 71 | local x = v 72 | while x ~= self.source do 73 | local e = self.edgeTo[x] 74 | stack:push(e) 75 | x = e:other(x) 76 | end 77 | return stack:toList() 78 | end 79 | 80 | 81 | return TopoSortShortestPath 82 | 83 | -------------------------------------------------------------------------------- /src/luagraphs/sort/TopologicalSort.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Created by IntelliJ IDEA. 3 | -- User: chen0 4 | -- Date: 11/7/2017 5 | -- Time: 8:42 AM 6 | -- To change this template use File | Settings | File Templates. 7 | -- 8 | 9 | local TopologicalSort = {} 10 | TopologicalSort.__index = TopologicalSort 11 | 12 | function TopologicalSort.create() 13 | local s = {} 14 | setmetatable(s, TopologicalSort) 15 | 16 | s.reversedPostOrder = require('luagraphs.data.stack').create() 17 | s.marked = {} 18 | 19 | return s 20 | end 21 | 22 | function TopologicalSort:run(G) 23 | 24 | for i = 0,G:vertexCount()-1 do 25 | local v = G:vertexAt(i) 26 | self.marked[v] = false 27 | end 28 | 29 | for i = 0, G:vertexCount()-1 do 30 | local v = G:vertexAt(i) 31 | if self.marked[v] == false then 32 | self:dfs(G, v) 33 | end 34 | end 35 | end 36 | 37 | function TopologicalSort:dfs(G, v) 38 | self.marked[v] = true 39 | 40 | local adj_v = G:adj(v) 41 | 42 | for i = 0, adj_v:size()-1 do 43 | local e = adj_v:get(i) 44 | local w = e:other(v) 45 | if self.marked[w] == false then 46 | self:dfs(G, w) 47 | end 48 | end 49 | 50 | 51 | self.reversedPostOrder:push(v) 52 | end 53 | 54 | function TopologicalSort:path() 55 | return self.reversedPostOrder:toList() 56 | end 57 | 58 | return TopologicalSort 59 | 60 | --------------------------------------------------------------------------------