Skip to content

Commit db8210d

Browse files
authored
Corrected PyDOE code files
1 parent 44d6958 commit db8210d

File tree

2 files changed

+334
-0
lines changed

2 files changed

+334
-0
lines changed

doe_box_behnken.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"""
2+
This code was originally published by the following individuals for use with
3+
Scilab:
4+
Copyright (C) 2012 - 2013 - Michael Baudin
5+
Copyright (C) 2012 - Maria Christopoulou
6+
Copyright (C) 2010 - 2011 - INRIA - Michael Baudin
7+
Copyright (C) 2009 - Yann Collette
8+
Copyright (C) 2009 - CEA - Jean-Marc Martinez
9+
10+
website: forge.scilab.org/index.php/p/scidoe/sourcetree/master/macros
11+
12+
Much thanks goes to these individuals. It has been converted to Python by
13+
Abraham Lee.
14+
"""
15+
16+
import numpy as np
17+
from pyDOE.doe_factorial import ff2n
18+
from pyDOE.doe_repeat_center import repeat_center
19+
20+
__all__ = ['bbdesign']
21+
22+
def bbdesign(n, center=None):
23+
"""
24+
Create a Box-Behnken design
25+
26+
Parameters
27+
----------
28+
n : int
29+
The number of factors in the design
30+
31+
Optional
32+
--------
33+
center : int
34+
The number of center points to include (default = 1).
35+
36+
Returns
37+
-------
38+
mat : 2d-array
39+
The design matrix
40+
41+
Example
42+
-------
43+
::
44+
45+
>>> bbdesign(3)
46+
array([[-1., -1., 0.],
47+
[ 1., -1., 0.],
48+
[-1., 1., 0.],
49+
[ 1., 1., 0.],
50+
[-1., 0., -1.],
51+
[ 1., 0., -1.],
52+
[-1., 0., 1.],
53+
[ 1., 0., 1.],
54+
[ 0., -1., -1.],
55+
[ 0., 1., -1.],
56+
[ 0., -1., 1.],
57+
[ 0., 1., 1.],
58+
[ 0., 0., 0.],
59+
[ 0., 0., 0.],
60+
[ 0., 0., 0.]])
61+
62+
"""
63+
assert n>=3, 'Number of variables must be at least 3'
64+
65+
# First, compute a factorial DOE with 2 parameters
66+
H_fact = ff2n(2)
67+
# Now we populate the real DOE with this DOE
68+
69+
# We made a factorial design on each pair of dimensions
70+
# - So, we created a factorial design with two factors
71+
# - Make two loops
72+
Index = 0
73+
nb_lines = int((0.5*n*(n-1))*H_fact.shape[0])
74+
H = repeat_center(n, nb_lines)
75+
76+
for i in range(n - 1):
77+
for j in range(i + 1, n):
78+
Index = Index + 1
79+
H[max([0, (Index - 1)*H_fact.shape[0]]):Index*H_fact.shape[0], i] = H_fact[:, 0]
80+
H[max([0, (Index - 1)*H_fact.shape[0]]):Index*H_fact.shape[0], j] = H_fact[:, 1]
81+
82+
if center is None:
83+
if n<=16:
84+
points= [0, 0, 0, 3, 3, 6, 6, 6, 8, 9, 10, 12, 12, 13, 14, 15, 16]
85+
center = points[n]
86+
else:
87+
center = n
88+
89+
H = np.c_[H.T, repeat_center(n, center).T].T
90+
91+
return H

