puppet 0.24.1 → 0.24.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (266) hide show
  1. data/CHANGELOG +94 -0
  2. data/Rakefile +0 -4
  3. data/bin/puppet +18 -10
  4. data/bin/puppetd +1 -1
  5. data/bin/puppetdoc +14 -4
  6. data/bin/puppetmasterd +1 -1
  7. data/bin/puppetrun +3 -8
  8. data/bin/ralsh +12 -11
  9. data/conf/freebsd/puppetd +1 -1
  10. data/conf/freebsd/puppetmasterd +1 -1
  11. data/conf/gentoo/puppet/puppet.conf +29 -0
  12. data/conf/namespaceauth.conf +20 -0
  13. data/conf/redhat/puppet.spec +4 -1
  14. data/conf/solaris/smf/puppetd.xml +1 -1
  15. data/conf/solaris/smf/puppetmasterd.xml +1 -1
  16. data/conf/suse/puppet.spec +10 -8
  17. data/examples/root/etc/puppet/{puppetmasterd.conf → puppet.conf} +6 -3
  18. data/ext/logcheck/puppet +7 -0
  19. data/ext/puppet-test +28 -5
  20. data/lib/puppet.rb +2 -1
  21. data/lib/puppet/defaults.rb +12 -5
  22. data/lib/puppet/dsl.rb +43 -45
  23. data/lib/puppet/external/{gratr/rdot.rb → dot.rb} +0 -0
  24. data/lib/puppet/external/nagios.rb +50 -0
  25. data/lib/puppet/external/nagios/base.rb +421 -0
  26. data/lib/puppet/external/nagios/parser.rb +816 -0
  27. data/lib/puppet/file_serving/file_base.rb +16 -3
  28. data/lib/puppet/file_serving/metadata.rb +29 -11
  29. data/lib/puppet/indirector/terminus.rb +1 -0
  30. data/lib/puppet/metatype/closure.rb +4 -0
  31. data/lib/puppet/metatype/evaluation.rb +2 -17
  32. data/lib/puppet/metatype/metaparams.rb +1 -1
  33. data/lib/puppet/network.rb +3 -0
  34. data/lib/puppet/network/client.rb +4 -5
  35. data/lib/puppet/network/client/master.rb +10 -7
  36. data/lib/puppet/network/handler/fileserver.rb +22 -45
  37. data/lib/puppet/network/http_pool.rb +3 -0
  38. data/lib/puppet/network/http_server/mongrel.rb +7 -1
  39. data/lib/puppet/network/http_server/webrick.rb +4 -3
  40. data/lib/puppet/network/xmlrpc/client.rb +12 -1
  41. data/lib/puppet/node/catalog.rb +51 -40
  42. data/lib/puppet/parser/ast.rb +27 -49
  43. data/lib/puppet/parser/ast/astarray.rb +5 -24
  44. data/lib/puppet/parser/ast/caseopt.rb +4 -4
  45. data/lib/puppet/parser/ast/casestatement.rb +4 -5
  46. data/lib/puppet/parser/ast/collection.rb +3 -5
  47. data/lib/puppet/parser/ast/collexpr.rb +3 -5
  48. data/lib/puppet/parser/ast/definition.rb +148 -159
  49. data/lib/puppet/parser/ast/else.rb +2 -3
  50. data/lib/puppet/parser/ast/function.rb +3 -10
  51. data/lib/puppet/parser/ast/hostclass.rb +66 -59
  52. data/lib/puppet/parser/ast/ifstatement.rb +4 -5
  53. data/lib/puppet/parser/ast/leaf.rb +6 -6
  54. data/lib/puppet/parser/ast/node.rb +26 -58
  55. data/lib/puppet/parser/ast/resource.rb +5 -7
  56. data/lib/puppet/parser/ast/resource_defaults.rb +2 -4
  57. data/lib/puppet/parser/ast/resource_override.rb +4 -6
  58. data/lib/puppet/parser/ast/resource_reference.rb +2 -4
  59. data/lib/puppet/parser/ast/resourceparam.rb +2 -4
  60. data/lib/puppet/parser/ast/selector.rb +5 -6
  61. data/lib/puppet/parser/ast/tag.rb +2 -4
  62. data/lib/puppet/parser/ast/vardef.rb +3 -4
  63. data/lib/puppet/parser/collector.rb +5 -5
  64. data/lib/puppet/parser/{compile.rb → compiler.rb} +69 -107
  65. data/lib/puppet/parser/functions.rb +3 -3
  66. data/lib/puppet/parser/interpreter.rb +32 -23
  67. data/lib/puppet/parser/lexer.rb +391 -282
  68. data/lib/puppet/parser/parser.rb +5 -4
  69. data/lib/puppet/parser/parser_support.rb +3 -6
  70. data/lib/puppet/parser/resource.rb +24 -36
  71. data/lib/puppet/parser/resource/param.rb +1 -1
  72. data/lib/puppet/parser/resource/reference.rb +7 -3
  73. data/lib/puppet/parser/scope.rb +12 -7
  74. data/lib/puppet/parser/templatewrapper.rb +1 -1
  75. data/lib/puppet/pgraph.rb +9 -98
  76. data/lib/puppet/provider/interface/redhat.rb +65 -65
  77. data/lib/puppet/provider/mount/parsed.rb +1 -1
  78. data/lib/puppet/provider/naginator.rb +55 -0
  79. data/lib/puppet/provider/nameservice/directoryservice.rb +6 -7
  80. data/lib/puppet/provider/package/fink.rb +0 -2
  81. data/lib/puppet/provider/package/gem.rb +9 -5
  82. data/lib/puppet/provider/package/openbsd.rb +1 -1
  83. data/lib/puppet/provider/package/pkgdmg.rb +3 -8
  84. data/lib/puppet/provider/package/portage.rb +4 -4
  85. data/lib/puppet/provider/package/yumhelper.py +8 -6
  86. data/lib/puppet/provider/parsedfile.rb +7 -1
  87. data/lib/puppet/provider/service/debian.rb +2 -0
  88. data/lib/puppet/provider/service/gentoo.rb +4 -0
  89. data/lib/puppet/provider/service/init.rb +1 -1
  90. data/lib/puppet/provider/sshkey/parsed.rb +2 -0
  91. data/lib/puppet/provider/user/useradd.rb +1 -1
  92. data/lib/puppet/rails.rb +4 -0
  93. data/lib/puppet/rails/database/001_add_created_at_to_all_tables.rb +17 -0
  94. data/lib/puppet/rails/fact_value.rb +4 -0
  95. data/lib/puppet/rails/host.rb +1 -2
  96. data/lib/puppet/rails/param_value.rb +4 -0
  97. data/lib/puppet/rails/resource_tag.rb +4 -0
  98. data/lib/puppet/rails/source_file.rb +4 -1
  99. data/lib/puppet/relationship.rb +5 -1
  100. data/lib/puppet/reports/tagmail.rb +12 -1
  101. data/lib/puppet/resource_reference.rb +1 -1
  102. data/lib/puppet/simple_graph.rb +78 -11
  103. data/lib/puppet/sslcertificates.rb +1 -1
  104. data/lib/puppet/sslcertificates/ca.rb +3 -3
  105. data/lib/puppet/transaction.rb +7 -4
  106. data/lib/puppet/transportable.rb +1 -1
  107. data/lib/puppet/type.rb +3 -10
  108. data/lib/puppet/type/cron.rb +18 -0
  109. data/lib/puppet/type/exec.rb +18 -12
  110. data/lib/puppet/type/{pfile.rb → file.rb} +66 -84
  111. data/lib/puppet/type/file/checksum.rb +271 -0
  112. data/lib/puppet/type/{pfile → file}/content.rb +10 -15
  113. data/lib/puppet/type/{pfile → file}/ensure.rb +15 -8
  114. data/lib/puppet/type/{pfile → file}/group.rb +0 -0
  115. data/lib/puppet/type/{pfile → file}/mode.rb +0 -0
  116. data/lib/puppet/type/{pfile → file}/owner.rb +0 -0
  117. data/lib/puppet/type/{pfile → file}/source.rb +34 -48
  118. data/lib/puppet/type/{pfile → file}/target.rb +0 -0
  119. data/lib/puppet/type/{pfile → file}/type.rb +0 -0
  120. data/lib/puppet/type/{pfilebucket.rb → filebucket.rb} +0 -0
  121. data/lib/puppet/type/host.rb +13 -0
  122. data/lib/puppet/type/mailalias.rb +1 -1
  123. data/lib/puppet/type/nagios_command.rb +3 -0
  124. data/lib/puppet/type/nagios_contact.rb +3 -0
  125. data/lib/puppet/type/nagios_contactgroup.rb +3 -0
  126. data/lib/puppet/type/nagios_host.rb +3 -0
  127. data/lib/puppet/type/nagios_hostextinfo.rb +3 -0
  128. data/lib/puppet/type/nagios_hostgroup.rb +3 -0
  129. data/lib/puppet/type/nagios_hostgroupescalation.rb +3 -0
  130. data/lib/puppet/type/nagios_service.rb +3 -0
  131. data/lib/puppet/type/nagios_servicedependency.rb +3 -0
  132. data/lib/puppet/type/nagios_serviceescalation.rb +3 -0
  133. data/lib/puppet/type/nagios_serviceextinfo.rb +3 -0
  134. data/lib/puppet/type/nagios_timeperiod.rb +3 -0
  135. data/lib/puppet/type/package.rb +4 -12
  136. data/lib/puppet/type/service.rb +9 -0
  137. data/lib/puppet/type/sshkey.rb +3 -3
  138. data/lib/puppet/util/autoload.rb +5 -5
  139. data/lib/puppet/util/checksums.rb +51 -13
  140. data/lib/puppet/util/constant_inflector.rb +14 -0
  141. data/lib/puppet/util/filetype.rb +1 -1
  142. data/lib/puppet/util/graph.rb +3 -9
  143. data/lib/puppet/util/nagios_maker.rb +57 -0
  144. data/lib/puppet/util/settings.rb +19 -16
  145. data/lib/puppet/util/tagging.rb +39 -0
  146. data/test/executables/puppetbin.rb +17 -0
  147. data/test/language/ast.rb +8 -58
  148. data/test/language/ast/casestatement.rb +3 -3
  149. data/test/language/ast/resource.rb +6 -7
  150. data/test/language/ast/resource_reference.rb +12 -12
  151. data/test/language/ast/selector.rb +2 -2
  152. data/test/language/ast/variable.rb +2 -2
  153. data/test/language/functions.rb +24 -24
  154. data/test/language/parser.rb +20 -8
  155. data/test/language/resource.rb +5 -42
  156. data/test/language/scope.rb +21 -37
  157. data/test/language/snippets.rb +7 -0
  158. data/test/lib/puppettest.rb +28 -14
  159. data/test/lib/puppettest/parsertesting.rb +10 -10
  160. data/test/lib/puppettest/support/resources.rb +1 -1
  161. data/test/network/client/master.rb +10 -0
  162. data/test/network/handler/fileserver.rb +51 -49
  163. data/test/network/server/webrick.rb +1 -1
  164. data/test/other/dsl.rb +3 -4
  165. data/test/other/transactions.rb +6 -4
  166. data/test/rails/ast.rb +2 -2
  167. data/test/rails/configuration.rb +1 -1
  168. data/test/rails/railsparameter.rb +2 -0
  169. data/test/rails/railsresource.rb +1 -0
  170. data/test/ral/manager/type.rb +4 -4
  171. data/test/ral/providers/cron/crontab.rb +3 -1
  172. data/test/ral/providers/package.rb +1 -1
  173. data/test/ral/{types → type}/basic.rb +2 -2
  174. data/test/ral/{types → type}/cron.rb +0 -0
  175. data/test/ral/{types → type}/exec.rb +42 -2
  176. data/test/ral/{types → type}/file.rb +34 -79
  177. data/test/ral/{types → type}/file/target.rb +0 -0
  178. data/test/ral/{types → type}/filebucket.rb +0 -0
  179. data/test/ral/{types → type}/fileignoresource.rb +0 -0
  180. data/test/ral/{types → type}/filesources.rb +8 -27
  181. data/test/ral/{types → type}/group.rb +0 -0
  182. data/test/ral/{types → type}/host.rb +16 -0
  183. data/test/ral/{types → type}/mailalias.rb +0 -0
  184. data/test/ral/{types → type}/parameter.rb +0 -0
  185. data/test/ral/{types → type}/port.rb +0 -0
  186. data/test/ral/{types → type}/property.rb +0 -0
  187. data/test/ral/{types → type}/resources.rb +0 -0
  188. data/test/ral/{types → type}/service.rb +0 -0
  189. data/test/ral/{types → type}/sshkey.rb +0 -0
  190. data/test/ral/{types → type}/tidy.rb +1 -0
  191. data/test/ral/{types → type}/user.rb +0 -0
  192. data/test/ral/{types → type}/yumrepo.rb +0 -0
  193. data/test/ral/{types → type}/zone.rb +0 -0
  194. data/test/util/autoload.rb +24 -5
  195. metadata +60 -107
  196. data/conf/gentoo/puppet/puppetca.conf +0 -29
  197. data/conf/gentoo/puppet/puppetd.conf +0 -29
  198. data/conf/gentoo/puppet/puppetmasterd.conf +0 -29
  199. data/examples/root/etc/puppet/puppetd.conf +0 -4
  200. data/lib/puppet/external/gratr.rb +0 -33
  201. data/lib/puppet/external/gratr/adjacency_graph.rb +0 -257
  202. data/lib/puppet/external/gratr/base.rb +0 -34
  203. data/lib/puppet/external/gratr/biconnected.rb +0 -116
  204. data/lib/puppet/external/gratr/chinese_postman.rb +0 -123
  205. data/lib/puppet/external/gratr/common.rb +0 -73
  206. data/lib/puppet/external/gratr/comparability.rb +0 -92
  207. data/lib/puppet/external/gratr/digraph.rb +0 -116
  208. data/lib/puppet/external/gratr/digraph_distance.rb +0 -185
  209. data/lib/puppet/external/gratr/dot.rb +0 -90
  210. data/lib/puppet/external/gratr/edge.rb +0 -145
  211. data/lib/puppet/external/gratr/graph.rb +0 -303
  212. data/lib/puppet/external/gratr/graph_api.rb +0 -83
  213. data/lib/puppet/external/gratr/import.rb +0 -44
  214. data/lib/puppet/external/gratr/labels.rb +0 -90
  215. data/lib/puppet/external/gratr/maximum_flow.rb +0 -64
  216. data/lib/puppet/external/gratr/search.rb +0 -409
  217. data/lib/puppet/external/gratr/strong_components.rb +0 -127
  218. data/lib/puppet/external/gratr/undirected_graph.rb +0 -153
  219. data/lib/puppet/rails/external/tagging/acts_as_taggable.rb +0 -62
  220. data/lib/puppet/rails/external/tagging/init.rb +0 -5
  221. data/lib/puppet/rails/external/tagging/tag.rb +0 -50
  222. data/lib/puppet/rails/external/tagging/tagging.rb +0 -12
  223. data/lib/puppet/rails/puppet_class.rb +0 -6
  224. data/lib/puppet/reference/node_source.rb +0 -9
  225. data/lib/puppet/reference/report.rb +0 -21
  226. data/lib/puppet/type/pfile/checksum.rb +0 -326
  227. data/test/language/ast/definition.rb +0 -166
  228. data/test/language/ast/hostclass.rb +0 -184
  229. data/test/language/compile.rb +0 -569
  230. data/test/language/lexer.rb +0 -276
  231. data/test/lib/mocha.rb +0 -19
  232. data/test/lib/mocha/any_instance_method.rb +0 -35
  233. data/test/lib/mocha/auto_verify.rb +0 -113
  234. data/test/lib/mocha/central.rb +0 -35
  235. data/test/lib/mocha/class_method.rb +0 -62
  236. data/test/lib/mocha/deprecation.rb +0 -22
  237. data/test/lib/mocha/exception_raiser.rb +0 -17
  238. data/test/lib/mocha/expectation.rb +0 -378
  239. data/test/lib/mocha/expectation_error.rb +0 -6
  240. data/test/lib/mocha/infinite_range.rb +0 -25
  241. data/test/lib/mocha/inspect.rb +0 -39
  242. data/test/lib/mocha/instance_method.rb +0 -8
  243. data/test/lib/mocha/is_a.rb +0 -9
  244. data/test/lib/mocha/metaclass.rb +0 -7
  245. data/test/lib/mocha/missing_expectation.rb +0 -27
  246. data/test/lib/mocha/mock.rb +0 -207
  247. data/test/lib/mocha/multiple_yields.rb +0 -20
  248. data/test/lib/mocha/no_yields.rb +0 -11
  249. data/test/lib/mocha/object.rb +0 -110
  250. data/test/lib/mocha/parameter_matchers.rb +0 -9
  251. data/test/lib/mocha/parameter_matchers/all_of.rb +0 -39
  252. data/test/lib/mocha/parameter_matchers/any_of.rb +0 -44
  253. data/test/lib/mocha/parameter_matchers/anything.rb +0 -30
  254. data/test/lib/mocha/parameter_matchers/has_entry.rb +0 -39
  255. data/test/lib/mocha/parameter_matchers/has_key.rb +0 -39
  256. data/test/lib/mocha/parameter_matchers/has_value.rb +0 -39
  257. data/test/lib/mocha/parameter_matchers/includes.rb +0 -37
  258. data/test/lib/mocha/pretty_parameters.rb +0 -28
  259. data/test/lib/mocha/return_values.rb +0 -31
  260. data/test/lib/mocha/setup_and_teardown.rb +0 -23
  261. data/test/lib/mocha/single_return_value.rb +0 -24
  262. data/test/lib/mocha/single_yield.rb +0 -18
  263. data/test/lib/mocha/standalone.rb +0 -32
  264. data/test/lib/mocha/stub.rb +0 -18
  265. data/test/lib/mocha/test_case_adapter.rb +0 -49
  266. data/test/lib/mocha/yield_parameters.rb +0 -31
