roby 0.7

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.
Files changed (240) hide show
  1. data/.gitignore +29 -0
  2. data/History.txt +4 -0
  3. data/License-fr.txt +519 -0
  4. data/License.txt +515 -0
  5. data/Manifest.txt +245 -0
  6. data/NOTES +4 -0
  7. data/README.txt +163 -0
  8. data/Rakefile +161 -0
  9. data/TODO.txt +146 -0
  10. data/app/README.txt +24 -0
  11. data/app/Rakefile +8 -0
  12. data/app/config/ROBOT.rb +5 -0
  13. data/app/config/app.yml +91 -0
  14. data/app/config/init.rb +7 -0
  15. data/app/config/roby.yml +3 -0
  16. data/app/controllers/.gitattributes +0 -0
  17. data/app/controllers/ROBOT.rb +2 -0
  18. data/app/data/.gitattributes +0 -0
  19. data/app/planners/ROBOT/main.rb +6 -0
  20. data/app/planners/main.rb +5 -0
  21. data/app/scripts/distributed +3 -0
  22. data/app/scripts/generate/bookmarks +3 -0
  23. data/app/scripts/replay +3 -0
  24. data/app/scripts/results +3 -0
  25. data/app/scripts/run +3 -0
  26. data/app/scripts/server +3 -0
  27. data/app/scripts/shell +3 -0
  28. data/app/scripts/test +3 -0
  29. data/app/tasks/.gitattributes +0 -0
  30. data/app/tasks/ROBOT/.gitattributes +0 -0
  31. data/bin/roby +210 -0
  32. data/bin/roby-log +168 -0
  33. data/bin/roby-shell +25 -0
  34. data/doc/images/event_generalization.png +0 -0
  35. data/doc/images/exception_propagation_1.png +0 -0
  36. data/doc/images/exception_propagation_2.png +0 -0
  37. data/doc/images/exception_propagation_3.png +0 -0
  38. data/doc/images/exception_propagation_4.png +0 -0
  39. data/doc/images/exception_propagation_5.png +0 -0
  40. data/doc/images/replay_handler_error.png +0 -0
  41. data/doc/images/replay_handler_error_0.png +0 -0
  42. data/doc/images/replay_handler_error_1.png +0 -0
  43. data/doc/images/roby_cycle_overview.png +0 -0
  44. data/doc/images/roby_replay_02.png +0 -0
  45. data/doc/images/roby_replay_03.png +0 -0
  46. data/doc/images/roby_replay_04.png +0 -0
  47. data/doc/images/roby_replay_event_representation.png +0 -0
  48. data/doc/images/roby_replay_first_state.png +0 -0
  49. data/doc/images/roby_replay_relations.png +0 -0
  50. data/doc/images/roby_replay_startup.png +0 -0
  51. data/doc/images/task_event_generalization.png +0 -0
  52. data/doc/papers.rdoc +11 -0
  53. data/doc/styles/allison.css +314 -0
  54. data/doc/styles/allison.js +316 -0
  55. data/doc/styles/allison.rb +276 -0
  56. data/doc/styles/jamis.rb +593 -0
  57. data/doc/tutorials/01-GettingStarted.rdoc +86 -0
  58. data/doc/tutorials/02-GoForward.rdoc +220 -0
  59. data/doc/tutorials/03-PlannedPath.rdoc +268 -0
  60. data/doc/tutorials/04-EventPropagation.rdoc +236 -0
  61. data/doc/tutorials/05-ErrorHandling.rdoc +319 -0
  62. data/doc/tutorials/06-Overview.rdoc +40 -0
  63. data/doc/videos.rdoc +69 -0
  64. data/ext/droby/dump.cc +175 -0
  65. data/ext/droby/extconf.rb +3 -0
  66. data/ext/graph/algorithm.cc +746 -0
  67. data/ext/graph/extconf.rb +7 -0
  68. data/ext/graph/graph.cc +529 -0
  69. data/ext/graph/graph.hh +183 -0
  70. data/ext/graph/iterator_sequence.hh +102 -0
  71. data/ext/graph/undirected_dfs.hh +226 -0
  72. data/ext/graph/undirected_graph.hh +421 -0
  73. data/lib/roby.rb +41 -0
  74. data/lib/roby/app.rb +870 -0
  75. data/lib/roby/app/rake.rb +56 -0
  76. data/lib/roby/app/run.rb +14 -0
  77. data/lib/roby/app/scripts/distributed.rb +13 -0
  78. data/lib/roby/app/scripts/generate/bookmarks.rb +162 -0
  79. data/lib/roby/app/scripts/replay.rb +31 -0
  80. data/lib/roby/app/scripts/results.rb +15 -0
  81. data/lib/roby/app/scripts/run.rb +26 -0
  82. data/lib/roby/app/scripts/server.rb +18 -0
  83. data/lib/roby/app/scripts/shell.rb +88 -0
  84. data/lib/roby/app/scripts/test.rb +40 -0
  85. data/lib/roby/basic_object.rb +151 -0
  86. data/lib/roby/config.rb +5 -0
  87. data/lib/roby/control.rb +747 -0
  88. data/lib/roby/decision_control.rb +17 -0
  89. data/lib/roby/distributed.rb +32 -0
  90. data/lib/roby/distributed/base.rb +440 -0
  91. data/lib/roby/distributed/communication.rb +871 -0
  92. data/lib/roby/distributed/connection_space.rb +592 -0
  93. data/lib/roby/distributed/distributed_object.rb +206 -0
  94. data/lib/roby/distributed/drb.rb +62 -0
  95. data/lib/roby/distributed/notifications.rb +539 -0
  96. data/lib/roby/distributed/peer.rb +550 -0
  97. data/lib/roby/distributed/protocol.rb +529 -0
  98. data/lib/roby/distributed/proxy.rb +343 -0
  99. data/lib/roby/distributed/subscription.rb +311 -0
  100. data/lib/roby/distributed/transaction.rb +498 -0
  101. data/lib/roby/event.rb +897 -0
  102. data/lib/roby/exceptions.rb +234 -0
  103. data/lib/roby/executives/simple.rb +30 -0
  104. data/lib/roby/graph.rb +166 -0
  105. data/lib/roby/interface.rb +390 -0
  106. data/lib/roby/log.rb +3 -0
  107. data/lib/roby/log/chronicle.rb +303 -0
  108. data/lib/roby/log/console.rb +72 -0
  109. data/lib/roby/log/data_stream.rb +197 -0
  110. data/lib/roby/log/dot.rb +279 -0
  111. data/lib/roby/log/event_stream.rb +151 -0
  112. data/lib/roby/log/file.rb +340 -0
  113. data/lib/roby/log/gui/basic_display.ui +83 -0
  114. data/lib/roby/log/gui/chronicle.rb +26 -0
  115. data/lib/roby/log/gui/chronicle_view.rb +40 -0
  116. data/lib/roby/log/gui/chronicle_view.ui +70 -0
  117. data/lib/roby/log/gui/data_displays.rb +172 -0
  118. data/lib/roby/log/gui/data_displays.ui +155 -0
  119. data/lib/roby/log/gui/notifications.rb +26 -0
  120. data/lib/roby/log/gui/relations.rb +248 -0
  121. data/lib/roby/log/gui/relations.ui +123 -0
  122. data/lib/roby/log/gui/relations_view.rb +185 -0
  123. data/lib/roby/log/gui/relations_view.ui +149 -0
  124. data/lib/roby/log/gui/replay.rb +327 -0
  125. data/lib/roby/log/gui/replay_controls.rb +200 -0
  126. data/lib/roby/log/gui/replay_controls.ui +259 -0
  127. data/lib/roby/log/gui/runtime.rb +130 -0
  128. data/lib/roby/log/hooks.rb +185 -0
  129. data/lib/roby/log/logger.rb +202 -0
  130. data/lib/roby/log/notifications.rb +244 -0
  131. data/lib/roby/log/plan_rebuilder.rb +470 -0
  132. data/lib/roby/log/relations.rb +1056 -0
  133. data/lib/roby/log/server.rb +550 -0
  134. data/lib/roby/log/sqlite.rb +47 -0
  135. data/lib/roby/log/timings.rb +164 -0
  136. data/lib/roby/plan-object.rb +247 -0
  137. data/lib/roby/plan.rb +762 -0
  138. data/lib/roby/planning.rb +13 -0
  139. data/lib/roby/planning/loops.rb +302 -0
  140. data/lib/roby/planning/model.rb +906 -0
  141. data/lib/roby/planning/task.rb +151 -0
  142. data/lib/roby/propagation.rb +562 -0
  143. data/lib/roby/query.rb +619 -0
  144. data/lib/roby/relations.rb +583 -0
  145. data/lib/roby/relations/conflicts.rb +70 -0
  146. data/lib/roby/relations/ensured.rb +20 -0
  147. data/lib/roby/relations/error_handling.rb +23 -0
  148. data/lib/roby/relations/events.rb +9 -0
  149. data/lib/roby/relations/executed_by.rb +193 -0
  150. data/lib/roby/relations/hierarchy.rb +239 -0
  151. data/lib/roby/relations/influence.rb +10 -0
  152. data/lib/roby/relations/planned_by.rb +63 -0
  153. data/lib/roby/robot.rb +7 -0
  154. data/lib/roby/standard_errors.rb +218 -0
  155. data/lib/roby/state.rb +5 -0
  156. data/lib/roby/state/events.rb +221 -0
  157. data/lib/roby/state/information.rb +55 -0
  158. data/lib/roby/state/pos.rb +110 -0
  159. data/lib/roby/state/shapes.rb +32 -0
  160. data/lib/roby/state/state.rb +353 -0
  161. data/lib/roby/support.rb +92 -0
  162. data/lib/roby/task-operations.rb +182 -0
  163. data/lib/roby/task.rb +1618 -0
  164. data/lib/roby/test/common.rb +399 -0
  165. data/lib/roby/test/distributed.rb +214 -0
  166. data/lib/roby/test/tasks/empty_task.rb +9 -0
  167. data/lib/roby/test/tasks/goto.rb +36 -0
  168. data/lib/roby/test/tasks/simple_task.rb +23 -0
  169. data/lib/roby/test/testcase.rb +519 -0
  170. data/lib/roby/test/tools.rb +160 -0
  171. data/lib/roby/thread_task.rb +87 -0
  172. data/lib/roby/transactions.rb +462 -0
  173. data/lib/roby/transactions/proxy.rb +292 -0
  174. data/lib/roby/transactions/updates.rb +139 -0
  175. data/plugins/fault_injection/History.txt +4 -0
  176. data/plugins/fault_injection/README.txt +37 -0
  177. data/plugins/fault_injection/Rakefile +18 -0
  178. data/plugins/fault_injection/TODO.txt +0 -0
  179. data/plugins/fault_injection/app.rb +52 -0
  180. data/plugins/fault_injection/fault_injection.rb +89 -0
  181. data/plugins/fault_injection/test/test_fault_injection.rb +84 -0
  182. data/plugins/subsystems/README.txt +40 -0
  183. data/plugins/subsystems/Rakefile +18 -0
  184. data/plugins/subsystems/app.rb +171 -0
  185. data/plugins/subsystems/test/app/README +24 -0
  186. data/plugins/subsystems/test/app/Rakefile +8 -0
  187. data/plugins/subsystems/test/app/config/app.yml +71 -0
  188. data/plugins/subsystems/test/app/config/init.rb +9 -0
  189. data/plugins/subsystems/test/app/config/roby.yml +3 -0
  190. data/plugins/subsystems/test/app/planners/main.rb +20 -0
  191. data/plugins/subsystems/test/app/scripts/distributed +3 -0
  192. data/plugins/subsystems/test/app/scripts/replay +3 -0
  193. data/plugins/subsystems/test/app/scripts/results +3 -0
  194. data/plugins/subsystems/test/app/scripts/run +3 -0
  195. data/plugins/subsystems/test/app/scripts/server +3 -0
  196. data/plugins/subsystems/test/app/scripts/shell +3 -0
  197. data/plugins/subsystems/test/app/scripts/test +3 -0
  198. data/plugins/subsystems/test/app/tasks/services.rb +15 -0
  199. data/plugins/subsystems/test/test_subsystems.rb +71 -0
  200. data/test/distributed/test_communication.rb +178 -0
  201. data/test/distributed/test_connection.rb +282 -0
  202. data/test/distributed/test_execution.rb +373 -0
  203. data/test/distributed/test_mixed_plan.rb +341 -0
  204. data/test/distributed/test_plan_notifications.rb +238 -0
  205. data/test/distributed/test_protocol.rb +516 -0
  206. data/test/distributed/test_query.rb +102 -0
  207. data/test/distributed/test_remote_plan.rb +491 -0
  208. data/test/distributed/test_transaction.rb +463 -0
  209. data/test/mockups/tasks.rb +27 -0
  210. data/test/planning/test_loops.rb +380 -0
  211. data/test/planning/test_model.rb +427 -0
  212. data/test/planning/test_task.rb +106 -0
  213. data/test/relations/test_conflicts.rb +42 -0
  214. data/test/relations/test_ensured.rb +38 -0
  215. data/test/relations/test_executed_by.rb +149 -0
  216. data/test/relations/test_hierarchy.rb +158 -0
  217. data/test/relations/test_planned_by.rb +54 -0
  218. data/test/suite_core.rb +24 -0
  219. data/test/suite_distributed.rb +9 -0
  220. data/test/suite_planning.rb +3 -0
  221. data/test/suite_relations.rb +8 -0
  222. data/test/test_bgl.rb +508 -0
  223. data/test/test_control.rb +399 -0
  224. data/test/test_event.rb +894 -0
  225. data/test/test_exceptions.rb +592 -0
  226. data/test/test_interface.rb +37 -0
  227. data/test/test_log.rb +114 -0
  228. data/test/test_log_server.rb +132 -0
  229. data/test/test_plan.rb +584 -0
  230. data/test/test_propagation.rb +210 -0
  231. data/test/test_query.rb +266 -0
  232. data/test/test_relations.rb +180 -0
  233. data/test/test_state.rb +414 -0
  234. data/test/test_support.rb +16 -0
  235. data/test/test_task.rb +938 -0
  236. data/test/test_testcase.rb +122 -0
  237. data/test/test_thread_task.rb +73 -0
  238. data/test/test_transactions.rb +569 -0
  239. data/test/test_transactions_proxy.rb +198 -0
  240. metadata +570 -0