doe_factorial.py

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
"""
2+
This code was originally published by the following individuals for use with
3+
Scilab:
4+
Copyright (C) 2012 - 2013 - Michael Baudin
5+
Copyright (C) 2012 - Maria Christopoulou
6+
Copyright (C) 2010 - 2011 - INRIA - Michael Baudin
7+
Copyright (C) 2009 - Yann Collette
8+
Copyright (C) 2009 - CEA - Jean-Marc Martinez
9+
10+
website: forge.scilab.org/index.php/p/scidoe/sourcetree/master/macros
11+
12+
Much thanks goes to these individuals. It has been converted to Python by
13+
Abraham Lee.
14+
"""
15+
16+
import re
17+
import numpy as np
18+
19+
__all__ = ['np', 'fullfact', 'ff2n', 'fracfact']
20+
21+
def fullfact(levels):
22+
"""
23+
Create a general full-factorial design
24+
25+
Parameters
26+
----------
27+
levels : array-like
28+
An array of integers that indicate the number of levels of each input
29+
design factor.
30+
31+
Returns
32+
-------
33+
mat : 2d-array
34+
The design matrix with coded levels 0 to k-1 for a k-level factor
35+
36+
Example
37+
-------
38+
::
39+
40+
>>> fullfact([2, 4, 3])
41+
array([[ 0., 0., 0.],
42+
[ 1., 0., 0.],
43+
[ 0., 1., 0.],
44+
[ 1., 1., 0.],
45+
[ 0., 2., 0.],
46+
[ 1., 2., 0.],
47+
[ 0., 3., 0.],
48+
[ 1., 3., 0.],
49+
[ 0., 0., 1.],
50+
[ 1., 0., 1.],
51+
[ 0., 1., 1.],
52+
[ 1., 1., 1.],
53+
[ 0., 2., 1.],
54+
[ 1., 2., 1.],
55+
[ 0., 3., 1.],
56+
[ 1., 3., 1.],
57+
[ 0., 0., 2.],
58+
[ 1., 0., 2.],
59+
[ 0., 1., 2.],
60+
[ 1., 1., 2.],
61+
[ 0., 2., 2.],
62+
[ 1., 2., 2.],
63+
[ 0., 3., 2.],
64+
[ 1., 3., 2.]])
65+
66+
"""
67+
n = len(levels) # number of factors
68+
nb_lines = np.prod(levels) # number of trial conditions
69+
H = np.zeros((nb_lines, n))
70+
71+
level_repeat = 1
72+
range_repeat = np.prod(levels)
73+
for i in range(n):
74+
range_repeat //= levels[i]
75+
lvl = []
76+
for j in range(levels[i]):
77+
lvl += [j]*level_repeat
78+
rng = lvl*range_repeat
79+
level_repeat *= levels[i]
80+
H[:, i] = rng
81+
82+
return H
83+
84+
################################################################################
85+
86+
def ff2n(n):
87+
"""
88+
Create a 2-Level full-factorial design
89+
90+
Parameters
91+
----------
92+
n : int
93+
The number of factors in the design.
94+
95+
Returns
96+
-------
97+
mat : 2d-array
98+
The design matrix with coded levels -1 and 1
99+
100+
Example
101+
-------
102+
::
103+
104+
>>> ff2n(3)
105+
array([[-1., -1., -1.],
106+
[ 1., -1., -1.],
107+
[-1., 1., -1.],
108+
[ 1., 1., -1.],
109+
[-1., -1., 1.],
110+
[ 1., -1., 1.],
111+
[-1., 1., 1.],
112+
[ 1., 1., 1.]])
113+
114+
"""
115+
return 2*fullfact([2]*n) - 1
116+
117+
################################################################################
118+
119+
def fracfact(gen):
120+
"""
121+
Create a 2-level fractional-factorial design with a generator string.
122+
123+
Parameters
124+
----------
125+
gen : str
126+
A string, consisting of lowercase, uppercase letters or operators "-"
127+
and "+", indicating the factors of the experiment
128+
129+
Returns
130+
-------
131+
H : 2d-array
132+
A m-by-n matrix, the fractional factorial design. m is 2^k, where k
133+
is the number of letters in ``gen``, and n is the total number of
134+
entries in ``gen``.
135+
136+
Notes
137+
-----
138+
In ``gen`` we define the main factors of the experiment and the factors
139+
whose levels are the products of the main factors. For example, if
140+
141+
gen = "a b ab"
142+
143+
then "a" and "b" are the main factors, while the 3rd factor is the product
144+
of the first two. If we input uppercase letters in ``gen``, we get the same
145+
result. We can also use the operators "+" and "-" in ``gen``.
146+
147+
For example, if
148+
149+
gen = "a b -ab"
150+
151+
then the 3rd factor is the opposite of the product of "a" and "b".
152+
153+
The output matrix includes the two level full factorial design, built by
154+
the main factors of ``gen``, and the products of the main factors. The
155+
columns of ``H`` follow the sequence of ``gen``.
156+
157+
For example, if
158+
159+
gen = "a b ab c"
160+
161+
then columns H[:, 0], H[:, 1], and H[:, 3] include the two level full
162+
factorial design and H[:, 2] includes the products of the main factors.
163+
164+
Examples
165+
--------
166+
::
167+
168+
>>> fracfact("a b ab")
169+
array([[-1., -1., 1.],
170+
[ 1., -1., -1.],
171+
[-1., 1., -1.],
172+
[ 1., 1., 1.]])
173+
174+
>>> fracfact("A B AB")
175+
array([[-1., -1., 1.],
176+
[ 1., -1., -1.],
177+
[-1., 1., -1.],
178+
[ 1., 1., 1.]])
179+
180+
>>> fracfact("a b -ab c +abc")
181+
array([[-1., -1., -1., -1., -1.],
182+
[ 1., -1., 1., -1., 1.],
183+
[-1., 1., 1., -1., 1.],
184+
[ 1., 1., -1., -1., -1.],
185+
[-1., -1., -1., 1., 1.],
186+
[ 1., -1., 1., 1., -1.],
187+
[-1., 1., 1., 1., -1.],
188+
[ 1., 1., -1., 1., 1.]])
189+
190+
"""
191+
# Recognize letters and combinations
192+
A = [item for item in re.split('\-?\s?\+?', gen) if item] # remove empty strings
193+
C = [len(item) for item in A]
194+
195+
# Indices of single letters (main factors)
196+
I = [i for i, item in enumerate(C) if item==1]
197+
198+
# Indices of letter combinations (we need them to fill out H2 properly).
199+
J = [i for i, item in enumerate(C) if item!=1]
200+
201+
# Check if there are "-" or "+" operators in gen
202+
U = [item for item in gen.split(' ') if item] # remove empty strings
203+
204+
# If R1 is either None or not, the result is not changed, since it is a
205+
# multiplication of 1.
206+
R1 = _grep(U, '+')
207+
R2 = _grep(U, '-')
208+
209+
# Fill in design with two level factorial design
210+
H1 = ff2n(len(I))
211+
H = np.zeros((H1.shape[0], len(C)))
212+
H[:, I] = H1
213+
214+
# Recognize combinations and fill in the rest of matrix H2 with the proper
215+
# products
216+
for k in J:
217+
# For lowercase letters
218+
xx = np.array([ord(c) for c in A[k]]) - 97
219+
220+
# For uppercase letters
221+
if np.any(xx<0):
222+
xx = np.array([ord(c) for c in A[k]]) - 65
223+
224+
H[:, k] = np.prod(H1[:, xx], axis=1)
225+
226+
# Update design if gen includes "-" operator
227+
if R2:
228+
H[:, R2] *= -1
229+
230+
# Return the fractional factorial design
231+
return H
232+
233+
def _grep(haystack, needle):
234+
try:
235+
haystack[0]
236+
except (TypeError, AttributeError):
237+
return [0] if needle in haystack else []
238+
else:
239+
locs = []
240+
for idx, item in enumerate(haystack):
241+
if needle in item:
242+
locs += [idx]
243+
return locs

0 commit comments

Comments
 (0)