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,92 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'redshift'
|
4
|
+
|
5
|
+
include RedShift
|
6
|
+
|
7
|
+
=begin
|
8
|
+
|
9
|
+
This file runs tests that have to be done without the presence of other objects in the world. Each test is performed in a separate world.
|
10
|
+
|
11
|
+
=end
|
12
|
+
|
13
|
+
class DiscreteIsolatedTestComponent < Component
|
14
|
+
def initialize(*args)
|
15
|
+
super
|
16
|
+
@t = world.clock
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# transitions with no body keep the discrete step alive
|
21
|
+
|
22
|
+
class DiscreteIsolated_1 < DiscreteIsolatedTestComponent
|
23
|
+
prev = Enter
|
24
|
+
for state_name in "State_01".."State_10"
|
25
|
+
state state_name
|
26
|
+
|
27
|
+
curr = const_get(state_name)
|
28
|
+
|
29
|
+
flow prev do
|
30
|
+
diff "x' = 1"
|
31
|
+
end
|
32
|
+
|
33
|
+
transition prev => curr
|
34
|
+
prev = curr
|
35
|
+
end
|
36
|
+
@@last = prev
|
37
|
+
|
38
|
+
def assert_consistent test
|
39
|
+
test.assert_equal(@@last, state)
|
40
|
+
test.assert_in_delta(0, x, 1.0E-20)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# transitions with just a guard keep the discrete step alive
|
45
|
+
|
46
|
+
class DiscreteIsolated_2 < DiscreteIsolatedTestComponent
|
47
|
+
state :A, :B
|
48
|
+
flow A do
|
49
|
+
diff "x' = 1"
|
50
|
+
end
|
51
|
+
transition Enter => A, A => B do
|
52
|
+
guard {true}
|
53
|
+
end
|
54
|
+
def assert_consistent test
|
55
|
+
test.assert_equal(B, state)
|
56
|
+
test.assert_in_delta(0, x, 1.0E-20)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
#-----#
|
62
|
+
|
63
|
+
require 'test/unit'
|
64
|
+
|
65
|
+
class TestDiscrete < Test::Unit::TestCase
|
66
|
+
|
67
|
+
def setup
|
68
|
+
@world = World.new
|
69
|
+
@world.time_step = 0.1
|
70
|
+
end
|
71
|
+
|
72
|
+
def teardown
|
73
|
+
@world = nil
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_discrete_isolated
|
77
|
+
testers = []
|
78
|
+
ObjectSpace.each_object(Class) do |cl|
|
79
|
+
if cl <= DiscreteIsolatedTestComponent and
|
80
|
+
cl.instance_methods.include? "assert_consistent"
|
81
|
+
world = World.new
|
82
|
+
world.time_step = 0.1
|
83
|
+
testers << [world, world.create(cl)]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
for w,t in testers
|
88
|
+
w.run
|
89
|
+
t.assert_consistent self
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/test/test_exit.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'redshift'
|
4
|
+
|
5
|
+
include RedShift
|
6
|
+
|
7
|
+
# Tests that exited components do not evolve continuously or discretely.
|
8
|
+
|
9
|
+
class ExitComponent < Component
|
10
|
+
strictly_continuous :x
|
11
|
+
flow do
|
12
|
+
diff "x' = 1"
|
13
|
+
end
|
14
|
+
|
15
|
+
setup do
|
16
|
+
@guard_count = 0
|
17
|
+
@x_event_time = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
transition Enter => Exit do
|
21
|
+
guard {x > 0.5}
|
22
|
+
end
|
23
|
+
|
24
|
+
transition Exit => Exit do
|
25
|
+
action {@transition_on_exit = true}
|
26
|
+
end
|
27
|
+
|
28
|
+
def assert_consistent(test)
|
29
|
+
test.assert(!@transition_on_exit)
|
30
|
+
test.assert(x < 0.61)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
#-----#
|
35
|
+
|
36
|
+
require 'test/unit'
|
37
|
+
|
38
|
+
class TestExit < Test::Unit::TestCase
|
39
|
+
|
40
|
+
def setup
|
41
|
+
@world = World.new
|
42
|
+
@world.time_step = 0.1
|
43
|
+
end
|
44
|
+
|
45
|
+
def teardown
|
46
|
+
@world = nil
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_exit
|
50
|
+
tc = @world.create(ExitComponent)
|
51
|
+
|
52
|
+
tc.assert_consistent(self)
|
53
|
+
@world.run 10 do
|
54
|
+
tc.assert_consistent(self)
|
55
|
+
end
|
56
|
+
tc.assert_consistent(self)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
data/test/test_flow.rb
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'redshift'
|
4
|
+
|
5
|
+
include RedShift
|
6
|
+
|
7
|
+
class FlowTestComponent < Component
|
8
|
+
def finish test
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Empty flows are constant.
|
13
|
+
|
14
|
+
class Flow_Empty < FlowTestComponent
|
15
|
+
continuous :x
|
16
|
+
setup { self.x = 5 }
|
17
|
+
def assert_consistent test
|
18
|
+
test.assert_in_delta(5, x, 0.0000000000001)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Make sure timers work!
|
23
|
+
|
24
|
+
class Flow_Euler < FlowTestComponent
|
25
|
+
flow { euler "t' = 1" }
|
26
|
+
setup { self.t = 0 }
|
27
|
+
def assert_consistent test
|
28
|
+
test.assert_in_delta(world.clock, t, 0.0000000001)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Alg flows.
|
33
|
+
|
34
|
+
class Flow_Alg < FlowTestComponent
|
35
|
+
flow { alg "f = 1", "g = f + 2" }
|
36
|
+
def assert_consistent test
|
37
|
+
test.assert_in_delta(1, f, 0.0000000001)
|
38
|
+
test.assert_in_delta(3, g, 0.0000000001)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Trig functions.
|
43
|
+
|
44
|
+
class Flow_Sin < FlowTestComponent
|
45
|
+
flow { diff "y' = y_prime", "y_prime' = -y" }
|
46
|
+
setup { self.y = 0; self.y_prime = 1 }
|
47
|
+
def assert_consistent test
|
48
|
+
test.assert_in_delta(sin(world.clock), y, 0.000000001)
|
49
|
+
## is this epsilon ok? how does it compare with cshift?
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Exp functions.
|
54
|
+
|
55
|
+
class Flow_Exp < FlowTestComponent
|
56
|
+
flow { diff "y' = y" }
|
57
|
+
setup { self.y = 1 }
|
58
|
+
def assert_consistent test
|
59
|
+
test.assert_in_delta(exp(world.clock), y, 0.0001)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Polynomials.
|
64
|
+
|
65
|
+
class Flow_Poly < Flow_Euler # note use of timer t from Flow_Euler
|
66
|
+
flow {
|
67
|
+
alg "poly = -6 * pow(t,3) + 1.2 * pow(t,2) - t + 10"
|
68
|
+
diff "y' = y1", "y1' = y2", "y2' = y3", "y3' = 0"
|
69
|
+
}
|
70
|
+
setup { self.y = 10; self.y1 = -1; self.y2 = 1.2 * 2; self.y3 = -6 * 3 * 2 }
|
71
|
+
def assert_consistent test
|
72
|
+
test.assert_in_delta(poly, y, 0.000000001, "at time #{world.clock}")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# test for detection of circularity and assignment to algebraically
|
77
|
+
# defined vars
|
78
|
+
|
79
|
+
class Flow_AlgebraicErrors < FlowTestComponent
|
80
|
+
flow {
|
81
|
+
alg "x = y"
|
82
|
+
alg "y = x"
|
83
|
+
alg "z = 1"
|
84
|
+
}
|
85
|
+
|
86
|
+
def assert_consistent test
|
87
|
+
return if world.clock > 1
|
88
|
+
test.assert_raises(RedShift::CircularDefinitionError) {y}
|
89
|
+
test.assert_raises(RedShift::AlgebraicAssignmentError) {self.z = 2}
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Assignments to continuous vars force update of alg flows
|
94
|
+
|
95
|
+
class Flow_AlgUpdate_Assignment < FlowTestComponent
|
96
|
+
flow {alg "y = x"}
|
97
|
+
continuous :x
|
98
|
+
|
99
|
+
def assert_consistent test
|
100
|
+
return if world.clock > 1
|
101
|
+
test.assert_in_delta(0, y, 1E-10);
|
102
|
+
self.x = 1
|
103
|
+
test.assert_in_delta(1, y, 1E-10);
|
104
|
+
self.x = 0
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Test that a diff flow that refers to an alg flow updates it during c.u. and
|
109
|
+
# that the updated value is used in the next d.u. This is related to the
|
110
|
+
# var->d_tick assignment in step_continuous(). We're testing that the
|
111
|
+
# optimization doesn't *prevent* the evaluation of y.
|
112
|
+
class Flow_AlgDiff < FlowTestComponent
|
113
|
+
flow {
|
114
|
+
alg " x = 3*y "
|
115
|
+
diff " y' = x "
|
116
|
+
}
|
117
|
+
state :S1
|
118
|
+
default {self.y = 1}
|
119
|
+
transition Enter => S1 do
|
120
|
+
guard "y > 5"
|
121
|
+
action {@x = x; @y = y}
|
122
|
+
end
|
123
|
+
|
124
|
+
def assert_consistent test
|
125
|
+
if @x
|
126
|
+
test.assert_in_delta(3*@y, @x, 1E-10)
|
127
|
+
@x = @y = nil
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
## TO DO ##
|
133
|
+
=begin
|
134
|
+
|
135
|
+
varying time step (dynamically?)
|
136
|
+
|
137
|
+
handling of syntax errors
|
138
|
+
|
139
|
+
=end
|
140
|
+
|
141
|
+
###class Flow_MixedType < FlowTestComponent
|
142
|
+
### flow {
|
143
|
+
### euler "w' = 4"
|
144
|
+
### diff "x' = w"
|
145
|
+
### diff "y' = 4"
|
146
|
+
### diff "z' = y" ### fails if these are more complex than just w or y
|
147
|
+
### }
|
148
|
+
### setup { self.w = self.y = 0; self.x = self.z = 0 }
|
149
|
+
### def assert_consistent test
|
150
|
+
### test.assert_in_delta(x, z, 0.001, "at time #{world.clock}")
|
151
|
+
### end
|
152
|
+
###end
|
153
|
+
|
154
|
+
|
155
|
+
#-----#
|
156
|
+
|
157
|
+
require 'test/unit'
|
158
|
+
|
159
|
+
class TestFlow < Test::Unit::TestCase
|
160
|
+
|
161
|
+
def setup
|
162
|
+
@world = World.new
|
163
|
+
@world.time_step = 0.01
|
164
|
+
@world.zeno_limit = 100
|
165
|
+
end
|
166
|
+
|
167
|
+
def teardown
|
168
|
+
@world = nil
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_flow
|
172
|
+
testers = []
|
173
|
+
ObjectSpace.each_object(Class) do |cl|
|
174
|
+
if cl <= FlowTestComponent and
|
175
|
+
cl.instance_methods.include? "assert_consistent"
|
176
|
+
testers << @world.create(cl)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
testers.each { |t| t.assert_consistent self }
|
181
|
+
@world.run 1000 do
|
182
|
+
testers.each { |t| t.assert_consistent self }
|
183
|
+
end
|
184
|
+
testers.each { |t| t.finish self }
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
END {
|
189
|
+
|
190
|
+
# require 'plot/plot'
|
191
|
+
# Plot.new ('gnuplot') {
|
192
|
+
# add Flow_Reconfig::Y, 'title "y" with lines'
|
193
|
+
# add Flow_Reconfig::Y1, 'title "y1" with lines'
|
194
|
+
# add Flow_Reconfig::Y2, 'title "y2" with lines'
|
195
|
+
# add Flow_Reconfig::Y3, 'title "y3" with lines'
|
196
|
+
# show
|
197
|
+
# pause 5
|
198
|
+
# }
|
199
|
+
|
200
|
+
}
|
@@ -0,0 +1,288 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'redshift'
|
4
|
+
|
5
|
+
include RedShift
|
6
|
+
|
7
|
+
class FlowTestComponent < Component
|
8
|
+
def finish test
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# test links in flows
|
13
|
+
|
14
|
+
class Flow_UsingLink < FlowTestComponent
|
15
|
+
class Sub < Component
|
16
|
+
flow { diff "x' = 2" }
|
17
|
+
end
|
18
|
+
|
19
|
+
link :sub => Sub
|
20
|
+
setup { self.sub = create Sub }
|
21
|
+
|
22
|
+
flow {
|
23
|
+
diff "y' = sub.x"
|
24
|
+
diff "t' = 1"
|
25
|
+
}
|
26
|
+
|
27
|
+
def assert_consistent test
|
28
|
+
test.assert_in_delta(
|
29
|
+
t**2,
|
30
|
+
y,
|
31
|
+
0.00000000001,
|
32
|
+
"in #{state.name} after #{t} sec,\n")
|
33
|
+
end
|
34
|
+
|
35
|
+
def finish test
|
36
|
+
# puts "y = #{y} at time #{t}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# test links in flows
|
41
|
+
|
42
|
+
class Flow_UsingLink2 < FlowTestComponent
|
43
|
+
class Sub < Component
|
44
|
+
flow { alg "alg_dy = 2" }
|
45
|
+
flow { diff "diff_dy' = 0" }; default { self.diff_dy = 2 }
|
46
|
+
continuous :const_dy; default { self.const_dy = 2 }
|
47
|
+
end
|
48
|
+
|
49
|
+
link :sub => Sub
|
50
|
+
|
51
|
+
setup do
|
52
|
+
self.sub = create Sub
|
53
|
+
end
|
54
|
+
|
55
|
+
flow do
|
56
|
+
diff "t' = 1"
|
57
|
+
diff "y' = 2"
|
58
|
+
|
59
|
+
diff "y1' = sub.alg_dy"
|
60
|
+
diff "y2' = sub.diff_dy"
|
61
|
+
diff "y3' = sub.const_dy"
|
62
|
+
end
|
63
|
+
|
64
|
+
def assert_consistent test
|
65
|
+
test.assert_in_delta(y, y1, 0.00000000001,
|
66
|
+
"in #{state.name} after #{t} sec,\n")
|
67
|
+
test.assert_in_delta(y, y2, 0.00000000001,
|
68
|
+
"in #{state.name} after #{t} sec,\n")
|
69
|
+
test.assert_in_delta(y, y3, 0.00000000001,
|
70
|
+
"in #{state.name} after #{t} sec,\n")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# compare a system of equations in one component
|
75
|
+
# with the same system distributed among several
|
76
|
+
|
77
|
+
class Flow_UsingLink3 < FlowTestComponent
|
78
|
+
class Sub1 < Component; end
|
79
|
+
class Sub2 < Component; end
|
80
|
+
|
81
|
+
class Sub1
|
82
|
+
flow do
|
83
|
+
diff "x' = 3*y + sub2.f"
|
84
|
+
diff "y' = x + y*(0.1 * sub2.z - 0.2 * sub2.g)"
|
85
|
+
# diff "z' = (f + y + z) * 0.1"
|
86
|
+
# alg "f = 0.3*(x + g) + 0.02"
|
87
|
+
# alg "g = 2*z + h"
|
88
|
+
alg "h = y - sub2.z + 1"
|
89
|
+
end
|
90
|
+
link :sub2 => Sub2
|
91
|
+
end
|
92
|
+
|
93
|
+
class Sub2
|
94
|
+
flow do
|
95
|
+
# diff "x' = 3*y + f"
|
96
|
+
# diff "y' = x + y*(0.1 * z - 0.2 * g)"
|
97
|
+
diff "z' = (f + sub1.y + z) * 0.1"
|
98
|
+
alg "f = 0.3*(sub1.x + g) + 0.02"
|
99
|
+
alg "g = 2*z + sub1.h"
|
100
|
+
# alg "h = y - z + 1"
|
101
|
+
end
|
102
|
+
link :sub1 => Sub1
|
103
|
+
end
|
104
|
+
|
105
|
+
link :sub1 => Sub1
|
106
|
+
link :sub2 => Sub2
|
107
|
+
|
108
|
+
setup do
|
109
|
+
self.sub1 = create Sub1
|
110
|
+
self.sub2 = create Sub2
|
111
|
+
|
112
|
+
sub1.sub2 = sub2
|
113
|
+
sub2.sub1 = sub1
|
114
|
+
end
|
115
|
+
|
116
|
+
flow do
|
117
|
+
diff "x' = 3*y + f"
|
118
|
+
diff "y' = x + y*(0.1 * z - 0.2 * g)"
|
119
|
+
diff "z' = (f + y + z) * 0.1"
|
120
|
+
alg "f = 0.3*(x + g) + 0.02"
|
121
|
+
alg "g = 2*z + h"
|
122
|
+
alg "h = y - z + 1"
|
123
|
+
end
|
124
|
+
|
125
|
+
def assert_consistent test
|
126
|
+
cmp = proc do |x, y|
|
127
|
+
test.assert_in_delta(x, y, 0.00000000001,
|
128
|
+
"in #{state.name} after #{world.clock} sec,\n")
|
129
|
+
end
|
130
|
+
|
131
|
+
cmp[x,sub1.x]
|
132
|
+
cmp[y,sub1.y]
|
133
|
+
cmp[z,sub2.z]
|
134
|
+
cmp[f,sub2.f]
|
135
|
+
cmp[g,sub2.g]
|
136
|
+
cmp[h,sub1.h]
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# test "lnk ? lnk.z : w" and "lnk1 = lnk2 ? x : y"
|
141
|
+
|
142
|
+
class Flow_Boolean < FlowTestComponent
|
143
|
+
class Sub < Component
|
144
|
+
flow {alg "x = 1"}
|
145
|
+
end
|
146
|
+
link :sub0 => Sub
|
147
|
+
link :sub1 => Sub
|
148
|
+
link :sub2 => Sub
|
149
|
+
setup {
|
150
|
+
self.sub1 = create Sub
|
151
|
+
self.sub2 = sub1
|
152
|
+
}
|
153
|
+
flow {
|
154
|
+
alg "y0 = sub1 ? sub1.x : 0"
|
155
|
+
alg "y1 = sub0 ? 0 : sub2.x"
|
156
|
+
alg "y2 = sub1 == sub2 ? sub1.x : 0"
|
157
|
+
}
|
158
|
+
def assert_consistent test
|
159
|
+
cmp = proc do |x, y|
|
160
|
+
test.assert_in_delta(x, y, 0.00000000001,
|
161
|
+
"in #{state.name} after #{world.clock} sec,\n")
|
162
|
+
end
|
163
|
+
|
164
|
+
cmp[1,y0]
|
165
|
+
cmp[1,y1]
|
166
|
+
cmp[1,y2]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# test error handling of nil links
|
171
|
+
|
172
|
+
class Flow_NilLink < FlowTestComponent
|
173
|
+
class Sub < Component
|
174
|
+
continuous :z
|
175
|
+
end
|
176
|
+
link :nl => Sub
|
177
|
+
continuous :x
|
178
|
+
flow {alg "y = x ? nl.z : 0"}
|
179
|
+
def assert_consistent test
|
180
|
+
return true if x > 0
|
181
|
+
test.assert_raises(Flow::NilLinkError, "Didn't detect nil link.") do
|
182
|
+
self.x = 1
|
183
|
+
y
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
# test self links
|
189
|
+
|
190
|
+
class Flow_SelfLink < FlowTestComponent
|
191
|
+
link :sl => Flow_SelfLink
|
192
|
+
setup {self.sl = self; self.y=1; self.z=1}
|
193
|
+
flow {diff "y' = sl.y"; diff "z'=z"}
|
194
|
+
def assert_consistent test
|
195
|
+
test.assert_in_delta(z, y, 0.00000000001)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# test dynamic reconfiguration in flows
|
200
|
+
|
201
|
+
class Flow_Reconfig < FlowTestComponent
|
202
|
+
class Sub < Component
|
203
|
+
continuous :k; default { self.k = 2 }
|
204
|
+
flow { alg "dy = k" }
|
205
|
+
end
|
206
|
+
|
207
|
+
link :sub => Sub
|
208
|
+
|
209
|
+
setup do
|
210
|
+
@sub1 = create Sub
|
211
|
+
@sub2 = create Sub
|
212
|
+
@sub2.k = - @sub1.k
|
213
|
+
@next_t = 0
|
214
|
+
end
|
215
|
+
|
216
|
+
state :Sub1, :Sub2
|
217
|
+
|
218
|
+
continuous :dy; setup { self.dy = 2 }
|
219
|
+
|
220
|
+
flow Sub1, Sub2 do
|
221
|
+
diff "y' = sub.dy"
|
222
|
+
diff "y1' = dy"
|
223
|
+
diff "t' = 1"
|
224
|
+
end
|
225
|
+
|
226
|
+
transition Enter => Sub1, Sub2 => Sub1 do
|
227
|
+
guard { t >= @next_t }
|
228
|
+
action { self.sub = @sub1; @next_t += 1; self.dy = sub.dy }
|
229
|
+
end
|
230
|
+
|
231
|
+
transition Sub1 => Sub2 do
|
232
|
+
guard { t >= @next_t }
|
233
|
+
action { self.sub = @sub2; @next_t += 1; self.dy = sub.dy }
|
234
|
+
end
|
235
|
+
|
236
|
+
def assert_consistent test
|
237
|
+
test.assert_in_delta(y1, y, 0.00000000001,
|
238
|
+
"in #{state.name} after #{t} sec,\n")
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
|
243
|
+
#-----#
|
244
|
+
|
245
|
+
require 'test/unit'
|
246
|
+
|
247
|
+
class TestFlow < Test::Unit::TestCase
|
248
|
+
|
249
|
+
def setup
|
250
|
+
@world = World.new
|
251
|
+
@world.time_step = 0.01
|
252
|
+
@world.zeno_limit = 100
|
253
|
+
end
|
254
|
+
|
255
|
+
def teardown
|
256
|
+
@world = nil
|
257
|
+
end
|
258
|
+
|
259
|
+
def test_flow_link
|
260
|
+
testers = []
|
261
|
+
ObjectSpace.each_object(Class) do |cl|
|
262
|
+
if cl <= FlowTestComponent and
|
263
|
+
cl.instance_methods.include? "assert_consistent"
|
264
|
+
testers << @world.create(cl)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
testers.each { |t| t.assert_consistent self }
|
269
|
+
@world.run 100 do
|
270
|
+
testers.each { |t| t.assert_consistent self }
|
271
|
+
end
|
272
|
+
testers.each { |t| t.finish self }
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
END {
|
277
|
+
|
278
|
+
# require 'plot/plot'
|
279
|
+
# Plot.new ('gnuplot') {
|
280
|
+
# add Flow_Reconfig::Y, 'title "y" with lines'
|
281
|
+
# add Flow_Reconfig::Y1, 'title "y1" with lines'
|
282
|
+
# add Flow_Reconfig::Y2, 'title "y2" with lines'
|
283
|
+
# add Flow_Reconfig::Y3, 'title "y3" with lines'
|
284
|
+
# show
|
285
|
+
# pause 5
|
286
|
+
# }
|
287
|
+
|
288
|
+
}
|