1 /* ------------------------------------------------------------------ */
2 /* SARAG - Linear Algebra */
3 /* by Fabrizio Caruso modified by Alexandre Le Meur and Marie-Françoise Roy */
6 /* It counts the sign change of a determinant after */
7 /* i consecutive row changes */
8 revRowsCount(i) := (-1)^(i*(i-1)/2);
24 size : first(third(arrayinfo(m)))+1,
25 for k : 0 thru size-1 do
36 /* Fix columns exchanges */
37 fixColumns(m,colEx) :=
39 colEx : reverse(colEx),
40 for i : 1 thru colEx do
41 exchangeCols(m,colEx[i][1],colEx[i][2]),
46 removeElements(lst,blackList) :=
47 removeElementsAux(lst,blackList,[],1);
49 removeElementsAux(lst,blackList,res,indx) :=
53 if first(blackList)=indx then
54 removeElementsAux(rest(lst,1),rest(blackList,1),res,indx+1)
56 if indx<first(blackList) then
57 removeElementsAux(rest(lst,1),blackList,
58 endcons(first(lst),res),indx+1)
60 removeElementsAux(rest(lst,1),rest(blackList),
61 endcons(first(lst),res),indx+1);
65 gaussTriangularize(m) :=
67 [removeElements(array2list(first(lst)),
69 second(lst)])(gaussElimArray(m));
73 [array2list(first(lst)),second(lst),third(lst)])(gaussElimArray(m));
75 /* It performs Gaussian elimiation on a matrix */
76 /* by columns exchange */
82 k,i,j,r,flag,colExList,
85 offset : 0, /* it compensates for zero rows */
89 g : make_array('any,nRows,nCols),
94 for i : 0 thru nRows-1 do
95 for j : 0 thru nCols-1 do
101 k : 0, /* index of the row of the pivot */
102 r : 0, /* index of the column of the pivot */
104 while r<= nCols-1 and k <= nRows-1 do
107 /* Test for zero row */
110 while flag and j <= nCols do
111 if not(g[k+1-1,j-1]=0) then
117 zeroRows : endcons(k,zeroRows),
121 if not(j=r+1) and not(flag) then
123 colExList : endcons([r+1-1,j-1],colExList),
124 exchangeCol(g,r+1-1,j-1)
128 for i : k+2 thru nRows do
130 for j : r+2 thru nCols do
133 g[i-1,j-1] - g[i-1,r+1-1]*
134 g[k+1-1,j-1]/g[k+1-1,r+1-1]
143 ), /* end main while loop */
145 /* add zero rows below the upper square part to zeroRows*/
148 zeroRows : append(zeroRows, makelist(i,i,k,nRows-1)),
150 return([g,colExList,zeroRows])
154 gaussElimMod(m,gmod) :=
155 gaussElimWithDivisionMod(m,gmod);
159 [array2list(first(lst)),second(lst),third(lst)])(gaussElimModArray(m,gmod));
162 gaussElimWithDivisionMod(m,gmod) :=
164 [array2list(first(lst)),second(lst),third(lst)])(gaussElimWithDivisionModArray(m,gmod));
166 /* It performs Gaussian elimiation on a matrix */
167 /* by columns exchange */
168 gaussElimWithDivisionModArray(m,gmod) :=
171 nCols : length(m[1]),
172 g : make_array('any),
173 k,i,j,r,flag,colExList,
174 zeroRows,offset,modInv],
176 offset : 0, /* it compensates for zero rows */
178 modulus : gmod, /* it sets the modular computation */
182 g : make_array('any,nRows,nCols),
187 for i : 0 thru nRows-1 do
188 for j : 0 thru nCols-1 do
189 g[i,j] : m[i+1][j+1],
193 k : 0, /* index of the row of the pivot */
194 r : 0, /* index of the column of the pivot */
196 while r<= nCols-1 and k <= nRows-1 do
199 /* Test for zero row */
202 while flag and j <= nCols do
203 if not(g[k+1-1,j-1]=0) then
209 zeroRows : endcons(k,zeroRows),
213 if not(j=r+1) and not(flag) then
215 colExList : endcons([r+1-1,j-1],colExList),
216 exchangeCol(g,r+1-1,j-1)
220 for i : k+2 thru nRows do
222 /* it computes the inverse for the column */
223 modInv : rat(1/g[k+1-1,r+1-1]),
225 for j : r+2 thru nCols do
229 ratexpand(g[i-1,j-1] - g[i-1,r+1-1]*g[k+1-1,j-1]*modInv)
239 ), /* end main while loop */
241 /* add zero rows below the upper square part to zeroRows*/
244 zeroRows : append(zeroRows, makelist(i,i,k,nRows-1)),
246 modulus : false, /* it resets the computation over the rationals */
247 return([g,colExList,zeroRows])
251 gaussElimWithoutDivisionMod(m,gmod) :=
253 [array2list(first(lst)),
254 second(lst),third(lst)])(gaussElimWithoutDivisionModArray(m,gmod));
256 gaussElimWithoutDivisionModArray(m,gmod) :=
259 nCols : length(m[1]),
260 g : make_array('any),
261 k,i,j,r,flag,colExList,
264 offset : 0, /* it compensates for zero rows */
266 modulus : gmod, /* it sets the modular computation */
270 g : make_array('any,nRows,nCols),
275 for i : 0 thru nRows-1 do
276 for j : 0 thru nCols-1 do
277 g[i,j] : m[i+1][j+1],
281 k : 0, /* index of the row of the pivot */
282 r : 0, /* index of the column of the pivot */
284 while r<= nCols-1 and k <= nRows-1 do
287 /* Test for zero row */
290 while flag and j <= nCols do
291 if not(g[k+1-1,j-1]=0) then
297 zeroRows : endcons(k,zeroRows),
301 if not(j=r+1) and not(flag) then
303 colExList : endcons([r+1-1,j-1],colExList),
304 exchangeCol(g,r+1-1,j-1)
308 for i : k+2 thru nRows do
310 /* it computes the inverse for the column */
312 modInv : rat(1/g[k+1-1,r+1-1]),
314 for j : r+2 thru nCols do
318 ratexpand(g[k+1-1,r+1-1]*g[i-1,j-1] - g[i-1,r+1-1]*g[k+1-1,j-1])
328 ), /* end main while loop */
330 /* add zero rows below the upper square part to zeroRows*/
333 zeroRows : append(zeroRows, makelist(i,i,k,nRows-1)),
335 modulus : false, /* it resets the computation over the rationals */
336 return([g,colExList,zeroRows])
339 echelonMod(m,gmod) :=
340 echelonWithDivisionMod(m,gmod);
343 echelonWithDivisionMod(m,gmod) :=
345 [array2list(first(lst)),second(lst),third(lst)])(echelonWithDivisionModArray(m,gmod));
347 /* It performs Gaussian elimiation on a matrix */
348 /* by columns exchange */
349 echelonWithDivisionModArray(m,gmod) :=
352 nCols : length(m[1]),
353 g : make_array('any),
354 k,i,j,r,flag,colExList,
355 zeroRows,offset,modInv],
357 offset : 0, /* it compensates for zero rows */
359 modulus : gmod, /* it sets the modular computation */
363 g : make_array('any,nRows,nCols),
367 for i : 0 thru nRows-1 do
368 for j : 0 thru nCols-1 do
369 g[i,j] : m[i+1][j+1],
373 k : 0, /* index of the row of the pivot */
374 r : 0, /* index of the column of the pivot */
376 while r<= nCols-1 and k <= nRows-1 do
379 /* Test for zero row */
382 while flag and j <= nCols do
384 if not(g[k+1-1,j-1]=0) then
392 zeroRows : endcons(k,zeroRows),
396 if not(j=r+1) and not(flag) then
398 colExList : endcons([r+1-1,j-1],colExList),
399 exchangeCol(g,r+1-1,j-1)
406 /* it computes the inverse for the column */
407 modInv : rat(1/g[k+1-1,r+1-1]),
410 for j : r+2 thru nCols do
414 ratexpand(g[i-1,j-1] - g[i-1,r+1-1]*g[k+1-1,j-1]*modInv)
423 for i : k+2 thru nRows do
425 /* it computes the inverse for the column */
426 modInv : rat(1/g[k+1-1,r+1-1]),
429 for j : r+2 thru nCols do
433 ratexpand(g[i-1,j-1] - g[i-1,r+1-1]*g[k+1-1,j-1]*modInv)
443 ), /* end main while loop */
445 /* add zero rows below the upper square part to zeroRows*/
448 zeroRows : append(zeroRows, makelist(i,i,k,nRows-1)),
450 modulus : false, /* it resets the computation over the rationals */
451 return([g,colExList,zeroRows])
455 /* It computes the determinant by Gauss elimination */
459 g : make_array('any),
460 k,i,j,flag,colEx,size],
467 for i : 0 thru size-1 do
468 for j : 0 thru size-1 do
469 g[i,j] : m[i+1][j+1],
472 for k : 0 thru size-2 do
474 /* Test for zero row */
477 while flag and j <= size do
478 if not(g[k+1-1,j-1]=0) then
485 /* column exchange check */
488 /* column exchange required */
490 exchangeCol(g,k+1-1,j-1)
493 for i : k+2 thru size do
495 for j : k+2 thru size do
496 g[i-1,j-1] : g[i-1,j-1] - g[i-1,k+1-1]*g[k+1-1,j-1]/g[k+1-1,k+1-1],
500 return(expand((-1)^colEx * product(g[i,i],i,0,size-1)))
505 /* It computes the determinant by Dogdson-Jordan-Bareiss method */
509 g : make_array('any),
510 k,i,j,flag,colEx,oldPivot, size],
515 for i : 0 thru size-1 do
516 for j : 0 thru size-1 do
517 g[i,j] : m[i+1][j+1],
520 for k : 0 thru size-2 do
522 /* Test for zero row */
525 while flag and j <= size do
526 if not(g[k+1-1,j-1]=0) then
532 /* column exchange check */
535 /* column exchange required */
537 exchangeCol(g,k+1-1,j-1)
540 for i : k+2 thru size do /* column loop */
542 for j : k+2 thru size do /* row loop */
547 oldPivot : g[k-1,k-1],
548 g[i-1,j-1] : (g[k+1-1,k+1-1]*g[i-1,j-1]-g[i-1,k+1-1]*g[k+1-1,j-1])/oldPivot
554 return(expand((-1)^colEx * g[size-1,size-1]))
558 princSubMat(m,ord) :=
559 block([res:make_array('any,ord,ord),i,j],
561 for i : 0 thru ord-1 do
562 for j : 0 thru ord-1 do
567 extractCol(m,j,size) :=
568 block([res:make_array('any,size),k],
570 for k : 0 thru size-1 do
576 extractRow(m,i,size) :=
577 block([res:make_array('any,size),k],
579 for k : 0 thru size-1 do
586 /* Linear algebra support routines */
587 solveSys(mat,vec,solver) :=
588 block([sol,unk,i,j,sys,nRows,nCols,newEq],
591 nCols : length(mat[1]),
593 for i : 1 thru nRows do
595 newEq : sum(mat[i][j]*unk[j],j,1,nCols)-vec[i]=0,
596 sys : endcons(newEq,sys)
598 sol : solver(sys,makelist(unk[i],i,1,nCols)),
603 return(map(second,sol))
608 newtonFromPoly(pol,var,len) :=
609 array2singleList(newtonArrFromPoly(pol,var,len));
611 newtonArrFromPoly(pol,var,len) :=
612 block([newtonRes,degPol,i,j],
613 degPol : degree(pol,var),
614 newtonRes : make_array('any,len+1),
616 newtonRes[0] : degPol,
618 for i : 1 thru len do
621 newtonRes[i] : (degPol-i)*ratcoeff(pol,var,degPol-i)-
622 sum(ratcoeff(pol,var,degPol-j)*
630 polyFromNewton(ns,var) :=
631 list2poly(getCoeffFromNewton(ns),var);
633 getCoeffFromNewton(ns) :=
634 array2singleList(getCoeffFromNewtonArray(singleList2array(ns)));
636 getCoeffFromNewtonArray(ns) :=
637 block([i,j,degRes : arrayLength(ns)-1,resCoeff:make_array('any)],
639 resCoeff : make_array('any,degRes+1),
643 for i : 1 thru degRes do
644 resCoeff[degRes-i] : -1/i*sum(ns[j+1-1]*resCoeff[degRes+j-i],j,1,i),
651 getCoeffFromNewtonList(ns) :=
652 array2singleList(getCoeffFromNewton(ns));
655 array2list(matrixProdArray(list2array(a),list2array(b)));
657 matrixProdArray(a,b) :=
658 block([i,j,k,n,m,l,res:mame_array('any)],
660 n : first(third(arrayinfo(a)))+1,
662 m : second(third(arrayinfo(a)))+1,
664 if not(first(third(arrayinfo(b)))+1=m) then
666 print("matrixProd) incompatible matrices"),
667 print("matrixProd) a : ", a),
668 print("matrixProd) b : ", b),
673 l : second(third(arrayinfo(b)))+1,
675 res : make_array('any,n,l),
680 res[i-1,k-1] : sum(a[i-1,j-1]*b[j-1,k-1],j,1,m),
692 for i : 1 thru ALen do
693 res : res + A[i-1,i-1],
697 discreteSquareRoot(n) :=
702 for i : 1 thru ceiling(bfloat(n/2)) do
706 /* before 5.9.2 but also forwards-compatible*/
707 for i : 1 thru comp_ceiling(bfloat(n/2)) do
713 babyGiantCharPol(A,var) :=
714 babyGiantCharPolAux(list2array(A),var);
716 babyGiantCharPolAux(A,var) :=
717 list2poly(array2singleList(getCoeffFromNewtonArray(
718 getNewtonFromMatrix(A))),
724 makelist(A[i][j]-B[i][j],j,1,length(A[1])),
727 diagonal(elem,len) :=
729 makelist(if(i=j) then elem else 0,j,1,len),
732 gaussCharPol(A,var) :=
733 expandIf(gaussDet(matrixMinus(A,diagonal(var,length(A)))));
735 bareissCharPol(A,var) :=
736 expandIf(bareissDet(matrixMinus(A,diagonal(var,length(A)))));
738 /* Input : a bidimensional array */
739 /* Output : the Newton sums of the corresponding characteristic polynomial */
740 getNewtonFromMatrix(A) :=
741 block([i,j,k,r,n,dsr,
742 B:make_array('any),G:make_array('any),ss:make_array('any)],
745 ss : make_array('any,n +1 /* +1 */),
747 dsr : discreteSquareRoot(n),
752 B : make_array('any,r-1),
753 for i : 1 thru r-1 do
754 B[i-1] : make_array('any,n,r),
758 ss[1] : matrixTrace(A),
760 for i : 1 thru r-2 do
762 B[i+1 -1] : matrixProdArray(A,B[i -1]),
763 ss[i+1] : matrixTrace(B[i+1 -1])
766 G : make_array('any,r-1),
767 for j : 1 thru r-1 do
768 G[j-1] : make_array('any,n,r),
770 G[1 -1] : matrixProdArray(A,B[r-1 -1]),
771 ss[r] : matrixTrace(G[1 -1]),
773 for j : 1 thru r-2 do
777 G[j+1 -1] : matrixProdArray(G[1-1],G[j -1]),
778 ss[(j+1)*r] : matrixTrace(G[j+1 -1])
782 for i : 1 thru r-1 do
783 for j : 1 thru r-1 do
786 ss[j*r+i] : matrixTrace(matrixProdArray(B[i -1],G[j -1]))
792 companion(pol,var) :=
793 array2list(companion(pol,var));
795 companionArray(pol,var) :=
797 [m : make_array('any),n, i,j],
800 m: make_array('any,n,n),
802 for j : 0 thru n - 2 do
804 m[0,n-1] : -coeff(pol,var,0),
807 for i : 1 thru n-1 do
809 for j : 0 thru i-2 do
812 for j : i thru n-2 do
814 m[i,n-1] : -coeff(pol,var,i)
820 /* This should be changed with the algorithm shown in Proposition 4.7 */
821 companionPoly2Newton(pol,var) :=
822 array2singleList(getNewtonFromMatrix(companionArray(pol,var)));
824 newton2Poly(newtonLst) :=
825 array2singleList(newtonArr2Poly(singleList2array(newtonLst)));
827 newtonArr2Poly(newtonArr) :=
828 block([res,i,j,degP],
829 degP : arrayLength(newtonArr)-1,
831 res : make_array('any,degP+1),
833 for i : 1 thru degP do
837 res[degP-i] : sum(res[degP-i+j]*newtonArr[j],j,1,i)*(-1/i)
843 /* Descartes Signature */
844 descartesSignature(mtx) :=
845 block([charP,x,revCoeffList,charPDeg,i],
846 charP : babyGiantCharPol(mtx,x), /* DEBUGGING */
847 charPDeg : length(mtx),
848 revCoeffList : reverse(poly2list(charP,x)),
850 return(signChanges(revCoeffList)-
852 makelist((-1)^(charPDeg-i)*revCoeffList[i+1],i,0,