datafarming 1.3.0 → 2.1.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.
@@ -1,23 +1,23 @@
1
1
  require 'fwt'
2
2
 
3
- # Generate a Resolution V Fractional Factorial design for the specified
4
- # number of factors. The design is guaranteed to yield unconfounded
5
- # interactions for all pairs of factors. The design uses standardized
6
- # notation, i.e., -1 represents a low setting and 1 represents a high
7
- # setting for each factor.
8
- #
9
- # *Arguments*::
10
- # - +number_of_factors+ -> the number of factors in your design. Limit is 120.
11
- # *Returns*::
12
- # - a two-dimensional array specifying the design, where each column
13
- # corresponds to a factor and each row is a design point.
14
- #
15
- # Author:: Paul J Sanchez (mailto:pjs@alum.mit.edu)
16
- # Copyright:: Copyright (c) 2018 Paul J Sanchez
17
- # License:: MIT
18
- #
19
- def make_design(number_of_factors)
20
- index = [1, 2, 4, 8, 15, 16, 32, 51, 64, 85, 106, 128, 150, 171,
3
+ module RESV
4
+ # Generate a Resolution V Fractional Factorial design for the specified
5
+ # number of factors. The design is guaranteed to yield unconfounded
6
+ # interactions for all pairs of factors. The design uses standardized
7
+ # notation, i.e., -1 represents a low setting and 1 represents a high
8
+ # setting for each factor.
9
+ #
10
+ # *Arguments*::
11
+ # - +number_of_factors+ -> the number of factors in your design. Limit is 120.
12
+ # *Returns*::
13
+ # - a two-dimensional array specifying the design, where each column
14
+ # corresponds to a factor and each row is a design point.
15
+ #
16
+ # Author:: Paul J Sanchez (mailto:pjs@alum.mit.edu)
17
+ # Copyright:: Copyright (c) 2023 Paul J Sanchez
18
+ # License:: MIT
19
+ #
20
+ INDEX = [1, 2, 4, 8, 15, 16, 32, 51, 64, 85, 106, 128, 150, 171,
21
21
  219, 237, 247, 256, 279, 297, 455, 512, 537, 557, 594, 643, 803,
22
22
  863, 998, 1024, 1051, 1070, 1112, 1169, 1333, 1345, 1620, 1866,
23
23
  2048, 2076, 2085, 2185, 2372, 2456, 2618, 2800, 2873, 3127, 3284,
@@ -28,9 +28,8 @@ def make_design(number_of_factors)
28
28
  14_965, 15_125, 15_554, 16_384, 16_457, 16_517, 16_609, 16_771,
29
29
  16_853, 17_022, 17_453, 17_891, 18_073, 18_562, 18_980, 19_030,
30
30
  19_932, 20_075, 20_745, 21_544, 22_633, 23_200, 24_167, 25_700,
31
- 26_360, 26_591, 26_776, 28_443, 28_905, 29_577, 32_705
32
- ]
33
- power = [1, 2, 4, 8, 16, 16, 32, 64, 64, 128, 128, 128, 256, 256,
31
+ 26_360, 26_591, 26_776, 28_443, 28_905, 29_577, 32_705]
32
+ POWER = [1, 2, 4, 8, 16, 16, 32, 64, 64, 128, 128, 128, 256, 256,
34
33
  256, 256, 256, 256, 512, 512, 512, 512, 1024, 1024, 1024, 1024,
35
34
  1024, 1024, 1024, 1024, 2048, 2048, 2048, 2048, 2048, 2048, 2048,
36
35
  2048, 2048, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096,
@@ -42,14 +41,17 @@ def make_design(number_of_factors)
42
41
  32_768, 32_768, 32_768, 32_768, 32_768, 32_768, 32_768, 32_768,
43
42
  32_768, 32_768, 32_768, 32_768, 32_768, 32_768, 32_768, 32_768,
44
43
  32_768, 32_768, 32_768, 32_768, 32_768, 32_768, 32_768, 32_768,
45
- 32_768, 32_768, 32_768
46
- ]
44
+ 32_768, 32_768, 32_768]
47
45
 
