datafarming 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a222e42c364401edf4bb67e403cc9169ca3935c74d4e21d428336ad535349218
4
- data.tar.gz: 929f66d57cb5997dbf1089f7436af8753a9cdf0f26e231d6e31b29c370f0a151
3
+ metadata.gz: 8d7589dc50c37a95f61fcd663202a51b54f5dcab18b40f06fd82a7ca6335a0ae
4
+ data.tar.gz: be600740132b28b59ee3b0b11b45dffaa630023b2babc884bb732efdb0757d49
5
5
  SHA512:
6
- metadata.gz: 02b975dbe89ee318131bb13439926c0fc4b1a99a2db1c6e97bfce34f7caf3235cb97fb9b04ac37a89934273bb83b04b522d5e7fc8ece8ed951a8e80422062f7c
7
- data.tar.gz: f9d61f4ec3b96a9cb8d51d826f05fdd8a44e191fd53b1a654368d9b4d6fca2dd80804b2061b418a942fc96255641c0c788ca13dd0c8b3b2f3d8cc70c9b938443
6
+ metadata.gz: 7d734fadf28fdef038fbb3f4cc9ee0b0d836d0c388345a005ecd3d9609396b411e527e7f408832a69dade7414ae01c1d016fc16a475be9b6a91045390c88fa44
7
+ data.tar.gz: 51122d843649187c2e335244b532d1df783fb100c5f0588f9965e604d1570a4cd036b44694590d1368087e13f2eff4649261803d23943512ca9c8032a1afae7b
@@ -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.yaml",
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.yaml'. (The output file can be given any name",
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 < my_template.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
- raise 'Too many factors for ResV designs' if options[:num_factors] > RESV::INDEX.size
97
-
98
- RESV.make_design options[:num_factors]
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
- raise 'Too many factors for CCD designs' if options[:num_factors] > RESV::INDEX.size
104
-
105
- RESV.make_design(options[:num_factors]) + RESV.star_pts(options[:num_factors])
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
- raise 'Too many factors for Rotatable designs' if options[:num_factors] > RESV::INDEX.size
111
-
112
- inv_len = 1.0 / Math.sqrt(options[:num_factors])
113
- RESV.make_design(options[:num_factors]).each do |line|
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(options[:num_factors])
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 options[:num_factors]
127
+ case num_factors
122
128
  when 1..7
123
129
  17
124
130
  when 8..11
@@ -132,25 +138,19 @@ def nolh(options)
132
138
  when 30..100
133
139
  512
134
140
  else
135
- raise "invalid number of factors: #{options[:num_factors]}"
141
+ fatal_err "invalid number of factors: #{num_factors}"
136
142
  end
137
-
138
143
  options[:levels] ||= minimal_size
139
- if options[:levels] < minimal_size
140
- raise "Latin hypercube with #{options[:levels]} levels is" \
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
- raise "No design (yet) for #{options[:num_factors]} factors" unless
149
- design_set.key? options[:num_factors]
150
-
150
+ num_factors = options[:specs].size
151
+ fatal_err("No design (yet) for #{num_factors} factors") unless design_set.key? num_factors
151
152
  design_num = 0 # most have only one design after removing isomorphisms
152
-
153
- ds = design_set[options[:num_factors]]
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]
@@ -176,17 +176,15 @@ end
176
176
  def validate_opts(options)
177
177
  required_options = [:design]
178
178
  missing = required_options - options.keys
179
- raise "Missing required options: #{missing}" unless missing.empty?
180
-
179
+ fatal_err("Missing required options: --#{missing.join(', --')}") unless missing.empty?
181
180
  options[:design] = options[:design].to_sym
182
181
  end
183
182
 
184
183
  def validate(spec)
185
184
  unknown = spec.keys - REQUIRED_SPECS - ELECTIVE_SPECS
186
- raise "Unknown factor spec(s): #{unknown}" unless unknown.empty?
187
-
185
+ fatal_err("Unknown factor spec(s): #{unknown}") unless unknown.empty?
188
186
  missing = REQUIRED_SPECS - spec.keys
189
- raise "Factor spec #{spec} missing #{missing}" unless missing.empty?
187
+ fatal_err("Factor spec #{spec} missing #{missing}") unless missing.empty?
190
188
  end
191
189
 
192
190
  def optional_specs(factor_spec, i)
@@ -201,64 +199,89 @@ end
201
199
 
202
200
  def parse_specs(options, remainder)
203
201
  if remainder.size.positive?
