xpflow 0.1b → 0.1c
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/bin/xpflow +19 -5
- data/lib/xpflow/cmdline.rb +4 -4
- data/lib/xpflow/data.rb +97 -70
- data/lib/xpflow/exts/g5k.rb +0 -2
- data/lib/xpflow/nodes.rb +21 -11
- data/lib/xpflow/stdlib.rb +52 -14
- metadata +1 -1
data/bin/xpflow
CHANGED
@@ -47,12 +47,26 @@ def usage
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def use(*args)
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
# obsolete, but backwards compatible 'use'
|
51
|
+
return import(*args)
|
52
|
+
end
|
53
|
+
|
54
|
+
def import_via_name(name)
|
55
|
+
# TODO: it should be more sophisticated
|
56
|
+
name = name.to_s
|
57
|
+
begin
|
58
|
+
Kernel.load("./#{name}")
|
59
|
+
rescue LoadError
|
60
|
+
Kernel.require("xpflow/exts/#{name}_use")
|
61
|
+
end
|
62
|
+
end
|
53
63
|
|
54
|
-
|
55
|
-
|
64
|
+
def import(*args)
|
65
|
+
if args.length == 0
|
66
|
+
raise "Import requires a file or a library"
|
67
|
+
end
|
68
|
+
args.each do |it|
|
69
|
+
import_via_name(it)
|
56
70
|
end
|
57
71
|
end
|
58
72
|
|
data/lib/xpflow/cmdline.rb
CHANGED
@@ -131,12 +131,12 @@ module XPFlow
|
|
131
131
|
@config[:labels] += labels.split(',').map { |x| x.downcase.to_sym }
|
132
132
|
end
|
133
133
|
|
134
|
-
opts.on("-
|
134
|
+
opts.on("-i", "--ignore-checkpoints", "Ignore automatically saved checkpoints") do
|
135
135
|
@config[:ignore_checkpoints] = true
|
136
136
|
end
|
137
|
-
|
138
|
-
|
139
|
-
|
137
|
+
opts.on("-c", "--checkpoint NAME", "Jump to checkpoint NAME (if exists)") do |name|
|
138
|
+
@config[:checkpoint] = name
|
139
|
+
end
|
140
140
|
# opts.on("-c", "--list-checkpoints", "List available checkpoints") do
|
141
141
|
# @config[:instead] += [ RunInfo.new(:list_checkpoints) ]
|
142
142
|
# end
|
data/lib/xpflow/data.rb
CHANGED
@@ -48,58 +48,87 @@ module XPFlow
|
|
48
48
|
return average_stddev().last
|
49
49
|
end
|
50
50
|
|
51
|
-
#
|
51
|
+
# START OF DISTRIBUTIONS
|
52
|
+
|
53
|
+
# Credit for cdf_inverse : http://home.online.no/~pjacklam/notes/invnorm/
|
52
54
|
# inverse standard normal cumulative distribution function
|
53
|
-
def cdf_inverse(p)
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
end
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
55
|
+
def self.cdf_inverse(p)
|
56
|
+
a = [0, -3.969683028665376e+01, 2.209460984245205e+02, -2.759285104469687e+02, 1.383577518672690e+02, -3.066479806614716e+01, 2.506628277459239e+00]
|
57
|
+
b = [0, -5.447609879822406e+01, 1.615858368580409e+02, -1.556989798598866e+02, 6.680131188771972e+01, -1.328068155288572e+01]
|
58
|
+
c = [0, -7.784894002430293e-03, -3.223964580411365e-01, -2.400758277161838e+00, -2.549732539343734e+00, 4.374664141464968e+00, 2.938163982698783e+00]
|
59
|
+
d = [0, 7.784695709041462e-03, 3.224671290700398e-01, 2.445134137142996e+00, 3.754408661907416e+00]
|
60
|
+
#Define break-points.
|
61
|
+
p_low = 0.02425
|
62
|
+
p_high = 1.0 - p_low
|
63
|
+
|
64
|
+
x = 0.0
|
65
|
+
q = 0.0
|
66
|
+
#Rational approximation for lower region.
|
67
|
+
if 0.0 < p && p < p_low
|
68
|
+
q = Math.sqrt(-2.0*Math.log(p))
|
69
|
+
x = (((((c[1]*q+c[2])*q+c[3])*q+c[4])*q+c[5])*q+c[6]) / ((((d[1]*q+d[2])*q+d[3])*q+d[4])*q+1.0)
|
70
|
+
|
71
|
+
#Rational approximation for central region.
|
72
|
+
elsif p_low <= p && p <= p_high
|
73
|
+
q = p - 0.5
|
74
|
+
r = q*q
|
75
|
+
x = (((((a[1]*r+a[2])*r+a[3])*r+a[4])*r+a[5])*r+a[6])*q / (((((b[1]*r+b[2])*r+b[3])*r+b[4])*r+b[5])*r+1.0)
|
76
|
+
|
77
|
+
#Rational approximation for upper region.
|
78
|
+
elsif p_high < p && p < 1.0
|
79
|
+
q = Math.sqrt(-2.0*Math.log(1.0-p))
|
80
|
+
x = -(((((c[1]*q+c[2])*q+c[3])*q+c[4])*q+c[5])*q+c[6]) / ((((d[1]*q+d[2])*q+d[3])*q+d[4])*q+1.0)
|
81
|
+
end
|
82
|
+
|
83
|
+
#The relative error of the approximation has
|
84
|
+
#absolute value less than 1.15 × 10−9. One iteration of
|
85
|
+
#Halley’s rational method (third order) gives full machine precision.
|
86
|
+
if 0 < p && p < 1
|
87
|
+
e = 0.5 * Math.erfc(-x/Math.sqrt(2.0)) - p
|
88
|
+
u = e * Math.sqrt(2.0*Math::PI) * Math.exp((x**2.0)/2.0)
|
89
|
+
x = x - u/(1.0 + x*u/2.0)
|
90
|
+
end
|
91
|
+
return x
|
92
|
+
end
|
93
|
+
|
94
|
+
# computes confidence interval, assuming that
|
95
|
+
# the number of measures is large enough
|
96
|
+
# to be approximated with CLT
|
97
|
+
# prec is ABSOLUTE (here and below)
|
98
|
+
|
99
|
+
def _compute_dist(prec, conf, cvalue)
|
100
|
+
m, s = average_stddev()
|
101
|
+
d = (cvalue * s).to_f / (@values.length ** 0.5)
|
102
|
+
sample = ((cvalue * s / prec) ** 2).to_i + 1
|
103
|
+
return {
|
104
|
+
:interval => [ m - d, m + d ],
|
105
|
+
:d => d,
|
106
|
+
:sample => sample
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
def _dist(name, prec, conf)
|
111
|
+
r = case name
|
112
|
+
when :n then _dist_n(prec, conf)
|
113
|
+
when :t then _dist_t(prec, conf)
|
114
|
+
else
|
115
|
+
raise "Unknown distribution: #{name}"
|
116
|
+
end
|
117
|
+
return r
|
118
|
+
end
|
119
|
+
|
120
|
+
def _dist_n(prec, conf)
|
121
|
+
cvalue = ValueData.cdf_inverse((1 + conf) * 0.5)
|
122
|
+
return _compute_dist(prec, conf, cvalue)
|
123
|
+
end
|
124
|
+
|
125
|
+
def confidence_interval_n(conf)
|
126
|
+
return _dist_n(1.0, conf)[:interval]
|
127
|
+
end
|
128
|
+
|
129
|
+
# computes the minimal sample size
|
130
|
+
def minimal_sample_n(prec, conf)
|
131
|
+
return _dist_n(prec, conf)[:sample]
|
103
132
|
end
|
104
133
|
|
105
134
|
TSTUDENT = [
|
@@ -108,33 +137,31 @@ module XPFlow
|
|
108
137
|
2.074, 2.069, 2.064, 2.060, 2.056, 2.052, 2.048, 2.045, 2.042, 2.021, 2.009,
|
109
138
|
2.000, 1.990, 1.984, 1.980, 1.960 ]
|
110
139
|
|
111
|
-
def
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
factor = TSTUDENT[size()]
|
116
|
-
end
|
117
|
-
m, s = average_stddev()
|
118
|
-
d = (factor * s).to_f / (@values.length ** 0.5)
|
119
|
-
return [m - d, m + d]
|
140
|
+
def _get_tstudent_factor
|
141
|
+
n = size()
|
142
|
+
raise "size of sample must be positive" if n <= 0
|
143
|
+
return (n < TSTUDENT.length) ? TSTUDENT[n] : TSTUDENT[-1]
|
120
144
|
end
|
121
145
|
|
122
|
-
def
|
123
|
-
|
124
|
-
return (
|
146
|
+
def _dist_t(prec, conf)
|
147
|
+
cvalue = _get_tstudent_factor()
|
148
|
+
return _compute_dist(prec, conf, cvalue)
|
125
149
|
end
|
126
150
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
151
|
+
# computes confidence interval, assuming that
|
152
|
+
# each measure is normal; therefore their
|
153
|
+
# average is t-student
|
154
|
+
def confidence_interval_t(conf)
|
155
|
+
# TODO: confidence is ignored
|
156
|
+
return _dist_t(1.0, conf)[:interval]
|
132
157
|
end
|
133
158
|
|
134
|
-
def
|
135
|
-
return
|
159
|
+
def minimal_sample_t(prec, conf)
|
160
|
+
return _dist_t(prec, conf)[:sample]
|
136
161
|
end
|
137
162
|
|
163
|
+
# END OF DISTRIBUTIONS
|
164
|
+
|
138
165
|
def map(&block)
|
139
166
|
arr = @values.map(&block)
|
140
167
|
return ValueData.new(arr)
|
data/lib/xpflow/exts/g5k.rb
CHANGED
data/lib/xpflow/nodes.rb
CHANGED
@@ -458,7 +458,8 @@ module XPFlow
|
|
458
458
|
:bootstrap_taktuk, :simple_node, :node_range, :taktuk_raw, :test_connectivity,
|
459
459
|
:nodes_from_file, :nodes_from_result, :distribute, :chain_copy, :ssh_key,
|
460
460
|
:nodes_from_machinefile, :g5k_deploy_keys, :localhost, :file_consistency,
|
461
|
-
:ping_localhost, :ping_node, :g5k_reserve_nodes
|
461
|
+
:ping_localhost, :ping_node, :g5k_reserve_nodes,
|
462
|
+
:g5k_sites
|
462
463
|
|
463
464
|
def setup
|
464
465
|
nil
|
@@ -975,21 +976,30 @@ module XPFlow
|
|
975
976
|
return true
|
976
977
|
end
|
977
978
|
|
978
|
-
def
|
979
|
-
p = proxy()
|
979
|
+
def with_g5k_lib(p)
|
980
980
|
lib = G5K::Library.new
|
981
981
|
lib.logging = proc { |x| p.engine.log(x) }
|
982
|
-
lib.proxy =
|
983
|
-
return lib
|
982
|
+
lib.proxy = p
|
983
|
+
return yield(lib)
|
984
|
+
|
985
|
+
end
|
986
|
+
|
987
|
+
def g5k_reserve_nodes(*args)
|
988
|
+
with_g5k_lib(proxy) do |lib|
|
989
|
+
lib.reserve_nodes(*args)
|
990
|
+
end
|
991
|
+
end
|
992
|
+
|
993
|
+
def g5k_sites(*args)
|
994
|
+
with_g5k_lib(proxy) do |lib|
|
995
|
+
lib.sites()
|
996
|
+
end
|
984
997
|
end
|
985
998
|
|
986
999
|
def g5k_get_avail(opts = {})
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
lib.proxy = proxy
|
991
|
-
job = lib.pick_reservation(opts)
|
992
|
-
return job
|
1000
|
+
with_g5k_lib(proxy) do |lib|
|
1001
|
+
lib.pick_reservation(opts)
|
1002
|
+
end
|
993
1003
|
end
|
994
1004
|
|
995
1005
|
def nodes_file(user, filepath)
|
data/lib/xpflow/stdlib.rb
CHANGED
@@ -84,8 +84,9 @@ module XPFlow
|
|
84
84
|
return result
|
85
85
|
end
|
86
86
|
|
87
|
-
def value(
|
88
|
-
return
|
87
|
+
def value(*args)
|
88
|
+
return args.first if args.length == 1
|
89
|
+
return args
|
89
90
|
end
|
90
91
|
|
91
92
|
def code(*args)
|
@@ -249,9 +250,9 @@ module XPFlow
|
|
249
250
|
class DataLibrary < SyncedActivityLibrary
|
250
251
|
|
251
252
|
activities :store, :data, :avg, :sum, :stddev, :gauss,
|
252
|
-
:
|
253
|
-
:data_vector, :
|
254
|
-
:run_later, :get_of, :minimal_sample, :
|
253
|
+
:conf_interval, :save_yaml,
|
254
|
+
:data_vector, :data_push,
|
255
|
+
:run_later, :get_of, :minimal_sample, :sample_enough
|
255
256
|
|
256
257
|
def data_vector(values = nil)
|
257
258
|
return ValueData.new(values)
|
@@ -318,10 +319,6 @@ module XPFlow
|
|
318
319
|
return m + s * Math.cos(2*Math::PI*x) * p
|
319
320
|
end
|
320
321
|
|
321
|
-
def data_append(data, x)
|
322
|
-
return data.append(x)
|
323
|
-
end
|
324
|
-
|
325
322
|
def data_push(data, x)
|
326
323
|
data.push(x)
|
327
324
|
end
|
@@ -353,13 +350,54 @@ module XPFlow
|
|
353
350
|
def save_yaml(filename, obj)
|
354
351
|
IO.write(filename, obj.to_yaml)
|
355
352
|
end
|
356
|
-
|
357
|
-
|
353
|
+
|
354
|
+
# opts:
|
355
|
+
# :dist => distribution type (default: :normal, also: :n, :t, :tstudent)
|
356
|
+
# :conf => confidence (default: 0.95)
|
357
|
+
# :rel => relative precision in percents (default: 0.1)
|
358
|
+
# :abs => absolute precision (e.g., 5)
|
359
|
+
|
360
|
+
def _parse_sample_opts(v, _opts)
|
361
|
+
opts = { :conf => 0.95, :rel => 0.1, :abs => nil, :dist => :n }.merge(_opts)
|
362
|
+
dists = { :n => :n, :normal => :n, :t => :t, :tstudent => :t }
|
363
|
+
opts[:dist] = dists[opts[:dist]]
|
364
|
+
raise "Wrong confidence" if (opts[:conf] <= 0.0 or opts[:conf] >= 1.0)
|
365
|
+
if opts[:abs].nil?
|
366
|
+
opts[:abs] = v.average() * opts[:rel]
|
367
|
+
end
|
368
|
+
opts[:info] = v._dist(opts[:dist], opts[:abs], opts[:conf])
|
369
|
+
return opts
|
358
370
|
end
|
359
|
-
|
360
|
-
|
361
|
-
|
371
|
+
|
372
|
+
def flatten_data(x)
|
373
|
+
if x.is_a?(Array)
|
374
|
+
return ValueData.new(x)
|
375
|
+
elsif x.is_a?(ValueData)
|
376
|
+
return x
|
377
|
+
else
|
378
|
+
raise "Wrong data type: #{x.class}"
|
379
|
+
end
|
362
380
|
end
|
381
|
+
|
382
|
+
def sample_enough(v, opts = {})
|
383
|
+
v = flatten_data(v)
|
384
|
+
opts = _parse_sample_opts(v, opts)
|
385
|
+
info = opts[:info]
|
386
|
+
return info[:d] <= opts[:abs]
|
387
|
+
end
|
388
|
+
|
389
|
+
def minimal_sample(v, opts = {})
|
390
|
+
v = flatten_data(v)
|
391
|
+
opts = _parse_sample_opts(v, opts)
|
392
|
+
return opts[:info][:sample]
|
393
|
+
end
|
394
|
+
|
395
|
+
def conf_interval(v, opts = {})
|
396
|
+
v = flatten_data(v)
|
397
|
+
opts = _parse_sample_opts(v, opts)
|
398
|
+
return opts[:info][:interval]
|
399
|
+
end
|
400
|
+
|
363
401
|
end
|
364
402
|
|
365
403
|
class TestLibrary < SyncedActivityLibrary
|