48
- design = Array.new(number_of_factors)
49
- design.each_index do |i|
50
- design[i] = Array.new(power[number_of_factors], 0)
51
- design[i][index[i]] = 1
52
- design[i].hadamard
46
+ def RESV.make_design(number_of_factors)
47
+ Array.new(number_of_factors) do |i|
48
+ Array.new(POWER[number_of_factors], 0).tap { |a| a[INDEX[i]] = 1 }.hadamard
49
+ end.transpose
50
+ end
51
+
52
+ def RESV.star_pts(k)
53
+ Array.new(2*k+1) do |i|
54
+ Array.new(k) { |j| (j+1) == (i+1) / 2 ? (i.odd? ? -1 : 1) : 0 }
55
+ end
53
56
  end
54
- design.transpose
55
57
  end
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby -w
2
+
3
+ # A Scaler object will rescale a design from standard range [-1, 1] to a
4
+ # range specified by min & max, with the desired number of decimals
5
+ class Scaler
6
+ def initialize(min: -1, max: 1, decimals: nil)
7
+ unless decimals.nil? || ((decimals >= 0) && (decimals == decimals.to_i))
8
+ fail "Invalid decimals argument: #{decimals}. Must be a non-negative integer"
9
+ end
10
+ @range = (max - min).to_r / 2
11
+ @mid = min + @range
12
+ @scale_factor = (decimals.nil? || decimals.zero?) ? decimals : 10r**decimals
13
+ end
14
+
15
+ def scale(value)
16
+ new_value = @mid + @range * value
17
+ if @scale_factor.nil?
18
+ if new_value.to_r.denominator == 1
19
+ new_value.to_i
20
+ else
21
+ new_value.to_f
22
+ end
23
+ elsif @scale_factor.zero?
24
+ new_value.round
25
+ else
26
+ ((@scale_factor * new_value).round / @scale_factor).to_f
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FBS
4
+ TWO_PI = 2.0 * Math::PI
5
+
6
+ DesignSet = Struct.new(:nyq, :freqs, keyword_init: true)
7
+
8
+ DESIGN_SETS = {
9
+ 2 => DesignSet.new(
10
+ nyq: 11, freqs: [
11
+ [1, 3],
12
+ [1, 4],
13
+ [1, 5]
14
+ ]
15
+ ),
16
+ 3 => DesignSet.new(
17
+ nyq: 19, freqs: [
18
+ [1, 3, 7],
19
+ [1, 7, 8],
20
+ [2, 3, 5],
21
+ [4, 6, 9]
22
+ ]
23
+ ),
24
+ 4 => DesignSet.new(
25
+ nyq: 29, freqs: [
26
+ [1, 4, 5, 11]
27
+ ]
28
+ ),
29
+ 5 => DesignSet.new(
30
+ nyq: 43, freqs: [
31
+ [1, 5, 6, 8, 20],
32
+ [1, 8, 9, 11, 14],
33
+ [3, 4, 7, 9, 19]
34
+ ]
35
+ ),
36
+ 6 => DesignSet.new(
37
+ nyq: 59, freqs: [
38
+ [1, 6, 10, 16, 24, 28],
39
+ [1, 7, 11, 16, 19, 23],
40
+ [2, 8, 20, 23, 25, 29]
41
+ ]
42
+ ),
43
+ 7 => DesignSet.new(
44
+ nyq: 79, freqs: [
45
+ [1, 3, 8, 11, 26, 29, 33],
46
+ [1, 4, 11, 12, 29, 30, 35],
47
+ [1, 5, 6, 14, 15, 17, 38],
48
+ [1, 10, 11, 16, 17, 24, 25],
49
+ [2, 3, 5, 11, 20, 21, 25],
50
+ [2, 3, 17, 22, 25, 33, 36],
51
+ [2, 5, 7, 13, 15, 16, 39],
52
+ [2, 7, 9, 10, 15, 19, 33],
53
+ [2, 20, 22, 29, 31, 32, 34],
54
+ [3, 8, 15, 17, 18, 24, 28]
55
+ ]
56
+ ),
57
+ 8 => DesignSet.new(
58
+ nyq: 101, freqs: [
59
+ [1, 4, 5, 17, 21, 27, 41, 45],
60
+ [1, 5, 6, 14, 15, 17, 38, 41],
61
+ [2, 8, 10, 11, 19, 34, 42, 47],
62
+ [2, 14, 29, 31, 38, 40, 48, 50],
63
+ [3, 5, 8, 24, 28, 33, 42, 47],
64
+ [3, 13, 15, 18, 22, 42, 45, 50],
65
+ [4, 7, 16, 17, 20, 22, 26, 45],
66
+ [5, 7, 13, 25, 29, 31, 40, 42],
67
+ [5, 8, 12, 20, 26, 34, 43, 45]
68
+ ]
69
+ ),
70
+ 9 => DesignSet.new(
71
+ nyq: 127, freqs: [
72
+ [1, 3, 10, 11, 15, 33, 38, 49, 57],
73
+ [1, 7, 8, 18, 19, 24, 39, 52, 53],
74
+ [1, 7, 8, 18, 19, 24, 52, 53, 62],
75
+ [1, 9, 13, 22, 28, 37, 42, 51, 58],
76
+ [1, 13, 14, 22, 23, 54, 55, 61, 62],
77
+ [1, 29, 38, 39, 41, 54, 55, 61, 62],
78
+ [2, 3, 5, 11, 15, 31, 38, 50, 52],
79
+ [2, 5, 20, 26, 28, 39, 41, 55, 63],
80
+ [3, 4, 7, 12, 27, 29, 38, 47, 52],
81
+ [4, 5, 9, 11, 15, 23, 36, 48, 62],
82
+ [5, 7, 16, 20, 22, 28, 45, 46, 48],
83
+ [5, 7, 16, 20, 22, 28, 46, 48, 62],
84
+ [7, 13, 16, 18, 24, 28, 34, 51, 54],
85
+ [7, 17, 20, 24, 26, 30, 38, 42, 53]
86
+ ]
87
+ ),
88
+ 10 => DesignSet.new(
89
+ nyq: 149, freqs: [
90
+ [3, 15, 18, 25, 40, 41, 49, 56, 60, 61]
91
+ ]
92
+ ),
93
+ 11 => DesignSet.new(
94
+ nyq: 191, freqs: [
95
+ [1, 8, 9, 12, 19, 34, 41, 46, 62, 85, 93],
96
+ [1, 9, 22, 29, 41, 46, 52, 56, 59, 61, 94],
97
+ [1, 15, 16, 19, 20, 26, 27, 62, 75, 79, 84],
98
+ [1, 19, 25, 26, 35, 36, 40, 41, 48, 64, 94],
99
+ [2, 3, 10, 13, 19, 33, 44, 54, 58, 72, 82],
100
+ [2, 3, 11, 12, 31, 34, 44, 47, 61, 82, 87],
101
+ [2, 5, 7, 13, 18, 35, 38, 48, 67, 82, 85],
102
+ [2, 7, 15, 20, 31, 36, 48, 54, 57, 69, 73],
103
+ [3, 16, 19, 36, 39, 44, 47, 62, 65, 92, 95],
104
+ [4, 7, 11, 16, 20, 37, 41, 49, 55, 83, 84],
105
+ [4, 18, 19, 21, 22, 28, 31, 51, 60, 65, 76],
106
+ [5, 7, 13, 15, 16, 34, 35, 59, 67, 71, 79],
107
+ [6, 10, 16, 19, 25, 33, 39, 40, 46, 51, 93],
108
+ [8, 9, 17, 21, 28, 29, 31, 32, 70, 76, 88],
109
+ [9, 35, 38, 39, 47, 59, 65, 75, 84, 90, 92],
110
+ [12, 15, 16, 22, 34, 51, 53, 54, 65, 74, 79],
111
+ [16, 25, 30, 31, 33, 39, 43, 49, 77, 84, 85]
112
+ ]
113
+ ),
114
+ 12 => DesignSet.new(
115
+ nyq: 223, freqs: [
116
+ [1, 15, 16, 19, 20, 27, 28, 61, 62, 64, 86, 87],
117
+ [2, 8, 17, 19, 41, 43, 47, 48, 50, 61, 70, 73],
118
+ [2, 11, 13, 19, 21, 31, 33, 37, 82, 84, 109, 111],
119
+ [2, 19, 21, 39, 41, 47, 49, 50, 52, 64, 74, 108]
120
+ ]
121
+ ),
122
+ 13 => DesignSet.new(
123
+ nyq: 263, freqs: [
124
+ [1, 4, 5, 22, 23, 35, 36, 55, 56, 84, 98, 99, 126]
125
+ ]
126
+ ),
127
+ 14 => DesignSet.new(
128
+ nyq: 331, freqs: [
129
+ [1, 3, 7, 19, 26, 36, 47, 60, 70, 79, 128, 148, 153, 161]
130
+ ]
131
+ ),
132
+ 15 => DesignSet.new(
133
+ nyq: 389, freqs: [
134
+ [1, 3, 7, 12, 29, 40, 49, 65, 91, 100, 125, 131, 148, 154, 172]
135
+ ]
136
+ ),
137
+ 20 => DesignSet.new(
138
+ nyq: 853, freqs: [
139
+ [1, 3, 7, 12, 15, 25, 41, 58, 60, 80, 107, 154, 161, 193, 232, 249, 284, 291, 377, 412]
140
+ ]
141
+ )
142
+ }.freeze
143
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DataFarming
4
+ VERSION = "2.1.0"
5
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "datafarming/version"
4
+
5
+ module DataFarming
6
+ class Error < StandardError; end
7
+ # Your code goes here...
8
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datafarming
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul J Sanchez
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-08-17 00:00:00.000000000 Z
11
+ date: 2023-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fwt
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0.8'
33
+ version: '1'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0.8'
40
+ version: '1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: quickstats
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,26 +52,52 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '2'
55
- description: Ruby scripts for data farming, including pre- and post-processing, design
55
+ - !ruby/object:Gem::Dependency
56
+ name: optparse
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.4'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: yaml
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.3'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.3'
83
+ description: Ruby scripts for data farming, including pre- andpost-processing, design
56
84
  generation and scaling, and run control.
