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.
- data/CHANGELOG +94 -0
- data/Rakefile +0 -4
- data/bin/puppet +18 -10
- data/bin/puppetd +1 -1
- data/bin/puppetdoc +14 -4
- data/bin/puppetmasterd +1 -1
- data/bin/puppetrun +3 -8
- data/bin/ralsh +12 -11
- data/conf/freebsd/puppetd +1 -1
- data/conf/freebsd/puppetmasterd +1 -1
- data/conf/gentoo/puppet/puppet.conf +29 -0
- data/conf/namespaceauth.conf +20 -0
- data/conf/redhat/puppet.spec +4 -1
- data/conf/solaris/smf/puppetd.xml +1 -1
- data/conf/solaris/smf/puppetmasterd.xml +1 -1
- data/conf/suse/puppet.spec +10 -8
- data/examples/root/etc/puppet/{puppetmasterd.conf → puppet.conf} +6 -3
- data/ext/logcheck/puppet +7 -0
- data/ext/puppet-test +28 -5
- data/lib/puppet.rb +2 -1
- data/lib/puppet/defaults.rb +12 -5
- data/lib/puppet/dsl.rb +43 -45
- data/lib/puppet/external/{gratr/rdot.rb → dot.rb} +0 -0
- data/lib/puppet/external/nagios.rb +50 -0
- data/lib/puppet/external/nagios/base.rb +421 -0
- data/lib/puppet/external/nagios/parser.rb +816 -0
- data/lib/puppet/file_serving/file_base.rb +16 -3
- data/lib/puppet/file_serving/metadata.rb +29 -11
- data/lib/puppet/indirector/terminus.rb +1 -0
- data/lib/puppet/metatype/closure.rb +4 -0
- data/lib/puppet/metatype/evaluation.rb +2 -17
- data/lib/puppet/metatype/metaparams.rb +1 -1
- data/lib/puppet/network.rb +3 -0
- data/lib/puppet/network/client.rb +4 -5
- data/lib/puppet/network/client/master.rb +10 -7
- data/lib/puppet/network/handler/fileserver.rb +22 -45
- data/lib/puppet/network/http_pool.rb +3 -0
- data/lib/puppet/network/http_server/mongrel.rb +7 -1
- data/lib/puppet/network/http_server/webrick.rb +4 -3
- data/lib/puppet/network/xmlrpc/client.rb +12 -1
- data/lib/puppet/node/catalog.rb +51 -40
- data/lib/puppet/parser/ast.rb +27 -49
- data/lib/puppet/parser/ast/astarray.rb +5 -24
- data/lib/puppet/parser/ast/caseopt.rb +4 -4
- data/lib/puppet/parser/ast/casestatement.rb +4 -5
- data/lib/puppet/parser/ast/collection.rb +3 -5
- data/lib/puppet/parser/ast/collexpr.rb +3 -5
- data/lib/puppet/parser/ast/definition.rb +148 -159
- data/lib/puppet/parser/ast/else.rb +2 -3
- data/lib/puppet/parser/ast/function.rb +3 -10
- data/lib/puppet/parser/ast/hostclass.rb +66 -59
- data/lib/puppet/parser/ast/ifstatement.rb +4 -5
- data/lib/puppet/parser/ast/leaf.rb +6 -6
- data/lib/puppet/parser/ast/node.rb +26 -58
- data/lib/puppet/parser/ast/resource.rb +5 -7
- data/lib/puppet/parser/ast/resource_defaults.rb +2 -4
- data/lib/puppet/parser/ast/resource_override.rb +4 -6
- data/lib/puppet/parser/ast/resource_reference.rb +2 -4
- data/lib/puppet/parser/ast/resourceparam.rb +2 -4
- data/lib/puppet/parser/ast/selector.rb +5 -6
- data/lib/puppet/parser/ast/tag.rb +2 -4
- data/lib/puppet/parser/ast/vardef.rb +3 -4
- data/lib/puppet/parser/collector.rb +5 -5
- data/lib/puppet/parser/{compile.rb → compiler.rb} +69 -107
- data/lib/puppet/parser/functions.rb +3 -3
- data/lib/puppet/parser/interpreter.rb +32 -23
- data/lib/puppet/parser/lexer.rb +391 -282
- data/lib/puppet/parser/parser.rb +5 -4
- data/lib/puppet/parser/parser_support.rb +3 -6
- data/lib/puppet/parser/resource.rb +24 -36
- data/lib/puppet/parser/resource/param.rb +1 -1
- data/lib/puppet/parser/resource/reference.rb +7 -3
- data/lib/puppet/parser/scope.rb +12 -7
- data/lib/puppet/parser/templatewrapper.rb +1 -1
- data/lib/puppet/pgraph.rb +9 -98
- data/lib/puppet/provider/interface/redhat.rb +65 -65
- data/lib/puppet/provider/mount/parsed.rb +1 -1
- data/lib/puppet/provider/naginator.rb +55 -0
- data/lib/puppet/provider/nameservice/directoryservice.rb +6 -7
- data/lib/puppet/provider/package/fink.rb +0 -2
- data/lib/puppet/provider/package/gem.rb +9 -5
- data/lib/puppet/provider/package/openbsd.rb +1 -1
- data/lib/puppet/provider/package/pkgdmg.rb +3 -8
- data/lib/puppet/provider/package/portage.rb +4 -4
- data/lib/puppet/provider/package/yumhelper.py +8 -6
- data/lib/puppet/provider/parsedfile.rb +7 -1
- data/lib/puppet/provider/service/debian.rb +2 -0
- data/lib/puppet/provider/service/gentoo.rb +4 -0
- data/lib/puppet/provider/service/init.rb +1 -1
- data/lib/puppet/provider/sshkey/parsed.rb +2 -0
- data/lib/puppet/provider/user/useradd.rb +1 -1
- data/lib/puppet/rails.rb +4 -0
- data/lib/puppet/rails/database/001_add_created_at_to_all_tables.rb +17 -0
- data/lib/puppet/rails/fact_value.rb +4 -0
- data/lib/puppet/rails/host.rb +1 -2
- data/lib/puppet/rails/param_value.rb +4 -0
- data/lib/puppet/rails/resource_tag.rb +4 -0
- data/lib/puppet/rails/source_file.rb +4 -1
- data/lib/puppet/relationship.rb +5 -1
- data/lib/puppet/reports/tagmail.rb +12 -1
- data/lib/puppet/resource_reference.rb +1 -1
- data/lib/puppet/simple_graph.rb +78 -11
- data/lib/puppet/sslcertificates.rb +1 -1
- data/lib/puppet/sslcertificates/ca.rb +3 -3
- data/lib/puppet/transaction.rb +7 -4
- data/lib/puppet/transportable.rb +1 -1
- data/lib/puppet/type.rb +3 -10
- data/lib/puppet/type/cron.rb +18 -0
- data/lib/puppet/type/exec.rb +18 -12
- data/lib/puppet/type/{pfile.rb → file.rb} +66 -84
- data/lib/puppet/type/file/checksum.rb +271 -0
- data/lib/puppet/type/{pfile → file}/content.rb +10 -15
- data/lib/puppet/type/{pfile → file}/ensure.rb +15 -8
- data/lib/puppet/type/{pfile → file}/group.rb +0 -0
- data/lib/puppet/type/{pfile → file}/mode.rb +0 -0
- data/lib/puppet/type/{pfile → file}/owner.rb +0 -0
- data/lib/puppet/type/{pfile → file}/source.rb +34 -48
- data/lib/puppet/type/{pfile → file}/target.rb +0 -0
- data/lib/puppet/type/{pfile → file}/type.rb +0 -0
- data/lib/puppet/type/{pfilebucket.rb → filebucket.rb} +0 -0
- data/lib/puppet/type/host.rb +13 -0
- data/lib/puppet/type/mailalias.rb +1 -1
- data/lib/puppet/type/nagios_command.rb +3 -0
- data/lib/puppet/type/nagios_contact.rb +3 -0
- data/lib/puppet/type/nagios_contactgroup.rb +3 -0
- data/lib/puppet/type/nagios_host.rb +3 -0
- data/lib/puppet/type/nagios_hostextinfo.rb +3 -0
- data/lib/puppet/type/nagios_hostgroup.rb +3 -0
- data/lib/puppet/type/nagios_hostgroupescalation.rb +3 -0
- data/lib/puppet/type/nagios_service.rb +3 -0
- data/lib/puppet/type/nagios_servicedependency.rb +3 -0
- data/lib/puppet/type/nagios_serviceescalation.rb +3 -0
- data/lib/puppet/type/nagios_serviceextinfo.rb +3 -0
- data/lib/puppet/type/nagios_timeperiod.rb +3 -0
- data/lib/puppet/type/package.rb +4 -12
- data/lib/puppet/type/service.rb +9 -0
- data/lib/puppet/type/sshkey.rb +3 -3
- data/lib/puppet/util/autoload.rb +5 -5
- data/lib/puppet/util/checksums.rb +51 -13
- data/lib/puppet/util/constant_inflector.rb +14 -0
- data/lib/puppet/util/filetype.rb +1 -1
- data/lib/puppet/util/graph.rb +3 -9
- data/lib/puppet/util/nagios_maker.rb +57 -0
- data/lib/puppet/util/settings.rb +19 -16
- data/lib/puppet/util/tagging.rb +39 -0
- data/test/executables/puppetbin.rb +17 -0
- data/test/language/ast.rb +8 -58
- data/test/language/ast/casestatement.rb +3 -3
- data/test/language/ast/resource.rb +6 -7
- data/test/language/ast/resource_reference.rb +12 -12
- data/test/language/ast/selector.rb +2 -2
- data/test/language/ast/variable.rb +2 -2
- data/test/language/functions.rb +24 -24
- data/test/language/parser.rb +20 -8
- data/test/language/resource.rb +5 -42
- data/test/language/scope.rb +21 -37
- data/test/language/snippets.rb +7 -0
- data/test/lib/puppettest.rb +28 -14
- data/test/lib/puppettest/parsertesting.rb +10 -10
- data/test/lib/puppettest/support/resources.rb +1 -1
- data/test/network/client/master.rb +10 -0
- data/test/network/handler/fileserver.rb +51 -49
- data/test/network/server/webrick.rb +1 -1
- data/test/other/dsl.rb +3 -4
- data/test/other/transactions.rb +6 -4
- data/test/rails/ast.rb +2 -2
- data/test/rails/configuration.rb +1 -1
- data/test/rails/railsparameter.rb +2 -0
- data/test/rails/railsresource.rb +1 -0
- data/test/ral/manager/type.rb +4 -4
- data/test/ral/providers/cron/crontab.rb +3 -1
- data/test/ral/providers/package.rb +1 -1
- data/test/ral/{types → type}/basic.rb +2 -2
- data/test/ral/{types → type}/cron.rb +0 -0
- data/test/ral/{types → type}/exec.rb +42 -2
- data/test/ral/{types → type}/file.rb +34 -79
- data/test/ral/{types → type}/file/target.rb +0 -0
- data/test/ral/{types → type}/filebucket.rb +0 -0
- data/test/ral/{types → type}/fileignoresource.rb +0 -0
- data/test/ral/{types → type}/filesources.rb +8 -27
- data/test/ral/{types → type}/group.rb +0 -0
- data/test/ral/{types → type}/host.rb +16 -0
- data/test/ral/{types → type}/mailalias.rb +0 -0
- data/test/ral/{types → type}/parameter.rb +0 -0
- data/test/ral/{types → type}/port.rb +0 -0
- data/test/ral/{types → type}/property.rb +0 -0
- data/test/ral/{types → type}/resources.rb +0 -0
- data/test/ral/{types → type}/service.rb +0 -0
- data/test/ral/{types → type}/sshkey.rb +0 -0
- data/test/ral/{types → type}/tidy.rb +1 -0
- data/test/ral/{types → type}/user.rb +0 -0
- data/test/ral/{types → type}/yumrepo.rb +0 -0
- data/test/ral/{types → type}/zone.rb +0 -0
- data/test/util/autoload.rb +24 -5
- metadata +60 -107
- data/conf/gentoo/puppet/puppetca.conf +0 -29
- data/conf/gentoo/puppet/puppetd.conf +0 -29
- data/conf/gentoo/puppet/puppetmasterd.conf +0 -29
- data/examples/root/etc/puppet/puppetd.conf +0 -4
- data/lib/puppet/external/gratr.rb +0 -33
- data/lib/puppet/external/gratr/adjacency_graph.rb +0 -257
- data/lib/puppet/external/gratr/base.rb +0 -34
- data/lib/puppet/external/gratr/biconnected.rb +0 -116
- data/lib/puppet/external/gratr/chinese_postman.rb +0 -123
- data/lib/puppet/external/gratr/common.rb +0 -73
- data/lib/puppet/external/gratr/comparability.rb +0 -92
- data/lib/puppet/external/gratr/digraph.rb +0 -116
- data/lib/puppet/external/gratr/digraph_distance.rb +0 -185
- data/lib/puppet/external/gratr/dot.rb +0 -90
- data/lib/puppet/external/gratr/edge.rb +0 -145
- data/lib/puppet/external/gratr/graph.rb +0 -303
- data/lib/puppet/external/gratr/graph_api.rb +0 -83
- data/lib/puppet/external/gratr/import.rb +0 -44
- data/lib/puppet/external/gratr/labels.rb +0 -90
- data/lib/puppet/external/gratr/maximum_flow.rb +0 -64
- data/lib/puppet/external/gratr/search.rb +0 -409
- data/lib/puppet/external/gratr/strong_components.rb +0 -127
- data/lib/puppet/external/gratr/undirected_graph.rb +0 -153
- data/lib/puppet/rails/external/tagging/acts_as_taggable.rb +0 -62
- data/lib/puppet/rails/external/tagging/init.rb +0 -5
- data/lib/puppet/rails/external/tagging/tag.rb +0 -50
- data/lib/puppet/rails/external/tagging/tagging.rb +0 -12
- data/lib/puppet/rails/puppet_class.rb +0 -6
- data/lib/puppet/reference/node_source.rb +0 -9
- data/lib/puppet/reference/report.rb +0 -21
- data/lib/puppet/type/pfile/checksum.rb +0 -326
- data/test/language/ast/definition.rb +0 -166
- data/test/language/ast/hostclass.rb +0 -184
- data/test/language/compile.rb +0 -569
- data/test/language/lexer.rb +0 -276
- data/test/lib/mocha.rb +0 -19
- data/test/lib/mocha/any_instance_method.rb +0 -35
- data/test/lib/mocha/auto_verify.rb +0 -113
- data/test/lib/mocha/central.rb +0 -35
- data/test/lib/mocha/class_method.rb +0 -62
- data/test/lib/mocha/deprecation.rb +0 -22
- data/test/lib/mocha/exception_raiser.rb +0 -17
- data/test/lib/mocha/expectation.rb +0 -378
- data/test/lib/mocha/expectation_error.rb +0 -6
- data/test/lib/mocha/infinite_range.rb +0 -25
- data/test/lib/mocha/inspect.rb +0 -39
- data/test/lib/mocha/instance_method.rb +0 -8
- data/test/lib/mocha/is_a.rb +0 -9
- data/test/lib/mocha/metaclass.rb +0 -7
- data/test/lib/mocha/missing_expectation.rb +0 -27
- data/test/lib/mocha/mock.rb +0 -207
- data/test/lib/mocha/multiple_yields.rb +0 -20
- data/test/lib/mocha/no_yields.rb +0 -11
- data/test/lib/mocha/object.rb +0 -110
- data/test/lib/mocha/parameter_matchers.rb +0 -9
- data/test/lib/mocha/parameter_matchers/all_of.rb +0 -39
- data/test/lib/mocha/parameter_matchers/any_of.rb +0 -44
- data/test/lib/mocha/parameter_matchers/anything.rb +0 -30
- data/test/lib/mocha/parameter_matchers/has_entry.rb +0 -39
- data/test/lib/mocha/parameter_matchers/has_key.rb +0 -39
- data/test/lib/mocha/parameter_matchers/has_value.rb +0 -39
- data/test/lib/mocha/parameter_matchers/includes.rb +0 -37
- data/test/lib/mocha/pretty_parameters.rb +0 -28
- data/test/lib/mocha/return_values.rb +0 -31
- data/test/lib/mocha/setup_and_teardown.rb +0 -23
- data/test/lib/mocha/single_return_value.rb +0 -24
- data/test/lib/mocha/single_yield.rb +0 -18
- data/test/lib/mocha/standalone.rb +0 -32
- data/test/lib/mocha/stub.rb +0 -18
- data/test/lib/mocha/test_case_adapter.rb +0 -49
- 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
|