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.
- data/.gitignore +8 -0
- data/README +5 -0
- data/RELEASE-NOTES +455 -0
- data/TODO +431 -0
- data/bench/alg-state.rb +61 -0
- data/bench/bench +26 -0
- data/bench/bench.rb +10 -0
- data/bench/continuous.rb +76 -0
- data/bench/diff-bench +86 -0
- data/bench/discrete.rb +101 -0
- data/bench/euler.rb +50 -0
- data/bench/formula.rb +78 -0
- data/bench/half-strict.rb +103 -0
- data/bench/inertness.rb +116 -0
- data/bench/queue.rb +92 -0
- data/bench/run +66 -0
- data/bench/simple.rb +74 -0
- data/bench/strictness.rb +86 -0
- data/examples/ball-tkar.rb +72 -0
- data/examples/ball.rb +123 -0
- data/examples/collide.rb +70 -0
- data/examples/connect-parallel.rb +48 -0
- data/examples/connect.rb +109 -0
- data/examples/constants.rb +27 -0
- data/examples/delay.rb +80 -0
- data/examples/derivative.rb +77 -0
- data/examples/euler.rb +46 -0
- data/examples/external-lib.rb +33 -0
- data/examples/guard-debugger.rb +77 -0
- data/examples/lotka-volterra.rb +33 -0
- data/examples/persist-ball.rb +68 -0
- data/examples/pid.rb +87 -0
- data/examples/ports.rb +60 -0
- data/examples/queue.rb +56 -0
- data/examples/queue2.rb +98 -0
- data/examples/reset-with-event-val.rb +28 -0
- data/examples/scheduler.rb +104 -0
- data/examples/set-dest.rb +23 -0
- data/examples/simulink/README +1 -0
- data/examples/simulink/delay.mdl +827 -0
- data/examples/simulink/derivative.mdl +655 -0
- data/examples/step-discrete-profiler.rb +103 -0
- data/examples/subsystem.rb +109 -0
- data/examples/sync-deadlock.rb +32 -0
- data/examples/sync-queue.rb +91 -0
- data/examples/sync-retry.rb +20 -0
- data/examples/sync.rb +51 -0
- data/examples/thermostat.rb +53 -0
- data/examples/zeno.rb +53 -0
- data/lib/accessible-index.rb +47 -0
- data/lib/redshift.rb +1 -0
- data/lib/redshift/component.rb +412 -0
- data/lib/redshift/meta.rb +183 -0
- data/lib/redshift/mixins/zeno-debugger.rb +69 -0
- data/lib/redshift/port.rb +57 -0
- data/lib/redshift/queue.rb +104 -0
- data/lib/redshift/redshift.rb +111 -0
- data/lib/redshift/state.rb +31 -0
- data/lib/redshift/syntax.rb +558 -0
- data/lib/redshift/target/c.rb +37 -0
- data/lib/redshift/target/c/component-gen.rb +1303 -0
- data/lib/redshift/target/c/flow-gen.rb +325 -0
- data/lib/redshift/target/c/flow/algebraic.rb +85 -0
- data/lib/redshift/target/c/flow/buffer.rb +74 -0
- data/lib/redshift/target/c/flow/delay.rb +203 -0
- data/lib/redshift/target/c/flow/derivative.rb +101 -0
- data/lib/redshift/target/c/flow/euler.rb +67 -0
- data/lib/redshift/target/c/flow/expr.rb +113 -0
- data/lib/redshift/target/c/flow/rk4.rb +80 -0
- data/lib/redshift/target/c/library.rb +85 -0
- data/lib/redshift/target/c/world-gen.rb +1370 -0
- data/lib/redshift/target/spec.rb +34 -0
- data/lib/redshift/world.rb +300 -0
- data/rakefile +37 -0
- data/test/test.rb +52 -0
- data/test/test_buffer.rb +58 -0
- data/test/test_connect.rb +242 -0
- data/test/test_connect_parallel.rb +47 -0
- data/test/test_connect_strict.rb +135 -0
- data/test/test_constant.rb +74 -0
- data/test/test_delay.rb +145 -0
- data/test/test_derivative.rb +48 -0
- data/test/test_discrete.rb +592 -0
- data/test/test_discrete_isolated.rb +92 -0
- data/test/test_exit.rb +59 -0
- data/test/test_flow.rb +200 -0
- data/test/test_flow_link.rb +288 -0
- data/test/test_flow_sub.rb +100 -0
- data/test/test_flow_trans.rb +292 -0
- data/test/test_inherit.rb +127 -0
- data/test/test_inherit_event.rb +74 -0
- data/test/test_inherit_flow.rb +139 -0
- data/test/test_inherit_link.rb +65 -0
- data/test/test_inherit_setup.rb +56 -0
- data/test/test_inherit_state.rb +66 -0
- data/test/test_inherit_transition.rb +168 -0
- data/test/test_numerics.rb +34 -0
- data/test/test_queue.rb +90 -0
- data/test/test_queue_alone.rb +115 -0
- data/test/test_reset.rb +209 -0
- data/test/test_setup.rb +119 -0
- data/test/test_strict_continuity.rb +410 -0
- data/test/test_strict_reset_error.rb +30 -0
- data/test/test_strictness_error.rb +32 -0
- data/test/test_sync.rb +185 -0
- data/test/test_world.rb +328 -0
- metadata +204 -0
@@ -0,0 +1,100 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'redshift'
|
4
|
+
|
5
|
+
include RedShift
|
6
|
+
|
7
|
+
# Substitutability of algebraic flows (i.e. flows have function semantics)
|
8
|
+
# Dependencies of diff/euler/alg on alg, and alg on diff.
|
9
|
+
|
10
|
+
class FlowTestComponent < Component
|
11
|
+
def finish test
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Flow_Sub < FlowTestComponent
|
16
|
+
s1 = "2*sin(u) + 1"
|
17
|
+
s2 = "pow(u, 2) + 3 * u"
|
18
|
+
|
19
|
+
f1 = proc { |v| s1.gsub(/u/,"(" + v + ")") }
|
20
|
+
f2 = proc { |v| s2.gsub(/u/,"(" + v + ")") }
|
21
|
+
|
22
|
+
flow {
|
23
|
+
diff "t' = 1"
|
24
|
+
|
25
|
+
alg "x = #{f1['t']}"
|
26
|
+
alg "xx = #{f2['x']}"
|
27
|
+
|
28
|
+
diff "y0' = #{f2[f1['t']]}"
|
29
|
+
diff "y1' = #{f2['x']}"
|
30
|
+
diff "y2' = xx"
|
31
|
+
|
32
|
+
euler "z0' = #{f2[f1['t']]}"
|
33
|
+
euler "z1' = #{f2['x']}"
|
34
|
+
euler "z2' = xx"
|
35
|
+
}
|
36
|
+
setup {
|
37
|
+
self.t = 0
|
38
|
+
self.y0 = self.y1 = self.y2 = self.z0 = self.z1 = self.z2 = 0
|
39
|
+
}
|
40
|
+
def assert_consistent test
|
41
|
+
str = "at time #{t}"
|
42
|
+
test.assert_in_delta(x, 2*sin(t) + 1, 0.000000001, str)
|
43
|
+
test.assert_in_delta(xx, (2*sin(t) + 1)**2 + 3 * (2*sin(t) + 1),
|
44
|
+
0.000000001, str)
|
45
|
+
|
46
|
+
test.assert_in_delta(y0, y1, 0.000000001, str)
|
47
|
+
test.assert_in_delta(y0, y2, 0.000000001, str)
|
48
|
+
|
49
|
+
test.assert_in_delta(z0, z1, 0.000000001, str)
|
50
|
+
test.assert_in_delta(z0, z2, 0.000000001, str)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
#-----#
|
56
|
+
|
57
|
+
require 'test/unit'
|
58
|
+
|
59
|
+
class TestFlow < Test::Unit::TestCase
|
60
|
+
|
61
|
+
def setup
|
62
|
+
@world = World.new
|
63
|
+
@world.time_step = 0.01
|
64
|
+
@world.zeno_limit = 100
|
65
|
+
end
|
66
|
+
|
67
|
+
def teardown
|
68
|
+
@world = nil
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_flow
|
72
|
+
testers = []
|
73
|
+
ObjectSpace.each_object(Class) do |cl|
|
74
|
+
if cl <= FlowTestComponent and
|
75
|
+
cl.instance_methods.include? "assert_consistent"
|
76
|
+
testers << @world.create(cl)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
testers.each { |t| t.assert_consistent self }
|
81
|
+
@world.run 1000 do
|
82
|
+
testers.each { |t| t.assert_consistent self }
|
83
|
+
end
|
84
|
+
testers.each { |t| t.finish self }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
END {
|
89
|
+
|
90
|
+
# require 'plot/plot'
|
91
|
+
# Plot.new ('gnuplot') {
|
92
|
+
# add Flow_Reconfig::Y, 'title "y" with lines'
|
93
|
+
# add Flow_Reconfig::Y1, 'title "y1" with lines'
|
94
|
+
# add Flow_Reconfig::Y2, 'title "y2" with lines'
|
95
|
+
# add Flow_Reconfig::Y3, 'title "y3" with lines'
|
96
|
+
# show
|
97
|
+
# pause 5
|
98
|
+
# }
|
99
|
+
|
100
|
+
}
|
@@ -0,0 +1,292 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'redshift'
|
4
|
+
require 'sci/random'
|
5
|
+
require 'isaac'
|
6
|
+
|
7
|
+
# Adaptor class to use ISAAC with sci/random distributions.
|
8
|
+
class ISAACGenerator < ISAAC
|
9
|
+
def initialize(*seeds)
|
10
|
+
super()
|
11
|
+
if seeds.compact.empty?
|
12
|
+
seeds = [Random::Sequence.random_seed]
|
13
|
+
end
|
14
|
+
@seeds = seeds
|
15
|
+
srand(seeds)
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :seeds
|
19
|
+
|
20
|
+
alias next rand
|
21
|
+
end
|
22
|
+
|
23
|
+
include RedShift
|
24
|
+
|
25
|
+
class FlowTestComponent < Component
|
26
|
+
def finish test
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Shows that despite lazy eval of alg flows, they do get evaled before
|
31
|
+
# changing states.
|
32
|
+
|
33
|
+
class Flow_Transition_Alg_To_Other < FlowTestComponent
|
34
|
+
state :A, :B
|
35
|
+
start A
|
36
|
+
flow A do
|
37
|
+
alg "x=42"
|
38
|
+
end
|
39
|
+
transition A => B
|
40
|
+
|
41
|
+
def assert_consistent test
|
42
|
+
if state == B
|
43
|
+
test.assert_equal(42, x)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# state changes which change the type of flow
|
49
|
+
|
50
|
+
class Flow_Transition < FlowTestComponent
|
51
|
+
state :Alg, :Diff, :Euler, :Empty, :Switch
|
52
|
+
|
53
|
+
flow Alg, Diff, Euler, Empty do
|
54
|
+
diff "t' = 1"
|
55
|
+
end
|
56
|
+
|
57
|
+
flow Alg do
|
58
|
+
alg "x = 10*t"
|
59
|
+
end
|
60
|
+
|
61
|
+
flow Diff do
|
62
|
+
diff "x' = 10"
|
63
|
+
end
|
64
|
+
|
65
|
+
flow Euler do
|
66
|
+
euler "x' = 10"
|
67
|
+
end
|
68
|
+
|
69
|
+
setup do
|
70
|
+
self.x = 0
|
71
|
+
@alarm_time = 0
|
72
|
+
@alarm_seq = Random::Exponential.new \
|
73
|
+
:generator => ISAACGenerator,
|
74
|
+
:seed => nil, # 614822716,
|
75
|
+
:mean => 0.5
|
76
|
+
@state_seq = Random::Discrete.new \
|
77
|
+
:generator => ISAACGenerator,
|
78
|
+
:seed => nil, # 3871653669,
|
79
|
+
:distrib =>
|
80
|
+
{
|
81
|
+
Alg => 100,
|
82
|
+
Diff => 100,
|
83
|
+
Euler => 100,
|
84
|
+
Empty => 100
|
85
|
+
}
|
86
|
+
puts "\n\n Flow_Transition used the following seeds:"
|
87
|
+
puts " alarm seed = #{@alarm_seq.generator.seeds}"
|
88
|
+
puts " state seed = #{@state_seq.generator.seeds}"
|
89
|
+
end
|
90
|
+
|
91
|
+
transition Enter => Switch,
|
92
|
+
Alg => Switch, Diff => Switch,
|
93
|
+
Euler => Switch, Empty => Switch do
|
94
|
+
guard { t >= @alarm_time }
|
95
|
+
action {
|
96
|
+
# puts "Switching to #{@state_seq.next} at #{@alarm_time} sec."
|
97
|
+
# puts "x = #{x}, t = #{t}."
|
98
|
+
@alarm_time += @alarm_seq.next
|
99
|
+
@current = @state_seq.next
|
100
|
+
# puts " Next switch at #{@alarm_time} sec.\n\n"
|
101
|
+
## unless we eval x here, the alg flow for x might not be up to date.
|
102
|
+
if (state == Empty)
|
103
|
+
@last_empty_t = t
|
104
|
+
self.x = 10 * t # manually update x
|
105
|
+
end
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
109
|
+
transition Switch => Alg do
|
110
|
+
guard { @current == Alg }
|
111
|
+
end
|
112
|
+
transition Switch => Diff do
|
113
|
+
guard { @current == Diff }
|
114
|
+
end
|
115
|
+
transition Switch => Euler do
|
116
|
+
guard { @current == Euler }
|
117
|
+
end
|
118
|
+
transition Switch => Empty do
|
119
|
+
guard { @current == Empty }
|
120
|
+
end
|
121
|
+
|
122
|
+
transition Empty => Empty do
|
123
|
+
guard { t > (@last_empty_t || 0) }
|
124
|
+
action {
|
125
|
+
@last_empty_t = t
|
126
|
+
self.x = 10 * t # manually update x
|
127
|
+
}
|
128
|
+
end
|
129
|
+
|
130
|
+
def assert_consistent test
|
131
|
+
# In the alg case, calling the accessor invokes the update method. We want
|
132
|
+
# to test that alg flows work even if the update method isn't called.
|
133
|
+
unless state == Alg
|
134
|
+
test.assert_in_delta(
|
135
|
+
10 * t,
|
136
|
+
x,
|
137
|
+
0.00000000001,
|
138
|
+
"in #{state.name} after #{t} sec,\n")
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def finish test
|
143
|
+
# puts "At finish: t = #{t}, alarm_time = #{@alarm_time}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
# After changing out of a state with an alg flow, the variable should
|
149
|
+
# have a value defined by that flow, even if the flow was never
|
150
|
+
# explicitly referenced. Check that the strict optimization doesn't
|
151
|
+
# interfere with this evaluation.
|
152
|
+
class Flow_LeavingAlgebraic < FlowTestComponent
|
153
|
+
continuous :x
|
154
|
+
strictly_continuous :y
|
155
|
+
state :S, :T
|
156
|
+
flow S do
|
157
|
+
alg " x = 42 "
|
158
|
+
alg " y = 43 "
|
159
|
+
end
|
160
|
+
transition Enter => S, S => T
|
161
|
+
def assert_consistent test
|
162
|
+
if state == T
|
163
|
+
test.assert_equal(42, x)
|
164
|
+
test.assert_equal(43, y)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
# Test what happens when a transition changes the algebraic flow of a variable
|
171
|
+
|
172
|
+
class Flow_AlgToAlg < FlowTestComponent
|
173
|
+
state :A, :B
|
174
|
+
flow A, B do diff "t' = 1" end
|
175
|
+
flow A do alg "x = 1" end
|
176
|
+
flow B do alg "x = 2" end
|
177
|
+
start A
|
178
|
+
transition A => B do
|
179
|
+
guard "t > 0.2"
|
180
|
+
action do
|
181
|
+
@snapshotA = x
|
182
|
+
end
|
183
|
+
end
|
184
|
+
transition B => B do
|
185
|
+
guard {!@snapshotB}
|
186
|
+
action do
|
187
|
+
@snapshotB = x
|
188
|
+
end
|
189
|
+
end
|
190
|
+
def assert_consistent test
|
191
|
+
return if t > 0.4 ## should be a way to remove this component
|
192
|
+
case state
|
193
|
+
when A; test.assert_equal(1, x)
|
194
|
+
when B; test.assert_equal(2, x)
|
195
|
+
test.assert_equal(1, @snapshotA)
|
196
|
+
test.assert_equal(2, @snapshotB)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
# Test what happens during an action when an algebraic flow's inputs change.
|
202
|
+
# The alg flow's value *does* change during the action, if there are changes
|
203
|
+
# in any of the links, continuous vars, or constants that it depends on.
|
204
|
+
|
205
|
+
class Flow_AlgebraicAction < FlowTestComponent
|
206
|
+
continuous :x, :y
|
207
|
+
constant :k
|
208
|
+
link :other => self
|
209
|
+
flow {alg " x = other.y + k "}
|
210
|
+
|
211
|
+
@@first = true
|
212
|
+
|
213
|
+
setup do
|
214
|
+
self.other = self
|
215
|
+
if @@first
|
216
|
+
@@first = false
|
217
|
+
@other = create(Flow_AlgebraicAction) {|c| c.y = 5}
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
transition Enter => Exit do
|
222
|
+
action do
|
223
|
+
next unless @other
|
224
|
+
|
225
|
+
@x_values = []
|
226
|
+
@x_values << x
|
227
|
+
other.y = 1
|
228
|
+
@x_values << x
|
229
|
+
other.y = 2
|
230
|
+
@x_values << x
|
231
|
+
|
232
|
+
self.other = @other
|
233
|
+
@x_values << x
|
234
|
+
|
235
|
+
self.k = 10
|
236
|
+
@x_values << x
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def assert_consistent test
|
241
|
+
test.assert_equal([0,1,2,5,15], @x_values) if @x_values
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
|
246
|
+
#-----#
|
247
|
+
|
248
|
+
require 'test/unit'
|
249
|
+
|
250
|
+
class TestFlow < Test::Unit::TestCase
|
251
|
+
|
252
|
+
def setup
|
253
|
+
@world = World.new
|
254
|
+
@world.time_step = 0.01
|
255
|
+
@world.zeno_limit = 100
|
256
|
+
end
|
257
|
+
|
258
|
+
def teardown
|
259
|
+
@world = nil
|
260
|
+
end
|
261
|
+
|
262
|
+
def test_flow
|
263
|
+
testers = []
|
264
|
+
ObjectSpace.each_object(Class) do |cl|
|
265
|
+
if cl <= FlowTestComponent and
|
266
|
+
cl.instance_methods.include? "assert_consistent"
|
267
|
+
testers << @world.create(cl)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
testers.each { |t| t.assert_consistent self }
|
272
|
+
@world.run 1000 do
|
273
|
+
testers.each { |t| t.assert_consistent self }
|
274
|
+
# testers.reject! { |t| t.state == Exit }
|
275
|
+
end
|
276
|
+
testers.each { |t| t.finish self }
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
END {
|
281
|
+
|
282
|
+
# require 'plot/plot'
|
283
|
+
# Plot.new ('gnuplot') {
|
284
|
+
# add Flow_Reconfig::Y, 'title "y" with lines'
|
285
|
+
# add Flow_Reconfig::Y1, 'title "y1" with lines'
|
286
|
+
# add Flow_Reconfig::Y2, 'title "y2" with lines'
|
287
|
+
# add Flow_Reconfig::Y3, 'title "y3" with lines'
|
288
|
+
# show
|
289
|
+
# pause 5
|
290
|
+
# }
|
291
|
+
|
292
|
+
}
|
@@ -0,0 +1,127 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'redshift'
|
4
|
+
|
5
|
+
include RedShift
|
6
|
+
|
7
|
+
=begin
|
8
|
+
|
9
|
+
=test_inherit.rb
|
10
|
+
|
11
|
+
One big, complex test class hierarchy, for testing mixed features.
|
12
|
+
|
13
|
+
=end
|
14
|
+
|
15
|
+
class A < Component
|
16
|
+
|
17
|
+
attr_accessor :t
|
18
|
+
|
19
|
+
state :S0, :S1, :S2
|
20
|
+
|
21
|
+
setup { start S0; @x = -100000; @t = 0 } # To override
|
22
|
+
|
23
|
+
flow(S0, S1, S2) { diff "t' = 1" }
|
24
|
+
|
25
|
+
flow(S0) { diff "x' = 1" }
|
26
|
+
flow(S1) { diff "x' = -10" } # To override
|
27
|
+
flow(S2) { diff "x' = 100" }
|
28
|
+
|
29
|
+
transition S0 => S1 do guard { @t > 1 }; action { @t -= 1 } end
|
30
|
+
|
31
|
+
# To override:
|
32
|
+
transition(S1 => S2) {
|
33
|
+
name :from_S1_to_S2 # so that inheritance knows what to replace
|
34
|
+
guard { @t > 0.5 }; action { puts "KABOOM!" }
|
35
|
+
}
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
class B < A
|
40
|
+
|
41
|
+
state :S3
|
42
|
+
|
43
|
+
setup { @x = 0 }
|
44
|
+
|
45
|
+
flow(S1) { diff "x' = -20" } # To override
|
46
|
+
flow(S3) { diff "x' = 1000", "t' = 1" }
|
47
|
+
|
48
|
+
transition(S1 => S2) {
|
49
|
+
name :from_S1_to_S2
|
50
|
+
guard { @t > 1 }; action { @t -= 1 }
|
51
|
+
}
|
52
|
+
|
53
|
+
transition(S2 => S3) { guard { @t > 1 }; action { @t -= 1 } }
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
class C < B
|
58
|
+
|
59
|
+
state :S4
|
60
|
+
|
61
|
+
flow(S1) { diff "x' = 10" }
|
62
|
+
flow(S4) { diff "x' = 10000", "t' = 1" }
|
63
|
+
|
64
|
+
transition(S3 => S4) { guard { @t > 1 }; action { @t -= 1 } }
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
class Z < Component
|
69
|
+
|
70
|
+
attr_accessor :t
|
71
|
+
|
72
|
+
state :S0, :S1, :S2, :S3, :S4
|
73
|
+
|
74
|
+
setup { start S0; @x = 0; @t = 0 }
|
75
|
+
|
76
|
+
flow(S0, S1, S2, S3, S4) { diff "t' = 1" }
|
77
|
+
|
78
|
+
flow(S0) { diff "x' = 1" }
|
79
|
+
flow(S1) { diff "x' = 10" }
|
80
|
+
flow(S2) { diff "x' = 100" }
|
81
|
+
flow(S3) { diff "x' = 1000" }
|
82
|
+
flow(S4) { diff "x' = 10000" }
|
83
|
+
|
84
|
+
transition(S0 => S1) { guard { @t > 1 }; action { @t -= 1 } }
|
85
|
+
transition(S1 => S2) { guard { @t > 1 }; action { @t -= 1 } }
|
86
|
+
transition(S2 => S3) { guard { @t > 1 }; action { @t -= 1 } }
|
87
|
+
transition(S3 => S4) { guard { @t > 1 }; action { @t -= 1 } }
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
require 'test/unit'
|
93
|
+
|
94
|
+
class TestInherit < Test::Unit::TestCase
|
95
|
+
|
96
|
+
def setup
|
97
|
+
@world = World.new
|
98
|
+
@world.time_step = 0.1
|
99
|
+
end
|
100
|
+
|
101
|
+
def teardown
|
102
|
+
@world = nil
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_mixed
|
106
|
+
c = @world.create(C)
|
107
|
+
z = @world.create(Z)
|
108
|
+
|
109
|
+
# Static assertions
|
110
|
+
c_state_names = c.states.map {|s| s.name}
|
111
|
+
z_state_names = z.states.map {|s| s.name}
|
112
|
+
assert_equal([], c_state_names - z_state_names)
|
113
|
+
assert_equal([], z_state_names - c_state_names)
|
114
|
+
|
115
|
+
# Dynamic assertions
|
116
|
+
while @world.clock <= 10 do
|
117
|
+
@world.run
|
118
|
+
|
119
|
+
assert_equal(c.t, z.t,
|
120
|
+
"time #{@world.clock}\n")
|
121
|
+
assert_equal(c.state.name, z.state.name,
|
122
|
+
"time #{@world.clock}\n c.t: #{c.t} z.t: #{z.t}")
|
123
|
+
|
124
|
+
assert_in_delta(c.x, z.x, 0.000001)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|