57
85
  email: pjs@alum.mit.edu
58
86
  executables:
59
- - augment_design.rb
60
87
  - batchrunner.rb
61
88
  - blank2csv.rb
62
89
  - cat.rb
63
90
  - convert_line_endings.rb
64
91
  - cross.rb
65
92
  - csv2blank.rb
93
+ - datafarming.rb
94
+ - generate_design.rb
66
95
  - moving_average.rb
67
96
  - mser.rb
68
97
  - mser_nolbm.rb
69
98
  - mser_olbm.rb
70
99
  - pool_files.rb
71
100
  - rundesign_general.rb
72
- - scaled_fde.rb
73
- - scaled_rf_cubed.rb
74
- - stack_nolhs.rb
75
101
  - stripheaderdups.rb
76
102
  - stripheaders.rb
77
103
  extensions: []
@@ -80,35 +106,37 @@ files:
80
106
  - LICENSE.md
81
107
  - README.md
82
108
  - datafarming.gemspec
83
- - exe/augment_design.rb
84
109
  - exe/batchrunner.rb
85
110
  - exe/blank2csv.rb
86
111
  - exe/cat.rb
87
112
  - exe/convert_line_endings.rb
88
113
  - exe/cross.rb
89
114
  - exe/csv2blank.rb
115
+ - exe/datafarming.rb
116
+ - exe/generate_design.rb
90
117
  - exe/moving_average.rb
