1 #if defined(HAVE_CONFIG_H) && !defined(DISABLE_DAKOTA_CONFIG_H)
2 #include "ddace_config.h"
3 #endif
4 /*
5
6 These programs construct and manipulate orthogonal
7 arrays. They were prepared by
8
9 Art Owen
10 Department of Statistics
11 Sequoia Hall
12 Stanford CA 94305
13
14 They may be freely used and shared. This code comes
15 with no warranty of any kind. Use it at your own
16 risk.
17
18 I thank the Semiconductor Research Corporation and
19 the National Science Foundation for supporting this
20 work.
21
22 */
23
24
25 /* Constructions for designs using Galois fields */
26
27 #include <math.h>
28 #include <stdio.h>
29
30 #include "galois.h"
31
32 /* BMA, 20151007: Prototypes added for functions in other files to
33 avoid implicit declaration warnings. Keeping out of headers to
34 avoid conflicts. */
35 int akeven(struct GF *gf, int *kay, int *b, int *c, int *k);
36 int akodd(struct GF *gf, int *kay, int *b, int *c, int *k);
37 void free_imatrix(int **m, int nrl, int nrh, int ncl, int nch);
38 void free_ivector(int *v, int nl, int nh);
39 int ipow(int a, int b);
40 int isprime(int p);
41
42 /* Glossary:
43
44 bose: OA( q^2, q+1, q, 2 )
45 R.C. Bose (1938) Sankhya Vol 3 pp 323-338
46 bosecheck: test input to bose
47
48 bosebush: OA( 2q^2, 2q+1, q, 2 ), only implemented for q=2^n
49 bosebushcheck: test input to bosebush
50
51 polyeval: evaluate a polynomial with coefficients, argument
52 and result in a Galois field
53
54 */
55
56
bosecheck(q,ncol)57 int bosecheck( q,ncol )
58 int q, ncol;
59 {
60 if( ncol > q+1 ){
61 fprintf(stderr,"Bose's design must have ncol <= q+1.\n");
62 fprintf(stderr,"Had q=%d and ncol=%d.\n",q,ncol);
63 return 0;
64 }
65 if( ncol <= 0 ){
66 fprintf(stderr,"Nonpositive number of columns requested for Bose's design\n");
67 return 0;
68 }
69 return 1;
70 }
71
72
bose(gf,A,ncol)73 int bose( gf, A, ncol )
74 struct GF *gf;
75 int **A, ncol;
76 {
77 int i,j, icol, q=gf->q, irow;
78
79 if( !bosecheck(q,ncol) )return 0;
80
81 irow = 0;
82 for( i=0; i<q; i++ )
83 for( j=0; j<q; j++ ){
84 icol=0;
85 A[ irow ][ icol++ ] = i;
86 if( ncol > 1 )A[ irow ][ icol++ ] = j;
87 for( icol=2; icol<ncol; icol++ )
88 A[ irow ][ icol ] = gf->plus[j][gf->times[i][icol-1]];
89 irow++;
90 }
91
92
93 return 1;
94 }
95
itopoly(n,q,d,coef)96 void itopoly( n,q,d,coef )
97 int n,q,d,*coef;
98 {
99 int i;
100
101 for( i=0; i<=d; i++ ){
102 coef[i] = n % q;
103 n = n/q;
104 }
105 }
106
107
polyeval(gf,d,poly,arg,value)108 void polyeval( gf, d, poly, arg, value )
109 /* find value = poly(arg) where poly is a polynomial of degree d
110 and all the arithmetic takes place in the given Galois field.*/
111
112 struct GF *gf;
113 int d, *poly, arg, *value;
114 {
115 int i,ans;
116
117 ans = 0;
118 for( i= d; i>=0; i-- ) /* Horner's rule */
119 ans = gf->plus[ gf->times[ans][arg] ][ poly[i] ];
120
121 *value = ans;
122 }
123
bushcheck(q,str,ncol)124 int bushcheck(q,str,ncol)
125 int q,str,ncol;
126 {
127 if( ncol > q+1 ){
128 fprintf(stderr,"Bush designs require ncol <= q+1.\n");
129 fprintf(stderr,"Cannot have q = %d and ncol = %d.\n",q,ncol);
130 return 0;
131 }
132 if( str > ncol ){
133 fprintf(stderr,"It doesn't make sense to have an array of strength\n");
134 fprintf(stderr,"%d with only %d columns.\n",str,ncol);
135 return 0;
136 }
137 if( str >= q+1 ){
138 fprintf(stderr,"Bush's (1952) theorem has a condition t<q where t\n");
139 fprintf(stderr,"is the strength of the array and q is the number of symbols.\n");
140 fprintf(stderr,"Here we have t = %d and q = %d. The array may still\n",str,q);
141 fprintf(stderr,"be useful, but a full factorial would have at least as\n");
142 fprintf(stderr,"many columns.\n");
143 return 1;
144 }
145
146 return 1;
147 }
148
149
bush(gf,A,str,ncol)150 int bush( gf, A, str, ncol )
151 struct GF *gf;
152 int **A, str, ncol;
153 {
154 int *coef;
155 int q, i,j;
156
157 q = gf->q;
158 if( !bushcheck(q,str,ncol) )return 0;
159
160 coef = ivector( 0,str-1 );
161 if( !coef ){ /* Very unlikely */
162 fprintf(stderr,"Could not allocate memory for Bush design.\n");
163 return 0;
164 }
165
166 for( i=0; i<ipow(q,str); i++ ){
167 itopoly( i,q,str-1,coef );
168 A[i][0] = coef[str-1];
169 for( j=0; j<ncol-1; j++ )
170 polyeval( gf, str-1, coef, j, &A[i][1+j] );
171 }
172 free_ivector( coef,0,str-1 );
173 return 1;
174 }
175
176
addelkempcheck(q,p,ncol)177 int addelkempcheck( q,p,ncol )
178 int q,p,ncol;
179 {
180
181 if( p==2 && q>4 ){
182 fprintf(stderr,"This Addelman-Kempthorne OA(2q^2,ncol,q,2) is only\n");
183 fprintf(stderr,"available for odd prime powers q and for even prime\n");
184 fprintf(stderr,"powers q<=4. q=%d is not available, but a Bose Bush\n",q);
185 fprintf(stderr,"construction exists for that design.\n");
186 return 0;
187 }
188
189 if( ncol > 2*q+1 ){
190 fprintf(stderr,"The Addelman-Kempthorne construction needs ncol <= 2q+1.\n");
191 fprintf(stderr,"Can't have ncol = %d with q = %d,\n",ncol,q);
192 return 0;
193 }
194
195 if( ncol == 2*q+1 ){
196 fprintf(stderr,"\nWarning: The Addelman-Kempthorne construction with ncol = 2q+1\n");
197 fprintf(stderr,"has a defect. While it is still an OA(2q^2,2q+1,q,2),\n");
198 fprintf(stderr,"there exist some pairs of rows that agree in three columns.\n");
199 fprintf(stderr,"The final column in the array is involved in all of these\n");
200 fprintf(stderr,"triple coincidences.\n\n\n");
201 }
202 return 1;
203 }
204
205
addelkemp(gf,A,ncol)206 int addelkemp( gf, A, ncol )
207 /* Implement Addelman and Kempthorne's 1961 A.M.S. method with n=2 */
208 struct GF *gf;
209 int ncol, **A;
210 {
211 int i,j,m,p,q;
212 int kay,*b,*c,*k; /* A&K notation */
213 int row, col, square, ksquare, temp;
214
215 p=gf->p, q=gf->q;
216
217 if( !addelkempcheck( q,p,ncol ) )return 0;
218
219 b = ivector( 0,q-1 );
220 c = ivector( 0,q-1 );
221 k = ivector( 0,q-1 );
222
223 for( i=0; i<q; i++ ){ /* First q*q rows */
224 square = gf->times[i][i];
225 for( j=0; j<q; j++ ){
226 row = i*q+j;
227 col = 0;
228 if( col<ncol )A[row][col++]=j;
229 for( m=1; m<q && col<ncol; m++ )
230 A[row][col++] = gf->plus[i][gf->times[m][j]];
231 for( m=0; m<q && col<ncol; m++ ){
232 temp = gf->plus[j][gf->times[m][i]];
233 A[row][col++] = gf->plus[temp][square]; /* Rgt cols */
234 }
235 if( col<ncol )A[row][col++]=i;
236 }
237 }
238
239 if( p !=2 ) /* Constants kay,b,c,k for odd p */
240 akodd( gf,&kay,b,c,k );
241 else /* Constants kay,b,c,k for even p */
242 akeven( gf,&kay,b,c,k );
243
244 for( i=0; i<q; i++ ){ /* Second q*q rows */
245 square = gf->times[i][i];
246 ksquare = gf->times[kay][square];
247 for( j=0; j<q; j++ ){
248 row = q*q+i*q+j;
249 col = 0;
250 if( col<ncol )A[row][col++]=j;
251 for( m=1; m<q && col<ncol; m++,col++ )
252 A[row][col] = gf->plus[A[row-q*q][col]][b[m]];
253 if( col<ncol )A[row][col++] = gf->plus[ksquare][j]; /* q+1 */
254 for( m=1; m<q && col<ncol; m++ ){
255 temp = gf->times[i][k[m]];
256 temp = gf->plus[ksquare][temp];
257 temp = gf->plus[j][temp];
258 A[row][col++] = gf->plus[temp][c[m]];
259 }
260 if( col<ncol )A[row][col++]=i;
261 }
262 }
263
264 /*for( i=0; i<2*q*q; i++ )
265 for( j=0; j<ncol; j++ )
266 printf("%3d%s",A[i][j],j==(ncol-1)?"\n":" ");
267 */
268
269 return 1;
270 }
271
272
bosebushcheck(q,p,ncol)273 int bosebushcheck( q,p,ncol )
274 int q,p,ncol;
275 {
276
277 if( p!=2 ){
278 fprintf(stderr,"This version of Bose and Bush needs q=2^n for some n.\n");
279 return 0;
280 }
281
282 if( ncol > 2*q+1 ){
283 fprintf(stderr,"The Bose-Bush construction needs ncol <= 2q+1.\n");
284 fprintf(stderr,"Can't have ncol = %d with q = %d,\n",ncol,q);
285 return 0;
286 }
287
288 if( ncol == 2*q+1 ){
289 fprintf(stderr,"\nWarning: The Bose-Bush construction with ncol = 2q+1\n");
290 fprintf(stderr,"has a defect. While it is still an OA(2q^2,2q+1,q,2),\n");
291 fprintf(stderr,"there exist some pairs of rows that agree in three columns.\n\n\n");
292 }
293 return 1;
294 }
295
bosebush(gf,B,ncol)296 int bosebush( gf, B, ncol )
297 /* Implement Bose and Bush's 1952 A.M.S. method with p=2, u=1 */
298 struct GF *gf;
299 int **B;
300 int ncol;
301 {
302 int p,q,s,irow;
303 int i,j,k,mul;
304 int **A;
305
306 p=gf->p, /* GF(q) used to generate design with q/2 levels */
307 q=gf->q;
308 s=q/2; /* number of levels in design */
309
310 if( !bosebushcheck( s,p,ncol ) )
311 return 0;
312
313 A = imatrix(0,s-1,0,q-1);
314 if( !A ){
315 fprintf(stderr,"Unable to allocate scratch space for Bose-Bush array.\n");
316 return 0;
317 }
318
319 irow = 0;
320 for( i=0; i<q; i++ ){
321 for( j=0; j<q; j++ ){
322 mul = gf->times[i][j];
323 mul = mul % s;
324 for( k=0; k<s; k++ )
325 /* A[k][j] = gf->plus[mul][k];*/
326 A[k][j] = gf->plus[mul][k];
327 }
328 for( k=0; k<s; k++ ){
329 for( j=0; j<ncol && j<2*s+1; j++ )
330 B[irow][j] = A[k][j];
331 if( ncol==2*s+1 )
332 B[irow][ncol-1] = i%s;
333 irow++;
334 }
335 }
336 free_imatrix(A,0,s-1,0,q-1);
337 return 1;
338 }
339
340
bosebushlcheck(s,p,lam,ncol)341 int bosebushlcheck( s,p,lam,ncol )
342 int s,p,lam,ncol;
343 {
344
345 if( !isprime(p) ){
346 fprintf(stderr,"Bose Bush routine given a nonprime.\n");
347 return 0;
348 }
349
350 if( ncol > lam*s+1 ){
351 fprintf(stderr,"The Bose-Bush construction needs ncol <= lambda*q+1.\n");
352 fprintf(stderr,"Can't have ncol = %d with lam = %d and q = %d,\n",ncol,lam,s);
353 return 0;
354 }
355
356 if( ncol == lam*s+1 ){
357 fprintf(stderr,"\nWarning: The Bose-Bush construction with ncol = lambda*q+1\n");
358 fprintf(stderr,"has a defect. While it is still an OA(lambda*q^2,lambda*q+1,q,2),\n");
359 fprintf(stderr,"it may have worse coincidence properties than\n");
360 fprintf(stderr,"OA(lambda*q^2,lambda*q+1,q,2).\n");
361 }
362 return 1;
363 }
364
bosebushl(gf,lam,B,ncol)365 int bosebushl( gf, lam, B, ncol )
366 /* Implement Bose and Bush's 1952 A.M.S. method with given lambda */
367 struct GF *gf;
368 int **B, lam;
369 int ncol;
370 {
371 int p,q,s,irow;
372 int i,j,k,mul;
373 int **A;
374
375 p=gf->p, /* GF(q) used to generate design with q/lam levels */
376 q=gf->q;
377 s=q/lam; /* number of levels in design */
378
379 if( !bosebushlcheck( s,p,lam,ncol ) )
380 return 0;
381
382 A = imatrix(0,s-1,0,q-1);
383 if( !A ){
384 fprintf(stderr,"Unable to allocate scratch space for Bose-Bush array.\n");
385 return 0;
386 }
387
388 irow = 0;
389 for( i=0; i<q; i++ ){
390 for( j=0; j<q; j++ ){
391 mul = gf->times[i][j];
392 mul = mul % s;
393 for( k=0; k<s; k++ )
394 /* A[k][j] = gf->plus[mul][k];*/
395 A[k][j] = gf->plus[mul][k];
396 }
397 for( k=0; k<s; k++ ){
398 for( j=0; j<ncol && j<lam*s+1; j++ )
399 B[irow][j] = A[k][j];
400 if( ncol==lam*s+1 )
401 B[irow][ncol-1] = i%s;
402 irow++;
403 }
404 }
405
406
407
408
409
410 free_imatrix(A,0,s-1,0,q-1);
411 return 1;
412 }
413
414
415