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,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
|