91
118
  - exe/mser.rb
92
119
  - exe/mser_nolbm.rb
93
120
  - exe/mser_olbm.rb
94
121
  - exe/pool_files.rb
95
122
  - exe/rundesign_general.rb
96
- - exe/scaled_fde.rb
97
- - exe/scaled_rf_cubed.rb
98
- - exe/stack_nolhs.rb
99
123
  - exe/stripheaderdups.rb
100
124
  - exe/stripheaders.rb
125
+ - lib/datafarming.rb
101
126
  - lib/datafarming/cross.rb
102
127
  - lib/datafarming/error_handling.rb
103
- - lib/datafarming/factorial_generator.rb
104
128
  - lib/datafarming/freq_sets.rb
105
129
  - lib/datafarming/moving_average.rb
106
130
  - lib/datafarming/nolh_designs.rb
107
- homepage: https://gitlab.nps.edu/pjsanche/datafarmingrubyscripts.git
131
+ - lib/datafarming/res_v_seqs.rb
132
+ - lib/datafarming/scale_design.rb
133
+ - lib/datafarming/screen_freq_sets.rb
134
+ - lib/datafarming/version.rb
135
+ homepage: https://bitbucket.org/paul_j_sanchez/datafarmingrubyscripts
108
136
  licenses:
109
137
  - MIT
