www.pudn.com > calc.rar > i9.c


/* i9.c */ 
#include  
#include  
#include "integer.h" 
#include "fun.h" 
 
extern long int nettbytes; 
/* 
MPI *MAXI, *PMAXI, *QMAXI; 
*/ 
extern int answer; 
 
MPI **SMITHI(MPMATI *Mptr, MPMATI **Pptr, MPMATI **Qptr, USI *ptr, MPI *Eptr, USI m1, USI n1) 
/* 
 * returns the invariant factors of *Mptr. 
 * **Pptr and **Qptr are invertible matrices such that 
 * **Pptr x *Mptr x **Qptr is the Smith canonical form *Nptr below. 
 * *ptr is the number of invariant factors. 
 * See Rings, Modules and Linear Algebra by B. Hartley and T. O. Hawkes, 
 * Chapman and Hall, 1970. 
 * *Eptr is the cutoff above which we bring in MLLL. In any case MLLL is 
 * done before each block is processed, as a chance of getting small entries. 
 * This modification of the LLL algorithm was outlined by M. Pohst in J.  
 * Symbolic Computation (1987) 4, 123-127. m1/n1 is the LLL parameter alpha,  
 * 1/4 < alpha |= 1. 
 * I initially coded this I think in 1992, along the lines of suggestions by 
 * George Havas. 
 */ 
{ 
	unsigned int i, k, l, m, n, p, q, j, t, z, size, r, s; 
	unsigned int flag = 1, FLAG = 1; 
	MPI *Q, **N, *Tmp; 
	MPMATI *Nptr, *Temp; 
	int isok; 
	 
	m = Mptr->R; 
	n = Mptr->C; 
	Nptr = COPYMATI(Mptr); 
	*Pptr = IDENTITYI(m); 
	*Qptr = IDENTITYI(n); 
/* 
	MAXI = MAXELTI(Mptr); 
	PMAXI = MAXELTI(*Pptr); 
	QMAXI = MAXELTI(*Qptr); 
*/ 
	z = MIN((int) m - 1, (int) n - 1); 
	N = (MPI **)mmalloc((z + 1) * sizeof(MPI *)); 
	for (i = 0; i <= z; i++) 
	{ 
		ZEROTESTI(0, Nptr, &r, &s); 
		if (r == Nptr->R && s == Nptr->C) 
			break; 
		flag = HAVAS_PIVOTI(Nptr, &p, &q, r, s); 
		if (p > 0)/* must have a non-zero row 1 for MLLL */ 
		{ 
			Nptr = SWAP_ROWSI1(0, p, Nptr); 
			*Pptr = SWAP_ROWSI1(i, p + i, *Pptr); 
		} 
		if (q > 0) 
		{ 
			Nptr = SWAP_COLSI1(0, q, Nptr); 
			*Qptr = SWAP_COLSI1(i, q + i, *Qptr); 
		} 
		if (flag) 
			FLAG = 1; 
		if (!flag && FLAG) 
		{ 
			size = Nptr->R; 
			Temp = Nptr; 
			Nptr = BASIS_REDUCTION(Nptr, Pptr, i, m1, n1); 
			/*Nptr = BASIS_REDUCTION0(Nptr, 3, 4);*/ 
			FREEMATI(Temp); 
			ZEROTESTI(0, Nptr, &r, &s); 
			if (r == Nptr->R && s == Nptr->C) 
				break; 
			flag = HAVAS_PIVOTI(Nptr, &p, &q, r, s); 
			if (p > 0) 
			{ 
				Nptr = SWAP_ROWSI1(0, p, Nptr); 
				*Pptr = SWAP_ROWSI1(i, p + i, *Pptr); 
			} 
			if (q > 0) 
			{ 
				Nptr = SWAP_COLSI1(0, q, Nptr); 
				*Qptr = SWAP_COLSI1(i, q + i, *Qptr); 
			} 
			FLAG = 0; 
			size = size - Nptr->R; 
			m = m - size; 
			z = MIN((int) m - 1, (int) n - 1); 
		} 
		/* Now elt(Nptr, 0, 0) != 0. */ 
		while (1) 
		{ 
 		    while(1) 
		    { /* PA bit */ 
			isok = 1; 
			for(j = 0; j < Nptr->C; j++) 
			{ 
				if ((Nptr->V[0][j])->S == -1) 
				{ 
					for(t = 0; t < Nptr->R; t++) 
						(Nptr->V[t][j])->S = - (Nptr->V[t][j])->S; 
					for(t = 0; t < n; t++) 
						((*Qptr)->V[t][j + i])->S = - ((*Qptr)->V[t][j + i])->S; 
				} 
			} 
			/* Now all non-zero elements in row 0 are positive. */ 
			while (1) 
			{ 
				l = ROWSEEKI(0, Nptr); 
				if (l == Nptr->C) 
					 break; 
				else 
				{ 
					/* Case 1, p. 112. */ 
					Q = INT(Nptr->V[0][l], Nptr->V[0][0]); 
					Nptr = COLSUBI(0, l, Q, Nptr);  
/* 
					MAXI = UPDATEMAXI(MAXI, Nptr); 
*/ 
					*Qptr = COLSUBI(i, l + i, Q, *Qptr);  
/* 
					QMAXI = UPDATEMAXI(QMAXI, *Qptr); 
*/ 
					FREEMPI(Q); 
					Nptr = SWAP_COLSI1(0, l, Nptr);  
					*Qptr = SWAP_COLSI1(i, l + i, *Qptr);  
					/* This reduces the size of elt(Nptr, 0, 0). */ 
				} 
			} 
			for(j = 1; j < Nptr->R; j++) 
			{ 
				if ((Nptr->V[j][0])->S == -1) 
				{ 
					for(t = 0; t < Nptr->C; t++) 
						(Nptr->V[j][t])->S = - (Nptr->V[j][t])->S; 
					for(t = 0; t < (*Pptr)->R; t++) 
						((*Pptr)->V[j + i][t])->S = - ((*Pptr)->V[j + i][t])->S; 
				} 
			} 
/* 
Now all non-zero elements in column 0 are positive. 
*/ 
			while (1) 
			{ 
				k = COLSEEKI(0, Nptr); 
				if (k == Nptr->R) 
					break; 
				else 
				{ 
					isok = 0; 
					/* Case 2, p. 112. */ 
					Q = INT0(Nptr->V[k][0], Nptr->V[0][0]); 
					Nptr = ROWSUBI(0, k, Q, Nptr);  
/* 
					MAXI = UPDATEMAXI(MAXI, Nptr); 
*/ 
					*Pptr = ROWSUBI(i, k + i, Q, *Pptr); 
/* 
					PMAXI = UPDATEMAXI(PMAXI, *Pptr); 
*/ 
					FREEMPI(Q); 
					Nptr = SWAP_ROWSI1(0, k, Nptr);  
					*Pptr = SWAP_ROWSI1(i, k + i, *Pptr); 
					/* This reduces the size of elt(Nptr, 0, 0). */ 
				} 
			} 
			/* now l = Nptr->C and k = Nptr->R */ 
			if (isok) 
				break; 
		   } /*PA bit*/ 
/* 
Now (Case 3, p.112) elt(Nptr, 0, 0) divides each element to its right as well as below it. 
*/ 
		for (l = 1; l < Nptr->C; l++) 
		{ 
			if ((Nptr->V[0][l])->S != 0) 
			{ 
	/* NOTE: Swapping above may have made elt(Nptr, 0, l) <0 */ 
				Q = INT(Nptr->V[0][l], Nptr->V[0][0]); 
				Nptr = COLSUBI(0, l, Q, Nptr);  
/* 
				MAXI = UPDATEMAXI(MAXI, Nptr); 
*/ 
				*Qptr = COLSUBI(i, l + i, Q, *Qptr);  
/* 
				QMAXI = UPDATEMAXI(QMAXI, *Qptr); 
*/ 
				FREEMPI(Q); 
			} 
		} 
		for (k = 1; k < Nptr->R; k++) 
		{ 
			if ((Nptr->V[k][0])->S != 0) 
			{ 
				Q = INT0(Nptr->V[k][0], Nptr->V[0][0]); 
				FREEMPI(Nptr->V[k][0]); 
				Nptr->V[k][0] = ZEROI(); 
				*Pptr = ROWSUBI(i, k + i, Q, *Pptr); 
/* 
				PMAXI = UPDATEMAXI(PMAXI, *Pptr); 
*/ 
				FREEMPI(Q); 
			} 
		} 
/* 
Now each element to the right of and below elt(Nptr, 0, 0) is zero. 
*/ 
		k = MATSEEKI(0, Nptr); 
		if (k != Nptr->R) 
		{ 
			for (t = 0; t < Nptr->C; t++) 
			{ 
				if ((Nptr->V[k][t])->S != 0) 
				{ 
					Tmp = Nptr->V[0][t]; 
					Nptr->V[0][t] = ADDI(Nptr->V[0][t], Nptr->V[k][t]); 
/* 
					MAXI = UPDATEMAXI(MAXI, Nptr); 
*/ 
					FREEMPI(Tmp); 
				} 
			} 
			for (t = 0; t < Mptr->R; t++) 
			{ 
				if (((*Pptr)->V[k + i][t])->S != 0) 
				{ 
					Tmp = (*Pptr)->V[i][t]; 
					(*Pptr)->V[i][t] = ADDI((*Pptr)->V[i][t], (*Pptr)->V[k + i][t]); 
/* 
					PMAXI = UPDATEMAXI(PMAXI, *Pptr); 
*/ 
					FREEMPI(Tmp); 
				} 
			} 
		} 
		else 
			break; 
	} 
/* 
Now elt(Nptr, 0, 0) divides all elements elt(Nptr, k, l), k,l > 0. 
*/ 
		N[i] = COPYI(Nptr->V[0][0]); 
 
		if (i < z) 
		{ 
			Temp = Nptr; 
			Nptr = DELETE_ROW1I(Nptr);	 
			FREEMATI(Temp); 
			Temp = Nptr; 
			Nptr = DELETE_COL1I(Nptr);	 
			FREEMATI(Temp); 
		} 
		size = Nptr->R; 
		Tmp = MAXELTI(Nptr); 
		printf("found invariant factor d[%u] = ", i + 1); PRINTI(N[i]); printf("\n"); 
/* 
		printf("MAXI = "); PRINTI(MAXI); printf("\n"); 
		printf("PMAXI = "); PRINTI(PMAXI); printf("\n"); 
		printf("QMAXI = "); PRINTI(QMAXI); printf("\n"); 
*/ 
		printf("MAX_ENTRY(Nptr) = "); PRINTI(Tmp); printf("\n"); 
		l = RSV(Tmp, Eptr); 
		FREEMPI(Tmp); 
		if (l == 1 && !flag)/* we don't want to use MLLL if there are 
1's or -1's still present */ 
		{ 
			ZEROTESTI(0, Nptr, &r, &s); 
			if (r > 0)/* must have a non-zero row 1 for MLLL */ 
			{ 
				printf("r = %u > 0\n", r); 
				Nptr = SWAP_ROWSI1(0, r, Nptr); 
				*Pptr = SWAP_ROWSI1(i + 1, r + i + 1, *Pptr); 
			} 
			Temp = Nptr; 
			Nptr = BASIS_REDUCTION(Nptr, Pptr, i+1, m1, n1); 
			/*Nptr = BASIS_REDUCTION0(Nptr, 3, 4);*/ 
			FREEMATI(Temp); 
		} 
		size = size - Nptr->R; 
		m = m - size; 
		z = MIN((int) m - 1, (int) n - 1); 
	} 
	FREEMATI(Nptr); 
	*ptr = i++; 
/* 
	printf("MAXI = "); PRINTI(MAXI); printf("\n"); 
	printf("PMAXI = "); PRINTI(PMAXI); printf("\n"); 
	printf("QMAXI = "); PRINTI(QMAXI); printf("\n"); 
	FREEMPI(MAXI); 
	FREEMPI(PMAXI); 
	FREEMPI(QMAXI); 
*/ 
	return (N); 
} 
 