204
- options[:num_factors] = remainder.size
205
- remainder.map.with_index { |factor_spec, i| optional_specs(factor_spec, i) }
206
- elsif options.key? :num_factors
207
- Array.new(options[:num_factors]) do |i|
208
- { "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)
209
204
  end
210
- else
211
- y_options, factor_specs = YAML.safe_load($stdin, permitted_classes: [Symbol])
212
- y_options.each_key { |key| options[key] ||= y_options[key] }
213
- factor_specs.each { |spec| validate(spec) }
214
205
  end
215
206
  end
216
207
 
217
208
  def parse_args
218
- options = {
209
+ default_options = {
219
210
  headers: true,
220
211
  replicate: 1,
221
212
  stack: 1,
222
- center: false
213
+ center: false,
214
+ specs: []
223
215
  }
224
216
 
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')
236
- opts.on('-r', '--replicate=QTY', /[1-9][0-9]*/, Integer,
237
- 'Replicate QTY times', '(default: 1)')
238
- opts.on('-s', '--stack=QTY', /[1-9][0-9]*/, Integer,
239
- 'Stack QTY times', '(default: 1)')
240
- opts.on('--[no-]center', 'NOTE: Applies only to stacked designs',
241
- 'Stacking includes center pt','(default: no-center)')
242
- opts.on('--[no-]headers', 'Output has column headers', '(default: headers)')
243
- opts.on('-l', '--levels=QTY', Regexp.new("(#{LEVELS.join(')|(')})"),
244
- Integer, 'NOTE: Applies only to NOLH designs',
245
- 'Number of levels in the base NOLH:',
246
- " #{LEVELS.join ' '}")
247
- opts.on('-o', '--output_yaml', 'Write design YAML to STDOUT')
248
- opts.on('-i', '--input_yaml', 'Read design YAML from STDIN')
249
- end.parse!(into: options)
250
-
251
- raise 'Optional factor specs ignored when using YAML input' if options[:input_yaml] && remainder.size.positive?
252
-
253
- specs = parse_specs(options, remainder)
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)
254
278
  validate_opts options
255
- [options, specs]
279
+ options
256
280
  end
257
281
 
258
282
  def stack(design, num_stacks, centered)
259
283
  return design if num_stacks < 2
260
- raise "Stacking #{num_stacks} times exceeds number of design columns" if num_stacks > design[0].length
261
-
284
+ fatal_err("Stacking #{num_stacks} times exceeds number of design columns") if num_stacks > design[0].length
262
285
  num_stacks -= 1
263
286
  result = design.transpose
264
287
  if num_stacks > 0
@@ -275,25 +298,24 @@ def stack(design, num_stacks, centered)
275
298
  result.transpose
276
299
  end
277
300
 
278
-
279
301
  ARGV << '--help' if ARGV.empty?
280
302
 
281
- options, specs = parse_args
303
+ options = parse_args
282
304
 
283
305
  if options[:output_yaml]
284
306
  options.delete :output_yaml
285
- puts [options, specs].to_yaml
307
+ puts options.to_yaml
286
308
  else
287
309
  base_design = method(options[:design]).call(options)
288
310
  separator = ','
289
- puts Array.new(options[:num_factors]) { |i| specs[i][:id] }.join(separator) if options[:headers]
311
+ puts Array.new(options[:specs].size) { |i| options[:specs][i][:id] }.join(separator) if options[:headers]
290
312
 
291
313
  # stack
292
314
  design = stack(base_design, options[:stack], options[:center])
293
- .transpose.first(options[:num_factors]).transpose
315
+ .transpose.first(options[:specs].size).transpose
294
316
 
295
317
  # scale
296
- scaler = specs.map do |spec|
318
+ scaler = options[:specs].map do |spec|
297
319
  Scaler.new(min: spec[:min], max: spec[:max], decimals: spec[:decimals])
298
320
  end
299
321
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DataFarming
4
- VERSION = "2.2.0"
4
+ VERSION = "2.3.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datafarming
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul J Sanchez
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-12-11 00:00:00.000000000 Z
10
+ date: 2025-01-26 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: fwt
@@ -136,7 +135,6 @@ homepage: https://bitbucket.org/paul_j_sanchez/datafarmingrubyscripts
136
135
  licenses:
137
136
  - MIT
138
137
  metadata: {}
139
- post_install_message:
140
138
  rdoc_options: []
141
139
  require_paths:
142
140
  - lib
@@ -151,8 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
151
149
  - !ruby/object:Gem::Version
152
150
  version: '0'
153
151
  requirements: []
154
- rubygems_version: 3.5.23
155
- signing_key:
152
+ rubygems_version: 3.6.2
156
153
  specification_version: 4
157
154
  summary: Useful scripts for data farming.
158
155
  test_files: []