yargi 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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