110
138
  metadata: {}
111
- post_install_message:
139
+ post_install_message:
112
140
  rdoc_options: []
113
141
  require_paths:
114
142
  - lib
@@ -116,16 +144,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
116
144
  requirements:
117
145
  - - ">="
118
146
  - !ruby/object:Gem::Version
119
- version: '2.3'
147
+ version: '2.6'
120
148
  required_rubygems_version: !ruby/object:Gem::Requirement
121
149
  requirements:
122
150
  - - ">="
123
151
  - !ruby/object:Gem::Version
124
152
  version: '0'
125
153
  requirements: []
126
- rubyforge_project:
127
- rubygems_version: 2.7.7
128
- signing_key:
154
+ rubygems_version: 3.4.20
155
+ signing_key:
129
156
  specification_version: 4
130
157
  summary: Useful scripts for data farming.
131
158
  test_files: []
@@ -1,66 +0,0 @@
1
- #!/usr/bin/env ruby -w
2
-
3
- # This script generates star points to augment a fractional factorial
4
- # so you can check for quadratic effects.
5
-
6
- require 'colorize'
7
-
8
- String.disable_colorization false
9
-
10
- require 'optparse'
11
- require 'datafarming/error_handling'
12
-
13
- help_msg = [
14
- 'Generate star points to augment a fractional factorial ' \
15
- 'with quadratic effects.',
16
- 'Results are white-space delimited data written to ' +
17
- 'stdout'.light_blue + ', and can be redirected', 'as desired.', '',
18
- 'Syntax:',
19
- "\n\t#{ErrorHandling.prog_name} [--help] FACTOR_INFO".yellow, '',
20
- "Arguments in square brackets are optional. A vertical bar '|'",
21
- 'indicates valid alternatives for invoking the option. Prefix',
22
- 'the command with "' + 'ruby'.yellow +
23
- '" if it is not on your PATH.', '',
24
- ' --help | -h | -? | ?'.green,
25
- "\tProduce this help message.",
26
- ' FACTOR_INFO'.green,
27
- "\tEITHER the number of factors (produces standardized +/-1 design),",
28
- "\tOR pairs of values " + 'low1 hi1 low2 hi2...lowN hiN'.green +
29
- ' for each of the',
30
- "\tN factors.", ''
31
- ]
32
-
33
- OptionParser.new do |opts|
34
- opts.banner = "Usage: #{$PROGRAM_NAME} [-h|--help] [number of factors]"
35
- opts.on('-h', '-?', '--help') { ErrorHandling.clean_abort help_msg }
36
- end.parse!
37
-
38
- if ARGV.length == 0 || (ARGV[0] == '?') || (ARGV.length > 1 && ARGV.length.odd?)
39
- ErrorHandling.clean_abort help_msg
40
- else
41
- num_factors = 0
42
- if ARGV.length == 1
43
- num_factors = ARGV.shift.to_i
44
- x = Array.new(num_factors, ' 0')
45
- ranges = Array.new(2 * num_factors)
46
- ranges.each_index { |i| ranges[i] = (i.even? ? '-1' : ' 1') }
47
- else
48
- num_factors = ARGV.length / 2
49
- x = Array.new(num_factors)
50
- ranges = ARGV
51
- num_factors.times do |i|
52
- x[i] = 0.5 * (ranges[2 * i].to_f + ranges[2 * i + 1].to_f)
53
- end
54
- end
55
- # create and print an array at the global center point (0,0,...,0)
56
- puts x.join(' ')
57
-
58
- # now generate and print the star points at +/-1 along each factor axis
59
- num_factors.times do |i|
60
- y = x.clone
61
- y[i] = ranges[2 * i]
62
- puts y.join(' ')
63
- y[i] = ranges[2 * i + 1]
64
- puts y.join(' ')
65
- end
66
- end
data/exe/scaled_fde.rb DELETED
@@ -1,169 +0,0 @@
1
- #!/usr/bin/env ruby -w
2
-
3
- require 'colorize'
4
- String.disable_colorization false
5
-
6
- require 'datafarming/error_handling'
7
- require 'datafarming/freq_sets'
8
-
9
- help_msg = [
10
- 'Generate scaled FDE designs with shifting and stacking. The resulting',
11
- 'design is written to ' +
12
- 'stdout'.light_blue + '.', '',
13
- 'Syntax:',
14
- "\n\t#{$PROGRAM_NAME.split(%r{/|\\})[-1]} [--help]".yellow +
15
- " [-c] [-d #] [-e] [-k #] [-s #] [file_name]\n".yellow,
16
- "Arguments in square brackets are optional. A vertical bar '|'",
17
- 'indicates valid alternatives for invoking the option. Prefix',
18
- 'the command with "' + 'ruby'.yellow +
19
- '" if it is not on your PATH.', '',
20
- ' --help | -h | -? | ?'.green,
21
- "\tProduce this help message. Supersedes any other choices.",
22
- ' --csv | -c'.green,
23
- "\tGenerate output as comma-separated-values.",
24
- ' --num_factors # | -k #'.green,
25
- "\tSpecify number of factors using standard (+/-1) scaling.",
26
- ' --design # | -d #'.green,
27
- "\tSpecify which design number you want. Default is highest",
28
- "\tfrequency set available for the target number of factors.",
29
- "\tAn input larger than the available number will produce an",
30
- "\terror message that identifies the allowable range.",
31
- ' --stack # | -s #'.green,
32
- "\t# specifies the number of stackings. The specified value cannot",
33
- "\texceed the number of columns in the design being used. If this",
34
- "\toption is omitted then only the base design is generated.",
35
- ' --excel-style-input | -e'.green,
36
- "\tSpecify factor ranges similarly to the NOLH spreadsheet, i.e.,",
37
- "\tthe first line is the set of minimum range values for all factors,",
38
- "\tand the second line is maximum range values. Without this option,",
39
- "\tthe default input format is one line per factor, comprised of the",
40
- "\tmin and max separated by commas or whitespace.",
41
- ' file_name'.green,
42
- "\tThe name of a file containing the factor specifications. If no",
43
- "\tfilename is given, the user can enter the values interactively in",
44
- "\tthe desired form or use file redirection with '<'.", '',
45
- 'Options may be given in any order, but must come before the file name',
46
- 'if one is provided.'
47
- ]
48
-
49
- # Scaler objects will rescale a FDE design from standard units
50
- # to a range specified by min and max
51
- class Scaler
52
- def initialize(min = -1, max = 1)
53
- @mid = 0.5 * (max + min)
54
- @amplitude = 0.5 * (max - min)
55
- end
56
-
57
- def scale(value)
58
- @mid + @amplitude * value
59
- end
60
- end
61
-
62
- def make_design(number_of_factors, design_num = -1)
63
- design = Array.new(number_of_factors)
64
- ds = FDE::DESIGN_SETS[number_of_factors]
65
- freqs = ds.freqs[design_num].map { |f| Rational(f, ds.nyq) }
66
- design.each_index do |column|
67
- omega = freqs[column]
68
- design[column] = Array.new(ds.nyq) do |i|
69
- Math.sin(((i * omega) % 1) * FDE::TWO_PI)
70
- end
71
- end
72
- design.transpose
73
- end
74
-
75
- excel_style_inputs = false
76
- csv_out = false
77
- design_num = -1
78
- num_stackings = 1
79
- n = nil
80
- while ARGV[0] && (ARGV[0][0] == '-' || ARGV[0][0] == 45 || ARGV[0][0] == '?')
81
- current_value = ARGV.shift
82
- case current_value
83
- when '--csv', '-c'
84
- csv_out = true
85
- when '--design', '-d'
86
- design_num = ARGV.shift.to_i - 1
87
- when '--num_factors', '-k'
88
- n = ARGV.shift.to_i
89
- when '--stack', '-s'
90
- num_stackings = ARGV.shift.to_i
91
- when '--excel-style-input', '-e'
92
- excel_style_inputs = true
93
- when '--help', '-h', '-help', '-?', '?'
94
- ErrorHandling.clean_abort help_msg
95
- else
96
- ErrorHandling.message ['Unknown argument: '.red + current_value.yellow]
97
- ErrorHandling.clean_abort help_msg
98
- end
99
- end
100
-
101
- if n
102
- factor = Array.new(n) { Scaler.new }
103
- else
104
- begin
105
- if excel_style_inputs
106
- if ARGF.filename == '-'
107
- STDERR.puts 'Enter one line of min values, and one of max values.'.green
108
- end
109
- min_values = ARGF.gets.strip.split(/\s*[,;:]\s*|\s+/).map(&:to_f)
110
- max_values = ARGF.gets.strip.split(/\s*[,;:]\s*|\s+/).map(&:to_f)
111
- else
112
- if ARGF.filename == '-'
113
- STDERR.puts 'To terminate input enter '.green + 'ctrl-d'.cyan +
114
- ' (Mac/Unix/Linux)'.green + ' or '.green + 'ctrl-z'.cyan +
115
- ' (Windows).'.green
116
- STDERR.puts 'Enter ranges for each factor on a separate line.'.green
117
- STDERR.puts "\nMIN\tMAX".cyan
118
- end
119
- min_values = []
120
- max_values = []
121
- while line = ARGF.gets
122
- values = line.strip.split(/\s*[,;:]\s*|\s+/).map(&:to_f)
123
- min_values << values.shift
124
- max_values << values.shift
125
- end
126
- end
127
- rescue StandardError => e
128
- ErrorHandling.message [e.message.red]
129
- ErrorHandling.clean_abort help_msg
130
- end
131
-
132
- n = min_values.size
133
- if max_values.size != n
134
- ErrorHandling.message ['Unequal counts for min, max'.red]
135
- ErrorHandling.clean_abort help_msg
136
- end
137
-
138
- factor = Array.new(n) do |i|
139
- Scaler.new(min_values[i], max_values[i])
140
- end
141
- end
142
-
143
- if design_num >= FDE::DESIGN_SETS[n].freqs.length
144
- ErrorHandling.clean_abort [
145
- "Design number cannot exceed #{FDE::DESIGN_SETS[n].freqs.length} for #{n} factors".red
146
- ]
147
- end
148
-
149
- design = make_design(n, design_num)
150
-
151
- num_columns = design[0].length
152
- if num_stackings > num_columns
153
- ErrorHandling.clean_abort [
154
- 'Requested stacking exceeds number of columns in FDE '.red +
155
- "(#{num_columns})".red
156
- ]
157
- end
158
-
159
- num_stackings.times do |_stack_num|
160
- design.each_with_index do |dp, i|
161
- scaled_dp = dp.slice(0, n).map.with_index { |x, k| factor[k].scale(x) }
162
- if csv_out
163
- puts scaled_dp.join ','
164
- else
165
- puts scaled_dp.join "\t"
166
- end
167
- design[i] = dp.rotate
168
- end
169
- end