MPI *ROWSUMI(MPMATI *Mptr, USI i) 
{ 
	unsigned int j; 
	MPI *S, *Temp1I, *Temp2I; 
 
	S = ZEROI(); 
	for (j = 0; j < Mptr->C; j++) 
	{ 
		Temp1I = ABSI(Mptr->V[i][j]); 
		Temp2I = S; 
		S = ADD0I(Temp1I, S); 
		FREEMPI(Temp1I); 
		FREEMPI(Temp2I); 
	} 
	return (S); 
} 
 
MPI *COLSUMI(MPMATI *Mptr, USI j) 
{ 
	unsigned int i; 
	MPI *S, *Temp1I, *Temp2I; 
 
	S = ZEROI(); 
	for (i = 0; i < Mptr->R; i++) 
	{ 
		Temp1I = ABSI(Mptr->V[i][j]); 
		Temp2I = S; 
		S = ADD0I(Temp1I, S); 
		FREEMPI(Temp1I); 
		FREEMPI(Temp2I); 
	} 
	return (S); 
} 
 
MPI *MINELTI(MPMATI *Mptr) 
/* returns the minimum element of *Mptr */ 
{ 
	unsigned int i, j, I, J, flag = 0; 
 
	I = J = 0; 
	for (i = 0; i < Mptr->R; i++) 
	{ 
		for (j = 0; j < Mptr->C; j++) 
		{ 
			if ((Mptr->V[i][j])->S) 
			{ 
				I = i; 
				J = j; 
				flag = 1; 
				break; 
			} 
		} 
		if (flag) 
			break; 
	} 
	for (i = I; i < Mptr->R; i++) 
	{ 
		for (j = 0; j < Mptr->C; j++) 
		{ 
			if (RSV(Mptr->V[I][J], Mptr->V[i][j]) == 1 && (Mptr->V[i][j])->S) 
			{ 
				I = i; 
				J = j; 
			} 
		} 
	} 
	return (ABSI(Mptr->V[I][J])); 
} 
 
