Skip to content

RGL is a framework for graph data structures and algorithms in Ruby.

Notifications You must be signed in to change notification settings

javanthropus/rgl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

92 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

= Ruby Graph Library (RGL)

RGL is a framework for graph data structures and algorithms.

The design of the library is much influenced by the Boost Graph Library (BGL)
which is written in C++ heavily using its template mechanism. Refer to
http://www.boost.org/libs/graph/doc for further links and documentation on graph
data structures and algorithms and the design rationales of BGL.

A comprehensive summary of graph terminology can be found in the the graph
section of the <em>Dictionary of Algorithms and Data Structures</em> at
http://www.nist.gov/dads/HTML/graph.html.

== Design principles

This document concentrates on the special issues of the implementation in
Ruby. The main design goals directly taken from the BGL design are:

* An interface for how the structure of a graph can be accessed using a generic
  interface that hides the details of the graph data structure
  implementation. This interface is defined by the module Graph, which should be
  included in concrete classes.

* A standardized generic interface for traversing graphs (RGL::GraphIterator)

RGL provides some general purpose graph classes that conform to this interface,
but they are not meant to be the *only* graph classes. As in BGL I believe that
the main contribution of the RGL is the formulation of this interface.

The BGL graph interface and graph components are generic in the sense of the C++
Standard Template Library (STL). In Ruby other techniques are available to
express the generic character of the algorithms and data structures mainly using
mixins and iterators. The BGL documentation mentions three means to achieve
genericity:

* Algorithm/Data-Structure Interoperability
* Extension through Function Objects and Visitors
* Element Type Parameterization
* Vertex and Edge Property Multi-Parameterization

