Annotation of OpenXM_contrib2/asir2000/builtin/array.c, Revision 1.1.1.1
1.1 noro 1: /* $OpenXM: OpenXM/src/asir99/builtin/array.c,v 1.2 1999/11/23 07:14:14 noro Exp $ */
2: #include "ca.h"
3: #include "base.h"
4: #include "parse.h"
5: #include "inline.h"
6: /*
7: #undef DMAR
8: #define DMAR(a1,a2,a3,d,r) (r)=dmar(a1,a2,a3,d);
9: */
10:
11: extern int Print; /* XXX */
12:
13: void solve_by_lu_gfmmat(GFMMAT,unsigned int,unsigned int *,unsigned int *);
14: int lu_gfmmat(GFMMAT,unsigned int,int *);
15: void mat_to_gfmmat(MAT,unsigned int,GFMMAT *);
16:
17: int generic_gauss_elim_mod(int **,int,int,int,int *);
18: int generic_gauss_elim(MAT ,MAT *,Q *,int **,int **);
19:
20: int gauss_elim_mod(int **,int,int,int);
21: int gauss_elim_mod1(int **,int,int,int);
22: int gauss_elim_geninv_mod(unsigned int **,int,int,int);
23: int gauss_elim_geninv_mod_swap(unsigned int **,int,int,unsigned int,unsigned int ***,int **);
24: void Pnewvect(), Pnewmat(), Psepvect(), Psize(), Pdet(), Pleqm(), Pleqm1(), Pgeninvm();
25:
26: void Pgeneric_gauss_elim_mod();
27:
28: void Pmat_to_gfmmat(),Plu_gfmmat(),Psolve_by_lu_gfmmat();
29: void Pgeninvm_swap(), Premainder(), Psremainder(), Pvtol();
30: void sepvect();
31: void Pmulmat_gf2n();
32: void Pbconvmat_gf2n();
33: void Pmul_vect_mat_gf2n();
34: void PNBmul_gf2n();
35: void Pmul_mat_vect_int();
36: void Psepmat_destructive();
37: void Px962_irredpoly_up2();
38: void Pirredpoly_up2();
39: void Pnbpoly_up2();
40: void Pqsort();
41:
42: struct ftab array_tab[] = {
43: {"solve_by_lu_gfmmat",Psolve_by_lu_gfmmat,4},
44: {"lu_gfmmat",Plu_gfmmat,2},
45: {"mat_to_gfmmat",Pmat_to_gfmmat,2},
46: {"generic_gauss_elim_mod",Pgeneric_gauss_elim_mod,2},
47: {"newvect",Pnewvect,-2},
48: {"newmat",Pnewmat,-3},
49: {"sepmat_destructive",Psepmat_destructive,2},
50: {"sepvect",Psepvect,2},
51: {"qsort",Pqsort,-2},
52: {"vtol",Pvtol,1},
53: {"size",Psize,1},
54: {"det",Pdet,-2},
55: {"leqm",Pleqm,2},
56: {"leqm1",Pleqm1,2},
57: {"geninvm",Pgeninvm,2},
58: {"geninvm_swap",Pgeninvm_swap,2},
59: {"remainder",Premainder,2},
60: {"sremainder",Psremainder,2},
61: {"mulmat_gf2n",Pmulmat_gf2n,1},
62: {"bconvmat_gf2n",Pbconvmat_gf2n,-4},
63: {"mul_vect_mat_gf2n",Pmul_vect_mat_gf2n,2},
64: {"mul_mat_vect_int",Pmul_mat_vect_int,2},
65: {"nbmul_gf2n",PNBmul_gf2n,3},
66: {"x962_irredpoly_up2",Px962_irredpoly_up2,2},
67: {"irredpoly_up2",Pirredpoly_up2,2},
68: {"nbpoly_up2",Pnbpoly_up2,2},
69: {0,0,0},
70: };
71:
72: int comp_obj(a,b)
73: Obj *a,*b;
74: {
75: return arf_comp(CO,*a,*b);
76: }
77:
78: static FUNC generic_comp_obj_func;
79: static NODE generic_comp_obj_arg;
80:
81: int generic_comp_obj(a,b)
82: Obj *a,*b;
83: {
84: Q r;
85:
86: BDY(generic_comp_obj_arg)=(pointer)(*a);
87: BDY(NEXT(generic_comp_obj_arg))=(pointer)(*b);
88: r = (Q)bevalf(generic_comp_obj_func,generic_comp_obj_arg);
89: if ( !r )
90: return 0;
91: else
92: return SGN(r)>0?1:-1;
93: }
94:
95:
96: void Pqsort(arg,rp)
97: NODE arg;
98: VECT *rp;
99: {
100: VECT vect;
101: char buf[BUFSIZ];
102: char *fname;
103: NODE n;
104: P p;
105: V v;
106:
107: asir_assert(ARG0(arg),O_VECT,"qsort");
108: vect = (VECT)ARG0(arg);
109: if ( argc(arg) == 1 )
110: qsort(BDY(vect),vect->len,sizeof(Obj),(int (*)(const void *,const void *))comp_obj);
111: else {
112: p = (P)ARG1(arg);
113: if ( !p || OID(p)!=2 )
114: error("qsort : invalid argument");
115: v = VR(p);
116: if ( (int)v->attr != V_SR )
117: error("qsort : no such function");
118: generic_comp_obj_func = (FUNC)v->priv;
119: MKNODE(n,0,0); MKNODE(generic_comp_obj_arg,0,n);
120: qsort(BDY(vect),vect->len,sizeof(Obj),(int (*)(const void *,const void *))generic_comp_obj);
121: }
122: *rp = vect;
123: }
124:
125: void PNBmul_gf2n(arg,rp)
126: NODE arg;
127: GF2N *rp;
128: {
129: GF2N a,b;
130: GF2MAT mat;
131: int n,w;
132: unsigned int *ab,*bb;
133: UP2 r;
134:
135: a = (GF2N)ARG0(arg);
136: b = (GF2N)ARG1(arg);
137: mat = (GF2MAT)ARG2(arg);
138: if ( !a || !b )
139: *rp = 0;
140: else {
141: n = mat->row;
142: w = (n+BSH-1)/BSH;
143:
144: ab = (unsigned int *)ALLOCA(w*sizeof(unsigned int));
145: bzero((char *)ab,w*sizeof(unsigned int));
146: bcopy(a->body->b,ab,(a->body->w)*sizeof(unsigned int));
147:
148: bb = (unsigned int *)ALLOCA(w*sizeof(unsigned int));
149: bzero((char *)bb,w*sizeof(unsigned int));
150: bcopy(b->body->b,bb,(b->body->w)*sizeof(unsigned int));
151:
152: NEWUP2(r,w);
153: bzero((char *)r->b,w*sizeof(unsigned int));
154: mul_nb(mat,ab,bb,r->b);
155: r->w = w;
156: _adjup2(r);
157: if ( !r->w )
158: *rp = 0;
159: else
160: MKGF2N(r,*rp);
161: }
162: }
163:
164: void Pmul_vect_mat_gf2n(arg,rp)
165: NODE arg;
166: GF2N *rp;
167: {
168: GF2N a;
169: GF2MAT mat;
170: int n,w;
171: unsigned int *b;
172: UP2 r;
173:
174: a = (GF2N)ARG0(arg);
175: mat = (GF2MAT)ARG1(arg);
176: if ( !a )
177: *rp = 0;
178: else {
179: n = mat->row;
180: w = (n+BSH-1)/BSH;
181: b = (unsigned int *)ALLOCA(w*sizeof(unsigned int));
182: bzero((char *)b,w*sizeof(unsigned int));
183: bcopy(a->body->b,b,(a->body->w)*sizeof(unsigned int));
184: NEWUP2(r,w);
185: bzero((char *)r->b,w*sizeof(unsigned int));
186: mulgf2vectmat(mat->row,b,mat->body,r->b);
187: r->w = w;
188: _adjup2(r);
189: if ( !r->w )
190: *rp = 0;
191: else {
192: MKGF2N(r,*rp);
193: }
194: }
195: }
196:
197: void Pbconvmat_gf2n(arg,rp)
198: NODE arg;
199: LIST *rp;
200: {
201: P p0,p1;
202: int to;
203: GF2MAT p01,p10;
204: GF2N root;
205: NODE n0,n1;
206:
207: p0 = (P)ARG0(arg);
208: p1 = (P)ARG1(arg);
209: to = ARG2(arg)?1:0;
210: if ( argc(arg) == 4 ) {
211: root = (GF2N)ARG3(arg);
212: compute_change_of_basis_matrix_with_root(p0,p1,to,root,&p01,&p10);
213: } else
214: compute_change_of_basis_matrix(p0,p1,to,&p01,&p10);
215: MKNODE(n1,p10,0); MKNODE(n0,p01,n1);
216: MKLIST(*rp,n0);
217: }
218:
219: void Pmulmat_gf2n(arg,rp)
220: NODE arg;
221: GF2MAT *rp;
222: {
223: GF2MAT m;
224:
225: if ( !compute_multiplication_matrix((P)ARG0(arg),&m) )
226: error("mulmat_gf2n : input is not a normal polynomial");
227: *rp = m;
228: }
229:
230: void Psepmat_destructive(arg,rp)
231: NODE arg;
232: LIST *rp;
233: {
234: MAT mat,mat1;
235: int i,j,row,col;
236: Q **a,**a1;
237: Q ent;
238: N nm,mod,rem,quo;
239: int sgn;
240: NODE n0,n1;
241:
242: mat = (MAT)ARG0(arg); mod = NM((Q)ARG1(arg));
243: row = mat->row; col = mat->col;
244: MKMAT(mat1,row,col);
245: a = (Q **)mat->body; a1 = (Q **)mat1->body;
246: for ( i = 0; i < row; i++ )
247: for ( j = 0; j < col; j++ ) {
248: ent = a[i][j];
249: if ( !ent )
250: continue;
251: nm = NM(ent);
252: sgn = SGN(ent);
253: divn(nm,mod,&quo,&rem);
254: /* if ( quo != nm && rem != nm ) */
255: /* GC_free(nm); */
256: /* GC_free(ent); */
257: NTOQ(rem,sgn,a[i][j]); NTOQ(quo,sgn,a1[i][j]);
258: }
259: MKNODE(n1,mat1,0); MKNODE(n0,mat,n1);
260: MKLIST(*rp,n0);
261: }
262:
263: void Psepvect(arg,rp)
264: NODE arg;
265: VECT *rp;
266: {
267: sepvect((VECT)ARG0(arg),QTOS((Q)ARG1(arg)),rp);
268: }
269:
270: void sepvect(v,d,rp)
271: VECT v;
272: int d;
273: VECT *rp;
274: {
275: int i,j,k,n,q,q1,r;
276: pointer *pv,*pw,*pu;
277: VECT w,u;
278:
279: n = v->len;
280: if ( d > n )
281: d = n;
282: q = n/d; r = n%d; q1 = q+1;
283: MKVECT(w,d); *rp = w;
284: pv = BDY(v); pw = BDY(w); k = 0;
285: for ( i = 0; i < r; i++ ) {
286: MKVECT(u,q1); pw[i] = (pointer)u;
287: for ( pu = BDY(u), j = 0; j < q1; j++, k++ )
288: pu[j] = pv[k];
289: }
290: for ( ; i < d; i++ ) {
291: MKVECT(u,q); pw[i] = (pointer)u;
292: for ( pu = BDY(u), j = 0; j < q; j++, k++ )
293: pu[j] = pv[k];
294: }
295: }
296:
297: void Pnewvect(arg,rp)
298: NODE arg;
299: VECT *rp;
300: {
301: int len,i,r;
302: VECT vect;
303: pointer *vb;
304: LIST list;
305: NODE tn;
306:
307: asir_assert(ARG0(arg),O_N,"newvect");
308: len = QTOS((Q)ARG0(arg));
309: if ( len <= 0 )
310: error("newvect : invalid size");
311: MKVECT(vect,len);
312: if ( argc(arg) == 2 ) {
313: list = (LIST)ARG1(arg);
314: asir_assert(list,O_LIST,"newvect");
315: for ( r = 0, tn = BDY(list); tn; r++, tn = NEXT(tn) );
316: if ( r > len ) {
317: *rp = vect;
318: return;
319: }
320: for ( i = 0, tn = BDY(list), vb = BDY(vect); tn; i++, tn = NEXT(tn) )
321: vb[i] = (pointer)BDY(tn);
322: }
323: *rp = vect;
324: }
325:
326: void Pnewmat(arg,rp)
327: NODE arg;
328: MAT *rp;
329: {
330: int row,col;
331: int i,j,r,c;
332: NODE tn,sn;
333: MAT m;
334: pointer **mb;
335: LIST list;
336:
337: asir_assert(ARG0(arg),O_N,"newmat");
338: asir_assert(ARG1(arg),O_N,"newmat");
339: row = QTOS((Q)ARG0(arg)); col = QTOS((Q)ARG1(arg));
340: if ( row <= 0 || col <= 0 )
341: error("newmat : invalid size");
342: MKMAT(m,row,col);
343: if ( argc(arg) == 3 ) {
344: list = (LIST)ARG2(arg);
345: asir_assert(list,O_LIST,"newmat");
346: for ( r = 0, c = 0, tn = BDY(list); tn; r++, tn = NEXT(tn) ) {
347: for ( j = 0, sn = BDY((LIST)BDY(tn)); sn; j++, sn = NEXT(sn) );
348: c = MAX(c,j);
349: }
350: if ( (r > row) || (c > col) ) {
351: *rp = m;
352: return;
353: }
354: for ( i = 0, tn = BDY(list), mb = BDY(m); tn; i++, tn = NEXT(tn) ) {
355: asir_assert(BDY(tn),O_LIST,"newmat");
356: for ( j = 0, sn = BDY((LIST)BDY(tn)); sn; j++, sn = NEXT(sn) )
357: mb[i][j] = (pointer)BDY(sn);
358: }
359: }
360: *rp = m;
361: }
362:
363: void Pvtol(arg,rp)
364: NODE arg;
365: LIST *rp;
366: {
367: NODE n,n1;
368: VECT v;
369: pointer *a;
370: int len,i;
371:
372: asir_assert(ARG0(arg),O_VECT,"vtol");
373: v = (VECT)ARG0(arg); len = v->len; a = BDY(v);
374: for ( i = len - 1, n = 0; i >= 0; i-- ) {
375: MKNODE(n1,a[i],n); n = n1;
376: }
377: MKLIST(*rp,n);
378: }
379:
380: void Premainder(arg,rp)
381: NODE arg;
382: Obj *rp;
383: {
384: Obj a;
385: VECT v,w;
386: MAT m,l;
387: pointer *vb,*wb;
388: pointer **mb,**lb;
389: int id,i,j,n,row,col,t,smd,sgn;
390: Q md,q;
391:
392: a = (Obj)ARG0(arg); md = (Q)ARG1(arg);
393: if ( !a )
394: *rp = 0;
395: else {
396: id = OID(a);
397: switch ( id ) {
398: case O_N:
399: case O_P:
400: cmp(md,(P)a,(P *)rp); break;
401: case O_VECT:
402: smd = QTOS(md);
403: v = (VECT)a; n = v->len; vb = v->body;
404: MKVECT(w,n); wb = w->body;
405: for ( i = 0; i < n; i++ ) {
406: if ( q = (Q)vb[i] ) {
407: sgn = SGN(q); t = rem(NM(q),smd);
408: STOQ(t,q);
409: if ( q )
410: SGN(q) = sgn;
411: }
412: wb[i] = (pointer)q;
413: }
414: *rp = (Obj)w;
415: break;
416: case O_MAT:
417: m = (MAT)a; row = m->row; col = m->col; mb = m->body;
418: MKMAT(l,row,col); lb = l->body;
419: for ( i = 0; i < row; i++ )
420: for ( j = 0, vb = mb[i], wb = lb[i]; j < col; j++ )
421: cmp(md,(P)vb[j],(P *)&wb[j]);
422: *rp = (Obj)l;
423: break;
424: default:
425: error("remainder : invalid argument");
426: }
427: }
428: }
429:
430: void Psremainder(arg,rp)
431: NODE arg;
432: Obj *rp;
433: {
434: Obj a;
435: VECT v,w;
436: MAT m,l;
437: pointer *vb,*wb;
438: pointer **mb,**lb;
439: unsigned int t,smd;
440: int id,i,j,n,row,col;
441: Q md,q;
442:
443: a = (Obj)ARG0(arg); md = (Q)ARG1(arg);
444: if ( !a )
445: *rp = 0;
446: else {
447: id = OID(a);
448: switch ( id ) {
449: case O_N:
450: case O_P:
451: cmp(md,(P)a,(P *)rp); break;
452: case O_VECT:
453: smd = QTOS(md);
454: v = (VECT)a; n = v->len; vb = v->body;
455: MKVECT(w,n); wb = w->body;
456: for ( i = 0; i < n; i++ ) {
457: if ( q = (Q)vb[i] ) {
458: t = (unsigned int)rem(NM(q),smd);
459: if ( SGN(q) < 0 )
460: t = (smd - t) % smd;
461: UTOQ(t,q);
462: }
463: wb[i] = (pointer)q;
464: }
465: *rp = (Obj)w;
466: break;
467: case O_MAT:
468: m = (MAT)a; row = m->row; col = m->col; mb = m->body;
469: MKMAT(l,row,col); lb = l->body;
470: for ( i = 0; i < row; i++ )
471: for ( j = 0, vb = mb[i], wb = lb[i]; j < col; j++ )
472: cmp(md,(P)vb[j],(P *)&wb[j]);
473: *rp = (Obj)l;
474: break;
475: default:
476: error("remainder : invalid argument");
477: }
478: }
479: }
480:
481: void Psize(arg,rp)
482: NODE arg;
483: LIST *rp;
484: {
485:
486: int n,m;
487: Q q;
488: NODE t,s;
489:
490: if ( !ARG0(arg) )
491: t = 0;
492: else {
493: switch (OID(ARG0(arg))) {
494: case O_VECT:
495: n = ((VECT)ARG0(arg))->len;
496: STOQ(n,q); MKNODE(t,q,0);
497: break;
498: case O_MAT:
499: n = ((MAT)ARG0(arg))->row; m = ((MAT)ARG0(arg))->col;
500: STOQ(m,q); MKNODE(s,q,0); STOQ(n,q); MKNODE(t,q,s);
501: break;
502: default:
503: error("size : invalid argument"); break;
504: }
505: }
506: MKLIST(*rp,t);
507: }
508:
509: void Pdet(arg,rp)
510: NODE arg;
511: P *rp;
512: {
513: MAT m;
514: int n,i,j,mod;
515: P d;
516: P **mat,**w;
517:
518: m = (MAT)ARG0(arg);
519: asir_assert(m,O_MAT,"det");
520: if ( m->row != m->col )
521: error("det : non-square matrix");
522: else if ( argc(arg) == 1 )
523: detp(CO,(P **)BDY(m),m->row,rp);
524: else {
525: n = m->row; mod = QTOS((Q)ARG1(arg)); mat = (P **)BDY(m);
526: w = (P **)almat_pointer(n,n);
527: for ( i = 0; i < n; i++ )
528: for ( j = 0; j < n; j++ )
529: ptomp(mod,mat[i][j],&w[i][j]);
530: detmp(CO,mod,w,n,&d);
531: mptop(d,rp);
532: }
533: }
534:
535: /*
536: input : a row x col matrix A
537: A[I] <-> A[I][0]*x_0+A[I][1]*x_1+...
538:
539: output : [B,R,C]
540: B : a rank(A) x col-rank(A) matrix
541: R : a vector of length rank(A)
542: C : a vector of length col-rank(A)
543: B[I] <-> x_{R[I]}+B[I][0]x_{C[0]}+B[I][1]x_{C[1]}+...
544: */
545:
546: void Pgeneric_gauss_elim_mod(arg,rp)
547: NODE arg;
548: LIST *rp;
549: {
550: NODE n0;
551: MAT m,mat;
552: VECT rind,cind;
553: Q **tmat;
554: int **wmat;
555: Q *rib,*cib;
556: int *colstat;
557: Q q;
558: int md,i,j,k,l,row,col,t,n,rank;
559:
560: asir_assert(ARG0(arg),O_MAT,"generic_gauss_elim_mod");
561: asir_assert(ARG1(arg),O_N,"generic_gauss_elim_mod");
562: m = (MAT)ARG0(arg); md = QTOS((Q)ARG1(arg));
563: row = m->row; col = m->col; tmat = (Q **)m->body;
564: wmat = (int **)almat(row,col);
565: colstat = (int *)MALLOC_ATOMIC(col*sizeof(int));
566: for ( i = 0; i < row; i++ )
567: for ( j = 0; j < col; j++ )
568: if ( q = (Q)tmat[i][j] ) {
569: t = rem(NM(q),md);
570: if ( t && SGN(q) < 0 )
571: t = (md - t) % md;
572: wmat[i][j] = t;
573: } else
574: wmat[i][j] = 0;
575: rank = generic_gauss_elim_mod(wmat,row,col,md,colstat);
576:
577: MKMAT(mat,rank,col-rank);
578: tmat = (Q **)mat->body;
579: for ( i = 0; i < rank; i++ )
580: for ( j = k = 0; j < col; j++ )
581: if ( !colstat[j] ) {
582: UTOQ(wmat[i][j],tmat[i][k]); k++;
583: }
584:
585: MKVECT(rind,rank);
586: MKVECT(cind,col-rank);
587: rib = (Q *)rind->body; cib = (Q *)cind->body;
588: for ( j = k = l = 0; j < col; j++ )
589: if ( colstat[j] ) {
590: STOQ(j,rib[k]); k++;
591: } else {
592: STOQ(j,cib[l]); l++;
593: }
594: n0 = mknode(3,mat,rind,cind);
595: MKLIST(*rp,n0);
596: }
597:
598: void Pleqm(arg,rp)
599: NODE arg;
600: VECT *rp;
601: {
602: MAT m;
603: VECT vect;
604: pointer **mat;
605: Q *v;
606: Q q;
607: int **wmat;
608: int md,i,j,row,col,t,n,status;
609:
610: asir_assert(ARG0(arg),O_MAT,"leqm");
611: asir_assert(ARG1(arg),O_N,"leqm");
612: m = (MAT)ARG0(arg); md = QTOS((Q)ARG1(arg));
613: row = m->row; col = m->col; mat = m->body;
614: wmat = (int **)almat(row,col);
615: for ( i = 0; i < row; i++ )
616: for ( j = 0; j < col; j++ )
617: if ( q = (Q)mat[i][j] ) {
618: t = rem(NM(q),md);
619: if ( SGN(q) < 0 )
620: t = (md - t) % md;
621: wmat[i][j] = t;
622: } else
623: wmat[i][j] = 0;
624: status = gauss_elim_mod(wmat,row,col,md);
625: if ( status < 0 )
626: *rp = 0;
627: else if ( status > 0 )
628: *rp = (VECT)ONE;
629: else {
630: n = col - 1;
631: MKVECT(vect,n);
632: for ( i = 0, v = (Q *)vect->body; i < n; i++ ) {
633: t = (md-wmat[i][n])%md; STOQ(t,v[i]);
634: }
635: *rp = vect;
636: }
637: }
638:
639: int gauss_elim_mod(mat,row,col,md)
640: int **mat;
641: int row,col,md;
642: {
643: int i,j,k,inv,a,n;
644: int *t,*pivot;
645:
646: n = col - 1;
647: for ( j = 0; j < n; j++ ) {
648: for ( i = j; i < row && !mat[i][j]; i++ );
649: if ( i == row )
650: return 1;
651: if ( i != j ) {
652: t = mat[i]; mat[i] = mat[j]; mat[j] = t;
653: }
654: pivot = mat[j];
655: inv = invm(pivot[j],md);
656: for ( k = j; k <= n; k++ ) {
657: /* pivot[k] = dmar(pivot[k],inv,0,md); */
658: DMAR(pivot[k],inv,0,md,pivot[k])
659: }
660: for ( i = 0; i < row; i++ ) {
661: t = mat[i];
662: if ( i != j && (a = t[j]) )
663: for ( k = j, a = md - a; k <= n; k++ ) {
664: /* t[k] = dmar(pivot[k],a,t[k],md); */
665: DMAR(pivot[k],a,t[k],md,t[k])
666: }
667: }
668: }
669: for ( i = n; i < row && !mat[i][n]; i++ );
670: if ( i == row )
671: return 0;
672: else
673: return -1;
674: }
675:
676: struct oEGT eg_mod,eg_elim,eg_chrem,eg_gschk,eg_intrat,eg_symb;
677:
678: int generic_gauss_elim(mat,nm,dn,rindp,cindp)
679: MAT mat;
680: MAT *nm;
681: Q *dn;
682: int **rindp,**cindp;
683: {
684: int **wmat;
685: Q **bmat;
686: N **tmat;
687: Q *bmi;
688: N *tmi;
689: Q q;
690: int *wmi;
691: int *colstat,*wcolstat,*rind,*cind;
692: int row,col,ind,md,i,j,k,l,t,t1,rank,rank0,inv;
693: N m1,m2,m3,s,u;
694: MAT r,crmat;
695: struct oEGT tmp0,tmp1;
696: struct oEGT eg_mod_split,eg_elim_split,eg_chrem_split;
697: struct oEGT eg_intrat_split,eg_gschk_split;
698: int ret;
699:
700: init_eg(&eg_mod_split); init_eg(&eg_chrem_split);
701: init_eg(&eg_elim_split); init_eg(&eg_intrat_split);
702: init_eg(&eg_gschk_split);
703: bmat = (Q **)mat->body;
704: row = mat->row; col = mat->col;
705: wmat = (int **)almat(row,col);
706: colstat = (int *)MALLOC_ATOMIC(col*sizeof(int));
707: wcolstat = (int *)MALLOC_ATOMIC(col*sizeof(int));
708: for ( ind = 0; ; ind++ ) {
709: if ( Print )
710: fprintf(asir_out,".");
711: md = lprime[ind];
712: get_eg(&tmp0);
713: for ( i = 0; i < row; i++ )
714: for ( j = 0, bmi = bmat[i], wmi = wmat[i]; j < col; j++ )
715: if ( q = (Q)bmi[j] ) {
716: t = rem(NM(q),md);
717: if ( t && SGN(q) < 0 )
718: t = (md - t) % md;
719: wmi[j] = t;
720: } else
721: wmi[j] = 0;
722: get_eg(&tmp1);
723: add_eg(&eg_mod,&tmp0,&tmp1);
724: add_eg(&eg_mod_split,&tmp0,&tmp1);
725: get_eg(&tmp0);
726: rank = generic_gauss_elim_mod(wmat,row,col,md,wcolstat);
727: get_eg(&tmp1);
728: add_eg(&eg_elim,&tmp0,&tmp1);
729: add_eg(&eg_elim_split,&tmp0,&tmp1);
730: if ( !ind ) {
731: RESET:
732: UTON(md,m1);
733: rank0 = rank;
734: bcopy(wcolstat,colstat,col*sizeof(int));
735: MKMAT(crmat,rank,col-rank);
736: MKMAT(r,rank,col-rank); *nm = r;
737: tmat = (N **)crmat->body;
738: for ( i = 0; i < rank; i++ )
739: for ( j = k = 0, tmi = tmat[i], wmi = wmat[i]; j < col; j++ )
740: if ( !colstat[j] ) {
741: UTON(wmi[j],tmi[k]); k++;
742: }
743: } else {
744: if ( rank < rank0 ) {
745: if ( Print )
746: fprintf(asir_out,"lower rank matrix; continuing...\n");
747: continue;
748: } else if ( rank > rank0 ) {
749: if ( Print )
750: fprintf(asir_out,"higher rank matrix; resetting...\n");
751: goto RESET;
752: } else {
753: for ( j = 0; (j<col) && (colstat[j]==wcolstat[j]); j++ );
754: if ( j < col ) {
755: if ( Print )
756: fprintf(asir_out,"inconsitent colstat; resetting...\n");
757: goto RESET;
758: }
759: }
760:
761: get_eg(&tmp0);
762: inv = invm(rem(m1,md),md);
763: UTON(md,m2); muln(m1,m2,&m3);
764: for ( i = 0; i < rank; i++ )
765: for ( j = k = 0, tmi = tmat[i], wmi = wmat[i]; j < col; j++ )
766: if ( !colstat[j] ) {
767: if ( tmi[k] ) {
768: /* f3 = f1+m1*(m1 mod m2)^(-1)*(f2 - f1 mod m2) */
769: t = rem(tmi[k],md);
770: if ( wmi[j] >= t )
771: t = wmi[j]-t;
772: else
773: t = md-(t-wmi[j]);
774: DMAR(t,inv,0,md,t1)
775: UTON(t1,u);
776: muln(m1,u,&s);
777: addn(tmi[k],s,&u); tmi[k] = u;
778: } else if ( wmi[j] ) {
779: /* f3 = m1*(m1 mod m2)^(-1)*f2 */
780: DMAR(wmi[j],inv,0,md,t)
781: UTON(t,u);
782: muln(m1,u,&s); tmi[k] = s;
783: }
784: k++;
785: }
786: m1 = m3;
787: get_eg(&tmp1);
788: add_eg(&eg_chrem,&tmp0,&tmp1);
789: add_eg(&eg_chrem_split,&tmp0,&tmp1);
790:
791: get_eg(&tmp0);
792: ret = intmtoratm(crmat,m1,*nm,dn);
793: get_eg(&tmp1);
794: add_eg(&eg_intrat,&tmp0,&tmp1);
795: add_eg(&eg_intrat_split,&tmp0,&tmp1);
796: if ( ret ) {
797: *rindp = rind = (int *)MALLOC_ATOMIC(rank*sizeof(int));
798: *cindp = cind = (int *)MALLOC_ATOMIC((col-rank)*sizeof(int));
799: for ( j = k = l = 0; j < col; j++ )
800: if ( colstat[j] )
801: rind[k++] = j;
802: else
803: cind[l++] = j;
804: get_eg(&tmp0);
805: if ( gensolve_check(mat,*nm,*dn,rind,cind) )
806: get_eg(&tmp1);
807: add_eg(&eg_gschk,&tmp0,&tmp1);
808: add_eg(&eg_gschk_split,&tmp0,&tmp1);
809: if ( Print ) {
810: print_eg("Mod",&eg_mod_split);
811: print_eg("Elim",&eg_elim_split);
812: print_eg("ChRem",&eg_chrem_split);
813: print_eg("IntRat",&eg_intrat_split);
814: print_eg("Check",&eg_gschk_split);
815: fflush(asir_out);
816: }
817: return rank;
818: }
819: }
820: }
821: }
822:
823: int f4_nocheck;
824:
825: int gensolve_check(mat,nm,dn,rind,cind)
826: MAT mat,nm;
827: Q dn;
828: int *rind,*cind;
829: {
830: int row,col,rank,clen,i,j,k,l;
831: Q s,t,u;
832: Q *w;
833: Q *mati,*nmk;
834:
835: if ( f4_nocheck )
836: return 1;
837: row = mat->row; col = mat->col;
838: rank = nm->row; clen = nm->col;
839: w = (Q *)MALLOC(clen*sizeof(Q));
840: for ( i = 0; i < row; i++ ) {
841: mati = (Q *)mat->body[i];
842: #if 1
843: bzero(w,clen*sizeof(Q));
844: for ( k = 0; k < rank; k++ )
845: for ( l = 0, nmk = (Q *)nm->body[k]; l < clen; l++ ) {
846: mulq(mati[rind[k]],nmk[l],&t);
847: addq(w[l],t,&s); w[l] = s;
848: }
849: for ( j = 0; j < clen; j++ ) {
850: mulq(dn,mati[cind[j]],&t);
851: if ( cmpq(w[j],t) )
852: break;
853: }
854: #else
855: for ( j = 0; j < clen; j++ ) {
856: for ( k = 0, s = 0; k < rank; k++ ) {
857: mulq(mati[rind[k]],nm->body[k][j],&t);
858: addq(s,t,&u); s = u;
859: }
860: mulq(dn,mati[cind[j]],&t);
861: if ( cmpq(s,t) )
862: break;
863: }
864: #endif
865: if ( j != clen )
866: break;
867: }
868: if ( i != row )
869: return 0;
870: else
871: return 1;
872: }
873:
874: /* assuming 0 < c < m */
875:
876: int inttorat(c,m,b,sgnp,nmp,dnp)
877: N c,m,b;
878: int *sgnp;
879: N *nmp,*dnp;
880: {
881: Q qq,t,u1,v1,r1,nm;
882: N q,r,u2,v2,r2;
883:
884: u1 = 0; v1 = ONE; u2 = m; v2 = c;
885: while ( cmpn(v2,b) >= 0 ) {
886: divn(u2,v2,&q,&r2); u2 = v2; v2 = r2;
887: NTOQ(q,1,qq); mulq(qq,v1,&t); subq(u1,t,&r1); u1 = v1; v1 = r1;
888: }
889: if ( cmpn(NM(v1),b) >= 0 )
890: return 0;
891: else {
892: *nmp = v2;
893: *dnp = NM(v1);
894: *sgnp = SGN(v1);
895: return 1;
896: }
897: }
898:
899: /* mat->body = N ** */
900:
901: int intmtoratm(mat,md,nm,dn)
902: MAT mat;
903: N md;
904: MAT nm;
905: Q *dn;
906: {
907: N t,s,b;
908: Q bound,dn0,dn1,nm1,q,tq;
909: int i,j,k,l,row,col;
910: Q **rmat;
911: N **tmat;
912: N *tmi;
913: Q *nmk;
914: N u,unm,udn;
915: int sgn,ret;
916:
917: row = mat->row; col = mat->col;
918: bshiftn(md,1,&t);
919: isqrt(t,&s);
920: bshiftn(s,64,&b);
921: if ( !b )
922: b = ONEN;
923: dn0 = ONE;
924: tmat = (N **)mat->body;
925: rmat = (Q **)nm->body;
926: for ( i = 0; i < row; i++ )
927: for ( j = 0, tmi = tmat[i]; j < col; j++ )
928: if ( tmi[j] ) {
929: muln(tmi[j],NM(dn0),&s);
930: remn(s,md,&u);
931: ret = inttorat(u,md,b,&sgn,&unm,&udn);
932: if ( !ret )
933: return 0;
934: else {
935: NTOQ(unm,sgn,nm1);
936: NTOQ(udn,1,dn1);
937: if ( !UNIQ(dn1) ) {
938: for ( k = 0; k < i; k++ )
939: for ( l = 0, nmk = rmat[k]; l < col; l++ ) {
940: mulq(nmk[l],dn1,&q); nmk[l] = q;
941: }
942: for ( l = 0, nmk = rmat[i]; l < j; l++ ) {
943: mulq(nmk[l],dn1,&q); nmk[l] = q;
944: }
945: }
946: rmat[i][j] = nm1;
947: mulq(dn0,dn1,&q); dn0 = q;
948: }
949: }
950: *dn = dn0;
951: return 1;
952: }
953:
954: int generic_gauss_elim_mod(mat,row,col,md,colstat)
955: int **mat;
956: int row,col,md;
957: int *colstat;
958: {
959: int i,j,k,l,inv,a,rank;
960: int *t,*pivot;
961:
962: for ( rank = 0, j = 0; j < col; j++ ) {
963: for ( i = rank; i < row && !mat[i][j]; i++ );
964: if ( i == row ) {
965: colstat[j] = 0;
966: continue;
967: } else
968: colstat[j] = 1;
969: if ( i != rank ) {
970: t = mat[i]; mat[i] = mat[rank]; mat[rank] = t;
971: }
972: pivot = mat[rank];
973: inv = invm(pivot[j],md);
974: for ( k = j; k < col; k++ )
975: if ( pivot[k] ) {
976: DMAR(pivot[k],inv,0,md,pivot[k])
977: }
978: for ( i = rank+1; i < row; i++ ) {
979: t = mat[i];
980: if ( a = t[j] )
981: for ( k = j, a = md - a; k < col; k++ )
982: if ( pivot[k] ) {
983: DMAR(pivot[k],a,t[k],md,t[k])
984: }
985: }
986: rank++;
987: }
988: for ( j = col-1, l = rank-1; j >= 0; j-- )
989: if ( colstat[j] ) {
990: pivot = mat[l];
991: for ( i = 0; i < l; i++ ) {
992: t = mat[i];
993: if ( a = t[j] )
994: for ( k = j, a = md-a; k < col; k++ )
995: if ( pivot[k] ) {
996: DMAR(pivot[k],a,t[k],md,t[k])
997: }
998: }
999: l--;
1000: }
1001: return rank;
1002: }
1003:
1004: /* LU decomposition; a[i][i] = 1/U[i][i] */
1005:
1006: int lu_gfmmat(mat,md,perm)
1007: GFMMAT mat;
1008: unsigned int md;
1009: int *perm;
1010: {
1011: int row,col;
1012: int i,j,k,l;
1013: unsigned int *t,*pivot;
1014: unsigned int **a;
1015: unsigned int inv,m;
1016:
1017: row = mat->row; col = mat->col;
1018: a = mat->body;
1019: bzero(perm,row*sizeof(int));
1020:
1021: for ( i = 0; i < row; i++ )
1022: perm[i] = i;
1023: for ( k = 0; k < col; k++ ) {
1024: for ( i = k; i < row && !a[i][k]; i++ );
1025: if ( i == row )
1026: return 0;
1027: if ( i != k ) {
1028: j = perm[i]; perm[i] = perm[k]; perm[k] = j;
1029: t = a[i]; a[i] = a[k]; a[k] = t;
1030: }
1031: pivot = a[k];
1032: pivot[k] = inv = invm(pivot[k],md);
1033: for ( i = k+1; i < row; i++ ) {
1034: t = a[i];
1035: if ( m = t[k] ) {
1036: DMAR(inv,m,0,md,t[k])
1037: for ( j = k+1, m = md - t[k]; j < col; j++ )
1038: if ( pivot[j] ) {
1039: DMAR(m,pivot[j],t[j],md,t[j])
1040: }
1041: }
1042: }
1043: }
1044: return 1;
1045: }
1046:
1047: void Pleqm1(arg,rp)
1048: NODE arg;
1049: VECT *rp;
1050: {
1051: MAT m;
1052: VECT vect;
1053: pointer **mat;
1054: Q *v;
1055: Q q;
1056: int **wmat;
1057: int md,i,j,row,col,t,n,status;
1058:
1059: asir_assert(ARG0(arg),O_MAT,"leqm1");
1060: asir_assert(ARG1(arg),O_N,"leqm1");
1061: m = (MAT)ARG0(arg); md = QTOS((Q)ARG1(arg));
1062: row = m->row; col = m->col; mat = m->body;
1063: wmat = (int **)almat(row,col);
1064: for ( i = 0; i < row; i++ )
1065: for ( j = 0; j < col; j++ )
1066: if ( q = (Q)mat[i][j] ) {
1067: t = rem(NM(q),md);
1068: if ( SGN(q) < 0 )
1069: t = (md - t) % md;
1070: wmat[i][j] = t;
1071: } else
1072: wmat[i][j] = 0;
1073: status = gauss_elim_mod1(wmat,row,col,md);
1074: if ( status < 0 )
1075: *rp = 0;
1076: else if ( status > 0 )
1077: *rp = (VECT)ONE;
1078: else {
1079: n = col - 1;
1080: MKVECT(vect,n);
1081: for ( i = 0, v = (Q *)vect->body; i < n; i++ ) {
1082: t = (md-wmat[i][n])%md; STOQ(t,v[i]);
1083: }
1084: *rp = vect;
1085: }
1086: }
1087:
1088: gauss_elim_mod1(mat,row,col,md)
1089: int **mat;
1090: int row,col,md;
1091: {
1092: int i,j,k,inv,a,n;
1093: int *t,*pivot;
1094:
1095: n = col - 1;
1096: for ( j = 0; j < n; j++ ) {
1097: for ( i = j; i < row && !mat[i][j]; i++ );
1098: if ( i == row )
1099: return 1;
1100: if ( i != j ) {
1101: t = mat[i]; mat[i] = mat[j]; mat[j] = t;
1102: }
1103: pivot = mat[j];
1104: inv = invm(pivot[j],md);
1105: for ( k = j; k <= n; k++ )
1106: pivot[k] = dmar(pivot[k],inv,0,md);
1107: for ( i = j+1; i < row; i++ ) {
1108: t = mat[i];
1109: if ( i != j && (a = t[j]) )
1110: for ( k = j, a = md - a; k <= n; k++ )
1111: t[k] = dmar(pivot[k],a,t[k],md);
1112: }
1113: }
1114: for ( i = n; i < row && !mat[i][n]; i++ );
1115: if ( i == row ) {
1116: for ( j = n-1; j >= 0; j-- ) {
1117: for ( i = j-1, a = (md-mat[j][n])%md; i >= 0; i-- ) {
1118: mat[i][n] = dmar(mat[i][j],a,mat[i][n],md);
1119: mat[i][j] = 0;
1120: }
1121: }
1122: return 0;
1123: } else
1124: return -1;
1125: }
1126:
1127: void Pgeninvm(arg,rp)
1128: NODE arg;
1129: LIST *rp;
1130: {
1131: MAT m;
1132: pointer **mat;
1133: Q **tmat;
1134: Q q;
1135: unsigned int **wmat;
1136: int md,i,j,row,col,t,status;
1137: MAT mat1,mat2;
1138: NODE node1,node2;
1139:
1140: asir_assert(ARG0(arg),O_MAT,"leqm1");
1141: asir_assert(ARG1(arg),O_N,"leqm1");
1142: m = (MAT)ARG0(arg); md = QTOS((Q)ARG1(arg));
1143: row = m->row; col = m->col; mat = m->body;
1144: wmat = (unsigned int **)almat(row,col+row);
1145: for ( i = 0; i < row; i++ ) {
1146: bzero((char *)wmat[i],(col+row)*sizeof(int));
1147: for ( j = 0; j < col; j++ )
1148: if ( q = (Q)mat[i][j] ) {
1149: t = rem(NM(q),md);
1150: if ( SGN(q) < 0 )
1151: t = (md - t) % md;
1152: wmat[i][j] = t;
1153: }
1154: wmat[i][col+i] = 1;
1155: }
1156: status = gauss_elim_geninv_mod(wmat,row,col,md);
1157: if ( status > 0 )
1158: *rp = 0;
1159: else {
1160: MKMAT(mat1,col,row); MKMAT(mat2,row-col,row);
1161: for ( i = 0, tmat = (Q **)mat1->body; i < col; i++ )
1162: for ( j = 0; j < row; j++ )
1163: STOQ(wmat[i][j+col],tmat[i][j]);
1164: for ( tmat = (Q **)mat2->body; i < row; i++ )
1165: for ( j = 0; j < row; j++ )
1166: STOQ(wmat[i][j+col],tmat[i-col][j]);
1167: MKNODE(node2,mat2,0); MKNODE(node1,mat1,node2); MKLIST(*rp,node1);
1168: }
1169: }
1170:
1171: int gauss_elim_geninv_mod(mat,row,col,md)
1172: unsigned int **mat;
1173: int row,col,md;
1174: {
1175: int i,j,k,inv,a,n,m;
1176: unsigned int *t,*pivot;
1177:
1178: n = col; m = row+col;
1179: for ( j = 0; j < n; j++ ) {
1180: for ( i = j; i < row && !mat[i][j]; i++ );
1181: if ( i == row )
1182: return 1;
1183: if ( i != j ) {
1184: t = mat[i]; mat[i] = mat[j]; mat[j] = t;
1185: }
1186: pivot = mat[j];
1187: inv = invm(pivot[j],md);
1188: for ( k = j; k < m; k++ )
1189: pivot[k] = dmar(pivot[k],inv,0,md);
1190: for ( i = j+1; i < row; i++ ) {
1191: t = mat[i];
1192: if ( a = t[j] )
1193: for ( k = j, a = md - a; k < m; k++ )
1194: t[k] = dmar(pivot[k],a,t[k],md);
1195: }
1196: }
1197: for ( j = n-1; j >= 0; j-- ) {
1198: pivot = mat[j];
1199: for ( i = j-1; i >= 0; i-- ) {
1200: t = mat[i];
1201: if ( a = t[j] )
1202: for ( k = j, a = md - a; k < m; k++ )
1203: t[k] = dmar(pivot[k],a,t[k],md);
1204: }
1205: }
1206: return 0;
1207: }
1208:
1209: void Psolve_by_lu_gfmmat(arg,rp)
1210: NODE arg;
1211: VECT *rp;
1212: {
1213: GFMMAT lu;
1214: Q *perm,*rhs,*v;
1215: int n,i;
1216: unsigned int md;
1217: unsigned int *b,*sol;
1218: VECT r;
1219:
1220: lu = (GFMMAT)ARG0(arg);
1221: perm = (Q *)BDY((VECT)ARG1(arg));
1222: rhs = (Q *)BDY((VECT)ARG2(arg));
1223: md = (unsigned int)QTOS((Q)ARG3(arg));
1224: n = lu->col;
1225: b = (unsigned int *)MALLOC_ATOMIC(n*sizeof(int));
1226: sol = (unsigned int *)MALLOC_ATOMIC(n*sizeof(int));
1227: for ( i = 0; i < n; i++ )
1228: b[i] = QTOS(rhs[QTOS(perm[i])]);
1229: solve_by_lu_gfmmat(lu,md,b,sol);
1230: MKVECT(r,n);
1231: for ( i = 0, v = (Q *)r->body; i < n; i++ )
1232: STOQ(sol[i],v[i]);
1233: *rp = r;
1234: }
1235:
1236: void solve_by_lu_gfmmat(lu,md,b,x)
1237: GFMMAT lu;
1238: unsigned int md;
1239: unsigned int *b;
1240: unsigned int *x;
1241: {
1242: int n;
1243: unsigned int **a;
1244: unsigned int *y;
1245: int i,j;
1246: unsigned int t,m;
1247:
1248: n = lu->col;
1249: a = lu->body;
1250: y = (unsigned int *)MALLOC_ATOMIC(n*sizeof(int));
1251: /* solve Ly=b */
1252: for ( i = 0; i < n; i++ ) {
1253: for ( t = b[i], j = 0; j < i; j++ )
1254: if ( a[i][j] ) {
1255: m = md - a[i][j];
1256: DMAR(m,y[j],t,md,t)
1257: }
1258: y[i] = t;
1259: }
1260: /* solve Ux=y */
1261: for ( i = n-1; i >= 0; i-- ) {
1262: for ( t = y[i], j =i+1; j < n; j++ )
1263: if ( a[i][j] ) {
1264: m = md - a[i][j];
1265: DMAR(m,x[j],t,md,t)
1266: }
1267: /* a[i][i] = 1/U[i][i] */
1268: DMAR(t,a[i][i],0,md,x[i])
1269: }
1270: }
1271:
1272: void Plu_gfmmat(arg,rp)
1273: NODE arg;
1274: LIST *rp;
1275: {
1276: MAT m;
1277: GFMMAT mm;
1278: unsigned int md;
1279: int i,row,col,status;
1280: int *iperm;
1281: Q *v;
1282: VECT perm;
1283: NODE n0;
1284:
1285: asir_assert(ARG0(arg),O_MAT,"mat_to_gfmmat");
1286: asir_assert(ARG1(arg),O_N,"mat_to_gfmmat");
1287: m = (MAT)ARG0(arg); md = (unsigned int)QTOS((Q)ARG1(arg));
1288: mat_to_gfmmat(m,md,&mm);
1289: row = m->row;
1290: col = m->col;
1291: iperm = (int *)MALLOC_ATOMIC(row*sizeof(int));
1292: status = lu_gfmmat(mm,md,iperm);
1293: if ( !status )
1294: n0 = 0;
1295: else {
1296: MKVECT(perm,row);
1297: for ( i = 0, v = (Q *)perm->body; i < row; i++ )
1298: STOQ(iperm[i],v[i]);
1299: n0 = mknode(2,mm,perm);
1300: }
1301: MKLIST(*rp,n0);
1302: }
1303:
1304: void Pmat_to_gfmmat(arg,rp)
1305: NODE arg;
1306: GFMMAT *rp;
1307: {
1308: MAT m;
1309: unsigned int md;
1310:
1311: asir_assert(ARG0(arg),O_MAT,"mat_to_gfmmat");
1312: asir_assert(ARG1(arg),O_N,"mat_to_gfmmat");
1313: m = (MAT)ARG0(arg); md = (unsigned int)QTOS((Q)ARG1(arg));
1314: mat_to_gfmmat(m,md,rp);
1315: }
1316:
1317: void mat_to_gfmmat(m,md,rp)
1318: MAT m;
1319: unsigned int md;
1320: GFMMAT *rp;
1321: {
1322: unsigned int **wmat;
1323: unsigned int t;
1324: Q **mat;
1325: Q q;
1326: int i,j,row,col;
1327:
1328: row = m->row; col = m->col; mat = (Q **)m->body;
1329: wmat = (unsigned int **)almat(row,col);
1330: for ( i = 0; i < row; i++ ) {
1331: bzero((char *)wmat[i],col*sizeof(unsigned int));
1332: for ( j = 0; j < col; j++ )
1333: if ( q = mat[i][j] ) {
1334: t = (unsigned int)rem(NM(q),md);
1335: if ( SGN(q) < 0 )
1336: t = (md - t) % md;
1337: wmat[i][j] = t;
1338: }
1339: }
1340: TOGFMMAT(row,col,wmat,*rp);
1341: }
1342:
1343: void Pgeninvm_swap(arg,rp)
1344: NODE arg;
1345: LIST *rp;
1346: {
1347: MAT m;
1348: pointer **mat;
1349: Q **tmat;
1350: Q *tvect;
1351: Q q;
1352: unsigned int **wmat,**invmat;
1353: int *index;
1354: unsigned int t,md;
1355: int i,j,row,col,status;
1356: MAT mat1;
1357: VECT vect1;
1358: NODE node1,node2;
1359:
1360: asir_assert(ARG0(arg),O_MAT,"geninvm_swap");
1361: asir_assert(ARG1(arg),O_N,"geninvm_swap");
1362: m = (MAT)ARG0(arg); md = QTOS((Q)ARG1(arg));
1363: row = m->row; col = m->col; mat = m->body;
1364: wmat = (unsigned int **)almat(row,col+row);
1365: for ( i = 0; i < row; i++ ) {
1366: bzero((char *)wmat[i],(col+row)*sizeof(int));
1367: for ( j = 0; j < col; j++ )
1368: if ( q = (Q)mat[i][j] ) {
1369: t = (unsigned int)rem(NM(q),md);
1370: if ( SGN(q) < 0 )
1371: t = (md - t) % md;
1372: wmat[i][j] = t;
1373: }
1374: wmat[i][col+i] = 1;
1375: }
1376: status = gauss_elim_geninv_mod_swap(wmat,row,col,md,&invmat,&index);
1377: if ( status > 0 )
1378: *rp = 0;
1379: else {
1380: MKMAT(mat1,col,col);
1381: for ( i = 0, tmat = (Q **)mat1->body; i < col; i++ )
1382: for ( j = 0; j < col; j++ )
1383: UTOQ(invmat[i][j],tmat[i][j]);
1384: MKVECT(vect1,row);
1385: for ( i = 0, tvect = (Q *)vect1->body; i < row; i++ )
1386: STOQ(index[i],tvect[i]);
1387: MKNODE(node2,vect1,0); MKNODE(node1,mat1,node2); MKLIST(*rp,node1);
1388: }
1389: }
1390:
1391: gauss_elim_geninv_mod_swap(mat,row,col,md,invmatp,indexp)
1392: unsigned int **mat;
1393: int row,col;
1394: unsigned int md;
1395: unsigned int ***invmatp;
1396: int **indexp;
1397: {
1398: int i,j,k,inv,a,n,m;
1399: unsigned int *t,*pivot,*s;
1400: int *index;
1401: unsigned int **invmat;
1402:
1403: n = col; m = row+col;
1404: *indexp = index = (int *)MALLOC_ATOMIC(row*sizeof(int));
1405: for ( i = 0; i < row; i++ )
1406: index[i] = i;
1407: for ( j = 0; j < n; j++ ) {
1408: for ( i = j; i < row && !mat[i][j]; i++ );
1409: if ( i == row ) {
1410: *indexp = 0; *invmatp = 0; return 1;
1411: }
1412: if ( i != j ) {
1413: t = mat[i]; mat[i] = mat[j]; mat[j] = t;
1414: k = index[i]; index[i] = index[j]; index[j] = k;
1415: }
1416: pivot = mat[j];
1417: inv = (unsigned int)invm(pivot[j],md);
1418: for ( k = j; k < m; k++ )
1419: if ( pivot[k] )
1420: pivot[k] = (unsigned int)dmar(pivot[k],inv,0,md);
1421: for ( i = j+1; i < row; i++ ) {
1422: t = mat[i];
1423: if ( a = t[j] )
1424: for ( k = j, a = md - a; k < m; k++ )
1425: if ( pivot[k] )
1426: t[k] = dmar(pivot[k],a,t[k],md);
1427: }
1428: }
1429: for ( j = n-1; j >= 0; j-- ) {
1430: pivot = mat[j];
1431: for ( i = j-1; i >= 0; i-- ) {
1432: t = mat[i];
1433: if ( a = t[j] )
1434: for ( k = j, a = md - a; k < m; k++ )
1435: if ( pivot[k] )
1436: t[k] = dmar(pivot[k],a,t[k],md);
1437: }
1438: }
1439: *invmatp = invmat = (unsigned int **)almat(col,col);
1440: for ( i = 0; i < col; i++ )
1441: for ( j = 0, s = invmat[i], t = mat[i]; j < col; j++ )
1442: s[j] = t[col+index[j]];
1443: return 0;
1444: }
1445:
1446: void _addn(N,N,N);
1447: int _subn(N,N,N);
1448: void _muln(N,N,N);
1449:
1450: void inner_product_int(a,b,n,r)
1451: Q *a,*b;
1452: int n;
1453: Q *r;
1454: {
1455: int la,lb,i;
1456: int sgn,sgn1;
1457: N wm,wma,sum,t;
1458:
1459: for ( la = lb = 0, i = 0; i < n; i++ ) {
1460: if ( a[i] )
1461: if ( DN(a[i]) )
1462: error("inner_product_int : invalid argument");
1463: else
1464: la = MAX(PL(NM(a[i])),la);
1465: if ( b[i] )
1466: if ( DN(b[i]) )
1467: error("inner_product_int : invalid argument");
1468: else
1469: lb = MAX(PL(NM(b[i])),lb);
1470: }
1471: sgn = 0;
1472: sum= NALLOC(la+lb+2);
1473: bzero((char *)sum,(la+lb+3)*sizeof(unsigned int));
1474: wm = NALLOC(la+lb+2);
1475: wma = NALLOC(la+lb+2);
1476: for ( i = 0; i < n; i++ ) {
1477: if ( !a[i] || !b[i] )
1478: continue;
1479: _muln(NM(a[i]),NM(b[i]),wm);
1480: sgn1 = SGN(a[i])*SGN(b[i]);
1481: if ( !sgn ) {
1482: sgn = sgn1;
1483: t = wm; wm = sum; sum = t;
1484: } else if ( sgn == sgn1 ) {
1485: _addn(sum,wm,wma);
1486: if ( !PL(wma) )
1487: sgn = 0;
1488: t = wma; wma = sum; sum = t;
1489: } else {
1490: /* sgn*sum+sgn1*wm = sgn*(sum-wm) */
1491: sgn *= _subn(sum,wm,wma);
1492: t = wma; wma = sum; sum = t;
1493: }
1494: }
1495: GC_free(wm);
1496: GC_free(wma);
1497: if ( !sgn ) {
1498: GC_free(sum);
1499: *r = 0;
1500: } else
1501: NTOQ(sum,sgn,*r);
1502: }
1503:
1504: void Pmul_mat_vect_int(arg,rp)
1505: NODE arg;
1506: VECT *rp;
1507: {
1508: MAT mat;
1509: VECT vect,r;
1510: int row,col,i;
1511:
1512: mat = (MAT)ARG0(arg);
1513: vect = (VECT)ARG1(arg);
1514: row = mat->row;
1515: col = mat->col;
1516: MKVECT(r,row);
1517: for ( i = 0; i < row; i++ )
1518: inner_product_int(mat->body[i],vect->body,col,&r->body[i]);
1519: *rp = r;
1520: }
1521:
1522: void Pnbpoly_up2(arg,rp)
1523: NODE arg;
1524: GF2N *rp;
1525: {
1526: int m,type,ret;
1527: UP2 r;
1528:
1529: m = QTOS((Q)ARG0(arg));
1530: type = QTOS((Q)ARG1(arg));
1531: ret = generate_ONB_polynomial(&r,m,type);
1532: if ( ret == 0 )
1533: MKGF2N(r,*rp);
1534: else
1535: *rp = 0;
1536: }
1537:
1538: void Px962_irredpoly_up2(arg,rp)
1539: NODE arg;
1540: GF2N *rp;
1541: {
1542: int m,type,ret,w;
1543: GF2N prev;
1544: UP2 r;
1545:
1546: m = QTOS((Q)ARG0(arg));
1547: prev = (GF2N)ARG1(arg);
1548: if ( !prev ) {
1549: w = (m>>5)+1; NEWUP2(r,w); r->w = 0;
1550: bzero((char *)r->b,w*sizeof(unsigned int));
1551: } else {
1552: r = prev->body;
1553: if ( degup2(r) != m ) {
1554: w = (m>>5)+1; NEWUP2(r,w); r->w = 0;
1555: bzero((char *)r->b,w*sizeof(unsigned int));
1556: }
1557: }
1558: ret = _generate_irreducible_polynomial(r,m,type);
1559: if ( ret == 0 )
1560: MKGF2N(r,*rp);
1561: else
1562: *rp = 0;
1563: }
1564:
1565: void Pirredpoly_up2(arg,rp)
1566: NODE arg;
1567: GF2N *rp;
1568: {
1569: int m,type,ret,w;
1570: GF2N prev;
1571: UP2 r;
1572:
1573: m = QTOS((Q)ARG0(arg));
1574: prev = (GF2N)ARG1(arg);
1575: if ( !prev ) {
1576: w = (m>>5)+1; NEWUP2(r,w); r->w = 0;
1577: bzero((char *)r->b,w*sizeof(unsigned int));
1578: } else {
1579: r = prev->body;
1580: if ( degup2(r) != m ) {
1581: w = (m>>5)+1; NEWUP2(r,w); r->w = 0;
1582: bzero((char *)r->b,w*sizeof(unsigned int));
1583: }
1584: }
1585: ret = _generate_good_irreducible_polynomial(r,m,type);
1586: if ( ret == 0 )
1587: MKGF2N(r,*rp);
1588: else
1589: *rp = 0;
1590: }
1591:
1592: /*
1593: * f = type 'type' normal polynomial of degree m if exists
1594: * IEEE P1363 A.7.2
1595: *
1596: * return value : 0 --- exists
1597: * 1 --- does not exist
1598: * -1 --- failure (memory allocation error)
1599: */
1600:
1601: int generate_ONB_polynomial(UP2 *rp,int m,int type)
1602: {
1603: int i,r;
1604: int w;
1605: UP2 f,f0,f1,f2,t;
1606:
1607: w = (m>>5)+1;
1608: switch ( type ) {
1609: case 1:
1610: if ( !TypeT_NB_check(m,1) ) return 1;
1611: NEWUP2(f,w); *rp = f; f->w = w;
1612: /* set all the bits */
1613: for ( i = 0; i < w; i++ )
1614: f->b[i] = 0xffffffff;
1615: /* mask the top word if necessary */
1616: if ( r = (m+1)&31 )
1617: f->b[w-1] &= (1<<r)-1;
1618: return 0;
1619: break;
1620: case 2:
1621: if ( !TypeT_NB_check(m,2) ) return 1;
1622: NEWUP2(f,w); *rp = f;
1623: W_NEWUP2(f0,w);
1624: W_NEWUP2(f1,w);
1625: W_NEWUP2(f2,w);
1626:
1627: /* recursion for genrating Type II normal polynomial */
1628:
1629: /* f0 = 1, f1 = t+1 */
1630: f0->w = 1; f0->b[0] = 1;
1631: f1->w = 1; f1->b[0] = 3;
1632: for ( i = 2; i <= m; i++ ) {
1633: /* f2 = t*f1+f0 */
1634: _bshiftup2(f1,-1,f2);
1635: _addup2_destructive(f2,f0);
1636: /* cyclic change of the variables */
1637: t = f0; f0 = f1; f1 = f2; f2 = t;
1638: }
1639: _copyup2(f1,f);
1640: return 0;
1641: break;
1642: default:
1643: return -1;
1644: break;
1645: }
1646: }
1647:
1648: /*
1649: * f = an irreducible trinomial or pentanomial of degree d 'after' f
1650: * return value : 0 --- exists
1651: * 1 --- does not exist (exhaustion)
1652: */
1653:
1654: int _generate_irreducible_polynomial(UP2 f,int d)
1655: {
1656: int ret,i,j,k,nz,i0,j0,k0;
1657: int w;
1658: unsigned int *fd;
1659:
1660: /*
1661: * if f = x^d+x^i+1 then i0 <- i, j0 <- 0, k0 <-0.
1662: * if f = x^d+x^k+x^j+x^i+1 (k>j>i) then i0 <- i, j0 <- j, k0 <-k.
1663: * otherwise i0,j0,k0 is set to 0.
1664: */
1665:
1666: fd = f->b;
1667: w = (d>>5)+1;
1668: if ( f->w && (d==degup2(f)) ) {
1669: for ( nz = 0, i = d; i >= 0; i-- )
1670: if ( fd[i>>5]&(1<<(i&31)) ) nz++;
1671: switch ( nz ) {
1672: case 3:
1673: for ( i0 = 1; !(fd[i0>>5]&(1<<(i0&31))) ; i0++ );
1674: /* reset i0-th bit */
1675: fd[i0>>5] &= ~(1<<(i0&31));
1676: j0 = k0 = 0;
1677: break;
1678: case 5:
1679: for ( i0 = 1; !(fd[i0>>5]&(1<<(i0&31))) ; i0++ );
1680: /* reset i0-th bit */
1681: fd[i0>>5] &= ~(1<<(i0&31));
1682: for ( j0 = i0+1; !(fd[j0>>5]&(1<<(j0&31))) ; j0++ );
1683: /* reset j0-th bit */
1684: fd[j0>>5] &= ~(1<<(j0&31));
1685: for ( k0 = j0+1; !(fd[k0>>5]&(1<<(k0&31))) ; k0++ );
1686: /* reset k0-th bit */
1687: fd[k0>>5] &= ~(1<<(k0&31));
1688: break;
1689: default:
1690: f->w = 0; break;
1691: }
1692: } else
1693: f->w = 0;
1694:
1695: if ( !f->w ) {
1696: fd = f->b;
1697: f->w = w; fd[0] |= 1; fd[d>>5] |= (1<<(d&31));
1698: i0 = j0 = k0 = 0;
1699: }
1700: /* if j0 > 0 then f is already a pentanomial */
1701: if ( j0 > 0 ) goto PENTA;
1702:
1703: /* searching for an irreducible trinomial */
1704:
1705: for ( i = 1; 2*i <= d; i++ ) {
1706: /* skip the polynomials 'before' f */
1707: if ( i < i0 ) continue;
1708: if ( i == i0 ) { i0 = 0; continue; }
1709: /* set i-th bit */
1710: fd[i>>5] |= (1<<(i&31));
1711: ret = irredcheck_dddup2(f);
1712: if ( ret == 1 ) return 0;
1713: /* reset i-th bit */
1714: fd[i>>5] &= ~(1<<(i&31));
1715: }
1716:
1717: /* searching for an irreducible pentanomial */
1718: PENTA:
1719: for ( i = 1; i < d; i++ ) {
1720: /* skip the polynomials 'before' f */
1721: if ( i < i0 ) continue;
1722: if ( i == i0 ) i0 = 0;
1723: /* set i-th bit */
1724: fd[i>>5] |= (1<<(i&31));
1725: for ( j = i+1; j < d; j++ ) {
1726: /* skip the polynomials 'before' f */
1727: if ( j < j0 ) continue;
1728: if ( j == j0 ) j0 = 0;
1729: /* set j-th bit */
1730: fd[j>>5] |= (1<<(j&31));
1731: for ( k = j+1; k < d; k++ ) {
1732: /* skip the polynomials 'before' f */
1733: if ( k < k0 ) continue;
1734: else if ( k == k0 ) { k0 = 0; continue; }
1735: /* set k-th bit */
1736: fd[k>>5] |= (1<<(k&31));
1737: ret = irredcheck_dddup2(f);
1738: if ( ret == 1 ) return 0;
1739: /* reset k-th bit */
1740: fd[k>>5] &= ~(1<<(k&31));
1741: }
1742: /* reset j-th bit */
1743: fd[j>>5] &= ~(1<<(j&31));
1744: }
1745: /* reset i-th bit */
1746: fd[i>>5] &= ~(1<<(i&31));
1747: }
1748: /* exhausted */
1749: return 1;
1750: }
1751:
1752: /*
1753: * f = an irreducible trinomial or pentanomial of degree d 'after' f
1754: *
1755: * searching strategy:
1756: * trinomial x^d+x^i+1:
1757: * i is as small as possible.
1758: * trinomial x^d+x^i+x^j+x^k+1:
1759: * i is as small as possible.
1760: * For such i, j is as small as possible.
1761: * For such i and j, 'k' is as small as possible.
1762: *
1763: * return value : 0 --- exists
1764: * 1 --- does not exist (exhaustion)
1765: */
1766:
1767: int _generate_good_irreducible_polynomial(UP2 f,int d)
1768: {
1769: int ret,i,j,k,nz,i0,j0,k0;
1770: int w;
1771: unsigned int *fd;
1772:
1773: /*
1774: * if f = x^d+x^i+1 then i0 <- i, j0 <- 0, k0 <-0.
1775: * if f = x^d+x^k+x^j+x^i+1 (k>j>i) then i0 <- i, j0 <- j, k0 <-k.
1776: * otherwise i0,j0,k0 is set to 0.
1777: */
1778:
1779: fd = f->b;
1780: w = (d>>5)+1;
1781: if ( f->w && (d==degup2(f)) ) {
1782: for ( nz = 0, i = d; i >= 0; i-- )
1783: if ( fd[i>>5]&(1<<(i&31)) ) nz++;
1784: switch ( nz ) {
1785: case 3:
1786: for ( i0 = 1; !(fd[i0>>5]&(1<<(i0&31))) ; i0++ );
1787: /* reset i0-th bit */
1788: fd[i0>>5] &= ~(1<<(i0&31));
1789: j0 = k0 = 0;
1790: break;
1791: case 5:
1792: for ( i0 = 1; !(fd[i0>>5]&(1<<(i0&31))) ; i0++ );
1793: /* reset i0-th bit */
1794: fd[i0>>5] &= ~(1<<(i0&31));
1795: for ( j0 = i0+1; !(fd[j0>>5]&(1<<(j0&31))) ; j0++ );
1796: /* reset j0-th bit */
1797: fd[j0>>5] &= ~(1<<(j0&31));
1798: for ( k0 = j0+1; !(fd[k0>>5]&(1<<(k0&31))) ; k0++ );
1799: /* reset k0-th bit */
1800: fd[k0>>5] &= ~(1<<(k0&31));
1801: break;
1802: default:
1803: f->w = 0; break;
1804: }
1805: } else
1806: f->w = 0;
1807:
1808: if ( !f->w ) {
1809: fd = f->b;
1810: f->w = w; fd[0] |= 1; fd[d>>5] |= (1<<(d&31));
1811: i0 = j0 = k0 = 0;
1812: }
1813: /* if j0 > 0 then f is already a pentanomial */
1814: if ( j0 > 0 ) goto PENTA;
1815:
1816: /* searching for an irreducible trinomial */
1817:
1818: for ( i = 1; 2*i <= d; i++ ) {
1819: /* skip the polynomials 'before' f */
1820: if ( i < i0 ) continue;
1821: if ( i == i0 ) { i0 = 0; continue; }
1822: /* set i-th bit */
1823: fd[i>>5] |= (1<<(i&31));
1824: ret = irredcheck_dddup2(f);
1825: if ( ret == 1 ) return 0;
1826: /* reset i-th bit */
1827: fd[i>>5] &= ~(1<<(i&31));
1828: }
1829:
1830: /* searching for an irreducible pentanomial */
1831: PENTA:
1832: for ( i = 3; i < d; i++ ) {
1833: /* skip the polynomials 'before' f */
1834: if ( i < i0 ) continue;
1835: if ( i == i0 ) i0 = 0;
1836: /* set i-th bit */
1837: fd[i>>5] |= (1<<(i&31));
1838: for ( j = 2; j < i; j++ ) {
1839: /* skip the polynomials 'before' f */
1840: if ( j < j0 ) continue;
1841: if ( j == j0 ) j0 = 0;
1842: /* set j-th bit */
1843: fd[j>>5] |= (1<<(j&31));
1844: for ( k = 1; k < j; k++ ) {
1845: /* skip the polynomials 'before' f */
1846: if ( k < k0 ) continue;
1847: else if ( k == k0 ) { k0 = 0; continue; }
1848: /* set k-th bit */
1849: fd[k>>5] |= (1<<(k&31));
1850: ret = irredcheck_dddup2(f);
1851: if ( ret == 1 ) return 0;
1852: /* reset k-th bit */
1853: fd[k>>5] &= ~(1<<(k&31));
1854: }
1855: /* reset j-th bit */
1856: fd[j>>5] &= ~(1<<(j&31));
1857: }
1858: /* reset i-th bit */
1859: fd[i>>5] &= ~(1<<(i&31));
1860: }
1861: /* exhausted */
1862: return 1;
1863: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>