redshift 1.3.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. data/.gitignore +8 -0
  2. data/README +5 -0
  3. data/RELEASE-NOTES +455 -0
  4. data/TODO +431 -0
  5. data/bench/alg-state.rb +61 -0
  6. data/bench/bench +26 -0
  7. data/bench/bench.rb +10 -0
  8. data/bench/continuous.rb +76 -0
  9. data/bench/diff-bench +86 -0
  10. data/bench/discrete.rb +101 -0
  11. data/bench/euler.rb +50 -0
  12. data/bench/formula.rb +78 -0
  13. data/bench/half-strict.rb +103 -0
  14. data/bench/inertness.rb +116 -0
  15. data/bench/queue.rb +92 -0
  16. data/bench/run +66 -0
  17. data/bench/simple.rb +74 -0
  18. data/bench/strictness.rb +86 -0
  19. data/examples/ball-tkar.rb +72 -0
  20. data/examples/ball.rb +123 -0
  21. data/examples/collide.rb +70 -0
  22. data/examples/connect-parallel.rb +48 -0
  23. data/examples/connect.rb +109 -0
  24. data/examples/constants.rb +27 -0
  25. data/examples/delay.rb +80 -0
  26. data/examples/derivative.rb +77 -0
  27. data/examples/euler.rb +46 -0
  28. data/examples/external-lib.rb +33 -0
  29. data/examples/guard-debugger.rb +77 -0
  30. data/examples/lotka-volterra.rb +33 -0
  31. data/examples/persist-ball.rb +68 -0
  32. data/examples/pid.rb +87 -0
  33. data/examples/ports.rb +60 -0
  34. data/examples/queue.rb +56 -0
  35. data/examples/queue2.rb +98 -0
  36. data/examples/reset-with-event-val.rb +28 -0
  37. data/examples/scheduler.rb +104 -0
  38. data/examples/set-dest.rb +23 -0
  39. data/examples/simulink/README +1 -0
  40. data/examples/simulink/delay.mdl +827 -0
  41. data/examples/simulink/derivative.mdl +655 -0
  42. data/examples/step-discrete-profiler.rb +103 -0
  43. data/examples/subsystem.rb +109 -0
  44. data/examples/sync-deadlock.rb +32 -0
  45. data/examples/sync-queue.rb +91 -0
  46. data/examples/sync-retry.rb +20 -0
  47. data/examples/sync.rb +51 -0
  48. data/examples/thermostat.rb +53 -0
  49. data/examples/zeno.rb +53 -0
  50. data/lib/accessible-index.rb +47 -0
  51. data/lib/redshift.rb +1 -0
  52. data/lib/redshift/component.rb +412 -0
  53. data/lib/redshift/meta.rb +183 -0
  54. data/lib/redshift/mixins/zeno-debugger.rb +69 -0
  55. data/lib/redshift/port.rb +57 -0
  56. data/lib/redshift/queue.rb +104 -0
  57. data/lib/redshift/redshift.rb +111 -0
  58. data/lib/redshift/state.rb +31 -0
  59. data/lib/redshift/syntax.rb +558 -0
  60. data/lib/redshift/target/c.rb +37 -0
  61. data/lib/redshift/target/c/component-gen.rb +1303 -0
  62. data/lib/redshift/target/c/flow-gen.rb +325 -0
  63. data/lib/redshift/target/c/flow/algebraic.rb +85 -0
  64. data/lib/redshift/target/c/flow/buffer.rb +74 -0
  65. data/lib/redshift/target/c/flow/delay.rb +203 -0
  66. data/lib/redshift/target/c/flow/derivative.rb +101 -0
  67. data/lib/redshift/target/c/flow/euler.rb +67 -0
  68. data/lib/redshift/target/c/flow/expr.rb +113 -0
  69. data/lib/redshift/target/c/flow/rk4.rb +80 -0
  70. data/lib/redshift/target/c/library.rb +85 -0
  71. data/lib/redshift/target/c/world-gen.rb +1370 -0
  72. data/lib/redshift/target/spec.rb +34 -0
  73. data/lib/redshift/world.rb +300 -0
  74. data/rakefile +37 -0
  75. data/test/test.rb +52 -0
  76. data/test/test_buffer.rb +58 -0
  77. data/test/test_connect.rb +242 -0
  78. data/test/test_connect_parallel.rb +47 -0
  79. data/test/test_connect_strict.rb +135 -0
  80. data/test/test_constant.rb +74 -0
  81. data/test/test_delay.rb +145 -0
  82. data/test/test_derivative.rb +48 -0
  83. data/test/test_discrete.rb +592 -0
  84. data/test/test_discrete_isolated.rb +92 -0
  85. data/test/test_exit.rb +59 -0
  86. data/test/test_flow.rb +200 -0
  87. data/test/test_flow_link.rb +288 -0
  88. data/test/test_flow_sub.rb +100 -0
  89. data/test/test_flow_trans.rb +292 -0
  90. data/test/test_inherit.rb +127 -0
  91. data/test/test_inherit_event.rb +74 -0
  92. data/test/test_inherit_flow.rb +139 -0
  93. data/test/test_inherit_link.rb +65 -0
  94. data/test/test_inherit_setup.rb +56 -0
  95. data/test/test_inherit_state.rb +66 -0
  96. data/test/test_inherit_transition.rb +168 -0
  97. data/test/test_numerics.rb +34 -0
  98. data/test/test_queue.rb +90 -0
  99. data/test/test_queue_alone.rb +115 -0
  100. data/test/test_reset.rb +209 -0
  101. data/test/test_setup.rb +119 -0
  102. data/test/test_strict_continuity.rb +410 -0
  103. data/test/test_strict_reset_error.rb +30 -0
  104. data/test/test_strictness_error.rb +32 -0
  105. data/test/test_sync.rb +185 -0
  106. data/test/test_world.rb +328 -0
  107. metadata +204 -0
