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
data/examples/ball.rb
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'redshift'
|
2
|
+
|
3
|
+
include RedShift
|
4
|
+
|
5
|
+
class Observer < Component
|
6
|
+
link :ball => :Ball
|
7
|
+
state :Observing, :Decision
|
8
|
+
attr_reader :counter
|
9
|
+
|
10
|
+
setup do
|
11
|
+
@counter = 0
|
12
|
+
end
|
13
|
+
|
14
|
+
start Observing
|
15
|
+
|
16
|
+
transition Observing => Decision do
|
17
|
+
sync :ball => :impact
|
18
|
+
action do
|
19
|
+
print "\n\n ***** Time of impact #{world.clock}.\n\n"
|
20
|
+
@counter += 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
transition Decision => Exit do
|
25
|
+
guard {@counter == 2}
|
26
|
+
action {print " ***** Observer leaving after 2 bounces.\n\n"}
|
27
|
+
end
|
28
|
+
|
29
|
+
transition Decision => Observing do
|
30
|
+
guard {@counter < 2}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Ball < Component
|
35
|
+
constant :y0, :v0, :a, :bounce_count
|
36
|
+
state :Falling, :Rising
|
37
|
+
|
38
|
+
flow Falling, Rising do
|
39
|
+
differential " y' = v "
|
40
|
+
euler " v' = a "
|
41
|
+
|
42
|
+
euler " t_elapsed' = 1.0 "
|
43
|
+
algebraic " true_y = y0 + v0 * t_elapsed +
|
44
|
+
0.5 * a * pow(t_elapsed, 2) "
|
45
|
+
algebraic " y_err = fabs(true_y - y) "
|
46
|
+
end
|
47
|
+
|
48
|
+
transition Falling => Rising do
|
49
|
+
guard "y <= 0"
|
50
|
+
event :impact
|
51
|
+
reset :v => "-v",
|
52
|
+
:y0 => "y",
|
53
|
+
:v0 => "-v",
|
54
|
+
:t_elapsed => 0,
|
55
|
+
:bounce_count => "bounce_count + 1"
|
56
|
+
# The reset is essentially the same as:
|
57
|
+
# action {
|
58
|
+
# self.v = -v
|
59
|
+
# self.y0 = y; self.v0 = v
|
60
|
+
# self.t_elapsed = 0.0
|
61
|
+
# self.bounce_count += 1
|
62
|
+
# }
|
63
|
+
# The difference: reset is faster, and has parallel semantics,
|
64
|
+
# which is why ':v0 => "-v"', in place of 'self.v0 = v'.
|
65
|
+
end
|
66
|
+
|
67
|
+
transition Rising => Falling do
|
68
|
+
guard "v <= 0"
|
69
|
+
end
|
70
|
+
|
71
|
+
transition Rising => Exit, Falling => Exit do
|
72
|
+
guard "bounce_count >= 3"
|
73
|
+
end
|
74
|
+
|
75
|
+
defaults {
|
76
|
+
start Falling
|
77
|
+
self.y0 = 100.0
|
78
|
+
self.v0 = 0.0
|
79
|
+
self.a = -9.8
|
80
|
+
}
|
81
|
+
|
82
|
+
setup {
|
83
|
+
self.y = y0; self.v = v0
|
84
|
+
self.t_elapsed = 0.0
|
85
|
+
self.bounce_count = 0
|
86
|
+
}
|
87
|
+
|
88
|
+
def inspect
|
89
|
+
sprintf "y = %8.4f, v = %8.4f, y_err = %8.6f%16s",
|
90
|
+
y, v, y_err, state
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
w = World.new
|
95
|
+
w.time_step = 0.01
|
96
|
+
|
97
|
+
ball = w.create(Ball) {|b| b.a = -9.8}
|
98
|
+
w.create(Observer) {|o|o.ball = ball}
|
99
|
+
|
100
|
+
y = [[w.clock, ball.y]]
|
101
|
+
|
102
|
+
while w.size > 0 do
|
103
|
+
t = w.clock
|
104
|
+
if t == t.floor
|
105
|
+
print "\nTime #{t}\n"
|
106
|
+
end
|
107
|
+
p ball unless ball.state == Exit
|
108
|
+
|
109
|
+
w.run
|
110
|
+
|
111
|
+
y << [w.clock, ball.y]
|
112
|
+
end
|
113
|
+
|
114
|
+
if ARGV.delete('-p')
|
115
|
+
require 'sci/plot'
|
116
|
+
include Plot::PlotUtils
|
117
|
+
|
118
|
+
gnuplot do |plot|
|
119
|
+
plot.add y, 'title "height" with lines'
|
120
|
+
end
|
121
|
+
else
|
122
|
+
puts "use -p switch to show plot"
|
123
|
+
end
|
data/examples/collide.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# Example of using sync and events to exchange data in parallel. This assumes that
|
2
|
+
# the two components are already linked, so it doesn't scale well. A scalable
|
3
|
+
# solution would separate detection into a cell mechanism or something, and use
|
4
|
+
# queues to notify the components. This example is more about collision _handling_
|
5
|
+
# than _detection_.
|
6
|
+
|
7
|
+
require 'redshift'
|
8
|
+
|
9
|
+
class Ball < RedShift::Component
|
10
|
+
link :other => Ball
|
11
|
+
continuous :v
|
12
|
+
constant :dir
|
13
|
+
|
14
|
+
state :Moving
|
15
|
+
|
16
|
+
transition Enter => Moving do
|
17
|
+
action do
|
18
|
+
self.dir = other.x < x ? -1 : 1
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
flow Moving do
|
23
|
+
diff " x' = v "
|
24
|
+
end
|
25
|
+
|
26
|
+
transition Moving => Moving do
|
27
|
+
guard " dir * (other.x - x) < 0 "
|
28
|
+
guard {other.other == self}
|
29
|
+
# meaning: only if other is colliding with self
|
30
|
+
# The guard above is a bit unnecessary in this model,
|
31
|
+
# but in general it is needed.
|
32
|
+
sync :other => :collision
|
33
|
+
event :collision
|
34
|
+
reset :v => "other.v", :x => "other.x"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
w = RedShift::World.new
|
39
|
+
b1 = w.create Ball
|
40
|
+
b2 = w.create Ball
|
41
|
+
b1.other = b2
|
42
|
+
b2.other = b1
|
43
|
+
b1.x = 0.0
|
44
|
+
b1.v = 30.0
|
45
|
+
b2.x = 100.0
|
46
|
+
b2.v = -70.0
|
47
|
+
|
48
|
+
b1_x, b2_x = [], []
|
49
|
+
gather = proc do
|
50
|
+
time = w.clock
|
51
|
+
b1_x << [time, b1.x]
|
52
|
+
b2_x << [time, b2.x]
|
53
|
+
end
|
54
|
+
|
55
|
+
gather.call
|
56
|
+
w.evolve 1.2 do
|
57
|
+
gather.call
|
58
|
+
end
|
59
|
+
|
60
|
+
require 'sci/plot'
|
61
|
+
include Plot::PlotUtils
|
62
|
+
|
63
|
+
gnuplot do |plot|
|
64
|
+
plot.command %{set title "Bouncing balls"}
|
65
|
+
plot.command %{set xlabel "time"}
|
66
|
+
plot.add b1_x, %{title "b1.x" with lines}
|
67
|
+
plot.add b2_x, %{title "b2.x" with lines}
|
68
|
+
end
|
69
|
+
|
70
|
+
sleep 1 if /mswin32|mingw32/ =~ RUBY_PLATFORM
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# Shows how to connect input variables in parallel, and also in
|
2
|
+
# parallel with resets.
|
3
|
+
|
4
|
+
require "redshift"
|
5
|
+
include RedShift
|
6
|
+
|
7
|
+
class A < Component
|
8
|
+
input :in
|
9
|
+
continuous :x => 1
|
10
|
+
constant :k => 1
|
11
|
+
link :comp
|
12
|
+
|
13
|
+
state :T
|
14
|
+
|
15
|
+
flow T do
|
16
|
+
diff " x' = k*in "
|
17
|
+
end
|
18
|
+
|
19
|
+
transition Enter => T do
|
20
|
+
reset :comp => nil # in parallel with the connect
|
21
|
+
if true
|
22
|
+
connect :in => proc {comp.port(:x)}
|
23
|
+
# alternate syntaxes:
|
24
|
+
# connect port(:in).to {comp.port(:x)}
|
25
|
+
# port(:in).connect {comp.port(:x)}
|
26
|
+
# connect { in {comp.port :x}; ... }
|
27
|
+
else
|
28
|
+
connect :in => [:comp, :x] # special case: literals
|
29
|
+
end
|
30
|
+
|
31
|
+
# The non-parallel equivalent, which would fail after
|
32
|
+
# resetting comp to nil:
|
33
|
+
#
|
34
|
+
# action do
|
35
|
+
# port(:in) << comp.port(:x)
|
36
|
+
# end
|
37
|
+
## actually this would fail as a post, but not as action
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
w = World.new
|
42
|
+
w.time_step = 0.001
|
43
|
+
a0, a1 = (0..1).map {w.create(A)}
|
44
|
+
a0.comp = a1
|
45
|
+
a1.comp = a0
|
46
|
+
|
47
|
+
w.evolve 1
|
48
|
+
p a0, a1
|
data/examples/connect.rb
ADDED
@@ -0,0 +1,109 @@
|
|
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
|
+
end
|
15
|
+
|
16
|
+
world = World.new
|
17
|
+
|
18
|
+
a = world.create(A)
|
19
|
+
b = world.create(B)
|
20
|
+
|
21
|
+
begin
|
22
|
+
b.y
|
23
|
+
rescue RedShift::UnconnectedInputError => ex
|
24
|
+
puts "As expected: #{ex}"
|
25
|
+
end
|
26
|
+
|
27
|
+
b.connect(:y, a, :x)
|
28
|
+
# doesn't construct Port objects, so slightly more efficent
|
29
|
+
p(b.port(:y) << a.port(:x)) # Port#<< is alias for Port#connect
|
30
|
+
|
31
|
+
begin
|
32
|
+
a.port(:x) << b.port(:y)
|
33
|
+
rescue TypeError => ex
|
34
|
+
puts "As expected: #{ex}"
|
35
|
+
end
|
36
|
+
|
37
|
+
begin
|
38
|
+
b.y = 1.23 # error
|
39
|
+
rescue NoMethodError => ex
|
40
|
+
puts "As expected: #{ex}"
|
41
|
+
end
|
42
|
+
|
43
|
+
a.x = 4.56
|
44
|
+
p b.y # ok
|
45
|
+
p b
|
46
|
+
|
47
|
+
p b.port(:y).source == a.port(:x) # true
|
48
|
+
p b.port(:y).source_component # a
|
49
|
+
p b.port(:y).source_variable # :x
|
50
|
+
|
51
|
+
p a.port(:x).component # a
|
52
|
+
p a.port(:x).variable # :x
|
53
|
+
|
54
|
+
b.disconnect :y
|
55
|
+
b.port(:y).disconnect # same
|
56
|
+
b.port(:y) << nil # same
|
57
|
+
|
58
|
+
begin
|
59
|
+
b.y
|
60
|
+
rescue RedShift::UnconnectedInputError => ex
|
61
|
+
puts "As expected: #{ex}"
|
62
|
+
end
|
63
|
+
|
64
|
+
p A.offset_table
|
65
|
+
p B.offset_table
|
66
|
+
|
67
|
+
b.port(:y) << a.port(:x)
|
68
|
+
world.evolve 1 do
|
69
|
+
p [a.x, b.y]
|
70
|
+
end
|
71
|
+
|
72
|
+
b.port(:y) << a.port(:k) # reconnect, but this time to a constant
|
73
|
+
world.evolve 0.5 do
|
74
|
+
p [a.k, b.y]
|
75
|
+
end
|
76
|
+
|
77
|
+
puts <<END
|
78
|
+
|
79
|
+
This example shows four things:
|
80
|
+
|
81
|
+
1. you can connect an input to an input (b1 to b2, and b2 to b3).
|
82
|
+
2. >> as an alternative to <<
|
83
|
+
3. chaining >> (or <<)
|
84
|
+
4. two input ports connected to the same var (b1 and b4 conn to a)
|
85
|
+
|
86
|
+
END
|
87
|
+
|
88
|
+
b1 = world.create(B)
|
89
|
+
b2 = world.create(B)
|
90
|
+
b3 = world.create(B)
|
91
|
+
b4 = world.create(B)
|
92
|
+
|
93
|
+
a.port(:x) >> b4.port(:y)
|
94
|
+
a.port(:x) >> b1.port(:y) >> b2.port(:y) >> b3.port(:y)
|
95
|
+
|
96
|
+
a.x = 3
|
97
|
+
p b3.y
|
98
|
+
|
99
|
+
puts <<END
|
100
|
+
|
101
|
+
This example shows that connections are treated dynamically, not statically.
|
102
|
+
Changing an upstream connection during a run affects all downstream vars.
|
103
|
+
|
104
|
+
END
|
105
|
+
|
106
|
+
a2 = world.create(A)
|
107
|
+
a2.x = 4
|
108
|
+
a2.port(:x) >> b1.port(:y)
|
109
|
+
p b2.y
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Overview of the different kinds of "constants" in redshift.
|
2
|
+
#
|
3
|
+
# 1. constants defined in a ruby module
|
4
|
+
#
|
5
|
+
# 2. constants defined in an external library -- see external-lib.rb
|
6
|
+
#
|
7
|
+
# 3. per component constant _functions_ (strict or piecewise).
|
8
|
+
|
9
|
+
require 'redshift'
|
10
|
+
|
11
|
+
RedShift.with_library do |library|
|
12
|
+
library.declare_external_constant "M_E" # GNU C math lib
|
13
|
+
end
|
14
|
+
|
15
|
+
class C < RedShift::Component
|
16
|
+
K = 10
|
17
|
+
L = 456
|
18
|
+
constant :kk => 2 # per instance, and can change discretely
|
19
|
+
|
20
|
+
flow do
|
21
|
+
alg "x = kk*K + #{L*1000} + M_E"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
w = RedShift::World.new
|
26
|
+
c = w.create C
|
27
|
+
p c.x
|
data/examples/delay.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# Delay of a continuous signal by a given time.
|
2
|
+
|
3
|
+
# Compare with simulink/delay.mdl -- note that redshift is more accurate
|
4
|
+
# because the delay flow operates at all integrator steps, not just at
|
5
|
+
# the simulation timesteps.
|
6
|
+
|
7
|
+
require 'redshift'
|
8
|
+
include RedShift
|
9
|
+
|
10
|
+
class C < Component
|
11
|
+
constant :pi => Math::PI
|
12
|
+
constant :d => 0.3
|
13
|
+
|
14
|
+
state :A, :B
|
15
|
+
start A
|
16
|
+
|
17
|
+
flow A, B do
|
18
|
+
diff " t' = 1 "
|
19
|
+
alg " u = sin(t*pi/2) "
|
20
|
+
alg " shift_u = sin((t-d)*pi/2) " # u shifted by d
|
21
|
+
delay " delay_u = u ", # delayed output from u (can be any expr)
|
22
|
+
:by => "d" # delayed by d (can be any expr)
|
23
|
+
alg " err = shift_u - delay_u "
|
24
|
+
|
25
|
+
# Check how delay interacts with integration:
|
26
|
+
diff " idu' = delay_u "
|
27
|
+
diff " iu' = u"
|
28
|
+
delay " diu = iu ", :by => "d"
|
29
|
+
alg "iddi_err = idu - diu"
|
30
|
+
end
|
31
|
+
|
32
|
+
constant :new_d => 0.5 # change this to see how varying delay works
|
33
|
+
constant :t_new_d => 5.0
|
34
|
+
transition A => B do
|
35
|
+
guard "t >= t_new_d"
|
36
|
+
reset :d => "new_d"
|
37
|
+
end
|
38
|
+
# Note that the buffered u values are preserved in the transition
|
39
|
+
end
|
40
|
+
|
41
|
+
world = World.new
|
42
|
+
world.time_step = 0.1
|
43
|
+
c = world.create(C)
|
44
|
+
|
45
|
+
u, shift_u, delay_u, err, iddi_err = [], [], [], [], []
|
46
|
+
gather = proc do
|
47
|
+
time = c.t
|
48
|
+
u << [time, c.u]
|
49
|
+
shift_u << [time, c.shift_u]
|
50
|
+
delay_u << [time, c.delay_u]
|
51
|
+
err << [time, c.err]
|
52
|
+
iddi_err<< [time, c.iddi_err]
|
53
|
+
end
|
54
|
+
|
55
|
+
gather.call
|
56
|
+
world.evolve 10 do
|
57
|
+
gather.call
|
58
|
+
end
|
59
|
+
|
60
|
+
# The buffer used to store u's history is available:
|
61
|
+
if false
|
62
|
+
p c.delay_u_buffer_data
|
63
|
+
p c.delay_u_buffer_offset
|
64
|
+
p c.delay_u_delay
|
65
|
+
end
|
66
|
+
|
67
|
+
require 'sci/plot'
|
68
|
+
include Plot::PlotUtils
|
69
|
+
|
70
|
+
gnuplot do |plot|
|
71
|
+
plot.command %{set title "Time delay"}
|
72
|
+
plot.command %{set xlabel "time"}
|
73
|
+
plot.add u, %{title "u" with lines}
|
74
|
+
plot.add shift_u, %{title "shift_u" with lines}
|
75
|
+
plot.add delay_u, %{title "delay_u" with lines}
|
76
|
+
plot.add err, %{title "err" with lines}
|
77
|
+
plot.add iddi_err, %{title "iddi_err" with lines}
|
78
|
+
end
|
79
|
+
|
80
|
+
sleep 1 if /mswin32|mingw32/ =~ RUBY_PLATFORM
|