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,119 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'redshift'
4
+
5
+ include RedShift
6
+
7
+ class SetupTestComponent < Component
8
+ attr_accessor :x
9
+ end
10
+
11
+ # setup and defaults should both be able to set @state
12
+
13
+ class Setup_1a < SetupTestComponent
14
+ state :A
15
+ start A # same as default { start A }
16
+ def assert_consistent test
17
+ test.assert_equal(A, state)
18
+ end
19
+ end
20
+
21
+ class Setup_1b < SetupTestComponent
22
+ state :A
23
+ setup { start A }
24
+ def assert_consistent test
25
+ test.assert_equal(A, state)
26
+ end
27
+ end
28
+
29
+ # defaults happen before setup
30
+
31
+ class Setup_2 < SetupTestComponent
32
+ state :A, :B
33
+ default { start A }
34
+ setup { start B }
35
+ def assert_consistent test
36
+ test.assert_equal(B, state)
37
+ end
38
+ end
39
+
40
+ # create block happens after defaults, before setup
41
+
42
+ class Setup_3a < SetupTestComponent
43
+ defaults { self.x = 0 }
44
+ def assert_consistent test
45
+ test.assert_equal(1, x)
46
+ end
47
+ end
48
+
49
+ class Setup_3b < SetupTestComponent
50
+ setup { self.x = 2 }
51
+ def assert_consistent test
52
+ test.assert_equal(2, x)
53
+ end
54
+ end
55
+
56
+ # multiple setup and defaults blocks chain after each other
57
+
58
+ class Setup_4a < SetupTestComponent
59
+ attr_accessor :y, :z
60
+ defaults { self.y = 3 }
61
+ defaults { self.z = 4 }
62
+ def assert_consistent test
63
+ test.assert_equal([3,4], [y,z])
64
+ end
65
+ end
66
+
67
+ class Setup_4b < SetupTestComponent
68
+ attr_accessor :y, :z
69
+ setup { self.y = 3 }
70
+ setup { self.z = 4 }
71
+ def assert_consistent test
72
+ test.assert_equal([3,4], [y,z])
73
+ end
74
+ end
75
+
76
+ # defaults and setup can take a hash of var=>value, and constant and continuous
77
+ # can take var => value as well
78
+
79
+ class Setup_5 < SetupTestComponent
80
+ constant :k => 111, :k2 => 3
81
+ continuous :x => 222, :x2 => 4
82
+ setup :k => 1, :x => 2
83
+ def assert_consistent test
84
+ test.assert_equal(1, k)
85
+ test.assert_equal(2, x)
86
+ test.assert_equal(3, k2)
87
+ test.assert_equal(4, x2)
88
+ end
89
+ end
90
+
91
+ #-----#
92
+
93
+ require 'test/unit'
94
+
95
+ class TestSetup < Test::Unit::TestCase
96
+
97
+ def setup
98
+ @world = World.new
99
+ @world.time_step = 0.1
100
+ end
101
+
102
+ def teardown
103
+ @world = nil
104
+ end
105
+
106
+ def test_setup
107
+ testers = []
108
+ ObjectSpace.each_object(Class) do |cl|
109
+ if cl <= SetupTestComponent and
110
+ cl.instance_methods.include? "assert_consistent"
111
+ testers << @world.create(cl) { |tester| tester.x = 1 }
112
+ end
113
+ end
114
+
115
+ for t in testers
116
+ t.assert_consistent self
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,410 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'redshift'
4
+
5
+ include RedShift
6
+
7
+ # Tests strictly continuous and strictly constant variables. Tests strict
8
+ # link variables.
9
+ #
10
+ # - tests that guard optimization works: guards are eval-ed once per step
11
+ #
12
+ # - tests exceptions raised by assigning to strict vars
13
+ #
14
+ # - tests exception raised by a transition to a state that algebraically
15
+ # defines a variable in an inconsistent way
16
+ #
17
+ # [Note: exceptions caused by algebraically defining a strict var
18
+ # in terms of a non-strict var are caught at compile time. See
19
+ # test_strictness_error.rb. Similarly, a reset on a strict var can
20
+ # be caught at compile time. See test_strict_reset_error.rb.]
21
+
22
+ class SCWorld < World
23
+ def num_checks
24
+ @num_checks ||= Hash.new do |h,comp|
25
+ h[comp] = Hash.new do |h1,trans|
26
+ h1[trans] = 0
27
+ end
28
+ end
29
+ end
30
+
31
+ def hook_eval_guard(comp, guard, enabled, trans, dest)
32
+ num_checks[comp][trans.name] += 1
33
+ end
34
+ end
35
+
36
+ class TestComponent < Component
37
+ def finish(test); end
38
+ end
39
+
40
+ class C < Component
41
+ strictly_constant :y
42
+ default do
43
+ self.y = 1
44
+ end
45
+ end
46
+
47
+ class A < TestComponent
48
+ strictly_continuous :x
49
+ strict_link :c => C
50
+
51
+ flow do
52
+ diff "x' = c.y"
53
+ end
54
+
55
+ setup do
56
+ self.c = create C
57
+ end
58
+
59
+ transition Enter => Exit do
60
+ name "t1"
61
+ guard " x > 0.50 "
62
+ end
63
+
64
+ transition Enter => Exit do
65
+ name "t2"
66
+ guard " x > 0.73 "
67
+ end
68
+
69
+ def assert_consistent(test)
70
+ case state
71
+ when Enter
72
+ # Should not check the guard more than once per step, or so.
73
+ num_checks = world.num_checks[self]
74
+ t1_count = num_checks["t1"]
75
+ t2_count = num_checks["t2"]
76
+
77
+ step_count = world.step_count
78
+
79
+ test.assert(t1_count <= step_count+2)
80
+ test.assert(t2_count <= step_count+2)
81
+ # This accounts for the fact that step_discrete is called an "extra"
82
+ # time at the start of one call to World#step or #evolve, plus an
83
+ # extra time by "run(0)" below.
84
+
85
+ when Exit
86
+ ## we really only need to do these tests once...
87
+ old_x = x
88
+ old_c = c
89
+ old_c_y = c.y
90
+
91
+ test.assert_raises(RedShift::StrictnessError) do
92
+ self.x = x
93
+ end
94
+
95
+ test.assert_raises(RedShift::StrictnessError) do
96
+ self.c = c
97
+ end
98
+
99
+ test.assert_raises(RedShift::StrictnessError) do
100
+ c.y = c.y
101
+ end
102
+
103
+ # strictness has a backdoor...
104
+ begin
105
+ self.x = 123
106
+ rescue RedShift::StrictnessError
107
+ end
108
+ test.assert_equal(123, x)
109
+
110
+ begin
111
+ self.c = nil
112
+ rescue RedShift::StrictnessError
113
+ end
114
+ test.assert_equal(nil, c)
115
+
116
+ (self.x = old_x) rescue nil
117
+ (self.c = old_c) rescue nil
118
+ (c.y = old_c_y) rescue nil
119
+ end
120
+ end
121
+ end
122
+
123
+ # This component exists to give the A instance a chance to make too many
124
+ # guard checks.
125
+ class B < TestComponent
126
+ state :S, :T, :U
127
+ setup do
128
+ start S
129
+ end
130
+
131
+ flow S do
132
+ diff "time' = 1"
133
+ end
134
+
135
+ transition S => T do
136
+ guard "time > 0"
137
+ reset :time => 0 # so we do it again next timestep
138
+ end
139
+
140
+ transition T => U
141
+
142
+ transition U => S do
143
+ action do
144
+ @awake = world.size - world.strict_sleep.size - world.inert.size
145
+ end
146
+ end
147
+
148
+ def assert_consistent(test)
149
+ if @awake
150
+ test.assert_equal(1, @awake) # just the B
151
+ end
152
+ end
153
+ end
154
+
155
+ class D1 < Component
156
+ strictly_continuous :x
157
+ setup do
158
+ self.x = 1
159
+ end
160
+
161
+ state :Inconsistent
162
+
163
+ flow Inconsistent do
164
+ algebraic " x = 2 "
165
+ end
166
+
167
+ transition Enter => Inconsistent do
168
+ guard "x > 0"
169
+ end
170
+ end
171
+
172
+ class D2 < Component
173
+ strictly_continuous :x
174
+ setup do
175
+ self.x = 1
176
+ end
177
+
178
+ state :Inconsistent
179
+
180
+ flow Inconsistent do
181
+ algebraic " x = 2 "
182
+ end
183
+
184
+ transition Enter => Inconsistent do
185
+ guard {x > 0}
186
+ end
187
+ end
188
+
189
+ # test that lazily evaluated alg exprs get evaled correctly on demand
190
+ class Lazy < TestComponent
191
+ strictly_continuous :x, :y
192
+ # z is not strict, so that the second test below is meaningful
193
+ state :Test1, :Test2, :Test3
194
+
195
+ flow Test1, Test2 do
196
+ diff " x' = 1 "
197
+ alg " y = 2*x "
198
+ alg " z = y "
199
+ end
200
+
201
+ transition Test1 => Test2 do
202
+ guard "x >= 0.5"
203
+ action {@x = x; @test = y}
204
+ end
205
+
206
+ transition Test2 => Test3 do
207
+ guard "x >= 0.7"
208
+ action {@x = x; @test = z}
209
+ # indirect eval of y from z's alg expr is different from
210
+ # using the y reader method.
211
+ end
212
+
213
+ def assert_consistent(test)
214
+ case state
215
+ when Test1, Test2
216
+ test.assert_in_delta(2 * @x, @test, 1.0E-10)
217
+ end
218
+ end
219
+ end
220
+
221
+ # test that a reset of a non-strict link doesn't get around the optimization
222
+ class NonStrictLink < TestComponent
223
+ link :c => C
224
+ state :Fail, :Pass, :Relink
225
+ setup do
226
+ self.c = create(C) {|c| c.y = -1}
227
+ end
228
+ transition Enter => Fail do
229
+ guard "c.y >= 0"
230
+ end
231
+ transition Enter => Relink do
232
+ guard "c.y < 0"
233
+ reset :c => proc {create(C) {|c| c.y = 1}} # try to fool the optimization!
234
+ end
235
+ transition Relink => Fail do
236
+ guard "c.y <= 0"
237
+ end
238
+ transition Relink => Pass do
239
+ guard "c.y > 0"
240
+ end
241
+ def assert_consistent(test)
242
+ test.flunk if state == Fail
243
+ end
244
+ end
245
+
246
+ # test that a strict link to a nonstrict var is not optimized
247
+ class StrictLinkToNonStrictVar < TestComponent
248
+ class NS < Component
249
+ constant :k
250
+ continuous :x
251
+ end
252
+
253
+ flow { diff "t'=1" }
254
+
255
+ strict_link :ns => NS
256
+
257
+ default {self.ns = create(NS)}
258
+
259
+ state :Pass
260
+
261
+ transition do
262
+ guard "ns.k == 0 && ns.x == 0"
263
+ action { ns.k = ns.x = 1 }
264
+ end
265
+
266
+ transition do
267
+ guard "ns.k == 1 && ns.x == 1"
268
+ action { ns.k = 0 }
269
+ end
270
+
271
+ transition Enter => Pass do
272
+ guard "ns.k == 0 && ns.x == 1"
273
+ end
274
+
275
+ def assert_consistent(test)
276
+ test.flunk if t > 0 and not state == Pass
277
+ end
278
+ end
279
+
280
+ # test that, if evaluation of a strict guard is deferred due to a transition
281
+ # then it is still evaluated.
282
+ class StrictGuardsEvaled < TestComponent
283
+ strictly_constant :k
284
+ constant :l
285
+ transition do
286
+ guard "l==0"
287
+ reset :l => 1
288
+ end
289
+ transition Enter => Exit do
290
+ guard "k<1"
291
+ end
292
+ def assert_consistent(test)
293
+ if l > 0
294
+ test.assert_equal(Exit, state)
295
+ end
296
+ end
297
+ end
298
+
299
+ # test that, if evaluation of a strict guard is deferred due to a transition
300
+ # then it is still evaluated.
301
+ class StrictGuardsEvaled2 < TestComponent
302
+ strictly_constant :k
303
+ transition do
304
+ guard "k<1"
305
+ end
306
+ end
307
+
308
+ # Test that there is no memory of which strict guards have been "checked"
309
+ # after moving to a new state.
310
+ class StrictGuardsEvaled3 < TestComponent
311
+ state :S1, :S2
312
+ link :checker => :Checker
313
+ constant :i => 0
314
+ transition Enter => S1 do
315
+ reset :checker => proc {create(Checker) {|c| c.emitter = self}}
316
+ end
317
+ transition S1 => S2 do
318
+ guard "i > 5"
319
+ event :e
320
+ end
321
+ transition S1 => S1 do # give other comp time to check guards
322
+ reset :i => "i+1"
323
+ end
324
+
325
+ class Checker < Component
326
+ strictly_constant :x => 0, :y => 1
327
+ state :S1
328
+ link :emitter => StrictGuardsEvaled3
329
+ transition Enter => Exit do
330
+ guard "x > 0"
331
+ post {raise}
332
+ end
333
+ transition Enter => S1 do
334
+ sync :emitter => :e
335
+ end
336
+ transition S1 => Exit do
337
+ guard "y > 0"
338
+ end
339
+ end
340
+
341
+ def assert_consistent(test)
342
+ if self.state == S2
343
+ test.assert_equal(Exit, checker.state)
344
+ end
345
+ end
346
+ end
347
+
348
+ #-----#
349
+
350
+ require 'test/unit'
351
+
352
+ class TestStrictContinuity < Test::Unit::TestCase
353
+
354
+ def setup
355
+ @world = SCWorld.new
356
+ @world.time_step = 0.1
357
+ end
358
+
359
+ def teardown
360
+ @world = nil
361
+ end
362
+
363
+ def test_strict_continuity
364
+ testers = []
365
+ ObjectSpace.each_object(Class) do |cl|
366
+ if cl <= TestComponent and
367
+ cl.instance_methods.include? "assert_consistent"
368
+ testers << @world.create(cl)
369
+ end
370
+ end
371
+
372
+ testers.each { |t| t.assert_consistent self }
373
+ @world.run 0
374
+ # now we can check what happened after one discrete step, which
375
+ # is needed for StrictGuardsEvaled3.
376
+ testers.each { |t| t.assert_consistent self }
377
+ @world.run 10 do
378
+ testers.each { |t| t.assert_consistent self }
379
+ end
380
+ testers.each { |t| t.finish self }
381
+
382
+ a = testers.find {|t| t.class == A}
383
+ assert(a)
384
+ assert_equal(TestComponent::Exit, a.state)
385
+
386
+ b = testers.find {|t| t.class == B}
387
+ assert(b)
388
+ end
389
+
390
+ def test_algebraic_inconsistency1
391
+ d = @world.create(D1)
392
+ assert_raises(RedShift::StrictnessError) do
393
+ @world.run 10
394
+ end
395
+ end
396
+
397
+ def test_algebraic_inconsistency2
398
+ d = @world.create(D2)
399
+ assert_raises(RedShift::StrictnessError) do
400
+ @world.run 10
401
+ end
402
+ end
403
+
404
+ def test_StrictGuardsEvaled
405
+ c = @world.create(StrictGuardsEvaled2)
406
+ assert_raises(RedShift::ZenoError) do
407
+ @world.run 10
408
+ end
409
+ end
410
+ end