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