void MINELTI1(MPMATI *Mptr, USI *iptr, USI *jptr) 
/* returns the position of the minimum element of *Mptr */ 
{ 
	unsigned int i, j, I, J, flag = 0; 
 
	I = J = 0; 
	for (i = 0; i < Mptr->R; i++) 
	{ 
		for (j = 0; j < Mptr->C; j++) 
		{ 
			if ((Mptr->V[i][j])->S) 
			{ 
				I = i; 
				J = j; 
				flag = 1; 
				break; 
			} 
		} 
		if (flag) 
			break; 
	} 
	for (i = 0; i < Mptr->R; i++) 
	{ 
		for (j = 0; j < Mptr->C; j++) 
		{ 
			if (RSV(Mptr->V[I][J], Mptr->V[i][j]) == 1 && (Mptr->V[i][j])->S) 
			{ 
				I = i; 
				J = j; 
			} 
		} 
	} 
	*iptr = I; 
	*jptr = J; 
	return; 
} 
 
MPI *MAXELTI(MPMATI *Mptr) 
/* returns the maximum element of *Mptr */ 
{ 
	unsigned int i, j, I = 0, J = 0; 
 
	for (i = 0; i < Mptr->R; i++) 
	{ 
		for (j = 0; j < Mptr->C; j++) 
		{ 
			if (RSV(Mptr->V[i][j], Mptr->V[I][J]) == 1) 
			{ 
				I = i; 
				J = j; 
			} 
		} 
	} 
	return (ABSI(Mptr->V[I][J])); 
} 
 
