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.
Files changed (107) hide show
  1. data/.gitignore +8 -0
  2. data/README +5 -0
  3. data/RELEASE-NOTES +455 -0
  4. data/TODO +431 -0
  5. data/bench/alg-state.rb +61 -0
  6. data/bench/bench +26 -0
  7. data/bench/bench.rb +10 -0
  8. data/bench/continuous.rb +76 -0
  9. data/bench/diff-bench +86 -0
  10. data/bench/discrete.rb +101 -0
  11. data/bench/euler.rb +50 -0
  12. data/bench/formula.rb +78 -0
  13. data/bench/half-strict.rb +103 -0
  14. data/bench/inertness.rb +116 -0
  15. data/bench/queue.rb +92 -0
  16. data/bench/run +66 -0
  17. data/bench/simple.rb +74 -0
  18. data/bench/strictness.rb +86 -0
  19. data/examples/ball-tkar.rb +72 -0
  20. data/examples/ball.rb +123 -0
  21. data/examples/collide.rb +70 -0
  22. data/examples/connect-parallel.rb +48 -0
  23. data/examples/connect.rb +109 -0
  24. data/examples/constants.rb +27 -0
  25. data/examples/delay.rb +80 -0
  26. data/examples/derivative.rb +77 -0
  27. data/examples/euler.rb +46 -0
  28. data/examples/external-lib.rb +33 -0
  29. data/examples/guard-debugger.rb +77 -0
  30. data/examples/lotka-volterra.rb +33 -0
  31. data/examples/persist-ball.rb +68 -0
  32. data/examples/pid.rb +87 -0
  33. data/examples/ports.rb +60 -0
  34. data/examples/queue.rb +56 -0
  35. data/examples/queue2.rb +98 -0
  36. data/examples/reset-with-event-val.rb +28 -0
  37. data/examples/scheduler.rb +104 -0
  38. data/examples/set-dest.rb +23 -0
  39. data/examples/simulink/README +1 -0
  40. data/examples/simulink/delay.mdl +827 -0
  41. data/examples/simulink/derivative.mdl +655 -0
  42. data/examples/step-discrete-profiler.rb +103 -0
  43. data/examples/subsystem.rb +109 -0
  44. data/examples/sync-deadlock.rb +32 -0
  45. data/examples/sync-queue.rb +91 -0
  46. data/examples/sync-retry.rb +20 -0
  47. data/examples/sync.rb +51 -0
  48. data/examples/thermostat.rb +53 -0
  49. data/examples/zeno.rb +53 -0
  50. data/lib/accessible-index.rb +47 -0
  51. data/lib/redshift.rb +1 -0
  52. data/lib/redshift/component.rb +412 -0
  53. data/lib/redshift/meta.rb +183 -0
  54. data/lib/redshift/mixins/zeno-debugger.rb +69 -0
  55. data/lib/redshift/port.rb +57 -0
  56. data/lib/redshift/queue.rb +104 -0
  57. data/lib/redshift/redshift.rb +111 -0
  58. data/lib/redshift/state.rb +31 -0
  59. data/lib/redshift/syntax.rb +558 -0
  60. data/lib/redshift/target/c.rb +37 -0
  61. data/lib/redshift/target/c/component-gen.rb +1303 -0
  62. data/lib/redshift/target/c/flow-gen.rb +325 -0
  63. data/lib/redshift/target/c/flow/algebraic.rb +85 -0
  64. data/lib/redshift/target/c/flow/buffer.rb +74 -0
  65. data/lib/redshift/target/c/flow/delay.rb +203 -0
  66. data/lib/redshift/target/c/flow/derivative.rb +101 -0
  67. data/lib/redshift/target/c/flow/euler.rb +67 -0
  68. data/lib/redshift/target/c/flow/expr.rb +113 -0
  69. data/lib/redshift/target/c/flow/rk4.rb +80 -0
  70. data/lib/redshift/target/c/library.rb +85 -0
  71. data/lib/redshift/target/c/world-gen.rb +1370 -0
  72. data/lib/redshift/target/spec.rb +34 -0
  73. data/lib/redshift/world.rb +300 -0
  74. data/rakefile +37 -0
  75. data/test/test.rb +52 -0
  76. data/test/test_buffer.rb +58 -0
  77. data/test/test_connect.rb +242 -0
  78. data/test/test_connect_parallel.rb +47 -0
  79. data/test/test_connect_strict.rb +135 -0
  80. data/test/test_constant.rb +74 -0
  81. data/test/test_delay.rb +145 -0
  82. data/test/test_derivative.rb +48 -0
  83. data/test/test_discrete.rb +592 -0
  84. data/test/test_discrete_isolated.rb +92 -0
  85. data/test/test_exit.rb +59 -0
  86. data/test/test_flow.rb +200 -0
  87. data/test/test_flow_link.rb +288 -0
  88. data/test/test_flow_sub.rb +100 -0
  89. data/test/test_flow_trans.rb +292 -0
  90. data/test/test_inherit.rb +127 -0
  91. data/test/test_inherit_event.rb +74 -0
  92. data/test/test_inherit_flow.rb +139 -0
  93. data/test/test_inherit_link.rb +65 -0
  94. data/test/test_inherit_setup.rb +56 -0
  95. data/test/test_inherit_state.rb +66 -0
  96. data/test/test_inherit_transition.rb +168 -0
  97. data/test/test_numerics.rb +34 -0
  98. data/test/test_queue.rb +90 -0
  99. data/test/test_queue_alone.rb +115 -0
  100. data/test/test_reset.rb +209 -0
  101. data/test/test_setup.rb +119 -0
  102. data/test/test_strict_continuity.rb +410 -0
  103. data/test/test_strict_reset_error.rb +30 -0
  104. data/test/test_strictness_error.rb +32 -0
  105. data/test/test_sync.rb +185 -0
  106. data/test/test_world.rb +328 -0
  107. metadata +204 -0
