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,34 @@
1
+ require 'pp'
2
+
3
+ #
4
+ # Note: This is not a complete program specification, since Procs and methods
5
+ # cannot be dumped. It is useful for inspecting the vars, flows, and also
6
+ # transitions, to the extent that these are defined without Procs.
7
+ #
8
+
9
+ class World
10
+ def World.new(*args)
11
+ exit ## could just call the code below and then exit...
12
+ end
13
+ end
14
+
15
+ END {
16
+ ## this duplicates some code from Library
17
+ cc = []
18
+ ObjectSpace.each_object(Class) do |cl|
19
+ cc << cl if cl < Component # Component is abstract
20
+ end
21
+ cc = cc.sort_by {|c| c.ancestors.reverse!.map!{|d|d.to_s}}
22
+
23
+ cc.each do |c|
24
+ puts "=" * 60
25
+ puts "=" * 20 + "class #{c.name}"
26
+ c.instance_eval do
27
+ instance_variables.each do |var|
28
+ val = eval(var)
29
+ puts "#{var}:"
30
+ pp val
31
+ end
32
+ end
33
+ end
34
+ }
@@ -0,0 +1,300 @@
1
+ require 'pstore'
2
+
3
+ module RedShift
4
+
5
+ class ZenoError < RuntimeError; end
6
+
7
+ # Set zeno_level to this to turn off zeno checking.
8
+ ZENO_UNLIMITED = -1
9
+
10
+ class World
11
+ include Enumerable
12
+
13
+ {
14
+ :Debugger => "debugger",
15
+ :ZenoDebugger => "zeno-debugger"
16
+ }.each {|m,f| autoload(m, "redshift/mixins/#{f}")}
17
+
18
+ class ComponentList
19
+ include Enumerable
20
+
21
+ attr_reader :summands
22
+
23
+ def initialize(*summands)
24
+ @summands = summands
25
+ end
26
+
27
+ def each(&block)
28
+ summands.each { |enum| enum.each(&block) }
29
+ self
30
+ end
31
+
32
+ def size
33
+ summands.inject(0) { |sum,enum| sum + enum.size }
34
+ end
35
+
36
+ def inspect
37
+ to_a.inspect # looks better in irb, but slow
38
+ end
39
+
40
+ def [](idx)
41
+ warn "World#[] is deprecated"
42
+ to_a[idx] ## very inefficient
43
+ end
44
+
45
+ def clear
46
+ summands.each {|list| list.clear}
47
+ end
48
+ end
49
+
50
+ @subclasses = []
51
+
52
+ class << self
53
+ # World is not included in subclasses. This returns nil when called on subs.
54
+ attr_reader :subclasses
55
+
56
+ def inherited(sub)
57
+ World.subclasses << sub
58
+ end
59
+ end
60
+
61
+ def self.new(*args, &block)
62
+ RedShift.require_target # redefines World.new
63
+ new(*args, &block) # which is what this line calls
64
+ end
65
+
66
+ attr_reader :components
67
+
68
+ def default_options
69
+ {
70
+ :name => "#{self.class}_#{@@count}",
71
+ :time_unit => "second",
72
+ :time_step => 0.1,
73
+ :zeno_limit => 100,
74
+ :clock_start => 0.0,
75
+ :clock_finish => Infinity,
76
+ }
77
+ end
78
+
79
+ @@count = 0
80
+
81
+ attr_accessor :name, :time_unit
82
+
83
+ def started?; @started; end
84
+ def running?; @running; end
85
+
86
+ # Can override the options using assignments in the block.
87
+ # Note that clock_start should not be assigned after the block.
88
+ def initialize # :yields: world
89
+ self.curr_A = []; self.curr_P = []; self.curr_CR = []
90
+ self.curr_S = []; self.next_S = []; self.curr_T = []
91
+ self.active_E = []; self.prev_active_E = []
92
+ self.awake = []; self.prev_awake = []
93
+ self.strict_sleep = []; self.inert = []
94
+ self.diff_list = []; self.queue_sleep = {}
95
+ @components = ComponentList.new \
96
+ awake, prev_awake, curr_T, strict_sleep, inert # _not_ diff_list
97
+
98
+ options = default_options
99
+
100
+ @name = options[:name]
101
+ @time_unit = options[:time_unit]
102
+ self.time_step = options[:time_step]
103
+ self.zeno_limit = options[:zeno_limit]
104
+ self.clock_start = options[:clock_start]
105
+ self.clock_finish = options[:clock_finish]
106
+
107
+ self.step_count = 0
108
+
109
+ @@count += 1
110
+
111
+ do_defaults
112
+ yield self if block_given?
113
+
114
+ self.base_step_count = 0
115
+ self.base_clock = clock_start
116
+ end
117
+
118
+ def do_defaults
119
+ self.class.do_defaults self
120
+ end
121
+ private :do_defaults
122
+
123
+ def self.do_defaults instance
124
+ superclass.do_defaults instance if superclass.respond_to? :do_defaults
125
+ if @defaults_procs
126
+ @defaults_procs.each do |pr|
127
+ instance.instance_eval(&pr)
128
+ end
129
+ end
130
+ end
131
+
132
+ def do_setup
133
+ self.class.do_setup self
134
+ if @setup_procs
135
+ @setup_procs.each do |pr|
136
+ instance_eval(&pr)
137
+ end
138
+ @setup_procs = nil # so we can serialize
139
+ end
140
+ end
141
+ private :do_setup
142
+
143
+ def self.do_setup instance
144
+ superclass.do_setup instance if superclass.respond_to? :do_setup
145
+ if @setup_procs
146
+ @setup_procs.each do |pr|
147
+ instance.instance_eval(&pr)
148
+ end
149
+ end
150
+ end
151
+
152
+ def create(component_class)
153
+ component =
154
+ if block_given?
155
+ component_class.new(self) {|c| yield c}
156
+ else
157
+ component_class.new(self)
158
+ end
159
+
160
+ unless component.is_a? Component # Component is abstract
161
+ raise TypeError, "#{component.class} is not a Component class"
162
+ end
163
+
164
+ awake << component if component.world == self
165
+ component
166
+ end
167
+
168
+ ## is this a good idea? tests? #add ?
169
+ def remove c
170
+ if components.summands.any? {|list| list.delete(c)}
171
+ raise unless c.world == self
172
+ c.__set__world(nil)
173
+ else
174
+ raise "Tried to remove #{c} from #{self}, but its world is #{c.world}."
175
+ end
176
+ end
177
+
178
+ # All evolution methods untimately call step, which can be overridden.
179
+ # After each step, yields to block. It is the block's responsibility to
180
+ # step_discrete at this point after changing any vars.
181
+ def step(steps = 1)
182
+ @running = true
183
+
184
+ unless @started
185
+ do_setup
186
+ @started = true
187
+ end
188
+
189
+ step_discrete
190
+ steps.to_i.times do
191
+ break if clock > clock_finish
192
+ self.step_count += 1
193
+ step_continuous
194
+ step_discrete
195
+ @running = false
196
+ yield self if block_given?
197
+ @running = true
198
+ end
199
+
200
+ self
201
+
202
+ ensure
203
+ @running = false
204
+ ## how to continue stepping after an exception?
205
+ end
206
+
207
+ def run(*args, &block)
208
+ ## warn "World#run is deprecated -- use #step or #evolve"
209
+ step(*args, &block)
210
+ end
211
+
212
+ def evolve(time = 1.0, &block)
213
+ run((time.to_f/time_step).round, &block)
214
+ end
215
+
216
+ # Default implementation is to raise RedShift::ZenoError.
217
+ def step_zeno
218
+ raise RedShift::ZenoError, "Exceeded zeno limit of #{zeno_limit}."
219
+ end
220
+
221
+ ## is this a good idea? tests?
222
+ def garbage_collect
223
+ self.components.clear
224
+ GC.start
225
+ ObjectSpace.each_object(Component) do |c|
226
+ components << c if c.world == self
227
+ end
228
+ end
229
+
230
+ def each(&b)
231
+ @components.each(&b)
232
+ end
233
+
234
+ def size
235
+ @components.size
236
+ end
237
+
238
+ def include? component
239
+ component.world == self
240
+ end
241
+ alias member? include?
242
+
243
+ def inspect
244
+ if @started
245
+ digits = -Math.log10(time_step).floor
246
+ digits = 0 if digits < 0
247
+
248
+ data = []
249
+ data << "%d step%s" % [step_count, ("s" if step_count != 1)]
250
+ data << "%.#{digits}f #{@time_unit}%s" % [clock, ("s" if clock != 1)]
251
+ data << "%d component%s" % [size, ("s" if size != 1)]
252
+ data << "discrete step = #{discrete_step}" ## only if in step_discrete?
253
+ else
254
+ data = ["not started. Do 'run 0' to setup, or 'run n' to run."]
255
+ end
256
+
257
+ str = [name, data.join("; ")].join(": ")
258
+ "<#{str}>"
259
+ end
260
+
261
+ def save filename = @name
262
+ raise "Can't save world during its run method." if @running
263
+ File.delete(filename) rescue SystemCallError
264
+ store = PStore.new filename
265
+ store.transaction do
266
+ store['world'] = self
267
+ yield store if block_given?
268
+ end
269
+ end
270
+
271
+ def World.open filename
272
+ RedShift.require_target
273
+ commit
274
+
275
+ world = nil
276
+ store = PStore.new filename
277
+ store.transaction do
278
+ if store.root? 'world'
279
+ world = store['world']
280
+ yield store if block_given?
281
+ end
282
+ end
283
+ world
284
+ end
285
+
286
+ # This is for when Component#world is nonpersistent
287
+ # def __restore__world__refs
288
+ # ## need this list because @components is not restored yet
289
+ # [awake, prev_awake, curr_T, strict_sleep, inert].each do |list|
290
+ # list.each do |c|
291
+ # c.send :__set__world, self
292
+ # end
293
+ # end
294
+ # ## could be in C
295
+ # end
296
+ # private :__restore__world__refs
297
+
298
+ end # class World
299
+
300
+ end # module RedShift
data/rakefile ADDED
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'bones'
3
+ rescue LoadError
4
+ abort '### please install the bones gem ###'
5
+ end
6
+
7
+ ensure_in_path 'lib'
8
+ require 'redshift'
9
+
10
+ Bones {
11
+ name 'redshift'
12
+ authors 'Joel VanderWerf'
13
+ email 'vjoel@users.sourceforge.net'
14
+ url 'http://rubyforge.org/projects/redshift'
15
+ rubyforge.name 'redshift'
16
+ version RedShift::VERSION
17
+ readme_file 'README'
18
+
19
+ summary 'Simulation of hybrid automata'
20
+ description <<END
21
+ A framework for simulation of networks of hybrid automata, similar to SHIFT and Lambda-SHIFT. Includes ruby-based DSL for defining simulation components, and ruby/C code generation and runtime.
22
+ END
23
+
24
+ depend_on 'cgen'
25
+
26
+ history_file 'RELEASE-NOTES'
27
+ changes File.read(history_file)[/^\w.*?(?=^\w)/m]
28
+ (rdoc.dir File.readlink(rdoc.dir)) rescue nil
29
+
30
+ spec.opts << '--color'
31
+ test.files = Dir["test/test-*.rb"]
32
+ }
33
+
34
+ task :release => ["rubyforge:release", "rubyforge:doc_release"]
35
+
36
+ # EOF
37
+
data/test/test.rb ADDED
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if RUBY_VERSION == "1.6.6"
4
+ puts "DEBUG mode is turned off in Ruby 1.6.6 due to bug."
5
+ $DEBUG = false
6
+ else
7
+ $DEBUG = true
8
+ end
9
+
10
+ if RUBY_VERSION == "1.8.0"
11
+ class Module
12
+ alias instance_methods_with_warning instance_methods
13
+ def instance_methods(include_super=true)
14
+ instance_methods_with_warning(include_super)
15
+ end
16
+ end
17
+ end
18
+
19
+ $REDSHIFT_DEBUG=3 ## what should this be?
20
+
21
+ ### have to fix the CLIB_NAME problem before can do this
22
+ ### require 'redshift' ## all the tests will need this anyway
23
+
24
+ pat = ARGV.join("|")
25
+ tests = Dir["test_*.rb"].grep(/#{pat}/)
26
+ tests.sort!
27
+
28
+ #trap("CLD") do
29
+ # # trapping "INT" doesn't work because child gets the signal
30
+ # exit!
31
+ #end
32
+
33
+ require 'rbconfig'
34
+ ruby = Config::CONFIG["RUBY_INSTALL_NAME"]
35
+
36
+ failed = tests.reject do |file|
37
+ puts "_"*50 + "\nStarting #{file}...\n"
38
+ system "#{ruby} #{file}"
39
+ # pid = fork { ## should use popen3 so we can weed out successful output
40
+ # $REDSHIFT_CLIB_NAME = file
41
+ # require 'redshift'
42
+ # load file
43
+ # }
44
+ # Process.waitpid(pid)
45
+ end
46
+
47
+ puts "_"*50
48
+ if failed.empty?
49
+ puts "All tests passed."
50
+ else
51
+ puts "Some tests failed:", failed
52
+ end
@@ -0,0 +1,58 @@
1
+ require 'redshift'
2
+
3
+ include RedShift
4
+
5
+ RedShift.with_library do |library|
6
+ require "redshift/target/c/flow/buffer"
7
+ library.define_buffer
8
+ end
9
+
10
+ require 'test/unit'
11
+
12
+ class TestBuffer < Test::Unit::TestCase
13
+
14
+ class T < Component
15
+ RedShift.with_library do
16
+ shadow_attr_accessor :b => "Buffer b"
17
+ end
18
+ end
19
+
20
+ def setup
21
+ @world = World.new
22
+ @t = @world.create(T)
23
+ end
24
+
25
+ def teardown
26
+ @world = nil
27
+ end
28
+
29
+ def test_accessor
30
+ a = [1.0, 2.0, 3.0, 4.0]
31
+ @t.b = a
32
+ assert_equal(a, @t.b)
33
+ end
34
+
35
+ def test_empty
36
+ assert_equal([], @t.b)
37
+ end
38
+
39
+ def test_marshal
40
+ t2 = Marshal.load(Marshal.dump(@t))
41
+ assert_equal(@t.b, t2.b)
42
+ end
43
+
44
+ def make_garbage
45
+ 5.times do
46
+ @world = World.new
47
+ @world.create(T)
48
+ end
49
+ end
50
+
51
+ def test_gc
52
+ make_garbage
53
+ n1 = ObjectSpace.each_object(T) {}
54
+ GC.start
55
+ n2 = ObjectSpace.each_object(T) {}
56
+ assert(n2 < n1)
57
+ end
58
+ end