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,183 @@
1
+ module RedShift
2
+
3
+ class Component
4
+
5
+ class_superhash2 :flows
6
+ class_superhash :exported_events # :event => index
7
+ class_superhash :states
8
+ class_superhash :continuous_variables, :constant_variables
9
+ class_superhash :link_variables # :link_name => [type, strictness]
10
+ class_superhash :input_variables # :var_name => :piecewise | :strict
11
+ class_superhash :queues
12
+
13
+ @subclasses = []
14
+
15
+ class << self
16
+ # Component is abstract, and not included in subclasses. This returns nil
17
+ # when called on subs.
18
+ attr_reader :subclasses
19
+
20
+ def inherited(sub)
21
+ Component.subclasses << sub
22
+ end
23
+
24
+ # Declare +events+ to be exported (optional). Returns array of corresponding
25
+ # event indexes which can be used in code generation.
26
+ def export(*events)
27
+ events.map do |event|
28
+ exported_events[event.to_sym] ||= exported_events.size
29
+ end
30
+ end
31
+
32
+ def queue(*var_names)
33
+ var_names.each do |var_name|
34
+ next if queues[var_name]
35
+ queues[var_name] = true
36
+ class_eval %{
37
+ def #{var_name}
38
+ @#{var_name} ||= Queue.new(self)
39
+ end
40
+ }
41
+ end
42
+ end
43
+
44
+ def attach_link vars, strictness
45
+ unless not strictness or strictness == :strict
46
+ raise ArgumentError, "Strictness must be false or :strict"
47
+ end
48
+ unless vars.is_a? Hash
49
+ raise SyntaxError, "Arguments to link must be of form :var => class, " +
50
+ "where class can be either a Class or a string denoting class name"
51
+ end
52
+ vars.each do |var_name, var_type|
53
+ link_variables[var_name.to_sym] = [var_type, strictness]
54
+ end
55
+ end
56
+
57
+ def attach_state name
58
+ state = State.new(name, self)
59
+ const_set(name, state)
60
+ states[name] = state
61
+ end
62
+
63
+ def attach states, features
64
+ if features.class != Array
65
+ features = [features]
66
+ end
67
+
68
+ case states
69
+ when Array; attach_flows states, features
70
+ when Hash; attach_transitions states, features
71
+ else raise SyntaxError, "Bad state list: #{states.inspect}"
72
+ end
73
+ end
74
+
75
+ def attach_flows states, new_flows
76
+ states.each do |state|
77
+ fl = flows(state)
78
+ for f in new_flows
79
+ fl[f.var] = f
80
+ end
81
+ end
82
+ end
83
+
84
+ def attach_transitions state_pairs, new_transitions
85
+ new_transitions.delete_if {|t| t.guard && t.guard.any?{|g| g==false}}
86
+ state_pairs.each do |src, dst|
87
+ a = own_transitions(src)
88
+ new_transitions.each do |t|
89
+ name = t.name
90
+ a.delete_if {|u,d| u.name == name}
91
+ a << [t, dst]
92
+ end
93
+ end
94
+ end
95
+
96
+ # returns list of transitions from state s in evaluation order
97
+ # (just the ones defined in this class)
98
+ def own_transitions(s)
99
+ @own_transitions ||= {}
100
+ @own_transitions[s] ||= []
101
+ end
102
+
103
+ def all_transitions(s)
104
+ if self < Component
105
+ own_transitions(s) + superclass.all_transitions(s)
106
+ else
107
+ own_transitions(s)
108
+ end
109
+ end
110
+
111
+ def outgoing_transition_data s
112
+ ary = []
113
+ all_strict = true
114
+ seen = {}
115
+ all_transitions(s).each do |t, d|
116
+ next if seen[t.name] # overridden in subclass
117
+ seen[t.name] = true
118
+
119
+ t_strict = !t.sync || t.sync.empty?
120
+ guard_list = t.guard
121
+ guard_list and guard_list.each do |g|
122
+ t_strict &&= g.respond_to?(:strict) && g.strict
123
+ end
124
+ all_strict &&= t_strict
125
+
126
+ ary << [t, d, t.guard, t_strict]
127
+ end
128
+
129
+ result = []
130
+ ary.reverse_each do |list| # since step_discrete reads them in reverse
131
+ result.concat list
132
+ end
133
+ result << (all_strict ? 1 : 0) # other bits are used elsewhere
134
+ result
135
+ end
136
+
137
+ def attach_variables(dest, kind, var_names, var_type = nil)
138
+ if var_names.last.kind_of? Hash
139
+ h = var_names.pop
140
+ var_names.concat h.keys.sort_by {|n|n.to_s}
141
+ defaults h
142
+ end
143
+ var_names.each do |var_name|
144
+ dest[var_name.to_sym] = var_type ? [var_type, kind] : kind
145
+ end
146
+ end
147
+
148
+ # kind is :strict, :piecewise, or :permissive
149
+ def attach_continuous_variables(kind, var_names)
150
+ attach_variables(continuous_variables, kind, var_names)
151
+ end
152
+
153
+ # kind is :strict, :piecewise, or :permissive
154
+ def attach_constant_variables(kind, var_names)
155
+ attach_variables(constant_variables, kind, var_names)
156
+ end
157
+
158
+ def attach_input(kind, var_names)
159
+ var_names.each do |var_name|
160
+ input_variables[var_name.to_sym] = kind
161
+ end
162
+ end
163
+
164
+ def find_var_superhash var_name
165
+ [continuous_variables, constant_variables,
166
+ link_variables, input_variables].find {|sh| sh[var_name]}
167
+ end
168
+ end
169
+
170
+ def states
171
+ self.class.states.values
172
+ end
173
+
174
+ def flows s = state
175
+ self.class.flows s
176
+ end
177
+
178
+ def transitions s = state
179
+ self.class.all_transitions s
180
+ end
181
+ end # class Component
182
+
183
+ end # module RedShift
@@ -0,0 +1,69 @@
1
+ class RedShift::World
2
+
3
+ # Include this module in a World class. See example in examples/zeno.rb. Has a
4
+ # very small performance cost, so don't use it in production runs. Note that,
5
+ # even without ZenoDebugger, RedShift will still detect zeno problems by
6
+ # raising a ZenoError when world.zeno_counter > world.zeno_limit, if
7
+ # zeno_limit >= 0.
8
+ #
9
+ # ZenoDebugger is compatible with other kinds of debuggers.
10
+
11
+ module ZenoDebugger
12
+
13
+ # Can be used to turn on and off this module, set to $REDSHIFT_DEBUG_ZENO by
14
+ # default.
15
+ attr_accessor :debug_zeno
16
+
17
+ # Zeno output goes to this object, $stderr by default, using #<<.
18
+ attr_accessor :zeno_output
19
+
20
+ # Can be used to see which components are causing trouble. Ny default,
21
+ # the output covers all compontents taking transitions. However, you
22
+ # can use this attr to focus more narrowly.
23
+ attr_accessor :zeno_watch_list
24
+
25
+ # How many zeno steps before the debugger gives up. Set to ZENO_UNLIMITED to
26
+ # debug indefinitely, e.g., for interactive mode. By default, equal to 3
27
+ # times world.zeno_limit, so that batch runs will terminate.
28
+ attr_accessor :debug_zeno_limit
29
+
30
+ def initialize
31
+ @debug_zeno ||= $REDSHIFT_DEBUG_ZENO
32
+ @zeno_output ||= $stderr
33
+ super
34
+ end
35
+
36
+ # This method is called for each discrete step after the zeno_limit has been
37
+ # exceeded. This implementation is just one possibility, useful for
38
+ # debugging. One other useful behavior might be to shuffle guards in the
39
+ # active components.
40
+ #
41
+ # In this implementation, when the zeno_counter exceeds zeno_limit, we start
42
+ # to add active objects to the zeno_watch_list. When the counter exceeds
43
+ # two times the zeno_limit, we call report_zeno. When the counter exceeds
44
+ # three times the zeno_limit, we fall back to the super definition of
45
+ # step_zeno, which is typically to raise a ZenoError.
46
+
47
+ def step_zeno
48
+ self.debug_zeno_limit ||= zeno_limit*3
49
+ if debug_zeno and
50
+ (debug_zeno_limit == RedShift::ZENO_UNLIMITED or
51
+ zeno_counter < debug_zeno_limit)
52
+ report_zeno if zeno_counter >= 2*zeno_limit
53
+ else
54
+ super
55
+ end
56
+ end
57
+
58
+ HEADER = '-'*10 + " Zeno step: %d; Components: %d; Active: %d " + '-'*10 + "\n"
59
+
60
+ # Reports to zeno_output the list of active components.
61
+ def report_zeno
62
+ f = zeno_output
63
+ active = zeno_watch_list || curr_T
64
+
65
+ f << HEADER % [zeno_counter, components.size, curr_T.size]
66
+ f << ' ' + active.map{|c|c.inspect}.join("\n ") + "\n"
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,57 @@
1
+ module RedShift; class Component
2
+ class Port
3
+ attr_reader :component, :variable, :connectable
4
+
5
+ def initialize component, variable, connectable
6
+ @component, @variable, @connectable = component, variable, connectable
7
+ end
8
+
9
+ # Convenience method to get source port rather than component/var pair.
10
+ def source
11
+ source_component && source_component.port(source_variable)
12
+ end
13
+
14
+ def check_connectable
15
+ unless connectable
16
+ raise TypeError, "Not an input: #{variable} in #{component.class}"
17
+ end
18
+ end
19
+
20
+ def connect port
21
+ check_connectable
22
+ component.connect(variable, port && port.component, port && port.variable)
23
+ end
24
+
25
+ def _connect port
26
+ component.connect(variable, port && port.component, port && port.variable, false)
27
+ end
28
+
29
+ def <<(other)
30
+ connect(other)
31
+ return other
32
+ end
33
+
34
+ def >>(other)
35
+ other.connect(self)
36
+ return other
37
+ end
38
+
39
+ def disconnect
40
+ connect nil
41
+ end
42
+
43
+ def source_component
44
+ check_connectable
45
+ component.source_component_for(variable)
46
+ end
47
+
48
+ def source_variable
49
+ check_connectable
50
+ component.source_variable_for(variable)
51
+ end
52
+
53
+ def value
54
+ component.send variable
55
+ end
56
+ end
57
+ end; end
@@ -0,0 +1,104 @@
1
+ module RedShift
2
+ # a queue entry that contains multiple simultaneously enqueued objects
3
+ # (same in both continuous and discrete time)
4
+ class SimultaneousQueueEntries < Array; end
5
+
6
+ class Queue
7
+ # Owner of the queue.
8
+ attr_reader :component
9
+
10
+ def initialize component
11
+ @q = []
12
+ @step_count = nil
13
+ @discrete_step = nil
14
+ @component = component
15
+ end
16
+
17
+ def push obj
18
+ world = @component.world
19
+ step_count = world.step_count
20
+ discrete_step = world.discrete_step
21
+
22
+ if step_count == @step_count and discrete_step == @discrete_step
23
+ last = @q[-1]
24
+ case last
25
+ when SimultaneousQueueEntries
26
+ last << obj
27
+ when nil; raise "Internal error: expected simultaneous queue entry."
28
+ else
29
+ @q[-1] = SimultaneousQueueEntries[last, obj]
30
+ end
31
+
32
+ else
33
+ was_empty = @q.empty?
34
+ @step_count = step_count
35
+ @discrete_step = discrete_step
36
+ @q << obj
37
+ @component.inc_queue_ready_count if was_empty
38
+ end
39
+
40
+ self
41
+ end
42
+
43
+ alias << push
44
+
45
+ class QueueEmptyError < StandardError; end
46
+
47
+ # When popping from a queue, the result may be an instance
48
+ # of SimultaneousQueueEntries, which should probably be handled specially.
49
+ def pop
50
+ if @q.empty?
51
+ raise QueueEmptyError, "tried to pop empty queue in #{@component.inspect}"
52
+ end
53
+ obj = @q.shift
54
+ @component.dec_queue_ready_count if @q.empty?
55
+ obj
56
+ end
57
+
58
+ # Correctly handles case when obj is SimultaneousQueueEntries.
59
+ def unpop obj
60
+ was_empty = @q.empty?
61
+ case obj
62
+ when SimultaneousQueueEntries
63
+ case obj.size
64
+ when 0
65
+ was_empty = false # just to prevent the inc
66
+ when 1
67
+ @q.unshift obj.first
68
+ else
69
+ @q.unshift obj
70
+ end
71
+ else
72
+ @q.unshift obj
73
+ end
74
+ @component.inc_queue_ready_count if was_empty
75
+ end
76
+
77
+ # Called from guard evaluation in step_discrete. Returns true if at least
78
+ # one entry in the head of the queue matches _all_ of the conditions, which
79
+ # may be Procs (called to return boolean) or any objects with #===.
80
+ def head_matches(*conds)
81
+ return false if @q.empty?
82
+ head = @q[0]
83
+ case head
84
+ when SimultaneousQueueEntries
85
+ head.any? do |head_item|
86
+ item_matches conds, head_item
87
+ end
88
+ else
89
+ item_matches conds, head
90
+ end
91
+ end
92
+
93
+ def item_matches conds, item
94
+ conds.all? do |cond|
95
+ case cond
96
+ when Proc
97
+ cond.call(item)
98
+ else
99
+ cond === item
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,111 @@
1
+ # Copyright (C) 2001-2006, Joel VanderWerf
2
+ # Distributed under the Ruby license. See www.ruby-lang.org.
3
+
4
+ # Read all environment variables related to RedShift and store in globals
5
+ ## see importenv.rb for a way to keep these in sync
6
+ ENV.keys.grep(/RedShift/i) do |key|
7
+ val = ENV[key] # make eval safe
8
+ eval "$#{key} = val unless defined? $#{key}"
9
+ end
10
+
11
+ if $REDSHIFT_DEBUG
12
+ f = $stderr
13
+ f.puts " ----------------------------------------------------------------- "
14
+ f.puts " |RedShift debugging information enabled by env var REDSHIFT_DEBUG.|"
15
+ f.puts " | Please ignore error messages that do not halt the progam. |"
16
+ f.puts " ----------------------------------------------------------------- "
17
+ f.puts "\n debug level = #{$REDSHIFT_DEBUG}\n\n" if $REDSHIFT_DEBUG != true
18
+
19
+ $REDSHIFT_DEBUG = ($REDSHIFT_DEBUG.to_i rescue 1)
20
+ end
21
+
22
+ class AssertionFailure < StandardError; end
23
+ class Object ## get rid of this?
24
+ def assert(test, *msg)
25
+ raise AssertionFailure, *msg unless test
26
+ end
27
+ end
28
+
29
+ module Math
30
+ Infinity = 1.0/0.0 unless defined? Infinity
31
+ end
32
+
33
+ module RedShift
34
+ include Math
35
+
36
+ VERSION = '1.3.15'
37
+
38
+ Infinity = Math::Infinity
39
+
40
+ def debug setting = true, &block
41
+ if block
42
+ begin
43
+ save_setting = $REDSHIFT_DEBUG
44
+ $REDSHIFT_DEBUG = setting
45
+ block.call
46
+ ensure
47
+ $REDSHIFT_DEBUG = save_setting
48
+ end
49
+ else
50
+ $REDSHIFT_DEBUG = setting
51
+ end
52
+ end
53
+
54
+ # Returns a list of all worlds (instances of RedShift::World and subclasses),
55
+ # or just those descending from +world_class+.
56
+ # Not very efficient, since it uses <tt>ObjectSpace.each_object</tt>, but
57
+ # useful in irb.
58
+ def self.worlds(world_class = World)
59
+ worlds = []
60
+ ObjectSpace.each_object(world_class) {|w| worlds << w}
61
+ worlds
62
+ end
63
+
64
+ # class Warning < Exception; end
65
+ #
66
+ # # Warn with string str and skipping n stack frames.
67
+ # def warn str, n = 0
68
+ # warning = sprintf "\nWarning: #{str}\n\t#{caller(n).join("\n\t")}\n"
69
+ # #if $REDSHIFT_DEBUG -- in debug mode, exception is always printed ???
70
+ # raise Warning, warning
71
+ # #else
72
+ # # $stderr.print warning
73
+ # #end
74
+ # end
75
+ # module_function :warn
76
+
77
+ @library_calls = []
78
+
79
+ # Defer a block until just after the library ruby code is loaded, but before
80
+ # commit. Necessary for defining inline C functions or shadow_attrs. Note that
81
+ # a whole require statement could be placed inside the with_library block.
82
+ def RedShift.with_library(&block) # :yields: library
83
+ @library_calls << block
84
+ end
85
+
86
+ def RedShift.do_library_calls
87
+ @library_calls.each do |block|
88
+ block[library]
89
+ end
90
+ end
91
+
92
+ def RedShift.require_target
93
+ require $REDSHIFT_TARGET
94
+ end
95
+
96
+ end # module RedShift
97
+
98
+ case $REDSHIFT_TARGET
99
+ when nil, /^c$/i
100
+ $REDSHIFT_TARGET = 'redshift/target/c'
101
+ when /^spec$/i
102
+ $REDSHIFT_TARGET = 'redshift/target/spec'
103
+ when /^dot$/i
104
+ $REDSHIFT_TARGET = 'redshift/target/dot'
105
+ end
106
+
107
+ # There could be other things here... Java, YAML, HSIF, Teja, pure ruby
108
+ # reference impl. etc. (but procs are a problem for all but ruby)
109
+
110
+ require 'redshift/syntax'
111
+