roby 0.8.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.deep-cover.rb +3 -0
- data/.gitattributes +1 -0
- data/.gitignore +24 -0
- data/.simplecov +10 -0
- data/.travis.yml +17 -0
- data/.yardopts +4 -0
- data/Gemfile +15 -0
- data/README.md +11 -0
- data/Rakefile +47 -177
- data/benchmark/{alloc_misc.rb → attic/alloc_misc.rb} +2 -2
- data/benchmark/{discovery_latency.rb → attic/discovery_latency.rb} +19 -19
- data/benchmark/{garbage_collection.rb → attic/garbage_collection.rb} +9 -9
- data/benchmark/{genom.rb → attic/genom.rb} +0 -0
- data/benchmark/attic/transactions.rb +62 -0
- data/benchmark/plan_basic_operations.rb +28 -0
- data/benchmark/relations/graph.rb +63 -0
- data/benchmark/ruby/identity.rb +18 -0
- data/benchmark/ruby/set_intersect_vs_hash_merge.rb +39 -0
- data/benchmark/ruby/yield_vs_block.rb +35 -0
- data/benchmark/run +5 -0
- data/benchmark/synthetic_plan_modifications_with_transactions.rb +79 -0
- data/benchmark/transactions.rb +99 -51
- data/bin/roby +38 -197
- data/bin/roby-display +14 -0
- data/bin/roby-log +3 -176
- data/doc/guide/{src → attic}/abstraction/achieve_with.page +1 -1
- data/doc/guide/{src → attic}/abstraction/forwarding.page +1 -1
- data/doc/guide/{src → attic}/abstraction/hierarchy.page +1 -1
- data/doc/guide/{src → attic}/abstraction/index.page +1 -1
- data/doc/guide/{src → attic}/abstraction/task_models.page +1 -1
- data/doc/guide/{overview.rdoc → attic/cycle/api_overview.rdoc} +6 -1
- data/doc/guide/{src → attic}/cycle/cycle-overview.png +0 -0
- data/doc/guide/{src → attic}/cycle/cycle-overview.svg +0 -0
- data/doc/guide/attic/cycle/error_handling.page +98 -0
- data/doc/guide/{src → attic}/cycle/error_instantaneous_repair.png +0 -0
- data/doc/guide/{src → attic}/cycle/error_instantaneous_repair.svg +0 -0
- data/doc/guide/{src/cycle/error_handling.page → attic/cycle/error_sources.page} +46 -89
- data/doc/guide/{src → attic}/cycle/garbage_collection.page +1 -1
- data/doc/guide/{src → attic}/cycle/index.page +1 -1
- data/doc/guide/{src → attic}/cycle/propagation.page +11 -1
- data/doc/guide/{src → attic}/cycle/propagation_diamond.png +0 -0
- data/doc/guide/{src → attic}/cycle/propagation_diamond.svg +0 -0
- data/doc/guide/attic/plans/building_plans.page +89 -0
- data/doc/guide/attic/plans/code.page +192 -0
- data/doc/guide/{src/basics → attic/plans}/events.page +3 -4
- data/doc/guide/attic/plans/index.page +7 -0
- data/doc/guide/{plan_modifications.rdoc → attic/plans/plan_modifications.rdoc} +5 -3
- data/doc/guide/{src/basics → attic/plans}/plan_objects.page +2 -1
- data/doc/guide/attic/plans/querying_plans.page +5 -0
- data/doc/guide/{src/basics → attic/plans}/tasks.page +20 -20
- data/doc/guide/config.yaml +7 -4
- data/doc/guide/ext/extended_menu.rb +29 -0
- data/doc/guide/ext/init.rb +6 -0
- data/doc/guide/ext/rdoc_links.rb +7 -6
- data/doc/guide/src/advanced_concepts/history.page +5 -0
- data/doc/guide/src/advanced_concepts/index.page +11 -0
- data/doc/guide/src/advanced_concepts/recognizing_patterns.page +83 -0
- data/doc/guide/src/advanced_concepts/scheduling.page +87 -0
- data/doc/guide/src/advanced_concepts/transactions.page +5 -0
- data/doc/guide/src/advanced_concepts/unreachability.page +42 -0
- data/doc/guide/src/base.template +96 -0
- data/doc/guide/src/basics_shell_header.txt +5 -7
- data/doc/guide/src/building/action_coordination.page +96 -0
- data/doc/guide/src/building/actions.page +124 -0
- data/doc/guide/src/building/file_layout.page +71 -0
- data/doc/guide/src/building/index.page +50 -0
- data/doc/guide/src/building/patterns.page +86 -0
- data/doc/guide/src/building/patterns_forwarding.png +0 -0
- data/doc/guide/src/building/patterns_forwarding.svg +277 -0
- data/doc/guide/src/building/runtime.page +95 -0
- data/doc/guide/src/building/task_models.page +94 -0
- data/doc/guide/src/building/tasks.page +284 -0
- data/doc/guide/src/concepts/error_handling.page +100 -0
- data/doc/guide/src/concepts/exception_propagation.png +0 -0
- data/doc/guide/src/concepts/exception_propagation.svg +445 -0
- data/doc/guide/src/concepts/execution.page +85 -0
- data/doc/guide/src/concepts/execution.png +0 -0
- data/doc/guide/src/concepts/execution.svg +573 -0
- data/doc/guide/src/concepts/execution_cycle.png +0 -0
- data/doc/guide/src/concepts/garbage_collection.page +57 -0
- data/doc/guide/src/concepts/index.page +27 -0
- data/doc/guide/src/concepts/plans.page +101 -0
- data/doc/guide/src/concepts/policy.page +31 -0
- data/doc/guide/src/concepts/reactor.page +61 -0
- data/doc/guide/src/concepts/simple_plan_example.png +0 -0
- data/doc/guide/src/concepts/simple_plan_example.svg +376 -0
- data/doc/guide/src/default.template +9 -74
- data/doc/guide/src/event_relations/forward.page +71 -0
- data/doc/guide/src/event_relations/index.page +12 -0
- data/doc/guide/src/event_relations/scheduling_constraints.page +43 -0
- data/doc/guide/src/event_relations/signal.page +55 -0
- data/doc/guide/src/event_relations/temporal_constraints.page +77 -0
- data/doc/guide/src/htmldoc.metainfo +21 -8
- data/doc/guide/src/index.page +8 -3
- data/doc/guide/src/{introduction/install.page → installation/index.page} +37 -25
- data/doc/guide/src/installation/publications.page +14 -0
- data/doc/guide/src/{introduction → installation}/videos.page +14 -7
- data/doc/guide/src/interacting/index.page +16 -0
- data/doc/guide/src/interacting/run.page +33 -0
- data/doc/guide/src/interacting/shell.page +95 -0
- data/doc/guide/src/plugins/creating_plugins.page +72 -0
- data/doc/guide/src/plugins/index.page +27 -5
- data/doc/guide/src/plugins/{fault_tolerance.page → standard_plugins/fault_tolerance.page} +2 -2
- data/doc/guide/src/plugins/standard_plugins/index.page +11 -0
- data/doc/guide/src/plugins/{subsystems.page → standard_plugins/subsystems.page} +2 -2
- data/doc/guide/src/style_screen.css +687 -0
- data/doc/guide/src/task_relations/dependency.page +107 -0
- data/doc/guide/src/task_relations/executed_by.page +77 -0
- data/doc/guide/src/task_relations/index.page +12 -0
- data/doc/guide/src/task_relations/new_relations.page +119 -0
- data/doc/guide/src/task_relations/planned_by.page +46 -0
- data/doc/guide/src/tutorial/app.page +117 -0
- data/doc/guide/src/{basics → tutorial}/code_examples.page +6 -5
- data/doc/guide/src/{basics → tutorial}/dry.page +15 -15
- data/doc/guide/src/{basics → tutorial}/errors.page +43 -68
- data/doc/guide/src/tutorial/events.page +195 -0
- data/doc/guide/src/{basics → tutorial}/hierarchy.page +53 -52
- data/doc/guide/src/tutorial/index.page +13 -0
- data/doc/guide/src/tutorial/log_replay/goForward_1.png +0 -0
- data/doc/guide/src/tutorial/log_replay/goForward_2.png +0 -0
- data/doc/guide/src/tutorial/log_replay/goForward_3.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/goForward_4.png +0 -0
- data/doc/guide/src/tutorial/log_replay/goForward_5.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/hierarchy_error_1.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/hierarchy_error_2.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/hierarchy_error_3.png +0 -0
- data/doc/guide/src/tutorial/log_replay/moveto_code_error.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/plan_repair_1.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/plan_repair_2.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/plan_repair_3.png +0 -0
- data/doc/guide/src/tutorial/log_replay/plan_repair_4.png +0 -0
- data/doc/guide/src/tutorial/log_replay/roby_log_main_window.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/roby_log_relation_window.png +0 -0
- data/doc/guide/src/{basics → tutorial}/log_replay/roby_replay_event_representation.png +0 -0
- data/doc/guide/src/tutorial/relations_display.page +153 -0
- data/doc/guide/src/{basics → tutorial}/roby_cycle_overview.png +0 -0
- data/doc/guide/src/tutorial/shell.page +121 -0
- data/doc/guide/src/{basics → tutorial}/summary.page +1 -1
- data/doc/guide/src/tutorial/tasks.page +374 -0
- data/lib/roby.rb +102 -47
- data/lib/roby/actions.rb +17 -0
- data/lib/roby/actions/action.rb +80 -0
- data/lib/roby/actions/interface.rb +45 -0
- data/lib/roby/actions/library.rb +23 -0
- data/lib/roby/actions/models/action.rb +224 -0
- data/lib/roby/actions/models/coordination_action.rb +58 -0
- data/lib/roby/actions/models/interface.rb +22 -0
- data/lib/roby/actions/models/interface_base.rb +294 -0
- data/lib/roby/actions/models/library.rb +12 -0
- data/lib/roby/actions/models/method_action.rb +90 -0
- data/lib/roby/actions/task.rb +114 -0
- data/lib/roby/and_generator.rb +125 -0
- data/lib/roby/app.rb +2795 -829
- data/lib/roby/app/autotest_console_reporter.rb +138 -0
- data/lib/roby/app/base.rb +21 -0
- data/lib/roby/app/cucumber.rb +2 -0
- data/lib/roby/app/cucumber/controller.rb +439 -0
- data/lib/roby/app/cucumber/helpers.rb +280 -0
- data/lib/roby/app/cucumber/world.rb +32 -0
- data/lib/roby/app/debug.rb +136 -0
- data/lib/roby/app/gen.rb +2 -0
- data/lib/roby/app/rake.rb +178 -38
- data/lib/roby/app/robot_config.rb +9 -0
- data/lib/roby/app/robot_names.rb +115 -0
- data/lib/roby/app/run.rb +3 -2
- data/lib/roby/app/scripts.rb +72 -0
- data/lib/roby/app/scripts/autotest.rb +173 -0
- data/lib/roby/app/scripts/display.rb +2 -0
- data/lib/roby/app/scripts/restart.rb +52 -0
- data/lib/roby/app/scripts/results.rb +17 -8
- data/lib/roby/app/scripts/run.rb +155 -24
- data/lib/roby/app/scripts/shell.rb +147 -62
- data/lib/roby/app/scripts/test.rb +107 -22
- data/lib/roby/app/test_reporter.rb +74 -0
- data/lib/roby/app/test_server.rb +159 -0
- data/lib/roby/app/vagrant.rb +47 -0
- data/lib/roby/backports.rb +16 -0
- data/lib/roby/cli/display.rb +190 -0
- data/lib/roby/cli/exceptions.rb +17 -0
- data/lib/roby/cli/gen/actions/class.rb +5 -0
- data/lib/roby/cli/gen/actions/test.rb +6 -0
- data/lib/roby/cli/gen/app/.yardopts +6 -0
- data/lib/roby/cli/gen/app/README.md +28 -0
- data/lib/roby/cli/gen/app/Rakefile +15 -0
- data/{app → lib/roby/cli/gen/app}/config/app.yml +29 -39
- data/lib/roby/cli/gen/app/models/.gitattributes +1 -0
- data/{app → lib/roby/cli/gen/app/scripts}/controllers/.gitattributes +0 -0
- data/{app/data/.gitattributes → lib/roby/cli/gen/app/test/.gitignore} +0 -0
- data/lib/roby/cli/gen/class/class.rb +6 -0
- data/lib/roby/cli/gen/class/test.rb +7 -0
- data/lib/roby/cli/gen/helpers.rb +203 -0
- data/lib/roby/cli/gen/module/module.rb +5 -0
- data/lib/roby/cli/gen/module/test.rb +6 -0
- data/lib/roby/cli/gen/roby_app/config/init.rb +17 -0
- data/lib/roby/cli/gen/roby_app/config/robots/robot.rb +40 -0
- data/lib/roby/cli/gen/task/class.rb +44 -0
- data/lib/roby/cli/gen/task/test.rb +6 -0
- data/lib/roby/cli/gen_main.rb +120 -0
- data/lib/roby/cli/log.rb +276 -0
- data/lib/roby/cli/log/flamegraph.html +499 -0
- data/lib/roby/cli/log/flamegraph_renderer.rb +88 -0
- data/lib/roby/cli/main.rb +153 -0
- data/lib/roby/coordination.rb +60 -0
- data/lib/roby/coordination/action_script.rb +25 -0
- data/lib/roby/coordination/action_state_machine.rb +125 -0
- data/lib/roby/coordination/actions.rb +106 -0
- data/lib/roby/coordination/base.rb +145 -0
- data/lib/roby/coordination/calculus.rb +40 -0
- data/lib/roby/coordination/child.rb +28 -0
- data/lib/roby/coordination/event.rb +29 -0
- data/lib/roby/coordination/fault_handler.rb +25 -0
- data/lib/roby/coordination/fault_handling_task.rb +13 -0
- data/lib/roby/coordination/fault_response_table.rb +110 -0
- data/lib/roby/coordination/models/action_script.rb +64 -0
- data/lib/roby/coordination/models/action_state_machine.rb +224 -0
- data/lib/roby/coordination/models/actions.rb +191 -0
- data/lib/roby/coordination/models/arguments.rb +55 -0
- data/lib/roby/coordination/models/base.rb +176 -0
- data/lib/roby/coordination/models/capture.rb +86 -0
- data/lib/roby/coordination/models/child.rb +35 -0
- data/lib/roby/coordination/models/event.rb +41 -0
- data/lib/roby/coordination/models/exceptions.rb +42 -0
- data/lib/roby/coordination/models/fault_handler.rb +219 -0
- data/lib/roby/coordination/models/fault_response_table.rb +77 -0
- data/lib/roby/coordination/models/root.rb +22 -0
- data/lib/roby/coordination/models/script.rb +283 -0
- data/lib/roby/coordination/models/task.rb +184 -0
- data/lib/roby/coordination/models/task_from_action.rb +50 -0
- data/lib/roby/coordination/models/task_from_as_plan.rb +33 -0
- data/lib/roby/coordination/models/task_from_instanciation_object.rb +31 -0
- data/lib/roby/coordination/models/task_from_variable.rb +27 -0
- data/lib/roby/coordination/models/task_with_dependencies.rb +48 -0
- data/lib/roby/coordination/models/variable.rb +32 -0
- data/lib/roby/coordination/script.rb +200 -0
- data/lib/roby/coordination/script_instruction.rb +12 -0
- data/lib/roby/coordination/task.rb +45 -0
- data/lib/roby/coordination/task_base.rb +69 -0
- data/lib/roby/coordination/task_script.rb +293 -0
- data/lib/roby/coordination/task_state_machine.rb +308 -0
- data/lib/roby/decision_control.rb +33 -21
- data/lib/roby/distributed_object.rb +76 -0
- data/lib/roby/droby.rb +17 -0
- data/lib/roby/droby/droby_id.rb +6 -0
- data/lib/roby/droby/enable.rb +153 -0
- data/lib/roby/droby/event_logger.rb +189 -0
- data/lib/roby/droby/event_logging.rb +57 -0
- data/lib/roby/droby/exceptions.rb +14 -0
- data/lib/roby/droby/identifiable.rb +22 -0
- data/lib/roby/droby/logfile.rb +141 -0
- data/lib/roby/droby/logfile/client.rb +176 -0
- data/lib/roby/droby/logfile/file_format.md +97 -0
- data/lib/roby/droby/logfile/index.rb +117 -0
- data/lib/roby/droby/logfile/reader.rb +139 -0
- data/lib/roby/droby/logfile/server.rb +199 -0
- data/lib/roby/droby/logfile/writer.rb +114 -0
- data/lib/roby/droby/marshal.rb +264 -0
- data/lib/roby/droby/marshallable.rb +12 -0
- data/lib/roby/droby/null_event_logger.rb +25 -0
- data/lib/roby/droby/object_manager.rb +205 -0
- data/lib/roby/droby/peer_id.rb +6 -0
- data/lib/roby/droby/plan_rebuilder.rb +373 -0
- data/lib/roby/droby/rebuilt_plan.rb +160 -0
- data/lib/roby/droby/remote_droby_id.rb +6 -0
- data/lib/roby/droby/timepoints.rb +205 -0
- data/lib/roby/droby/timepoints_ctf.metadata.erb +101 -0
- data/lib/roby/droby/timepoints_ctf.rb +125 -0
- data/lib/roby/droby/v5.rb +14 -0
- data/lib/roby/droby/v5/builtin.rb +120 -0
- data/lib/roby/droby/v5/droby_class.rb +45 -0
- data/lib/roby/droby/v5/droby_constant.rb +81 -0
- data/lib/roby/droby/v5/droby_dump.rb +1026 -0
- data/lib/roby/droby/v5/droby_id.rb +44 -0
- data/lib/roby/droby/v5/droby_model.rb +82 -0
- data/lib/roby/droby/v5/peer_id.rb +10 -0
- data/lib/roby/droby/v5/remote_droby_id.rb +42 -0
- data/lib/roby/event.rb +79 -957
- data/lib/roby/event_constraints.rb +835 -0
- data/lib/roby/event_generator.rb +1047 -0
- data/lib/roby/event_structure/causal_link.rb +6 -0
- data/lib/roby/event_structure/forwarding.rb +6 -0
- data/lib/roby/event_structure/precedence.rb +7 -0
- data/lib/roby/event_structure/signal.rb +8 -0
- data/lib/roby/event_structure/temporal_constraints.rb +640 -0
- data/lib/roby/exceptions.rb +446 -152
- data/lib/roby/executable_plan.rb +549 -0
- data/lib/roby/execution_engine.rb +1997 -950
- data/lib/roby/filter_generator.rb +26 -0
- data/lib/roby/gui/chronicle_view.rb +225 -0
- data/lib/roby/gui/chronicle_widget.rb +925 -0
- data/lib/roby/gui/dot_id.rb +11 -0
- data/lib/roby/gui/exception_view.rb +44 -0
- data/lib/roby/gui/log_display.rb +273 -0
- data/lib/roby/gui/model_views.rb +2 -0
- data/lib/roby/gui/model_views/action_interface.rb +53 -0
- data/lib/roby/gui/model_views/task.rb +47 -0
- data/lib/roby/gui/model_views/task.rhtml +41 -0
- data/lib/roby/gui/object_info_view.rb +89 -0
- data/lib/roby/gui/plan_dot_layout.rb +427 -0
- data/lib/roby/gui/plan_rebuilder_widget.rb +357 -0
- data/lib/roby/gui/qt4_toMSecsSinceEpoch.rb +8 -0
- data/lib/roby/gui/relations_view.rb +278 -0
- data/lib/roby/gui/relations_view/relations.ui +139 -0
- data/lib/roby/gui/relations_view/relations_canvas.rb +1088 -0
- data/lib/roby/gui/relations_view/relations_config.rb +292 -0
- data/lib/roby/gui/relations_view/relations_view.ui +53 -0
- data/lib/roby/gui/scheduler_view.css +24 -0
- data/lib/roby/gui/scheduler_view.rb +46 -0
- data/lib/roby/gui/scheduler_view.rhtml +53 -0
- data/lib/roby/gui/stepping.rb +93 -0
- data/lib/roby/gui/stepping.ui +181 -0
- data/lib/roby/gui/styles.rb +81 -0
- data/lib/roby/gui/task_display_configuration.rb +42 -0
- data/lib/roby/gui/task_state_at.rb +38 -0
- data/lib/roby/hooks.rb +26 -0
- data/lib/roby/interface.rb +136 -469
- data/lib/roby/interface/async.rb +20 -0
- data/lib/roby/interface/async/action_monitor.rb +188 -0
- data/lib/roby/interface/async/interface.rb +498 -0
- data/lib/roby/interface/async/job_monitor.rb +213 -0
- data/lib/roby/interface/async/log.rb +238 -0
- data/lib/roby/interface/async/new_job_listener.rb +79 -0
- data/lib/roby/interface/async/ui_connector.rb +183 -0
- data/lib/roby/interface/client.rb +553 -0
- data/lib/roby/interface/command.rb +24 -0
- data/lib/roby/interface/command_argument.rb +16 -0
- data/lib/roby/interface/command_library.rb +92 -0
- data/lib/roby/interface/droby_channel.rb +174 -0
- data/lib/roby/interface/exceptions.rb +22 -0
- data/lib/roby/interface/interface.rb +655 -0
- data/lib/roby/interface/job.rb +47 -0
- data/lib/roby/interface/rest.rb +10 -0
- data/lib/roby/interface/rest/api.rb +29 -0
- data/lib/roby/interface/rest/helpers.rb +24 -0
- data/lib/roby/interface/rest/server.rb +212 -0
- data/lib/roby/interface/server.rb +154 -0
- data/lib/roby/interface/shell_client.rb +468 -0
- data/lib/roby/interface/shell_subcommand.rb +24 -0
- data/lib/roby/interface/subcommand_client.rb +35 -0
- data/lib/roby/interface/tcp.rb +168 -0
- data/lib/roby/models/arguments.rb +112 -0
- data/lib/roby/models/plan_object.rb +83 -0
- data/lib/roby/models/task.rb +835 -0
- data/lib/roby/models/task_event.rb +62 -0
- data/lib/roby/models/task_service.rb +78 -0
- data/lib/roby/or_generator.rb +88 -0
- data/lib/roby/plan.rb +1751 -864
- data/lib/roby/plan_object.rb +611 -0
- data/lib/roby/plan_service.rb +200 -0
- data/lib/roby/promise.rb +332 -0
- data/lib/roby/queries.rb +23 -0
- data/lib/roby/queries/and_matcher.rb +32 -0
- data/lib/roby/queries/any.rb +27 -0
- data/lib/roby/queries/code_error_matcher.rb +58 -0
- data/lib/roby/queries/event_generator_matcher.rb +9 -0
- data/lib/roby/queries/execution_exception_matcher.rb +165 -0
- data/lib/roby/queries/index.rb +165 -0
- data/lib/roby/queries/localized_error_matcher.rb +149 -0
- data/lib/roby/queries/matcher_base.rb +107 -0
- data/lib/roby/queries/none.rb +27 -0
- data/lib/roby/queries/not_matcher.rb +30 -0
- data/lib/roby/queries/op_matcher.rb +8 -0
- data/lib/roby/queries/or_matcher.rb +30 -0
- data/lib/roby/queries/plan_object_matcher.rb +363 -0
- data/lib/roby/queries/query.rb +188 -0
- data/lib/roby/queries/task_event_generator_matcher.rb +86 -0
- data/lib/roby/queries/task_matcher.rb +344 -0
- data/lib/roby/relations.rb +42 -678
- data/lib/roby/relations/bidirectional_directed_adjacency_graph.rb +492 -0
- data/lib/roby/relations/directed_relation_support.rb +268 -0
- data/lib/roby/relations/event_relation_graph.rb +19 -0
- data/lib/roby/relations/fork_merge_visitor.rb +154 -0
- data/lib/roby/relations/graph.rb +533 -0
- data/lib/roby/relations/models/directed_relation_support.rb +11 -0
- data/lib/roby/relations/models/graph.rb +75 -0
- data/lib/roby/relations/models/task_relation_graph.rb +18 -0
- data/lib/roby/relations/space.rb +380 -0
- data/lib/roby/relations/task_relation_graph.rb +20 -0
- data/lib/roby/robot.rb +85 -38
- data/lib/roby/schedulers/basic.rb +155 -25
- data/lib/roby/schedulers/null.rb +20 -0
- data/lib/roby/schedulers/reporting.rb +31 -0
- data/lib/roby/schedulers/state.rb +129 -0
- data/lib/roby/schedulers/temporal.rb +91 -0
- data/lib/roby/singletons.rb +87 -0
- data/lib/roby/standalone.rb +4 -2
- data/lib/roby/standard_errors.rb +405 -82
- data/lib/roby/state.rb +6 -3
- data/lib/roby/state/conf_model.rb +5 -0
- data/lib/roby/state/events.rb +181 -95
- data/lib/roby/state/goal_model.rb +77 -0
- data/lib/roby/state/open_struct.rb +591 -0
- data/lib/roby/state/open_struct_model.rb +68 -0
- data/lib/roby/state/pos.rb +45 -45
- data/lib/roby/state/shapes.rb +11 -11
- data/lib/roby/state/state_model.rb +303 -0
- data/lib/roby/state/task.rb +43 -0
- data/lib/roby/support.rb +88 -148
- data/lib/roby/task.rb +1361 -1750
- data/lib/roby/task_arguments.rb +428 -0
- data/lib/roby/task_event.rb +127 -0
- data/lib/roby/task_event_generator.rb +337 -0
- data/lib/roby/task_service.rb +6 -0
- data/lib/roby/task_structure/conflicts.rb +104 -0
- data/lib/roby/task_structure/dependency.rb +932 -0
- data/lib/roby/task_structure/error_handling.rb +118 -0
- data/lib/roby/task_structure/executed_by.rb +234 -0
- data/lib/roby/task_structure/planned_by.rb +90 -0
- data/lib/roby/tasks/aggregator.rb +37 -0
- data/lib/roby/tasks/external_process.rb +275 -0
- data/lib/roby/tasks/group.rb +27 -0
- data/lib/roby/tasks/null.rb +19 -0
- data/lib/roby/tasks/parallel.rb +43 -0
- data/lib/roby/tasks/sequence.rb +88 -0
- data/lib/roby/tasks/simple.rb +21 -0
- data/lib/roby/{thread_task.rb → tasks/thread.rb} +50 -24
- data/lib/roby/tasks/timeout.rb +17 -0
- data/lib/roby/tasks/virtual.rb +55 -0
- data/lib/roby/template_plan.rb +7 -0
- data/lib/roby/test/aruba_minitest.rb +74 -0
- data/lib/roby/test/assertion.rb +16 -0
- data/lib/roby/test/assertions.rb +490 -0
- data/lib/roby/test/common.rb +368 -591
- data/lib/roby/test/dsl.rb +149 -0
- data/lib/roby/test/error.rb +18 -0
- data/lib/roby/test/event_reporter.rb +83 -0
- data/lib/roby/test/execution_expectations.rb +1134 -0
- data/lib/roby/test/expect_execution.rb +151 -0
- data/lib/roby/test/minitest_helpers.rb +166 -0
- data/lib/roby/test/roby_app_helpers.rb +200 -0
- data/lib/roby/test/run_planners.rb +155 -0
- data/lib/roby/test/self.rb +112 -0
- data/lib/roby/test/spec.rb +198 -0
- data/lib/roby/test/tasks/empty_task.rb +4 -4
- data/lib/roby/test/tasks/goto.rb +28 -27
- data/lib/roby/test/teardown_plans.rb +100 -0
- data/lib/roby/test/testcase.rb +239 -307
- data/lib/roby/test/tools.rb +159 -155
- data/lib/roby/test/validate_state_machine.rb +75 -0
- data/lib/roby/transaction.rb +1125 -0
- data/lib/roby/transaction/event_generator_proxy.rb +63 -0
- data/lib/roby/transaction/plan_object_proxy.rb +99 -0
- data/lib/roby/transaction/plan_service_proxy.rb +43 -0
- data/lib/roby/transaction/proxying.rb +120 -0
- data/lib/roby/transaction/task_event_generator_proxy.rb +19 -0
- data/lib/roby/transaction/task_proxy.rb +135 -0
- data/lib/roby/until_generator.rb +30 -0
- data/lib/roby/version.rb +5 -0
- data/lib/roby/yard.rb +169 -0
- data/lib/yard-roby.rb +1 -0
- data/manifest.xml +32 -6
- data/roby.gemspec +59 -0
- metadata +788 -587
- data/Manifest.txt +0 -321
- data/NOTES +0 -4
- data/README.txt +0 -166
- data/TODO.txt +0 -146
- data/app/README.txt +0 -24
- data/app/Rakefile +0 -8
- data/app/config/ROBOT.rb +0 -5
- data/app/config/init.rb +0 -33
- data/app/config/roby.yml +0 -3
- data/app/controllers/ROBOT.rb +0 -2
- data/app/planners/ROBOT/main.rb +0 -6
- data/app/planners/main.rb +0 -5
- data/app/scripts/distributed +0 -3
- data/app/scripts/generate/bookmarks +0 -3
- data/app/scripts/replay +0 -3
- data/app/scripts/results +0 -3
- data/app/scripts/run +0 -3
- data/app/scripts/server +0 -3
- data/app/scripts/shell +0 -3
- data/app/scripts/test +0 -3
- data/app/tasks/.gitattributes +0 -0
- data/app/tasks/ROBOT/.gitattributes +0 -0
- data/bin/roby-shell +0 -25
- data/doc/guide/src/basics/app.page +0 -139
- data/doc/guide/src/basics/index.page +0 -11
- data/doc/guide/src/basics/log_replay/goForward_1.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_2.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_3.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_5.png +0 -0
- data/doc/guide/src/basics/log_replay/plan_repair_4.png +0 -0
- data/doc/guide/src/basics/log_replay/roby_log_main_window.png +0 -0
- data/doc/guide/src/basics/relations_display.page +0 -203
- data/doc/guide/src/basics/shell.page +0 -102
- data/doc/guide/src/default.css +0 -319
- data/doc/guide/src/introduction/index.page +0 -29
- data/doc/guide/src/introduction/publications.page +0 -14
- data/doc/guide/src/relations/dependency.page +0 -89
- data/doc/guide/src/relations/index.page +0 -12
- data/ext/droby/dump.cc +0 -175
- data/ext/droby/extconf.rb +0 -3
- data/ext/graph/algorithm.cc +0 -746
- data/ext/graph/extconf.rb +0 -7
- data/ext/graph/graph.cc +0 -575
- data/ext/graph/graph.hh +0 -183
- data/ext/graph/iterator_sequence.hh +0 -102
- data/ext/graph/undirected_dfs.hh +0 -226
- data/ext/graph/undirected_graph.hh +0 -421
- data/lib/roby/app/scripts/generate/bookmarks.rb +0 -162
- data/lib/roby/app/scripts/replay.rb +0 -31
- data/lib/roby/app/scripts/server.rb +0 -18
- data/lib/roby/basic_object.rb +0 -151
- data/lib/roby/config.rb +0 -14
- data/lib/roby/distributed.rb +0 -36
- data/lib/roby/distributed/base.rb +0 -448
- data/lib/roby/distributed/communication.rb +0 -875
- data/lib/roby/distributed/connection_space.rb +0 -616
- data/lib/roby/distributed/distributed_object.rb +0 -206
- data/lib/roby/distributed/drb.rb +0 -62
- data/lib/roby/distributed/notifications.rb +0 -531
- data/lib/roby/distributed/peer.rb +0 -555
- data/lib/roby/distributed/protocol.rb +0 -529
- data/lib/roby/distributed/proxy.rb +0 -343
- data/lib/roby/distributed/subscription.rb +0 -311
- data/lib/roby/distributed/transaction.rb +0 -498
- data/lib/roby/external_process_task.rb +0 -225
- data/lib/roby/graph.rb +0 -160
- data/lib/roby/log.rb +0 -3
- data/lib/roby/log/chronicle.rb +0 -303
- data/lib/roby/log/console.rb +0 -74
- data/lib/roby/log/data_stream.rb +0 -275
- data/lib/roby/log/dot.rb +0 -279
- data/lib/roby/log/event_stream.rb +0 -161
- data/lib/roby/log/file.rb +0 -396
- data/lib/roby/log/gui/basic_display.ui +0 -83
- data/lib/roby/log/gui/basic_display_ui.rb +0 -89
- data/lib/roby/log/gui/chronicle.rb +0 -26
- data/lib/roby/log/gui/chronicle_view.rb +0 -40
- data/lib/roby/log/gui/chronicle_view.ui +0 -70
- data/lib/roby/log/gui/chronicle_view_ui.rb +0 -90
- data/lib/roby/log/gui/data_displays.rb +0 -171
- data/lib/roby/log/gui/data_displays.ui +0 -155
- data/lib/roby/log/gui/data_displays_ui.rb +0 -146
- data/lib/roby/log/gui/notifications.rb +0 -26
- data/lib/roby/log/gui/relations.rb +0 -269
- data/lib/roby/log/gui/relations.ui +0 -123
- data/lib/roby/log/gui/relations_ui.rb +0 -120
- data/lib/roby/log/gui/relations_view.rb +0 -185
- data/lib/roby/log/gui/relations_view.ui +0 -149
- data/lib/roby/log/gui/relations_view_ui.rb +0 -144
- data/lib/roby/log/gui/replay.rb +0 -366
- data/lib/roby/log/gui/replay_controls.rb +0 -206
- data/lib/roby/log/gui/replay_controls.ui +0 -282
- data/lib/roby/log/gui/replay_controls_ui.rb +0 -249
- data/lib/roby/log/gui/runtime.rb +0 -130
- data/lib/roby/log/hooks.rb +0 -186
- data/lib/roby/log/logger.rb +0 -203
- data/lib/roby/log/notifications.rb +0 -244
- data/lib/roby/log/plan_rebuilder.rb +0 -468
- data/lib/roby/log/relations.rb +0 -1084
- data/lib/roby/log/server.rb +0 -547
- data/lib/roby/log/sqlite.rb +0 -47
- data/lib/roby/log/timings.rb +0 -233
- data/lib/roby/plan-object.rb +0 -371
- data/lib/roby/planning.rb +0 -13
- data/lib/roby/planning/loops.rb +0 -309
- data/lib/roby/planning/model.rb +0 -1012
- data/lib/roby/planning/task.rb +0 -180
- data/lib/roby/query.rb +0 -655
- data/lib/roby/relations/conflicts.rb +0 -67
- data/lib/roby/relations/dependency.rb +0 -358
- data/lib/roby/relations/ensured.rb +0 -19
- data/lib/roby/relations/error_handling.rb +0 -22
- data/lib/roby/relations/events.rb +0 -7
- data/lib/roby/relations/executed_by.rb +0 -208
- data/lib/roby/relations/influence.rb +0 -10
- data/lib/roby/relations/planned_by.rb +0 -63
- data/lib/roby/state/information.rb +0 -55
- data/lib/roby/state/state.rb +0 -367
- data/lib/roby/task-operations.rb +0 -186
- data/lib/roby/task_index.rb +0 -80
- data/lib/roby/test/distributed.rb +0 -230
- data/lib/roby/test/tasks/simple_task.rb +0 -23
- data/lib/roby/transactions.rb +0 -507
- data/lib/roby/transactions/proxy.rb +0 -325
- data/plugins/fault_injection/History.txt +0 -4
- data/plugins/fault_injection/README.txt +0 -34
- data/plugins/fault_injection/Rakefile +0 -12
- data/plugins/fault_injection/TODO.txt +0 -0
- data/plugins/fault_injection/app.rb +0 -52
- data/plugins/fault_injection/fault_injection.rb +0 -89
- data/plugins/fault_injection/test/test_fault_injection.rb +0 -78
- data/plugins/subsystems/README.txt +0 -37
- data/plugins/subsystems/Rakefile +0 -13
- data/plugins/subsystems/app.rb +0 -182
- data/plugins/subsystems/test/app/README +0 -24
- data/plugins/subsystems/test/app/Rakefile +0 -8
- data/plugins/subsystems/test/app/config/app.yml +0 -71
- data/plugins/subsystems/test/app/config/init.rb +0 -12
- data/plugins/subsystems/test/app/config/roby.yml +0 -3
- data/plugins/subsystems/test/app/planners/main.rb +0 -20
- data/plugins/subsystems/test/app/scripts/distributed +0 -3
- data/plugins/subsystems/test/app/scripts/replay +0 -3
- data/plugins/subsystems/test/app/scripts/results +0 -3
- data/plugins/subsystems/test/app/scripts/run +0 -3
- data/plugins/subsystems/test/app/scripts/server +0 -3
- data/plugins/subsystems/test/app/scripts/shell +0 -3
- data/plugins/subsystems/test/app/scripts/test +0 -3
- data/plugins/subsystems/test/app/tasks/services.rb +0 -15
- data/plugins/subsystems/test/test_subsystems.rb +0 -78
- data/test/distributed/test_communication.rb +0 -195
- data/test/distributed/test_connection.rb +0 -284
- data/test/distributed/test_execution.rb +0 -378
- data/test/distributed/test_mixed_plan.rb +0 -341
- data/test/distributed/test_plan_notifications.rb +0 -238
- data/test/distributed/test_protocol.rb +0 -525
- data/test/distributed/test_query.rb +0 -106
- data/test/distributed/test_remote_plan.rb +0 -491
- data/test/distributed/test_transaction.rb +0 -466
- data/test/mockups/external_process +0 -28
- data/test/mockups/tasks.rb +0 -27
- data/test/planning/test_loops.rb +0 -432
- data/test/planning/test_model.rb +0 -427
- data/test/planning/test_task.rb +0 -126
- data/test/relations/test_conflicts.rb +0 -42
- data/test/relations/test_dependency.rb +0 -324
- data/test/relations/test_ensured.rb +0 -38
- data/test/relations/test_executed_by.rb +0 -224
- data/test/relations/test_planned_by.rb +0 -56
- data/test/suite_core.rb +0 -29
- data/test/suite_distributed.rb +0 -10
- data/test/suite_planning.rb +0 -4
- data/test/suite_relations.rb +0 -8
- data/test/tasks/test_external_process.rb +0 -126
- data/test/tasks/test_thread_task.rb +0 -70
- data/test/test_bgl.rb +0 -528
- data/test/test_event.rb +0 -969
- data/test/test_exceptions.rb +0 -591
- data/test/test_execution_engine.rb +0 -987
- data/test/test_gui.rb +0 -20
- data/test/test_interface.rb +0 -43
- data/test/test_log.rb +0 -125
- data/test/test_log_server.rb +0 -133
- data/test/test_plan.rb +0 -418
- data/test/test_query.rb +0 -424
- data/test/test_relations.rb +0 -260
- data/test/test_state.rb +0 -432
- data/test/test_support.rb +0 -16
- data/test/test_task.rb +0 -1181
- data/test/test_testcase.rb +0 -138
- data/test/test_transactions.rb +0 -610
- data/test/test_transactions_proxy.rb +0 -216
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
module Roby
|
|
2
|
+
module Relations
|
|
3
|
+
# Base support for relations. It is mixed in objects on which a
|
|
4
|
+
# Relations::Space applies on, like Task for TaskStructure and EventGenerator
|
|
5
|
+
# for EventStructure.
|
|
6
|
+
#
|
|
7
|
+
# See also the definition of Relations::Graph#add_relation and
|
|
8
|
+
# Relations::Graph#remove_relation for the possibility to define hooks that
|
|
9
|
+
# get called when a new edge involving +self+ as a vertex gets added and
|
|
10
|
+
# removed
|
|
11
|
+
module DirectedRelationSupport
|
|
12
|
+
attr_reader :relation_graphs
|
|
13
|
+
|
|
14
|
+
def relation_graph_for(rel)
|
|
15
|
+
relation_graphs.fetch(rel)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Enumerate all relations that are relevant for this plan object
|
|
19
|
+
#
|
|
20
|
+
# Unlike {#each_relation_graph}, which enumerate only the graphs
|
|
21
|
+
# that include self, it enumerates all possible relations for self
|
|
22
|
+
#
|
|
23
|
+
# @yieldparam [Class<Graph>]
|
|
24
|
+
def each_relation
|
|
25
|
+
return enum_for(__method__) if !block_given?
|
|
26
|
+
relation_graphs.each do |k, g|
|
|
27
|
+
yield(k) if k != g
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Enumerate the relation graphs that include this vertex
|
|
32
|
+
#
|
|
33
|
+
# @yieldparam [Graph]
|
|
34
|
+
def each_relation_graph
|
|
35
|
+
return enum_for(__method__) if !block_given?
|
|
36
|
+
relation_graphs.each do |k, g|
|
|
37
|
+
yield(g) if g.has_vertex?(self) && (k == g)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Enumerate the relation graphs that include this vertex and that
|
|
42
|
+
# are subgraphs of no other graphs
|
|
43
|
+
#
|
|
44
|
+
# @yieldparam [Graph]
|
|
45
|
+
def each_root_relation_graph
|
|
46
|
+
return enum_for(__method__) if !block_given?
|
|
47
|
+
each_relation_graph do |g|
|
|
48
|
+
yield(g) if g.root_relation?
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def root?(relation = nil)
|
|
53
|
+
if relation
|
|
54
|
+
relation_graphs[relation].root?(self)
|
|
55
|
+
else
|
|
56
|
+
each_relation_graph.all? { |g| g.root?(self) }
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def leaf?(relation = nil)
|
|
61
|
+
if relation
|
|
62
|
+
relation_graphs[relation].leaf?(self)
|
|
63
|
+
else
|
|
64
|
+
each_relation_graph.all? { |g| g.leaf?(self) }
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def child_object?(object, relation = nil)
|
|
69
|
+
relation_graphs[relation].has_edge?(self, object)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def parent_object?(object, relation = nil)
|
|
73
|
+
relation_graphs[relation].has_edge?(object, self)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def related_object?(object, relation = nil)
|
|
77
|
+
parent_object?(object, relation) || child_object?(object, relation)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def each_parent_object(graph, &block)
|
|
81
|
+
relation_graphs[graph].each_in_neighbour(self, &block)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def each_in_neighbour(graph, &block)
|
|
85
|
+
relation_graphs[graph].each_in_neighbour(self, &block)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def each_child_object(graph, &block)
|
|
89
|
+
relation_graphs[graph].each_out_neighbour(self, &block)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def each_out_neighbour(graph, &block)
|
|
93
|
+
relation_graphs[graph].each_out_neighbour(self, &block)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def sorted_relations
|
|
97
|
+
Relations.all_relations.
|
|
98
|
+
find_all do |rel|
|
|
99
|
+
(rel = relation_graphs.fetch(rel, nil)) && rel.has_vertex?(self)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Yields each relation this vertex is part of, starting with the most
|
|
104
|
+
# specialized relations
|
|
105
|
+
def each_relation_sorted(&block)
|
|
106
|
+
sorted_relations.each(&block)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Removes +self+ from all the graphs it is included in.
|
|
110
|
+
def clear_vertex(remove_strong: true)
|
|
111
|
+
for rel in sorted_relations
|
|
112
|
+
graph = relation_graphs[rel]
|
|
113
|
+
if remove_strong || !graph.strong?
|
|
114
|
+
if graph.remove_vertex(self)
|
|
115
|
+
removed = true
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
removed
|
|
120
|
+
end
|
|
121
|
+
alias :clear_relations :clear_vertex
|
|
122
|
+
|
|
123
|
+
def enum_relations
|
|
124
|
+
Roby.warn_deprecated "DirectedRelationSupport#enum_relations is deprecated, use #each_relation instead"
|
|
125
|
+
each_relation
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# The array of relations this object is part of
|
|
129
|
+
def relations; each_relation.to_a end
|
|
130
|
+
|
|
131
|
+
# Computes and returns the set of objects related with this one (parent
|
|
132
|
+
# or child). If +relation+ is given, enumerate only for this relation,
|
|
133
|
+
# otherwise enumerate for all relations. If +result+ is given, it is a
|
|
134
|
+
# Set in which the related objects are added
|
|
135
|
+
def related_objects(relation = nil, result = Set.new)
|
|
136
|
+
if relation
|
|
137
|
+
result.merge(parent_objects(relation))
|
|
138
|
+
result.merge(child_objects(relation))
|
|
139
|
+
else
|
|
140
|
+
each_root_relation_graph do |g|
|
|
141
|
+
result.merge(g.in_neighbours(self))
|
|
142
|
+
result.merge(g.out_neighbours(self))
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
result
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def enum_parent_objects(relation)
|
|
149
|
+
Roby.warn_deprecated "#enum_parent_objects is deprecated, use #parent_objects or #each_parent_object instead"
|
|
150
|
+
parent_objects(relation)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def parent_objects(relation)
|
|
154
|
+
relation_graphs[relation].in_neighbours(self)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def enum_child_objects(relation)
|
|
158
|
+
Roby.warn_deprecated "#enum_child_objects is deprecated, use #parent_objects or #each_parent_object instead"
|
|
159
|
+
child_objects(relation)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def child_objects(relation)
|
|
163
|
+
relation_graphs[relation].out_neighbours(self)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Add a new child object in the +relation+ relation. This calls
|
|
167
|
+
# * #adding_child_object on +self+ and #adding_parent_object on +child+
|
|
168
|
+
# just before the relation is added
|
|
169
|
+
# * #added_child_object on +self+ and #added_parent_object on +child+
|
|
170
|
+
# just after
|
|
171
|
+
def add_child_object(child, relation, info = nil)
|
|
172
|
+
relation_graphs[relation].add_relation(self, child, info)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Add a new parent object in the +relation+ relation
|
|
176
|
+
# * #adding_child_object on +parent+ and #adding_parent_object on
|
|
177
|
+
# +self+ just before the relation is added
|
|
178
|
+
# * #added_child_object on +parent+ and #added_child_object on +self+
|
|
179
|
+
# just after
|
|
180
|
+
def add_parent_object(parent, relation, info = nil)
|
|
181
|
+
relation_graphs[parent].add_child_object(self, relation, info)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Remove all edges in which +self+ is the source and +child+ the
|
|
185
|
+
# target. If +relation+ is given, it removes only the edge in that
|
|
186
|
+
# relation graph.
|
|
187
|
+
def remove_child_object(child, relation = nil)
|
|
188
|
+
if !relation
|
|
189
|
+
for rel in sorted_relations
|
|
190
|
+
rel.remove_relation(self, child)
|
|
191
|
+
end
|
|
192
|
+
else
|
|
193
|
+
relation_graphs[relation].remove_relation(self, child)
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Remove all edges in which +self+ is the source. If +relation+
|
|
198
|
+
# is given, it removes only the edges in that relation graph.
|
|
199
|
+
def remove_children(relation = nil)
|
|
200
|
+
if !relation
|
|
201
|
+
for rel in sorted_relations
|
|
202
|
+
remove_children(rel)
|
|
203
|
+
end
|
|
204
|
+
return
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
children = child_objects(relation).to_a
|
|
208
|
+
for child in children
|
|
209
|
+
remove_child_object(child, relation)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Remove all edges in which +child+ is the source and +self+ the
|
|
214
|
+
# target. If +relation+ is given, it removes only the edge in that
|
|
215
|
+
# relation graph.
|
|
216
|
+
def remove_parent_object(parent, relation = nil)
|
|
217
|
+
parent.remove_child_object(self, relation)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Remove all edges in which +self+ is the target. If +relation+
|
|
221
|
+
# is given, it removes only the edges in that relation graph.
|
|
222
|
+
def remove_parents(relation = nil)
|
|
223
|
+
if !relation
|
|
224
|
+
for rel in sorted_relations
|
|
225
|
+
remove_parents(rel)
|
|
226
|
+
end
|
|
227
|
+
return
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
parents = parent_objects(relation).to_a
|
|
231
|
+
for parent in parents
|
|
232
|
+
remove_parent_object(relation, parent)
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Remove all relations that point to or come from +to+ If +to+ is nil,
|
|
237
|
+
# it removes all edges in which +self+ is involved.
|
|
238
|
+
#
|
|
239
|
+
# If +relation+ is not nil, only edges of that relation graph are removed.
|
|
240
|
+
def remove_relations(relation = nil)
|
|
241
|
+
if !relation
|
|
242
|
+
for rel in sorted_relations
|
|
243
|
+
remove_relations(rel)
|
|
244
|
+
end
|
|
245
|
+
return
|
|
246
|
+
end
|
|
247
|
+
relation = relation_graphs[relation]
|
|
248
|
+
return if !relation.has_vertex?(self)
|
|
249
|
+
|
|
250
|
+
each_parent_object(relation).to_a.each do |parent|
|
|
251
|
+
relation.remove_relation(parent, self)
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
each_child_object(relation).to_a.each do |child|
|
|
255
|
+
relation.remove_relation(self, child)
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def [](object, graph)
|
|
260
|
+
relation_graphs[graph].edge_info(self, object)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def []=(object, relation, value)
|
|
264
|
+
relation_graphs[relation].set_edge_info(self, object, value)
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Roby
|
|
2
|
+
module Relations
|
|
3
|
+
# Subclass of Relations::Space for events. Its main usage is to keep track of
|
|
4
|
+
# which tasks are related in a given relation through their events.
|
|
5
|
+
#
|
|
6
|
+
# I.e. if events 'a' and 'b' are parts of the tasks ta and tb, and
|
|
7
|
+
#
|
|
8
|
+
# a -> b
|
|
9
|
+
#
|
|
10
|
+
# in this relation graph, then
|
|
11
|
+
#
|
|
12
|
+
# relation.related_tasks?(ta, tb)
|
|
13
|
+
#
|
|
14
|
+
# will return true
|
|
15
|
+
class EventRelationGraph < Relations::Graph
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
module Roby
|
|
2
|
+
module Relations
|
|
3
|
+
# @api private
|
|
4
|
+
#
|
|
5
|
+
# A graph visitor which propagates a value through a subgraph of an
|
|
6
|
+
# acyclic graph, copying the value using #fork at graph forks, and
|
|
7
|
+
# merging them back with #merge when reaching a merge point
|
|
8
|
+
class ForkMergeVisitor < RGL::DFSVisitor
|
|
9
|
+
# The vertex from which we start visiting
|
|
10
|
+
attr_reader :origin
|
|
11
|
+
|
|
12
|
+
# The neighbours of this vertex that should be visited.
|
|
13
|
+
attr_reader :origin_neighbours
|
|
14
|
+
|
|
15
|
+
# A mapping from vertex to the propagated object for this vertex
|
|
16
|
+
attr_reader :vertex_to_object
|
|
17
|
+
|
|
18
|
+
# The pending merges, i.e. a collection of objects gathered so far
|
|
19
|
+
# at a merge point
|
|
20
|
+
attr_reader :pending_merges
|
|
21
|
+
|
|
22
|
+
# The in-degree of each node in the subgraph defined by {#origin}
|
|
23
|
+
# and {#origin_neighbours}
|
|
24
|
+
attr_reader :in_degree
|
|
25
|
+
|
|
26
|
+
# The out-degree of each node in the subgraph defined by {#origin}
|
|
27
|
+
# and {#origin_neighbours}
|
|
28
|
+
attr_reader :out_degree
|
|
29
|
+
|
|
30
|
+
# @param graph the directed graph we propagate the value in
|
|
31
|
+
# @param origin the vertex from which to propagate
|
|
32
|
+
# @param [#include?] origin_neighbours the neighbours of 'origin' to
|
|
33
|
+
# propagate towards
|
|
34
|
+
# @param [#fork,#merge] object the object to propagate in the graph
|
|
35
|
+
def initialize(graph, object, origin, origin_neighbours = graph.out_neighbours(origin))
|
|
36
|
+
super(graph)
|
|
37
|
+
@origin = origin
|
|
38
|
+
@origin_neighbours = origin_neighbours
|
|
39
|
+
|
|
40
|
+
@vertex_to_object = Hash[origin => object]
|
|
41
|
+
@pending_merges = Hash.new { |h, k| h[k] = Array.new }
|
|
42
|
+
|
|
43
|
+
@in_degree, @out_degree = compute_in_out_degrees(origin, origin_neighbours)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def visit
|
|
47
|
+
graph.depth_first_visit(origin, self) {}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# A visitor that counts the in/out degree of vertices contained in a
|
|
51
|
+
# subgraph
|
|
52
|
+
class SubgraphDegreeCounter < RGL::DFSVisitor
|
|
53
|
+
attr_reader :out_degree
|
|
54
|
+
attr_reader :in_degree
|
|
55
|
+
def initialize(graph)
|
|
56
|
+
@out_degree = Hash.new(0)
|
|
57
|
+
@in_degree = Hash.new(0)
|
|
58
|
+
super(graph)
|
|
59
|
+
end
|
|
60
|
+
def handle_tree_edge(u, v)
|
|
61
|
+
out_degree[u] += 1
|
|
62
|
+
in_degree[v] += 1
|
|
63
|
+
end
|
|
64
|
+
def handle_back_edge(u, v)
|
|
65
|
+
out_degree[u] += 1
|
|
66
|
+
in_degree[v] += 1
|
|
67
|
+
end
|
|
68
|
+
def handle_forward_edge(u, v)
|
|
69
|
+
out_degree[u] += 1
|
|
70
|
+
in_degree[v] += 1
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Computes the in and out degree of the subgraph starting at
|
|
75
|
+
# 'origin', following the out-edges of 'origin' that go towards
|
|
76
|
+
# 'origin_neighbours'
|
|
77
|
+
def compute_in_out_degrees(origin, origin_neighbours)
|
|
78
|
+
visitor = SubgraphDegreeCounter.new(graph)
|
|
79
|
+
origin_neighbours.each do |v|
|
|
80
|
+
next if visitor.color_map[v] != :WHITE
|
|
81
|
+
graph.depth_first_visit(v, visitor) { }
|
|
82
|
+
end
|
|
83
|
+
in_degree, out_degree = visitor.in_degree, visitor.out_degree
|
|
84
|
+
|
|
85
|
+
in_degree[origin] = 0
|
|
86
|
+
out_degree[origin] = origin_neighbours.size
|
|
87
|
+
origin_neighbours.each do |v|
|
|
88
|
+
in_degree[v] += 1
|
|
89
|
+
end
|
|
90
|
+
return in_degree, out_degree
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def follow_edge?(u, v)
|
|
94
|
+
if u == origin
|
|
95
|
+
return if !origin_neighbours.include?(v)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
degree = in_degree[v]
|
|
99
|
+
if degree == 1
|
|
100
|
+
true
|
|
101
|
+
else
|
|
102
|
+
(pending_merges[v].size + 1) == degree
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def handle_forward_edge(u, v)
|
|
107
|
+
if u == origin
|
|
108
|
+
return if !origin_neighbours.include?(v)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
obj = vertex_to_object.fetch(u)
|
|
112
|
+
if obj
|
|
113
|
+
if out_degree[u] > 1
|
|
114
|
+
obj = fork_object(obj)
|
|
115
|
+
end
|
|
116
|
+
obj = propagate_object(u, v, obj)
|
|
117
|
+
end
|
|
118
|
+
if in_degree[v] > 1
|
|
119
|
+
pending_merges[v] << obj
|
|
120
|
+
else
|
|
121
|
+
vertex_to_object[v] = obj
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def handle_tree_edge(u, v)
|
|
126
|
+
obj = vertex_to_object.fetch(u)
|
|
127
|
+
if obj
|
|
128
|
+
if out_degree[u] > 1
|
|
129
|
+
obj = fork_object(obj)
|
|
130
|
+
end
|
|
131
|
+
obj = propagate_object(u, v, obj)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
if in_degree[v] > 1
|
|
135
|
+
obj = (pending_merges.delete(v) << obj).compact.inject { |a, b| a.merge(b) }
|
|
136
|
+
end
|
|
137
|
+
vertex_to_object[v] = obj
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def handle_back_edge(u, v)
|
|
141
|
+
raise "#handle_back_edge should never happen in a fork-merge traversal"
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def propagate_object(u, v, obj)
|
|
145
|
+
obj
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def fork_object(obj)
|
|
149
|
+
obj.fork
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
module Roby
|
|
2
|
+
module Relations
|
|
3
|
+
# A relation graph
|
|
4
|
+
#
|
|
5
|
+
# Relation graphs extend the base graph class
|
|
6
|
+
# {BidirectionalDirectedAdjacencyGraph} by adding the ability to
|
|
7
|
+
# arrange the graphs in a hierarchy (where a 'child' is a subgraph of a
|
|
8
|
+
# 'parent'), and the modification methods {#add_relation} and
|
|
9
|
+
# {#remove_relation} that maintain consistency in the hierarchy.
|
|
10
|
+
# Moreover, it allows to set an {#observer} object that listens to graph
|
|
11
|
+
# modifications (Roby uses it to emit relation hooks on plan objects
|
|
12
|
+
# when included in a {ExecutablePlan}).
|
|
13
|
+
#
|
|
14
|
+
# Note that the underlying methods {#add_edge} and {#remove_edge}
|
|
15
|
+
# are still available in cases where the hooks should not be called
|
|
16
|
+
# *and* hierarchy consistency is maintained by other means (e.g. when
|
|
17
|
+
# copying a plan).
|
|
18
|
+
#
|
|
19
|
+
# Finally, it is possible for {#add_edge} to update an existing edge
|
|
20
|
+
# info. For this purpose, a subclass has to implement the {#merge_info}
|
|
21
|
+
# method which is called with the old and new info and should return the
|
|
22
|
+
# merged object. The default implementation raises ArgumentError
|
|
23
|
+
class Graph < BidirectionalDirectedAdjacencyGraph
|
|
24
|
+
extend Models::Graph
|
|
25
|
+
|
|
26
|
+
# True if this relation graph is a DAG
|
|
27
|
+
#
|
|
28
|
+
# This property is not enforced by the Graph class itself as in a
|
|
29
|
+
# lot of cases it would be too expensive. When used in Roby, it is
|
|
30
|
+
# either enforced by {ExecutablePlan} or when committing a
|
|
31
|
+
# transaction
|
|
32
|
+
attr_predicate :dag
|
|
33
|
+
# True if this relation should be seen by remote peers
|
|
34
|
+
attr_predicate :distribute
|
|
35
|
+
# If this relation is weak
|
|
36
|
+
#
|
|
37
|
+
# Weak relations are not considered during garbage collection
|
|
38
|
+
attr_predicate :weak
|
|
39
|
+
# If this relation is strong
|
|
40
|
+
#
|
|
41
|
+
# Strong relations mark parts of the plan that can't be exchanged
|
|
42
|
+
# bit-by-bit. I.e. {Plan#replace_task} will ignore those relations.
|
|
43
|
+
attr_predicate :strong
|
|
44
|
+
|
|
45
|
+
# If this relation embeds some additional information
|
|
46
|
+
attr_predicate :embeds_info?
|
|
47
|
+
|
|
48
|
+
# Whether edges in this relation should be copied on replacement or
|
|
49
|
+
# moved. The default is to move.
|
|
50
|
+
attr_predicate :copy_on_replace
|
|
51
|
+
|
|
52
|
+
# The relation parent (if any)
|
|
53
|
+
#
|
|
54
|
+
# @see superset_of recursive_subsets
|
|
55
|
+
attr_accessor :parent
|
|
56
|
+
|
|
57
|
+
# The set of graphs that are directly children of self in the graph
|
|
58
|
+
# hierarchy. They are subgraphs of self, but not all the existing
|
|
59
|
+
# subgraphs of self
|
|
60
|
+
#
|
|
61
|
+
# @see superset_of recursive_subsets
|
|
62
|
+
attr_reader :subsets
|
|
63
|
+
|
|
64
|
+
# An object that is called for relation modifications
|
|
65
|
+
#
|
|
66
|
+
# The relation will call the following hooks.
|
|
67
|
+
#
|
|
68
|
+
# Addition/removal hooks are called once per modification in the
|
|
69
|
+
# relation hierarchy. They get a 'relations' array which is the list
|
|
70
|
+
# of relation IDs (i.e. graph classes, e.g.
|
|
71
|
+
# {TaskStructure::Dependency}) which are concerned with the
|
|
72
|
+
# modification. This array is sorted from the downmost in the
|
|
73
|
+
# relation hierarchy (i.e. the most specialized) up to the upmost
|
|
74
|
+
# (the biggest superset).
|
|
75
|
+
#
|
|
76
|
+
# adding_edge(from, to, relations, info)
|
|
77
|
+
# added_edge(from, to, relations, info)
|
|
78
|
+
#
|
|
79
|
+
# Before and after a new edge is added between two vertices in the
|
|
80
|
+
# graph. 'info' is the edge info that is set for the edge in the
|
|
81
|
+
# first element of 'relations' (the other relations get nil)
|
|
82
|
+
#
|
|
83
|
+
# updating_edge(from, to, relation, info)
|
|
84
|
+
# updated_edge(from, to, relation, info)
|
|
85
|
+
#
|
|
86
|
+
# Before and after the edge info is set on a given edge. 'relation'
|
|
87
|
+
# is a single relation ID.
|
|
88
|
+
#
|
|
89
|
+
# removing_edge(from, to, relations)
|
|
90
|
+
# removed_edge(from, to, relations)
|
|
91
|
+
#
|
|
92
|
+
# Before and after an edge has been removed.
|
|
93
|
+
attr_reader :observer
|
|
94
|
+
|
|
95
|
+
# Creates a relation graph with the given name and options. The
|
|
96
|
+
# following options are recognized:
|
|
97
|
+
# +dag+::
|
|
98
|
+
# if the graph is a DAG. If true, add_relation will check that
|
|
99
|
+
# no cycle is created
|
|
100
|
+
# +subsets+::
|
|
101
|
+
# a set of Relations::Graph objects that are children of this one.
|
|
102
|
+
# See #superset_of.
|
|
103
|
+
# +distributed+::
|
|
104
|
+
# if this relation graph should be seen by remote hosts
|
|
105
|
+
def initialize(
|
|
106
|
+
observer: nil,
|
|
107
|
+
distribute: self.class.distribute?,
|
|
108
|
+
dag: self.class.dag?,
|
|
109
|
+
weak: self.class.weak?,
|
|
110
|
+
strong: self.class.strong?,
|
|
111
|
+
copy_on_replace: self.class.copy_on_replace?,
|
|
112
|
+
noinfo: !self.class.embeds_info?,
|
|
113
|
+
subsets: Set.new)
|
|
114
|
+
|
|
115
|
+
@observer = observer
|
|
116
|
+
@distribute = distribute
|
|
117
|
+
@dag = dag
|
|
118
|
+
@weak = weak
|
|
119
|
+
@strong = strong
|
|
120
|
+
@copy_on_replace = copy_on_replace
|
|
121
|
+
@embeds_info = !noinfo
|
|
122
|
+
|
|
123
|
+
# If the relation is a single-child relation, it expects to have
|
|
124
|
+
# this ivar set
|
|
125
|
+
if respond_to?(:single_child_accessor)
|
|
126
|
+
@single_child_accessor = "@#{self.class.child_name}"
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
@subsets = Set.new
|
|
130
|
+
subsets.each { |g| superset_of(g) }
|
|
131
|
+
|
|
132
|
+
super()
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Tests whether a vertex is reachable from this one
|
|
136
|
+
#
|
|
137
|
+
# This is at worst O(E), i.e. the number of vertices that are
|
|
138
|
+
# reachable from the source vertex.
|
|
139
|
+
#
|
|
140
|
+
# If you want to do a lot of these queries, or if you want to check
|
|
141
|
+
# for acyclicity, RGL offers better alternatives.
|
|
142
|
+
#
|
|
143
|
+
# @param [Object] u the origin vertex
|
|
144
|
+
# @param [Object] v the vertex whose reachability we want to test
|
|
145
|
+
# from 'u'
|
|
146
|
+
def reachable?(u, v)
|
|
147
|
+
depth_first_visit(u) { |o| return true if o == v }
|
|
148
|
+
false
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def to_s
|
|
152
|
+
"#{self.class.name}:#{object_id.to_s(16)}"
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def inspect; to_s end
|
|
156
|
+
|
|
157
|
+
# Copy a subgraph of self into another graph
|
|
158
|
+
#
|
|
159
|
+
# This method allows to define a mapping of vertices from self
|
|
160
|
+
# (source set) into vertices of another graph (target set), and
|
|
161
|
+
# copies the edges that exist between the vertices of the source set
|
|
162
|
+
# to edges between the corresponding vertices of target set
|
|
163
|
+
#
|
|
164
|
+
# @param [Graph] graph the target graph
|
|
165
|
+
# @param [Hash<Object,Object>] a mapping from the subgraph vertices
|
|
166
|
+
# in self to the corresponding vertices in the target graph
|
|
167
|
+
def copy_subgraph_to(graph, mappings)
|
|
168
|
+
mappings.each do |v, mapped_v|
|
|
169
|
+
each_out_neighbour(v) do |child|
|
|
170
|
+
if mapped_child = mappings[child]
|
|
171
|
+
graph.add_edge(mapped_v, mapped_child,
|
|
172
|
+
edge_info(v, child))
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def find_edge_difference(graph, mapping)
|
|
179
|
+
if graph.num_edges != num_edges
|
|
180
|
+
return [:num_edges_differ]
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
each_edge do |parent, child|
|
|
184
|
+
m_parent, m_child = mapping[parent], mapping[child]
|
|
185
|
+
if !m_parent
|
|
186
|
+
return [:missing_mapping, parent]
|
|
187
|
+
elsif !m_child
|
|
188
|
+
return [:missing_mapping, child]
|
|
189
|
+
elsif !graph.has_vertex?(m_parent) || !graph.has_vertex?(m_child) || !graph.has_edge?(m_parent, m_child)
|
|
190
|
+
return [:missing_edge, parent, child]
|
|
191
|
+
elsif edge_info(parent, child) != graph.edge_info(m_parent, m_child)
|
|
192
|
+
return [:differing_edge_info, parent, child]
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
nil
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Moves a vertex relations onto another
|
|
199
|
+
#
|
|
200
|
+
# @param [Object] from the vertex whose relations are going to be
|
|
201
|
+
# moved
|
|
202
|
+
# @param [Object] to the vertex on which the relations will be
|
|
203
|
+
# added
|
|
204
|
+
# @param [Boolean] remove whether 'from' should be removed from the
|
|
205
|
+
# graph after replacement
|
|
206
|
+
def replace_vertex(from, to, remove: true)
|
|
207
|
+
edges = Array.new
|
|
208
|
+
each_in_neighbour(from) do |parent|
|
|
209
|
+
if parent != to
|
|
210
|
+
add_edge(parent, to, edge_info(parent, from))
|
|
211
|
+
edges << [parent, from]
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
each_out_neighbour(from) do |child|
|
|
215
|
+
if to != child
|
|
216
|
+
add_edge(to, child, edge_info(from, child))
|
|
217
|
+
edges << [from, child]
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
edges.each do |parent, child|
|
|
222
|
+
remove_relation(parent, child)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
if remove
|
|
226
|
+
remove_vertex(from)
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# Add the vertices and edges of a graph in self
|
|
231
|
+
#
|
|
232
|
+
# @param [Graph] graph the graph whose relations should be added to
|
|
233
|
+
# self
|
|
234
|
+
def merge!(graph)
|
|
235
|
+
merge(graph)
|
|
236
|
+
graph.clear
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# @api private
|
|
240
|
+
#
|
|
241
|
+
# Updates the edge information of an existing info, or does nothing
|
|
242
|
+
# if the edge does not exist
|
|
243
|
+
#
|
|
244
|
+
# If the edge has a non-nil info already, the graph's #merge_info is
|
|
245
|
+
# called to merge the existing and new information. If #merge_info
|
|
246
|
+
# returns nil, the update is aborted
|
|
247
|
+
#
|
|
248
|
+
# @param from the edge parent object
|
|
249
|
+
# @param to the edge child object
|
|
250
|
+
# @param info the new edge info
|
|
251
|
+
# @return [Boolean] true if the edge existed and false otherwise
|
|
252
|
+
def try_updating_existing_edge_info(from, to, info)
|
|
253
|
+
return false if !has_edge?(from, to)
|
|
254
|
+
|
|
255
|
+
if !(old_info = edge_info(from, to)).nil?
|
|
256
|
+
if old_info == info
|
|
257
|
+
return true
|
|
258
|
+
elsif !(info = merge_info(from, to, old_info, info))
|
|
259
|
+
raise ArgumentError, "trying to change edge information in #{self} for #{from} => #{to}: old was #{old_info} and new is #{info}"
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
set_edge_info(from, to, info)
|
|
263
|
+
true
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# Add an edge between two objects
|
|
267
|
+
#
|
|
268
|
+
# Unlike {BidirectionalDirectedAdjacencyGraph#add_edge}, it will
|
|
269
|
+
# update the edge info (using {#merge_info}) if the edge already
|
|
270
|
+
# exists.
|
|
271
|
+
#
|
|
272
|
+
# @return true if a new edge was created
|
|
273
|
+
def add_edge(a, b, info)
|
|
274
|
+
if !try_updating_existing_edge_info(a, b, info)
|
|
275
|
+
super
|
|
276
|
+
true
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
# Add an edge between +from+ and +to+. The relation is added on all
|
|
281
|
+
# parent relation graphs as well. If #dag? is true on +self+ or on one
|
|
282
|
+
# of its parents, the method will raise {CycleFoundError} in case the new
|
|
283
|
+
# edge would create a cycle.
|
|
284
|
+
#
|
|
285
|
+
# If +from+ or +to+ define the following hooks:
|
|
286
|
+
# adding_parent_object(parent, relations, info)
|
|
287
|
+
# adding_child_object(child, relations, info)
|
|
288
|
+
# added_parent_object(parent, relations, info)
|
|
289
|
+
# added_child_object(child, relations, info)
|
|
290
|
+
#
|
|
291
|
+
# then these hooks get respectively called before and after having
|
|
292
|
+
# added the relation, where +relations+ is the set of
|
|
293
|
+
# Relations::Graph
|
|
294
|
+
# instances where the edge has been added. It can be either [+self+] if
|
|
295
|
+
# the edge does not already exist in it, or [+self+, +parent+,
|
|
296
|
+
# <tt>parent.parent</tt>, ...] if the parent, grandparent, ... graphs
|
|
297
|
+
# do not include the edge either.
|
|
298
|
+
def add_relation(from, to, info = nil)
|
|
299
|
+
# First check if we're trying to change the edge information
|
|
300
|
+
# rather than creating a new edge
|
|
301
|
+
if try_updating_existing_edge_info(from, to, info)
|
|
302
|
+
return
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
new_relations = []
|
|
306
|
+
new_relations_ids = []
|
|
307
|
+
rel = self
|
|
308
|
+
while rel
|
|
309
|
+
if !rel.has_edge?(from, to)
|
|
310
|
+
new_relations << rel
|
|
311
|
+
new_relations_ids << rel.class
|
|
312
|
+
end
|
|
313
|
+
rel = rel.parent
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
if !new_relations.empty?
|
|
317
|
+
if observer
|
|
318
|
+
observer.adding_edge(from, to, new_relations_ids, info)
|
|
319
|
+
end
|
|
320
|
+
for rel in new_relations
|
|
321
|
+
rel.add_edge(from, to, (info if self == rel))
|
|
322
|
+
end
|
|
323
|
+
if observer
|
|
324
|
+
observer.added_edge(from, to, new_relations_ids, info)
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
# Set the information of an object relation
|
|
330
|
+
def set_edge_info(from, to, info)
|
|
331
|
+
if observer
|
|
332
|
+
observer.updating_edge_info(from, to, self.class, info)
|
|
333
|
+
end
|
|
334
|
+
super
|
|
335
|
+
if observer
|
|
336
|
+
observer.updated_edge_info(from, to, self.class, info)
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
# Method used in {#add_relation} and {#add_edge} to merge existing
|
|
341
|
+
# information with new information
|
|
342
|
+
#
|
|
343
|
+
# It is safe to raise from within this method
|
|
344
|
+
#
|
|
345
|
+
# @return [nil,Object] if nil, the update is aborted. If non-nil,
|
|
346
|
+
# it is the new information
|
|
347
|
+
def merge_info(from, to, old, new)
|
|
348
|
+
raise ArgumentError, "cannot update edge information in #{self}: #merge_info is not implemented"
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
alias :remove_vertex! :remove_vertex
|
|
352
|
+
|
|
353
|
+
def remove_vertex(object)
|
|
354
|
+
if !observer
|
|
355
|
+
return super
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
rel = self
|
|
359
|
+
relations, relations_ids = [], []
|
|
360
|
+
while rel
|
|
361
|
+
relations << rel
|
|
362
|
+
relations_ids << rel.class
|
|
363
|
+
rel = rel.parent
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
removed_relations = Array.new
|
|
367
|
+
in_neighbours(object).each { |parent| removed_relations << parent << object }
|
|
368
|
+
out_neighbours(object).each { |child| removed_relations << object << child }
|
|
369
|
+
|
|
370
|
+
removed_relations.each_slice(2) do |parent, child|
|
|
371
|
+
observer.removing_edge(parent, child, relations_ids)
|
|
372
|
+
end
|
|
373
|
+
relations.each { |rel| rel.remove_vertex!(object) }
|
|
374
|
+
removed_relations.each_slice(2) do |parent, child|
|
|
375
|
+
observer.removed_edge(parent, child, relations_ids)
|
|
376
|
+
end
|
|
377
|
+
!removed_relations.empty?
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# Remove the relation between +from+ and +to+, in this graph and in its
|
|
381
|
+
# parent graphs as well.
|
|
382
|
+
#
|
|
383
|
+
# If +from+ or +to+ define the following hooks:
|
|
384
|
+
# removing_child_object(child, relations)
|
|
385
|
+
# removed_child_object(child, relations)
|
|
386
|
+
#
|
|
387
|
+
# then these hooks get respectively called once before and once after
|
|
388
|
+
# having removed the relation, where +relations+ is the set of
|
|
389
|
+
# Relations::Graph instances where the edge has been removed. It is always
|
|
390
|
+
# <tt>[self, parent, parent.parent, ...]</tt> up to the root relation
|
|
391
|
+
# which is a superset of +self+.
|
|
392
|
+
def remove_relation(from, to)
|
|
393
|
+
if !has_edge?(from, to)
|
|
394
|
+
return
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
rel = self
|
|
398
|
+
relations, relations_ids = [], []
|
|
399
|
+
while rel
|
|
400
|
+
relations << rel
|
|
401
|
+
relations_ids << rel.class
|
|
402
|
+
rel = rel.parent
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
if observer
|
|
406
|
+
observer.removing_edge(from, to, relations_ids)
|
|
407
|
+
end
|
|
408
|
+
for rel in relations
|
|
409
|
+
rel.remove_edge(from, to)
|
|
410
|
+
end
|
|
411
|
+
if observer
|
|
412
|
+
observer.removed_edge(from, to, relations_ids)
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
# Compute the set of all graphs that are subsets of this one in the
|
|
417
|
+
# subset hierarchy
|
|
418
|
+
def recursive_subsets
|
|
419
|
+
result = Set.new
|
|
420
|
+
queue = subsets.to_a.dup
|
|
421
|
+
while !queue.empty?
|
|
422
|
+
g = queue.shift
|
|
423
|
+
result << g
|
|
424
|
+
queue.concat(g.subsets.to_a)
|
|
425
|
+
end
|
|
426
|
+
result
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
# True if this relation does not have a parent
|
|
430
|
+
def root_relation?; !parent end
|
|
431
|
+
|
|
432
|
+
# Returns true if +relation+ is included in this relation (i.e. it is
|
|
433
|
+
# either the same relation or one of its children)
|
|
434
|
+
#
|
|
435
|
+
# See also #superset_of
|
|
436
|
+
def subset?(relation)
|
|
437
|
+
self.eql?(relation) || subsets.any? { |subrel| subrel.subset?(relation) }
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
# The root in this graph's hierarchy
|
|
441
|
+
def root_graph
|
|
442
|
+
g = self
|
|
443
|
+
while g.parent
|
|
444
|
+
g = g.parent
|
|
445
|
+
end
|
|
446
|
+
g
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
# Tests the presence of an edge in this graph or in its supersets
|
|
450
|
+
#
|
|
451
|
+
# See #superset_of for a description of the parent mechanism
|
|
452
|
+
def has_edge_in_hierarchy?(source, target)
|
|
453
|
+
root_graph.has_edge?(source, target)
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
# Declare that +self+ is a superset of +relation+. Once this is done,
|
|
457
|
+
# the system manages two constraints:
|
|
458
|
+
# * new relations added with {#add_relation} are also added in self
|
|
459
|
+
# * a relation can only exist in one subset of self
|
|
460
|
+
#
|
|
461
|
+
# One single graph can be the superset of multiple subgraphs (these are
|
|
462
|
+
# stored in the {#subsets} attribute), but one graph can have only one
|
|
463
|
+
# parent {#parent}.
|
|
464
|
+
#
|
|
465
|
+
# This operation can be called only if the new subset is empty (no
|
|
466
|
+
# edges and no vertices)
|
|
467
|
+
#
|
|
468
|
+
# @param [Graph] relation the relation that should be added as a
|
|
469
|
+
# subset of self
|
|
470
|
+
# @raise [ArgumentError] if 'relation' is not empty
|
|
471
|
+
def superset_of(relation)
|
|
472
|
+
if !relation.empty?
|
|
473
|
+
raise ArgumentError, "cannot pass a non-empty graph to #superset_of"
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
relation.parent = self
|
|
477
|
+
subsets << relation
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
def remove(vertex)
|
|
481
|
+
Roby.warn_deprecated "Graph#remove is deprecated, use #remove_vertex instead"
|
|
482
|
+
remove_vertex(vertex)
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
def link(a, b, info)
|
|
486
|
+
Roby.warn_deprecated "Graph#link is deprecated, use #add_edge instead"
|
|
487
|
+
add_edge(a, b, info)
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
def linked?(parent, child)
|
|
491
|
+
Roby.warn_deprecated "Graph#linked? is deprecated, use #add_edge instead"
|
|
492
|
+
has_edge?(parent, child)
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
def unlink(parent, child)
|
|
496
|
+
Roby.warn_deprecated "Graph#unlink is deprecated, use #remove_edge instead"
|
|
497
|
+
remove_edge(parent, child)
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
def each_parent_vertex(object, &block)
|
|
501
|
+
Roby.warn_deprecated "#each_parent_vertex has been replaced by #each_in_neighbour"
|
|
502
|
+
each_in_neighbour(object, &block)
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
def each_child_vertex(object, &block)
|
|
506
|
+
Roby.warn_deprecated "#each_child_vertex has been replaced by #each_out_neighbour"
|
|
507
|
+
each_out_neighbour(object, &block)
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
def copy_to(target)
|
|
511
|
+
Roby.warn_deprecated "Graph#copy_to is deprecated, use #merge instead (WARN: a.copy_to(b) is b.merge(a) !"
|
|
512
|
+
target.merge(self)
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
def size
|
|
516
|
+
Roby.warn_deprecated "Graph#size is deprecated, use #num_vertices instead"
|
|
517
|
+
num_vertices
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
def include?(object)
|
|
521
|
+
Roby.warn_deprecated "Graph#include? is deprecated, use #has_vertex? instead"
|
|
522
|
+
has_vertex?(object)
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
# @deprecated use {#has_edge_in_hierarchy?}
|
|
526
|
+
def linked_in_hierarchy?(source, target)
|
|
527
|
+
Roby.warn_deprecated "#linked_in_hierarchy? is deprecated, use #has_edge_in_hierarchy? instead"
|
|
528
|
+
has_edge_in_hierarchy?(source, target)
|
|
529
|
+
end
|
|
530
|
+
end
|
|
531
|
+
end
|
|
532
|
+
end
|
|
533
|
+
|