void MAXELTI1(MPMATI *Mptr, USI *iptr, USI *jptr) 
/* returns the position of the maximum element of *Mptr */ 
{ 
	unsigned int i, j, I = 0, J = 0; 
 
	for (i = 0; i < Mptr->R; i++) 
	{ 
		for (j = 0; j < Mptr->C; j++) 
		{ 
			if (RSV(Mptr->V[i][j], Mptr->V[I][J]) == 1) 
			{ 
				I = i; 
				J = j; 
			} 
		} 
	} 
	*iptr = I; 
	*jptr = J; 
	return; 
} 
 
MPI *UPDATEMAXI(MPI *S, MPMATI *Mptr) 
{ 
	MPI *TempI; 
 
	TempI = MAXELTI(Mptr); 
	if (RSV(TempI, S) == 1) 
	{ 
		FREEMPI(S); 
		return(TempI); 
	}	 
	else 
	{ 
		FREEMPI(TempI); 
		return (S); 
	} 
} 
 
unsigned int HAVAS_PIVOTI(MPMATI *Mptr, USI *rptr, USI *cptr, USI r, USI s) 
{ 
	MPI **RS, **CS, *S, *Temp1I, *Temp2I, *TempI; 
	unsigned int i, j, I, J, m, n, flag; 
 
	m = Mptr->R; 
	n = Mptr->C; 
	RS = (MPI **)mmalloc(m * sizeof(MPI *)); 
	CS = (MPI **)mmalloc(n * sizeof(MPI *)); 
	for (i = 0; i < m; i++) 
	{ 
		TempI = ROWSUMI(Mptr, i); 
		if (TempI->S == 0) 
		{ 
			FREEMPI(TempI); 
			RS[i] = MINUS_ONEI(); 
		} 
		else 
		{ 
			Temp1I = ONEI(); 
			RS[i] = SUB0I(TempI, Temp1I); 
			FREEMPI(TempI); 
			FREEMPI(Temp1I); 
		} 
	} 
	for (j = 0; j < Mptr->C; j++) 
	{ 
		TempI = COLSUMI(Mptr, j); 
		if (TempI->S == 0) 
		{ 
			FREEMPI(TempI); 
			CS[j] = MINUS_ONEI(); 
		} 
		else 
		{ 
			Temp1I = ONEI(); 
			CS[j] = SUB0I(TempI, Temp1I); 
			FREEMPI(TempI); 
			FREEMPI(Temp1I); 
		} 
	} 
	S = MULTI(RS[r], CS[s]); /* elt(r,s) is the 1st non-zero elt of Nptr */ 
	I = r; J = s; 
	flag = 0; 
	/* first minimize RS[i]*CS[j] over ones or minus-ones */ 
	for (i = r; i < m; i++) 
	{ 
		for (j = 0; j < n; j++) 
		{ 
			if ((Mptr->V[i][j])->D == 0 && (Mptr->V[i][j])->V[0] == 1) 
			{ 
				flag = 1; 
				Temp1I = S; 
				Temp2I = MULTI(RS[i], CS[j]); 
				if(RSV(Temp1I, Temp2I) == 1) 
				{ 
					S = Temp2I; 
					FREEMPI(Temp1I); 
					I = i; J = j; 
				} 
				else 
					FREEMPI(Temp2I);	 
			} 
		} 
	} 
	if (!flag) /* minimize RS[i]*CS[j] over a matrix with no ones or minus-ones */ 
	{ 
		for (i = r; i < m; i++) 
		{ 
			for (j = 0; j < n; j++) 
			{ 
				if ((Mptr->V[i][j])->S) 
				{ 
					Temp1I = S; 
					Temp2I = MULTI(RS[i], CS[j]); 
					if(RSV(Temp1I, Temp2I) == 1) 
					{ 
						S = Temp2I; 
						FREEMPI(Temp1I); 
						I = i; J = j; 
					} 
					else 
						FREEMPI(Temp2I);	 
					 
				} 
			} 
		} 
	} 
	*rptr = I; 
	*cptr = J; 
	for (i = 0; i < m; i++) 
		FREEMPI(RS[i]); 
	for (j = 0; j < n; j++) 
		FREEMPI(CS[j]); 
	ffree((char *)RS, m * sizeof(MPI *)); 
	ffree((char *)CS, n * sizeof(MPI *)); 
	FREEMPI(S); 
	return (flag); 
} 
 
