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