redshift 1.3.15

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 (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