@@ -0,0 +1,145 @@
1
+ require 'redshift'
2
+ include RedShift
3
+
4
+ # Tests delay of continuous var.
5
+ class DelayTestComponent < Component
6
+ constant :pi => Math::PI
7
+ constant :d => 0.2
8
+ @@d2 = d2 = 0.1
9
+
10
+ flow do
11
+ diff " t' = 1 "
12
+ alg " u = sin(t*pi/2) "
13
+ alg " shift_u = sin((t-(d+#{d2}))*pi/2) " # u shifted by d+d2
14
+ delay " delay_u = u + 1 ", :by => "d+#{d2}" # u+1 delayed by d+d2
15
+ alg " err = shift_u - (delay_u - 1)"
16
+
17
+ delay " zdelay_t = t ", :by => 0.3
18
+ end
19
+
20
+ constant :new_d => 0.5 # change this to see how varying delay works
21
+ constant :t_new_d => 5.0
22
+ transition do
23
+ guard "t > t_new_d && d != new_d"
24
+ reset :d => "new_d"
25
+ end
26
+
27
+ def assert_consistent test
28
+ if t > d + @@d2 and (t < t_new_d or t > t_new_d + new_d)
29
+ test.assert_in_delta(0, err, 1.0E-10)
30
+ end
31
+
32
+ if t >= 0.3
33
+ test.assert_in_delta(t - 0.3, zdelay_t, 1.0E-10)
34
+ # zdelay will be evaluated after t (alphabetical), so this assertion
35
+ # breaks before the fix in 1.2.19. (At rk_level==3, evaluating t
36
+ # writes to t's value_0, which is what the evaluation of zdelay is
37
+ # trying to capture.
38
+ end
39
+ end
40
+ end
41
+
42
+ class StateChanger < Component
43
+ state :Normal, :Delayed
44
+ start Normal
45
+ constant :eps => 1e-10
46
+
47
+ flow Normal, Delayed do
48
+ diff " x' = 1 "
49
+ end
50
+
51
+ flow Delayed do
52
+ delay " xd = x ", :by => "1.0"
53
+ end
54
+
55
+ debug = false
56
+
57
+ transition Normal => Delayed do
58
+ guard " x >= 2 - eps && x < 2.2 "
59
+ action {debug_output} if debug
60
+ end
61
+
62
+ transition Delayed => Normal do
63
+ guard " x >= 5 - eps && x < 5.2 "
64
+ action {debug_output} if debug
65
+ end
66
+
67
+ transition Normal => Delayed do
68
+ guard " x >= 7 - eps && x < 7.2 "
69
+ action {debug_output} if debug
70
+ end
71
+
72
+ transition Delayed => Normal do
73
+ guard " x >= 9 - eps && x < 9.2 "
74
+ action {debug_output} if debug
75
+ end
76
+
77
+ def assert_consistent test
78
+ if x <= 2 + eps
79
+ # at 2, nothing has been put in buffer yet
80
+ test.assert_in_delta(0, xd, 1e-10)
81
+ elsif x <= 3 - eps
82
+ # buffer warm up
83
+ test.assert_in_delta(2, xd, 1e-10)
84
+ elsif x <= 5 - eps
85
+ test.assert_in_delta(x-1, xd, 1e-10)
86
+ elsif x <= 7 - eps
87
+ # stale data
88
+ test.assert_in_delta(4, xd, 1e-10)
89
+ elsif x <= 8 - eps
90
+ # still consuming old data -- not sure this is right, but it
91
+ # is simple -- see comments in delay.rb
92
+ test.assert_in_delta(x-3, xd, 1e-10)
93
+ elsif x <= 9 - eps
94
+ test.assert_in_delta(x-1, xd, 1e-10)
95
+ else
96
+ test.assert_in_delta(8, xd, 1e-10)
97
+ end
98
+ end
99
+
100
+ def debug_output
101
+ p self, self.xd_buffer_data
102
+ end
103
+ end
104
+
105
+ require 'test/unit'
106
+
107
+ class TestDelay < Test::Unit::TestCase
108
+
109
+ def setup
110
+ @world = World.new
111
+ end
112
+
113
+ def teardown
114
+ @world = nil
115
+ end
116
+
117
+ def test_delay
118
+ c = @world.create(DelayTestComponent)
119
+ @world.evolve 100 do
120
+ c.assert_consistent self
121
+ end
122
+ end
123
+
124
+ def test_persist
125
+ c = @world.create(DelayTestComponent)
126
+ @world.evolve 50
127
+
128
+ w = Marshal.load(Marshal.dump(@world))
129
+ a = w.grep(DelayTestComponent)
130
+ assert_equal(1, a.size)
131
+ c2 = a[0]
132
+
133
+ w.evolve 100 do
134
+ c2.assert_consistent self
135
+ end
136
+ end
137
+
138
+ def test_state_change
139
+ c = @world.create(StateChanger)
140
+ @world.evolve 10.0 do
141
+ c.assert_consistent self
142
+ #puts "%5.3f: %5.3f" % [c.x, c.xd]
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,48 @@
1
+ require 'redshift'
2
+ include RedShift
3
+
4
+ # Tests numerical differentiation.
5
+ class DerivativeTestComponent < Component
6
+ flow do
7
+ diff " t' = 1 "
8
+
9
+ alg " u = sin(t) "
10
+ alg " sdu = cos(t) " # symbolic derivative
11
+ derive " ndu = (u+5)' ",# numerical derivative -- expr OK
12
+ :feedback => false
13
+ diff " nindu' = ndu " # numerical integral of ndu
14
+ diff " niu' = u " # numerical integral of u
15
+ derive " ndniu = niu' ",# numerical derivative of niu
16
+ :feedback => false
17
+
18
+ alg " err = sdu - ndu "
19
+ alg " e_ndni = ndniu - u "
20
+ alg " e_nind = nindu - u "
21
+ end
22
+
23
+ def assert_consistent test
24
+ test.assert_in_delta(0, err, 0.025)
25
+ test.assert_in_delta(0, e_ndni, 0.0025)
26
+ test.assert_in_delta(0, e_nind, 0.2)
27
+ end
28
+ end
29
+
30
+ require 'test/unit'
31
+
32
+ class TestDerivative < Test::Unit::TestCase
33
+
34
+ def setup
35
+ @world = World.new
36
+ end
37
+
38
+ def teardown
39
+ @world = nil
40
+ end
41
+
42
+ def test_derivative
43
+ c = @world.create(DerivativeTestComponent)
44
+ @world.evolve 100 do
45
+ c.assert_consistent self
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,592 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'redshift'
4
+
5
+ include RedShift
6
+
7
+ =begin
8
+
9
+ This file tests discrete features of RedShift, such as transitions and events. Inheritance of discrete behavior is tested separately in test_interit*.rb.
10
+
11
+ =end
12
+
13
+ class DiscreteTestComponent < Component
14
+ def initialize(*args)
15
+ super
16
+ @t = world.clock if world
17
+ end
18
+ end
19
+
20
+ # Enter is the default starting state
21
+
22
+ class Discrete_1 < DiscreteTestComponent
23
+ def assert_consistent test
24
+ test.assert_equal(state, Enter)
25
+ end
26
+ end
27
+
28
+ # Transitions are Enter => Enter by default
29
+
30
+ class Discrete_1_1 < DiscreteTestComponent
31
+ transition do
32
+ guard {not @check}
33
+ action {@check = true}
34
+ end
35
+ def assert_consistent test
36
+ test.assert(@check == true)
37
+ end
38
+ end
39
+
40
+ # Exit causes the component to leave the world
41
+
42
+ class Discrete_2 < DiscreteTestComponent
43
+ def initialize(*args)
44
+ super
45
+ @prev_world = world
46
+ end
47
+ transition Enter => Exit
48
+ def assert_consistent test
49
+ test.assert_equal(Exit, state)
50
+ test.assert_nil(world)
51
+ test.assert_nil(@prev_world.find {|c| c == self})
52
+ end
53
+ end
54
+
55
+ class Discrete_2a < DiscreteTestComponent
56
+ default {@prev_world = world}
57
+ start Exit
58
+ def assert_consistent test
59
+ test.assert_equal(Exit, state)
60
+ test.assert_nil(world)
61
+ test.assert_nil(@prev_world.find {|c| c == self})
62
+ end
63
+ end
64
+
65
+ # 'start <state>' sets the start state, but fails after initialization
66
+
67
+ class Discrete_3 < DiscreteTestComponent
68
+ state :A
69
+ default { start A }
70
+ def assert_consistent test
71
+ test.assert_equal(A, state)
72
+ test.assert_raises(AlreadyStarted) {start A}
73
+ end
74
+ end
75
+
76
+ class Discrete_4a < DiscreteTestComponent
77
+ state :A, :B; start A
78
+ transition A => B do
79
+ event :e => 3
80
+ end
81
+ transition B => Exit do
82
+ event :e => 4
83
+ end
84
+ end
85
+
86
+ class Discrete_4b < DiscreteTestComponent
87
+ state :A, :B; start A
88
+ link :x
89
+ constant :x_e_value_in_reset
90
+
91
+ transition A => B do
92
+ sync :x => :e
93
+ guard {
94
+ @x_e_value_in_guard = [x.e] #no value during guard
95
+ true
96
+ }
97
+ reset :x_e_value_in_reset => proc {x.e}
98
+ action {
99
+ @x_e_value_in_action = x.e
100
+ }
101
+ post {
102
+ @x_e_value_in_post = x.e
103
+ }
104
+ end
105
+
106
+ transition B => Exit do
107
+ sync :x => :e
108
+ guard {
109
+ @x_e_value_in_guard2 = [x.e] #no value during guard
110
+ true
111
+ }
112
+ end
113
+
114
+ setup { self.x = create Discrete_4a }
115
+ def assert_consistent test
116
+ test.assert_equal(Exit, state)
117
+ test.assert_equal([nil], @x_e_value_in_guard)
118
+ test.assert_equal(3, @x_e_value_in_action)
119
+ test.assert_equal(3, @x_e_value_in_post)
120
+ test.assert_equal(3, x_e_value_in_reset)
121
+ test.assert_equal([nil], @x_e_value_in_guard2)
122
+ end
123
+ end
124
+
125
+ # event value is true by default, and nil when not exported
126
+
127
+ class Discrete_5a < DiscreteTestComponent
128
+ transition Enter => Exit do event :e end
129
+ end
130
+
131
+ class Discrete_5b < DiscreteTestComponent
132
+ link :x
133
+ transition do
134
+ sync :x => :e
135
+ action {@x_e = [x.e]}
136
+ end
137
+ setup { self.x = create Discrete_5a }
138
+ def assert_consistent test
139
+ test.assert_equal([true], @x_e)
140
+ test.assert_equal(nil, x.e)
141
+ end
142
+ end
143
+
144
+ # event value can be supplied statically...
145
+
146
+ class Discrete_6a < DiscreteTestComponent
147
+ EventValue = [[3.75], {1 => :foo}]
148
+ transition Enter => Exit do
149
+ event :e => EventValue
150
+ end
151
+ end
152
+
153
+ class Discrete_6b < DiscreteTestComponent
154
+ link :x
155
+ transition do
156
+ sync :x => :e
157
+ action {@x_e = x.e}
158
+ end
159
+ setup { self.x = create Discrete_6a }
160
+ def assert_consistent test
161
+ test.assert_equal(Discrete_6a::EventValue, @x_e)
162
+ end
163
+ end
164
+
165
+ # ...or dynamically
166
+
167
+ class Discrete_7a < DiscreteTestComponent
168
+ EventValue = [[3.75], {1 => :foo}]
169
+ transition Enter => Exit do
170
+ event {
171
+ e {EventValue}
172
+ }
173
+ end
174
+ end
175
+
176
+ class Discrete_7b < DiscreteTestComponent
177
+ link :x
178
+ transition do
179
+ sync :x => :e
180
+ action {@x_e = x.e}
181
+ end
182
+ setup { self.x = create Discrete_7a }
183
+ def assert_consistent test
184
+ test.assert_equal(Discrete_7a::EventValue, @x_e)
185
+ end
186
+ end
187
+
188
+ # Also, can use C exprs.
189
+
190
+ class Discrete_7c < DiscreteTestComponent
191
+ constant :z => 0.31
192
+ transition Enter => Exit do
193
+ event :g => "z+0.11"
194
+ end
195
+ end
196
+
197
+ class Discrete_7d < DiscreteTestComponent
198
+ state :A
199
+ link :x => Discrete_7c
200
+ setup { self.x = create Discrete_7c }
201
+ transition Enter => A do
202
+ sync :x => :g
203
+ action {@x_g = x.g}
204
+ end
205
+ def assert_consistent test
206
+ test.assert_equal(A, state)
207
+ test.assert_in_delta(0.42, @x_g, 1.0E-10)
208
+ end
209
+ end
210
+
211
+ # a guard testing for event doesn't need a block
212
+
213
+ class Discrete_8a < DiscreteTestComponent
214
+ state :A, :B
215
+ transition Enter => A do
216
+ event :e
217
+ end
218
+ transition A => B do
219
+ event :f => 2.3, :g => literal("x+1") # Not an expr!
220
+ end
221
+ end
222
+
223
+ class Discrete_8b < DiscreteTestComponent
224
+ state :A, :B
225
+ transition Enter => A do
226
+ sync :x => :e
227
+ end
228
+ transition A => B do
229
+ sync [:x, :f] # alt. syntax, in future will allow value
230
+ action {@x_f = x.f; @x_g = x.g}
231
+ end
232
+ link :x => Discrete_8a
233
+ setup { self.x = create Discrete_8a }
234
+ def assert_consistent test
235
+ test.assert_equal(B, state)
236
+ test.assert_equal(2.3, @x_f)
237
+ test.assert_equal("x+1", @x_g)
238
+ end
239
+ end
240
+
241
+ # multiple guard terms are implicitly AND-ed
242
+
243
+ class Discrete_9a < DiscreteTestComponent
244
+ state :A, :B
245
+ transition Enter => A do
246
+ event :e
247
+ end
248
+ transition A => B do
249
+ event :f
250
+ end
251
+ end
252
+
253
+ class Discrete_9b < DiscreteTestComponent
254
+ state :A, :B, :C
255
+ transition Enter => A do
256
+ sync :x => :e
257
+ end
258
+ transition A => B do
259
+ sync [:x, :f]
260
+ sync :x => :e # x.f AND x.e
261
+ # or we could write sync :x => [:f, :e]
262
+ end
263
+ transition A => C do
264
+ sync [:x, :f]
265
+ guard do false end # x.f AND FALSE
266
+ end
267
+ link :x => Discrete_9a
268
+ setup { self.x = create Discrete_9a }
269
+ def assert_consistent test
270
+ test.assert_equal(A, state)
271
+ end
272
+ end
273
+
274
+ # test C expressions as guards
275
+
276
+ class Discrete_10a < DiscreteTestComponent
277
+ state :A, :B
278
+ continuous :v
279
+ transition Enter => A do
280
+ action {self.v = 1}
281
+ end
282
+ transition A => B do
283
+ action {self.v = 2}
284
+ end
285
+ end
286
+
287
+ class Discrete_10b < DiscreteTestComponent
288
+ state :A, :B
289
+ transition Enter => A do
290
+ guard "x.v == 1"
291
+ end
292
+ transition A => B do
293
+ guard "x.v == 3"
294
+ end
295
+ link :x => Discrete_10a
296
+ setup { self.x = create Discrete_10a }
297
+ def assert_consistent test
298
+ test.assert_equal(A, state)
299
+ end
300
+ end
301
+
302
+ # multiple guard terms with C exprs
303
+
304
+ class Discrete_11a < DiscreteTestComponent
305
+ state :A, :B
306
+ continuous :v
307
+ transition Enter => A do
308
+ action {self.v = 1}
309
+ end
310
+ transition A => B do
311
+ action {self.v = 2}
312
+ event :e
313
+ end
314
+ end
315
+
316
+ class Discrete_11b < DiscreteTestComponent
317
+ state :A, :B, :C
318
+ transition Enter => A do
319
+ guard "x.v == 1", "0"
320
+ end
321
+ transition Enter => B do
322
+ guard "x.v == 1"
323
+ sync :x => :f
324
+ end
325
+ transition Enter => C do
326
+ guard "x.v == 1" do false end
327
+ end
328
+ link :x => Discrete_11a
329
+ setup { self.x = create Discrete_11a }
330
+ def assert_consistent test
331
+ test.assert_equal(Enter, state)
332
+ end
333
+ end
334
+
335
+ # testing for an event in link which is nil is false
336
+
337
+ class Discrete_12a < DiscreteTestComponent
338
+ transition do
339
+ event :e
340
+ end
341
+ end
342
+
343
+ class Discrete_12b < DiscreteTestComponent
344
+ link :comp => Discrete_12a
345
+ transition Enter => Exit do
346
+ sync :comp => :e
347
+ end
348
+ def assert_consistent test
349
+ test.assert_equal(Enter, state)
350
+ end
351
+ end
352
+
353
+ # test when the state actually changes during a transition
354
+ # (to wit, after the last clause)
355
+
356
+ class Discrete_13 < DiscreteTestComponent
357
+ state :A1, :A2
358
+ start A1
359
+ flow A1 do alg "var = 1" end
360
+ flow A2 do alg "var = 2" end
361
+ transition A1 => A2 do
362
+ action {@x = var}
363
+ action {@xx = var}
364
+ end
365
+ transition A2 => Exit do
366
+ action {@y = var}
367
+ action {@yy = var}
368
+ end
369
+ def assert_consistent test
370
+ test.assert_equal(1, @x)
371
+ test.assert_equal(1, @xx)
372
+ test.assert_equal(2, @y)
373
+ test.assert_equal(2, @yy)
374
+ end
375
+ end
376
+
377
+ # test that resets and events all happen in parallel
378
+
379
+ class Discrete_14 < DiscreteTestComponent
380
+ state :A1, :A2, :B1, :B2
381
+ continuous :x
382
+ link :other => self
383
+
384
+ default {start A1}
385
+ setup {
386
+ self.x = 1
387
+ self.other ||= create(self.class) { |c|
388
+ start B1
389
+ self.x = 10
390
+ c.other = self
391
+ }
392
+ }
393
+
394
+ transition A1 => A2 do
395
+ reset :x => "other.x"
396
+ event :e => "x"
397
+ end
398
+ transition A2 => Exit do
399
+ reset :x => proc { other.e.to_i }
400
+ end
401
+
402
+ transition B1 => B2 do
403
+ reset :x => "other.x"
404
+ event :e => "x"
405
+ end
406
+ transition B2 => Exit do
407
+ reset :x => proc { other.e.to_i }
408
+ end
409
+
410
+ def assert_consistent test
411
+ case state
412
+ when A1
413
+ test.assert_equal(1, x)
414
+ test.assert_equal(nil, e)
415
+ when A2
416
+ test.assert_equal(10, x)
417
+ test.assert_equal(1, e)
418
+ when B1
419
+ test.assert_equal(10, x)
420
+ test.assert_equal(nil, e)
421
+ when B2
422
+ test.assert_equal(1, x)
423
+ test.assert_equal(10, e)
424
+ end
425
+ end
426
+ end
427
+
428
+ # multiple simultaneous events
429
+
430
+ class Discrete_15a < DiscreteTestComponent
431
+ transition Enter => Exit do
432
+ event {e; f}
433
+ end
434
+ end
435
+
436
+ class Discrete_15b < DiscreteTestComponent
437
+ link :x => Discrete_15a
438
+ setup { self.x = create Discrete_15a }
439
+ transition Enter => Exit do
440
+ sync :x => [:e, :f]
441
+ end
442
+ def assert_consistent test
443
+ test.assert_equal(Exit, state)
444
+ end
445
+ end
446
+
447
+ # priority of transitions is based on program text
448
+
449
+ class Discrete_16 < DiscreteTestComponent
450
+ state :S
451
+ transition(Enter => S) {name "C"; action {@pass=true}}
452
+ transition(Enter => S) {name "B"; action {@pass=false}}
453
+ transition(Enter => S) {name "A"; action {@pass=false}}
454
+ transition(Enter => S) {name "X"; action {@pass=false}}
455
+ transition(Enter => S) {name "Y"; action {@pass=false}}
456
+ transition(Enter => S) {name "Z"; action {@pass=false}}
457
+ def assert_consistent test
458
+ test.flunk("transitions are not in priority order") unless @pass
459
+ end
460
+ end
461
+
462
+ # Multiple transitions in one definition are allowed (but discouraged since
463
+ # they are not checked in order).
464
+ class Discrete_17 < DiscreteTestComponent
465
+ state :A, :B
466
+ transition Enter => A, A => B
467
+ def assert_consistent test
468
+ test.assert_equal(B, state)
469
+ end
470
+ end
471
+
472
+ # Multiple transitions can be defined using arrays of source states.
473
+ class Discrete_18 < DiscreteTestComponent
474
+ state :A, :B
475
+ transition [A, Enter] => B
476
+ def assert_consistent test
477
+ test.assert_equal(B, state)
478
+ end
479
+ end
480
+
481
+ # Check that post actions work.
482
+ class Discrete_19 < DiscreteTestComponent
483
+ state :A
484
+ constant :x
485
+ transition Enter => A do
486
+ reset :x => 1
487
+ post {@x = x}
488
+ end
489
+ def assert_consistent test
490
+ test.assert_equal(1, @x)
491
+ end
492
+ end
493
+
494
+ # Check that false guards are never taken, but nil (empty) guards always are.
495
+ class Discrete_20 < DiscreteTestComponent
496
+ transition Enter => Exit do
497
+ guard false
498
+ action { @fail = true }
499
+ end
500
+ transition Enter => Exit do
501
+ guard nil
502
+ end
503
+ def assert_consistent test
504
+ test.assert_equal(Exit, state)
505
+ test.assert_equal(nil, @fail)
506
+ end
507
+ end
508
+
509
+ # guard expr accepts "lnk.lnk"
510
+ class Discrete_21 < DiscreteTestComponent
511
+ link :lnk => self, :old_lnk => self
512
+
513
+ total = 2
514
+ setup do
515
+ self.name = total
516
+ if total > 0
517
+ total -= 1
518
+ self.lnk = create(self.class)
519
+ end
520
+ end
521
+
522
+ transition Enter => Exit do
523
+ guard "lnk && lnk.lnk"
524
+ reset :lnk => "lnk.lnk", :old_lnk => "lnk"
525
+ end
526
+
527
+ def assert_consistent test
528
+ if name == 2
529
+ test.assert_equal(Exit, state)
530
+ test.assert_equal(old_lnk.lnk, lnk)
531
+ else
532
+ test.assert_equal(Enter, state)
533
+ end
534
+ end
535
+ end
536
+
537
+ # alg flow evaluated after state change remembers its value,
538
+ # even if never explicitly evaluated before.
539
+ class Discrete_22 < DiscreteTestComponent
540
+ state :S
541
+ flow Enter do
542
+ alg " x = 123 "
543
+ end
544
+ transition Enter => S
545
+
546
+ def assert_consistent test
547
+ if state == S
548
+ test.assert_equal(123, x)
549
+ end
550
+ end
551
+ end
552
+
553
+ =begin
554
+
555
+ test timing of other combinations of
556
+ action, guard, event, reset
557
+
558
+ test guard phases
559
+
560
+ =end
561
+
562
+ #-----#
563
+
564
+ require 'test/unit'
565
+
566
+ class TestDiscrete < Test::Unit::TestCase
567
+
568
+ def setup
569
+ @world = World.new
570
+ @world.time_step = 0.1
571
+ end
572
+
573
+ def teardown
574
+ @world = nil
575
+ end
576
+
577
+ def test_discrete
578
+ testers = []
579
+ ObjectSpace.each_object(Class) do |cl|
580
+ if cl <= DiscreteTestComponent and
581
+ cl.instance_methods.include? "assert_consistent"
582
+ testers << @world.create(cl)
583
+ end
584
+ end
585
+
586
+ @world.run
587
+
588
+ for t in testers
589
+ t.assert_consistent self
590
+ end
591
+ end
592
+ end