redshift 1.3.21 → 1.3.22

Sign up to get free protection for your applications and to get access to all the features.
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