redshift 1.3.15

Sign up to get free protection for your applications and to get access to all the features.
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
+