datafarming 2.2.0 → 2.3.0

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.
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: []