void ZEROTESTI(USI i, MPMATI *Mptr, USI *p, USI *q) 
/* 
 * returns the least indices *p >= i, *q >= i such that elt(Mptr, *p, *q) != 0. 
 * otherwise *p = Mptr->R and *q = Mptr->C. 
 */ 
{ 
	unsigned int k, l; 
	 
	for (k = i; k <= Mptr->R - 1; k++) 
	{ 
		for (l = i; l <= Mptr->C - 1; l++) 
		{ 
			if ((Mptr->V[k][l])->S != 0) 
			{ 
				*p = k; 
				*q = l; 
				return; 
			} 
		} 
	} 
	*p = Mptr->R; 
	*q = Mptr->C; 
	return; 
} 
 
unsigned int MATSEEKI(USI i, MPMATI *Mptr) 
/* 
 * returns the least row index k, i < k <= Mptr->R - 1, such that  
 * elt(Mptr, k, l) is not divisible by elt(Mptr, i, i), for some l, 
 * i < l <= Mptr->C - 1; otherwise returns Mptr->R. 
 */ 
{ 
	int s; 
	unsigned int k, l; 
	MPI *P, *Q; 
	 
	Q = ABSI(Mptr->V[i][i]); 
	for (k = i + 1; k <= Mptr->R - 1; k++) 
	{ 
		for (l = i + 1; l <= Mptr->C - 1; l++) 
		{ 
			P = MOD(Mptr->V[k][l], Q); 
			s = P->S; 
			FREEMPI(P); 
			if (s != 0) 
			{ 
				FREEMPI(Q); 
				return (k); 
			} 
		} 
	} 
	FREEMPI(Q); 
	return (Mptr->R); 
} 
 
