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
data/test/test_delay.rb
ADDED
@@ -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
|