yargi 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/CHANGELOG.md +54 -0
  2. data/Gemfile +7 -0
  3. data/Gemfile.lock +23 -0
  4. data/LICENCE.md +22 -0
  5. data/Manifest.txt +15 -0
  6. data/README.md +128 -0
  7. data/Rakefile +23 -0
  8. data/examples/fs2dot.rb +1 -1
  9. data/examples/random.rb +20 -0
  10. data/lib/yargi.rb +8 -10
  11. data/lib/yargi/decorate.rb +55 -0
  12. data/lib/yargi/digraph.rb +71 -46
  13. data/lib/yargi/digraph_edge.rb +23 -23
  14. data/lib/yargi/digraph_vertex.rb +27 -27
  15. data/lib/yargi/edge_set.rb +12 -12
  16. data/lib/yargi/element_set.rb +54 -54
  17. data/lib/yargi/loader.rb +1 -0
  18. data/lib/yargi/markable.rb +12 -12
  19. data/lib/yargi/predicate.rb +62 -43
  20. data/lib/yargi/random.rb +98 -0
  21. data/lib/yargi/version.rb +14 -0
  22. data/lib/yargi/vertex_set.rb +12 -12
  23. data/spec/spec_helper.rb +2 -0
  24. data/spec/test_decorate.rb +28 -0
  25. data/spec/test_digraph.rb +42 -0
  26. data/spec/test_random.rb +45 -0
  27. data/spec/test_yargi.rb +8 -0
  28. data/tasks/debug_mail.rake +75 -0
  29. data/tasks/debug_mail.txt +13 -0
  30. data/tasks/gem.rake +68 -0
  31. data/tasks/spec_test.rake +71 -0
  32. data/tasks/unit_test.rake +76 -0
  33. data/tasks/yard.rake +51 -0
  34. data/test/test_all.rb +1 -1
  35. data/test/yargi/README-example.gif +0 -0
  36. data/test/yargi/digraph_set_features_test.rb +14 -16
  37. data/test/yargi/digraph_test.rb +33 -33
  38. data/test/yargi/digraph_vertex_test.rb +9 -9
  39. data/test/yargi/documentation_test.rb +7 -7
  40. data/test/yargi/edge_set_test.rb +3 -3
  41. data/test/yargi/element_set_test.rb +2 -2
  42. data/test/yargi/hypotheses_test.rb +4 -4
  43. data/test/yargi/markable_test.rb +11 -11
  44. data/test/yargi/predicate_test.rb +14 -14
  45. data/test/yargi/source-sink.gif +0 -0
  46. data/test/yargi/vertex_set_test.rb +7 -7
  47. data/yargi.gemspec +187 -0
  48. data/yargi.noespec +23 -0
  49. metadata +110 -38
  50. data/CONTRIBUTE +0 -11
  51. data/LICENCE +0 -25
  52. data/README +0 -79
  53. data/examples/fs2dot.dot +0 -78
  54. data/examples/fs2dot.gif +0 -0