unsigned int ROWSEEKI(USI i, MPMATI *Mptr) 
/* 
 * returns the least integer l > i such that elt(Mptr, i, l) is not divisible 
 * by elt(Mptr, i, i), otherwise returns Mptr->C. 
 */ 
{ 
	int s; 
	unsigned int l; 
	MPI *P; 
 
	for (l = i + 1; l <= Mptr->C - 1; l++) 
	{ 
		if ((Mptr->V[i][l])->S != 0) 
		{ 
			P = MOD0(Mptr->V[i][l], Mptr->V[i][i]); 
			s = P->S; 
			FREEMPI(P); 
			if (s != 0) 
				return (l); 
		} 
	} 
	return (Mptr->C); 
} 
 
unsigned int COLSEEKI(USI i, MPMATI *Mptr) 
/* 
 * returns the least integer k > i such that Mptr->V[k][i] is not divisible 
 * by Mptr->V[i][i], otherwise returns Mptr->R. 
 */ 
{ 
	int s; 
	unsigned int k; 
	MPI *P; 
 
	for (k = i + 1; k <= Mptr->R - 1; k++) 
	{ 
		if ((Mptr->V[k][i])->S != 0) 
		{ 
			P = MOD0(Mptr->V[k][i], Mptr->V[i][i]); 
			s = P->S; 
			FREEMPI(P); 
			if (s != 0) 
				return (k); 
		} 
	} 
	return (Mptr->R); 
} 
 
MPMATI *ROWSUBI0(USI p, USI q, MPI *Aptr, MPMATI *Mptr) 
/* 
 * subtracts *Aptr times the p-th row of *Mptr from the q-th. 
 * 0 <= p, q <= Mprt->R - 1, where elt(Mptr, i, j) = 0 if j < p. 
 */ 
{ 
	MPI *Y, *Temp; 
	unsigned int l; 
	if (Aptr->S != 0) 
	{ 
		for (l = p; l <= Mptr->C - 1; l++)  
		{ 
			if ((Mptr->V[p][l])->S != 0) 
			{ 
				Y = MULTI(Aptr, Mptr->V[p][l]); 
				Temp = Mptr->V[q][l]; 
				Mptr->V[q][l] = SUBI(Mptr->V[q][l], Y); 
				FREEMPI(Y); 
				FREEMPI(Temp); 
			} 
		} 
	} 
	return (Mptr); 
} 
 
MPMATI *COLSUBI0(USI p, USI q, MPI *Aptr, MPMATI *Mptr) 
/* 
 * subtracts *Aptr times the p-th column of *Mptr from the q-th. 
 * 0 <= p, q <= Mprt->C - 1, where elt(Mptr, i, j) = 0 if i < p. 
 */ 
{ 
	MPI *Y, *Temp; 
	unsigned int k; 
 
	if (Aptr->S != 0) 
	{ 
		for (k = p; k <= Mptr->R - 1; k++)  
		{ 
			if ((Mptr->V[k][p])->S != 0) 
			{ 
				Y = MULTI(Aptr, Mptr->V[k][p]); 
				Temp = Mptr->V[k][q]; 
				Mptr->V[k][q] = SUBI(Mptr->V[k][q], Y); 
				FREEMPI(Y); 
				FREEMPI(Temp); 
			} 
		} 
	} 
	return (Mptr); 
} 
 
