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