datafarming 2.1.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.md +1 -1
- data/README.md +2 -0
- data/exe/generate_design.rb +107 -83
- data/lib/datafarming/freq_sets.rb +45 -891
- data/lib/datafarming/version.rb +1 -1
- metadata +3 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d7589dc50c37a95f61fcd663202a51b54f5dcab18b40f06fd82a7ca6335a0ae
|
4
|
+
data.tar.gz: be600740132b28b59ee3b0b11b45dffaa630023b2babc884bb732efdb0757d49
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d734fadf28fdef038fbb3f4cc9ee0b0d836d0c388345a005ecd3d9609396b411e527e7f408832a69dade7414ae01c1d016fc16a475be9b6a91045390c88fa44
|
7
|
+
data.tar.gz: 51122d843649187c2e335244b532d1df783fb100c5f0588f9965e604d1570a4cd036b44694590d1368087e13f2eff4649261803d23943512ca9c8032a1afae7b
|
data/LICENSE.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
The MIT License (MIT)
|
3
3
|
|
4
|
-
Copyright (c) 2017-
|
4
|
+
Copyright (c) 2017-2024 Paul J. Sanchez
|
5
5
|
|
6
6
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
7
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -21,3 +21,5 @@ Gem installation only needs to be done once. If you explicitly downloaded the `
|
|
21
21
|
Ruby is a powerful and concise object-oriented scripting language. Normally, Ruby scripts are run from a command-line or terminal environment by typing the `ruby` command followed by a script name, often followed by one or more command-line arguments. However, scripts installed as gems do not need the `ruby` command to be typed explicitly. For example, typing `stripheaderdups.rb my_file.txt` will invoke the `stripheaderdups.rb` script and apply it to file `my_file.txt` in your current working directory. Note that on Windows the `.rb` suffix is not needed to run your scripts, e.g., `stripheaderdups my_file.txt` will suffice.
|
22
22
|
|
23
23
|
All scripts in this distribution are self documenting if run with a `--help`, or `-h` option. You can run the command `datafarming.rb` at any point after installing this gem to see descriptions of the various data farming utilities included in thie distribution.
|
24
|
+
|
25
|
+
After installing the gem and making sure that gems are on your PATH, run the command `datafarming.rb` for a summary/overview of the various data farming tools.
|
data/exe/generate_design.rb
CHANGED
@@ -62,15 +62,15 @@ EXAMPLES = [
|
|
62
62
|
" by whitespace.",
|
63
63
|
'',
|
64
64
|
'EXAMPLE 3:',
|
65
|
-
"\n #{File.basename($PROGRAM_NAME)} -d nolh -k 5 --output_yaml > my_template.
|
65
|
+
"\n #{File.basename($PROGRAM_NAME)} -d nolh -k 5 --output_yaml > my_template.yml",
|
66
66
|
"\n Generate a YAML template for a 5-factor NOLH design, and redirect it",
|
67
|
-
" to the file 'my_template.
|
67
|
+
" to the file 'my_template.yml'. (The output file can be given any name",
|
68
68
|
' of your choosing.) The resulting YAML file has an intuitive human',
|
69
69
|
" readable format. It can be edited using your favorite programmer's",
|
70
70
|
' text editor (NOTE: word processors will not work!). After saving your',
|
71
71
|
' revisions, you can read it back in to generate the actual design using',
|
72
72
|
" the '--input_yaml' option:\n",
|
73
|
-
" #{File.basename($PROGRAM_NAME)} --input_yaml
|
73
|
+
" #{File.basename($PROGRAM_NAME)} --input_yaml my_template.yml",
|
74
74
|
' '
|
75
75
|
].freeze
|
76
76
|
|
@@ -91,34 +91,40 @@ def examples(opts)
|
|
91
91
|
exit
|
92
92
|
end
|
93
93
|
|
94
|
+
def fatal_err(msg)
|
95
|
+
STDERR.puts msg
|
96
|
+
exit 1
|
97
|
+
end
|
98
|
+
|
94
99
|
def resv(options)
|
95
100
|
require 'datafarming/res_v_seqs'
|
96
|
-
|
97
|
-
|
98
|
-
RESV.make_design
|
101
|
+
num_factors = options[:specs].size
|
102
|
+
fatal_err("Too many factors for ResV designs") if num_factors > RESV::INDEX.size
|
103
|
+
RESV.make_design num_factors
|
99
104
|
end
|
100
105
|
|
101
106
|
def ccd(options)
|
102
107
|
require 'datafarming/res_v_seqs'
|
103
|
-
|
104
|
-
|
105
|
-
RESV.make_design(
|
108
|
+
num_factors = options[:specs].size
|
109
|
+
fatal_err("Too many factors for CCD designs") if num_factors > RESV::INDEX.size
|
110
|
+
RESV.make_design(num_factors) + RESV.star_pts(num_factors)
|
106
111
|
end
|
107
112
|
|
108
113
|
def rotatable(options)
|
109
114
|
require 'datafarming/res_v_seqs'
|
110
|
-
|
111
|
-
|
112
|
-
inv_len = 1.0 / Math.sqrt(
|
113
|
-
RESV.make_design(
|
115
|
+
num_factors = options[:specs].size
|
116
|
+
fatal_err("Too many factors for Rotatable designs") if num_factors > RESV::INDEX.size
|
117
|
+
inv_len = 1.0 / Math.sqrt(num_factors)
|
118
|
+
RESV.make_design(num_factors).each do |line|
|
114
119
|
line.map! { |value| value * inv_len }
|
115
|
-
end + RESV.star_pts(
|
120
|
+
end + RESV.star_pts(num_factors)
|
116
121
|
end
|
117
122
|
|
118
123
|
def nolh(options)
|
119
124
|
require 'datafarming/nolh_designs'
|
125
|
+
num_factors = options[:specs].size
|
120
126
|
minimal_size =
|
121
|
-
case
|
127
|
+
case num_factors
|
122
128
|
when 1..7
|
123
129
|
17
|
124
130
|
when 8..11
|
@@ -132,32 +138,28 @@ def nolh(options)
|
|
132
138
|
when 30..100
|
133
139
|
512
|
134
140
|
else
|
135
|
-
|
141
|
+
fatal_err "invalid number of factors: #{num_factors}"
|
136
142
|
end
|
137
|
-
|
138
143
|
options[:levels] ||= minimal_size
|
139
|
-
|
140
|
-
|
141
|
-
"too small for #{options[:num_factors]} factors."
|
142
|
-
end
|
143
|
-
|
144
|
+
fatal_err("Latin hypercube with #{options[:levels]} levels is " \
|
145
|
+
"too small for #{num_factors} factors.") if options[:levels] < minimal_size
|
144
146
|
NOLH::DESIGN_TABLE[options[:levels]]
|
145
147
|
end
|
146
148
|
|
147
149
|
def freqs2cols(options, design_set)
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
ds = design_set[options[:num_factors]]
|
150
|
+
num_factors = options[:specs].size
|
151
|
+
fatal_err("No design (yet) for #{num_factors} factors") unless design_set.key? num_factors
|
152
|
+
design_num = 0 # most have only one design after removing isomorphisms
|
153
|
+
ds = design_set[num_factors]
|
154
154
|
freqs = ds.freqs[design_num]
|
155
155
|
Array.new(freqs.size) do |row|
|
156
156
|
omega = freqs[row]
|
157
|
-
Array.new(ds.nyq) do |i|
|
157
|
+
v = Array.new(ds.nyq) do |i|
|
158
158
|
f = ((i * omega) % ds.nyq).to_f / ds.nyq
|
159
159
|
Math.sin(f * TWO_PI)
|
160
160
|
end
|
161
|
+
scale_factor = v.max
|
162
|
+
v.map { |x| (x / scale_factor).round(15) }
|
161
163
|
end.transpose
|
162
164
|
end
|
163
165
|
|
@@ -174,17 +176,15 @@ end
|
|
174
176
|
def validate_opts(options)
|
175
177
|
required_options = [:design]
|
176
178
|
missing = required_options - options.keys
|
177
|
-
|
178
|
-
|
179
|
+
fatal_err("Missing required options: --#{missing.join(', --')}") unless missing.empty?
|
179
180
|
options[:design] = options[:design].to_sym
|
180
181
|
end
|
181
182
|
|
182
183
|
def validate(spec)
|
183
184
|
unknown = spec.keys - REQUIRED_SPECS - ELECTIVE_SPECS
|
184
|
-
|
185
|
-
|
185
|
+
fatal_err("Unknown factor spec(s): #{unknown}") unless unknown.empty?
|
186
186
|
missing = REQUIRED_SPECS - spec.keys
|
187
|
-
|
187
|
+
fatal_err("Factor spec #{spec} missing #{missing}") unless missing.empty?
|
188
188
|
end
|
189
189
|
|
190
190
|
def optional_specs(factor_spec, i)
|
@@ -199,64 +199,89 @@ end
|
|
199
199
|
|
200
200
|
def parse_specs(options, remainder)
|
201
201
|
if remainder.size.positive?
|
202
|
-
|
203
|
-
|
204
|
-
elsif options.key? :num_factors
|
205
|
-
Array.new(options[:num_factors]) do |i|
|
206
|
-
{ "id": "X_#{format('%03d', (i + 1))}", "min": -1, "max": 1, "decimals": nil }
|
202
|
+
remainder.each.with_index do |factor_spec, i|
|
203
|
+
options[:specs] << optional_specs(factor_spec, i)
|
207
204
|
end
|
208
|
-
else
|
209
|
-
y_options, factor_specs = YAML.safe_load($stdin, permitted_classes: [Symbol])
|
210
|
-
y_options.each_key { |key| options[key] ||= y_options[key] }
|
211
|
-
factor_specs.each { |spec| validate(spec) }
|
212
205
|
end
|
213
206
|
end
|
214
207
|
|
215
208
|
def parse_args
|
216
|
-
|
209
|
+
default_options = {
|
217
210
|
headers: true,
|
218
211
|
replicate: 1,
|
219
212
|
stack: 1,
|
220
|
-
center: false
|
213
|
+
center: false,
|
214
|
+
specs: []
|
221
215
|
}
|
222
216
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
217
|
+
yaml_input = false
|
218
|
+
if ARGV.size > 2 && ARGV.any? { |elt| elt.eql?("-i") || elt.eql?("--input_yaml") }
|
219
|
+
STDERR.puts 'NOTE: All other arguments ignored when using YAML input'
|
220
|
+
end
|
221
|
+
|
222
|
+
options = default_options
|
223
|
+
|
224
|
+
begin
|
225
|
+
remainder = OptionParser.new do |opts|
|
226
|
+
opts.banner = HELP_MSG.join("\n")
|
227
|
+
opts.on('-h', '--help', 'Prints help') { prog_help(opts) }
|
228
|
+
opts.on('-v', '--verbose-help', 'Print more verbose help') { verbose(opts) }
|
229
|
+
opts.on('-x', '--examples', 'Show some examples') { examples(opts) }
|
230
|
+
opts.on('-d', '--design TYPE', DESIGN_TYPES,
|
231
|
+
'REQUIRED: Type of design, one of:',
|
232
|
+
" #{DESIGN_TYPES.join ' '}")
|
233
|
+
opts.on('-k', '--num_factors QTY', /[1-9][0-9]*/, Integer,
|
234
|
+
'Number of factors',
|
235
|
+
'Ignored if optional factor specs provided') do |k|
|
236
|
+
options[:specs] = Array.new(k) do |i|
|
237
|
+
{id: "X_#{format('%03d', (i + 1))}", :min => -1, :max => 1 }
|
238
|
+
end
|
239
|
+
k
|
240
|
+
end
|
241
|
+
opts.on('-r', '--replicate QTY', /[1-9][0-9]*/, Integer,
|
242
|
+
'Replicate QTY times', '(default: 1)')
|
243
|
+
opts.on('-s', '--stack QTY', /[1-9][0-9]*/, Integer,
|
244
|
+
'Stack QTY times', '(default: 1)')
|
245
|
+
opts.on('--[no-]center', 'NOTE: Applies only to stacked designs',
|
246
|
+
'Stacking includes center pt','(default: no-center)')
|
247
|
+
opts.on('--[no-]headers', 'Output has column headers', '(default: headers)')
|
248
|
+
opts.on('-l', '--levels QTY', Regexp.new("(#{LEVELS.join(')|(')})"),
|
249
|
+
Integer, 'NOTE: Applies only to NOLH designs',
|
250
|
+
'Number of levels in the base NOLH:',
|
251
|
+
" #{LEVELS.join ' '}")
|
252
|
+
opts.on('-o', '--output_yaml', 'Write design YAML to STDOUT')
|
253
|
+
opts.on("-i PATH", "--input_yaml", 'Read design YAML from PATH',
|
254
|
+
'Mutually exclusive with all other options, prints',
|
255
|
+
'warning to STDERR if other options are passed') do |path|
|
256
|
+
ARGV.clear
|
257
|
+
options = {specs: []}
|
258
|
+
yaml_input = true
|
259
|
+
YAML::safe_load_file(path, permitted_classes: [Symbol]).each do |k, v|
|
260
|
+
options.merge!({k.to_sym => v})
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end.parse!(into: options)
|
264
|
+
rescue OptionParser::ParseError => error
|
265
|
+
fatal_err("#{error}\n(-h or --help will show valid options)")
|
266
|
+
end
|
267
|
+
|
268
|
+
fatal_err("Levels option only valid for NOLH designs") if options[:levels] && options[:design] != :nolh
|
269
|
+
|
270
|
+
remainder = [] if yaml_input
|
271
|
+
if remainder.size.positive? && options[:specs].size.positive?
|
272
|
+
STDERR.puts 'NOTE: Num_factors ignored when using optional factor specs'
|
273
|
+
options[:specs] = []
|
274
|
+
end
|
275
|
+
options.delete(:num_factors) if options.include?(:num_factors)
|
276
|
+
|
277
|
+
parse_specs(options, remainder)
|
252
278
|
validate_opts options
|
253
|
-
|
279
|
+
options
|
254
280
|
end
|
255
281
|
|
256
282
|
def stack(design, num_stacks, centered)
|
257
283
|
return design if num_stacks < 2
|
258
|
-
|
259
|
-
|
284
|
+
fatal_err("Stacking #{num_stacks} times exceeds number of design columns") if num_stacks > design[0].length
|
260
285
|
num_stacks -= 1
|
261
286
|
result = design.transpose
|
262
287
|
if num_stacks > 0
|
@@ -273,25 +298,24 @@ def stack(design, num_stacks, centered)
|
|
273
298
|
result.transpose
|
274
299
|
end
|
275
300
|
|
276
|
-
|
277
301
|
ARGV << '--help' if ARGV.empty?
|
278
302
|
|
279
|
-
options
|
303
|
+
options = parse_args
|
280
304
|
|
281
305
|
if options[:output_yaml]
|
282
306
|
options.delete :output_yaml
|
283
|
-
puts
|
307
|
+
puts options.to_yaml
|
284
308
|
else
|
285
309
|
base_design = method(options[:design]).call(options)
|
286
310
|
separator = ','
|
287
|
-
puts Array.new(options[:
|
311
|
+
puts Array.new(options[:specs].size) { |i| options[:specs][i][:id] }.join(separator) if options[:headers]
|
288
312
|
|
289
313
|
# stack
|
290
314
|
design = stack(base_design, options[:stack], options[:center])
|
291
|
-
.transpose.first(options[:
|
315
|
+
.transpose.first(options[:specs].size).transpose
|
292
316
|
|
293
317
|
# scale
|
294
|
-
scaler = specs.map do |spec|
|
318
|
+
scaler = options[:specs].map do |spec|
|
295
319
|
Scaler.new(min: spec[:min], max: spec[:max], decimals: spec[:decimals])
|
296
320
|
end
|
297
321
|
|