0.0
No release in over a year
Native implementation of Dijkstra algorithm for finding the shortest path between two vertices in a large, sparse graphs. Underlying algorithm is implemented in C using a priority queue. Edges are represented using linked lists rather than an adjacency matrix to reduce memory footprint when operating on very large graphs where the average number of edges between nodes is relatively small (e.g. < 1/10 the number of nodes). See https://en.wikipedia.org/wiki/Dijkstra's_algorithm for additional information.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies
 Project Readme

Dijkstra (Fast!)

Status

Gem Version Build Status Code Climate Test Coverage MIT License

Description

Dijkstra is a commonly used algorithm for finding the shortest path/distance between two items in an interconnected collection of items (such as a graph or network).

Features

  • Native implementation of Dijkstra's algorithm intended for use on large, typically sparse graphs.
  • Allows for calculating shortest distance without requiring all nodes/edges to be produced. (In many applications doing this can be more expensive than Dijkstra's algorithm itself - or even impractical.)
  • Can be used in one of three ways:
    • Method 1: Use an instance of DijkstraFast::Graph by adding edges to it.
    • Method 2: Add shortest_path and shortest_distance methods to an existing class by including the DijkstraFast::ShortestPath module.
    • Method 3: Call DijkstraFast::ShortestPath.shortest_path or DijkstraFast::ShortestPath.shortest_distance directly when the source and dest objects know how to find "connected" items via some method.

Installation

gem install dijkstra_fast

Requirements

  • Ruby 3.0 or higher

Usage

Method 1: Use DijkstraFast::Graph

graph = DijkstraFast::Graph.new
graph.add("A", "B", distance: 5)
graph.add("A", "C", distance: 8)
graph.add("B", "C", distance: 2)
distance, path = graph.shortest_path("A", "C")
path

=> ["A", "B", "C"]

distance

=> 7

Method 2: Include DijkstraFast::ShortestPath

class MyNetwork
  include DijkstraFast::ShortestPath

  def connections(source)
    case source
    when "A"
      yield "B", 3
      yield "C", 8
    when "B"
      yield "C" # Default distance 1
    end
  end
end

distance, path = MyNetwork.new.shortest_path("A", "C")
path

=> ["A", "B", "C"]

distance

=> 4

Method 3: Call DijkstraFast.shortest_path or DijkstraFast.shortest_distance

Node = Struct.new(:label) do
  def connections
    case label
    when "A"
      yield Node.new("B"), 5
      yield Node.new("C"), 8
    when "B"
      yield Node.new("C"), 2
    end
  end
end

a = Node.new("A")
b = Node.new("B")
c = Node.new("C")

distance, path = DijkstraFast.shortest_path(a, c)
path.map(&:label)

=> ["A", "B", "C"]

distance

=> 7

Additional Notes

  • When using arbitrary Ruby objects as graph nodes, it is important to ensure that Object#hash and Object#eql? are properly implemented so that two instances which are logically the same will be considered as the same node. Under the hood, this gem creates a bi-directional mapping between nodes and an auto-incrementing integer id so that Ruby objects do not have to be passed into the internals of the native implementation; doing so would risk problems with garbage collection and is otherwise frowned upon when implementing native extensions.
  • All shortest_path and shortest_distance methods provide an optional progress named argument which (when set to anything truthy) will provide progress as the algorithm proceeds. The default implementation uses the progressbar gem, but this is not required.
  • The maximum number of items that can be handled by this implementation is determined by the size of unsigned long which is compiler dependent. On many machines this can be 18,446,744,073,709,551,615 (2^64 – 1). A RuntimeError will be thrown if this is surpassed; if so, congratulations on being bad ass!
  • A priority queue is used within the native Dijkstra implemenation to maintain the next shortest path to consider within the algorithm's main loop. It is possible that switching to a Fibonacci heap might improve performance.

License

MIT. See the LICENSE file.

References

Cormen, Thomas H.; Leiserson, Charles E.; Rivest, Ronald L.; Stein, Clifford (2001). "Section 24.3: Dijkstra's algorithm". Introduction to Algorithms (Second ed.). MIT Press and McGraw–Hill. pp. 595–601. ISBN 0-262-03293-7.

Knuth, D.E. (1977). "A Generalization of Dijkstra's Algorithm". Information Processing Letters. 6 (1): 1–5. doi:10.1016/0020-0190(77)90002-3.