@@ -1,83 +0,0 @@
1
- #--
2
- # Copyright (c) 2006 Shawn Patrick Garbett
3
- # Copyright (c) 2002,2004,2005 by Horst Duchene
4
- #
5
- # Redistribution and use in source and binary forms, with or without modification,
6
- # are permitted provided that the following conditions are met:
7
- #
8
- # * Redistributions of source code must retain the above copyright notice(s),
9
- # this list of conditions and the following disclaimer.
10
- # * Redistributions in binary form must reproduce the above copyright notice,
11
- # this list of conditions and the following disclaimer in the documentation
12
- # and/or other materials provided with the distribution.
13
- # * Neither the name of the Shawn Garbett nor the names of its contributors
14
- # may be used to endorse or promote products derived from this software
15
- # without specific prior written permission.
16
- #
17
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18
- # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
- # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
- # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21
- # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
- # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
- # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
- # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
- # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
- #++
28
-
29
-
30
- module GRATR
31
-
32
- # This defines the minimum set of functions required to make a graph class that can
33
- # use the algorithms defined by this library
34
- module GraphAPI
35
-
36
- # Is the graph directed?
37
- #
38
- # This method must be implemented by the specific graph class
39
- def directed?() raise NotImplementedError; end
40
-
41
- # Add a vertex to the Graph and return the Graph
42
- # An additional label l can be specified as well
43
- #
44
- # This method must be implemented by the specific graph class
45
- def add_vertex!(v,l=nil) raise NotImplementedError; end
46
-
47
- # Add an edge to the Graph and return the Graph
48
- # u can be an object of type GRATR::Edge or u,v specifies
49
- # a source, target pair. The last parameter is an optional label
50
- #
51
- # This method must be implemented by the specific graph class
52
- def add_edge!(u,v=nil,l=nil) raise NotImplementedError; end
53
-
54
- # Remove a vertex to the Graph and return the Graph
55
- #
56
- # This method must be implemented by the specific graph class
57
- def remove_vertex!(v) raise NotImplementedError; end
58
-
59
- # Remove an edge from the Graph and return the Graph
60
- #
61
- # Can be a type of GRATR::Edge or a source and target
62
- # This method must be implemented by the specific graph class
63
- def remove_edge!(u,v=nil) raise NotImplementedError; end
64
-
65
- # Return the array of vertices.
66
- #
67
- # This method must be implemented by the specific graph class
68
- def vertices() raise NotImplementedError; end
69
-
70
- # Return the array of edges.
71
- #
72
- # This method must be implemented by the specific graph class
73
- def edges() raise NotImplementedError; end
74
-
75
- # Returns the edge class
76
- def edge_class() raise NotImplementedError; end
77
-
78
- # Return the chromatic number for this graph
79
- # This is currently incomplete and in some cases will be NP-complete
80
- # FIXME: Should this even be here? My gut feeling is no...
81
- def chromatic_number() raise NotImplementedError; end
82
- end
83
- end
@@ -1,44 +0,0 @@
1
- #--
2
- # Copyright (c) 2006 Shawn Patrick Garbett
3
- #
4
- # Redistribution and use in source and binary forms, with or without modification,
5
- # are permitted provided that the following conditions are met:
6
- #
7
- # * Redistributions of source code must retain the above copyright notice(s),
8
- # this list of conditions and the following disclaimer.
9
- # * Redistributions in binary form must reproduce the above copyright notice,
10
- # this list of conditions and the following disclaimer in the documentation
11
- # and/or other materials provided with the distribution.
12
- # * Neither the name of the Shawn Garbett nor the names of its contributors
13
- # may be used to endorse or promote products derived from this software
14
- # without specific prior written permission.
15
- #
16
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
- # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
- # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
- # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20
- # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
- # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
- # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
- # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
- # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
- #++
27
-
28
-
29
- require 'puppet/external/gratr'
30
-
31
- # Pull all GRATR classes up into the current namespace
32
- Edge = GRATR::Edge
33
- UndirectedEdge = GRATR::UndirectedEdge
34
- MultiEdge = GRATR::MultiEdge
35
- MultiUndirectedEdge = GRATR::MultiUndirectedEdge
36
- Graph = GRATR::Graph
37
- Digraph = GRATR::Digraph
38
- DirectedGraph = GRATR::DirectedGraph
39
- DirectedPseudoGraph = GRATR::DirectedPseudoGraph
40
- DirectedMultiGraph = GRATR::DirectedMultiGraph
41
- UndirectedGraph = GRATR::UndirectedGraph
42
- UndirectedPseudoGraph = GRATR::UndirectedPseudoGraph
43
- UndirectedMultiGraph = GRATR::UndirectedMultiGraph
44
- Complete = GRATR::Complete
@@ -1,90 +0,0 @@
1
- #--
2
- # Copyright (c) 2006 Shawn Patrick Garbett
3
- #
4
- # Redistribution and use in source and binary forms, with or without modification,
5
- # are permitted provided that the following conditions are met:
6
- #
7
- # * Redistributions of source code must retain the above copyright notice(s),
8
- # this list of conditions and the following disclaimer.
9
- # * Redistributions in binary form must reproduce the above copyright notice,
10
- # this list of conditions and the following disclaimer in the documentation
11
- # and/or other materials provided with the distribution.
12
- # * Neither the name of the Shawn Garbett nor the names of its contributors
13
- # may be used to endorse or promote products derived from this software
14
- # without specific prior written permission.
15
- #
16
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
- # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
- # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
- # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20
- # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
- # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
- # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
- # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
- # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
- #++
27
-
28
- module GRATR
29
- module Labels
30
- # Return a label for an edge or vertex
31
- def [](u) (u.kind_of? GRATR::Edge) ? edge_label(u) : vertex_label(u); end
32
-
33
- # Set a label for an edge or vertex
34
- def []= (u, value) (u.kind_of? GRATR::Edge) ? edge_label_set(u,value) : vertex_label_set(u, value); end
35
-
36
- # Delete a label entirely
37
- def delete_label(u) (u.kind_of? GRATR::Edge) ? edge_label_delete(u) : vertex_label_delete(u); end
38
-
39
- # Get the label for an edge
40
- def vertex_label(v) vertex_label_dict[v]; end
41
-
42
- # Set the label for an edge
43
- def vertex_label_set(v, l) vertex_label_dict[v] = l; self; end
44
-
45
- # Get the label for an edge
46
- def edge_label(u,v=nil,n=nil)
47
- u = edge_convert(u,v,n)
48
- edge_label_dict[u]
49
- end
50
-
51
- # Set the label for an edge
52
- def edge_label_set(u, v=nil, l=nil, n=nil)
53
- u.kind_of?(GRATR::Edge) ? l = v : u = edge_convert(u,v,n)
54
- edge_label_dict[u] = l; self
55
- end
56
-
57
- # Delete all graph labels
58
- def clear_all_labels() @vertex_labels = {}; @edge_labels = {}; end
59
-
60
- # Delete an edge label
61
- def edge_label_delete(u, v=nil, n=nil)
62
- u = edge_convert(u,v,n)
63
- edge_label_dict.delete(u)
64
- end
65
-
66
- # Delete a vertex label
67
- def vertex_label_delete(v) vertex_label_dict.delete(v); end
68
-
69
- protected
70
-
71
- def vertex_label_dict() @vertex_labels ||= {}; end
72
- def edge_label_dict() @edge_labels ||= {}; end
73
-
74
- # A generic cost function. It either calls the weight function with and edge
75
- # constructed from the two nodes, or calls the [] operator of the label
76
- # when given a value. If no weight value is specified, the label itself is
77
- # treated as the cost value.
78
- #
79
- # Note: This function will not work for Pseudo or Multi graphs at present.
80
- def cost(u,v=nil,weight=nil)
81
- u.kind_of?(Edge) ? weight = v : u = edge_class[u,v]
82
- case weight
83
- when Proc : weight.call(u)
84
- when nil : self[u]
85
- else self[u][weight]
86
- end
87
- end
88
-
89
- end
90
- end
@@ -1,64 +0,0 @@
1
- #--
2
- # Copyright (c) 2006 Shawn Patrick Garbett
3
- # Copyright (c) 2002,2004,2005 by Horst Duchene
4
- #
5
- # Redistribution and use in source and binary forms, with or without modification,
6
- # are permitted provided that the following conditions are met:
7
- #
8
- # * Redistributions of source code must retain the above copyright notice(s),
9
- # this list of conditions and the following disclaimer.
10
- # * Redistributions in binary form must reproduce the above copyright notice,
11
- # this list of conditions and the following disclaimer in the documentation
12
- # and/or other materials provided with the distribution.
13
- # * Neither the name of the Shawn Garbett nor the names of its contributors
14
- # may be used to endorse or promote products derived from this software
15
- # without specific prior written permission.
16
- #
17
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18
- # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
- # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
- # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21
- # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
- # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
- # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
- # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
- # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
- #++
28
-
29
- module GRATR
30
-
31
- module Graph
32
-
33
- module MaximumFlow
34
-
35
- # Maximum flow, it returns an array with the maximum flow and a hash of flow per edge
36
- # Currently a highly inefficient implementation, FIXME, This should use Goldberg and Tarjan's method.
37
- def maximum_flow(s, t, capacity = nil, zero = 0)
38
- flow = Hash.new(zero)
39
- available = Hash.new(zero)
40
- total = zero
41
- edges.each {|e| available[e] = cost(e,capacity)}
42
- adj_positive = Proc.new do |u|
43
- adjacent(u).select {|r| available[edge_class[u,r]] > zero}
44
- end
45
- while (tree = bfs_tree_from_vertex(start))[t]
46
- route = [t]
47
- while route[-1] != s
48
- route << tree[route[route[-1]]]
49
- raise ArgumentError, "No route from #{s} to #{t} possible"
50
- end; route.reverse
51
- amt = route.map {|e| available[e]}.min
52
- route.each do |e|
53
- flow[e] += amt
54
- available[e] -= amt
55
- end
56
- total += amt
57
- end
58
-
59
- [total, flow]
60
- end
61
-
62
- end # MaximumFlow
63
- end # Graph
64
- end # GRATR
@@ -1,409 +0,0 @@
1
- #--
2
- # Copyright (c) 2006 Shawn Patrick Garbett
3
- # Copyright (c) 2002,2004,2005 by Horst Duchene
4
- #
5
- # Redistribution and use in source and binary forms, with or without modification,
6
- # are permitted provided that the following conditions are met:
7
- #
8
- # * Redistributions of source code must retain the above copyright notice(s),
9
- # this list of conditions and the following disclaimer.
10
- # * Redistributions in binary form must reproduce the above copyright notice,
11
- # this list of conditions and the following disclaimer in the documentation
12
- # and/or other materials provided with the distribution.
13
- # * Neither the name of the Shawn Garbett nor the names of its contributors
14
- # may be used to endorse or promote products derived from this software
15
- # without specific prior written permission.
16
- #
17
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18
- # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
- # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
- # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21
- # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
- # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
- # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
- # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
- # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
- #++
28
-
29
-
30
- module GRATR
31
- module Graph
32
- module Search
33
-
34
- # Options are mostly callbacks passed in as a hash.
35
- # The following are valid, anything else is ignored
36
- # :enter_vertex => Proc Called upon entry of a vertex
37
- # :exit_vertex => Proc Called upon exit of a vertex
38
- # :root_vertex => Proc Called when a vertex the a root of a tree
39
- # :start_vertex => Proc Called for the first vertex of the search
40
- # :examine_edge => Proc Called when an edge is examined
41
- # :tree_edge => Proc Called when the edge is a member of the tree
42
- # :back_edge => Proc Called when the edge is a back edge
43
- # :forward_edge => Proc Called when the edge is a forward edge
44
- # :adjacent => Proc that given a vertex returns adjacent nodes, defaults to adjacent call of graph useful for changing the definition of adjacent in some algorithms
45
- #
46
- # :start => Vertex Specifies the vertex to start search from
47
- #
48
- # If a &block is specified it defaults to :enter_vertex
49
- #
50
- # Returns the list of vertexes as reached by enter_vertex
51
- # This allows for calls like, g.bfs.each {|v| ...}
52
- #
53
- # Can also be called like bfs_examine_edge {|e| ... } or
54
- # dfs_back_edge {|e| ... } for any of the callbacks
55
- #
56
- # A full example usage is as follows:
57
- #
58
- # ev = Proc.new {|x| puts "Enter Vertex #{x}"}
59
- # xv = Proc.new {|x| puts "Exit Vertex #{x}"}
60
- # sv = Proc.new {|x| puts "Start Vertex #{x}"}
61
- # ee = Proc.new {|x| puts "Examine Edge #{x}"}
62
- # te = Proc.new {|x| puts "Tree Edge #{x}"}
63
- # be = Proc.new {|x| puts "Back Edge #{x}"}
64
- # fe = Proc.new {|x| puts "Forward Edge #{x}"}
65
- # Digraph[1,2,2,3,3,4].dfs({
66
- # :enter_vertex => ev,
67
- # :exit_vertex => xv,
68
- # :start_vertex => sv,
69
- # :examine_edge => ee,
70
- # :tree_edge => te,
71
- # :back_edge => be,
72
- # :forward_edge => fe })
73
- #
74
- # Which outputs:
75
- #
76
- # Start Vertex 1
77
- # Enter Vertex 1
78
- # Examine Edge (1=2)
79
- # Tree Edge (1=2)
80
- # Enter Vertex 2
81
- # Examine Edge (2=3)
82
- # Tree Edge (2=3)
83
- # Enter Vertex 3
84
- # Examine Edge (3=4)
85
- # Tree Edge (3=4)
86
- # Enter Vertex 4
87
- # Examine Edge (1=4)
88
- # Back Edge (1=4)
89
- # Exit Vertex 4
90
- # Exit Vertex 3
91
- # Exit Vertex 2
92
- # Exit Vertex 1
93
- def bfs(options={}, &block) gratr_search_helper(:shift, options, &block); end
94
-
95
- # See options for bfs method
96
- def dfs(options={}, &block) gratr_search_helper(:pop, options, &block); end
97
-
98
- # Routine to compute a spanning forest for the given search method
99
- # Returns two values, first is a hash of predecessors and second an array of root nodes
100
- def spanning_forest(start, routine)
101
- predecessor = {}
102
- roots = []
103
- te = Proc.new {|e| predecessor[e.target] = e.source}
104
- rv = Proc.new {|v| roots << v}
105
- method(routine).call :start => start, :tree_edge => te, :root_vertex => rv
106
- [predecessor, roots]
107
- end
108
-
109
- # Return the dfs spanning forest for the given start node, see spanning_forest
110
- def dfs_spanning_forest(start) spanning_forest(start, :dfs); end
111
-
112
- # Return the bfs spanning forest for the given start node, see spanning_forest
113
- def bfs_spanning_forest(start) spanning_forest(start, :bfs); end
114
-
115
- # Returns a hash of predecessors in a tree rooted at the start node. If this is a connected graph
116
- # then it will be a spanning tree and contain all vertices. An easier way to tell if it's a spanning tree is to
117
- # use a spanning_forest call and check if there is a single root node.
118
- def tree_from_vertex(start, routine)
119
- predecessor={}
120
- correct_tree = false
121
- te = Proc.new {|e| predecessor[e.target] = e.source if correct_tree}
122
- rv = Proc.new {|v| correct_tree = (v == start)}
123
- method(routine).call :start => start, :tree_edge => te, :root_vertex => rv
124
- predecessor
125
- end
126
-
127
- # Returns a hash of predecessors for the depth first search tree rooted at the given node
128
- def dfs_tree_from_vertex(start) tree_from_vertex(start, :dfs); end
129
-
130
- # Returns a hash of predecessors for the depth first search tree rooted at the given node
131
- def bfs_tree_from_vertex(start) tree_from_vertex(start, :bfs); end
132
-
133
- # An inner class used for greater efficiency in lexicograph_bfs
134
- #
135
- # Original desgn taken from Golumbic's, "Algorithmic Graph Theory and
136
- # Perfect Graphs" pg, 87-89
137
- class LexicographicQueue
138
-
139
- # Called with the initial values (array)
140
- def initialize(values)
141
- @node = Struct.new(:back, :forward, :data)
142
- @node.class_eval { def hash() @hash; end; @@cnt=0 }
143
- @set = {}
144
- @tail = @node.new(nil, nil, Array.new(values))
145
- @tail.instance_eval { @hash = (@@cnt+=1) }
146
- values.each {|a| @set[a] = @tail}
147
- end
148
-
149
- # Pop an entry with maximum lexical value from queue
150
- def pop()
151
- return nil unless @tail
152
- value = @tail[:data].pop
153
- @tail = @tail[:forward] while @tail and @tail[:data].size == 0
154
- @set.delete(value); value
155
- end
156
-
157
- # Increase lexical value of given values (array)
158
- def add_lexeme(values)
159
- fix = {}
160
- values.select {|v| @set[v]}.each do |w|
161
- sw = @set[w]
162
- if fix[sw]
163
- s_prime = sw[:back]
164
- else
165
- s_prime = @node.new(sw[:back], sw, [])
166
- s_prime.instance_eval { @hash = (@@cnt+=1) }
167
- @tail = s_prime if @tail == sw
168
- sw[:back][:forward] = s_prime if sw[:back]
169
- sw[:back] = s_prime
170
- fix[sw] = true
171
- end
172
- s_prime[:data] << w
173
- sw[:data].delete(w)
174
- @set[w] = s_prime
175
- end
176
- fix.keys.select {|n| n[:data].size == 0}.each do |e|
177
- e[:forward][:back] = e[:back] if e[:forward]
178
- e[:back][:forward] = e[:forward] if e[:back]
179
- end
180
- end
181
-
182
- end
183
-
184
- # Lexicographic breadth-first search, the usual queue of vertices
185
- # is replaced by a queue of unordered subsets of the vertices,
186
- # which is sometimes refined but never reordered.
187
- #
188
- # Originally developed by Rose, Tarjan, and Leuker, "Algorithmic
189
- # aspects of vertex elimination on graphs", SIAM J. Comput. 5, 266-283
190
- # MR53 #12077
191
- #
192
- # Implementation taken from Golumbic's, "Algorithmic Graph Theory and
193
- # Perfect Graphs" pg, 84-90
194
- def lexicograph_bfs(&block)
195
- lex_q = GRATR::Graph::Search::LexicographicQueue.new(vertices)
196
- result = []
197
- num_vertices.times do
198
- v = lex_q.pop
199
- result.unshift(v)
200
- lex_q.add_lexeme(adjacent(v))
201
- end
202
- result.each {|r| block.call(r)} if block
203
- result
204
- end
205
-
206
-
207
- # A* Heuristic best first search
208
- #
209
- # start is the starting vertex for the search
210
- #
211
- # func is a Proc that when passed a vertex returns the heuristic
212
- # weight of sending the path through that node. It must always
213
- # be equal to or less than the true cost
214
- #
215
- # options are mostly callbacks passed in as a hash, the default block is
216
- # :discover_vertex and weight is assumed to be the label for the Edge.
217
- # The following options are valid, anything else is ignored.
218
- #
219
- # * :weight => can be a Proc, or anything else is accessed using the [] for the
220
- # the label or it defaults to using
221
- # the value stored in the label for the Edge. If it is a Proc it will
222
- # pass the edge to the proc and use the resulting value.
223
- # * :discover_vertex => Proc invoked when a vertex is first discovered
224
- # and is added to the open list.
225
- # * :examine_vertex => Proc invoked when a vertex is popped from the
226
- # queue (i.e., it has the lowest cost on the open list).
227
- # * :examine_edge => Proc invoked on each out-edge of a vertex
228
- # immediately after it is examined.
229
- # * :edge_relaxed => Proc invoked on edge (u,v) if d[u] + w(u,v) < d[v].
230
- # * :edge_not_relaxed=> Proc invoked if the edge is not relaxed (see above).
231
- # * :black_target => Proc invoked when a vertex that is on the closed
232
- # list is "rediscovered" via a more efficient path, and is re-added
233
- # to the OPEN list.
234
- # * :finish_vertex => Proc invoked on a vertex when it is added to the
235
- # closed list, which happens after all of its out edges have been
236
- # examined.
237
- #
238
- # Returns array of nodes in path, or calls block on all nodes,
239
- # upon failure returns nil
240
- #
241
- # Can also be called like astar_examine_edge {|e| ... } or
242
- # astar_edge_relaxed {|e| ... } for any of the callbacks
243
- #
244
- # The criteria for expanding a vertex on the open list is that it has the
245
- # lowest f(v) = g(v) + h(v) value of all vertices on open.
246
- #
247
- # The time complexity of A* depends on the heuristic. It is exponential
248
- # in the worst case, but is polynomial when the heuristic function h
249
- # meets the following condition: |h(x) - h*(x)| < O(log h*(x)) where h*
250
- # is the optimal heuristic, i.e. the exact cost to get from x to the goal.
251
- #
252
- # Also see: http://en.wikipedia.org/wiki/A-star_search_algorithm
253
- #
254
- def astar(start, goal, func, options, &block)
255
- options.instance_eval "def handle_vertex(sym,u) self[sym].call(u) if self[sym]; end"
256
- options.instance_eval "def handle_edge(sym,u,v) self[sym].call(#{edge_class}[u,v]) if self[sym]; end"
257
-
258
- d = { start => 0 }
259
- f = { start => func.call(start) }
260
- color = {start => :gray}
261
- p = Hash.new {|k| p[k] = k}
262
- queue = [start]
263
- block.call(start) if block
264
- until queue.empty?
265
- u = queue.pop
266
- options.handle_vertex(:examine_vertex, u)
267
- adjacent(u).each do |v|
268
- e = edge_class[u,v]
269
- options.handle_edge(:examine_edge, u, v)
270
- w = cost(e, options[:weight])
271
- raise ArgumentError unless w
272
- if d[v].nil? or (w + d[u]) < d[v]
273
- options.handle_edge(:edge_relaxed, u, v)
274
- d[v] = w + d[u]
275
- f[v] = d[v] + func.call(u)
276
- p[v] = u
277
- unless color[v] == :gray
278
- options.handle_vertex(:black_target, v) if color[v] == :black
279
- color[v] = :gray
280
- options.handle_vertex(:discover_vertex, v)
281
- queue << v
282
- block.call(v) if block
283
- return [start]+queue if v == goal
284
- end
285
- else
286
- options.handle_edge(:edge_not_relaxed, u, v)
287
- end
288
- end # adjacent(u)
289
- color[u] = :black
290
- options.handle_vertex(:finish_vertex,u)
291
- end # queue.empty?
292
- nil # failure, on fall through
293
- end # astar
294
-
295
- # Best first has all the same options as astar with func set to h(v) = 0.
296
- # There is an additional option zero which should be defined to zero
297
- # for the operation '+' on the objects used in the computation of cost.
298
- # The parameter zero defaults to 0.
299
- def best_first(start, goal, options, zero=0, &block)
300
- func = Proc.new {|v| zero}
301
- astar(start, goal, func, options, &block)
302
- end
303
-
304
- alias_method :pre_search_method_missing, :method_missing # :nodoc:
305
- def method_missing(sym,*args, &block) # :nodoc:
306
- m1=/^dfs_(\w+)$/.match(sym.to_s)
307
- dfs((args[0] || {}).merge({m1.captures[0].to_sym => block})) if m1
308
- m2=/^bfs_(\w+)$/.match(sym.to_s)
309
- bfs((args[0] || {}).merge({m2.captures[0].to_sym => block})) if m2
310
- pre_search_method_missing(sym, *args, &block) unless m1 or m2
311
- end
312
-
313
- private
314
-
315
- def gratr_search_helper(op, options={}, &block) # :nodoc:
316
- return nil if size == 0
317
- result = []
318
- # Create options hash that handles callbacks
319
- options = {:enter_vertex => block, :start => to_a[0]}.merge(options)
320
- options.instance_eval "def handle_vertex(sym,u) self[sym].call(u) if self[sym]; end"
321
- options.instance_eval "def handle_edge(sym,e) self[sym].call(e) if self[sym]; end"
322
- # Create waiting list that is a queue or stack depending on op specified.
323
- # First entry is the start vertex.
324
- waiting = [options[:start]]
325
- waiting.instance_eval "def next() #{op.to_s}; end"
326
- # Create color map with all set to unvisited except for start vertex
327
- # will be set to waiting
328
- color_map = vertices.inject({}) {|a,v| a[v] = :unvisited; a}
329
- color_map.merge!(waiting[0] => :waiting)
330
- options.handle_vertex(:start_vertex, waiting[0])
331
- options.handle_vertex(:root_vertex, waiting[0])
332
- # Perform the actual search until nothing is waiting
333
- until waiting.empty?
334
- # Loop till the search iterator exhausts the waiting list
335
- visited_edges={} # This prevents retraversing edges in undirected graphs
336
- until waiting.empty?
337
- gratr_search_iteration(options, waiting, color_map, visited_edges, result, op == :pop)
338
- end
339
- # Waiting list is exhausted, see if a new root vertex is available
340
- u=color_map.detect {|key,value| value == :unvisited}
341
- waiting.push(u[0]) if u
342
- options.handle_vertex(:root_vertex, u[0]) if u
343
- end; result
344
- end
345
-
346
- def gratr_search_iteration(options, waiting, color_map, visited_edges, result, recursive=false) # :nodoc:
347
- # Get the next waiting vertex in the list
348
- u = waiting.next
349
- options.handle_vertex(:enter_vertex,u)
350
- result << u
351
- # Examine all adjacent outgoing edges, not previously traversed
352
- adj_proc = options[:adjacent] || self.method(:adjacent).to_proc
353
- adj_proc.call(u,:type => :edges, :direction => :out).reject {|w| visited_edges[w]}.each do |e|
354
- e = e.reverse unless directed? or e.source == u # Preserves directionality where required
355
- v = e.target
356
- options.handle_edge(:examine_edge, e)
357
- visited_edges[e]=true
358
- case color_map[v]
359
- # If it's unvisited it goes into the waiting list
360
- when :unvisited
361
- options.handle_edge(:tree_edge, e)
362
- color_map[v] = :waiting
363
- waiting.push(v)
364
- # If it's recursive (i.e. dfs) then call self
365
- gratr_search_iteration(options, waiting, color_map, visited_edges, result, true) if recursive
366
- when :waiting
367
- options.handle_edge(:back_edge, e)
368
- else
369
- options.handle_edge(:forward_edge, e)
370
- end
371
- end
372
- # Finished with this vertex
373
- options.handle_vertex(:exit_vertex, u)
374
- color_map[u] = :visited
375
- end
376
-
377
- public
378
- # Topological Sort Iterator
379
- #
380
- # The topological sort algorithm creates a linear ordering of the vertices
381
- # such that if edge (u,v) appears in the graph, then u comes before v in
382
- # the ordering. The graph must be a directed acyclic graph (DAG).
383
- #
384
- # The iterator can also be applied to undirected graph or to a DG graph
385
- # which contains a cycle. In this case, the Iterator does not reach all
386
- # vertices. The implementation of acyclic? and cyclic? uses this fact.
387
- #
388
- # Can be called with a block as a standard Ruby iterator, or it can
389
- # be used directly as it will return the result as an Array
390
- def topsort(start = nil, &block)
391
- result = []
392
- go = true
393
- back = Proc.new {|e| go = false }
394
- push = Proc.new {|v| result.unshift(v) if go}
395
- start ||= vertices[0]
396
- dfs({:exit_vertex => push, :back_edge => back, :start => start})
397
- result.each {|v| block.call(v)} if block; result
398
- end
399
-
400
- # Returns true if a graph contains no cycles, false otherwise
401
- def acyclic?() topsort.size == size; end
402
-
403
- # Returns false if a graph contains no cycles, true otherwise
404
- def cyclic?() not acyclic?; end
405
-
406
-
407
- end # Search
408
- end # Graph
409
- end # GRATR