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,203 @@
1
+ module RedShift; class DelayFlow
2
+ def flow_wrapper cl, state
3
+ var_name = @var
4
+ flow = self
5
+ flow_name = "flow_#{CGenerator.make_c_name cl.name}_#{var_name}_#{state}"
6
+ delay_by = @delay_by
7
+
8
+ Component::FlowWrapper.make_subclass flow_name do
9
+ @inspect_str =
10
+ "#{cl.name}:#{state}: " +
11
+ "#{var_name} = #{flow.formula} [delay: #{delay_by}]"
12
+
13
+ ssn = cl.shadow_struct.name
14
+ cont_state_ssn = cl.cont_state_class.shadow_struct.name
15
+
16
+ require "redshift/target/c/flow/buffer"
17
+ RedShift.library.define_buffer
18
+
19
+ bufname = "#{var_name}_buffer_data"
20
+ offsetname = "#{var_name}_buffer_offset"
21
+ delayname = "#{var_name}_delay"
22
+ tsname = "#{var_name}_time_step"
23
+
24
+ cl.class_eval do
25
+ shadow_attr_accessor bufname => "Buffer #{bufname}"
26
+ shadow_attr_accessor offsetname => "long #{offsetname}"
27
+ shadow_attr_accessor delayname => "double #{delayname}"
28
+ # delay should be set only using the expr designated in :by => "expr"
29
+ shadow_attr tsname => "double #{tsname}"
30
+
31
+ after_commit do
32
+ alias_method "__#{bufname}=", "#{bufname}="
33
+ define_method "#{bufname}=" do |val|
34
+ send("__#{bufname}=", val)
35
+ d = world.time_step * (val.size / 4)
36
+ send("#{delayname}=", d) # keep cached delay consistent
37
+ end
38
+ end
39
+ private :"#{delayname}="
40
+ end
41
+
42
+ # We need the struct
43
+ shadow_library_source_file.include(cl.shadow_library_include_file)
44
+
45
+ shadow_library_source_file.define(flow_name).instance_eval do
46
+ arguments "ComponentShadow *comp_shdw"
47
+ declare :shadow => %{
48
+ struct #{ssn} *shadow;
49
+ struct #{cont_state_ssn} *cont_state;
50
+
51
+ ContVar *var;
52
+ double *ptr;
53
+ long i, len, offset, steps;
54
+ double delay, fill;
55
+ }
56
+ setup :shadow => %{
57
+ shadow = (#{ssn} *)comp_shdw;
58
+ cont_state = (#{cont_state_ssn} *)shadow->cont_state;
59
+ var = &cont_state->#{var_name};
60
+ }
61
+ setup :rk_level => %{
62
+ shadow->world->rk_level--;
63
+ } # has to happen before referenced alg flows are called in other setups
64
+
65
+ setup :delay =>
66
+ begin
67
+ "delay = #{Float(delay_by)}"
68
+ rescue ArgumentError
69
+ flow.translate(self, "delay", 0, cl, delay_by)
70
+ end
71
+
72
+ include World.shadow_library_include_file
73
+
74
+ # Note: cases 1,2 must proceed to allow alg deps to be computed,
75
+ # since their values are used later.
76
+ body %{
77
+ switch (shadow->world->rk_level) {
78
+ case 0:
79
+ ptr = shadow->#{bufname}.ptr;
80
+ offset = shadow->#{offsetname};
81
+
82
+ if (shadow->world->time_step != shadow->#{tsname}) {
83
+ if (shadow->#{tsname} == 0.0)
84
+ shadow->#{tsname} = shadow->world->time_step;
85
+ else
86
+ rs_raise(#{declare_class RedShiftError}, shadow->self,
87
+ "Delay flow doesn't support changing time_step yet"); // ##
88
+ }
89
+
90
+ if (ptr && delay == shadow->#{delayname}) {
91
+ len = shadow->#{bufname}.len;
92
+ if (offset < 0 || offset > len - 4) {
93
+ rs_raise(#{declare_class RedShiftError}, shadow->self,
94
+ "Offset out of bounds: %d not in 0..%d!", offset, len - 4);
95
+ }
96
+ }
97
+ else {
98
+ steps = floor(delay / shadow->world->time_step + 0.5);
99
+ if (steps <= 0) {
100
+ rs_raise(#{declare_class RedShiftError}, shadow->self,
101
+ "Delay too small: %f.", delay);
102
+ }
103
+ len = steps*4;
104
+
105
+ if (!ptr) {
106
+ #{flow.translate(self, "fill", 0, cl).join("
107
+ ")};
108
+
109
+ ptr = ALLOC_N(double, len);
110
+ shadow->#{bufname}.ptr = ptr;
111
+ shadow->#{bufname}.len = len;
112
+ shadow->#{offsetname} = 0;
113
+ shadow->#{delayname} = delay;
114
+
115
+ for (i=0; i<len; i++) {
116
+ ptr[i] = fill;
117
+ }
118
+ }
119
+ else { // # delay != shadow->#{delayname}
120
+ long old_len = shadow->#{bufname}.len;
121
+ double *dst, *src;
122
+
123
+ if (delay < shadow->#{delayname}) {
124
+ if (offset < len) {
125
+ dst = ptr + offset;
126
+ src = ptr + offset + old_len - len;
127
+ }
128
+ else {
129
+ dst = ptr;
130
+ src = ptr + offset - len;
131
+ offset = 0;
132
+ }
133
+ memmove(dst, src, (len - offset) * sizeof(double));
134
+ REALLOC_N(ptr, double, len);
135
+ // ## maybe better: don't release space, just use less of it
136
+ }
137
+ else { // # delay > shadow->#{delayname}
138
+ REALLOC_N(ptr, double, len);
139
+
140
+ fill = ptr[offset];
141
+ dst = ptr + offset + len - old_len;
142
+ src = ptr + offset;
143
+ memmove(dst, src, (old_len - offset) * sizeof(double));
144
+
145
+ for (i = 0; i < len - old_len; i++) {
146
+ ptr[offset + i] = fill;
147
+ }
148
+ }
149
+
150
+ shadow->#{bufname}.ptr = ptr;
151
+ shadow->#{bufname}.len = len;
152
+ shadow->#{offsetname} = offset;
153
+ shadow->#{delayname} = delay;
154
+ }
155
+ }
156
+
157
+ offset = (offset + 4) % len;
158
+ shadow->#{offsetname} = offset;
159
+
160
+ var->value_0 = ptr[offset];
161
+ var->value_1 = ptr[offset + 1];
162
+ var->value_2 = ptr[offset + 2];
163
+ var->value_3 = ptr[offset + 3];
164
+
165
+ #{flow.translate(self, "ptr[offset]", 0, cl).join("
166
+ ")};
167
+ break;
168
+
169
+ case 1:
170
+ case 2:
171
+ break;
172
+
173
+ case 3:
174
+ ptr = shadow->#{bufname}.ptr;
175
+ len = shadow->#{bufname}.len;
176
+ offset = shadow->#{offsetname};
177
+
178
+ #{flow.translate(self, "ptr[offset+1]", 1, cl).join("
179
+ ")};
180
+ #{flow.translate(self, "ptr[offset+2]", 2, cl).join("
181
+ ")};
182
+ #{flow.translate(self, "ptr[offset+3]", 3, cl).join("
183
+ ")};
184
+
185
+ var->value_0 = ptr[(offset + 4) % len];
186
+ break;
187
+
188
+ default:
189
+ rb_raise(#{declare_class RuntimeError},
190
+ "Bad rk_level, %d!", shadow->world->rk_level);
191
+ }
192
+
193
+ shadow->world->rk_level++;
194
+ var->rk_level = shadow->world->rk_level;
195
+ }
196
+ end
197
+
198
+ define_c_method :calc_function_pointer do
199
+ body "shadow->flow = &#{flow_name}"
200
+ end
201
+ end
202
+ end
203
+ end; end
@@ -0,0 +1,101 @@
1
+ module RedShift; class DerivativeFlow
2
+ def flow_wrapper cl, state
3
+ var_name = @var
4
+ flow = self
5
+ flow_name = "flow_#{CGenerator.make_c_name cl.name}_#{var_name}_#{state}"
6
+ feedback = @feedback
7
+
8
+ Component::FlowWrapper.make_subclass flow_name do
9
+ @inspect_str = "#{cl.name}:#{state}: #{var_name} = #{flow.formula}'"
10
+
11
+ ssn = cl.shadow_struct.name
12
+ cont_state_ssn = cl.cont_state_class.shadow_struct.name
13
+
14
+ # We need the struct
15
+ shadow_library_source_file.include(cl.shadow_library_include_file)
16
+
17
+ init_rhs_name = "#{var_name}_init_rhs"
18
+ cl.class_eval do
19
+ shadow_attr_accessor init_rhs_name => "double #{init_rhs_name}"
20
+ end
21
+
22
+ shadow_library_source_file.define(flow_name).instance_eval do
23
+ arguments "ComponentShadow *comp_shdw"
24
+ declare :shadow => %{
25
+ struct #{ssn} *shadow;
26
+ struct #{cont_state_ssn} *cont_state;
27
+ ContVar *var;
28
+ double antiddt, *scratch;
29
+ double time_step;
30
+ }
31
+ setup :shadow => %{
32
+ shadow = (#{ssn} *)comp_shdw;
33
+ cont_state = (#{cont_state_ssn} *)shadow->cont_state;
34
+ var = &cont_state->#{var_name};
35
+ scratch = &shadow->#{init_rhs_name};
36
+ time_step = shadow->world->time_step;
37
+ }
38
+ setup :rk_level => %{
39
+ shadow->world->rk_level--;
40
+ } # has to happen before referenced alg flows are called in other setups
41
+ if feedback ## possible to unite these cases somehow?
42
+ body %{
43
+ switch (shadow->world->rk_level) {
44
+ case 0:
45
+ #{flow.translate(self, "antiddt", 0, cl).join("
46
+ ")};
47
+ var->value_0 = var->value_1 =
48
+ var->value_2 = var->value_3 =
49
+ (antiddt - *scratch) / time_step;
50
+ *scratch = antiddt;
51
+ }
52
+ shadow->world->rk_level++;
53
+ var->rk_level = shadow->world->rk_level;
54
+ }
55
+ else
56
+ body %{
57
+ switch (shadow->world->rk_level) {
58
+ case 0:
59
+ #{flow.translate(self, "antiddt", 0, cl).join("
60
+ ")};
61
+ var->value_1 = var->value_0;
62
+ *scratch = antiddt;
63
+ break;
64
+
65
+ case 1:
66
+ #{flow.translate(self, "antiddt", 1, cl).join("
67
+ ")};
68
+ var->value_2 = (antiddt - *scratch) / (time_step/2);
69
+ *scratch = antiddt;
70
+ break;
71
+
72
+ case 2:
73
+ #{flow.translate(self, "antiddt", 2, cl).join("
74
+ ")};
75
+ var->value_3 = (antiddt - *scratch) / (time_step/2);
76
+ break;
77
+
78
+ case 3:
79
+ #{flow.translate(self, "antiddt", 3, cl).join("
80
+ ")};
81
+ var->value_0 = (antiddt - *scratch) / (time_step/2);
82
+ break;
83
+
84
+ default:
85
+ rb_raise(#{declare_class RuntimeError},
86
+ "Bad rk_level, %d!", shadow->world->rk_level);
87
+ }
88
+
89
+ shadow->world->rk_level++;
90
+ var->rk_level = shadow->world->rk_level;
91
+ }
92
+ end
93
+ end
94
+
95
+ define_c_method :calc_function_pointer do
96
+ body "shadow->flow = &#{flow_name}"
97
+ end
98
+ end
99
+ end
100
+
101
+ end; end
@@ -0,0 +1,67 @@
1
+ module RedShift; class EulerDifferentialFlow
2
+ def flow_wrapper cl, state
3
+ var_name = @var
4
+ flow = self
5
+
6
+ flow_name = "flow_#{CGenerator.make_c_name cl.name}_#{var_name}_#{state}"
7
+
8
+ Component::FlowWrapper.make_subclass flow_name do
9
+ @inspect_str = "#{cl.name}:#{state}: #{var_name} = #{flow.formula}"
10
+
11
+ ssn = cl.shadow_struct.name
12
+ cont_state_ssn = cl.cont_state_class.shadow_struct.name
13
+
14
+ # We need the struct
15
+ shadow_library_source_file.include(cl.shadow_library_include_file)
16
+
17
+ shadow_library_source_file.define(flow_name).instance_eval do
18
+ arguments "ComponentShadow *comp_shdw"
19
+ declare :shadow => %{
20
+ struct #{ssn} *shadow;
21
+ struct #{cont_state_ssn} *cont_state;
22
+ ContVar *var;
23
+ double ddt_#{var_name};
24
+ double time_step;
25
+ }
26
+ setup :first => %{
27
+ if (comp_shdw->world->rk_level == 2 ||
28
+ comp_shdw->world->rk_level == 3)
29
+ return;
30
+ } ## optimization: in rk_level==4 case, don't need to calc deps
31
+ setup :shadow => %{
32
+ shadow = (#{ssn} *)comp_shdw;
33
+ cont_state = (#{cont_state_ssn} *)shadow->cont_state;
34
+ var = &cont_state->#{var_name};
35
+ time_step = shadow->world->time_step;
36
+ } # return is necessary--else shadow, cont_state, var are uninitialized
37
+ setup :rk_level => %{
38
+ shadow->world->rk_level--;
39
+ } # has to happen before referenced alg flows are called in other setups
40
+ body %{
41
+ switch (shadow->world->rk_level) {
42
+ case 0:
43
+ #{flow.translate(self, "ddt_#{var_name}", 0, cl).join("
44
+ ")};
45
+
46
+ var->value_1 = var->value_2 =
47
+ var->value_0 + ddt_#{var_name} * time_step/2;
48
+ var->value_3 =
49
+ var->value_0 + ddt_#{var_name} * time_step;
50
+ var->rk_level = 3;
51
+ break;
52
+
53
+ case 3:
54
+ var->value_0 = var->value_3;
55
+ var->rk_level = 4;
56
+ break;
57
+ }
58
+
59
+ shadow->world->rk_level++;
60
+ }
61
+ end
62
+ define_c_method :calc_function_pointer do
63
+ body "shadow->flow = &#{flow_name}"
64
+ end
65
+ end
66
+ end
67
+ end; end
@@ -0,0 +1,113 @@
1
+ module RedShift; class CexprGuard
2
+
3
+ def initialize f
4
+ super nil, f
5
+ end
6
+
7
+ @@serial = 0
8
+
9
+ # +cl+ is the component class
10
+ ## maybe all these methods should just be called wrapper?
11
+ def guard_wrapper cl
12
+ guard = self
13
+ cl_cname = CGenerator.make_c_name cl.name
14
+ g_cname = "Guard_#{@@serial}"; @@serial += 1
15
+ guard_name = "guard_#{cl_cname}_#{g_cname}"
16
+
17
+ Component::GuardWrapper.make_subclass guard_name do
18
+ @inspect_str = "#{cl.name}: #{guard.formula}"
19
+
20
+ ssn = cl.shadow_struct.name
21
+ cont_state_ssn = cl.cont_state_class.shadow_struct.name
22
+
23
+ # We need the struct
24
+ shadow_library_source_file.include(cl.shadow_library_include_file)
25
+
26
+ strict = false
27
+
28
+ shadow_library_source_file.define(guard_name).instance_eval do
29
+ arguments "ComponentShadow *comp_shdw"
30
+ return_type "int"
31
+ declare :shadow => %{
32
+ struct #{ssn} *shadow;
33
+ struct #{cont_state_ssn} *cont_state;
34
+ ContVar *var;
35
+ }
36
+ setup :shadow => %{
37
+ shadow = (#{ssn} *)comp_shdw;
38
+ cont_state = (#{cont_state_ssn} *)shadow->cont_state;
39
+ }
40
+ declare :result => "int result"
41
+ translation = guard.translate(self, "result", 0, cl) {|s| strict = s}
42
+ body %{
43
+ #{translation.join("
44
+ ")};
45
+ return result;
46
+ }
47
+ end
48
+
49
+ @strict = strict
50
+ ## should set guard.strict = strict too?
51
+
52
+ define_c_method :calc_function_pointer do
53
+ body "shadow->guard = &#{guard_name}"
54
+ end
55
+ end
56
+ end
57
+ end; end
58
+
59
+ module RedShift; class Expr
60
+ attr_reader :type
61
+
62
+ def initialize f, type = "double"
63
+ super nil, f
64
+ @type = type
65
+ end
66
+
67
+ @@serial = 0
68
+
69
+ # +cl+ is the component class
70
+ def wrapper(cl)
71
+ expr = self
72
+ cl_cname = CGenerator.make_c_name cl.name
73
+ ex_cname = "Expr_#{@@serial}"; @@serial += 1
74
+ expr_name = "expr_#{cl_cname}_#{ex_cname}"
75
+
76
+ Component::ExprWrapper.make_subclass expr_name do
77
+ @inspect_str = "#{cl.name}: #{expr.formula}"
78
+
79
+ ssn = cl.shadow_struct.name
80
+ cont_state_ssn = cl.cont_state_class.shadow_struct.name
81
+
82
+ # We need the struct
83
+ shadow_library_source_file.include(cl.shadow_library_include_file)
84
+
85
+ shadow_library_source_file.define(expr_name).instance_eval do
86
+ arguments "ComponentShadow *comp_shdw"
87
+ return_type expr.type
88
+ declare :shadow => %{
89
+ struct #{ssn} *shadow;
90
+ struct #{cont_state_ssn} *cont_state;
91
+ ContVar *var;
92
+ }
93
+ setup :shadow => %{
94
+ shadow = (#{ssn} *)comp_shdw;
95
+ cont_state = (#{cont_state_ssn} *)shadow->cont_state;
96
+ }
97
+ declare :result => "#{expr.type} result"
98
+ translation = expr.translate(self, "result", 0, cl)
99
+ body %{
100
+ #{translation.join("
101
+ ")};
102
+ return result;
103
+ }
104
+ end
105
+
106
+ define_c_method :calc_function_pointer do
107
+ body "shadow->expr = &#{expr_name}"
108
+ end
109
+ end
110
+ end
111
+ end; end
112
+
113
+ module RedShift; class ResetExpr < Expr; end; end