= Yargi Yargi aims at providing a powerful mutable digraph implementation. As reflected by its name, Yargi is Yet Another (Ruby) Graph Implementation: we all have implemented a graph data structure in almost every language that we use, probably many times. The reason is probably that each implementation has its own design decisions that makes the data-structure well-designed for the task at hand, or not. Below are the main design decisions made by Yargi; this way you can easily see if Yargi fits your needs. [Digraph, Vertex and Edge] Unlike {RGL}[http://rubyforge.org/projects/rgl/], Yargi implements graph components through concrete classes, not modules (that is, in a standard-but-closed way). See Digraph, Digraph::Vertex and Digraph::Edge respectively. [Markable pattern] Graphs, vertices and edges are markable through a Hash-like API: users can install their own key/value pairs on each graph element. When keys are Symbol objects, accessors are automatically generated to provide a friendly object-oriented API (this feature must be used with care, for obvious reasons). Example: graph = Yargi::Digraph.new v1 = graph.add_vertex(:kind => "simple vertex") puts v1.kind # prints "simple vertex" [Typed elements] Graph elements (vertices and edges) can be tagged with your own modules (at creation, or later). This is the standard Yargi way to apply a 'select-and-do' feature described below. Example: module Diamond; end module Circle; end graph = Yargi::Digraph.new graph.add_n_vertices(5, Diamond) do |v,i| v[:color] = (i%2==0 ? 'red' : 'blue') end graph.add_n_vertices(5, Circle) graph.connect(Diamond, Circle) # connect all diamonds to all circles [Selection mechanism] Yargi helps you finding the nodes and edges you are looking for through a declarative selection mechanism: almost all methods that return a set of vertices or edges (Vertex.out_edges, for example) accept a predicate argument to filter the result, module names being most-used shortcuts. See Yargi::Predicate for details. Example: [... previous example continued ...] graph.vertices(Diamond) # selects all diamonds graph.vertices(Diamond){|v| v.color=='blue'} # selects blue diamonds only # Proc variant, find sink states sink = Yargi.predicate {|v| v.out_edges.empty?} graph.vertices(sink & Circle) # select all Circle sink states (no one) # Or selection is_blue = Yargi.predicate {|v| Diamond===v and v.color=='blue'} graph.vertices(is_blue|Circle) # select blue diamonds and circles [VertexSet and EdgeSet] The selection mechanism always returns arrays ... being instances of Yargi::VertexSet and Yargi::EdgeSet. These classes help you walking your graph easily. Example: [... previous example continued ...] circles = graph.vertices(Diamond).adjacent puts graph.vertices(Circle)==circles # puts true [Select-and-do] Many graph methods accept sets of vertices and edges as well as selection queries to work. Instead of connecting one source to one target at a time by passing the vertices, describe what you want and Yardi does it. Add, connect, remove, mark, reconnect many vertices/edges with a single method call ! Example: graph.vertices(Diamond).add_marks(:label => '', :shape => 'diamond') graph.vertices(Circle).add_marks(:label => '', :shape => 'circle') puts graph.to_dot graph.remove_vertices(Circle) # remove all circles [Mutable graphs] Graphs here are mutable, mutable and mutable and this is the reason why Yargi exists. It comes from a project where manipulating graphs by reconnecting edges, removing vertices is the norm, not the exception. [Complexity don't care] The digraph implementation uses an incident list data structure. This graph library has not been designed with efficiency in mind so that complexities are not documented nor guaranteed. That is not to say that improvements are not welcome, of course. [Ruby minded] Because we love that language!