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,116 @@
1
+ require 'redshift'
2
+ require 'enumerator'
3
+
4
+ include RedShift
5
+
6
+ module Inertness
7
+ class Inert < Component
8
+ # An inert component is one that has no transitions out of its
9
+ # current state. However, flows are allowed. But for a sharper
10
+ # comparison, we don't define any.
11
+ #
12
+ # flow do
13
+ # diff " t' = 1 "
14
+ # end
15
+
16
+ # Adding just one trivial transition prevents the inert optimization,
17
+ # with dramatic effects (increase of 60% cpu time in first case).
18
+ #
19
+ # 1000 comps X 10000 steps X 0 non-inert: +0.60
20
+ # 1000 comps X 10000 steps X 1 non-inert: +0.59
21
+ #
22
+ # transition Enter => Exit do
23
+ # guard "0"
24
+ # end
25
+ #
26
+ # Turning off the inert optimization in the world source, without adding
27
+ # a transition, is a bit less dramatic, but a more realistic indicator
28
+ # of the value of the optimization:
29
+ #
30
+ # 1000 comps X 10000 steps X 0 non-inert: +0.39
31
+ # 1000 comps X 10000 steps X 1 non-inert: +0.36
32
+ end
33
+
34
+ class NonInert < Component
35
+ n_states = 10
36
+ # increasing this doesn't make the difference (w/ and w/o the inert
37
+ # optimization) larger because the inerts go on strict sleep anyway.
38
+ my_states = state((0...n_states).map {|i| "S#{i}"})
39
+ start S0
40
+ flow S0 do
41
+ diff " t' = 1 "
42
+ end
43
+ transition S0 => S1 do
44
+ guard " t >= 0.1 "
45
+ reset :t => 0
46
+ end
47
+ my_states[1..-1].each_cons(2) do |s, t|
48
+ transition s => t
49
+ end
50
+ transition my_states.last => my_states.first
51
+ end
52
+
53
+ def self.make_world n_inert, n_non_inert=0
54
+ w = World.new
55
+ n_inert.times {w.create(Inert)}
56
+ n_non_inert.times {w.create(NonInert)}
57
+ w
58
+ end
59
+
60
+ def self.do_bench
61
+ [0, 1].each do |n_non_inert|
62
+ [ [ 0, 10_000],
63
+ [ 1000, 10_000] ].each do
64
+ | n_inert, n_s|
65
+
66
+ w = make_world(n_inert, n_non_inert)
67
+ w.run 1 # warm up
68
+ r = bench do
69
+ w.run(n_s)
70
+ end
71
+
72
+ yield " - %10d comps X %10d steps X %10d non-inert: %8.2f" %
73
+ [n_inert, n_s, n_non_inert, r]
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ if __FILE__ == $0
80
+
81
+ require File.join(File.dirname(__FILE__), 'bench')
82
+ puts "inert:"
83
+ Inertness.do_bench {|l| puts l}
84
+
85
+ exit
86
+
87
+ n_inert = 10000
88
+ n_non_inert = 0
89
+ n_steps = 1000
90
+
91
+
92
+ times = Process.times
93
+ t0 = Time.now
94
+ pt0 = times.utime #+ times.stime
95
+
96
+ w.run n_steps
97
+
98
+ times = Process.times
99
+ t1 = Time.now
100
+ pt1 = times.utime #+ times.stime
101
+ puts "process time: %8.2f" % (pt1-pt0)
102
+ puts "elapsed time: %8.2f" % (t1-t0)
103
+
104
+ end
105
+
106
+ __END__
107
+
108
+ The best case so far is:
109
+
110
+ without inert optimization
111
+ process time: 6.58
112
+ elapsed time: 6.59
113
+
114
+ with inert optimization
115
+ process time: 5.11
116
+ elapsed time: 5.12
data/bench/queue.rb ADDED
@@ -0,0 +1,92 @@
1
+ # Measures performance of redshift queues.
2
+
3
+ require 'redshift'
4
+
5
+ module Queue
6
+ class Clock < RedShift::Component
7
+ # the only continuous var in the whole system
8
+ strictly_continuous :time
9
+ flow {
10
+ diff " time' = 1 "
11
+ }
12
+ end
13
+
14
+ class Sender < RedShift::Component
15
+ strict_link :clock => Clock
16
+
17
+ constant :next_wakeup
18
+ strictly_constant :period
19
+
20
+ # list of target queues that this comp will send to
21
+ def targets
22
+ @targets ||= []
23
+ end
24
+
25
+ setup do
26
+ self.next_wakeup = period
27
+ end
28
+
29
+ transition do
30
+ guard " clock.time >= next_wakeup "
31
+ reset :next_wakeup => " clock.time + period "
32
+ action do
33
+ targets.each do |target|
34
+ target << :awake
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ class Receiver < RedShift::Component
41
+ queue :q
42
+ transition do
43
+ wait :q
44
+ action do
45
+ q.pop
46
+ end
47
+ end
48
+ end
49
+
50
+ def self.make_world n_sender=1, n_receiver=0
51
+ w = RedShift::World.new
52
+ clock = w.create(Clock)
53
+ n_sender.times do |i|
54
+ sender = w.create(Sender) do |s|
55
+ s.clock = clock
56
+ s.next_wakeup = ((i % 99)+1) / 10.0
57
+ s.period = 10
58
+ n_receiver.times do
59
+ w.create(Receiver) do |r|
60
+ s.targets << r.q
61
+ end
62
+ end
63
+ end
64
+ end
65
+ w
66
+ end
67
+
68
+ def self.do_bench
69
+ [1, 10, 100].each do |n_r|
70
+ [1, 10, 100].each do |n_s|
71
+ n_steps = 100_000 / (n_r * n_s)
72
+ do_bench_one(n_s, n_steps, n_r) {|r| yield r}
73
+ end
74
+ end
75
+ end
76
+
77
+ def self.do_bench_one(n_s, n_steps, n_r)
78
+ w = make_world(n_s, n_r)
79
+ r = bench do
80
+ w.run(n_steps)
81
+ end
82
+
83
+ yield " - %10d senders X %10d steps X %5d receivers: %8.2f" %
84
+ [n_s, n_steps, n_r, r]
85
+ end
86
+ end
87
+
88
+ if __FILE__ == $0
89
+ require File.join(File.dirname(__FILE__), 'bench')
90
+ puts "queue:"
91
+ Queue.do_bench_one(*ARGV.map{|s|s.to_i}) {|l| puts l}
92
+ end
data/bench/run ADDED
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'my-profile.rb'
4
+
5
+ class Object
6
+ def rbprofile prof_flag = true
7
+ if block_given?
8
+ $profiler.instance_eval do
9
+ save = @do_profiling
10
+ @do_profiling = prof_flag
11
+ yield
12
+ @do_profiling = save
13
+ end
14
+ else
15
+ $profiler.instance_eval {@do_profiling = prof_flag}
16
+ end
17
+ end
18
+ end
19
+
20
+ bench_flag = ARGV.delete("b") || ARGV.delete("bench")
21
+ profile_flag = ARGV.delete("p") || ARGV.delete("profile")
22
+ rbprof_flag = ARGV.delete("rbprof")
23
+
24
+ prog_name = ARGV.shift
25
+
26
+ $REDSHIFT_CLIB_NAME = prog_name
27
+
28
+ case
29
+ when bench_flag
30
+ require prog_name; steps = $steps
31
+ require 'benchmark'
32
+ include Benchmark
33
+ bm(12) do |test|
34
+ for step in steps
35
+ test.report(step[0] + ":") do
36
+ step[1].call
37
+ end
38
+ end
39
+ end
40
+
41
+ when profile_flag
42
+ require prog_name; steps = $steps
43
+ for step in steps
44
+ # require 'profile' if step[0] == "run" # don't profile compilation
45
+ profile (step[0] == "run") do # only profile run, not compile or create
46
+ step[1].call
47
+ end
48
+ end
49
+
50
+ when rbprof_flag
51
+ require 'rbprof'; rbprofile false
52
+ require prog_name; steps = $steps
53
+ for step in steps
54
+ if step[0] == "run" # don't profile compilation
55
+ rbprofile {step[1].call}
56
+ else
57
+ step[1].call
58
+ end
59
+ end
60
+
61
+ else
62
+ require prog_name; steps = $steps
63
+ for step in steps
64
+ step[1].call
65
+ end
66
+ end
data/bench/simple.rb ADDED
@@ -0,0 +1,74 @@
1
+ require 'redshift'
2
+
3
+ class Thing < RedShift::Component
4
+ flow {
5
+ diff "w' = 1"
6
+ alg "ww = 2*w + (sin(w) + cos(w))*(sin(w) + cos(w))"
7
+ alg "www = ww-2"
8
+ diff "u' = www"
9
+ }
10
+ def inspect data = nil
11
+ d = "; #{data}" if data
12
+ vars = [
13
+ "w = #{w}"
14
+ ]
15
+ super "#{vars.join(", ")}#{d}"
16
+ end
17
+ end
18
+
19
+ class Base < RedShift::Component
20
+ flow {
21
+ diff "x' = 1"
22
+ }
23
+ def inspect data = nil
24
+ d = "; #{data}" if data
25
+ vars = [
26
+ "x = #{x}"
27
+ ]
28
+ super "#{vars.join(", ")}#{d}"
29
+ end
30
+ end
31
+
32
+ class Tester < Base
33
+ link :thing => Thing
34
+ flow {
35
+ alg "xx = 3*x"
36
+ diff "y' = xx"
37
+ diff "z' = y + 4*(thing.w+thing.u)"
38
+ }
39
+
40
+ def inspect data = nil
41
+ d = "; #{data}" if data
42
+ vars = [
43
+ "xx = #{xx}",
44
+ "y = #{y}",
45
+ "z = #{z}"
46
+ ]
47
+ super "#{vars.join(", ")}#{d}"
48
+ end
49
+
50
+ setup do
51
+ self.thing = create Thing
52
+ end
53
+ end
54
+
55
+ #----------------------------------#
56
+
57
+ n_obj = 100
58
+ n_iter = 100_000
59
+
60
+ # 10, 100_000 ==> 8.87 seconds
61
+
62
+ world = nil
63
+ $steps = [
64
+ ["commit", proc { world = RedShift::World.new {|w| w.time_step = 0.05} }],
65
+ ["create", proc { n_obj.times do world.create Tester end }],
66
+ ["run", proc { world.run n_iter }]
67
+ ]
68
+
69
+ END {
70
+ # puts "time_step = #{world.time_step}"
71
+ # puts "clock = #{world.clock}"
72
+ # t = world.find { |c| c.is_a? Tester }
73
+ # p t
74
+ }
@@ -0,0 +1,86 @@
1
+ require 'my-profile'
2
+
3
+ $strict = ARGV.delete("-s")
4
+
5
+ # This makes a 5x difference!
6
+ if $strict
7
+ $REDSHIFT_CLIB_NAME = "strictness-on"
8
+ else
9
+ $REDSHIFT_CLIB_NAME = "strictness-off"
10
+ end
11
+
12
+ require 'redshift'
13
+ include RedShift
14
+
15
+ class SimpleComponent < Component
16
+
17
+ continuous :x
18
+ if $strict
19
+ strictly_continuous :y
20
+ strict_link :other => SimpleComponent
21
+ else
22
+ continuous :y
23
+ link :other => SimpleComponent
24
+ end
25
+
26
+ state :A, :B; default { start A; self.other = self }
27
+
28
+ flow A do
29
+ diff " y' = 1 + x " # y still strict even though x is not
30
+ end
31
+
32
+ 5.times do
33
+ transition A => B do
34
+ guard " pow(y, 2) - sin(y) + cos(y) + other.y < 0 "
35
+ end
36
+ end
37
+
38
+ end
39
+
40
+ class ComplexComponent < Component
41
+
42
+ attr_accessor :start_value
43
+
44
+ state :A, :B, :C, :D, :E1, :F; default { start A }
45
+
46
+ flow A do
47
+ diff "t' = 1"
48
+ end
49
+
50
+ transition A => B do
51
+ guard "t > 1"
52
+ action do
53
+ if @start_value
54
+ self.t = @start_value
55
+ @start_value = nil
56
+ else
57
+ self.t = 0
58
+ end
59
+ end
60
+ end
61
+
62
+ transition B => C, C => D, D => E1, E1 => F, F => A
63
+
64
+ end
65
+
66
+ n = 1000
67
+ hz = 100
68
+ ts = 1.0/hz
69
+ w = World.new { |w| w.time_step = ts }
70
+ n.times do w.create SimpleComponent end
71
+ hz.times do |i|
72
+ cc = w.create ComplexComponent
73
+ cc.start_value = i*ts
74
+ end
75
+
76
+ times = Process.times
77
+ t0 = Time.now
78
+ pt0 = times.utime #+ times.stime
79
+ profile false do
80
+ w.run 1000
81
+ end
82
+ times = Process.times
83
+ t1 = Time.now
84
+ pt1 = times.utime #+ times.stime
85
+ puts "process time: %8.2f" % (pt1-pt0)
86
+ puts "elapsed time: %8.2f" % (t1-t0)
@@ -0,0 +1,72 @@
1
+ # Example showing how to use tkar to animate a redshift simulation.
2
+ #
3
+ # Tkar can be found at http://path.berkeley.edu/~vjoel/vis/tkar
4
+
5
+ require 'redshift'
6
+ include RedShift
7
+
8
+ class Ball < Component
9
+ continuous :x, :y, :v
10
+
11
+ flow do
12
+ diff "y' = v"
13
+ diff "v' = -9.8"
14
+ end
15
+
16
+ transition do
17
+ guard "y - 5 < 0 && v < 0"
18
+ reset :v => "-v"
19
+ end
20
+
21
+ attr_accessor :id # so we can keep track of which is which in animation
22
+ end
23
+
24
+ world = World.new
25
+ #world.time_step = 0.01
26
+
27
+ ball_count = 10
28
+ balls = Array.new(ball_count) do |id|
29
+ world.create(Ball) do |ball|
30
+ ball.x = id * 10
31
+ ball.y = rand(450) + 100
32
+ ball.v = 0
33
+ ball.id = id
34
+ end
35
+ end
36
+
37
+ begin
38
+ ## need --quiet option?
39
+ IO.popen("tkar --flip -v", "w") do |tkar|
40
+ # --flip means positive y is up
41
+ tkar.puts %{
42
+ title Bouncing ball
43
+ background gray95
44
+ height 600
45
+ width 600
46
+ bounds -300 0 300 600
47
+ shape ball oval-5,-5,5,5,fc:darkgreen,oc:red
48
+ shape ground line*0,0,*1,0,fc:purple,wi:4
49
+ add ground 10000 - 10 0 0 0 -300 300
50
+ view_at 0 540
51
+ }
52
+ balls.each do |ball|
53
+ tkar.puts %{
54
+ add ball #{ball.id} - 100 #{ball.x} #{ball.y} 0
55
+ }
56
+ end
57
+ tkar.flush
58
+ world.evolve 1000 do
59
+ balls.each do |ball|
60
+ tkar.puts "move #{ball.id} #{ball.x} #{ball.y}"
61
+ end
62
+ tkar.puts "update"
63
+ tkar.flush
64
+ #sleep 0.01
65
+ ## need timer to make this realistic
66
+ end
67
+ puts "Press <enter> when done"
68
+ gets
69
+ end
70
+ rescue Errno::EPIPE, Interrupt
71
+ puts "Exited."
72
+ end