@@ -0,0 +1,54 @@
1
+ # 0.2.0 / 2012-02-17
2
+
3
+ * Enhancements
4
+
5
+ * Digraph.new now yields self if a block is given. This allows building a
6
+ graph more smoothly:
7
+
8
+ graph = Digraph.new{|d|
9
+ d.add_n_vertices(5)
10
+ ...
11
+ }
12
+
13
+ * An integer is now automatically recognized as a selection predicate. This
14
+ means that the following will also work:
15
+
16
+ # connect 1-th and 2-th vertices
17
+ graph.connect(1, 2)
18
+
19
+ * Added Digraph#ith_vertex and Digraph#ith_edge
20
+ * Added Digraph#vertex_count and Digraph#edge_count
21
+ * Added Digraph.random to generate graph for tests and benchmarks
22
+
23
+ * Bug fixes
24
+
25
+ * Misused of $STDERR has been replaced by $stderr
26
+
27
+ * Internals & Devel
28
+
29
+ * The project structure is now handled by Noe.
30
+
31
+ # 0.1.2
32
+
33
+ * Enhancements
34
+
35
+ * Markable.add_marks also accepts a block to mimic add_n_vertices and
36
+ ElementSet.add_marks
37
+ * EdgeSet forwards source= and target= to its elements, allowing bulk
38
+ reconnection
39
+ * Digraph.to_dot_attributes made much more smart on typical array values
40
+
41
+ * Bug fixes
42
+
43
+ * Markable.has_key? is used to avoid predicate side-effects on v[:mark] when
44
+ the mark is false
45
+
46
+ # 0.1.1
47
+
48
+ * Bug fix in dot generation
49
+ * Examples started and documentation improved
50
+ * Web site index generation using wlang
51
+
52
+ # 0.1.0
53
+
54
+ * Birthday!
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'http://rubygems.org'
2
+
3
+ group :development do
4
+ gem "rake", "~> 0.9.2"
5
+ gem "rspec", "~> 2.8.0"
6
+ gem "wlang", "~> 0.10.2"
7
+ end
@@ -0,0 +1,23 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.3)
5
+ rake (0.9.2.2)
6
+ rspec (2.8.0)
7
+ rspec-core (~> 2.8.0)
8
+ rspec-expectations (~> 2.8.0)
9
+ rspec-mocks (~> 2.8.0)
10
+ rspec-core (2.8.0)
11
+ rspec-expectations (2.8.0)
12
+ diff-lcs (~> 1.1.2)
13
+ rspec-mocks (2.8.0)
14
+ wlang (0.10.2)
15
+
16
+ PLATFORMS
17
+ java
18
+ ruby
19
+
20
+ DEPENDENCIES
21
+ rake (~> 0.9.2)
22
+ rspec (~> 2.8.0)
23
+ wlang (~> 0.10.2)
@@ -0,0 +1,22 @@
1
+ # The MIT Licence
2
+
3
+ Copyright (c) 2009-2011 - Bernard Lambeau
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,15 @@
1
+ yargi.gemspec
2
+ yargi.noespec
3
+ CHANGELOG.md
4
+ Gemfile
5
+ Gemfile.lock
6
+ bin/**/*
7
+ lib/**/*
8
+ examples/**/*
9
+ LICENCE.md
10
+ Manifest.txt
11
+ Rakefile
12
+ README.md
13
+ spec/**/*
14
+ tasks/**/*
15
+ test/**/*
@@ -0,0 +1,128 @@
1
+ # Yargi
2
+
3
+ Yet Another Ruby Graph Library
4
+
5
+ ## Links
6
+
7
+ * http://rubydoc.info/github/blambeau/yargi/master/frames
8
+ * http://github.com/blambeau/yargi
9
+ * http://rubygems.org/gems/yargi
10
+
11
+ ## Description
12
+
13
+ Yargi provides a powerful **mutable** digraph implementation. It has been
14
+ designed to allow full mutability the easy way. A quick tour below.
15
+
16
+ ## Quick tour
17
+
18
+ ### Digraph, Vertex and Edge
19
+
20
+ Unlike {http://rubyforge.org/projects/rgl/ RGL}, Yargi implements graph
21
+ components through concrete classes, not modules (that is, in a
22
+ standard-but-closed way). See Digraph, Digraph::Vertex and Digraph::Edge
23
+ respectively.
24
+
25
+ ### Markable pattern
26
+
27
+ Graphs, vertices and edges are markable through a Hash-like API: users can
28
+ install their own key/value pairs on each graph element. When keys are Symbol
29
+ objects, accessors are automatically generated to provide a friendly
30
+ object-oriented API (this feature must be used with care, for obvious reasons).
31
+
32
+ graph = Yargi::Digraph.new
33
+ v1 = graph.add_vertex(:kind => "simple vertex")
34
+ puts v1.kind
35
+ # => "simple vertex"
36
+
37
+ ### Typed elements
38
+
39
+ Graph elements (vertices and edges) can be tagged with your own modules (at
40
+ creation, or later). This is the standard Yargi way to apply a 'select-and-do'
41
+ feature described below:
42
+
43
+ # These are node types
44
+ module Diamond; end
45
+ module Circle; end
46
+
47
+ # Let build a graph with 5 diamonds
48
+ graph = Yargi::Digraph.new
49
+ graph.add_n_vertices(5, Diamond) do |v,i|
50
+ v[:color] = (i%2==0 ? 'red' : 'blue')
51
+ end
52
+
53
+ # Let add 5 circles
54
+ graph.add_n_vertices(5, Circle)
55
+
56
+ # connect all diamonds to all circles
57
+ graph.connect(Diamond, Circle)
58
+
59
+ ### Selection mechanism
60
+
61
+ Yargi helps you finding the nodes and edges you are looking for through a
62
+ declarative selection mechanism: almost all methods that return a set of
63
+ vertices or edges (Vertex.out_edges, for example) accept a predicate argument
64
+ to filter the result, module names being most-used shortcuts.
65
+ See Yargi::Predicate for details.
66
+
67
+ # [... previous example continued ...]
68
+ graph.vertices(Diamond) # selects all diamonds
69
+ graph.vertices(Diamond){|v| v.color=='blue'} # selects blue diamonds only
70
+
71
+ # Proc variant, find sink states
72
+ sink = Yargi.predicate {|v| v.out_edges.empty?}
73
+ graph.vertices(sink & Circle) # select all Circle sink states (no one)
74
+
75
+ # Or selection
76
+ is_blue = Yargi.predicate {|v| Diamond===v and v.color=='blue'}
77
+ graph.vertices(is_blue|Circle) # select blue diamonds and circles
78
+
79
+ ### VertexSet and EdgeSet
80
+
81
+ The selection mechanism always returns arrays ... being instances of
82
+ Yargi::VertexSet and Yargi::EdgeSet. These classes help you walking your graph
83
+ easily:
84
+
85
+ # [... previous example continued ...]
86
+ circles = graph.vertices(Diamond).adjacent
87
+ puts graph.vertices(Circle)==circles
88
+ # => true
89
+
90
+ ### Select-and-do
91
+
92
+ Many graph methods accept sets of vertices and edges as well as selection queries
93
+ to work. Instead of connecting one source to one target at a time by passing the
94
+ vertices, describe what you want and Yardi does it. Add, connect, remove, mark,
95
+ reconnect many vertices/edges with a single method call:
96
+
97
+ graph.vertices(Diamond).add_marks(:label => '', :shape => 'diamond')
98
+ graph.vertices(Circle).add_marks(:label => '', :shape => 'circle')
99
+ puts graph.to_dot
100
+ graph.remove_vertices(Circle) # remove all circles
101
+
102
+ ### Mutable graphs
103
+
104
+ Graphs here are mutable, mutable and mutable and this is the reason why Yargi
105
+ exists. It comes from a project where manipulating graphs by reconnecting edges,
106
+ removing vertices is the norm, not the exception.
107
+
108
+ ### Complexity don't care
109
+
110
+ The digraph implementation uses an incident list data structure. This graph
111
+ library has not been designed with efficiency in mind so that complexities
112
+ are not documented nor guaranteed. That is not to say that improvements are
113
+ not welcome, of course.
114
+
115
+ ## Distribution & Credits
116
+
117
+ _Yargi_ is freely available (under a MIT licence) as a 'yargi' gem on
118
+ {http://rubygems.org/gems/yargi rubygems.org}. Use 'gem install yargi' to
119
+ install it. The sources are on {http://github.com/blambeau/yargi github}, which
120
+ is also the place where bugs and issues can be reported.
121
+
122
+ This work is supported by the {http://www.uclouvain.be/en-ingi.html department
123
+ of computer science} of the {http://www.uclouvain.be/en-index.html University of
124
+ Louvain} (EPL/INGI, Universite Catholique de Louvain, UCL, Louvain-la-Neuve,
125
+ Belgium).
126
+
127
+ This work was also partially supported by the Regional Government of Wallonia
128
+ (GISELE project, RW Conv. 616425).
@@ -0,0 +1,23 @@
1
+ begin
2
+ gem "bundler", "~> 1.0"
3
+ require "bundler/setup"
4
+ rescue LoadError => ex
5
+ puts ex.message
6
+ abort "Bundler failed to load, (did you run 'gem install bundler' ?)"
7
+ end
8
+
9
+ # Dynamically load the gem spec
10
+ $gemspec_file = File.expand_path('../yargi.gemspec', __FILE__)
11
+ $gemspec = Kernel.eval(File.read($gemspec_file))
12
+
13
+ # We run tests by default
14
+ task :default => :test
15
+
16
+ #
17
+ # Install all tasks found in tasks folder
18
+ #
19
+ # See .rake files there for complete documentation.
20
+ #
21
+ Dir["tasks/*.rake"].each do |taskfile|
22
+ load taskfile
23
+ end
@@ -50,7 +50,7 @@ graph.vertices(FileVertex){|v| /\.rb (.*)$/ =~ v.label}.add_marks(
50
50
  graph.vertices(FileVertex){|v| /\.rb (.*)$/ =~ v.label}.in_adjacent.add_marks do |v|
51
51
  {:fillcolor => 'gold', :fontcolor => 'black'}
52
52
  end
53
-
53
+
54
54
  # Save it
55
55
  File.open(File.join(File.dirname(__FILE__), 'fs2dot.dot'), 'w') do |f|
56
56
  f << graph.to_dot
@@ -0,0 +1,20 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require 'yargi'
3
+
4
+ COLORS = ["blue", "red", "yellow", "green"]
5
+
6
+ # We build a random graph with approximately 20 vertices
7
+ # and 60 edges (will be stripped by default). Each vertex
8
+ # will have a color picked at random.
9
+ graph = Yargi::Digraph.random(20,60) do |r|
10
+ r.vertex_builder = lambda{|v,i|
11
+ v[:color] = COLORS[Kernel.rand(COLORS.size)]
12
+ }
13
+ end
14
+
15
+ # The label of each vertex will be its depth
16
+ Yargi::Decorate::DEPTH.execute(graph)
17
+ graph.vertices.add_marks{|v| {:label => v[:depth]}}
18
+
19
+ # Print as a dot graph
20
+ puts graph.to_dot
@@ -1,25 +1,22 @@
1
+ require 'yargi/version'
2
+ require 'yargi/loader'
1
3
  require 'yargi/predicate'
2
-
3
4
  module Yargi
4
-
5
- # Current Yargi version
6
- VERSION = "0.1.2".freeze
7
-
5
+
8
6
  # When _what_ is not nil, converts it to a predicate (typically a module).
9
7
  # Otherwise, a block is expected, which is converted to a LambdaPredicate.
10
8
  # Otherwise, return ALL.
11
9
  def self.predicate(what=nil, &block)
12
10
  Predicate.to_predicate(what, &block)
13
11
  end
14
-
12
+
15
13
  # Predicates that always return true
16
14
  ALL = Yargi::Predicate.to_predicate(true)
17
-
15
+
18
16
  # Predicates that always return false
19
17
  NONE = Yargi::Predicate.to_predicate(false)
20
-
21
- end
22
18
 
19
+ end
23
20
  require 'yargi/markable'
24
21
  require 'yargi/digraph'
25
22
  require 'yargi/digraph_vertex'
@@ -27,4 +24,5 @@ require 'yargi/digraph_edge'
27
24
  require 'yargi/element_set'
28
25
  require 'yargi/vertex_set'
29
26
  require 'yargi/edge_set'
30
-
27
+ require 'yargi/decorate'
28
+ require 'yargi/random'
@@ -0,0 +1,55 @@
1
+ module Yargi
2
+ class Decorate
3
+ attr_accessor :key
4
+ attr_accessor :bottom
5
+ attr_accessor :d0
6
+ attr_accessor :suppremum
7
+ attr_accessor :propagate
8
+
9
+ def initialize
10
+ yield(self) if block_given?
11
+ end
12
+
13
+ def execute(digraph, initials = digraph.vertices(0))
14
+ # all to bottom except initial states
15
+ digraph.each_vertex{|s| s[key] = bottom}
16
+ initials.each{|s| s[key] = d0}
17
+
18
+ # main loop
19
+ to_explore = initials
20
+ until to_explore.empty?
21
+ source = to_explore.pop
22
+ source.out_edges.each do |edge|
23
+ target = edge.target
24
+ p_decor = propagate.call(source[key], edge)
25
+ p_decor = suppremum.call(target[key], p_decor)
26
+ unless p_decor == target[key]
27
+ target[key] = p_decor
28
+ to_explore << target unless to_explore.include?(target)
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ DEPTH = Decorate.new{|d|
35
+ d.key = :depth
36
+ d.bottom = 1.0/0
37
+ d.d0 = 0
38
+ d.suppremum = lambda{|d1,d2| d1 < d2 ? d1 : d2}
39
+ d.propagate = lambda{|d,e| d+1}
40
+ }
41
+
42
+ SHORTEST_PATH = Decorate.new{|d|
43
+ d.key = :shortest_path
44
+ d.bottom = nil
45
+ d.d0 = []
46
+ d.suppremum = lambda{|d1,d2|
47
+ d1.nil? ? d2 : (d2.nil? ? d1 : (d1.size < d2.size ? d1 : d2))
48
+ }
49
+ d.propagate = lambda{|d,e|
50
+ d.nil? ? [e] : (d + [e])
51
+ }
52
+ }
53
+
54
+ end # class Decorate
55
+ end # module Yargi
@@ -6,12 +6,12 @@ module Yargi
6
6
  #
7
7
  # Directed graph implementation.
8
8
  #
9
- # * All selection methods (vertices, each_vertex, edges, each_edge) implement the
10
- # predicate-selection mechanism (they accept a predicate filter as well as a
9
+ # * All selection methods (vertices, each_vertex, edges, each_edge) implement the
10
+ # predicate-selection mechanism (they accept a predicate filter as well as a
11
11
  # predicate block, with a AND semantics when used conjointly).
12
12
  # * Removal methods (remove_vertex, remove_vertices, remove_edge, remove_edges)
13
- # accept varying arguments that are automatically converted to set of vertices
14
- # or edges. Recognized arguments are Vertex and Edge instances, VertexSet and
13
+ # accept varying arguments that are automatically converted to set of vertices
14
+ # or edges. Recognized arguments are Vertex and Edge instances, VertexSet and
15
15
  # EdgeSet instances, Array instances, and predicates. When multiple arguments
16
16
  # are used conjointly, a OR-semantics is applied.
17
17
  #
@@ -21,22 +21,33 @@ module Yargi
21
21
  #
22
22
  class Digraph
23
23
  include Yargi::Markable
24
-
24
+
25
25
  # Creates an empty graph instance
26
26
  def initialize
27
27
  @vertices = VertexSet[]
28
28
  @edges = EdgeSet[]
29
29
  @marks = {}
30
+ yield(self) if block_given?
30
31
  end
31
-
32
+
32
33
  ### Vertex management ################################################
33
-
34
+
35
+ # Returns number of graph vertices
36
+ def vertex_count
37
+ @vertices.size
38
+ end
39
+
40
+ # Returns the i-th vertex
41
+ def ith_vertex(i)
42
+ @vertices[i]
43
+ end
44
+
34
45
  # Returns all graph vertices for which the 'filter and block' predicate
35
46
  # evaluates to true (see Yargi::Predicate).
36
47
  def vertices(filter=nil, &block)
37
48
  @vertices.filter(filter, &block)
38
49
  end
39
-
50
+
40
51
  # Calls block on each graph vertex for with the 'filter and block' predicate
41
52
  # evaluates to true.
42
53
  def each_vertex(filter=nil, &block)
@@ -46,20 +57,20 @@ module Yargi
46
57
  vertices(filter).each &block
47
58
  end
48
59
  end
49
-
50
- # Adds a vertex. _args_ can be module instances or hashes,
51
- # which are all installed on the vertex _v_ using <tt>v.tag</tt>
52
- # and <tt>v.add_marks</tt>, respectively.
60
+
61
+ # Adds a vertex. _args_ can be module instances or hashes,
62
+ # which are all installed on the vertex _v_ using <tt>v.tag</tt>
63
+ # and <tt>v.add_marks</tt>, respectively.
53
64
  def add_vertex(*args)
54
65
  vertex = Digraph::Vertex.new(self, @vertices.length)
55
66
  apply_arg_conventions(vertex, args)
56
67
  @vertices << vertex
57
68
  vertex
58
69
  end
59
-
60
- # Creates n vertices. _args_ can be module instances or hashes,
61
- # which are all installed on vertices _v_ using <tt>v.tag</tt>
62
- # and <tt>v.add_marks</tt>, respectively. If a block is given,
70
+
71
+ # Creates n vertices. _args_ can be module instances or hashes,
72
+ # which are all installed on vertices _v_ using <tt>v.tag</tt>
73
+ # and <tt>v.add_marks</tt>, respectively. If a block is given,
63
74
  # it is called after each vertex creation. The vertex is passed
64
75
  # as first argument and the iteration index (from 0 to n-1) as
65
76
  # second one.
@@ -72,8 +83,8 @@ module Yargi
72
83
  end
73
84
  VertexSet.new(vertices)
74
85
  end
75
-
76
- # Removes all vertices returned by evaluating the _vertices_ selection
86
+
87
+ # Removes all vertices returned by evaluating the _vertices_ selection
77
88
  # expression.
78
89
  def remove_vertices(*vertices)
79
90
  vertices = to_vertices(*vertices).sort{|v1,v2| v2<=>v1}
@@ -85,16 +96,26 @@ module Yargi
85
96
  @vertices.each_with_index {|v,i| v.index=i}
86
97
  self
87
98
  end
88
- alias :remove_vertex :remove_vertices
89
-
99
+ alias :remove_vertex :remove_vertices
100
+
90
101
  ### Edge management ##################################################
91
-
102
+
103
+ # Returns number of graph edges
104
+ def edge_count
105
+ @edges.size
106
+ end
107
+
108
+ # Returns the i-th edge
109
+ def ith_edge(i)
110
+ @edges[i]
111
+ end
112
+
92
113
  # Returns all graph edges for which the 'filter and block' predicate
93
114
  # evaluates to true (see Yargi::Predicate).
94
115
  def edges(filter=nil, &block)
95
116
  @edges.filter(filter, &block)
96
117
  end
97
-
118
+
98
119
  # Calls block on each graph edge for with the 'filter and block' predicate
99
120
  # evaluates to true.
100
121
  def each_edge(filter=nil, &block)
@@ -104,10 +125,10 @@ module Yargi
104
125
  edges(filter).each &block
105
126
  end
106
127
  end
107
-
108
- # Connects source to target state(s). _source_ and _target_ may be any
109
- # selection expression that can lead to vertex sets. _args_ can be module
110
- # instances or hashes, which are all installed on edges _e_ using
128
+
129
+ # Connects source to target state(s). _source_ and _target_ may be any
130
+ # selection expression that can lead to vertex sets. _args_ can be module
131
+ # instances or hashes, which are all installed on edges _e_ using
111
132
  # <tt>e.tag</tt> and <tt>e.add_marks</tt>, respectively.
112
133
  def add_edge(source, target, *args)
113
134
  if Vertex===source and Vertex===target
@@ -129,7 +150,7 @@ module Yargi
129
150
  end
130
151
  end
131
152
  alias :connect :add_edge
132
-
153
+
133
154
  # Adds many edges at once
134
155
  def add_edges(*extremities)
135
156
  extremities.collect do |extr|
@@ -137,8 +158,8 @@ module Yargi
137
158
  end
138
159
  end
139
160
  alias :connect_all :add_edges
140
-
141
- # Removes all edges returned by evaluating the _edges_ selection
161
+
162
+ # Removes all edges returned by evaluating the _edges_ selection
142
163
  # expression.
143
164
  def remove_edges(*edges)
144
165
  edges = to_edges(edges).sort{|e1,e2| e2<=>e1}
@@ -152,9 +173,9 @@ module Yargi
152
173
  self
153
174
  end
154
175
  alias :remove_edge :remove_edges
155
-
176
+
156
177
  # Reconnects some edge(s). _source_ and _target_ are expected to be
157
- # Vertex instances, or nil. _edges_ may be any selection expression
178
+ # Vertex instances, or nil. _edges_ may be any selection expression
158
179
  # that can be converted to an edge set. This method reconnects all
159
180
  # edges to the specified source and target vertices (at least one is
160
181
  # expected not to be nil).
@@ -165,7 +186,7 @@ module Yargi
165
186
  if source
166
187
  edge.source.remove_out_edge(edge)
167
188
  source.add_out_edge(edge)
168
- end
189
+ end
169
190
  if target
170
191
  edge.target.remove_in_edge(edge)
171
192
  target.add_in_edge(edge)
@@ -176,7 +197,7 @@ module Yargi
176
197
  end
177
198
 
178
199
  ### Standard exports #################################################
179
-
200
+
180
201
  # Encodes this graph for dot graphviz
181
202
  def to_dot(buffer='')
182
203
  buffer << "digraph G {\n"
@@ -189,10 +210,10 @@ module Yargi
189
210
  end
190
211
  buffer << "}\n"
191
212
  end
192
-
213
+
193
214
  ### Argument conventions #############################################
194
215
  protected
195
-
216
+
196
217
  # Converts a hash to dot attributes
197
218
  def to_dot_attributes(hash)
198
219
  # TODO: fix uncompatible key names
@@ -214,36 +235,38 @@ module Yargi
214
235
  end
215
236
  buffer
216
237
  end
217
-
238
+
218
239
  # Checks if _arg_ looks like an element set
219
240
  def looks_a_set?(arg)
220
241
  Array===arg or ElementSet===arg
221
242
  end
222
-
243
+
223
244
  # Checks graph sanity
224
245
  def check_sanity
225
- @vertices.each_with_index do |v,i|
246
+ @vertices.each_with_index do |v,i|
226
247
  raise "Removed vertex in vertex list" unless v.index==i
227
248
  v.in_edges.each do |ine|
228
249
  raise "Removed edge in vertex incoming edges" if ine.index<0
229
- raise "Vertex and edge don't agree on target" unless ine.target==v
250
+ raise "Vertex and edge don't agree on target" unless ine.target==v
230
251
  end
231
252
  v.out_edges.each do |oute|
232
253
  raise "Removed edge in vertex outgoing edges" if oute.index<0
233
- raise "Vertex and edge don't agree on source" unless oute.source==v
254
+ raise "Vertex and edge don't agree on source" unless oute.source==v
234
255
  end
235
256
  end
236
- @edges.each_with_index do |e,i|
257
+ @edges.each_with_index do |e,i|
237
258
  raise "Removed edge in edge list" unless e.index==i
238
259
  raise "Edge in-connected to a removed vertex" if e.source.index<0
239
260
  raise "Edge out-connected to a removed vertex" if e.target.index<0
240
261
  end
241
262
  end
242
-
263
+
243
264
  # Applies argument conventions about selection of vertices
244
265
  def to_vertices(*args)
245
266
  selected = args.collect do |arg|
246
267
  case arg
268
+ when Integer
269
+ [@vertices[arg]]
247
270
  when VertexSet
248
271
  arg
249
272
  when Array
@@ -257,11 +280,13 @@ module Yargi
257
280
  end.flatten.uniq
258
281
  VertexSet.new(selected)
259
282
  end
260
-
283
+
261
284
  # Applies argument conventions about selection of edges
262
285
  def to_edges(*args)
263
286
  selected = args.collect do |arg|
264
287
  case arg
288
+ when Integer
289
+ [@edges[arg]]
265
290
  when EdgeSet
266
291
  arg
267
292
  when Array
@@ -275,7 +300,7 @@ module Yargi
275
300
  end.flatten.uniq
276
301
  EdgeSet.new(selected)
277
302
  end
278
-
303
+
279
304
  # Applies argument conventions on _element_
280
305
  def apply_arg_conventions(element, args)
281
306
  args.each do |arg|
@@ -290,7 +315,7 @@ module Yargi
290
315
  end
291
316
  element
292
317
  end
293
-
318
+
294
319
  end # class Digraph
295
-
320
+
296
321
  end