redshift 1.3.15
Sign up to get free protection for your applications and to get access to all the features.
- 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,242 @@
|
|
1
|
+
require "redshift"
|
2
|
+
include RedShift
|
3
|
+
|
4
|
+
class A < Component
|
5
|
+
continuous :x
|
6
|
+
constant :k => 6.78
|
7
|
+
flow do
|
8
|
+
diff " x' = 2*x "
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class B < Component
|
13
|
+
input :y
|
14
|
+
input :yy # usually unused, so doesn't need to be connected
|
15
|
+
link :other => B
|
16
|
+
|
17
|
+
flow do
|
18
|
+
alg " z = y+1 "
|
19
|
+
alg " w = y + yy "
|
20
|
+
alg " u = other.y "
|
21
|
+
end
|
22
|
+
transition Enter => Exit do
|
23
|
+
guard "y < 0"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
#-----#
|
28
|
+
|
29
|
+
require 'test/unit'
|
30
|
+
|
31
|
+
class TestConnect < Test::Unit::TestCase
|
32
|
+
|
33
|
+
def setup
|
34
|
+
@world = World.new
|
35
|
+
@world.time_step = 0.1
|
36
|
+
@a = @world.create(A)
|
37
|
+
@b = @world.create(B)
|
38
|
+
end
|
39
|
+
|
40
|
+
def teardown
|
41
|
+
@world = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_unconnected
|
45
|
+
assert_raises(UnconnectedInputError) do
|
46
|
+
@b.y
|
47
|
+
end
|
48
|
+
|
49
|
+
assert_raises(NoMethodError) do
|
50
|
+
@b.y = 1.23
|
51
|
+
end
|
52
|
+
|
53
|
+
assert_raises(UnconnectedInputError) do
|
54
|
+
@world.evolve 1
|
55
|
+
end
|
56
|
+
|
57
|
+
assert_raises(UnconnectedInputError) do
|
58
|
+
@b.z
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_not_connectable
|
63
|
+
assert_raises(TypeError) do
|
64
|
+
@a.port(:x) << @b.port(:y)
|
65
|
+
end
|
66
|
+
assert_raises(TypeError) do
|
67
|
+
@a.connect(:x, @b, :y)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_connect
|
72
|
+
@b.connect(:y, @a, :x)
|
73
|
+
@a.x = 4.56
|
74
|
+
|
75
|
+
assert_equal(@a.x, @b.y)
|
76
|
+
assert_equal(@b.y+1, @b.z)
|
77
|
+
@world.evolve 1 do
|
78
|
+
assert_equal(@a.x, @b.y)
|
79
|
+
assert_equal(@b.y+1, @b.z)
|
80
|
+
end
|
81
|
+
|
82
|
+
# reconnect to different var (actually a constant)
|
83
|
+
@b.connect(:y, @a, :k)
|
84
|
+
|
85
|
+
assert_equal(@a.k, @b.y)
|
86
|
+
assert_equal(@b.y+1, @b.z)
|
87
|
+
@world.evolve 1 do
|
88
|
+
assert_equal(@a.k, @b.y)
|
89
|
+
assert_equal(@b.y+1, @b.z)
|
90
|
+
end
|
91
|
+
|
92
|
+
# disconnect
|
93
|
+
@b.disconnect(:y)
|
94
|
+
|
95
|
+
assert_raises(UnconnectedInputError) do
|
96
|
+
@b.z
|
97
|
+
end
|
98
|
+
|
99
|
+
assert_raises(UnconnectedInputError) do
|
100
|
+
@b.y
|
101
|
+
end
|
102
|
+
|
103
|
+
# nothing raised:
|
104
|
+
@b.disconnect(:y)
|
105
|
+
|
106
|
+
# reconnect to different component (using ports)
|
107
|
+
@a = @world.create(A)
|
108
|
+
@b.port(:y) << @a.port(:x)
|
109
|
+
|
110
|
+
@a.x = 7.89
|
111
|
+
|
112
|
+
assert_equal(@a.x, @b.y)
|
113
|
+
assert_equal(@a.x, @b.port(:y).value)
|
114
|
+
assert_equal(@b.y+1, @b.z)
|
115
|
+
@world.evolve 1 do
|
116
|
+
assert_equal(@a.x, @b.y)
|
117
|
+
assert_equal(@b.y+1, @b.z)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_reflection
|
122
|
+
@b.connect(:y, @a, :x)
|
123
|
+
|
124
|
+
assert_equal(@a.port(:x), @b.port(:y).source)
|
125
|
+
assert_equal(@a, @b.port(:y).source_component)
|
126
|
+
assert_equal(:x, @b.port(:y).source_variable)
|
127
|
+
|
128
|
+
assert_equal(@a, @a.port(:x).component)
|
129
|
+
assert_equal(:x, @a.port(:x).variable)
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_disconnect
|
133
|
+
@b.connect(:y, @a, :x)
|
134
|
+
@b.disconnect(:y)
|
135
|
+
assert_equal(nil, @b.port(:y).source)
|
136
|
+
|
137
|
+
@b.port(:y).disconnect
|
138
|
+
assert_equal(nil, @b.port(:y).source)
|
139
|
+
|
140
|
+
@b.port(:y) << nil
|
141
|
+
assert_equal(nil, @b.port(:y).source)
|
142
|
+
|
143
|
+
assert_raises(UnconnectedInputError) do
|
144
|
+
@b.y
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_connect_to_input
|
149
|
+
b2 = @world.create(B)
|
150
|
+
@b.port(:y) << @a.port(:x)
|
151
|
+
b2.port(:y) << @b.port(:y)
|
152
|
+
@a.x = 3.456
|
153
|
+
assert_equal(@b.y, b2.y)
|
154
|
+
assert_equal(@a.x, b2.y)
|
155
|
+
assert_equal(b2.y+1, b2.z)
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_connect_input_chain
|
159
|
+
b = (0..99).map {@world.create(B)}
|
160
|
+
(0..98).each do |i|
|
161
|
+
b[i+1].port(:y) << b[i].port(:y)
|
162
|
+
end
|
163
|
+
b[0].port(:y) << @a.port(:x)
|
164
|
+
|
165
|
+
@a.x = 42.4242
|
166
|
+
assert_equal(@a.x, b[99].y)
|
167
|
+
assert_equal(@a.x, b[0].y)
|
168
|
+
|
169
|
+
old_b_50 = b[50]
|
170
|
+
b[50] = @world.create(B)
|
171
|
+
b[50].port(:y) << b[49].port(:y)
|
172
|
+
b[51].port(:y) << b[50].port(:y)
|
173
|
+
|
174
|
+
@a.x = 987.789
|
175
|
+
assert_equal(@a.x, b[99].y)
|
176
|
+
assert_equal(@a.x, b[0].y)
|
177
|
+
assert_equal(@a.x, old_b_50.y)
|
178
|
+
end
|
179
|
+
|
180
|
+
def make_circle n
|
181
|
+
b = (0...n).map {@world.create(B)}
|
182
|
+
n.times do |i|
|
183
|
+
b[i].port(:y) << b[(i+1)%n].port(:y)
|
184
|
+
end
|
185
|
+
b
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_connect_input_circular
|
189
|
+
[1, 2, 3, 10].each do |n|
|
190
|
+
b = make_circle(n)
|
191
|
+
assert_raises(RedShift::CircularDefinitionError) do
|
192
|
+
b[0].y
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def test_connect_input_flow
|
198
|
+
b = (0..5).map {@world.create(B)}
|
199
|
+
(0..4).each do |i|
|
200
|
+
b[i+1].port(:y) << b[i].port(:y)
|
201
|
+
end
|
202
|
+
b[0].port(:y) << @a.port(:x)
|
203
|
+
|
204
|
+
@b.port(:y) << @a.port(:x) # ust so guard doesn't find y unconn.
|
205
|
+
|
206
|
+
@a.x = 1.0
|
207
|
+
assert_equal(@a.x, b[5].y)
|
208
|
+
assert_equal(@a.x, b[0].y)
|
209
|
+
|
210
|
+
@world.evolve 10
|
211
|
+
assert_equal(@a.x, b[5].y)
|
212
|
+
assert_equal(@a.x, b[0].y)
|
213
|
+
end
|
214
|
+
|
215
|
+
def test_connect_input_multiple
|
216
|
+
@b.port(:y) << @a.port(:x)
|
217
|
+
@b.port(:yy) << @b.port(:y) # Can connect to another var in self!
|
218
|
+
@a.x = 1.0
|
219
|
+
assert_equal(@a.x*2, @b.w)
|
220
|
+
end
|
221
|
+
|
222
|
+
def test_linked_input
|
223
|
+
@a.x = 99.876
|
224
|
+
|
225
|
+
@b.other = @world.create(B)
|
226
|
+
@b.other.port(:y) << @a.port(:k)
|
227
|
+
|
228
|
+
assert_equal(@b.other.y, @a.k)
|
229
|
+
assert_equal(@b.other.y, @b.u)
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_marshal
|
233
|
+
@a.x = -3.21
|
234
|
+
@b.port(:y) << @a.port(:x)
|
235
|
+
assert_equal(@a.x, @b.y)
|
236
|
+
|
237
|
+
world2 = Marshal.load(Marshal.dump(@world))
|
238
|
+
a = world2.grep(A).first
|
239
|
+
b = world2.grep(B).first
|
240
|
+
assert_equal(a.x, b.y)
|
241
|
+
end
|
242
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "redshift"
|
2
|
+
include RedShift
|
3
|
+
|
4
|
+
class A < Component
|
5
|
+
input :in
|
6
|
+
continuous :x => 1
|
7
|
+
link :comp
|
8
|
+
|
9
|
+
state :T
|
10
|
+
|
11
|
+
flow T do
|
12
|
+
diff " x' = in "
|
13
|
+
end
|
14
|
+
|
15
|
+
transition Enter => T do
|
16
|
+
reset :comp => nil
|
17
|
+
connect :in => proc {comp.port(:x)}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
#-----#
|
22
|
+
|
23
|
+
require 'test/unit'
|
24
|
+
|
25
|
+
class TestConnect < Test::Unit::TestCase
|
26
|
+
|
27
|
+
def setup
|
28
|
+
@world = World.new
|
29
|
+
@world.time_step = 0.001
|
30
|
+
@a0 = @world.create(A)
|
31
|
+
@a1 = @world.create(A)
|
32
|
+
@a0.comp = @a1
|
33
|
+
@a1.comp = @a0
|
34
|
+
end
|
35
|
+
|
36
|
+
def teardown
|
37
|
+
@world = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_evolve
|
41
|
+
@world.evolve 1
|
42
|
+
[@a0, @a1].each do |a|
|
43
|
+
assert_in_delta(Math::E, a.in, 1.0e-12)
|
44
|
+
assert_equal(nil, a.comp)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require "redshift"
|
2
|
+
include RedShift
|
3
|
+
|
4
|
+
class A < Component
|
5
|
+
continuous :ns_x
|
6
|
+
strictly_continuous :x
|
7
|
+
|
8
|
+
constant :ns_k
|
9
|
+
strictly_constant :k => 6.78
|
10
|
+
|
11
|
+
flow do
|
12
|
+
diff " x' = 2*x "
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class B < Component
|
17
|
+
strict_input :y
|
18
|
+
transition Enter => Exit do
|
19
|
+
name "t"
|
20
|
+
guard "y > 5"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Dummy < Component
|
25
|
+
state :S, :T, :U
|
26
|
+
setup do
|
27
|
+
start S
|
28
|
+
end
|
29
|
+
|
30
|
+
flow S do
|
31
|
+
diff "time' = 1"
|
32
|
+
end
|
33
|
+
|
34
|
+
transition S => T do
|
35
|
+
guard "time > 0"
|
36
|
+
reset :time => 0 # so we do it again next timestep
|
37
|
+
end
|
38
|
+
|
39
|
+
transition T => U, U => S
|
40
|
+
end
|
41
|
+
|
42
|
+
# From test_strict_continuity.rb
|
43
|
+
class SCWorld < World
|
44
|
+
def num_checks
|
45
|
+
@num_checks ||= Hash.new do |h,comp|
|
46
|
+
h[comp] = Hash.new do |h1,trans|
|
47
|
+
h1[trans] = 0
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def hook_eval_guard(comp, guard, enabled, trans, dest)
|
53
|
+
num_checks[comp][trans.name] += 1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
#-----#
|
58
|
+
|
59
|
+
require 'test/unit'
|
60
|
+
|
61
|
+
class TestConnectStrict < Test::Unit::TestCase
|
62
|
+
|
63
|
+
def setup
|
64
|
+
@world = SCWorld.new
|
65
|
+
@world.time_step = 0.1
|
66
|
+
@a = @world.create(A) {|a| a.x = 1 }
|
67
|
+
@b = @world.create(B)
|
68
|
+
@world.create(Dummy)
|
69
|
+
end
|
70
|
+
|
71
|
+
def teardown
|
72
|
+
@world = nil
|
73
|
+
end
|
74
|
+
|
75
|
+
# can connect strict_input *only* to strict var/const
|
76
|
+
def test_not_connectable
|
77
|
+
assert_raises(StrictnessError) do
|
78
|
+
@b.port(:y) << @a.port(:ns_x)
|
79
|
+
end
|
80
|
+
assert_raises(StrictnessError) do
|
81
|
+
@b.port(:y) << @a.port(:ns_k)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# can't disconnect strict_input that has been connected
|
86
|
+
def test_disconnect
|
87
|
+
@b.port(:y) << nil # ok
|
88
|
+
@b.port(:y) << @a.port(:x)
|
89
|
+
assert_raises(StrictnessError) do
|
90
|
+
@b.port(:y) << nil
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# can't connect to a different component
|
95
|
+
def test_reconnect_comp
|
96
|
+
@b.port(:y) << @a.port(:x)
|
97
|
+
@b.port(:y) << @a.port(:x) # ok
|
98
|
+
assert_raises(StrictnessError) do
|
99
|
+
@b.port(:y) << @world.create(A).port(:x)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# can't connect to a different var in same component
|
104
|
+
def test_reconnect_var
|
105
|
+
@b.port(:y) << @a.port(:x)
|
106
|
+
assert_raises(StrictnessError) do
|
107
|
+
@b.port(:y) << @a.port(:k)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# can reconnect if value is the same
|
112
|
+
def test_reconnect_same_value
|
113
|
+
a = @world.create(A) do |a|
|
114
|
+
a.x = a.k = 12.34
|
115
|
+
end
|
116
|
+
@b.port(:y) << a.port(:x)
|
117
|
+
assert_nothing_raised do
|
118
|
+
@b.port(:y) << a.port(:k)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# One check per step, despite the Dummy
|
123
|
+
def test_strict_guard
|
124
|
+
@b.port(:y) << @a.port(:x)
|
125
|
+
prev = nil
|
126
|
+
@world.evolve 2 do
|
127
|
+
if @b.state == Enter
|
128
|
+
if prev
|
129
|
+
assert_equal(prev + 1, @world.num_checks[@b]["t"])
|
130
|
+
end
|
131
|
+
prev = @world.num_checks[@b]["t"]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'redshift'
|
4
|
+
|
5
|
+
include RedShift
|
6
|
+
|
7
|
+
class ConstantTestComponent < Component
|
8
|
+
def finish test
|
9
|
+
end
|
10
|
+
|
11
|
+
constant :k
|
12
|
+
strictly_constant :ks
|
13
|
+
|
14
|
+
link :other => ConstantTestComponent
|
15
|
+
|
16
|
+
state :HasOther, :Stop
|
17
|
+
|
18
|
+
transition Enter => HasOther do
|
19
|
+
guard "other"
|
20
|
+
end
|
21
|
+
|
22
|
+
flow HasOther do
|
23
|
+
diff "x' = other.k + k + other.ks + ks"
|
24
|
+
diff "t' = 1"
|
25
|
+
end
|
26
|
+
|
27
|
+
transition HasOther => Stop do
|
28
|
+
guard "t >= 1"
|
29
|
+
action do
|
30
|
+
@y = other.k + k + other.ks + ks
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def assert_consistent test
|
35
|
+
if t >= 1
|
36
|
+
test.assert_in_delta(44, x, 1E-10)
|
37
|
+
test.assert_equal(44, @y)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
#-----#
|
43
|
+
|
44
|
+
require 'test/unit'
|
45
|
+
|
46
|
+
class TestConstant < Test::Unit::TestCase
|
47
|
+
|
48
|
+
def setup
|
49
|
+
@world = World.new
|
50
|
+
end
|
51
|
+
|
52
|
+
def teardown
|
53
|
+
@world = nil
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_constant
|
57
|
+
comp1 = @world.create(ConstantTestComponent) do |c1|
|
58
|
+
c1.k = 1.0
|
59
|
+
c1.ks = 10.0
|
60
|
+
end
|
61
|
+
|
62
|
+
comp2 = @world.create(ConstantTestComponent) do |c2|
|
63
|
+
c2.k = 3.0
|
64
|
+
c2.ks = 30.0
|
65
|
+
end
|
66
|
+
|
67
|
+
comp1.other = comp2
|
68
|
+
testers = [comp1, comp2]
|
69
|
+
|
70
|
+
@world.run 20
|
71
|
+
comp1.assert_consistent self
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|