MPI **SMITHI1(MPMATI *Mptr, USI *ptr, MPI *Eptr, USI m1, USI n1) 
/* 
 * returns the invariant factors of *Mptr. 
 * *ptr is the number of invariant factors. 
 * See Rings, Modules and Linear Algebra by B. Hartley and T. O. Hawkes, 
 * Chapman and Hall, 1970. 
 * *Eptr is the cutoff above which we bring in MLLL. 
 */ 
{ 
	unsigned int i, k, l, m, n, p, q, j, t, z, size, r, s; 
	unsigned int flag = 1; 
	MPI *Q, **N, *Tmp; 
	MPMATI *Nptr, *Temp; 
	int isok; 
	 
	m = Mptr->R; 
	n = Mptr->C; 
	Nptr = COPYMATI(Mptr); 
/* 
	MAXI = MAXELTI(Mptr); 
*/ 
	z = MIN((int) m - 1, (int) n - 1); 
	N = (MPI **)mmalloc((z + 1) * sizeof(MPI *)); 
	for (i = 0; i <= z; i++) 
	{ 
		ZEROTESTI(0, Nptr, &r, &s); 
		if (r == Nptr->R && s == Nptr->C) 
			break; 
		flag = HAVAS_PIVOTI(Nptr, &p, &q, r, s); 
		if (p > 0)/* must have a non-zero row 1 for MLLL */ 
			Nptr = SWAP_ROWSI1(0, p, Nptr); 
		if (q > 0) 
			Nptr = SWAP_COLSI1(0, q, Nptr); 
/* 
		if (flag) 
			FLAG = 1; 
		if (!flag && FLAG) 
		{ 
			size = Nptr->R; 
			Temp = Nptr; 
			printf("FLAG = 1 and flag = 0: doing MLLL:\n"); 
			Nptr = BASIS_REDUCTION0(Nptr, m1, n1); 
			FREEMATI(Temp); 
			ZEROTESTI(0, Nptr, &r, &s); 
			if (r == Nptr->R && s == Nptr->C) 
				break; 
			flag = HAVAS_PIVOTI(Nptr, &p, &q, r, s); 
			if (p > 0) 
				Nptr = SWAP_ROWSI1(0, p, Nptr); 
			if (q > 0) 
				Nptr = SWAP_COLSI1(0, q, Nptr); 
			FLAG = 0; 
			size = size - Nptr->R; 
			m = m - size; 
			z = MIN((int) m - 1, (int) n - 1); 
		} 
*/ 
		/* Now elt(Nptr, 0, 0) != 0. */ 
		while (1) 
		{ 
 		    while(1) 
		    { /* PA bit */ 
			isok = 1; 
			for(j = 0; j < Nptr->C; j++) 
			{ 
				if ((Nptr->V[0][j])->S == -1) 
				{ 
					for(t = 0; t < Nptr->R; t++) 
						(Nptr->V[t][j])->S = - (Nptr->V[t][j])->S; 
				} 
			} 
			/* Now all non-zero elements in row 0 are positive. */ 
			while (1) 
			{ 
				l = ROWSEEKI(0, Nptr); 
				if (l == Nptr->C) 
					 break; 
				else 
				{ 
					/* Case 1, p. 112. */ 
					Q = INT(Nptr->V[0][l], Nptr->V[0][0]); 
					Nptr = COLSUBI(0, l, Q, Nptr);  
/* 
					MAXI = UPDATEMAXI(MAXI, Nptr); 
*/ 
					FREEMPI(Q); 
					Nptr = SWAP_COLSI1(0, l, Nptr);  
					/* This reduces the size of elt(Nptr, 0, 0). */ 
				} 
			} 
			for(j = 1; j < Nptr->R; j++) 
			{ 
				if ((Nptr->V[j][0])->S == -1) 
				{ 
					for(t = 0; t < Nptr->C; t++) 
						(Nptr->V[j][t])->S = - (Nptr->V[j][t])->S; 
				} 
			} 
/* 
Now all non-zero elements in column 0 are positive. 
*/ 
			while (1) 
			{ 
				k = COLSEEKI(0, Nptr); 
				if (k == Nptr->R) 
					break; 
				else 
				{ 
					isok = 0; 
					/* Case 2, p. 112. */ 
					Q = INT0(Nptr->V[k][0], Nptr->V[0][0]); 
					Nptr = ROWSUBI(0, k, Q, Nptr);  
/* 
					MAXI = UPDATEMAXI(MAXI, Nptr); 
*/ 
					FREEMPI(Q); 
					Nptr = SWAP_ROWSI1(0, k, Nptr);  
					/* This reduces the size of elt(Nptr, 0, 0). */ 
				} 
			} 
			/* now l = Nptr->C and k = Nptr->R */ 
			if (isok) 
				break; 
		   } /*PA bit*/ 
/* 
Now (Case 3, p.112) elt(Nptr, 0, 0) divides each element to its right as well as below it. 
*/ 
		for (l = 1; l < Nptr->C; l++) 
		{ 
			if ((Nptr->V[0][l])->S != 0) 
			{ 
	/* NOTE: Swapping above may have made elt(Nptr, 0, l) <0 */ 
				Q = INT(Nptr->V[0][l], Nptr->V[0][0]); 
				Nptr = COLSUBI(0, l, Q, Nptr);  
/* 
				MAXI = UPDATEMAXI(MAXI, Nptr); 
*/ 
				FREEMPI(Q); 
			} 
		} 
		for (k = 1; k < Nptr->R; k++) 
		{ 
			if ((Nptr->V[k][0])->S != 0) 
			{ 
				Q = INT0(Nptr->V[k][0], Nptr->V[0][0]); 
				FREEMPI(Nptr->V[k][0]); 
				Nptr->V[k][0] = ZEROI(); 
				FREEMPI(Q); 
			} 
		} 
/* 
Now each element to the right of and below elt(Nptr, 0, 0) is zero. 
*/ 
		k = MATSEEKI(0, Nptr); 
		if (k != Nptr->R) 
		{ 
			for (t = 0; t < Nptr->C; t++) 
			{ 
				if ((Nptr->V[k][t])->S != 0) 
				{ 
					Tmp = Nptr->V[0][t]; 
					Nptr->V[0][t] = ADDI(Nptr->V[0][t], Nptr->V[k][t]); 
/* 
					MAXI = UPDATEMAXI(MAXI, Nptr); 
*/ 
					FREEMPI(Tmp); 
				} 
			} 
		} 
		else 
			break; 
	} 
/* 
Now elt(Nptr, 0, 0) divides all elements elt(Nptr, k, l), k,l > 0. 
*/ 
		N[i] = COPYI(Nptr->V[0][0]); 
 
		if (i < z) 
		{ 
			Temp = Nptr; 
			Nptr = DELETE_ROW1I(Nptr);	 
			FREEMATI(Temp); 
			Temp = Nptr; 
			Nptr = DELETE_COL1I(Nptr);	 
			FREEMATI(Temp); 
		} 
		size = Nptr->R; 
		Tmp = MAXELTI(Nptr); 
		printf("found invariant factor d[%u] = ", i + 1); PRINTI(N[i]); printf("\n"); 
/* 
		printf("MAXI = "); PRINTI(MAXI); printf("\n"); 
		printf("MAX_ENTRY(Nptr) = "); PRINTI(Tmp); printf("\n"); 
		printf("MAXI has %u digits\n", LENGTHI(MAXI)); 
*/ 
		l = RSV(Tmp, Eptr); 
		FREEMPI(Tmp); 
		if (l == 1 && !flag)/* we don't want to use MLLL if there are 
1's or -1's still present */ 
		{ 
			ZEROTESTI(0, Nptr, &r, &s); 
			if (r > 0)/* must have a non-zero row 1 for MLLL */ 
			{ 
				printf("r = %u > 0\n", r); 
				Nptr = SWAP_ROWSI1(0, r, Nptr); 
			} 
			Temp = Nptr; 
			Nptr = BASIS_REDUCTION0(Nptr, m1, n1); 
			FREEMATI(Temp); 
		} 
		size = size - Nptr->R; 
		m = m - size; 
		z = MIN((int) m - 1, (int) n - 1); 
	} 
	FREEMATI(Nptr); 
	*ptr = i++; 
/* 
	printf("MAXI = "); PRINTI(MAXI); printf("\n"); 
	FREEMPI(MAXI); 
*/ 
	return (N); 
} 
 
