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,228 @@
|
|
|
1
|
+
# base.rb
|
|
2
|
+
#
|
|
3
|
+
# Module RGL defines the namespace for all modules and classes of the graph
|
|
4
|
+
# library. The main module is RGL::Graph which defines the abstract behavior of
|
|
5
|
+
# all graphs in the library.
|
|
6
|
+
|
|
7
|
+
RGL_VERSION = "0.4.0"
|
|
8
|
+
|
|
9
|
+
module RGL
|
|
10
|
+
class NotDirectedError < RuntimeError; end
|
|
11
|
+
class NotUndirectedError < RuntimeError; end
|
|
12
|
+
|
|
13
|
+
class NoVertexError < IndexError; end
|
|
14
|
+
class NoEdgeError < IndexError; end
|
|
15
|
+
|
|
16
|
+
# Module Edge includes classes for representing egdes of directed and
|
|
17
|
+
# undirected graphs. There is no need for a Vertex class, because every ruby
|
|
18
|
+
# object can be a vertex of a graph.
|
|
19
|
+
module Edge
|
|
20
|
+
# Simply a directed pair (source -> target). Most library functions try do
|
|
21
|
+
# omit to instantiate edges. They instead use two vertex parameters for
|
|
22
|
+
# representing edges (see each_edge). If a client wants to store edges
|
|
23
|
+
# explicitly DirecteEdge or UnDirectedEdge instances are returned
|
|
24
|
+
# (i.e. Graph#edges).
|
|
25
|
+
class DirectedEdge
|
|
26
|
+
attr_accessor :source, :target
|
|
27
|
+
|
|
28
|
+
# Can be used to create an edge from a two element array.
|
|
29
|
+
def self.[](*a)
|
|
30
|
+
new(a[0],a[1])
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Create a new DirectedEdge with source _a_ and target _b_.
|
|
34
|
+
def initialize (a,b)
|
|
35
|
+
@source, @target = a,b
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Two directed edges (u,v) and (x,y) are equal iff u == x and v == y. eql?
|
|
39
|
+
# is needed when edges are inserted into a Set. eql? is aliased to ==.
|
|
40
|
+
def eql?(edge)
|
|
41
|
+
source == edge.source and target == edge.target
|
|
42
|
+
end
|
|
43
|
+
alias == eql?
|
|
44
|
+
|
|
45
|
+
# Returns (v,u) if self == (u,v).
|
|
46
|
+
def reverse
|
|
47
|
+
self.class.new(target, source)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Edges can be indexed. edge[0] == edge.source, edge[n] == edge.target for
|
|
51
|
+
# all n>0. Edges can thus be used as a two element array.
|
|
52
|
+
def [](index); index.zero? ? source : target; end
|
|
53
|
+
|
|
54
|
+
# DirectedEdge[1,2].to_s == "(1-2)"
|
|
55
|
+
def to_s
|
|
56
|
+
"(#{source}-#{target})"
|
|
57
|
+
end
|
|
58
|
+
# Returns the array [source,target].
|
|
59
|
+
def to_a; [source,target]; end
|
|
60
|
+
|
|
61
|
+
# Sort support is dispatched to the <=> method of Array
|
|
62
|
+
def <=> e
|
|
63
|
+
self.to_a <=> e.to_a
|
|
64
|
+
end
|
|
65
|
+
end # DirectedEdge
|
|
66
|
+
|
|
67
|
+
# An undirected edge is simply an undirected pair (source, target) used in
|
|
68
|
+
# undirected graphs. UnDirectedEdge[u,v] == UnDirectedEdge[v,u]
|
|
69
|
+
class UnDirectedEdge < DirectedEdge
|
|
70
|
+
def eql?(edge)
|
|
71
|
+
super or (target == edge.source and source == edge.target)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def hash
|
|
75
|
+
source.hash ^ target.hash
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# UnDirectedEdge[1,2].to_s == "(1=2)"
|
|
79
|
+
def to_s; "(#{source}=#{target})"; end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
end # Edge
|
|
83
|
+
|
|
84
|
+
# In BGL terminology the module Graph defines the graph concept (see
|
|
85
|
+
# http://www.boost.org/libs/graph/doc/graph_concepts.html). We however do not
|
|
86
|
+
# distinguish between the IncidenceGraph, EdgeListGraph and VertexListGraph
|
|
87
|
+
# concepts, which would complicate the interface too much. These concepts are
|
|
88
|
+
# defined in BGL to differentiate between efficient access to edges and
|
|
89
|
+
# vertices.
|
|
90
|
+
#
|
|
91
|
+
# The RGL Graph concept contains only a few requirements that are common to
|
|
92
|
+
# all the graph concepts. These include, especially, the iterators defining
|
|
93
|
+
# the sets of vertices and edges (see each_vertex and each_adjacent). Most
|
|
94
|
+
# other functions are derived from these fundamental iterators, i.e.
|
|
95
|
+
# num_vertices or num_edges.
|
|
96
|
+
#
|
|
97
|
+
# Each graph is an enumerable of vertices.
|
|
98
|
+
module Graph
|
|
99
|
+
include Enumerable
|
|
100
|
+
include Edge
|
|
101
|
+
|
|
102
|
+
# The each_vertex iterator defines the set of vertices. This method must be
|
|
103
|
+
# defined by concrete graph classes. It defines the BGL VertexListGraph
|
|
104
|
+
# concept.
|
|
105
|
+
def each_vertex () # :yields: v
|
|
106
|
+
raise NotImplementedError
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# The each_adjacent iterator defines the out edges of vertex _v_. This
|
|
110
|
+
# method must be defined by concrete graph classes. Its defines the BGL
|
|
111
|
+
# IncidenceGraph concept.
|
|
112
|
+
def each_adjacent (v) # :yields: v
|
|
113
|
+
raise NotImplementedError
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# The each_edge iterator should provide efficient access to all edges of the
|
|
117
|
+
# graph. Its defines the EdgeListGraph concept.
|
|
118
|
+
#
|
|
119
|
+
# This method must _not_ be defined by concrete graph classes, because it
|
|
120
|
+
# can be implemented using each_vertex and each_adjacent. However for
|
|
121
|
+
# undirected graph the function is inefficient because we must not yield
|
|
122
|
+
# (v,u) if we already visited edge (u,v).
|
|
123
|
+
def each_edge (&block)
|
|
124
|
+
if directed?
|
|
125
|
+
each_vertex { |u|
|
|
126
|
+
each_adjacent(u) { |v| yield u,v }
|
|
127
|
+
}
|
|
128
|
+
else
|
|
129
|
+
each_edge_aux(&block) # concrete graphs should to this better
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Vertices get enumerated. A graph is thus an enumerable of vertices.
|
|
134
|
+
# ---
|
|
135
|
+
# === Testing
|
|
136
|
+
def each(&block); each_vertex(&block); end
|
|
137
|
+
|
|
138
|
+
# Is the graph directed? The default returns false.
|
|
139
|
+
def directed?; false; end
|
|
140
|
+
|
|
141
|
+
# Returns true if _v_ is a vertex of the graph. Same as #include? inherited
|
|
142
|
+
# from Enumerable. Complexity is O(num_vertices) by default. Concrete graph
|
|
143
|
+
# may be better here (see AdjacencyGraph).
|
|
144
|
+
def has_vertex?(v); include?(v); end # inherited from enumerable
|
|
145
|
+
|
|
146
|
+
# Returns true if the graph has no vertices, i.e. num_vertices == 0.
|
|
147
|
+
# ---
|
|
148
|
+
# === accessing vertices and edges
|
|
149
|
+
def empty?; num_vertices.zero?; end
|
|
150
|
+
|
|
151
|
+
# Return the array of vertices. Synonym for #to_a inherited by Enumerable.
|
|
152
|
+
def vertices; to_a; end
|
|
153
|
+
|
|
154
|
+
# Returns the class for edges: DirectedEdge or UnDirectedEdge.
|
|
155
|
+
def edge_class; directed? ? DirectedEdge : UnDirectedEdge; end
|
|
156
|
+
|
|
157
|
+
# Return the array of edges (DirectedEdge or UnDirectedEdge) of the graph
|
|
158
|
+
# using each_edge, depending whether the graph is directed or not.
|
|
159
|
+
def edges
|
|
160
|
+
result = []
|
|
161
|
+
c = edge_class
|
|
162
|
+
each_edge { |u,v| result << c.new(u,v) }
|
|
163
|
+
result
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Returns an array of vertices adjacent to vertex _v_.
|
|
167
|
+
def adjacent_vertices (v)
|
|
168
|
+
r = []
|
|
169
|
+
each_adjacent(v) { |u| r << u }
|
|
170
|
+
r
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Returns the number of out-edges (for directed graphs) or the number of
|
|
174
|
+
# incident edges (for undirected graphs) of vertex _v_.
|
|
175
|
+
def out_degree (v)
|
|
176
|
+
r = 0
|
|
177
|
+
each_adjacent(v) { |u| r += 1}
|
|
178
|
+
r
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Returns the number of vertices.
|
|
182
|
+
def size() # Why not in Enumerable?
|
|
183
|
+
inject(0) { |n, v| n + 1 }
|
|
184
|
+
end
|
|
185
|
+
alias :num_vertices :size
|
|
186
|
+
|
|
187
|
+
# Returns the number of edges.
|
|
188
|
+
def num_edges; r = 0; each_edge {|u,v| r +=1}; r; end
|
|
189
|
+
|
|
190
|
+
# Utility method to show a string representation of the edges of the graph.
|
|
191
|
+
def to_s
|
|
192
|
+
edges.sort.to_s
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Equality is defined to be same set of edges and directed?
|
|
196
|
+
def eql?(g)
|
|
197
|
+
equal?(g) or
|
|
198
|
+
begin
|
|
199
|
+
g.is_a?(Graph) and directed? == g.directed? and
|
|
200
|
+
g.inject(0) { |n, v| has_vertex?(v) or return false; n+1} ==
|
|
201
|
+
num_vertices and begin
|
|
202
|
+
ng = 0
|
|
203
|
+
g.each_edge { |u,v| has_edge? u,v or return false; ng += 1 }
|
|
204
|
+
ng == num_edges
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
alias == eql?
|
|
209
|
+
|
|
210
|
+
private
|
|
211
|
+
|
|
212
|
+
def each_edge_aux
|
|
213
|
+
# needed in each_edge
|
|
214
|
+
visited = Hash.new
|
|
215
|
+
each_vertex { |u|
|
|
216
|
+
each_adjacent(u) { |v|
|
|
217
|
+
edge = UnDirectedEdge.new u,v
|
|
218
|
+
unless visited.has_key? edge
|
|
219
|
+
visited[edge]=true
|
|
220
|
+
yield u, v
|
|
221
|
+
end
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
end
|
|
225
|
+
end # module Graph
|
|
226
|
+
|
|
227
|
+
end # module RGL
|
|
228
|
+
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'laser/third_party/rgl/base'
|
|
2
|
+
|
|
3
|
+
module RGL
|
|
4
|
+
|
|
5
|
+
# BGL defines the concept BidirectionalGraph as follows:
|
|
6
|
+
#
|
|
7
|
+
# The BidirectionalGraph concept refines IncidenceGraph and adds the
|
|
8
|
+
# requirement for efficient access to the in-edges of each vertex. This
|
|
9
|
+
# concept is separated from IncidenceGraph because, for directed graphs,
|
|
10
|
+
# efficient access to in-edges typically requires more storage space,
|
|
11
|
+
# and many algorithms do not require access to in-edges. For undirected
|
|
12
|
+
# graphs, this is not an issue; because the in_edges() and out_edges()
|
|
13
|
+
# functions are the same, they both return the edges incident to the vertex.
|
|
14
|
+
module BidirectionalGraph
|
|
15
|
+
include Graph
|
|
16
|
+
|
|
17
|
+
# Iterator providing access to the in-edges (for directed graphs) or incident
|
|
18
|
+
# edges (for undirected graphs) of vertex _v_. For both directed and
|
|
19
|
+
# undirected graphs, the target of an out-edge is required to be vertex _v_
|
|
20
|
+
# and the source is required to be a vertex that is adjacent to _v_.
|
|
21
|
+
def each_in_neighbor(v, &blk)
|
|
22
|
+
each_predecessor(v, &blk)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Returns the number of in-edges (for directed graphs) or the number of
|
|
26
|
+
# incident edges (for undirected graphs) of vertex _v_.
|
|
27
|
+
def in_degree (v)
|
|
28
|
+
r = 0;
|
|
29
|
+
each_in_neighbor(v) { |u| r += 1}
|
|
30
|
+
r
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns the number of in-edges plus out-edges (for directed graphs) or the
|
|
34
|
+
# number of incident edges (for undirected graphs) of vertex _v_.
|
|
35
|
+
def degree (v)
|
|
36
|
+
in_degree(v) + out_degree(v)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'laser/third_party/rgl/base'
|
|
2
|
+
require 'laser/third_party/rgl/implicit'
|
|
3
|
+
|
|
4
|
+
module RGL
|
|
5
|
+
module Graph
|
|
6
|
+
# Returns an RGL::ImplicitGraph where the strongly connected components of
|
|
7
|
+
# this graph are condensed into single nodes represented by Set instances
|
|
8
|
+
# containing the members of each strongly connected component. Edges
|
|
9
|
+
# between the different strongly connected components are preserved while
|
|
10
|
+
# edges within strongly connected components are omitted.
|
|
11
|
+
#
|
|
12
|
+
# Raises RGL::NotDirectedError if run on an undirected graph.
|
|
13
|
+
def condensation_graph
|
|
14
|
+
raise NotDirectedError,
|
|
15
|
+
"condensation_graph only supported for directed graphs" unless directed?
|
|
16
|
+
|
|
17
|
+
# Get the component map for the strongly connected components.
|
|
18
|
+
comp_map = strongly_connected_components.comp_map
|
|
19
|
+
# Invert the map such that for any number, n, in the component map a Set
|
|
20
|
+
# instance is created containing all of the nodes which map to n. The Set
|
|
21
|
+
# instances will be used to map to the number, n, with which the elements
|
|
22
|
+
# of the set are associated.
|
|
23
|
+
inv_comp_map = {}
|
|
24
|
+
comp_map.each { |v, n| (inv_comp_map[n] ||= Set.new) << v }
|
|
25
|
+
|
|
26
|
+
# Create an ImplicitGraph where the nodes are the strongly connected
|
|
27
|
+
# components of this graph and the edges are the edges of this graph which
|
|
28
|
+
# cross between the strongly connected components.
|
|
29
|
+
ImplicitGraph.new do |g|
|
|
30
|
+
g.vertex_iterator do |b|
|
|
31
|
+
inv_comp_map.each_value(&b)
|
|
32
|
+
end
|
|
33
|
+
g.adjacent_iterator do |scc, b|
|
|
34
|
+
scc.each do |v|
|
|
35
|
+
each_adjacent(v) do |w|
|
|
36
|
+
# Do not make the cluster reference itself in the graph.
|
|
37
|
+
if comp_map[v] != comp_map[w] then
|
|
38
|
+
b.call(inv_comp_map[comp_map[w]])
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
g.directed = true
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# connected_components.rb
|
|
2
|
+
#
|
|
3
|
+
# This file contains the algorithms for the connected components of an
|
|
4
|
+
# undirected graph (each_connected_component) and strongly connected components
|
|
5
|
+
# for directed graphs (strongly_connected_components).
|
|
6
|
+
#
|
|
7
|
+
require 'laser/third_party/rgl/traversal'
|
|
8
|
+
|
|
9
|
+
module RGL
|
|
10
|
+
|
|
11
|
+
module Graph
|
|
12
|
+
|
|
13
|
+
# Compute the connected components of an undirected graph, using a
|
|
14
|
+
# DFS (Depth-first search)-based approach. A _connected component_ of
|
|
15
|
+
# an undirected graph is a set of vertices that are all reachable
|
|
16
|
+
# from each other.
|
|
17
|
+
#
|
|
18
|
+
# The function is implemented as an iterator which calls the client
|
|
19
|
+
# with an array of vertices for each component.
|
|
20
|
+
#
|
|
21
|
+
# It raises an exception if the graph is directed.
|
|
22
|
+
|
|
23
|
+
def each_connected_component
|
|
24
|
+
raise NotUndirectedError,
|
|
25
|
+
"each_connected_component only works " +
|
|
26
|
+
"for undirected graphs." if directed?
|
|
27
|
+
comp = []
|
|
28
|
+
vis = DFSVisitor.new(self)
|
|
29
|
+
vis.set_finish_vertex_event_handler { |v| comp << v }
|
|
30
|
+
vis.set_start_vertex_event_handler { |v|
|
|
31
|
+
yield comp unless comp.empty?
|
|
32
|
+
comp = []
|
|
33
|
+
}
|
|
34
|
+
depth_first_search(vis) { |v| }
|
|
35
|
+
yield comp unless comp.empty?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# This GraphVisitor is used by strongly_connected_components to compute
|
|
39
|
+
# the strongly connected components of a directed graph.
|
|
40
|
+
|
|
41
|
+
class TarjanSccVisitor < DFSVisitor
|
|
42
|
+
|
|
43
|
+
attr_reader :comp_map
|
|
44
|
+
|
|
45
|
+
# Creates a new TarjanSccVisitor for graph _g_, which should be directed.
|
|
46
|
+
|
|
47
|
+
def initialize (g)
|
|
48
|
+
super g
|
|
49
|
+
@root_map = {}
|
|
50
|
+
@comp_map = {}
|
|
51
|
+
@discover_time_map = {}
|
|
52
|
+
@dfs_time = 0
|
|
53
|
+
@c_index = 0
|
|
54
|
+
@stack = []
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def handle_examine_vertex (v)
|
|
58
|
+
@root_map[v] = v
|
|
59
|
+
@comp_map[v] = -1
|
|
60
|
+
@dfs_time += 1
|
|
61
|
+
@discover_time_map[v] = @dfs_time
|
|
62
|
+
@stack.push(v)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def handle_finish_vertex (v)
|
|
66
|
+
# Search adjacent vertex w with earliest discover time
|
|
67
|
+
root_v = @root_map[v]
|
|
68
|
+
graph.each_adjacent(v) do |w|
|
|
69
|
+
if @comp_map[w] == -1
|
|
70
|
+
root_v = min_discover_time(root_v, @root_map[w])
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
@root_map[v] = root_v
|
|
74
|
+
if root_v == v # v is topmost vertex of a SCC
|
|
75
|
+
begin # pop off all vertices until v
|
|
76
|
+
w = @stack.pop
|
|
77
|
+
@comp_map[w] = @c_index
|
|
78
|
+
end until w == v
|
|
79
|
+
@c_index += 1
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Return the number of components found so far.
|
|
84
|
+
|
|
85
|
+
def num_comp
|
|
86
|
+
@c_index
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
def min_discover_time (u, v)
|
|
92
|
+
@discover_time_map[u] < @discover_time_map[v] ? u : v
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
end # class TarjanSccVisitor
|
|
96
|
+
|
|
97
|
+
# This is Tarjan's algorithm for strongly connected components, from his
|
|
98
|
+
# paper "Depth first search and linear graph algorithms". It calculates
|
|
99
|
+
# the components in a single application of DFS. We implement the
|
|
100
|
+
# algorithm with the help of the DFSVisitor TarjanSccVisitor.
|
|
101
|
+
#
|
|
102
|
+
# === Definition
|
|
103
|
+
#
|
|
104
|
+
# A _strongly connected component_ of a directed graph G=(V,E) is a
|
|
105
|
+
# maximal set of vertices U which is in V, such that for every pair of
|
|
106
|
+
# vertices u and v in U, we have both a path from u to v and a path
|
|
107
|
+
# from v to u. That is to say, u and v are reachable from each other.
|
|
108
|
+
#
|
|
109
|
+
# @Article{Tarjan:1972:DFS,
|
|
110
|
+
# author = "R. E. Tarjan",
|
|
111
|
+
# key = "Tarjan",
|
|
112
|
+
# title = "Depth First Search and Linear Graph Algorithms",
|
|
113
|
+
# journal = "SIAM Journal on Computing",
|
|
114
|
+
# volume = "1",
|
|
115
|
+
# number = "2",
|
|
116
|
+
# pages = "146--160",
|
|
117
|
+
# month = jun,
|
|
118
|
+
# year = "1972",
|
|
119
|
+
# CODEN = "SMJCAT",
|
|
120
|
+
# ISSN = "0097-5397 (print), 1095-7111 (electronic)",
|
|
121
|
+
# bibdate = "Thu Jan 23 09:56:44 1997",
|
|
122
|
+
# bibsource = "Parallel/Multi.bib, Misc/Reverse.eng.bib",
|
|
123
|
+
# }
|
|
124
|
+
#
|
|
125
|
+
# The output of the algorithm is recorded in a TarjanSccVisitor _vis_.
|
|
126
|
+
# vis.comp_map will contain numbers giving the component ID assigned to
|
|
127
|
+
# each vertex. The number of components is vis.num_comp.
|
|
128
|
+
|
|
129
|
+
def strongly_connected_components
|
|
130
|
+
raise NotDirectedError,
|
|
131
|
+
"strong_components only works for directed graphs." unless directed?
|
|
132
|
+
vis = TarjanSccVisitor.new(self)
|
|
133
|
+
depth_first_search(vis) { |v| }
|
|
134
|
+
vis
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
end # module Graph
|
|
138
|
+
end # module RGL
|