@@ -0,0 +1,40 @@
1
+ {Previous tutorial}[link:files/doc/tutorials/05-ErrorHandling_rdoc.html]
2
+ = Overview of other Roby features
3
+
4
+ === Transactions
5
+
6
+ Transactions are a central tool for plan modification in Roby. They are a
7
+ representation of a plan _modification_, i.e. of the changes that are necessary
8
+ to bring the plan which is being executed in a new, desired state. It is
9
+ therefore a safe tool for asynchronous plan modification and execution:
10
+
11
+ * the decision tools can build a new plan without taking into account the
12
+ changes brought by execution
13
+ * the plan execution can safely assess if the new plans are still compatible
14
+ with the built transactions, and refuse applying a transaction if it is not
15
+ safe.
16
+
17
+ Ideally, a cooperation protocol should be implemented to properly handle
18
+ conflicting situations (where the transaction cannot be applied). For now, only
19
+ very crude means are used. This is one of the future evolutions of Roby.
20
+
21
+ Please refer to my PhD thesis for a more extensive presentation of this feature.
22
+
23
+ === Multi-robot execution
24
+
25
+ All models presented here are valid in multi-robot systems. In particular, the
26
+ transactions tool allow to build cooperatively a new plan (something which may
27
+ take time) and apply the plan when a common ground has been found by all the
28
+ present systems.
29
+
30
+ The communication layer, as it is implemented for now, is only valid for
31
+ bi-robot systems. One of its most interesting features is that it does not take
32
+ the presence of a communication link for granted. It is possible for the two
33
+ robots to execute the parts of the plan that do not need communication, and to
34
+ diagnose the loss of communication (for instance, deciding that the joint plan
35
+ is not valid anymore after a given timeout).
36
+
37
+ The communication layer extension to a true multi-robot setup is also for a
38
+ future evolution of Roby. It can be easily be done to a certain extent.
39
+ Reaching a full multi-robot plan execution would take more time.
40
+
data/doc/videos.rdoc ADDED
@@ -0,0 +1,69 @@
1
+ = Videos
2
+
3
+ == Normal operations
4
+
5
+ Those videos don't show what Roby itself does, only results showing
6
+ robots (real and in simulation) acting as they are controlled by a
7
+ Roby application.
8
+
9
+ === Single robot navigation
10
+
11
+ http://roby.rubyforge.org/videos/perception_loops.avi
12
+
13
+ What we see in this video is the perception loop (whose visible part is the DEM
14
+ building) being handled by Roby. The perception updates are triggered by Roby
15
+ on the basis of state events: they are triggered by the translation of the
16
+ robot and the change of heading, to reduce the number of times it is actually done.
17
+
18
+ === Bi-robot navigation
19
+
20
+ http://roby.rubyforge.org/videos/birobot.avi
21
+
22
+ What we see in this video is the cooperation between a rover and an UAV for a
23
+ navigation task. Both robots, as well as the common part of their joint plan is
24
+ written in and managed by Roby. Including part of the data transfer process.
25
+ This bi-robot setup has also successfully been tested on real robots, with an
26
+ iRobot ATRV and a Yamaha RMAX helicopter.
27
+
28
+ In this video, the rover plans its path (the line on the ground) in a
29
+ traversability map (red/green map: red is non-traversable, green is
30
+ traversable). It also generates a set of regions of interest for him. Those
31
+ regions are then considered by the UAV which decides how it will schedule its
32
+ own perception. When the UAV does have perceived a zone, it informs the rover
33
+ and sends it the relevant data. The rover can then update its own map.
34
+
35
+ == Error handling
36
+ === Rflex repaired
37
+
38
+ http://roby.rubyforge.org/videos/rflex_repaired.avi
39
+
40
+ This is a simple example of asynchronous repairs. In this video, the
41
+ microcontroller which drives the robot's motors can give us spurious
42
+ <tt>BRAKES_ON</tt> messages. Our problem is that the Roby controller must
43
+ determine if the message is spurious, or if brakes are actually set by the means
44
+ of an emergency switch for instance. To do that, an error handling is set up,
45
+ which wait for a few seconds and tests the <tt>BRAKES_ON</tt> state of the
46
+ robot. If the brakes are reported as off, then the robot can start moving again.
47
+ Otherwise, the error was a rightful one and should be handled by other means.
48
+
49
+ === P3d repaired
50
+
51
+ http://roby.rubyforge.org/videos/p3d_repaired.avi.
52
+
53
+ In this video, the system handles a problem with DEM generation ("DEM" means
54
+ "Digital Elevation Map". It is a representation of the terrain the robot is on).
55
+ Due to localization issues, it is possible to have a very bad DEM in which the
56
+ robot cannot move. If that happens, the locomotion activity (P3d::Track) emits
57
+ the +blocked+ event. Our way to handle it in three steps:
58
+ 1. a new DEM perception is done. As the robot is not moving, it should give a
59
+ better result. This is called the "Stage 1 handler" in the video.
60
+ 2. if the robot is still blocked, the "Stage 2 handler" completely reinitializes
61
+ the DEM and do a local update.
62
+ 3. if the fault remains, the problem does not lie in the DEM perception process,
63
+ but in the fact that the robot is actually blocked. The error must therefore be
64
+ handled by other means.
65
+
66
+ At all times, if the robot moves more than a given threshold, the problem was
67
+ actually the DEM perception process and the error handler is reset at the first
68
+ stage for following operations.
69
+
data/ext/droby/dump.cc ADDED
@@ -0,0 +1,175 @@
1
+ #include <ruby.h>
2
+ #include <intern.h>
3
+ #include <st.h>
4
+ #include <set>
5
+
6
+ static VALUE mRoby;
7
+ static VALUE mRobyDistributed;
8
+ static VALUE cDRbObject;
9
+ static VALUE cSet;
10
+ static VALUE cValueSet;
11
+ static ID id_droby_dump;
12
+ static ID id_remote_id;
13
+ static ID id_append;
14
+
15
+ /*
16
+ * Document-class: Roby::Distributed
17
+ */
18
+
19
+ /* call-seq:
20
+ * format(object, peer) => formatted_object
21
+ *
22
+ * Formats +object+ so that it is ready to be dumped by Marshal.dump for
23
+ * sending to +peer+. This means that if the object has a droby_dump method, it
24
+ * is called to get a marshallable object which represents +object+. Moreover,
25
+ * if +peer+ responds to #incremental_dump?(object), this is called to
26
+ * determine wether a full dump is required or if sending a
27
+ * Roby::Distributed::RemoteID for remote reference is enough.
28
+ *
29
+ * If the object is not a DRbObject and does not define a #droby_dump method,
30
+ * it is proxied through a DRbObject if it present in
31
+ * Distributed.allow_remote_access. Otherwise, we will try to dump it as-is.
32
+ */
33
+ static VALUE droby_format(int argc, VALUE* argv, VALUE self)
34
+ {
35
+ VALUE object, destination;
36
+ rb_scan_args(argc, argv, "11", &object, &destination);
37
+
38
+ if (RTEST(rb_obj_is_kind_of(object, cDRbObject)))
39
+ return object;
40
+
41
+ if (RTEST(rb_respond_to(object, id_droby_dump)))
42
+ {
43
+ if (!NIL_P(destination) && RTEST(rb_funcall(destination, rb_intern("incremental_dump?"), 1, object)))
44
+ return rb_funcall(object, id_remote_id, 0);
45
+ return rb_funcall(object, id_droby_dump, 1, destination);
46
+ }
47
+
48
+ VALUE remote_access = rb_iv_get(self, "@allowed_remote_access");
49
+ int i;
50
+ for (i = 0; i < RARRAY(remote_access)->len; ++i)
51
+ {
52
+ if (rb_obj_is_kind_of(object, RARRAY(remote_access)->ptr[i]))
53
+ return rb_class_new_instance(1, &object, cDRbObject);
54
+ }
55
+
56
+ return object;
57
+ }
58
+
59
+ typedef struct DROBY_DUMP_ITERATION_ARG
60
+ {
61
+ VALUE result;
62
+ VALUE dest;
63
+ } DROBY_DUMP_ITERATION_ARG;
64
+
65
+ static VALUE array_dump_element(VALUE element, DROBY_DUMP_ITERATION_ARG* arg)
66
+ {
67
+ VALUE args[2] = { element, arg->dest };
68
+ rb_ary_push(arg->result, droby_format(2, args, mRobyDistributed));
69
+ return Qnil;
70
+ }
71
+
72
+ // call-seq:
73
+ // droby_dump(dest) => dumped_array
74
+ //
75
+ // Creates a copy of this Array with all its values formatted for marshalling
76
+ // using Distributed.format.
77
+ static VALUE array_droby_dump(VALUE self, VALUE dest)
78
+ {
79
+ VALUE result = rb_ary_new();
80
+ struct RArray* array = RARRAY(self);
81
+ int i;
82
+
83
+ VALUE el[2] = { Qnil, dest };
84
+ for (i = 0; i < array->len; ++i)
85
+ {
86
+ el[0] = array->ptr[i];
87
+ rb_ary_push(result, droby_format(2, el, mRobyDistributed));
88
+ }
89
+
90
+ return result;
91
+ }
92
+
93
+ static int hash_dump_element(VALUE key, VALUE value, DROBY_DUMP_ITERATION_ARG* arg)
94
+ {
95
+ VALUE args_key[2] = { key, arg->dest };
96
+ key = droby_format(2, args_key, mRobyDistributed);
97
+ VALUE args_value[2] = { value, arg->dest };
98
+ value = droby_format(2, args_value, mRobyDistributed);
99
+ rb_hash_aset(arg->result, key, value);
100
+ return ST_CONTINUE;
101
+ }
102
+
103
+ // call-seq:
104
+ // droby_dump => dumped_hash
105
+ //
106
+ // Creates a copy of this Hash with all its values formatted for marshalling
107
+ // using Distributed.format. The keys are not modified.
108
+ static VALUE hash_droby_dump(VALUE self, VALUE dest)
109
+ {
110
+ DROBY_DUMP_ITERATION_ARG arg = { rb_hash_new(), dest };
111
+ rb_hash_foreach(self, (int(*)(ANYARGS)) hash_dump_element, (VALUE)&arg);
112
+ return arg.result;
113
+ }
114
+
115
+ static VALUE appendable_dump_element(VALUE value, DROBY_DUMP_ITERATION_ARG* arg)
116
+ {
117
+ VALUE args[2] = { value, arg->dest };
118
+ rb_funcall(arg->result, id_append, 1, droby_format(2, args, mRobyDistributed));
119
+ return Qnil;
120
+ }
121
+
122
+ // Creates a copy of this Set with all its values formatted for marshalling
123
+ // using Distributed.format
124
+ static VALUE set_droby_dump(VALUE self, VALUE dest)
125
+ {
126
+ DROBY_DUMP_ITERATION_ARG arg = { rb_class_new_instance(0, 0, cSet), dest };
127
+ rb_iterate(rb_each, self, RUBY_METHOD_FUNC(appendable_dump_element), (VALUE)&arg);
128
+ return arg.result;
129
+ }
130
+
131
+ // Creates a copy of this ValueSet with all its values formatted for
132
+ // marshalling using Distributed.format
133
+ static VALUE value_set_droby_dump(VALUE self, VALUE dest)
134
+ {
135
+ VALUE result = rb_class_new_instance(0, 0, cValueSet);
136
+ std::set<VALUE>* result_set;
137
+ Data_Get_Struct(result, std::set<VALUE>, result_set);
138
+
139
+ std::set<VALUE> const * source_set;
140
+ Data_Get_Struct(self, std::set<VALUE>, source_set);
141
+
142
+ VALUE el[2] = { Qnil, dest };
143
+ for (std::set<VALUE>::const_iterator it = source_set->begin(); it != source_set->end(); ++it)
144
+ {
145
+ el[0] = *it;
146
+ result_set->insert(droby_format(2, el, mRobyDistributed));
147
+ }
148
+
149
+ return result;
150
+ }
151
+
152
+ extern "C" void Init_roby_marshalling()
153
+ {
154
+ id_droby_dump = rb_intern("droby_dump");
155
+ id_remote_id = rb_intern("remote_id");
156
+ id_append = rb_intern("<<");
157
+
158
+ cDRbObject = rb_const_get(rb_cObject, rb_intern("DRbObject"));
159
+ cValueSet = rb_const_get(rb_cObject, rb_intern("ValueSet"));
160
+ cSet = rb_const_get(rb_cObject, rb_intern("Set"));
161
+
162
+ /* */
163
+ mRoby = rb_define_module("Roby");
164
+ /* */
165
+ mRobyDistributed = rb_define_module_under(mRoby, "Distributed");
166
+
167
+ rb_define_method(rb_cArray , "droby_dump" , RUBY_METHOD_FUNC(array_droby_dump) , 1);
168
+ rb_define_method(rb_cHash , "droby_dump" , RUBY_METHOD_FUNC(hash_droby_dump) , 1);
169
+ rb_define_method(cSet , "droby_dump" , RUBY_METHOD_FUNC(set_droby_dump) , 1);
170
+ rb_define_method(cValueSet , "droby_dump" , RUBY_METHOD_FUNC(value_set_droby_dump) , 1);
171
+
172
+ rb_define_singleton_method(mRobyDistributed, "format", RUBY_METHOD_FUNC(droby_format), -1);
173
+
174
+ }
175
+
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+ create_makefile("roby_marshalling")
3
+
@@ -0,0 +1,746 @@
1
+ #include "graph.hh"
2
+ #include <boost/graph/depth_first_search.hpp>
3
+ #include <boost/graph/breadth_first_search.hpp>
4
+ #include <boost/iterator/transform_iterator.hpp>
5
+ #include <boost/iterator/filter_iterator.hpp>
6
+ #include <boost/graph/connected_components.hpp>
7
+ #include <boost/graph/topological_sort.hpp>
8
+ #include <boost/bind.hpp>
9
+ #include <boost/graph/reverse_graph.hpp>
10
+ #include "undirected_graph.hh"
11
+ #include "undirected_dfs.hh"
12
+ #include <queue>
13
+ #include <functional>
14
+
15
+ typedef RubyGraph::vertex_iterator vertex_iterator;
16
+ typedef RubyGraph::vertex_descriptor vertex_descriptor;
17
+ typedef RubyGraph::edge_iterator edge_iterator;
18
+ typedef RubyGraph::edge_descriptor edge_descriptor;
19
+
20
+ static VALUE graph_view_of(VALUE self)
21
+ { return rb_iv_get(self, "@__bgl_real_graph__"); }
22
+
23
+ using namespace boost;
24
+ using namespace std;
25
+
26
+ static ID id_new;
27
+ static VALUE utilrbValueSet;
28
+
29
+ template<typename T>
30
+ struct Queue : std::queue<T>
31
+ {
32
+ T& top() { return this->front(); }
33
+ T const& top() const { return this->front(); }
34
+ };
35
+
36
+ namespace details {
37
+ // Reverse graphs do not have an adjacency_iterator
38
+ template<typename Graph>
39
+ struct vertex_range< boost::reverse_graph<Graph, Graph&>, false>
40
+ {
41
+ typedef typename Graph::adjacency_iterator iterator;
42
+ typedef std::pair<iterator, iterator> range;
43
+
44
+ static range get(RubyGraph::vertex_descriptor v,
45
+ boost::reverse_graph<Graph, Graph&> const& graph)
46
+ { return adjacent_vertices(v, graph.m_g); }
47
+ };
48
+
49
+ template<typename Graph>
50
+ struct vertex_range< boost::reverse_graph<Graph, Graph const&>, false>
51
+ {
52
+ typedef typename Graph::adjacency_iterator iterator;
53
+ typedef std::pair<iterator, iterator> range;
54
+
55
+ static range get(RubyGraph::vertex_descriptor v,
56
+ boost::reverse_graph<Graph, Graph const&> const& graph)
57
+ { return adjacent_vertices(v, graph.m_g); }
58
+ };
59
+ }
60
+
61
+ /* If +key+ is found in +assoc+, returns its value. Otherwise, initializes
62
+ * +key+ to +default_value+ in +assoc+ and returns it
63
+ */
64
+ template<typename Key, typename Value>
65
+ Value& get(map<Key, Value>& assoc, Key const& key, Value const& default_value)
66
+ {
67
+ typename map<Key, Value>::iterator it = assoc.find(key);
68
+ if (it != assoc.end())
69
+ return it->second;
70
+
71
+ tie(it, tuples::ignore) = assoc.insert( make_pair(key, default_value) );
72
+ return it->second;
73
+ }
74
+
75
+ /* If +key+ is found in +assoc+, returns its value. Otherwise, returns +default_value+
76
+ */
77
+ template<typename Key, typename Value>
78
+ Value const& get(map<Key, Value> const& assoc, Key const& key, Value const& default_value)
79
+ {
80
+ typename map<Key, Value>::const_iterator it = assoc.find(key);
81
+ if (it != assoc.end())
82
+ return it->second;
83
+
84
+ return default_value;
85
+ }
86
+
87
+ /* ColorMap is a map with default value */
88
+ class ColorMap : private map<vertex_descriptor, default_color_type>
89
+ {
90
+ template<typename Key, typename Value>
91
+ friend Value& get(map<Key, Value>&, Key const&, Value const&);
92
+
93
+ default_color_type const default_value;
94
+
95
+ typedef map<vertex_descriptor, default_color_type> Super;
96
+
97
+ public:
98
+
99
+ typedef Super::key_type key_type;
100
+ typedef Super::value_type value_type;
101
+
102
+ Super::clear;
103
+
104
+ ColorMap()
105
+ : default_value(color_traits<default_color_type>::white()) {}
106
+
107
+ default_color_type& operator[](vertex_descriptor key)
108
+ {
109
+ default_color_type& c = get(*this, key, default_value);
110
+ return c;
111
+ }
112
+
113
+ };
114
+
115
+ typedef list<vertex_descriptor> vertex_list;
116
+
117
+ struct vertex_recorder : public default_dfs_visitor
118
+ {
119
+ public:
120
+ set<VALUE>& component;
121
+ vertex_recorder( set<VALUE>& component )
122
+ : component(component) { }
123
+
124
+ template<typename G>
125
+ void discover_vertex(vertex_descriptor u, G const& g)
126
+ { component.insert(g[u]); }
127
+ };
128
+
129
+
130
+ static std::set<VALUE>& rb_to_set(VALUE object)
131
+ {
132
+ if (!RTEST(rb_obj_is_kind_of(object, utilrbValueSet)))
133
+ rb_raise(rb_eArgError, "expected a ValueSet");
134
+
135
+ std::set<VALUE>* result_set;
136
+ Data_Get_Struct(object, set<VALUE>, result_set);
137
+ return *result_set;
138
+ }
139
+
140
+ /** Converts a std::set<VALUE> into a ValueSet object
141
+ * After this method, +source+ is empty */
142
+ static VALUE set_to_rb(set<VALUE>& source)
143
+ {
144
+ VALUE result = rb_funcall(utilrbValueSet, id_new, 0);
145
+ set<VALUE>* result_set;
146
+ Data_Get_Struct(result, set<VALUE>, result_set);
147
+
148
+ result_set->swap(source);
149
+ return result;
150
+ }
151
+
152
+ typedef std::set<VALUE> ValueSet;
153
+ /* Adds in +result+ all components generated by the items in [it, end). We
154
+ * assume that there is no component which includes more than one item in
155
+ * [it, end) */
156
+ template<typename Graph, typename Iterator>
157
+ static void graph_components_i(std::list<ValueSet>& result, Graph const& g, Iterator it, Iterator end, bool include_singletons)
158
+ {
159
+ ColorMap colors;
160
+
161
+ result.push_front(ValueSet());
162
+ for (; it != end; ++it)
163
+ {
164
+ if (0 == *it) // elements not in +g+ are handled by graph_result_root_descriptor
165
+ continue;
166
+ if (colors[*it] != color_traits<default_color_type>::white())
167
+ continue;
168
+
169
+ ValueSet& component(*result.begin());
170
+ depth_first_visit(g, *it, vertex_recorder(component), make_assoc_property_map(colors));
171
+ if (component.size() > 1 || include_singletons)
172
+ result.push_front(ValueSet());
173
+ else
174
+ component.clear();
175
+ }
176
+ result.pop_front();
177
+ }
178
+
179
+ /** If +v+ is found in +g+, returns the corresponding vertex_descriptor. Otherwise,
180
+ * add a singleton component to +result+ and return NULL.
181
+ */
182
+ static vertex_descriptor graph_components_root_descriptor(std::list<ValueSet>& result, VALUE v, VALUE g, bool include_singletons)
183
+ {
184
+ vertex_descriptor d;
185
+ bool exists;
186
+ tie(d, exists) = rb_to_vertex(v, g);
187
+ if (! exists)
188
+ {
189
+ if (include_singletons)
190
+ {
191
+ ValueSet component;
192
+ component.insert(v);
193
+ result.push_back(component);
194
+ }
195
+ return NULL;
196
+ }
197
+ return d;
198
+ }
199
+ template<typename Graph>
200
+ static VALUE graph_do_generated_subgraphs(int argc, VALUE* argv, Graph const& g, VALUE self)
201
+ {
202
+ VALUE roots = Qnil, include_singletons;
203
+ if (rb_scan_args(argc, argv, "11", &roots, &include_singletons) == 1)
204
+ include_singletons = Qtrue;
205
+
206
+ bool with_singletons = RTEST(include_singletons) ? true : false;
207
+ std::list<ValueSet> result;
208
+ if (NIL_P(roots))
209
+ {
210
+ RubyGraph::vertex_iterator it, end;
211
+ tie(it, end) = vertices(g);
212
+ // call graph_components_i with all root vertices
213
+ // in +graph+
214
+ graph_components_i(result, g,
215
+ make_filter_iterator(
216
+ bind(
217
+ vertex_has_adjacent_i<Graph, false>,
218
+ _1, ref(g)
219
+ ), it, end
220
+ ),
221
+ make_filter_iterator(
222
+ bind(
223
+ vertex_has_adjacent_i<Graph, false>,
224
+ _1, ref(g)
225
+ ), end, end
226
+ ), with_singletons
227
+ );
228
+ }
229
+ else
230
+ {
231
+ std::set<VALUE>& root_set = rb_to_set(roots);
232
+ std::set<VALUE>::const_iterator
233
+ begin = root_set.begin(),
234
+ end = root_set.end();
235
+
236
+ // call graph_components_i with all vertices given in as argument
237
+ graph_components_i(result, g,
238
+ make_transform_iterator(begin,
239
+ bind(graph_components_root_descriptor, ref(result), _1, self, with_singletons)
240
+ ),
241
+ make_transform_iterator(end,
242
+ bind(graph_components_root_descriptor, ref(result), _1, self, with_singletons)
243
+ ), with_singletons);
244
+ }
245
+
246
+ // Now convert the result into a Ruby array
247
+ VALUE rb_result = rb_ary_new();
248
+ for (std::list<ValueSet>::iterator it = result.begin(); it != result.end(); ++it)
249
+ rb_ary_push(rb_result, set_to_rb(*it));
250
+ return rb_result;
251
+ }
252
+ /*
253
+ * call-seq:
254
+ * graph.components(seeds = nil, include_singletons = true) => components
255
+ *
256
+ * Returns an array of vertex sets. Each set is a connected component of
257
+ * +graph+. If a list of vertices +seeds+ is provided, returns only the
258
+ * components the vertices are part of. The graph is treated as if it were not
259
+ * directed.
260
+ *
261
+ * If +include_singletons+ is false and +seeds+ is non-nil, then +components+
262
+ * will not include the singleton components { v } where v is in +seeds+
263
+ */
264
+ static VALUE graph_components(int argc, VALUE* argv, VALUE self)
265
+ {
266
+ VALUE seeds, include_singletons;
267
+ rb_scan_args(argc, argv, "02", &seeds, &include_singletons);
268
+ if (argc == 1)
269
+ include_singletons = Qtrue;
270
+
271
+ // Compute the connected components
272
+ RubyGraph const& g = graph_wrapped(self);
273
+
274
+ typedef std::map<vertex_descriptor, int> ComponentMap;
275
+ ComponentMap component_map;
276
+ ColorMap color_map;
277
+ int count = connected_components(utilmm::make_undirected_graph(g),
278
+ make_assoc_property_map(component_map),
279
+ boost::color_map( make_assoc_property_map(color_map) ));
280
+
281
+ VALUE ret = rb_ary_new2(count);
282
+ std::vector<bool> enabled_components;
283
+ std::vector<VALUE> components(count);
284
+ if (0 == argc)
285
+ enabled_components.resize(count, true);
286
+ else
287
+ {
288
+ enabled_components.resize(count, false);
289
+ std::set<VALUE>& seed_set = rb_to_set(seeds);
290
+ for (std::set<VALUE>::const_iterator it = seed_set.begin(); it != seed_set.end(); ++it)
291
+ {
292
+ VALUE rb_vertex = *it;
293
+
294
+ vertex_descriptor v; bool in_graph;
295
+ tie(v, in_graph) = rb_to_vertex(rb_vertex, self);
296
+ if (in_graph)
297
+ {
298
+ int v_c = component_map[v];
299
+ enabled_components[v_c] = true;
300
+ }
301
+ else if (RTEST(include_singletons))
302
+ rb_ary_push(ret, rb_ary_new3(1, rb_vertex));
303
+ }
304
+ }
305
+
306
+ // Add empty array for all enabled components
307
+ for (int i = 0; i < count; ++i)
308
+ {
309
+ if (! enabled_components[i]) continue;
310
+ VALUE ary = components[i] = rb_ary_new();
311
+ rb_ary_store(ret, i, ary);
312
+ }
313
+
314
+ // Add the vertices to their corresponding Ruby component
315
+ for (ComponentMap::const_iterator it = component_map.begin(); it != component_map.end(); ++it)
316
+ {
317
+ int c = it->second;
318
+ if (! enabled_components[c])
319
+ continue;
320
+
321
+ rb_ary_push(components[c], g[it->first]);
322
+ }
323
+
324
+ if (argc > 0 && !RTEST(include_singletons))
325
+ {
326
+ // Remove the remaining singletons
327
+ for (int i = 0; i < count; ++i)
328
+ {
329
+ if (! enabled_components[i])
330
+ continue;
331
+ if (RARRAY(components[i])->len == 1)
332
+ rb_ary_store(ret, i, Qnil);
333
+ }
334
+ }
335
+
336
+ // Remove all unused component slots (disabled components)
337
+ rb_funcall(ret, rb_intern("compact!"), 0);
338
+ return ret;
339
+ }
340
+
341
+ /*
342
+ * call-seq:
343
+ * undirected_graph.components(seeds = nil, include_singletons = true) => components
344
+ *
345
+ * Returns an array of vertex sets. Each set is a connected component of +graph+. If
346
+ * a list of vertices is provided, returns only the components the vertices are part of.
347
+ * The graph is treated as if it were not directed. It is equivalent to graph.components.
348
+ */
349
+ static
350
+ VALUE graph_undirected_components(int argc, VALUE* argv, VALUE self)
351
+ { return graph_components(argc, argv, graph_view_of(self)); }
352
+
353
+ /* call-seq:
354
+ * graph.generated_subgraph([v1, v2, ...][, include_singletons]) => components
355
+ *
356
+ * Returns an array of vertex sets. Each set is the component that can be
357
+ * reached from one of the given seed. If no initial vertex is given, the graph
358
+ * roots are taken.
359
+ */
360
+ static VALUE graph_generated_subgraphs(int argc, VALUE* argv, VALUE self)
361
+ { return graph_do_generated_subgraphs(argc, argv, graph_wrapped(self), self); }
362
+
363
+ /* call-seq:
364
+ * graph.generated_subgraph([v1, v2, ...]) => components
365
+ *
366
+ * Like Graph#generated_subgraph, but on the reverse graph of +graph+ (where edges has
367
+ * been swapped)
368
+ */
369
+ static VALUE graph_reverse_generated_subgraphs(int argc, VALUE* argv, VALUE self)
370
+ {
371
+ VALUE real_graph = rb_iv_get(self, "@__bgl_real_graph__");
372
+ return graph_do_generated_subgraphs(argc, argv, make_reverse_graph(graph_wrapped(real_graph)), real_graph);
373
+ }
374
+
375
+ static const int VISIT_TREE_EDGES = 1;
376
+ static const int VISIT_BACK_EDGES = 2;
377
+ static const int VISIT_FORWARD_OR_CROSS_EDGES = 4;
378
+ static const int VISIT_NON_TREE_EDGES = 6;
379
+ static const int VISIT_ALL_EDGES = 7;
380
+
381
+ struct ruby_dfs_visitor : public default_dfs_visitor
382
+ {
383
+
384
+ int m_mode;
385
+ ruby_dfs_visitor(int mode)
386
+ : m_mode(mode) { }
387
+
388
+ template<typename E, typename G>
389
+ void tree_edge(E e, G const& graph)
390
+ { yield_edge(e, graph, VISIT_TREE_EDGES); }
391
+ template<typename E, typename G>
392
+ void back_edge(E e, G const& graph)
393
+ { yield_edge(e, graph, VISIT_BACK_EDGES); }
394
+ template<typename E, typename G>
395
+ void forward_or_cross_edge(E e, G const& graph)
396
+ { yield_edge(e, graph, VISIT_FORWARD_OR_CROSS_EDGES); }
397
+
398
+ template<typename E, typename G>
399
+ void yield_edge(E e, G const& graph, int what)
400
+ {
401
+ if (!(what & m_mode))
402
+ return;
403
+
404
+ VALUE rb_source = graph[source(e, graph)];
405
+ VALUE rb_target = graph[target(e, graph)];
406
+ VALUE info = graph[e].info;
407
+ rb_yield_values(4, rb_source, rb_target, info, INT2FIX(what));
408
+ }
409
+ };
410
+
411
+ template<typename G>
412
+ static bool search_terminator(vertex_descriptor u, G const& g)
413
+ {
414
+ VALUE thread = rb_thread_current();
415
+ bool result = RTEST(rb_thread_local_aref(thread, rb_intern("@prune")));
416
+ if (result)
417
+ rb_thread_local_aset(thread, rb_intern("@prune"), Qfalse);
418
+ return result;
419
+ }
420
+
421
+ /* call-seq:
422
+ * graph.prune
423
+ *
424
+ * In #each_dfs, call this method to stop developing the current branch
425
+ */
426
+ static VALUE graph_prune(VALUE self)
427
+ {
428
+ VALUE thread = rb_thread_current();
429
+ rb_thread_local_aset(thread, rb_intern("@prune"), Qtrue);
430
+ return Qtrue;
431
+ }
432
+
433
+ template<typename Graph>
434
+ static VALUE graph_each_dfs(VALUE self, Graph const& graph, VALUE root, VALUE mode)
435
+ {
436
+ rb_thread_local_aset(rb_thread_current(), rb_intern("@prune"), Qfalse);
437
+
438
+ vertex_descriptor v; bool exists;
439
+ tie(v, exists) = rb_to_vertex(root, self);
440
+ if (! exists)
441
+ return self;
442
+
443
+ map<vertex_descriptor, default_color_type> colors;
444
+ depth_first_visit(graph, v, ruby_dfs_visitor(FIX2INT(mode)),
445
+ make_assoc_property_map(colors), &search_terminator<Graph>);
446
+ return self;
447
+ }
448
+
449
+ /* call-seq:
450
+ * graph.each_dfs(root, mode) { |source, dest, info, kind| ... }
451
+ *
452
+ * Enumerates edges of the graph following a depth-first search order.
453
+ * +mode+ is a filter on the kind of edge which shall be enumerated (TREE,
454
+ * FORWARD_OR_CROSS, BACK and ALL) and +root+ is the source of the search
455
+ */
456
+ static VALUE graph_direct_each_dfs(VALUE self, VALUE root, VALUE mode)
457
+ {
458
+ RubyGraph& graph = graph_wrapped(self);
459
+ return graph_each_dfs(self, graph, root, mode);
460
+ }
461
+
462
+ /* call-seq:
463
+ * graph.each_dfs(root, mode) { |source, dest, info, kind| ... }
464
+ *
465
+ * Enumerates edges of the graph following a depth-first search order.
466
+ * +mode+ is a filter on the kind of edge which shall be enumerated (TREE,
467
+ * NON_TREE and ALL) and +root+ is the source of the search
468
+ */
469
+ static VALUE graph_reverse_each_dfs(VALUE self, VALUE root, VALUE mode)
470
+ {
471
+ VALUE real_graph = graph_view_of(self);
472
+ RubyGraph& graph = graph_wrapped(real_graph);
473
+ return graph_each_dfs(real_graph, make_reverse_graph(graph), root, mode);
474
+ }
475
+
476
+ /* call-seq:
477
+ * graph.each_dfs(root, mode) { |source, dest, info, kind| ... }
478
+ *
479
+ * Enumerates edges of the graph following a depth-first search order.
480
+ * +mode+ is a filter on the kind of edge which shall be enumerated (TREE,
481
+ * FORWARD_OR_CROSS, BACK and ALL) and +root+ is the source of the search
482
+ */
483
+ static VALUE graph_undirected_each_dfs(VALUE self, VALUE root, VALUE mode)
484
+ {
485
+ VALUE real_graph = graph_view_of(self);
486
+ RubyGraph& graph = graph_wrapped(real_graph);
487
+ typedef utilmm::undirected_graph<RubyGraph> Undirected;
488
+ Undirected undirected(graph);
489
+
490
+ vertex_descriptor v; bool exists;
491
+ tie(v, exists) = rb_to_vertex(root, real_graph);
492
+ if (! exists)
493
+ return self;
494
+
495
+ ColorMap colors;
496
+ edge_iterator ei, ei_end;
497
+ for(tie(ei, ei_end) = edges(graph); ei != ei_end; ++ei)
498
+ graph[*ei].color = boost::white_color;
499
+
500
+ rb_thread_local_aset(rb_thread_current(), rb_intern("@prune"), Qfalse);
501
+ utilmm::undirected_depth_first_visit(undirected, v, ruby_dfs_visitor(FIX2INT(mode)),
502
+ make_assoc_property_map(colors),
503
+ utilmm::make_undirected_edge_map(get(&EdgeProperty::color, graph)),
504
+ &search_terminator<Undirected>);
505
+ return self;
506
+ }
507
+
508
+ struct ruby_reachable_visitor : default_dfs_visitor
509
+ {
510
+ bool& m_found;
511
+ vertex_descriptor m_target;
512
+
513
+ ruby_reachable_visitor(bool& found, vertex_descriptor target)
514
+ : m_found(found), m_target(target) { m_found = false; }
515
+
516
+ template<typename E, typename G>
517
+ void tree_edge(E e, G const& graph)
518
+ {
519
+ if (m_target == target(e, graph))
520
+ m_found = true;
521
+ }
522
+ };
523
+
524
+ struct ruby_reachable_terminator
525
+ {
526
+ bool const& found;
527
+ ruby_reachable_terminator(bool const& found)
528
+ : found(found) { }
529
+
530
+ template<typename G>
531
+ bool operator()(vertex_descriptor u, G const& g) const { return found; }
532
+ };
533
+
534
+ /* call-seq:
535
+ * graph.reachable?(v1, v2)
536
+ *
537
+ * Returns true if v2 can be reached from v1
538
+ */
539
+ VALUE graph_reachable_p(VALUE self, VALUE source, VALUE target)
540
+ {
541
+ RubyGraph& graph = graph_wrapped(self);
542
+ vertex_descriptor s, t; bool exists;
543
+ tie(s, exists) = rb_to_vertex(source, self);
544
+ if (! exists)
545
+ return Qfalse;
546
+ tie(t, exists) = rb_to_vertex(target, self);
547
+ if (! exists)
548
+ return Qfalse;
549
+
550
+ map<vertex_descriptor, default_color_type> colors;
551
+ bool found;
552
+ depth_first_visit(graph, s, ruby_reachable_visitor(found, t),
553
+ make_assoc_property_map(colors), ruby_reachable_terminator(found));
554
+
555
+ return found;
556
+ }
557
+
558
+
559
+ struct ruby_bfs_visitor : public default_bfs_visitor
560
+ {
561
+ int m_mode;
562
+ ruby_bfs_visitor(int mode)
563
+ : m_mode(mode) { }
564
+
565
+ template<typename E, typename G>
566
+ void tree_edge(E e, G const& graph)
567
+ { yield_edge(e, graph, VISIT_TREE_EDGES); }
568
+ template<typename E, typename G>
569
+ void non_tree_edge(E e, G const& graph)
570
+ { yield_edge(e, graph, VISIT_NON_TREE_EDGES); }
571
+ template<typename E, typename G>
572
+ void yield_edge(E e, G const& graph, int what)
573
+ {
574
+ if (!(what & m_mode))
575
+ return;
576
+
577
+ VALUE source_vertex = graph[source(e, graph)];
578
+ VALUE target_vertex = graph[target(e, graph)];
579
+ VALUE info = graph[e].info;
580
+ rb_yield_values(4, source_vertex, target_vertex, info, INT2FIX(what));
581
+ }
582
+ };
583
+
584
+ template<typename Graph>
585
+ static VALUE graph_each_bfs(VALUE self, Graph const& graph, VALUE root, VALUE mode)
586
+ {
587
+ int intmode = FIX2INT(mode);
588
+ if ((intmode & VISIT_NON_TREE_EDGES) && ((intmode & VISIT_NON_TREE_EDGES) != VISIT_NON_TREE_EDGES))
589
+ rb_raise(rb_eArgError, "cannot use FORWARD_OR_CROSS and BACK");
590
+
591
+ vertex_descriptor v; bool exists;
592
+ tie(v, exists) = rb_to_vertex(root, self);
593
+ if (! exists)
594
+ return self;
595
+
596
+ rb_thread_local_aset(rb_thread_current(), rb_intern("@prune"), Qfalse);
597
+ map<vertex_descriptor, default_color_type> colors;
598
+ Queue<vertex_descriptor> queue;
599
+ breadth_first_search(graph, v, queue, ruby_bfs_visitor(intmode),
600
+ make_assoc_property_map(colors));
601
+ return self;
602
+ }
603
+
604
+ /* call-seq:
605
+ * graph.each_bfs(root, mode) { |source, dest, info, kind| ... }
606
+ *
607
+ * Enumerates edges of the graph following a breadth-first search order.
608
+ * +mode+ is a filter on the kind of edge which shall be enumerated (TREE,
609
+ * NON_TREE and ALL) and +root+ is the source of the search
610
+ */
611
+ static VALUE graph_direct_each_bfs(VALUE self, VALUE root, VALUE mode)
612
+ {
613
+ RubyGraph& graph = graph_wrapped(self);
614
+ return graph_each_bfs(self, graph, root, mode);
615
+ }
616
+
617
+ /* call-seq:
618
+ * graph.each_bfs(root, mode) { |source, dest, info, kind| ... }
619
+ *
620
+ * Enumerates edges of the graph following a breadth-first search order.
621
+ * +mode+ is a filter on the kind of edge which shall be enumerated (TREE,
622
+ * NON_TREE and ALL) and +root+ is the source of the search
623
+ */
624
+ static VALUE graph_reverse_each_bfs(VALUE self, VALUE root, VALUE mode)
625
+ {
626
+ VALUE real_graph = graph_view_of(self);
627
+ RubyGraph& graph = graph_wrapped(real_graph);
628
+ return graph_each_bfs(real_graph, make_reverse_graph(graph), root, mode);
629
+ }
630
+
631
+ /* call-seq:
632
+ * graph.each_bfs(root, mode) { |source, dest, info, kind| ... }
633
+ *
634
+ * Enumerates edges of the graph following a breadth-first search order.
635
+ * +mode+ is a filter on the kind of edge which shall be enumerated (TREE,
636
+ * NON_TREE and ALL) and +root+ is the source of the search
637
+ */
638
+ static VALUE graph_undirected_each_bfs(VALUE self, VALUE root, VALUE mode)
639
+ {
640
+ VALUE real_graph = graph_view_of(self);
641
+ RubyGraph& graph = graph_wrapped(real_graph);
642
+ return graph_each_bfs(real_graph, utilmm::make_undirected_graph(graph), root, mode);
643
+ }
644
+
645
+ /* call-seq:
646
+ * graph.topological_sort => array
647
+ *
648
+ * Returns a topological sorting of this graph
649
+ */
650
+ static VALUE graph_topological_sort(int argc, VALUE* argv, VALUE self)
651
+ {
652
+ VALUE rb_result;
653
+ rb_scan_args(argc, argv, "01", &rb_result);
654
+ if (NIL_P(rb_result))
655
+ rb_result = rb_ary_new();
656
+ else
657
+ rb_ary_clear(rb_result);
658
+
659
+ RubyGraph& graph = graph_wrapped(self);
660
+ typedef std::vector<RubyGraph::vertex_descriptor> Result;
661
+ Result result;
662
+
663
+ map<vertex_descriptor, default_color_type> colors;
664
+ try
665
+ {
666
+ topological_sort(graph, std::back_inserter(result),
667
+ boost::color_map(make_assoc_property_map(colors)));
668
+
669
+ for (int i = result.size() - 1; i >= 0; --i)
670
+ rb_ary_push(rb_result, graph[result[i]]);
671
+ return rb_result;
672
+ }
673
+ catch(boost::not_a_dag) {}
674
+ rb_raise(rb_eArgError, "the graph is not a DAG");
675
+ }
676
+
677
+ /**********************************************************************
678
+ * Extension initialization
679
+ */
680
+
681
+ /*
682
+ * Document-class: BGL
683
+ *
684
+ * The BGL module defines a Graph class and a Vertex module. The Graph class can
685
+ * be used to manipulate graphs where vertices are referenced by a graph descriptor
686
+ * (Graph#add_edge, Graph#add_vertex, ...). However, the preferred way to us BGL is
687
+ * to mix Vertex in the vertex objects and use the associated methods:
688
+ *
689
+ * class MyNode
690
+ * include BGL::Graph
691
+ * end
692
+ * graph = Graph.new
693
+ * v1, v2 = MyNode.new, MyNode.new
694
+ * graph.link(v1, v2, [])
695
+ * ...
696
+ * v1.each_child_object { ... }
697
+ */
698
+
699
+ /*
700
+ * Document-class: BGL::Graph
701
+ *
702
+ * A directed graph between Ruby objects. See BGL documentation.
703
+ */
704
+
705
+ /*
706
+ * Document-class: BGL::Vertex
707
+ *
708
+ * A module to be mixed in objects used as vertices in Graph. It
709
+ * allows to use the same object in more than one graph.
710
+ */
711
+
712
+ void Init_graph_algorithms()
713
+ {
714
+ id_new = rb_intern("new");
715
+
716
+ bglModule = rb_define_module("BGL");
717
+ bglGraph = rb_define_class_under(bglModule, "Graph", rb_cObject);
718
+ rb_define_const(bglGraph , "TREE" , INT2FIX(VISIT_TREE_EDGES));
719
+ rb_define_const(bglGraph , "FORWARD_OR_CROSS" , INT2FIX(VISIT_FORWARD_OR_CROSS_EDGES));
720
+ rb_define_const(bglGraph , "BACK" , INT2FIX(VISIT_BACK_EDGES));
721
+ rb_define_const(bglGraph , "NON_TREE" , INT2FIX(VISIT_NON_TREE_EDGES));
722
+ rb_define_const(bglGraph , "ALL" , INT2FIX(VISIT_ALL_EDGES));
723
+
724
+ rb_define_method(bglGraph, "components", RUBY_METHOD_FUNC(graph_components), -1);
725
+ rb_define_method(bglGraph, "generated_subgraphs", RUBY_METHOD_FUNC(graph_generated_subgraphs), -1);
726
+ rb_define_method(bglGraph, "each_dfs", RUBY_METHOD_FUNC(graph_direct_each_dfs), 2);
727
+ rb_define_method(bglGraph, "each_bfs", RUBY_METHOD_FUNC(graph_direct_each_bfs), 2);
728
+ rb_define_method(bglGraph, "reachable?", RUBY_METHOD_FUNC(graph_reachable_p), 2);
729
+ rb_define_method(bglGraph, "prune", RUBY_METHOD_FUNC(graph_prune), 0);
730
+ rb_define_method(bglGraph, "topological_sort", RUBY_METHOD_FUNC(graph_topological_sort), -1);
731
+
732
+ bglReverseGraph = rb_define_class_under(bglGraph, "Reverse", rb_cObject);
733
+ rb_define_method(bglReverseGraph, "generated_subgraphs",RUBY_METHOD_FUNC(graph_reverse_generated_subgraphs), -1);
734
+ rb_define_method(bglReverseGraph, "each_dfs", RUBY_METHOD_FUNC(graph_reverse_each_dfs), 2);
735
+ rb_define_method(bglReverseGraph, "each_bfs", RUBY_METHOD_FUNC(graph_reverse_each_bfs), 2);
736
+ rb_define_method(bglReverseGraph, "prune", RUBY_METHOD_FUNC(graph_prune), 0);
737
+
738
+ bglUndirectedGraph = rb_define_class_under(bglGraph, "Undirected", rb_cObject);
739
+ rb_define_method(bglUndirectedGraph, "generated_subgraphs", RUBY_METHOD_FUNC(graph_undirected_components), -1);
740
+ rb_define_method(bglUndirectedGraph, "each_dfs", RUBY_METHOD_FUNC(graph_undirected_each_dfs), 2);
741
+ rb_define_method(bglUndirectedGraph, "each_bfs", RUBY_METHOD_FUNC(graph_undirected_each_bfs), 2);
742
+ rb_define_method(bglUndirectedGraph, "prune", RUBY_METHOD_FUNC(graph_prune), 0);
743
+
744
+ utilrbValueSet = rb_define_class("ValueSet", rb_cObject);
745
+ }
746
+