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,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'mathn' # Use rationals for 1/2 etc.
|
4
|
+
|
5
|
+
require 'test/unit'
|
6
|
+
|
7
|
+
require 'redshift'
|
8
|
+
|
9
|
+
include RedShift
|
10
|
+
|
11
|
+
class Timer < Component
|
12
|
+
attr_accessor :x
|
13
|
+
flow { diff " x' = 1 " }
|
14
|
+
end
|
15
|
+
|
16
|
+
class TestNumerics < Test::Unit::TestCase
|
17
|
+
|
18
|
+
def setup
|
19
|
+
@world = World.new
|
20
|
+
@world.time_step = 0.1
|
21
|
+
end
|
22
|
+
|
23
|
+
def teardown
|
24
|
+
@world = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_rational
|
28
|
+
c = @world.create(Timer) { |timer| timer.x = 1/2}
|
29
|
+
@world.run 100
|
30
|
+
assert_in_delta(10.5, c.x, 0.000001)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
## should test NaN, Inf, precision, etc.
|
data/test/test_queue.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'redshift'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
class TestQueue < Test::Unit::TestCase
|
5
|
+
class Receiver < RedShift::Component
|
6
|
+
queue :q
|
7
|
+
transition Enter => Exit do
|
8
|
+
wait :q
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Sender < RedShift::Component
|
13
|
+
link :receiver => RedShift::Component
|
14
|
+
flow {diff "t'=1"}
|
15
|
+
transition Enter => Exit do
|
16
|
+
guard "t>1"
|
17
|
+
action do
|
18
|
+
receiver.q << "hello"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def setup
|
24
|
+
@world = RedShift::World.new
|
25
|
+
@s = @world.create(Sender)
|
26
|
+
@r = @world.create(Receiver)
|
27
|
+
@s.receiver = @r
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_msg_received
|
31
|
+
@world.evolve 0.9
|
32
|
+
assert_equal(RedShift::Component::Enter, @r.state)
|
33
|
+
assert(@world.queue_sleep[@r])
|
34
|
+
@world.evolve 0.2
|
35
|
+
assert_equal(RedShift::Component::Exit, @r.state)
|
36
|
+
assert_equal("hello", @r.q.pop)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class TestQueueAndStrict < Test::Unit::TestCase
|
41
|
+
class Receiver < RedShift::Component
|
42
|
+
queue :q
|
43
|
+
strictly_continuous :x
|
44
|
+
transition Enter => Exit do
|
45
|
+
guard "x>0"
|
46
|
+
end
|
47
|
+
transition Enter => Exit do
|
48
|
+
wait :q
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class Sender < RedShift::Component
|
53
|
+
link :receiver => RedShift::Component
|
54
|
+
flow {diff "t'=1"}
|
55
|
+
state :S1
|
56
|
+
transition Enter => S1 do
|
57
|
+
guard "t>1"
|
58
|
+
# this transition gives receiver a chance to go into strict sleep,
|
59
|
+
# if that bug exists in redshift
|
60
|
+
end
|
61
|
+
transition S1 => Exit do
|
62
|
+
action do
|
63
|
+
receiver.q << "hello"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def setup
|
69
|
+
@world = RedShift::World.new
|
70
|
+
@s = @world.create(Sender)
|
71
|
+
@r = @world.create(Receiver)
|
72
|
+
@s.receiver = @r
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_msg_received
|
76
|
+
@world.evolve 0.9
|
77
|
+
assert_equal(RedShift::Component::Enter, @r.state)
|
78
|
+
while @r.state == RedShift::Component::Enter do
|
79
|
+
# Can't be in queue sleep because of the x>0 guard.
|
80
|
+
assert(!@world.queue_sleep[@r])
|
81
|
+
@world.run 1
|
82
|
+
end
|
83
|
+
|
84
|
+
# in 1 step, @r should *both* receive the message and exit,
|
85
|
+
# which shows that it did not go into strict sleep after the first
|
86
|
+
# pass thru discrete update
|
87
|
+
assert_equal(RedShift::Component::Exit, @r.state)
|
88
|
+
assert_equal("hello", @r.q.pop)
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'redshift/queue'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
# Test queue class outside of simulation using mocked World and
|
5
|
+
# Component classes.
|
6
|
+
class TestQueueAlone < Test::Unit::TestCase
|
7
|
+
class World
|
8
|
+
attr_accessor :step_count, :discrete_step
|
9
|
+
end
|
10
|
+
class Component
|
11
|
+
attr_accessor :world, :awake
|
12
|
+
def inc_queue_ready_count
|
13
|
+
@awake = true
|
14
|
+
end
|
15
|
+
def dec_queue_ready_count
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def setup
|
20
|
+
@w = World.new
|
21
|
+
@w.step_count = 0
|
22
|
+
@w.discrete_step = 0
|
23
|
+
@c = Component.new
|
24
|
+
@c.world = @w
|
25
|
+
@q = RedShift::Queue.new @c
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_fifo
|
29
|
+
3.times do |i|
|
30
|
+
@q.push i
|
31
|
+
@w.discrete_step += 1
|
32
|
+
end
|
33
|
+
|
34
|
+
a = []
|
35
|
+
3.times do
|
36
|
+
a << @q.pop
|
37
|
+
end
|
38
|
+
|
39
|
+
assert_equal([0,1,2], a)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_unpop
|
43
|
+
@q.push 1
|
44
|
+
x = @q.pop
|
45
|
+
@q.unpop x
|
46
|
+
assert_equal(x, @q.pop)
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_simultaneous_entries
|
50
|
+
@w.step_count = 123
|
51
|
+
@w.discrete_step = 42
|
52
|
+
a = [1,2,3]
|
53
|
+
a.each do |x|
|
54
|
+
@q.push x
|
55
|
+
end
|
56
|
+
|
57
|
+
head = @q.pop
|
58
|
+
assert_equal(a, head)
|
59
|
+
@q.unpop head
|
60
|
+
|
61
|
+
@w.discrete_step += 1
|
62
|
+
@q.push "some stuff"
|
63
|
+
assert_equal(a, @q.pop)
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_unpop_partial
|
67
|
+
@w.step_count = 123
|
68
|
+
@w.discrete_step = 42
|
69
|
+
a = [1,2,3]
|
70
|
+
a.each do |x|
|
71
|
+
@q.push x
|
72
|
+
end
|
73
|
+
|
74
|
+
head = @q.pop
|
75
|
+
head.shift
|
76
|
+
@q.unpop head
|
77
|
+
|
78
|
+
head = @q.pop
|
79
|
+
assert_equal([2,3], head)
|
80
|
+
assert_equal(RedShift::SimultaneousQueueEntries, head.class)
|
81
|
+
head.shift
|
82
|
+
@q.unpop head
|
83
|
+
|
84
|
+
head = @q.pop
|
85
|
+
assert_equal(3, head)
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_wake
|
89
|
+
@c.awake = false
|
90
|
+
@q.push 1
|
91
|
+
assert_equal(true, @c.awake)
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_match_empty_queue
|
95
|
+
assert_equal(false, @q.head_matches(Object))
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_match_one_entry
|
99
|
+
@q.push("foo")
|
100
|
+
assert(@q.head_matches( ))
|
101
|
+
assert(@q.head_matches( /o/ ))
|
102
|
+
assert(@q.head_matches( String, /o/, proc {|x| x.kind_of?(String)} ))
|
103
|
+
|
104
|
+
assert_equal(false, @q.head_matches( /z/ ))
|
105
|
+
assert_equal(false, @q.head_matches( Symbol ))
|
106
|
+
assert_equal(false, @q.head_matches( proc {false} ))
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_match_simultaneous_entries
|
110
|
+
@q.push "foo"
|
111
|
+
@q.push "bar"
|
112
|
+
assert(@q.head_matches( /foo/ ))
|
113
|
+
assert(@q.head_matches( /bar/ ))
|
114
|
+
end
|
115
|
+
end
|
data/test/test_reset.rb
ADDED
@@ -0,0 +1,209 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'redshift'
|
4
|
+
|
5
|
+
include RedShift
|
6
|
+
|
7
|
+
# Tests resets in transitions.
|
8
|
+
|
9
|
+
class A < Component
|
10
|
+
constant :k1, :k2
|
11
|
+
|
12
|
+
continuous :x
|
13
|
+
continuous :y
|
14
|
+
|
15
|
+
link :other => A
|
16
|
+
|
17
|
+
state :S1, :S2
|
18
|
+
|
19
|
+
transition Enter => S1 do
|
20
|
+
reset :y => 1 # literal value (float or int)
|
21
|
+
end
|
22
|
+
|
23
|
+
transition S1 => S2 do
|
24
|
+
reset :x => "other.x", # expr value
|
25
|
+
:y => proc {10-y}, # proc value
|
26
|
+
:k1 => "y",
|
27
|
+
:k2 => proc {42}
|
28
|
+
end
|
29
|
+
|
30
|
+
transition S2 => Exit
|
31
|
+
end
|
32
|
+
|
33
|
+
class B < Component
|
34
|
+
state :S1, :S2
|
35
|
+
|
36
|
+
start S1
|
37
|
+
|
38
|
+
flow S1 do
|
39
|
+
alg " x = 1 "
|
40
|
+
end
|
41
|
+
flow S2 do
|
42
|
+
alg " x = 2 "
|
43
|
+
end
|
44
|
+
|
45
|
+
transition S1 => S2 do
|
46
|
+
reset :x => 3
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class C < Component
|
51
|
+
constant :k, :kk
|
52
|
+
state :S
|
53
|
+
transition Enter => S do
|
54
|
+
reset :k => "kk"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class ResetVarToNonFloat < Component
|
59
|
+
continuous :var
|
60
|
+
state :S
|
61
|
+
transition Enter => S do
|
62
|
+
reset :var => proc {nil}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class ResetLink < Component
|
67
|
+
link :lnk => C
|
68
|
+
state :S
|
69
|
+
transition Enter => S do
|
70
|
+
reset :lnk => proc {create(C) {|c| c.kk = 1.337}}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class ResetLinkToNil < Component
|
75
|
+
link :lnk => C
|
76
|
+
state :S
|
77
|
+
transition Enter => S do
|
78
|
+
reset :lnk => proc {nil}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class ResetLinkToLiteralNil < Component
|
83
|
+
link :lnk => C
|
84
|
+
state :S
|
85
|
+
transition Enter => S do
|
86
|
+
reset :lnk => nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class ResetLinkToWrongType < Component
|
91
|
+
link :lnk => C
|
92
|
+
state :S
|
93
|
+
transition Enter => S do
|
94
|
+
reset :lnk => proc {create(A)}
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class Emitter < Component
|
99
|
+
transition Enter => Exit do
|
100
|
+
event :e => 42.0
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class Receiver < Component
|
105
|
+
link :c => Emitter
|
106
|
+
constant :result
|
107
|
+
transition Enter => Exit do
|
108
|
+
sync :c => :e
|
109
|
+
event :e => 0.42
|
110
|
+
reset :result => "e + c.e"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
require 'test/unit'
|
115
|
+
|
116
|
+
class TestReset < Test::Unit::TestCase
|
117
|
+
|
118
|
+
def setup
|
119
|
+
@world = World.new
|
120
|
+
@world.time_step = 0.1
|
121
|
+
end
|
122
|
+
|
123
|
+
def teardown
|
124
|
+
@world = nil
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_reset
|
128
|
+
a1 = @world.create(A)
|
129
|
+
a2 = @world.create(A)
|
130
|
+
|
131
|
+
a1.other = a2
|
132
|
+
a2.other = a1
|
133
|
+
|
134
|
+
a1.x = v1 = 5
|
135
|
+
a2.x = v2 = 1.23
|
136
|
+
|
137
|
+
@world.run 1
|
138
|
+
|
139
|
+
assert_equal(v2, a1.x)
|
140
|
+
assert_equal(v1, a2.x)
|
141
|
+
|
142
|
+
assert_equal(9, a1.y)
|
143
|
+
assert_equal(9, a2.y)
|
144
|
+
|
145
|
+
assert_equal(1, a1.k1)
|
146
|
+
assert_equal(42, a1.k2)
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_reset_algebraic_flow_error
|
150
|
+
b = @world.create(B)
|
151
|
+
|
152
|
+
assert_equal(B::S1, b.state)
|
153
|
+
assert_equal(1, b.x)
|
154
|
+
|
155
|
+
@world.run 1
|
156
|
+
|
157
|
+
assert_equal(B::S2, b.state)
|
158
|
+
assert_equal(2, b.x)
|
159
|
+
end
|
160
|
+
|
161
|
+
# This is to test the expansion of the reset value cache.
|
162
|
+
def test_many_constant_resets
|
163
|
+
## need to get the limit as a const
|
164
|
+
n = World::CV_CACHE_SIZE + 10
|
165
|
+
cs = (0..n).map {|i| @world.create(C) {|c| c.kk = i}}
|
166
|
+
@world.run 1
|
167
|
+
cs.each do |c|
|
168
|
+
assert_equal(c.kk, c.k)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_reset_var_to_wrong_type
|
173
|
+
rl = @world.create(ResetVarToNonFloat)
|
174
|
+
assert_raises(VarTypeError) {@world.run 1}
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_reset_link
|
178
|
+
rl = @world.create(ResetLink)
|
179
|
+
assert_equal(nil, rl.lnk)
|
180
|
+
@world.run 1
|
181
|
+
assert_equal(C, rl.lnk.class)
|
182
|
+
assert_equal(1.337, rl.lnk.k)
|
183
|
+
end
|
184
|
+
|
185
|
+
def test_reset_link_to_nil
|
186
|
+
rl = @world.create(ResetLinkToNil)
|
187
|
+
assert_equal(nil, rl.lnk)
|
188
|
+
@world.run 1
|
189
|
+
assert_equal(nil, rl.lnk)
|
190
|
+
end
|
191
|
+
|
192
|
+
def test_reset_link_to_literal_nil
|
193
|
+
rl = @world.create(ResetLinkToLiteralNil)
|
194
|
+
assert_equal(nil, rl.lnk)
|
195
|
+
@world.run 1
|
196
|
+
assert_equal(nil, rl.lnk)
|
197
|
+
end
|
198
|
+
|
199
|
+
def test_reset_link_to_wrong_type
|
200
|
+
rl = @world.create(ResetLinkToWrongType)
|
201
|
+
assert_raises(LinkTypeError) {@world.run 1}
|
202
|
+
end
|
203
|
+
|
204
|
+
def test_reset_using_event_val
|
205
|
+
r = @world.create(Receiver) {|r| r.c = r.create(Emitter)}
|
206
|
+
@world.run 1
|
207
|
+
assert_equal(42.42, r.result)
|
208
|
+
end
|
209
|
+
end
|