The first is easily achieved in RGL using mixins, which of course is not as
efficient than C++ templates (but much more readable :-). The second one is
even more easily implemented using standard iterators with blocks or using the
Stream[http://rgl.rubyforge.org/stream/files/README.html] module. The third one
is no issue since Ruby is dynamically typed: Each object can be a graph
vertex. There is no need for a vertex (or even edge type). In the current
version of RGL properties of vertices are simply attached using hashes. At
first there seems to be not much need for the graph property machinery.

=== Algorithms

The first version of RGL only contains a core set of algorithm patterns:

* Breadth First Search (RGL::BFSIterator)
* Depth First Search (RGL::DFSIterator)

The algorithm patterns by themselves do not compute any meaningful quantities
over graphs, they are merely building blocks for constructing graph
algorithms. The graph algorithms in RGL currently include:

* Topological Sort (RGL::TopsortIterator)
* Connected Components (RGL::Graph#each_connected_component)
* Strongly Connected Components (RGL::Graph#strongly_connected_components)
* Transitive Closure (RGL::Graph#transitive_closure)

=== Data Structures

RGL currently provides two graph classes that implement a generalized adjacency
list and an edge list adaptor.

* RGL::AdjacencyGraph
* RGL::ImplicitGraph

The AdjacencyGraph class is the general purpose *swiss army knife* of graph
classes. It is highly parameterized so that it can be optimized for different
situations: the graph is directed or undirected, allow or disallow parallel
edges, efficient access to just the out-edges, fast vertex insertion and removal
at the cost of extra space overhead, etc.

=== Differences to BGL

The concepts of IncidenceGraph, AdjacencyGraph and VertexListGraph (see
http://www.boost.org/libs/graph/doc/IncidenceGraph.html) are here bundled in the
base graph module. Most methods of IncidenceGraph should be standard in the base
module Graph. The complexity guarantees can not necessarily provided.  See
http://www.boost.org/libs/graph/doc/graph_concepts.html.

== Installation

RGL is depended on the
stream[http://rgl.rubyforge.org/stream/files/README.html] library which can
also be downloaded from http://rubyforge.org/frs/?group_id=110. If you use gem
to install RGL the stream library will be installed as a prerequisite.

=== GEM Installation

Download the GEM file and install it with ..

  % gem install rgl-VERSION.gem

or directly with 

  % gem install rgl

Use the correct version number for VERSION (e.g. 0.2.x).  You may need root
privileges to install.

=== Running tests

RGL comes with a Rakefile which automatically runs the tests. Goto the
installation directory and start rake:

 % gem env
 Rubygems Environment:
  - VERSION: 0.9.0 (0.9.0)
  - INSTALLATION DIRECTORY: /usr/lib/ruby/gems/1.8
  - GEM PATH:
     - /usr/lib/ruby/gems/1.8
  - REMOTE SOURCES:
     - http://gems.rubyforge.org

 % cd /usr/lib/ruby/gems/1.8/gems/rgl-0.3.0/
 % rake
 (in /usr/lib/ruby/gems/1.8/gems/rgl-0.3.0)
 /usr/bin/ruby1.8 -Ilib:tests "/usr/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake/rake_test_loader.rb" "tests/TestTransitiveClosure.rb" "tests/TestComponents.rb" "tests/TestCycles.rb" "tests/TestDirectedGraph.rb" "tests/TestEdge.rb" "tests/TestGraph.rb" "tests/TestGraphXML.rb" "tests/TestImplicit.rb" "tests/TestUnDirectedGraph.rb" "tests/TestTraversal.rb" "tests/TestDot.rb" "tests/TestRdot.rb" 
 Loaded suite /usr/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake/rake_test_loader
 Started
 ......................................................................................................................................................
 Finished in 0.750958 seconds.

 86 tests, 625 assertions, 0 failures, 0 errors
 
=== Code coverage

Running rcov[http://eigenclass.org/hiki.rb?rcov] on the test suite generates this[link:coverage/index.html] result.

=== Normal Installation

You have to install stream library before. You can than install RGL with the
following command:

  % ruby install.rb

from its distribution directory. To uninstall it use

  % ruby install.rb -u

== Example irb session with RGL

  irb> require 'rgl/adjacency'
  irb> dg=RGL::DirectedAdjacencyGraph[1,2 ,2,3 ,2,4, 4,5, 6,4, 1,6]
  # Use DOT to visualize this graph:
  irb> require 'rgl/dot'
  irb> dg.write_to_graphic_file('jpg')
  "graph.jpg"
  
The result: link:../examples/example.jpg  
  
  irb> dg.directed?
  true
  irb> dg.vertices
  [5, 6, 1, 2, 3, 4]
  irb> dg.has_vertex? 4
  true

Every object could be a vertex (there is no class Vertex), even the class
object _Object_:

  irb> dg.has_vertex? Object
  false
  irb> dg.edges.sort.to_s
  "(1-2)(1-6)(2-3)(2-4)(4-5)(6-4)"
  irb> dg.to_undirected.edges.sort.to_s
  "(1=2)(1=6)(2=3)(2=4)(5=4)(6=4)"

Add inverse edge (4-2) to directed graph:

  irb> dg.add_edge 4,2

(4-2) == (2-4) in the undirected graph:

  irb> dg.to_undirected.edges.sort.to_s
  "(1=2)(1=6)(2=3)(2=4)(5=4)(6=4)"

(4-2) != (2-4) in directed graphs:

  irb> dg.edges.sort.to_s
  "(1-2)(1-6)(2-3)(2-4)(4-2)(4-5)(6-4)"
  irb> dg.remove_edge 4,2
  true

<em>Topological sort</em> is realized with as iterator:

  require 'rgl/topsort'
  irb> dg.topsort_iterator.to_a
  [1, 2, 3, 6, 4, 5]

A more elaborated example showing <em>implicit graphs</em>:

  def module_graph
	RGL::ImplicitGraph.new { |g|
	  g.vertex_iterator { |b|
		ObjectSpace.each_object(Module, &b) 
	  }
	  g.adjacent_iterator { |x, b|
		x.ancestors.each { |y|
		  b.call(y) unless x == y || y == Kernel || y == Object
		}
	  }
	  g.directed = true
	}
  end

This function creates a directed graph, with vertices being all loaded modules:

  g = module_graph

We only want to see the ancestors of RGL::AdjacencyGraph:

  tree = bfs_search_tree_from(g,RGL::AdjacencyGraph)

Now we want to visualize this component of g with DOT.  We therefore create a
subgraph of the original graph, using a filtered graph:

  g = g.vertices_filtered_by {|v| tree.has_vertex? v}

Create the graphics with DOT:

  g.write_to_graphic_file

produces module_graph.jpg: link:../examples/module_graph.jpg

Look for more in the examples directory (i.e.
examples.rb[link:files/examples/examples_rb.html]).

== My del.icio.us links concerning RGL

I collect some links to stuff around RGL at http://del.icio.us/monora/rgl. I
registered RGL at SWiK[http://swik.net/rgl].

== Credits

Many thanks to Robert Feldt which also worked on a graph library
(http://rockit.sf.net/subprojects/graphr) who pointed me to BGL and many other
graph resources.

Robert kindly allowed to integrate his work on graphr, which I did not yet
succeed. Especially his work to output graphs for
GraphViz[http://www.research.att.com/sw/tools/graphviz/download.html] is much
more elaborated than the minimal support in dot.rb.

Jeremy Siek one of the authors of the nice book "The Boost Graph Library (BGL)"
(http://www.boost.org/libs/graph/doc) kindly allowed to use the
BGL documentation as a _cheap_ reference for RGL. He and Robert also gave
feedback and many ideas for RGL.

Dave Thomas for RDoc[http://rdoc.sourceforge.net] which generated what you read
and matz for Ruby. Dave included in the latest version of RDoc (alpha9) the
module dot/dot.rb which I use instead of Roberts module to visualize graphs
(see rgl/dot.rb).

Jeremy Bopp, John Carter, Sascha Doerdelmann and Shawn Garbett for contributing
additions, test cases and bugfixes.

== Copying

RGL is Copyright (c) 2002,2004,2005,2008 by Horst Duchene.  It is free software, and may be
redistributed under the terms specified in the README file of the Ruby distribution.

== Support

Please contact me at mailto:[email protected] with bug reports
suggestions, and other comments. If you send patches, it would help if
they were in-line (not attachments) and generated using "diff -u".


About

RGL is a framework for graph data structures and algorithms in Ruby.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages