redshift 1.3.21 → 1.3.22

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.
data/RELEASE-NOTES CHANGED
@@ -1,3 +1,17 @@
1
+ redshift 1.3.22
2
+
3
+ - handling of env vars is more consistent
4
+
5
+ - added World#alg_depth_limit and #input_depth_limit
6
+
7
+ - optimized generated flow code to use less instruction cache
8
+
9
+ - added algebraic, connect, and linked-flows benchmarks
10
+
11
+ - added step-discrete-hook example
12
+
13
+ - World#input_depth_limit and #alg_depth_limit accessors
14
+
1
15
  redshift 1.3.21
2
16
 
3
17
  - share flow wrapper classes when equation is same
@@ -0,0 +1,61 @@
1
+ # Measures performance of redshift's integrator with algebraic flows.
2
+ #
3
+ # Formulas are minimal to factor out C library time.
4
+
5
+ require 'redshift'
6
+
7
+ include RedShift
8
+
9
+ module Algebraic
10
+ class C < Component
11
+ strictly_continuous :x, :y, :xa, :ya
12
+ flow do
13
+ diff " x' = ya "
14
+ diff " y' = -xa "
15
+ alg " ya = y "
16
+ alg " xa = x "
17
+ end
18
+ end
19
+
20
+ def self.make_world n=1
21
+ w = World.new
22
+ n.times do
23
+ w.create(C) do |c|
24
+ c.x = 0.0
25
+ c.y = 1.0
26
+ end
27
+ end
28
+ w
29
+ end
30
+
31
+ def self.do_bench
32
+ [ [ 1, 1_000_000],
33
+ [ 10, 100_000],
34
+ [ 100, 10_000],
35
+ [ 1_000, 1_000],
36
+ [ 10_000, 100],
37
+ [ 100_000, 10] ].each do
38
+ | n_c, n_s|
39
+
40
+ w = make_world(n_c)
41
+ w.run 1 # warm up
42
+ r = bench do
43
+ w.run(n_s)
44
+ end
45
+
46
+ yield " - %10d comps X %10d steps: %8.2f" % [n_c, n_s, r]
47
+ end
48
+ end
49
+ end
50
+
51
+ if __FILE__ == $0
52
+
53
+ require 'bench'
54
+ w = Algebraic.make_world(1000)
55
+ time = bench do
56
+ w.run(1000)
57
+ end
58
+ p time
59
+
60
+ end
61
+
data/bench/bench CHANGED
@@ -14,12 +14,15 @@ pat = ARGV.pop
14
14
  pat = pat ? Regexp.new(pat) : //
15
15
  %w{
16
16
  alg-state
17
+ algebraic
18
+ connect
17
19
  continuous
18
20
  discrete
19
21
  euler
20
22
  formula
21
23
  half-strict
22
24
  inertness
25
+ linked-flows
23
26
  queues
24
27
  }.grep(pat).each do |name|
25
28
  bench_one(name)
data/bench/connect.rb ADDED
@@ -0,0 +1,75 @@
1
+ # Measures performance of connected ports.
2
+ #
3
+ # Formulas are minimal to factor out C library time.
4
+
5
+ require 'redshift'
6
+
7
+ include RedShift
8
+
9
+ module Connect
10
+ class Source < Component
11
+ continuous :t
12
+ flow do
13
+ diff " t' = 1 "
14
+ end
15
+ end
16
+
17
+ class Sink < Component
18
+ input :t
19
+ flow do
20
+ diff " u' = t "
21
+ end
22
+ end
23
+
24
+ class Connector < Component
25
+ input :t
26
+ end
27
+
28
+ def self.make_world n=1
29
+ w = World.new
30
+ w.input_depth_limit = n
31
+ source = w.create(Source)
32
+ prev = source
33
+ n.times do
34
+ w.create(Connector) do |c|
35
+ c.port(:t) << prev.port(:t)
36
+ prev = c
37
+ end
38
+ end
39
+ sink = w.create(Sink) do |s|
40
+ s.port(:t) << prev.port(:t)
41
+ end
42
+ w
43
+ end
44
+
45
+ def self.do_bench
46
+ [ #[ 1, 1_000_000],
47
+ [ 10, 100_000],
48
+ [ 100, 10_000],
49
+ [ 1_000, 1_000],
50
+ [ 10_000, 100],
51
+ [ 100_000, 10] ].each do
52
+ | n_c, n_s|
53
+
54
+ w = make_world(n_c)
55
+ w.run 1 # warm up
56
+ r = bench do
57
+ w.run(n_s)
58
+ end
59
+
60
+ yield " - %10d comps X %10d steps: %8.2f" % [n_c, n_s, r]
61
+ end
62
+ end
63
+ end
64
+
65
+ if __FILE__ == $0
66
+
67
+ require 'bench'
68
+ w = Connect.make_world(1000)
69
+ time = bench do
70
+ w.run(1000)
71
+ end
72
+ p time
73
+
74
+ end
75
+
@@ -0,0 +1,71 @@
1
+ # Measures performance of redshift as an integrator with dynamically
2
+ # linked flows.
3
+ #
4
+ # Formulas are minimal to factor out C library time.
5
+
6
+ require 'redshift'
7
+
8
+ include RedShift
9
+
10
+ module LinkedFlows
11
+ class C < Component
12
+ strictly_continuous :x
13
+ strict_link :d => 'LinkedFlows::D'
14
+ flow do
15
+ diff " x' = d.y "
16
+ end
17
+ end
18
+
19
+ class D < Component
20
+ strictly_continuous :y
21
+ strict_link :c => C
22
+ flow do
23
+ diff " y' = -c.x "
24
+ end
25
+ end
26
+
27
+ def self.make_world n=1
28
+ w = World.new
29
+ n.times do
30
+ w.create(C) do |c|
31
+ c.d = w.create(D) do |d|
32
+ d.c = c
33
+ d.y = 1.0
34
+ end
35
+ c.x = 0.0
36
+ end
37
+ end
38
+ w
39
+ end
40
+
41
+ def self.do_bench
42
+ [ [ 1, 1_000_000],
43
+ [ 10, 100_000],
44
+ [ 100, 10_000],
45
+ [ 1_000, 1_000],
46
+ [ 10_000, 100],
47
+ [ 100_000, 10] ].each do
48
+ | n_c, n_s|
49
+
50
+ w = make_world(n_c)
51
+ w.run 1 # warm up
52
+ r = bench do
53
+ w.run(n_s)
54
+ end
55
+
56
+ yield " - %10d comps X %10d steps: %8.2f" % [n_c, n_s, r]
57
+ end
58
+ end
59
+ end
60
+
61
+ if __FILE__ == $0
62
+
63
+ require 'bench'
64
+ w = LinkedFlows.make_world(500)
65
+ time = bench do
66
+ w.run(500)
67
+ end
68
+ p time
69
+
70
+ end
71
+
@@ -0,0 +1,201 @@
1
+ # Show some of the hooks that can be dynamically compiled into a redshift
2
+ # simulation. All you have to do is define the following methods in the
3
+ # World class or your own subclass, and the hooks will be called when
4
+ # the world runs. Some hooks take arguments, such the component being
5
+ # handled. In all cases, if you do not define the hook, the code to call it
6
+ # is not generated, so there is no cost.
7
+ #
8
+ # grep -o -P 'hook_\w+' world-gen.rb | sort | uniq
9
+ #
10
+ # hook_begin
11
+ # hook_begin_eval_events
12
+ # hook_begin_eval_resets
13
+ # hook_begin_parallel_assign
14
+ # hook_begin_step
15
+ # hook_call_action
16
+ # hook_can_sync
17
+ # hook_end
18
+ # hook_end_eval_events
19
+ # hook_end_eval_resets
20
+ # hook_end_parallel_assign
21
+ # hook_end_step
22
+ # hook_enter_action_phase
23
+ # hook_enter_eval_phase
24
+ # hook_enter_guard_phase
25
+ # hook_enter_post_phase
26
+ # hook_enter_sync_phase
27
+ # hook_eval_event
28
+ # hook_eval_guard
29
+ # hook_eval_port_connect
30
+ # hook_eval_reset_constant
31
+ # hook_eval_reset_continuous
32
+ # hook_eval_reset_link
33
+ # hook_export_events
34
+ # hook_finish_transition
35
+ # hook_leave_action_phase
36
+ # hook_leave_eval_phase
37
+ # hook_leave_guard_phase
38
+ # hook_leave_post_phase
39
+ # hook_leave_sync_phase
40
+ # hook_pat
41
+ # hook_remove_comp
42
+ # hook_start_transition
43
+ # hook_sync_step
44
+
45
+ require 'redshift'
46
+
47
+ include RedShift
48
+
49
+ class Example < Component
50
+ state :S
51
+ continuous :x, :y
52
+
53
+ flow S do
54
+ diff "x' = 1"
55
+ end
56
+
57
+ transition Enter => S do
58
+ reset :x => 0
59
+ end
60
+
61
+ transition S => S do
62
+ guard "x > 1"
63
+ reset :x => 0, :y => "y+1"
64
+ end
65
+ end
66
+
67
+ # Can do this in World itself, or in a subclass
68
+ class ExampleWorld < World
69
+ def hook_begin
70
+ puts "world step #{step_count}"
71
+ puts " hook_begin"
72
+ end
73
+
74
+ def hook_end
75
+ puts " hook_end #{discrete_step}"
76
+ end
77
+
78
+ def hook_begin_step
79
+ puts " hook_begin_step #{discrete_step}"
80
+ end
81
+
82
+ def hook_end_step
83
+ puts " hook_end_step #{discrete_step}"
84
+ end
85
+
86
+ def hook_enter_guard_phase
87
+ puts " hook_enter_guard_phase #{discrete_step}"
88
+ end
89
+
90
+ def hook_leave_guard_phase
91
+ puts " hook_leave_guard_phase #{discrete_step}"
92
+ end
93
+
94
+ def hook_enter_action_phase
95
+ puts " hook_enter_proc_phase #{discrete_step}"
96
+ end
97
+
98
+ def hook_leave_action_phase
99
+ puts " hook_leave_proc_phase #{discrete_step}"
100
+ end
101
+
102
+ def hook_begin_parallel_assign
103
+ puts " hook_begin_parallel_assign #{discrete_step}"
104
+ end
105
+
106
+ def hook_end_parallel_assign
107
+ puts " hook_end_parallel_assign #{discrete_step}"
108
+ end
109
+
110
+ def hook_start_transition(comp, trans, dest)
111
+ puts " hook_start_transition:"
112
+ puts " %p" % [[comp, trans, dest]]
113
+ end
114
+
115
+ def hook_finish_transition(comp, trans, dest)
116
+ puts " hook_finish_transition:"
117
+ puts " %p" % [[comp, trans.class, dest]]
118
+ end
119
+
120
+ def hook_eval_guard(comp, guard, enabled, trans, dest)
121
+ puts " hook_eval_guard:"
122
+ puts " %p" % [[comp, guard, enabled, trans, dest]]
123
+ end
124
+
125
+ def hook_enter_sync_phase
126
+ puts " hook_enter_sync_phase #{discrete_step}"
127
+ end
128
+
129
+ def hook_leave_sync_phase
130
+ puts " hook_leave_sync_phase #{discrete_step}"
131
+ end
132
+
133
+ def hook_sync_step curr_S, changed
134
+ puts " hook_sync_step, changed = #{changed.inspect}:"
135
+ puts " %p" % [curr_S]
136
+ end
137
+
138
+ def hook_can_sync comp, can_sync
139
+ puts " hook_can_sync, can_sync = #{can_sync.inspect}:"
140
+ puts " %p" % [comp]
141
+ end
142
+
143
+ def hook_call_action(comp, pr)
144
+ puts " hook_call_proc:"
145
+ puts " %p" % [[comp, pr]]
146
+ file, lineno = pr.inspect.scan(/@(.*):(\d+)>\Z/)[0] ## better way?
147
+ lineno = lineno.to_i - 1
148
+ puts extract_code_block(file, lineno)
149
+ rescue Errno::ENOENT
150
+ puts " can't open file #{File.expand_path(file)}"
151
+ end
152
+
153
+ ## put in a lib somewhere--as inspect methods for proc subclasses?
154
+ def extract_code_block(file, lineno)
155
+ result = ""
156
+ File.open(file) do |f|
157
+ lineno.times {f.gets}
158
+ line = f.gets
159
+ result << line
160
+
161
+ first_indent = (line =~ /\S/)
162
+ loop do
163
+ str = f.gets
164
+ indent = (str =~ /\S/)
165
+ if indent > first_indent or
166
+ (indent == first_indent and str =~ /\A\s*(\}|end)/)
167
+ result << str
168
+ end
169
+ break if indent <= first_indent
170
+ end
171
+ end
172
+ result
173
+ end
174
+
175
+ def hook_eval_event(comp, event, event_value)
176
+ puts " hook_export_event:"
177
+ puts " %p" % [[comp, event, event_value]]
178
+ end
179
+
180
+ def hook_eval_reset_constant(comp, var, val)
181
+ puts " reset constant #{var} to #{val} in #{comp}"
182
+ end
183
+
184
+ def hook_eval_reset_continuous(comp, var, val)
185
+ puts " reset continuous #{var.name} to #{val} in #{comp}"
186
+ end
187
+
188
+ def hook_eval_reset_link(comp, var, val)
189
+ puts " reset link #{var} to #{val} in #{comp}"
190
+ end
191
+
192
+ def hook_not_a_known_hook
193
+ # This will generate a warning, since it is not a known hook.
194
+ end
195
+ end
196
+
197
+ world = ExampleWorld.new
198
+ comp = world.create(Example)
199
+
200
+ world.evolve 1.2
201
+ p world