@@ -0,0 +1,77 @@
1
+ # Numerical differentiation.
2
+
3
+ # Compare with simulink/derivative.mdl -- note that redshift is more accurate
4
+ # because the derivative 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
+ flow do
12
+ diff " t' = 1 "
13
+
14
+ alg " u = sin(t) "
15
+ alg " sdu = cos(t) " # symbolic derivative
16
+ derive " ndu = u' ",# numerical derivative (can be (<expr>)' )
17
+ :feedback => false
18
+ diff " nindu' = ndu " # numerical integral of ndu
19
+ diff " niu' = u " # numerical integral of u
20
+ derive " ndniu = niu' ",# numerical derivative of niu
21
+ :feedback => false
22
+
23
+ alg " err = sdu - ndu "
24
+ # This error is small.
25
+
26
+ alg " e_ndni = ndniu - u "
27
+ alg " e_nind = nindu - u "
28
+ # The error is very small when numerically differentiating a signal that
29
+ # has been numerically integrated (e_ndni), but the error is worse
30
+ # for the integral of a differentiated signal (e_nind).
31
+ end
32
+
33
+ # Some alternative examples:
34
+ # alg " u = pow(t, 4) - 17*pow(t,3) + 102*pow(t,2) - 1300*t "
35
+ # alg " sdu = 4*pow(t, 3) - 3*17*pow(t,2) + 2*102*t - 1300 "
36
+ #
37
+ # continuous :u => 1, :nindu => 1, :ndniu =>1
38
+ # diff " u' = 0.02*u "
39
+ # alg " sdu = 0.02*exp(0.02*u) "
40
+ end
41
+
42
+ world = World.new
43
+ c = world.create(C)
44
+
45
+ u, sdu, ndu, nindu, err, e_ndni, e_nind = [], [], [], [], [], [], []
46
+ gather = proc do
47
+ time = c.t
48
+ u << [time, c.u]
49
+ sdu << [time, c.sdu]
50
+ ndu << [time, c.ndu]
51
+ nindu << [time, c.nindu]
52
+ err << [time, c.err]
53
+ e_ndni << [time, c.e_ndni]
54
+ e_nind << [time, c.e_nind]
55
+ end
56
+
57
+ gather.call
58
+ world.evolve 10 do
59
+ gather.call
60
+ end
61
+
62
+ require 'sci/plot'
63
+ include Plot::PlotUtils
64
+
65
+ gnuplot do |plot|
66
+ plot.command %{set title "Numerical differentiation"}
67
+ plot.command %{set xlabel "time"}
68
+ plot.add u, %{title "u" with lines}
69
+ plot.add sdu, %{title "sdu" with lines}
70
+ plot.add ndu, %{title "ndu" with lines}
71
+ plot.add nindu, %{title "nindu" with lines}
72
+ plot.add err, %{title "err" with lines}
73
+ plot.add e_ndni, %{title "e_ndni" with lines}
74
+ plot.add e_nind, %{title "e_nind" with lines}
75
+ end
76
+
77
+ sleep 1 if /mswin32|mingw32/ =~ RUBY_PLATFORM
data/examples/euler.rb ADDED
@@ -0,0 +1,46 @@
1
+ require 'redshift'
2
+
3
+ include RedShift
4
+
5
+ class Flow_Euler < Component
6
+ flow do
7
+ euler "x' = 1"
8
+ euler "y_euler' = x" # y is a worse approx of z, due to Euler
9
+ diff " y_rk4' = x"
10
+ alg " y_true = 0.5 * pow(x,2)" # the true value
11
+ end
12
+ end
13
+
14
+ world = World.new
15
+ c = world.create(Flow_Euler)
16
+
17
+
18
+ x, y_euler, y_rk4, y_true, rk4_err, euler_err = [], [], [], [], [], []
19
+ gather = proc do
20
+ time = world.clock
21
+ x << [time, c.x]
22
+ y_euler << [time, c.y_euler]
23
+ y_rk4 << [time, c.y_rk4]
24
+ y_true << [time, c.y_true]
25
+ rk4_err << [time, (c.y_rk4 - c.y_true).abs]
26
+ euler_err << [time, (c.y_euler - c.y_true).abs]
27
+ end
28
+
29
+ gather.call
30
+ world.evolve 10 do
31
+ gather.call
32
+ end
33
+
34
+ require 'sci/plot'
35
+ include Plot::PlotUtils
36
+
37
+ gnuplot do |plot|
38
+ plot.command %{set title "Euler Integration"}
39
+ plot.command %{set xlabel "time"}
40
+ plot.add x, %{title "x" with lines}
41
+ plot.add y_true, %{title "y_true" with lp}
42
+ plot.add y_rk4, %{title "y_rk4" with lp}
43
+ plot.add y_euler, %{title "y_euler" with lp}
44
+ plot.add rk4_err, %{title "rk4_err" with lp}
45
+ plot.add euler_err, %{title "euler_err" with lp}
46
+ end
@@ -0,0 +1,33 @@
1
+ # Example of using an external C lib with redshift. Note that
2
+ # <math.h> is included and -lm is linked by default.
3
+
4
+ require 'redshift'
5
+
6
+ RedShift.with_library do |library|
7
+ library.include_file.include "<gsl/gsl_sf_gamma.h>"
8
+ library.include_file.include "<gsl/gsl_math.h>"
9
+ library.include_file.include "<gsl/gsl_const_mksa.h>"
10
+ library.link_with "-lgsl"
11
+ library.declare_external_constant "GSL_CONST_MKSA_MASS_ELECTRON"
12
+
13
+ # If you need custom cflags, you can put them here:
14
+ # $CFLAGS = "-fPIC -O2 -march=i686 -msse2 -mfpmath=sse"
15
+ end
16
+
17
+ class C < RedShift::Component
18
+ continuous :x, :y
19
+
20
+ flow do
21
+ diff " y' = 2 + GSL_CONST_MKSA_MASS_ELECTRON "
22
+ end
23
+
24
+ transition Enter => Exit do
25
+ guard " gsl_fcmp(y, 1.0, 0.01) == 0 "
26
+ reset :x => "gsl_sf_taylorcoeff(3, 2)"
27
+ end
28
+ end
29
+
30
+ w = RedShift::World.new
31
+ c = w.create C
32
+ w.evolve 1
33
+ p c.x, c.y
@@ -0,0 +1,77 @@
1
+ require 'redshift'
2
+
3
+ include RedShift
4
+
5
+ # This example is a simple debugger for stepping through guards. It's not
6
+ # intended to be useful as a debugger, but to show how hook methods can be
7
+ # used to develop debuggers.
8
+ #
9
+ # See examples/step-discrete-hook.rb for more examples of hook methods.
10
+ #
11
+ # See mixins/debugger.rb and examples/debugger.rb for a more useful debugger.
12
+
13
+ class DebuggingWorld < World
14
+ def hook_eval_guard(comp, guard, enabled, trans, dest)
15
+ puts "%-30p %-30p %-8s %6d" %
16
+ [comp, guard, enabled ? "enabled" : nil, discrete_step]
17
+ if enabled and dest != comp.state
18
+ puts "%-30s %-30s %-s" % [nil, nil, "#{comp.state} => #{dest}"]
19
+ end
20
+ puts "press <enter> to continue"
21
+ gets
22
+ end
23
+
24
+ def hook_begin
25
+ puts "-"*60
26
+ puts "Begin discrete update in #{inspect}"
27
+ puts "press <enter> to continue, ^C at any time to stop"
28
+ puts "%-30s %-30s %-8s %6s" %
29
+ %w(component guard status step)
30
+ gets
31
+ end
32
+
33
+ def hook_end
34
+ puts "End discrete update in #{inspect}"
35
+ puts "press <enter> to continue"
36
+ gets
37
+ end
38
+ end
39
+
40
+ class Thing < Component
41
+ state :A, :B
42
+ start A
43
+
44
+ continuous :x
45
+ flow A do
46
+ diff "x' = 1"
47
+ end
48
+
49
+ transition A => B do
50
+ guard "x > 2"
51
+ end
52
+
53
+ transition B => A do
54
+ guard "x < 1e-10"
55
+ reset :x => 0
56
+ end
57
+
58
+ transition B => B do
59
+ guard "x >= 1e-10"
60
+ reset :x => "x-1"
61
+ end
62
+ end
63
+
64
+ w = DebuggingWorld.new
65
+
66
+ w.create(Thing) do |th|
67
+ th.name = 1
68
+ th.x = 0.5
69
+ end
70
+
71
+ w.create(Thing) do |th|
72
+ th.name = 2
73
+ th.x = 5
74
+ th.start Thing::B
75
+ end
76
+
77
+ w.evolve 100
@@ -0,0 +1,33 @@
1
+ require 'redshift'
2
+
3
+ class Population < RedShift::Component
4
+ flow do
5
+ diff " rabbits' = 0.3*rabbits - 0.02 * rabbits * foxes "
6
+ diff " foxes' = 0.01*foxes*rabbits - 0.5 * foxes "
7
+ end
8
+ end
9
+
10
+ world = RedShift::World.new do |w|
11
+ w.time_step = 0.05
12
+ end
13
+
14
+ pop = world.create Population
15
+ pop.foxes = 2
16
+ pop.rabbits = 100
17
+
18
+ data = []
19
+ world.evolve 100 do |w|
20
+ data << [w.clock, pop.foxes, pop.rabbits]
21
+ end
22
+
23
+ require 'sci/plot'
24
+ include Plot::PlotUtils
25
+
26
+ gnuplot do |plot|
27
+ plot.command %{set title "Lotla-Volterra"}
28
+ plot.command %{set xlabel "time"}
29
+ plot.add data, %{using 1:2 title "foxes" with lines}
30
+ plot.add data, %{using 1:3 title "rabbits" with lines}
31
+ end
32
+
33
+ sleep 1 if /mswin32|mingw32/ =~ RUBY_PLATFORM
@@ -0,0 +1,68 @@
1
+ require 'redshift'
2
+ require 'plot/plot'
3
+ require 'nr/random'
4
+
5
+ include RedShift
6
+ include NR::Random
7
+ include Math
8
+
9
+
10
+ class Ball < Component
11
+
12
+ flow {
13
+ euler " x' = @vx "
14
+ euler " y' = @vy "
15
+ }
16
+
17
+ defaults {
18
+ @x = 0
19
+ @y = 0
20
+ }
21
+
22
+ end
23
+
24
+ world = World.open "ball.world"
25
+
26
+ unless world
27
+
28
+ world = World.new {time_step 0.01}
29
+
30
+ seq = UniformSequence.new :min => 0, :max => 2*PI
31
+
32
+ 5.times do
33
+ world.create(Ball) {
34
+ angle = seq.next
35
+ @vx = cos angle
36
+ @vy = sin angle
37
+ }
38
+ end
39
+
40
+ end
41
+
42
+ balls = world.select { |c| c.type == Ball }
43
+
44
+ data = {}
45
+ for b in balls
46
+ data[b] = [[b.x, b.y]]
47
+ end
48
+
49
+ 50.times do
50
+ world.run
51
+ for b in balls
52
+ data[b] << [b.x, b.y]
53
+ end
54
+ end
55
+
56
+ Plot.new ('gnuplot') {
57
+
58
+ command 'set xrange [ -2 : 2 ]; set yrange [ -2 : 2 ]'
59
+
60
+ for b in balls
61
+ add data[b], "title \"#{balls.index(b)}\" with lines"
62
+ end
63
+
64
+ show
65
+ pause 5
66
+ }
67
+
68
+ world.save "ball.world"
data/examples/pid.rb ADDED
@@ -0,0 +1,87 @@
1
+ # PID control example
2
+ # See http://en.wikipedia.org/wiki/PID_control.
3
+
4
+ require 'redshift'
5
+ include RedShift
6
+
7
+ srand(12345)
8
+
9
+ # Variable with discrete and continuous perturbation.
10
+ class Plant < Component
11
+ continuous :x => 0, :t => 1
12
+
13
+ link :control => :Control # fwd ref to undefined class Control
14
+
15
+ flow do
16
+ diff " x' = control.output + sin(t) "
17
+ diff " t' = -1 "
18
+ end
19
+
20
+ transition do
21
+ guard "t <= 0"
22
+ action do
23
+ self.t += rand * 20
24
+ self.x += (rand - 0.5) * 10
25
+ end
26
+ end
27
+ end
28
+
29
+ # Tries to bring x back to the set_point.
30
+ class Control < Component
31
+ continuous :set_point => 2.0
32
+ continuous :p_out, :i_out, :d_out, :output
33
+
34
+ # Gains
35
+ constant :k_p => 1.0,
36
+ :k_i => 1.0,
37
+ :k_d => 1.0
38
+
39
+ link :plant => Plant
40
+
41
+ flow do
42
+ algebraic " error = set_point - plant.x "
43
+ algebraic " p_out = k_p * error "
44
+ differential " i_out' = k_i * error "
45
+ algebraic " d_out = k_d * (- sin(plant.t)) "
46
+ # since in plant we have x' = control.output + sin(t)
47
+ # and we can algebraically remove the "output" term.
48
+ # this is a special case that doesn't need numerical differentiation
49
+ algebraic " output = p_out + i_out + d_out "
50
+ end
51
+ end
52
+
53
+ world = World.new
54
+ plant = world.create Plant
55
+ control = world.create Control
56
+ control.plant = plant
57
+ plant.control = control
58
+
59
+ x, p_out, i_out, d_out, output = [], [], [], [], []
60
+ gather = proc do
61
+ time = world.clock
62
+ x << [time, plant.x]
63
+ p_out << [time, control.p_out]
64
+ i_out << [time, control.i_out]
65
+ d_out << [time, control.d_out]
66
+ output << [time, control.output]
67
+ end
68
+
69
+ gather.call
70
+ world.evolve 1000 do
71
+ gather.call
72
+ end
73
+
74
+ require 'sci/plot'
75
+ include Plot::PlotUtils
76
+
77
+ gnuplot do |plot|
78
+ plot.command %{set title "PID control"}
79
+ plot.command %{set xlabel "time"}
80
+ plot.add x, %{title "x" with lines}
81
+ plot.add p_out, %{title "p_out" with lines}
82
+ plot.add i_out, %{title "i_out" with lines}
83
+ plot.add d_out, %{title "d_out" with lines}
84
+ plot.add output, %{title "output" with lines}
85
+ end
86
+
87
+ sleep 1 if /mswin32|mingw32/ =~ RUBY_PLATFORM
data/examples/ports.rb ADDED
@@ -0,0 +1,60 @@
1
+ # Shows how to use the port abstraction to refer to ports independently of the
2
+ # components (and classes) they are attached to.
3
+
4
+ require 'redshift'
5
+ include RedShift
6
+
7
+ class I < Component
8
+ flow do
9
+ diff " x' = -x "
10
+ end
11
+ end
12
+
13
+ class A < Component
14
+ flow do
15
+ diff " t' = 1 "
16
+ alg " x = cos(t) "
17
+ end
18
+ end
19
+
20
+ class K < Component
21
+ constant :x => 5.678
22
+ end
23
+
24
+ class W < Component
25
+ input :x
26
+ setup do
27
+ port(:x) << create(I).port(:x)
28
+ end
29
+ end
30
+
31
+ class L < Component
32
+ link :i => I
33
+ setup do
34
+ self.i = create(I)
35
+ end
36
+ flow do
37
+ alg " x = i.x "
38
+ end
39
+ end
40
+
41
+ class Tester < Component
42
+ input :x
43
+ end
44
+
45
+ w = World.new
46
+
47
+ comps = [I, A, K, W, L].map {|cl| w.create(cl)}
48
+ ports = comps.map {|comp| comp.port(:x)}
49
+ values = ports.map {|port| port.value}
50
+
51
+ p values # ==> [0.0, 1.0, 5.678, 0.0, 0.0]
52
+
53
+ tester = w.create(Tester)
54
+ values = ports.map do |port|
55
+ tester.port(:x) << port
56
+ tester.x
57
+ end
58
+
59
+ p values # same as above
60
+