MPMATI *DELETE_ROW1I(MPMATI *Mptr) 
/* 
 * deletes the first row of *Mptr. 
 */ 
{ 
	unsigned int i, j, m, n; 
	MPMATI *Nptr; 
 
	m = Mptr->R; 
	n = Mptr->C; 
	Nptr = BUILDMATI(m - 1, n); 
	for (i = 0; i <= Nptr->R - 1; i++) 
	{ 
		for (j = 0; j <= n - 1; j++) 
			Nptr->V[i][j] = COPYI(Mptr->V[i + 1][j]); 
	} 
	return (Nptr); 
} 
 
MPMATI *DELETE_COL1I(MPMATI *Mptr) 
/* 
 * deletes  the first column of *Mptr. 
 */ 
{ 
	unsigned int i, j, m, n; 
	MPMATI *Nptr; 
 
	m = Mptr->R; 
	n = Mptr->C; 
	Nptr = BUILDMATI(m, n - 1); 
	for (j = 0; j <= Nptr->C - 1; j++) 
	{ 
		for (i = 0; i <= m - 1; i++) 
			Nptr->V[i][j] = COPYI(Mptr->V[i][j + 1]); 
	} 
	return (Nptr); 
} 
 
unsigned int PIVOTI(MPMATI *Mptr, USI *rptr, USI *cptr, USI r, USI s) 
{ 
	unsigned int i, j, m, n; 
 
	m = Mptr->R; 
	n = Mptr->C; 
	*rptr = r; *cptr = s; 
	for (i = r; i < m; i++) 
	{ 
		for (j = 0; j < n; j++) 
		{ 
			if ((Mptr->V[i][j])->D == 0 && (Mptr->V[i][j])->V[0] == 1) 
			{ 
				*rptr = i; *cptr = j; 
				return (1); 
			} 
		} 
	} 
	return (0); 
}