laser 0.7.0.pre1
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.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +14 -0
- data/LICENSE +661 -0
- data/README.md +158 -0
- data/Rakefile +104 -0
- data/VERSION +1 -0
- data/bin/laser +7 -0
- data/design_docs/goals.md +57 -0
- data/design_docs/object_regex.md +426 -0
- data/design_docs/type_annotations.md +80 -0
- data/ext/laser/BasicBlock.cpp +572 -0
- data/ext/laser/BasicBlock.h +118 -0
- data/ext/laser/extconf.rb +3 -0
- data/features/laser.feature +25 -0
- data/features/step_definitions/laser_steps.rb +39 -0
- data/features/support/env.rb +14 -0
- data/features/support/testdata/1_input +1 -0
- data/features/support/testdata/1_output +1 -0
- data/features/support/testdata/2_input +4 -0
- data/features/support/testdata/2_output +4 -0
- data/features/support/testdata/3_input +8 -0
- data/features/support/testdata/3_output +11 -0
- data/features/support/testdata/4_input +5 -0
- data/features/support/testdata/4_output +5 -0
- data/features/support/testdata/5_input +13 -0
- data/laser.gemspec +382 -0
- data/lib/laser.rb +98 -0
- data/lib/laser/analysis/annotations.rb +95 -0
- data/lib/laser/analysis/annotations/annotation_config.yaml +3 -0
- data/lib/laser/analysis/annotations/comment_attachment_annotation.rb +66 -0
- data/lib/laser/analysis/annotations/node_pointers_annotation.rb +36 -0
- data/lib/laser/analysis/annotations/runtime_annotation.rb +55 -0
- data/lib/laser/analysis/argument_expansion.rb +132 -0
- data/lib/laser/analysis/arity.rb +34 -0
- data/lib/laser/analysis/bindings.rb +144 -0
- data/lib/laser/analysis/bootstrap/bootstrap.rb +298 -0
- data/lib/laser/analysis/bootstrap/laser_class.rb +106 -0
- data/lib/laser/analysis/bootstrap/laser_method.rb +255 -0
- data/lib/laser/analysis/bootstrap/laser_module.rb +403 -0
- data/lib/laser/analysis/bootstrap/laser_module_copy.rb +74 -0
- data/lib/laser/analysis/bootstrap/laser_object.rb +69 -0
- data/lib/laser/analysis/bootstrap/laser_proc.rb +150 -0
- data/lib/laser/analysis/bootstrap/laser_singleton_class.rb +44 -0
- data/lib/laser/analysis/comments.rb +35 -0
- data/lib/laser/analysis/control_flow.rb +28 -0
- data/lib/laser/analysis/control_flow/alias_analysis.rb +31 -0
- data/lib/laser/analysis/control_flow/basic_block.rb +105 -0
- data/lib/laser/analysis/control_flow/cfg_builder.rb +2505 -0
- data/lib/laser/analysis/control_flow/cfg_instruction.rb +190 -0
- data/lib/laser/analysis/control_flow/constant_propagation.rb +742 -0
- data/lib/laser/analysis/control_flow/control_flow_graph.rb +370 -0
- data/lib/laser/analysis/control_flow/lifetime_analysis.rb +91 -0
- data/lib/laser/analysis/control_flow/method_call_search.rb +26 -0
- data/lib/laser/analysis/control_flow/raise_properties.rb +25 -0
- data/lib/laser/analysis/control_flow/simulation.rb +385 -0
- data/lib/laser/analysis/control_flow/static_single_assignment.rb +185 -0
- data/lib/laser/analysis/control_flow/unreachability_analysis.rb +57 -0
- data/lib/laser/analysis/control_flow/unused_variables.rb +91 -0
- data/lib/laser/analysis/control_flow/yield_properties.rb +103 -0
- data/lib/laser/analysis/errors.rb +131 -0
- data/lib/laser/analysis/laser_utils.rb +18 -0
- data/lib/laser/analysis/lexical_analysis.rb +172 -0
- data/lib/laser/analysis/method_call.rb +68 -0
- data/lib/laser/analysis/protocol_registry.rb +30 -0
- data/lib/laser/analysis/scope.rb +118 -0
- data/lib/laser/analysis/sexp.rb +159 -0
- data/lib/laser/analysis/sexp_analysis.rb +40 -0
- data/lib/laser/analysis/sexp_extensions/constant_extraction.rb +115 -0
- data/lib/laser/analysis/sexp_extensions/source_location.rb +164 -0
- data/lib/laser/analysis/sexp_extensions/type_inference.rb +47 -0
- data/lib/laser/analysis/signature.rb +76 -0
- data/lib/laser/analysis/special_methods/send.rb +67 -0
- data/lib/laser/analysis/unused_methods.rb +21 -0
- data/lib/laser/analysis/visitor.rb +141 -0
- data/lib/laser/annotation_parser/annotations.treetop +126 -0
- data/lib/laser/annotation_parser/annotations_parser.rb +748 -0
- data/lib/laser/annotation_parser/class_annotations.treetop +82 -0
- data/lib/laser/annotation_parser/class_annotations_parser.rb +654 -0
- data/lib/laser/annotation_parser/overload.treetop +24 -0
- data/lib/laser/annotation_parser/overload_parser.rb +167 -0
- data/lib/laser/annotation_parser/parsers.rb +6 -0
- data/lib/laser/annotation_parser/structural.treetop +37 -0
- data/lib/laser/annotation_parser/structural_parser.rb +406 -0
- data/lib/laser/annotation_parser/useful_parsers.treetop +47 -0
- data/lib/laser/annotation_parser/useful_parsers_parser.rb +674 -0
- data/lib/laser/rake/task.rb +46 -0
- data/lib/laser/runner.rb +189 -0
- data/lib/laser/scanner.rb +169 -0
- data/lib/laser/standard_library/_thread.rb +110 -0
- data/lib/laser/standard_library/abbrev.rb +103 -0
- data/lib/laser/standard_library/array.rb +418 -0
- data/lib/laser/standard_library/base64.rb +91 -0
- data/lib/laser/standard_library/basic_object.rb +55 -0
- data/lib/laser/standard_library/benchmark.rb +556 -0
- data/lib/laser/standard_library/bignum.rb +185 -0
- data/lib/laser/standard_library/cgi.rb +275 -0
- data/lib/laser/standard_library/cgi/cookie.rb +147 -0
- data/lib/laser/standard_library/cgi/core.rb +791 -0
- data/lib/laser/standard_library/cgi/html.rb +1021 -0
- data/lib/laser/standard_library/cgi/session.rb +537 -0
- data/lib/laser/standard_library/cgi/session/pstore.rb +111 -0
- data/lib/laser/standard_library/cgi/util.rb +188 -0
- data/lib/laser/standard_library/class_definitions.rb +333 -0
- data/lib/laser/standard_library/comparable.rb +125 -0
- data/lib/laser/standard_library/complex.rb +162 -0
- data/lib/laser/standard_library/enumerable.rb +178 -0
- data/lib/laser/standard_library/exceptions.rb +135 -0
- data/lib/laser/standard_library/fixnum.rb +188 -0
- data/lib/laser/standard_library/float.rb +180 -0
- data/lib/laser/standard_library/hash.rb +237 -0
- data/lib/laser/standard_library/integer.rb +123 -0
- data/lib/laser/standard_library/laser_magic.rb +7 -0
- data/lib/laser/standard_library/nil_false_true.rb +113 -0
- data/lib/laser/standard_library/numbers.rb +192 -0
- data/lib/laser/standard_library/proc.rb +31 -0
- data/lib/laser/standard_library/set.rb +1348 -0
- data/lib/laser/standard_library/string.rb +666 -0
- data/lib/laser/standard_library/stringio.rb +2 -0
- data/lib/laser/standard_library/symbol.rb +125 -0
- data/lib/laser/standard_library/tsort.rb +242 -0
- data/lib/laser/support/acts_as_struct.rb +66 -0
- data/lib/laser/support/frequency.rb +55 -0
- data/lib/laser/support/inheritable_attributes.rb +145 -0
- data/lib/laser/support/module_extensions.rb +94 -0
- data/lib/laser/support/placeholder_object.rb +13 -0
- data/lib/laser/third_party/rgl/adjacency.rb +221 -0
- data/lib/laser/third_party/rgl/base.rb +228 -0
- data/lib/laser/third_party/rgl/bidirectional.rb +39 -0
- data/lib/laser/third_party/rgl/condensation.rb +47 -0
- data/lib/laser/third_party/rgl/connected_components.rb +138 -0
- data/lib/laser/third_party/rgl/control_flow.rb +170 -0
- data/lib/laser/third_party/rgl/depth_first_spanning_tree.rb +37 -0
- data/lib/laser/third_party/rgl/dominators.rb +124 -0
- data/lib/laser/third_party/rgl/dot.rb +93 -0
- data/lib/laser/third_party/rgl/graphxml.rb +51 -0
- data/lib/laser/third_party/rgl/implicit.rb +174 -0
- data/lib/laser/third_party/rgl/mutable.rb +117 -0
- data/lib/laser/third_party/rgl/rdot.rb +445 -0
- data/lib/laser/third_party/rgl/topsort.rb +72 -0
- data/lib/laser/third_party/rgl/transitivity.rb +180 -0
- data/lib/laser/third_party/rgl/traversal.rb +348 -0
- data/lib/laser/types/types.rb +433 -0
- data/lib/laser/version.rb +14 -0
- data/lib/laser/warning.rb +149 -0
- data/lib/laser/warning_sets/default.yml +13 -0
- data/lib/laser/warnings/assignment_in_condition.rb +20 -0
- data/lib/laser/warnings/comment_spacing.rb +31 -0
- data/lib/laser/warnings/extra_blank_lines.rb +30 -0
- data/lib/laser/warnings/extra_whitespace.rb +16 -0
- data/lib/laser/warnings/hash_symbol_18_warning.rb +63 -0
- data/lib/laser/warnings/hash_symbol_19_warning.rb +29 -0
- data/lib/laser/warnings/line_length.rb +115 -0
- data/lib/laser/warnings/misaligned_unindentation.rb +17 -0
- data/lib/laser/warnings/operator_spacing.rb +68 -0
- data/lib/laser/warnings/parens_on_declaration.rb +30 -0
- data/lib/laser/warnings/rescue_exception.rb +42 -0
- data/lib/laser/warnings/semicolon.rb +25 -0
- data/lib/laser/warnings/sexp_errors.rb +24 -0
- data/lib/laser/warnings/uncalled_method_warning.rb +7 -0
- data/lib/laser/warnings/useless_double_quotes.rb +38 -0
- data/spec/analysis_specs/annotations_spec.rb +47 -0
- data/spec/analysis_specs/annotations_specs/comment_attachment_spec.rb +68 -0
- data/spec/analysis_specs/annotations_specs/node_pointers_annotation_spec.rb +90 -0
- data/spec/analysis_specs/annotations_specs/runtime_annotation_spec.rb +135 -0
- data/spec/analysis_specs/annotations_specs/spec_helper.rb +33 -0
- data/spec/analysis_specs/argument_expansion_spec.rb +113 -0
- data/spec/analysis_specs/bindings_spec.rb +36 -0
- data/spec/analysis_specs/comment_spec.rb +93 -0
- data/spec/analysis_specs/control_flow_specs/cfg_instruction_spec.rb +111 -0
- data/spec/analysis_specs/control_flow_specs/constant_propagation_spec.rb +560 -0
- data/spec/analysis_specs/control_flow_specs/control_flow_graph_spec.rb +5 -0
- data/spec/analysis_specs/control_flow_specs/raise_properties_spec.rb +310 -0
- data/spec/analysis_specs/control_flow_specs/raise_type_inference_spec.rb +301 -0
- data/spec/analysis_specs/control_flow_specs/return_type_inference_spec.rb +431 -0
- data/spec/analysis_specs/control_flow_specs/simulation_spec.rb +158 -0
- data/spec/analysis_specs/control_flow_specs/spec_helper.rb +110 -0
- data/spec/analysis_specs/control_flow_specs/tuple_misuse_inference_spec.rb +125 -0
- data/spec/analysis_specs/control_flow_specs/unreachability_analysis_spec.rb +76 -0
- data/spec/analysis_specs/control_flow_specs/unused_variable_spec.rb +99 -0
- data/spec/analysis_specs/control_flow_specs/yield_properties_spec.rb +372 -0
- data/spec/analysis_specs/error_spec.rb +30 -0
- data/spec/analysis_specs/laser_class_spec.rb +322 -0
- data/spec/analysis_specs/lexical_analysis_spec.rb +184 -0
- data/spec/analysis_specs/protocol_registry_spec.rb +63 -0
- data/spec/analysis_specs/scope_annotation_spec.rb +1013 -0
- data/spec/analysis_specs/scope_spec.rb +126 -0
- data/spec/analysis_specs/sexp_analysis_spec.rb +30 -0
- data/spec/analysis_specs/sexp_extension_specs/constant_extraction_spec.rb +309 -0
- data/spec/analysis_specs/sexp_extension_specs/source_location_spec.rb +231 -0
- data/spec/analysis_specs/sexp_extension_specs/spec_helper.rb +1 -0
- data/spec/analysis_specs/sexp_extension_specs/type_inference_spec.rb +252 -0
- data/spec/analysis_specs/sexp_spec.rb +167 -0
- data/spec/analysis_specs/spec_helper.rb +27 -0
- data/spec/analysis_specs/unused_methods_spec.rb +65 -0
- data/spec/analysis_specs/visitor_spec.rb +64 -0
- data/spec/annotation_parser_specs/annotations_parser_spec.rb +89 -0
- data/spec/annotation_parser_specs/class_annotation_parser_spec.rb +120 -0
- data/spec/annotation_parser_specs/overload_parser_spec.rb +39 -0
- data/spec/annotation_parser_specs/parsers_spec.rb +14 -0
- data/spec/annotation_parser_specs/spec_helper.rb +1 -0
- data/spec/annotation_parser_specs/structural_parser_spec.rb +67 -0
- data/spec/laser_spec.rb +14 -0
- data/spec/rake_specs/spec_helper.rb +1 -0
- data/spec/rake_specs/task_spec.rb +67 -0
- data/spec/runner_spec.rb +207 -0
- data/spec/scanner_spec.rb +75 -0
- data/spec/spec_helper.rb +121 -0
- data/spec/standard_library/exceptions_spec.rb +19 -0
- data/spec/standard_library/globals_spec.rb +14 -0
- data/spec/standard_library/set_spec.rb +31 -0
- data/spec/standard_library/spec_helper.rb +1 -0
- data/spec/standard_library/standard_library_spec.rb +302 -0
- data/spec/support_specs/acts_as_struct_spec.rb +94 -0
- data/spec/support_specs/frequency_spec.rb +23 -0
- data/spec/support_specs/module_extensions_spec.rb +117 -0
- data/spec/support_specs/spec_helper.rb +1 -0
- data/spec/type_specs/spec_helper.rb +1 -0
- data/spec/type_specs/types_spec.rb +133 -0
- data/spec/warning_spec.rb +95 -0
- data/spec/warning_specs/assignment_in_condition_spec.rb +68 -0
- data/spec/warning_specs/comment_spacing_spec.rb +65 -0
- data/spec/warning_specs/extra_blank_lines_spec.rb +70 -0
- data/spec/warning_specs/extra_whitespace_spec.rb +33 -0
- data/spec/warning_specs/hash_symbol_18_warning_spec.rb +89 -0
- data/spec/warning_specs/hash_symbol_19_warning_spec.rb +63 -0
- data/spec/warning_specs/line_length_spec.rb +173 -0
- data/spec/warning_specs/misaligned_unindentation_spec.rb +35 -0
- data/spec/warning_specs/operator_spacing_spec.rb +104 -0
- data/spec/warning_specs/parens_on_declaration_spec.rb +57 -0
- data/spec/warning_specs/rescue_exception_spec.rb +105 -0
- data/spec/warning_specs/semicolon_spec.rb +58 -0
- data/spec/warning_specs/spec_helper.rb +1 -0
- data/spec/warning_specs/useless_double_quotes_spec.rb +74 -0
- data/status_reports/2010/12/2010-12-14.md +163 -0
- data/status_reports/2010/12/2010-12-23.md +298 -0
- data/status_reports/2010/12/2010-12-24.md +6 -0
- data/test/third_party_tests/rgl_tests/TestComponents.rb +65 -0
- data/test/third_party_tests/rgl_tests/TestCycles.rb +61 -0
- data/test/third_party_tests/rgl_tests/TestDirectedGraph.rb +125 -0
- data/test/third_party_tests/rgl_tests/TestDot.rb +18 -0
- data/test/third_party_tests/rgl_tests/TestEdge.rb +34 -0
- data/test/third_party_tests/rgl_tests/TestGraph.rb +71 -0
- data/test/third_party_tests/rgl_tests/TestGraphXML.rb +57 -0
- data/test/third_party_tests/rgl_tests/TestImplicit.rb +52 -0
- data/test/third_party_tests/rgl_tests/TestRdot.rb +863 -0
- data/test/third_party_tests/rgl_tests/TestTransitivity.rb +129 -0
- data/test/third_party_tests/rgl_tests/TestTraversal.rb +220 -0
- data/test/third_party_tests/rgl_tests/TestUnDirectedGraph.rb +102 -0
- data/test/third_party_tests/rgl_tests/examples/north/Graph.log +128 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.0.graphml +28 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.1.graphml +28 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.11.graphml +31 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.12.graphml +27 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.13.graphml +27 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.14.graphml +27 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.15.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.16.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.17.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.19.graphml +37 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.2.graphml +28 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.20.graphml +38 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.22.graphml +43 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.24.graphml +30 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.25.graphml +45 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.27.graphml +38 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.28.graphml +30 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.29.graphml +38 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.3.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.30.graphml +34 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.31.graphml +42 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.34.graphml +42 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.37.graphml +28 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.38.graphml +38 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.39.graphml +36 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.4.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.40.graphml +37 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.41.graphml +37 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.42.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.45.graphml +28 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.46.graphml +32 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.5.graphml +31 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.50.graphml +30 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.56.graphml +29 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.57.graphml +32 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.58.graphml +32 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.6.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.60.graphml +32 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.61.graphml +34 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.62.graphml +34 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.68.graphml +30 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.69.graphml +32 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.7.graphml +29 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.70.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.71.graphml +27 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.72.graphml +28 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.74.graphml +29 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.75.graphml +29 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.78.graphml +27 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.79.graphml +34 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.8.graphml +29 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.80.graphml +34 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.82.graphml +35 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.83.graphml +32 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.85.graphml +34 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.86.graphml +34 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.88.graphml +37 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.89.graphml +29 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.9.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.90.graphml +32 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.91.graphml +31 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.92.graphml +26 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.93.graphml +32 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.10.94.graphml +34 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.12.8.graphml +40 -0
- data/test/third_party_tests/rgl_tests/examples/north/g.14.9.graphml +36 -0
- data/test/third_party_tests/rgl_tests/test_helper.rb +7 -0
- data/test/third_party_tests/test_inheritable_attributes.rb +187 -0
- metadata +470 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# topsort.rb
|
|
2
|
+
|
|
3
|
+
require 'laser/third_party/rgl/traversal'
|
|
4
|
+
|
|
5
|
+
module RGL
|
|
6
|
+
|
|
7
|
+
# Topological Sort Iterator
|
|
8
|
+
#
|
|
9
|
+
# The topological sort algorithm creates a linear ordering of the vertices
|
|
10
|
+
# such that if edge (u,v) appears in the graph, then u comes before v in
|
|
11
|
+
# the ordering. The graph must be a directed acyclic graph (DAG).
|
|
12
|
+
#
|
|
13
|
+
# The iterator can also be applied to undirected graph or to a DG graph
|
|
14
|
+
# which contains a cycle. In this case, the Iterator does not reach all
|
|
15
|
+
# vertices. The implementation of acyclic? uses this fact.
|
|
16
|
+
|
|
17
|
+
class TopsortIterator
|
|
18
|
+
|
|
19
|
+
include GraphIterator
|
|
20
|
+
|
|
21
|
+
def initialize (g)
|
|
22
|
+
super(g)
|
|
23
|
+
set_to_begin
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def set_to_begin # :nodoc:
|
|
27
|
+
@waiting = Array.new
|
|
28
|
+
@inDegrees = Hash.new(0)
|
|
29
|
+
|
|
30
|
+
graph.each_vertex do |u|
|
|
31
|
+
@inDegrees[u] = 0 unless @inDegrees.has_key?(u)
|
|
32
|
+
graph.each_adjacent(u) do |v|
|
|
33
|
+
@inDegrees[v] += 1
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
@inDegrees.each_pair do |v, indegree|
|
|
38
|
+
@waiting.push(v) if indegree.zero?
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def basic_forward # :nodoc:
|
|
43
|
+
u = @waiting.pop
|
|
44
|
+
graph.each_adjacent(u) do |v|
|
|
45
|
+
@inDegrees[v] -= 1
|
|
46
|
+
@waiting.push(v) if @inDegrees[v].zero?
|
|
47
|
+
end
|
|
48
|
+
u
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def at_beginning?; true; end # :nodoc: FIXME
|
|
52
|
+
def at_end?; @waiting.empty?; end # :nodoc:
|
|
53
|
+
|
|
54
|
+
end # class TopsortIterator
|
|
55
|
+
|
|
56
|
+
module Graph
|
|
57
|
+
|
|
58
|
+
# Returns a TopsortIterator.
|
|
59
|
+
|
|
60
|
+
def topsort_iterator
|
|
61
|
+
TopsortIterator.new(self)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Returns true if the graph contains no cycles. This is only meaningful
|
|
65
|
+
# for directed graphs. Returns false for undirected graphs.
|
|
66
|
+
|
|
67
|
+
def acyclic?
|
|
68
|
+
topsort_iterator.count == num_vertices
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end # module Graph
|
|
72
|
+
end # module RGL
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
require 'enumerator'
|
|
2
|
+
|
|
3
|
+
require 'laser/third_party/rgl/adjacency'
|
|
4
|
+
require 'laser/third_party/rgl/base'
|
|
5
|
+
require 'laser/third_party/rgl/connected_components'
|
|
6
|
+
require 'laser/third_party/rgl/condensation'
|
|
7
|
+
|
|
8
|
+
module RGL
|
|
9
|
+
module Graph
|
|
10
|
+
# Returns an RGL::DirectedAdjacencyGraph which is the transitive closure of
|
|
11
|
+
# this graph. Meaning, for each path u -> ... -> v in this graph, the path
|
|
12
|
+
# is copied and the edge u -> v is added. This method supports working with
|
|
13
|
+
# cyclic graphs by ensuring that edges are created between every pair of
|
|
14
|
+
# vertices in the cycle, including self-referencing edges.
|
|
15
|
+
#
|
|
16
|
+
# This method should run in O(|V||E|) time, where |V| and |E| are the number
|
|
17
|
+
# of vertices and edges respectively.
|
|
18
|
+
#
|
|
19
|
+
# Raises RGL::NotDirectedError if run on an undirected graph.
|
|
20
|
+
def transitive_closure
|
|
21
|
+
raise NotDirectedError,
|
|
22
|
+
"transitive_closure only supported for directed graphs" unless directed?
|
|
23
|
+
|
|
24
|
+
# Compute a condensation graph in order to hide cycles.
|
|
25
|
+
cg = condensation_graph
|
|
26
|
+
|
|
27
|
+
# Use a depth first search to calculate the transitive closure over the
|
|
28
|
+
# condensation graph. This ensures that as we traverse up the graph we
|
|
29
|
+
# know the transitive closure of each subgraph rooted at each node
|
|
30
|
+
# starting at the leaves. Subsequent root nodes which consume these
|
|
31
|
+
# subgraphs by way of the nodes' immediate successors can then immediately
|
|
32
|
+
# add edges to the roots of the subgraphs and to every successor of those
|
|
33
|
+
# roots.
|
|
34
|
+
tc_cg = DirectedAdjacencyGraph.new
|
|
35
|
+
cg.depth_first_search do |v|
|
|
36
|
+
# For each vertex v, w, and x where the edges v -> w and w -> x exist in
|
|
37
|
+
# the source graph, add edges v -> w and v -> x to the target graph.
|
|
38
|
+
cg.each_adjacent(v) do |w|
|
|
39
|
+
tc_cg.add_edge(v, w)
|
|
40
|
+
tc_cg.each_adjacent(w) do |x|
|
|
41
|
+
tc_cg.add_edge(v, x)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
# Ensure that a vertex with no in or out edges is added to the graph.
|
|
45
|
+
tc_cg.add_vertex(v)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Expand the condensed transitive closure.
|
|
49
|
+
#
|
|
50
|
+
# For each trivial strongly connected component in the condensed graph,
|
|
51
|
+
# add the single node it contains to the new graph and add edges for each
|
|
52
|
+
# edge the node begins in the original graph.
|
|
53
|
+
# For each NON-trivial strongly connected component in the condensed
|
|
54
|
+
# graph, add each node it contains to the new graph and add edges to
|
|
55
|
+
# every node in the strongly connected component, including self
|
|
56
|
+
# referential edges. Then for each edge of the original graph from any
|
|
57
|
+
# of the contained nodes, add edges from each of the contained nodes to
|
|
58
|
+
# all the edge targets.
|
|
59
|
+
g = DirectedAdjacencyGraph.new
|
|
60
|
+
tc_cg.each_vertex do |scc|
|
|
61
|
+
scc.each do |v|
|
|
62
|
+
# Add edges between all members of non-trivial strongly connected
|
|
63
|
+
# components (size > 1) and ensure that self referential edges are
|
|
64
|
+
# added when necessary for trivial strongly connected components.
|
|
65
|
+
if scc.size > 1 || has_edge?(v, v) then
|
|
66
|
+
scc.each do |w|
|
|
67
|
+
g.add_edge(v, w)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
# Ensure that a vertex with no in or out edges is added to the graph.
|
|
71
|
+
g.add_vertex(v)
|
|
72
|
+
end
|
|
73
|
+
# Add an edge from every member of a strongly connected component to
|
|
74
|
+
# every member of each strongly connected component to which the former
|
|
75
|
+
# points.
|
|
76
|
+
tc_cg.each_adjacent(scc) do |scc2|
|
|
77
|
+
scc.each do |v|
|
|
78
|
+
scc2.each do |w|
|
|
79
|
+
g.add_edge(v, w)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Finally, the transitive closure...
|
|
86
|
+
g
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Returns an RGL::DirectedAdjacencyGraph which is the transitive reduction
|
|
90
|
+
# of this graph. Meaning, that each edge u -> v is omitted if path
|
|
91
|
+
# u -> ... -> v exists. This method supports working with cyclic graphs;
|
|
92
|
+
# however, cycles are arbitrarily simplified which may lead to variant,
|
|
93
|
+
# although equally valid, results on equivalent graphs.
|
|
94
|
+
#
|
|
95
|
+
# This method should run in O(|V||E|) time, where |V| and |E| are the number
|
|
96
|
+
# of vertices and edges respectively.
|
|
97
|
+
#
|
|
98
|
+
# Raises RGL::NotDirectedError if run on an undirected graph.
|
|
99
|
+
def transitive_reduction
|
|
100
|
+
raise NotDirectedError,
|
|
101
|
+
"transitive_reduction only supported for directed graphs" unless directed?
|
|
102
|
+
|
|
103
|
+
# Compute a condensation graph in order to hide cycles.
|
|
104
|
+
cg = condensation_graph
|
|
105
|
+
|
|
106
|
+
# Use a depth first search to compute the transitive reduction over the
|
|
107
|
+
# condensed graph. This is similar to the computation of the transitive
|
|
108
|
+
# closure over the graph in that for any node of the graph all nodes
|
|
109
|
+
# reachable from the node are tracked. Using a depth first search ensures
|
|
110
|
+
# that all nodes reachable from a target node are known when considering
|
|
111
|
+
# whether or not to add an edge pointing to that target.
|
|
112
|
+
tr_cg = DirectedAdjacencyGraph.new
|
|
113
|
+
paths_from = {}
|
|
114
|
+
cg.depth_first_search do |v|
|
|
115
|
+
paths_from[v] = Set.new
|
|
116
|
+
cg.each_adjacent(v) do |w|
|
|
117
|
+
# Only add the edge v -> w if there is no other edge v -> x such that
|
|
118
|
+
# w is reachable from x. Make sure to completely skip the case where
|
|
119
|
+
# x == w.
|
|
120
|
+
unless Enumerator.new(cg, :each_adjacent, v).any? do |x|
|
|
121
|
+
x != w && paths_from[x].include?(w)
|
|
122
|
+
end then
|
|
123
|
+
tr_cg.add_edge(v, w)
|
|
124
|
+
|
|
125
|
+
# For each vertex v, track all nodes reachable from v by adding node
|
|
126
|
+
# w to the list as well as all the nodes readable from w.
|
|
127
|
+
paths_from[v] << w
|
|
128
|
+
paths_from[v].merge(paths_from[w])
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
# Ensure that a vertex with no in or out edges is added to the graph.
|
|
132
|
+
tr_cg.add_vertex(v)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Expand the condensed transitive reduction.
|
|
136
|
+
#
|
|
137
|
+
# For each trivial strongly connected component in the condensed graph,
|
|
138
|
+
# add the single node it contains to the new graph and add edges for each
|
|
139
|
+
# edge the node begins in the original graph.
|
|
140
|
+
# For each NON-trivial strongly connected component in the condensed
|
|
141
|
+
# graph, add each node it contains to the new graph and add arbitrary
|
|
142
|
+
# edges between the nodes to form a simple cycle. Then for each strongly
|
|
143
|
+
# connected component adjacent to the current one, find and add the first
|
|
144
|
+
# edge which exists in the original graph, starts in the first strongly
|
|
145
|
+
# connected component, and ends in the second strongly connected
|
|
146
|
+
# component.
|
|
147
|
+
g = DirectedAdjacencyGraph.new
|
|
148
|
+
tr_cg.each_vertex do |scc|
|
|
149
|
+
# Make a cycle of the contents of non-trivial strongly connected
|
|
150
|
+
# components.
|
|
151
|
+
scc_arr = scc.to_a
|
|
152
|
+
if scc.size > 1 || has_edge?(scc_arr.first, scc_arr.first) then
|
|
153
|
+
0.upto(scc_arr.size - 2) do |idx|
|
|
154
|
+
g.add_edge(scc_arr[idx], scc_arr[idx + 1])
|
|
155
|
+
end
|
|
156
|
+
g.add_edge(scc_arr.last, scc_arr.first)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Choose a single edge between the members of two different strongly
|
|
160
|
+
# connected component to add to the graph.
|
|
161
|
+
edges = Enumerator.new(self, :each_edge)
|
|
162
|
+
tr_cg.each_adjacent(scc) do |scc2|
|
|
163
|
+
g.add_edge(
|
|
164
|
+
*edges.find do |v, w|
|
|
165
|
+
scc.member?(v) && scc2.member?(w)
|
|
166
|
+
end
|
|
167
|
+
)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Ensure that a vertex with no in or out edges is added to the graph.
|
|
171
|
+
scc.each do |v|
|
|
172
|
+
g.add_vertex(v)
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Finally, the transitive reduction...
|
|
177
|
+
g
|
|
178
|
+
end
|
|
179
|
+
end # module Graph
|
|
180
|
+
end # module RGL
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
# traversal.rb
|
|
2
|
+
#
|
|
3
|
+
# This file defines the basic graph traversal algorithm for DFS and BFS search.
|
|
4
|
+
# They are implemented as an RGL::GraphIterator, which is a Stream of vertices
|
|
5
|
+
# of a given graph. The streams are not reversable.
|
|
6
|
+
#
|
|
7
|
+
# Beside being an iterator in the sense of the Stream mixin, RGL::BFSIterator
|
|
8
|
+
# and RGL::DFSIterator follow the BGL
|
|
9
|
+
# Visitor[http://www.boost.org/libs/graph/doc/visitor_concepts.html] Concepts
|
|
10
|
+
# in a slightly modified fashion (especially for the RGL::DFSIterator).
|
|
11
|
+
|
|
12
|
+
require 'laser/third_party/rgl/base'
|
|
13
|
+
require 'stream'
|
|
14
|
+
|
|
15
|
+
module RGL
|
|
16
|
+
|
|
17
|
+
module GraphWrapper # :nodoc:
|
|
18
|
+
|
|
19
|
+
attr_accessor :graph
|
|
20
|
+
|
|
21
|
+
# Creates a new GraphWrapper on _graph_.
|
|
22
|
+
def initialize (graph)
|
|
23
|
+
@graph = graph
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end # module GraphWrapper
|
|
27
|
+
|
|
28
|
+
# A GraphIterator is the abstract superclass of all Iterators on graphs.
|
|
29
|
+
# Each such iterator should implement the protocol defined in module Stream.
|
|
30
|
+
module GraphIterator
|
|
31
|
+
include Stream
|
|
32
|
+
include GraphWrapper
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Module GraphVisitor defines the BGL
|
|
36
|
+
# BFS[http://www.boost.org/libs/graph/doc/BFSVisitor.html] Visitor Concept).
|
|
37
|
+
#
|
|
38
|
+
# Visitors provide a mechanism for extending an algorithm (i.e., for
|
|
39
|
+
# customizing what is done at each step of the algorithm). They allow users
|
|
40
|
+
# to insert their own operations at various steps within a graph algorithm.
|
|
41
|
+
#
|
|
42
|
+
# Graph algorithms typically have multiple event points where one may want to
|
|
43
|
+
# insert a call-back. Therefore, visitors have several methods that
|
|
44
|
+
# correspond to the various event points. Each algorithm has a different
|
|
45
|
+
# set of event points. The following are common to both DFS and BFS search.
|
|
46
|
+
#
|
|
47
|
+
# * examine_vertex
|
|
48
|
+
# * finish_vertex
|
|
49
|
+
# * examine_edge
|
|
50
|
+
# * tree_edge
|
|
51
|
+
# * back_edge
|
|
52
|
+
# * forward_edge
|
|
53
|
+
#
|
|
54
|
+
# These methods are all called handle_* and can be set to appropriate blocks,
|
|
55
|
+
# using the methods set_*_event_handler, which are defined for each event
|
|
56
|
+
# mentioned above.
|
|
57
|
+
#
|
|
58
|
+
# As an alternative, you can also override the handle_* methods in a
|
|
59
|
+
# subclass, to configure the algorithm (as an example, see TarjanSccVisitor).
|
|
60
|
+
#
|
|
61
|
+
# During a graph traversal, vertices are *colored* using the colors :GRAY
|
|
62
|
+
# (when waiting) and :BLACK when finished. All other vertices are :WHITE.
|
|
63
|
+
# The color_map is also maintained in the visitor.
|
|
64
|
+
|
|
65
|
+
module GraphVisitor
|
|
66
|
+
|
|
67
|
+
include GraphWrapper
|
|
68
|
+
|
|
69
|
+
attr_reader :color_map
|
|
70
|
+
|
|
71
|
+
# Create a new GraphVisitor on _graph_.
|
|
72
|
+
|
|
73
|
+
def initialize (graph)
|
|
74
|
+
super graph
|
|
75
|
+
reset
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Mark each vertex unvisited (i.e. :WHITE)
|
|
79
|
+
|
|
80
|
+
def reset
|
|
81
|
+
@color_map = Hash.new(:WHITE)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Returns true if vertex _v_ is colored :BLACK (i.e. finished).
|
|
85
|
+
|
|
86
|
+
def finished_vertex? (v)
|
|
87
|
+
@color_map[v] == :BLACK
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Attach a map to the visitor which records the distance of a visited
|
|
91
|
+
# vertex to the start vertex.
|
|
92
|
+
#
|
|
93
|
+
# This is similar to BGLs
|
|
94
|
+
# distance_recorder[http://www.boost.org/libs/graph/doc/distance_recorder.html].
|
|
95
|
+
#
|
|
96
|
+
# After the distance_map is attached, the visitor has a new method
|
|
97
|
+
# distance_to_root, which answers the distance to the start vertex.
|
|
98
|
+
|
|
99
|
+
def attach_distance_map (map = Hash.new(0))
|
|
100
|
+
@dist_map = map
|
|
101
|
+
|
|
102
|
+
class << self
|
|
103
|
+
|
|
104
|
+
def handle_tree_edge (u, v)
|
|
105
|
+
super
|
|
106
|
+
@dist_map[v] = @dist_map[u] + 1
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Answer the distance to the start vertex.
|
|
110
|
+
|
|
111
|
+
def distance_to_root (v)
|
|
112
|
+
@dist_map[v]
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
end # class
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Shall we follow the edge (u,v); i.e. v has color :WHITE
|
|
119
|
+
|
|
120
|
+
def follow_edge? (u, v) # :nodoc:
|
|
121
|
+
@color_map[v] == :WHITE
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# == Visitor Event Points
|
|
125
|
+
|
|
126
|
+
def self.def_event_handler (m)
|
|
127
|
+
params = m =~ /edge/ ? "u,v" : "u"
|
|
128
|
+
self.class_eval %{
|
|
129
|
+
def handle_#{m} (#{params})
|
|
130
|
+
@#{m}_event_handler.call(#{params}) if defined? @#{m}_event_handler
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def set_#{m}_event_handler (&b)
|
|
134
|
+
@#{m}_event_handler = b
|
|
135
|
+
end
|
|
136
|
+
}
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
%w[examine_vertex finish_vertex examine_edge tree_edge back_edge
|
|
140
|
+
forward_edge].each do |m|
|
|
141
|
+
def_event_handler(m)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
end # module GraphVisitor
|
|
145
|
+
|
|
146
|
+
# A BFSIterator can be used to traverse a graph from a given start vertex in
|
|
147
|
+
# breath first search order. Since the Iterator also mixins the GraphVisitor,
|
|
148
|
+
# it provides all event points defined there.
|
|
149
|
+
#
|
|
150
|
+
# The vertices which are not yet visited are held in the queue @waiting.
|
|
151
|
+
# During the traversal, vertices are *colored* using the colors :GRAY
|
|
152
|
+
# (when waiting) and :BLACK when finished. All other vertices are :WHITE.
|
|
153
|
+
#
|
|
154
|
+
# For more doc see the BGL
|
|
155
|
+
# BFS[http://www.boost.org/libs/graph/doc/BFSVisitor.html] Visitor Concept .
|
|
156
|
+
#
|
|
157
|
+
# See the implementation of bfs_search_tree_from for an example usage.
|
|
158
|
+
|
|
159
|
+
class BFSIterator
|
|
160
|
+
|
|
161
|
+
include GraphIterator
|
|
162
|
+
include GraphVisitor
|
|
163
|
+
|
|
164
|
+
attr_accessor :start_vertex
|
|
165
|
+
|
|
166
|
+
# Create a new BFSIterator on _graph_, starting at vertex _start_.
|
|
167
|
+
|
|
168
|
+
def initialize (graph, start=graph.detect{ |x| true })
|
|
169
|
+
super(graph)
|
|
170
|
+
@start_vertex = start
|
|
171
|
+
set_to_begin
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Returns true if the @color_map has only one entry (for the start vertex).
|
|
175
|
+
|
|
176
|
+
def at_beginning? # :nodoc:
|
|
177
|
+
@color_map.size == 1
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Returns true if @waiting is empty.
|
|
181
|
+
|
|
182
|
+
def at_end?
|
|
183
|
+
@waiting.empty?
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Reset the iterator to the initial state (i.e. at_beginning? == true).
|
|
187
|
+
|
|
188
|
+
def set_to_begin
|
|
189
|
+
color_map[@start_vertex] = :GRAY
|
|
190
|
+
@waiting = [@start_vertex] # a queue
|
|
191
|
+
handle_tree_edge(nil, @start_vertex) # discovers start vertex
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def basic_forward # :nodoc:
|
|
195
|
+
u = next_vertex
|
|
196
|
+
handle_examine_vertex(u)
|
|
197
|
+
graph.each_adjacent(u) { |v|
|
|
198
|
+
handle_examine_edge(u, v)
|
|
199
|
+
if follow_edge?(u, v) # (u,v) is a tree edge
|
|
200
|
+
handle_tree_edge(u, v) # also discovers v
|
|
201
|
+
color_map[v] = :GRAY # color of v was :WHITE
|
|
202
|
+
@waiting.push(v)
|
|
203
|
+
else # (u,v) is a non tree edge
|
|
204
|
+
if color_map[v] == :GRAY
|
|
205
|
+
handle_back_edge(u, v) # (u,v) has gray target
|
|
206
|
+
else
|
|
207
|
+
handle_forward_edge(u, v) # (u,v) has black target
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
}
|
|
211
|
+
color_map[u] = :BLACK
|
|
212
|
+
handle_finish_vertex(u) # finish vertex
|
|
213
|
+
u
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
protected
|
|
217
|
+
|
|
218
|
+
def next_vertex # :nodoc:
|
|
219
|
+
# waiting is a queue
|
|
220
|
+
@waiting.shift
|
|
221
|
+
end
|
|
222
|
+
end # class BFSIterator
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
module Graph
|
|
226
|
+
|
|
227
|
+
# Returns a BFSIterator, starting at vertex _v_.
|
|
228
|
+
|
|
229
|
+
def bfs_iterator (v = self.detect { |x| true})
|
|
230
|
+
BFSIterator.new(self, v)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# Returns a DirectedAdjacencyGraph, which represents a BFS search tree
|
|
234
|
+
# starting at _v_. This method uses the tree_edge_event of BFSIterator
|
|
235
|
+
# to record all tree edges of the search tree in the result.
|
|
236
|
+
|
|
237
|
+
def bfs_search_tree_from (v)
|
|
238
|
+
require 'laser/third_party/rgl/adjacency'
|
|
239
|
+
bfs = bfs_iterator(v)
|
|
240
|
+
tree = DirectedAdjacencyGraph.new
|
|
241
|
+
bfs.set_tree_edge_event_handler { |from, to|
|
|
242
|
+
tree.add_edge(from, to)
|
|
243
|
+
}
|
|
244
|
+
bfs.set_to_end # does the search
|
|
245
|
+
tree
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
end # module Graph
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
# Iterator for a depth first search, starting at a given vertex. The only
|
|
252
|
+
# difference from BFSIterator is that @waiting is a stack, instead of a queue.
|
|
253
|
+
#
|
|
254
|
+
# Note that this is different from DFSVisitor, which is used in the recursive
|
|
255
|
+
# version for depth first search (see depth_first_search).
|
|
256
|
+
|
|
257
|
+
class DFSIterator < BFSIterator
|
|
258
|
+
|
|
259
|
+
def next_vertex
|
|
260
|
+
# waiting is a stack
|
|
261
|
+
@waiting.pop
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
end # class DFSIterator
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
# A DFSVisitor is needed by the depth_first_search and depth_first_visit
|
|
268
|
+
# methods of a graph. Besides the eventpoint of GraphVisitor, it provides
|
|
269
|
+
# an additional eventpoint start_vertex, which is called when a
|
|
270
|
+
# depth_first_search starts a new subtree of the depth first forest that is
|
|
271
|
+
# defined by the search.
|
|
272
|
+
#
|
|
273
|
+
# Note that the discover_vertex event defined in the BGL
|
|
274
|
+
# DFSVisitor[http://www.boost.org/libs/graph/doc/DFSVisitor.html] is not
|
|
275
|
+
# this is also defined in the common mixin GraphVisitor of DFSVisitor,
|
|
276
|
+
# DFSIterator, and BFSIterator.
|
|
277
|
+
|
|
278
|
+
class DFSVisitor
|
|
279
|
+
|
|
280
|
+
include GraphVisitor
|
|
281
|
+
|
|
282
|
+
GraphVisitor.def_event_handler("start_vertex")
|
|
283
|
+
|
|
284
|
+
end # class DFSVisitor
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
module Graph
|
|
288
|
+
|
|
289
|
+
# Returns a DFSIterator staring at vertex _v_.
|
|
290
|
+
|
|
291
|
+
def dfs_iterator (v = self.detect { |x| true })
|
|
292
|
+
DFSIterator.new(self, v)
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# Do a recursive DFS search on the whole graph. If a block is passed,
|
|
296
|
+
# it is called on each _finish_vertex_ event. See
|
|
297
|
+
# strongly_connected_components for an example usage.
|
|
298
|
+
|
|
299
|
+
def depth_first_search (vis = DFSVisitor.new(self), &b)
|
|
300
|
+
each_vertex do |u|
|
|
301
|
+
unless vis.finished_vertex?(u)
|
|
302
|
+
vis.handle_start_vertex(u)
|
|
303
|
+
depth_first_visit(u, vis, &b)
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
# Start a depth first search at vertex _u_. The block _b_ is called on
|
|
309
|
+
# each finish_vertex event.
|
|
310
|
+
|
|
311
|
+
def depth_first_visit (u, vis = DFSVisitor.new(self), &b)
|
|
312
|
+
vis.color_map[u] = :GRAY
|
|
313
|
+
vis.handle_examine_vertex(u)
|
|
314
|
+
each_adjacent(u) { |v|
|
|
315
|
+
vis.handle_examine_edge(u, v)
|
|
316
|
+
if vis.follow_edge?(u, v) # (u,v) is a tree edge
|
|
317
|
+
vis.handle_tree_edge(u, v) # also discovers v
|
|
318
|
+
vis.color_map[v] = :GRAY # color of v was :WHITE
|
|
319
|
+
depth_first_visit(v, vis, &b)
|
|
320
|
+
else # (u,v) is a non tree edge
|
|
321
|
+
if vis.color_map[v] == :GRAY
|
|
322
|
+
vis.handle_back_edge(u, v) # (u,v) has gray target
|
|
323
|
+
else
|
|
324
|
+
vis.handle_forward_edge(u, v) # (u,v) is a cross or forward edge
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
}
|
|
328
|
+
vis.color_map[u] = :BLACK
|
|
329
|
+
vis.handle_finish_vertex(u) # finish vertex
|
|
330
|
+
b.call(u)
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
end # module Graph
|
|
334
|
+
|
|
335
|
+
=begin
|
|
336
|
+
def acyclic?
|
|
337
|
+
has_cycle = false
|
|
338
|
+
dfs = DFSIterator.new(self)
|
|
339
|
+
dfs.set_back_edge_event {has_cycle = true}
|
|
340
|
+
dfs_each(dfs) do |x|
|
|
341
|
+
puts x,has_cycle,dfs.inspect
|
|
342
|
+
return false if has_cycle
|
|
343
|
+
end
|
|
344
|
+
true
|
|
345
|
+
end
|
|
346
|
+
=end
|
|
347
|
+
|
|
348
|
+
end # module RGL
|