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


/* The Pohst Algorithm updating only from where necessary */ 
#include  
#include  
#include "integer.h" 
#include "fun.h" 
extern MPI *MAXI, *PMAXI; 
 
extern unsigned int MLLLVERBOSE; 
extern unsigned int HERMITEVERBOSE; 
unsigned int GCDFLAG; 
 
MPMATI *BASIS_REDUCTION(MPMATI *Bptr, MPMATI **Eptr, USI rowstage, USI m1, USI n1) 
/* 
 * Input: *Bptr, a matrix of MPI's, whose first row is not zero. 
 * Output: a pointer to an MPMATI whose rows form a reduced basis for  
 * the lattice spanned by the rows of *Bptr. This basis is reduced in the  
 * sense of the paper "Factoring polynomials with rational coefficients" by 
 * A. K. Lenstra, H. W. Lenstra and L. Lovasz, Math. Ann. 261, 515-534 (1982) 
 * using the modified version in "Solving exponential Diophantine equations 
 * using lattice basis reduction algorithms" by B. M. M. De Weger, J. No. Theory 
 * 26, 325-367 (1987). A change of basis matrix **Eptr is also returned. 
 * De Weger's algorithm has been changed to cater for arbitrary matrices. The 
 * the rows are now in general linearly dependent.  
 * We use the fact that the Gram Schmidt process detects the first row  
 * which is a linear combination of the preceding rows. We employ a modification 
 * of the LLL algorithm outlined by M. Pohst in J. Symbolic Computation (1987)4, 
 * 123-127.  We call this the MLLL algorithm. 
 * The last sigma rows of the matrix **Eptr are relation vectors. 
 * m1 / n1 is usually taken to be 3 / 4. 
 */ 
{ 
	unsigned int i, k, l, n, m, t, flag = 0, Flag = 0; 
	unsigned int flagg, beta, K1 = 0, tau = 2, sigma = 0, rho; 
	MPI **D, *X, *Y, *Z, *H, *Tmp, *R, *M1, *N1; 
	MPMATI *C, *L, *B1ptr; 
 
	m = Bptr->C; 
	n = Bptr->R; 
	 
/* We initial Eptr outside the function whenever we call the function. */ 
/* This is because we have to do so in SMITH(). */ 
 
/*	MAXI = MAXELTI(Bptr); 
	PMAXI = MAXELTI(*Eptr); */ 
	B1ptr = COPYMATI(Bptr); 
	D = (MPI **)mmalloc((1 + n) * sizeof(MPI *)); 
	D[0] = ONEI(); 
	for (i = 1; i <= n; i++) 
		D[i] = ZEROI(); 
	C = ZEROMNI(n, m); 
	L = ZEROMNI(n, n); 
 
	found: 
	n = B1ptr->R; 
	i = (K1 == 0) ? 1 : K1; 
	/* K1 = no. of consecutive rows of *B1ptr that don't need updating  
for the Gram Schmidt process. */ 
	while (i <= B1ptr->R) 
	{ 
		BASIS_UPDATE(i, m, &C, &L, B1ptr, D); 
		flag = 1; 
		for (t = 0; t < m; t++) 
		{ 
			if (!EQZEROI(C->V[i - 1][t])) 
			{ 
				flag = 0;	 
				break; 
			} 
		}	 
		if (flag) 
			break; 
		X = ZEROI(); 
		for (t = 0; t < m; t++) 
		{ 
			H = MULTI(C->V[i - 1][t], C->V[i - 1][t]); 
			Tmp = X; 
			X = ADDI(X, H); 
			FREEMPI(Tmp); 
			FREEMPI(H); 
		} 
		FREEMPI(D[i]); 
		D[i] = INT(X, D[i - 1]);	 
		FREEMPI(X); 
		i++; 
	if (MLLLVERBOSE) 
		printf("i = %u\n", i); 
	} 
	beta =  (flag) ? i : i - 1; 
	rho = K1 = i - 1; 
if (MLLLVERBOSE) 
	printf("completed updating the basis\n"); 
/* Here K1 = no. of LI rows in *B1ptr found by Gram Schmidt process. 
   flag = 0 means all the rho = beta rows of *B1ptr are LI; 
   flag = 1 means that the first rho = beta - 1 rows of *B1ptr are LI, but the 
   beta-th row is a LC of the preceding rows. So beta = number of rows of *B1ptr 
   currently being examined by the LLL algorithm. */ 
	k = tau; 
	if (MLLLVERBOSE) 
		printf("beta = %u\n", beta); 
	M1 = CHANGE(m1); 
	N1 = CHANGE(n1); 
	while (k <= beta) 
	{ 
		if (MLLLVERBOSE) 
			printf("beta - k = %u\n", beta -k); 
		l = k - 1; 
		Flag = STEP4(k, l, &L, &B1ptr, Eptr, D, rowstage); 
		if (Flag)/* STEP 9 of POHST. */ 
		{ 
			sigma++; 
			if (MLLLVERBOSE) 
				printf("relation vector number %u found\n", sigma); 
			tau = k++; 
			goto found; 
		} 
		X = MULTI(D[k - 2], D[k]); 
		Y = MULTI(D[k - 1], D[k - 1]); 
		Tmp = Y; 
		Y = MULT_I(Y, m1); 
		FREEMPI(Tmp); 
		R = MULTI(L->V[k - 1][k - 2], L->V[k - 1][k - 2]); 
		Z = ADD0I(X, R); 
		Tmp = Z; 
		Z = MULT_I(Z, n1); 
		FREEMPI(Tmp); 
		if (RSV(Y, Z) == 1)/*& STEP 5 of POHST. */ 
		{ 
			flagg = 0; 
			if (EQZEROI(D[k]) && EQZEROI(R)) 
			{/* CASE B=0 of STEP 7 of POHST. */ 
				FREEMPI(D[k - 1]); 
				D[k - 1] = ZEROI(); 
				STEP8(k, &B1ptr, &L, Eptr, rowstage); 
				if (k - 1 < K1) 
					K1 = k - 1; 
				/* The swap may have changed 2nd last row */ 
				/* of *B1ptr. */ 
				for (t = 0; t < m; t++) 
				{ 
					FREEMPI(C->V[k - 2][t]); 
					C->V[k - 2][t] = ZEROI(); 
				} 
				beta--; 
				flagg = 1; 
				if (k > 2) 
					k--; 
				FREEMPI(X); 
				FREEMPI(Y); 
				FREEMPI(R); 
				FREEMPI(Z); 
				continue; 
			} 
			if (flagg == 0) 
			{ 
				for (i = k + 1; i <= beta; i++) 
					STEP7(i, k, &L, D); 
			} 
			STEP8(k, &B1ptr, &L, Eptr, rowstage); 
			if (k - 2 < K1) 
				K1 = k - 2; 
			/* swap will change last two rows of *B1ptr. */ 
			FREEMPI(R); 
			FREEMPI(Y); 
			Y = MULTI(L->V[k - 1][k - 2], L->V[k - 1][k - 2]); 
			Tmp = Y; 
			Y = ADD0I(Y, X); 
			FREEMPI(X); 
			FREEMPI(Tmp); 
			Tmp = D[k - 1]; 
			D[k - 1] = INT0(Y, D[k - 1]); 
			FREEMPI(Tmp); 
			FREEMPI(Y); 
			if (k > 2) 
				k--; 
		} 
		else 
		{ /* STEP 6 of POHST. */ 
			FREEMPI(R); 
			FREEMPI(X); 
			FREEMPI(Y); 
			for (l = k - 2; l >= 1; l--) 
			{ 
				Flag = 	STEP4(k, l, &L, &B1ptr, Eptr, D, rowstage); 
				if (Flag) 
				{ 
					FREEMPI(Z); 
					sigma++; 
				if (MLLLVERBOSE) 
					printf("relation vector number %u found\n", sigma); 
					tau = k++; 
					goto found; /* STEP 9 of POHST. */ 
				} 
			} 
			k++; 
		} 
		FREEMPI(Z); 
	} 
	FREEMPI(M1); 
	FREEMPI(N1); 
	FREEMATI(C); 
 
	printf("L = \n"); 
	PRINTMATI(0,L->R-1,0,L->C-1,L); 
	for (i = 0; i <= Bptr->R; i++) 
	{ 
		printf("D[%u] = ", i);PRINTI(D[i]);printf(", "); 
	} 
	printf("\n"); 
	FREEMATI(L); 
	for (i = 0; i <= Bptr->R; i++) 
		FREEMPI(D[i]); 
	ffree((char *)D, (1 + Bptr->R) * sizeof(MPI *)); 
	if (MLLLVERBOSE) 
	{ 
		printf("number of basis vectors found = %u ;\n", rho); 
		printf("number of relation vectors found = %u .\n", sigma); 
	} 
	return (B1ptr); 
} 
 
unsigned int STEP4(k, l, Lptr, Bptr, Eptr, D, i) 
/* 
 * updates *Lptr, *Bptr and *Eptr. 
 * returns 1 if row k of *Bptr becomes zero, returns zero otherwise. 
 */ 
unsigned int k, l, i; 
MPI *D[]; 
MPMATI **Lptr, **Bptr, **Eptr; 
{ 
	unsigned int j, flag = 1, t, m, n; 
	MPI *X, *Y, *R, *Tmp; 
	MPMATI *TmpMATI; 
 
	m = (*Bptr)->C; 
	n = (*Eptr)->R; 
	Y = MULT_I((*Lptr)->V[k - 1][l - 1], 2); 
	if (RSV(Y, D[l]) == 1) 
	{ 
		R = NEAREST_INTI((*Lptr)->V[k - 1][l - 1], D[l]); 
		X = MINUSI(R); 
		TmpMATI = *Bptr; 
		*Bptr = ADD_MULT_ROWI(l - 1, k - 1, X, *Bptr); 
/* 
		MAXI = UPDATEMAXI(MAXI, *Bptr); 
*/ 
		FREEMATI(TmpMATI); 
		TmpMATI = *Eptr; 
		*Eptr = ADD_MULT_ROWI(l + i - 1, k + i - 1, X, *Eptr); 
/* 
		PMAXI = UPDATEMAXI(PMAXI, *Eptr); 
*/ 
		FREEMATI(TmpMATI); 
		FREEMPI(X); 
		for (j = 1; j < l; j++) 
		{ 
			X = MULTI((*Lptr)->V[l - 1][j - 1], R); 
			Tmp = (*Lptr)->V[k - 1][j - 1]; 
			(*Lptr)->V[k - 1][j - 1] = SUBI((*Lptr)->V[k - 1][j - 1], X); 
			FREEMPI(Tmp); 
			FREEMPI(X); 
		} 
		X = MULTI(D[l], R); 
		Tmp = (*Lptr)->V[k - 1][l - 1]; 
		(*Lptr)->V[k - 1][l - 1] = SUBI((*Lptr)->V[k - 1][l - 1], X); 
		FREEMPI(Tmp); 
		FREEMPI(X); 
		FREEMPI(R); 
	} 
	for (t = 0; t < m; t++) 
	{ 
		if (!EQZEROI((*Bptr)->V[k - 1][t])) 
		{ 
			flag = 0;	 
			break; 
		} 
	}	 
	if (flag) 
	{ 
		TmpMATI = *Bptr; 
		*Bptr = DELETE_ROWI(k, *Bptr); 
		FREEMATI(TmpMATI); 
		for (j = k - 1; j < n - i - 1; j++) 
			*Eptr = SWAP_ROWSI1(j + i, j + i + 1, *Eptr); 
	} 
	FREEMPI(Y); 
	return (flag); 
} 
 
void STEP8(USI k, MPMATI **B1ptr, MPMATI **Lptr, MPMATI **Eptr, USI i) 
{ 
	MPI *T; 
 
	*B1ptr = SWAP_ROWSI1(k - 2, k - 1, *B1ptr); 
	*Eptr = SWAP_ROWSI1(k + i - 2, k + i - 1, *Eptr); 
	T = COPYI((*Lptr)->V[k - 1][ k - 2]); 
	*Lptr = SWAP_ROWSI1(k - 2, k - 1, *Lptr); 
	FREEMPI((*Lptr)->V[ k - 1][k - 2]); 
	(*Lptr)->V[k - 1][k - 2] = T; 
	FREEMPI((*Lptr)->V[k - 2][k - 2]); 
	(*Lptr)->V[k - 2][k - 2] = ZEROI(); 
	return; 
} 
 
void STEP7(USI i, USI k, MPMATI **Lptr, MPI *D[]) 
{ 
	MPI *X1, *X2, *X3, *Y1, *Y2, *Tmp; 
 
	X1 = MULTI((*Lptr)->V[i - 1][k - 2], (*Lptr)->V[k - 1][k - 2]); 
	Y1 = MULTI((*Lptr)->V[i - 1][k - 1], D[k - 2]); 
	Tmp = Y1; 
	Y1 = ADDI(Y1, X1); 
	FREEMPI(Tmp); 
	FREEMPI(X1); 
	X2 = MULTI((*Lptr)->V[i - 1][k - 2], D[k]); 
	X3 = MINUSI((*Lptr)->V[k - 1][k - 2]); 
	Y2 = MULTI((*Lptr)->V[i - 1][k - 1], X3); 
	FREEMPI(X3); 
	Tmp = Y2; 
	Y2 = ADDI(Y2, X2); 
	FREEMPI(Tmp); 
	FREEMPI(X2); 
	FREEMPI((*Lptr)->V[i - 1][k - 2]); 
	(*Lptr)->V[i - 1][k - 2] = INT(Y1, D[k - 1]); 
	FREEMPI((*Lptr)->V[i - 1][k - 1]); 
	(*Lptr)->V[i - 1][k - 1] = INT(Y2, D[k - 1]); 
	FREEMPI(Y1); 
	FREEMPI(Y2); 
	return; 
} 
 
void BASIS_UPDATE(USI i, USI m, MPMATI **Cptr, MPMATI **Lptr, MPMATI *B1ptr, MPI *D[]) 
{ 
	unsigned int j, k, t; 
	MPI *X, *Tmp, *X1, *X2, *H; 
 
	for (k = 1; k <= m; k++) 
	{ 
		FREEMPI((*Cptr)->V[i - 1][k - 1]); 
		(*Cptr)->V[i - 1][k - 1] = COPYI(B1ptr->V[i - 1][k - 1]); 
	} 
	for (j = 1; j < i; j++) 
	{ 
		X = ZEROI(); 
		for (t = 0; t < m; t++) 
		{ 
			if (((*Cptr)->V[j - 1][t])->S != 0 && (B1ptr->V[i - 1][t])->S != 0) 
			{ 
				H = MULTI((*Cptr)->V[j - 1][t], B1ptr->V[i - 1][t]); 
				Tmp = X; 
				X = ADDI(X, H); 
				FREEMPI(H); 
				FREEMPI(Tmp); 
			} 
		} 
		FREEMPI((*Lptr)->V[i - 1][j - 1]); 
		(*Lptr)->V[i - 1][j - 1] = X; 
		for (t = 0; t < m; t++) 
		{ 
			if (((*Cptr)->V[i - 1][t])->S == 0) 
				X1 = ZEROI(); 
			else 
				X1 = MULTI((*Cptr)->V[i - 1][t], D[j]); 
			if (((*Cptr)->V[j - 1][t])->S != 0 && ((*Lptr)->V[i - 1][j - 1])->S != 0) 
				X2 = MULTI((*Cptr)->V[j - 1][t], (*Lptr)->V[i - 1][j - 1]); 
			else 
				X2 = ZEROI(); 
			Tmp = X1; 
			X1 = SUBI(X1, X2); 
			FREEMPI(Tmp); 
			FREEMPI(X2); 
			FREEMPI((*Cptr)->V[i - 1][t]); 
			(*Cptr)->V[i - 1][t] = INT(X1, D[j - 1]); 
			FREEMPI(X1); 
		} 
	} 
	return; 
} 
 
void CSWAP_UPDATE(USI k, USI m, MPI *S, MPMATI **Cptr, MPI *D[]) 
{ 
	unsigned int t; 
	MPI *Tmp1, *Tmp2, *Tmp3, *Tmp4; 
 
	for (t = 0; t < m; t++) 
	{ 
		Tmp1 = MULTI((*Cptr)->V[k - 1][t], D[k - 2]); 
		Tmp2 = MULTI((*Cptr)->V[k - 2][t], S); 
		Tmp3 = ADDI(Tmp1, Tmp2); 
		FREEMPI(Tmp1); 
		FREEMPI(Tmp2); 
	 
		Tmp1 = MULTI((*Cptr)->V[k - 2][t], D[k]); 
		Tmp2 = MULTI((*Cptr)->V[k - 1][t], S); 
		Tmp4 = SUBI(Tmp1, Tmp2); 
		FREEMPI(Tmp1); 
		FREEMPI(Tmp2); 
		FREEMPI((*Cptr)->V[k - 2][t]); 
		FREEMPI((*Cptr)->V[k - 1][t]); 
		(*Cptr)->V[k - 2][t] = INT(Tmp3, D[k - 1]); 
		(*Cptr)->V[k - 1][t] = INT(Tmp4, D[k - 1]); 
		FREEMPI(Tmp3); 
		FREEMPI(Tmp4); 
	} 
	return; 
} 
 
MPMATI *BASIS_REDUCTION0(MPMATI *Bptr, USI m1, USI n1) 
/* 
 * Input: *Bptr, a matrix of MPI's, whose first row is not zero. 
 * Output: a pointer to an MPMATI whose rows form a reduced basis for  
 * the lattice spanned by the rows of *Bptr. This basis is reduced in the  
 * sense of the paper "Factoring polynomials with rational coefficients" by 
 * A. K. Lenstra, H. W. Lenstra and L. Lovasz, Math. Ann. 261, 515-534 (1982) 
 * using the modified version in "Solving exponential Diophantine equations 
 * using lattice basis reduction algorithms" by B. M. M. De Weger, J. No. Theory 
 * 26, 325-367 (1987). No change of basis matrix is returned. 
 * De Weger's algorithm has been changed to cater for arbitrary matrices. The 
 * the rows are now in general linearly dependent.  
 * We use the fact that the Gram Schmidt process detects the first row  
 * which is a linear combination of the preceding rows. We employ a modification 
 * of the LLL algorithm outlined by M. Pohst in J. Symbolic Computation (1987)4, 
 * 123-127.  We call this the MLLL algorithm. 
 * If we are using this algorithm to find small multipliers for the extended  
 * gcd problem, GCDFLAG is set in EXTGCD() and gcdflag is set below. 
 * m1 / n1 is usually taken to be 3 / 4. 
 */ 
{ 
	unsigned int i, k, l, n, m, t, flag = 0, Flag = 0, gcdflag = 0; 
	unsigned int flagg, beta, K1 = 0, tau = 2, sigma = 0, rho; 
	MPI **D, *X, *Y, *Z, *H, *Tmp, *R, *M1, *N1; 
	MPMATI *C, *L, *B1ptr; 
	unsigned int norig; 
 
	Z = NULL; 
	m = Bptr->C; 
	n = Bptr->R; 
	norig = n; 
	B1ptr = COPYMATI(Bptr); 
	D = (MPI **)mmalloc((1 + n) * sizeof(MPI *)); 
	D[0] = ONEI(); 
	for (i = 1; i <= n; i++) 
		D[i] = ZEROI(); 
	C = ZEROMNI(n, m); 
	L = ZEROMNI(n, n); 
 
	found: 
	n = B1ptr->R; 
	i = (K1 == 0) ? 1 : K1; 
	/* K1 = no. of consecutive rows of *B1ptr that don't need updating  
for the Gram Schmidt process. */ 
	while (i <= B1ptr->R) 
	{ 
		BASIS_UPDATE(i, m, &C, &L, B1ptr, D); 
		flag = 1; 
		for (t = 0; t < m; t++) 
		{ 
			if (!EQZEROI(C->V[i - 1][t])) 
			{ 
				flag = 0;	 
				break; 
			} 
		}	 
		if (flag) 
			break; 
		X = ZEROI(); 
		for (t = 0; t < m; t++) 
		{ 
			H = MULTI(C->V[i - 1][t], C->V[i - 1][t]); 
			Tmp = X; 
			X = ADDI(X, H); 
			FREEMPI(Tmp); 
			FREEMPI(H); 
		} 
		FREEMPI(D[i]); 
		D[i] = INT(X, D[i - 1]);	 
		FREEMPI(X); 
		i++; 
		if (MLLLVERBOSE) 
				printf("i = %u\n", i); 
	} 
	beta =  (flag) ? i : i - 1; 
	rho = K1 = i - 1; 
	if (MLLLVERBOSE) 
		printf("BASIS0 completed updating the basis\n"); 
/* Here K1 = no. of LI rows in *B1ptr found by Gram Schmidt process. 
   flag = 0 means all the rho = beta rows of *B1ptr are LI; 
   flag = 1 means that the first rho = beta - 1 rows of *B1ptr are LI, but the 
   beta-th row is a LC of the preceding rows. So beta = number of rows of *B1ptr 
   currently being examined by the LLL algorithm. */ 
	k = tau; 
	M1 = CHANGE(m1); 
	N1 = CHANGE(n1); 
	while (k <= beta) 
	{ 
		if (MLLLVERBOSE) 
			printf("beta - k = %u\n", beta -k); 
		l = k - 1; 
		Flag = STEP40(k, l, &L, &B1ptr, D); 
		if (k >= norig && GCDFLAG) 
		{ 
			gcdflag = 1; 
			goto FOUND; 
		} 
		if (Flag)/* STEP 9 of POHST. */ 
		{ 
			sigma++; 
			if (MLLLVERBOSE) 
				printf("relation vector number %u found\n", sigma); 
			tau = k++; 
			goto found; 
		} 
		X = MULTI(D[k - 2], D[k]); 
		Y = MULTI(D[k - 1], D[k - 1]); 
		Tmp = Y; 
		Y = MULT_I(Y, m1); 
		FREEMPI(Tmp); 
		R = MULTI(L->V[k - 1][k - 2], L->V[k - 1][k - 2]); 
		Z = ADD0I(X, R); 
		Tmp = Z; 
		Z = MULT_I(Z, n1); 
		FREEMPI(Tmp); 
		if (RSV(Y, Z) == 1)/*& STEP 5 of POHST. */ 
		{ 
			flagg = 0; 
			if (EQZEROI(D[k]) && EQZEROI(R)) 
			{/* CASE B=0 of STEP 7 of POHST. */ 
				FREEMPI(D[k - 1]); 
				D[k - 1] = ZEROI(); 
				STEP80(k, &B1ptr, &L); 
				if (k - 1 < K1) 
					K1 = k - 1; 
				/* The swap may have changed 2nd last row */ 
				/* of *B1ptr. */ 
				for (t = 0; t < m; t++) 
				{ 
					FREEMPI(C->V[k - 2][t]); 
					C->V[k - 2][t] = ZEROI(); 
				} 
				beta--; 
				flagg = 1; 
				if (k > 2) 
					k--; 
				FREEMPI(X); 
				FREEMPI(Y); 
				FREEMPI(R); 
				FREEMPI(Z); 
				continue; 
			} 
			if (flagg == 0) 
			{ 
				for (i = k + 1; i <= beta; i++) 
					STEP7(i, k, &L, D); 
			} 
			STEP80(k, &B1ptr, &L); 
			if (k - 2 < K1) 
				K1 = k - 2; 
			/* swap will change last two rows of *B1ptr. */ 
			FREEMPI(R); 
			FREEMPI(Y); 
			Y = MULTI(L->V[k - 1][k - 2], L->V[k - 1][k - 2]); 
			Tmp = Y; 
			Y = ADD0I(Y, X); 
			FREEMPI(X); 
			FREEMPI(Tmp); 
			Tmp = D[k - 1]; 
			D[k - 1] = INT0(Y, D[k - 1]); 
			FREEMPI(Tmp); 
			FREEMPI(Y); 
			if (k > 2) 
				k--; 
		} 
		else 
		{ /* STEP 6 of POHST. */ 
			FREEMPI(R); 
			FREEMPI(X); 
			FREEMPI(Y); 
FOUND: 
			for (l = k - 2; l >= 1; l--) 
			{ 
				Flag = 	STEP40(k, l, &L, &B1ptr, D); 
				if (Flag) 
				{ 
					FREEMPI(Z); 
					sigma++; 
					if (MLLLVERBOSE) 
						printf("relation vector number %u found\n", sigma); 
					tau = k++; 
					goto found; /* STEP 9 of POHST. */ 
				} 
			} 
			k++; 
		} 
		if (!gcdflag) 
			FREEMPI(Z); 
		else 
			break; 
	} 
	FREEMPI(M1); 
	FREEMPI(N1); 
	FREEMATI(C); 
/* 
	printf("L = \n"); 
	PRINTMATI(0,L->R-1,0,L->C-1,L); 
	for (i = 0; i <= norig; i++) 
	{ 
		printf("D[%u] = ", i);PRINTI(D[i]);printf(", "); 
	} 
	printf("\n"); 
*/ 
	FREEMATI(L); 
	for (i = 0; i <= norig; i++) 
		FREEMPI(D[i]); 
	ffree((char *)D, (1 + norig) * sizeof(MPI *)); 
	if (MLLLVERBOSE) 
	{ 
		printf("number of basis vectors found = %u ;\n", rho); 
		printf("number of relation vectors found = %u .\n", sigma); 
	} 
	return (B1ptr); 
} 
 
unsigned int STEP40(k, l, Lptr, Bptr, D) 
/* 
 * updates *Lptr, *Bptr. 
 * returns 1 if row k of *Bptr becomes zero, returns zero otherwise. 
 */ 
unsigned int k, l; 
MPI *D[]; 
MPMATI **Lptr, **Bptr; 
{ 
	unsigned int j, flag = 1, t, m; 
	MPI *X, *Y, *R, *Tmp; 
	MPMATI *TmpMATI; 
 
	m = (*Bptr)->C; 
	Y = MULT_I((*Lptr)->V[k - 1][l - 1], 2); 
	if (RSV(Y, D[l]) == 1) 
	{ 
		R = NEAREST_INTI((*Lptr)->V[k - 1][l - 1], D[l]); 
		X = MINUSI(R); 
		TmpMATI = *Bptr; 
		*Bptr = ADD_MULT_ROWI(l - 1, k - 1, X, *Bptr); 
		if (MLLLVERBOSE) 
		{ 
			printf("Row %u -> Row %u + ", k,k);PRINTI(X);printf(" x Row %u\n", l); 
			PRINTMATI(0,(*Bptr)->R-1,0,(*Bptr)->C-1,*Bptr); 
			GetReturn(); 
		} 
		FREEMATI(TmpMATI); 
/* 
		MAXI = UPDATEMAXI(MAXI, *Bptr); 
*/ 
		FREEMPI(X); 
		for (j = 1; j < l; j++) 
		{ 
			X = MULTI((*Lptr)->V[l - 1][j - 1], R); 
			Tmp = (*Lptr)->V[k - 1][j - 1]; 
			(*Lptr)->V[k - 1][j - 1] = SUBI((*Lptr)->V[k - 1][j - 1], X); 
			FREEMPI(Tmp); 
			FREEMPI(X); 
		} 
		X = MULTI(D[l], R); 
		Tmp = (*Lptr)->V[k - 1][l - 1]; 
		(*Lptr)->V[k - 1][l - 1] = SUBI((*Lptr)->V[k - 1][l - 1], X); 
		FREEMPI(Tmp); 
		FREEMPI(X); 
		FREEMPI(R); 
	} 
	for (t = 0; t < m; t++) 
	{ 
		if (!EQZEROI((*Bptr)->V[k - 1][t])) 
		{ 
			flag = 0;	 
			break; 
		} 
	}	 
	if (flag) 
	{ 
		TmpMATI = *Bptr; 
		*Bptr = DELETE_ROWI(k, *Bptr); 
		FREEMATI(TmpMATI); 
	} 
	FREEMPI(Y); 
	return (flag); 
} 
 
unsigned int STEP400(k, l, Lptr, Bptr, D, gcdflag, norig) 
/* 
 * updates *Lptr, *Bptr. 
 * returns 1 if row k of *Bptr becomes zero, returns zero otherwise. 
 */ 
unsigned int k, l, gcdflag, norig; 
MPI *D[]; 
MPMATI **Lptr, **Bptr; 
{ 
	unsigned int j, flag = 1, t, m; 
	MPI *X, *Y, *R, *Tmp; 
	MPMATI *TmpMATI; 
 
	m = (*Bptr)->C; 
	Y = MULT_I((*Lptr)->V[k - 1][l - 1], 2); 
	if (RSV(Y, D[l]) == 1) 
	{ 
		R = NEAREST_INTI((*Lptr)->V[k - 1][l - 1], D[l]); 
		X = MINUSI(R); 
		TmpMATI = *Bptr; 
		*Bptr = ADD_MULT_ROWI(l - 1, k - 1, X, *Bptr); 
		FREEMATI(TmpMATI); 
/* 
		MAXI = UPDATEMAXI(MAXI, *Bptr); 
*/ 
		FREEMPI(X); 
		for (j = 1; j < l; j++) 
		{ 
			X = MULTI((*Lptr)->V[l - 1][j - 1], R); 
			Tmp = (*Lptr)->V[k - 1][j - 1]; 
			(*Lptr)->V[k - 1][j - 1] = SUBI((*Lptr)->V[k - 1][j - 1], X); 
			FREEMPI(Tmp); 
			FREEMPI(X); 
		} 
		X = MULTI(D[l], R); 
		Tmp = (*Lptr)->V[k - 1][l - 1]; 
		(*Lptr)->V[k - 1][l - 1] = SUBI((*Lptr)->V[k - 1][l - 1], X); 
		FREEMPI(Tmp); 
		FREEMPI(X); 
		FREEMPI(R); 
	} 
	for (t = 0; t < m; t++) 
	{ 
		if (!EQZEROI((*Bptr)->V[k - 1][t])) 
		{ 
			flag = 0;	 
			break; 
		} 
	}	 
	if (flag) 
	{ 
		TmpMATI = *Bptr; 
		*Bptr = DELETE_ROWI(k, *Bptr); 
		FREEMATI(TmpMATI); 
	} 
	FREEMPI(Y); 
	return (flag); 
} 
 
void STEP80(k, B1ptr, Lptr) 
MPMATI **B1ptr, **Lptr; 
unsigned int k; 
{ 
	MPI *T; 
 
	*B1ptr = SWAP_ROWSI1(k - 2, k - 1, *B1ptr); 
	if (MLLLVERBOSE) 
	{ 
		printf("Swapping Rows %u and %u\n", k-1,k); 
		PRINTMATI(0,(*B1ptr)->R-1,0,(*B1ptr)->C-1,*B1ptr); 
		GetReturn(); 
	} 
	T = COPYI((*Lptr)->V[k - 1][k - 2]); 
	*Lptr = SWAP_ROWSI1(k - 2, k - 1, *Lptr); 
	FREEMPI((*Lptr)->V[k - 1][k - 2]); 
	(*Lptr)->V[k - 1][k - 2] = T; 
	FREEMPI((*Lptr)->V[k - 2][k - 2]); 
	(*Lptr)->V[k - 2][k - 2] = ZEROI(); 
	return; 
} 
 
MPMATI *EXTGCD(MPMATI *Dptr, MPI **Aptr, MPMATI **Q, USI m1, USI n1) 
/* 
 * Input: an n x 1 vector of MPI's. 
 * Output: *Aptr = gcd of the vector of MPI's. Also we return a small set of 
 * multipliers using the LLL method of Havas and Matthews. 
 * parameters m1 and n1 were put in at the request of George Havas on 11/7/94. 
 * Normally m1/n1 = 3/4. 
 * matrix Q of the LLL extended gcd paper of Havas-Matthews is returned. 
 */ 
{ 
	MPMATI *Temp, *P, *SM, *R; 
	USI i, m, n, *alpha, nz; 
	MPI **Tptr; 
 
	n = Dptr->R; 
	m = n - 1; 
	alpha = KB_ROWP(Dptr, &R, &nz); 
	Temp = HERMITE1P(Dptr, R, &P, alpha, nz); 
	FREEMATI(R); 
	ffree((char *)alpha, (Dptr->C) * sizeof(USI)); 
	*Aptr = COPYI(Temp->V[0][0]); 
	FREEMATI(Temp); 
	Tptr = P->V[0]; 
	for (i = 0; i < m; i++) 
		P->V[i] = P->V[i+1]; 
	P->V[n - 1] = Tptr; 
	GCDFLAG = 1; 
	*Q = BASIS_REDUCTION0(P, m1, n1);	 
	SM = BUILDMATI(1, n); 
	for (i = 0; i < n; i++) 
		SM->V[0][i] = COPYI((*Q)->V[m][i]); 
	FREEMATI(P); 
	GCDFLAG = 0; 
	return (SM); 
} 
 
MPI *LENGTHSQRI(MPMATI *Mptr, USI i) 
/* 
 * Returns the square of the length of row i of matrix *Mptr. 
 */ 
{ 
	MPI *SUM, *T, *T1; 
	USI j; 
	 
	SUM = ZEROI(); 
	for (j = 0; j < Mptr->C; j++) 
	{ 
		T = SUM; 
		T1 = MULTI(Mptr->V[i][j], Mptr->V[i][j]); 
		SUM = ADD0I(SUM, T1); 
		FREEMPI(T); 
		FREEMPI(T1); 
	} 
	return (SUM); 
} 
 
MPI *LENGTHSQCI(MPMATI *Mptr, USI j) 
/* 
 * Returns the square of the length of column j of matrix *Mptr. 
 */ 
{ 
	MPI *SUM, *T, *T1; 
	USI i; 
	 
	SUM = ZEROI(); 
	for (i = 0; i < Mptr->R; i++) 
	{ 
		T = SUM; 
		T1 = MULTI(Mptr->V[i][j], Mptr->V[i][j]); 
		SUM = ADD0I(SUM, T1); 
		FREEMPI(T); 
		FREEMPI(T1); 
	} 
	return (SUM); 
} 
 
MPMATI *BASIS_REDUCTION00(MPMATI *Bptr, USI m1, USI n1, USI norig) 
/* 
 * Input: *Bptr, a matrix of MPI's, whose first row is not zero. 
 * Output: a pointer to an MPMATI whose rows form a reduced basis for  
 * the lattice spanned by the rows of *Bptr. This basis is reduced in the  
 * sense of the paper "Factoring polynomials with rational coefficients" by 
 * A. K. Lenstra, H. W. Lenstra and L. Lovasz, Math. Ann. 261, 515-534 (1982) 
 * using the modified version in "Solving exponential Diophantine equations 
 * using lattice basis reduction algorithms" by B. M. M. De Weger, J. No. Theory 
 * 26, 325-367 (1987). No change of basis matrix is returned. 
 * De Weger's algorithm has been changed to cater for arbitrary matrices. The 
 * the rows are now in general linearly dependent.  
 * We use the fact that the Gram Schmidt process detects the first row  
 * which is a linear combination of the preceding rows. We employ a modification 
 * of the LLL algorithm outlined by M. Pohst in J. Symbolic Computation (1987)4, 
 * 123-127.  We call this the MLLL algorithm. 
 * If we are using this algorithm to find small multipliers for the extended  
 * gcd problem, GCDFLAG is set in IMPROVEP() and gcdflag is set below. 
 * m1 / n1 is usually taken to be 3 / 4. 
 * For use in IMPROVEP(). 
 */ 
{ 
	unsigned int i, k, n, m, t, flag = 0, Flag = 0, gcdflag = 0; 
	unsigned int flagg, beta, K1 = 0, tau = 2, sigma = 0, rho, norigg; 
	unsigned int K, j, REPEAT, iterate; 
	int l, tt; 
	MPI **D, *X, *Y, *Z, *H, *Tmp, *R, *M1, *N1; 
	MPI *t1, *t2, *t3, *t4; 
	MPMATI *C, *L, *B1ptr, *temp1; 
 
	Z = NULL; 
	m = Bptr->C; 
	norigg = n = Bptr->R; 
	B1ptr = COPYMATI(Bptr); 
	D = (MPI **)mmalloc((1 + n) * sizeof(MPI *)); 
	D[0] = ONEI(); 
	for (i = 1; i <= n; i++) 
		D[i] = ZEROI(); 
	C = ZEROMNI(n, m); 
	L = ZEROMNI(n, n); 
 
	found: 
	n = B1ptr->R; 
	i = (K1 == 0) ? 1 : K1; 
	/* K1 = no. of consecutive rows of *B1ptr that don't need updating  
for the Gram Schmidt process. */ 
	while (i <= B1ptr->R) 
	{ 
		BASIS_UPDATE(i, m, &C, &L, B1ptr, D); 
		flag = 1; 
		for (t = 0; t < m; t++) 
		{ 
			if (!EQZEROI(C->V[i - 1][t])) 
			{ 
				flag = 0;	 
				break; 
			} 
		}	 
		if (flag) 
			break; 
		X = ZEROI(); 
		for (t = 0; t < m; t++) 
		{ 
			H = MULTI(C->V[i - 1][t], C->V[i - 1][t]); 
			Tmp = X; 
			X = ADDI(X, H); 
			FREEMPI(Tmp); 
			FREEMPI(H); 
		} 
		FREEMPI(D[i]); 
		D[i] = INT(X, D[i - 1]);	 
		FREEMPI(X); 
		i++; 
		if (MLLLVERBOSE) 
			printf("i = %u\n", i); 
	} 
/* 
	strcpy(buff, "L.out"); 
	outfile = fopen(buff, "w"); 
	FPRINTMATI(outfile,0,L->R-1,0,L->C-1,L); 
	fclose(outfile); 
	for (t = 0;t < B1ptr->R; t++){ 
		printf("D[%u] = ", t);PRINTI(D[t]);printf("\n"); 
	} 
	GetReturn(); 
*/ 
	beta =  (flag) ? i : i - 1; 
	rho = K1 = i - 1; 
	if (MLLLVERBOSE) 
		printf("completed updating the basis\n"); 
/* Here K1 = no. of LI rows in *B1ptr found by Gram Schmidt process. 
   flag = 0 means all the rho = beta rows of *B1ptr are LI; 
   flag = 1 means that the first rho = beta - 1 rows of *B1ptr are LI, but the 
   beta-th row is a LC of the preceding rows. So beta = number of rows of *B1ptr 
   currently being examined by the LLL algorithm. */ 
	k = tau; 
	M1 = CHANGE(m1); 
	N1 = CHANGE(n1); 
	while (k <= beta) 
	{ 
		if (MLLLVERBOSE) 
			printf("beta - k = %u\n", beta -k); 
		if (gcdflag) 
			l = norig; 
		else 
			l = k - 1; 
		Flag = STEP40(k, l, &L, &B1ptr, D); 
		if (k > norig && GCDFLAG) 
		{ 
			gcdflag = 1; 
			if (MLLLVERBOSE) 
				printf("improving row %u\n", k); 
			goto FOUND; 
		} 
		if (Flag)/* STEP 9 of POHST. */ 
		{ 
			sigma++; 
			if (MLLLVERBOSE) 
				printf("relation vector number %u found\n", sigma); 
			tau = k++; 
			goto found; 
		} 
		X = MULTI(D[k - 2], D[k]); 
		Y = MULTI(D[k - 1], D[k - 1]); 
		Tmp = Y; 
		Y = MULT_I(Y, m1); 
		FREEMPI(Tmp); 
		R = MULTI(L->V[k - 1][k - 2], L->V[k - 1][k - 2]); 
		Z = ADD0I(X, R); 
		Tmp = Z; 
		Z = MULT_I(Z, n1); 
		FREEMPI(Tmp); 
		if (RSV(Y, Z) == 1)/*& STEP 5 of POHST. */ 
		{ 
			flagg = 0; 
			if (EQZEROI(D[k]) && EQZEROI(R)) 
			{/* CASE B=0 of STEP 7 of POHST. */ 
				FREEMPI(D[k - 1]); 
				D[k - 1] = ZEROI(); 
				STEP80(k, &B1ptr, &L); 
				if (k - 1 < K1) 
					K1 = k - 1; 
				/* The swap may have changed 2nd last row */ 
				/* of *B1ptr. */ 
				for (t = 0; t < m; t++) 
				{ 
					FREEMPI(C->V[k - 2][t]); 
					C->V[k - 2][t] = ZEROI(); 
				} 
				beta--; 
				flagg = 1; 
				if (k > 2) 
					k--; 
				FREEMPI(X); 
				FREEMPI(Y); 
				FREEMPI(R); 
				FREEMPI(Z); 
				continue; 
			} 
			if (flagg == 0) 
			{ 
				for (i = k + 1; i <= beta; i++) 
					STEP7(i, k, &L, D); 
			} 
			STEP80(k, &B1ptr, &L); 
			if (k - 2 < K1) 
				K1 = k - 2; 
			/* swap will change last two rows of *B1ptr. */ 
			FREEMPI(R); 
			FREEMPI(Y); 
			Y = MULTI(L->V[k - 1][k - 2], L->V[k - 1][k - 2]); 
			Tmp = Y; 
			Y = ADD0I(Y, X); 
			FREEMPI(X); 
			FREEMPI(Tmp); 
			Tmp = D[k - 1]; 
			D[k - 1] = INT0(Y, D[k - 1]); 
			FREEMPI(Tmp); 
			FREEMPI(Y); 
			if (k > 2) 
				k--; 
		} 
		else 
		{ /* STEP 6 of POHST. */ 
			FREEMPI(R); 
			FREEMPI(X); 
			FREEMPI(Y); 
FOUND: 
			if (gcdflag) 
			{ 
				if (MLLLVERBOSE) 
					printf("gcdflag set\n"); 
				K = norig + 1; 
			} 
			else 
				K = k; 
			for (l = K - 2; l >= 1; l--) 
			{ 
				Flag = 	STEP40(k, l, &L, &B1ptr, D); 
				if (Flag) 
				{ 
					FREEMPI(Z); 
					sigma++; 
					if (MLLLVERBOSE) 
						printf("relation vector number %u found\n", sigma); 
					tau = k++; 
					goto found; /* STEP 9 of POHST. */ 
				} 
			} 
			k++; 
		} 
		if (!gcdflag) 
			FREEMPI(Z); 
	} 
	FREEMPI(M1); 
	FREEMPI(N1); 
	FREEMATI(C); 
	FREEMATI(L); 
	for (i = 0; i <= norigg; i++) 
		FREEMPI(D[i]); 
	ffree((char *)D, (1 + norigg) * sizeof(MPI *)); 
	/* Now to improve the last n - norig rows of *B1ptr, using Gauss 
lattice reduction - pointed out by George Havas in Sims' book - 8/11/94: */ 
 
 
/* 
	strcpy(buff, "progress"); 
	outfile = fopen(buff, "a+"); 
	FPRINTMATI(outfile,0,B1ptr->R-1,0,B1ptr->C-1,B1ptr); 
*/ 
 
 
	REPEAT = 1; 
	temp1 = BUILDMATI(1, B1ptr->C); 
	for (k = 0; k < B1ptr->C; k++) 
		temp1->V[0][k] = ZEROI(); 
	iterate = 0; 
	QSORTMATI(B1ptr, 0, norig - 1); 
	while (REPEAT) 
	{ 
		REPEAT = 0; 
		for (j = 1; j < norig; j++) 
		{ 
			t4 = DOTRI(B1ptr, j, j); 
			for (i = 0; i < j; i++) 
			{ 
				t1 = DOTRI(B1ptr, j, i); 
				t2 = DOTRI(B1ptr, i, i); 
				t3 = NEAREST_INTI(t1, t2); 
				FREEMPI(t1); 
				FREEMPI(t2); 
				if (t3->S == 0) 
				{ 
					FREEMPI(t3); 
					continue; 
				} 
				t1 = t3; 
				t3 = MINUSI(t3); 
				FREEMPI(t1); 
				for (k = 0; k < B1ptr->C; k++) 
				{ 
					FREEMPI(temp1->V[0][k]); 
					X = MULTI(t3, B1ptr->V[i][k]); 
					temp1->V[0][k] = ADDI(X, B1ptr->V[j][k]); 
					FREEMPI(X); 
				} 
				t1 = DOTRI(temp1, 0, 0); 
				tt = RSV(t1, t4); 
				tt = RSV(t1, t4); 
				if (tt == -1) 
				{ 
					ADD_MULT_ROWI0(i, j, t3, B1ptr); 
					if (MLLLVERBOSE) 
					{ 
						printf("Gauss-improving nullspace row %u: length squared was = ", j + 1); 
						PRINTI(t4); 
						printf("\n"); 
						printf("lengthsquared now = "); 
						PRINTI(t1); 
						printf("\n"); 
					} 
/* 
					fprintf(outfile, "Gauss-improving nullspace row %u: length squared was = ", j + 1); 
					FPRINTI(outfile, t4); 
					fprintf(outfile, "\n"); 
					fprintf(outfile, "lengthsquared now = "); 
					FPRINTI(outfile, t1); 
					fprintf(outfile, "\n"); 
					fflush(outfile); 
*/ 
					FREEMPI(t4); 
					t4 = t1; 
					REPEAT = 1; 
				} 
				else 
					FREEMPI(t1); 
				FREEMPI(t3); 
			} 
				FREEMPI(t4); 
		} 
		iterate++; 
		QSORTMATI(B1ptr, 0, norig - 1); 
	} 
	REPEAT = 1; 
	iterate = 0; 
	while (REPEAT) 
	{ 
		REPEAT = 0; 
		for (j = norig; j < B1ptr->R; j++) 
		{ 
			t4 = DOTRI(B1ptr, j, j); 
			for (i = 0; i < norig; i++) 
			{ 
				t1 = DOTRI(B1ptr, j, i); 
				t2 = DOTRI(B1ptr, i, i); 
				t3 = NEAREST_INTI(t1, t2); 
				FREEMPI(t1); 
				FREEMPI(t2); 
				if (t3->S == 0) 
				{ 
					FREEMPI(t3); 
					continue; 
				} 
				t1 = t3; 
				t3 = MINUSI(t3); 
				FREEMPI(t1); 
				for (k = 0; k < B1ptr->C; k++) 
				{ 
					FREEMPI(temp1->V[0][k]); 
					X = MULTI(t3, B1ptr->V[i][k]); 
					temp1->V[0][k] = ADDI(X, B1ptr->V[j][k]); 
					FREEMPI(X); 
				} 
				t1 = DOTRI(temp1, 0, 0); 
				tt = RSV(t1, t4); 
				tt = RSV(t1, t4); 
				if (tt == -1) 
				{ 
					ADD_MULT_ROWI0(i, j, t3, B1ptr); 
					if (MLLLVERBOSE) 
					{ 
						printf("Gauss-improving row %u: length squared was = ", j + 1); 
						PRINTI(t4); 
						printf("\n"); 
						printf("lengthsquared now = "); 
						PRINTI(t1); 
						printf("\n"); 
					} 
/* 
					fprintf(outfile, "Gauss-improving row %u: length squared was = ", j + 1); 
					FPRINTI(outfile, t4); 
					fprintf(outfile, "\n"); 
					fprintf(outfile, "lengthsquared now = "); 
					FPRINTI(outfile, t1); 
					fprintf(outfile, "\n"); 
					fflush(outfile); 
*/ 
					FREEMPI(t4); 
					t4 = t1; 
					REPEAT = 1; 
				} 
				else 
					FREEMPI(t1); 
				FREEMPI(t3); 
			} 
			FREEMPI(t4); 
		} 
		iterate++; 
	} 
	FREEMATI(temp1); 
/* 
	fclose(outfile); 
*/ 
	return (B1ptr); 
} 
 
MPMATI *BASIS_REDUCTION000(MPMATI *Bptr, USI m1, USI n1, MPI *N) 
/* 
 * Input: *Bptr, a matrix of MPI's, whose first row is not zero. 
 * Output: a pointer to an MPMATI whose rows form a reduced basis for  
 * the lattice spanned by the rows of *Bptr. This basis is reduced in the  
 * sense of the paper "Factoring polynomials with rational coefficients" by 
 * A. K. Lenstra, H. W. Lenstra and L. Lovasz, Math. Ann. 261, 515-534 (1982) 
 * using the modified version in "Solving exponential Diophantine equations 
 * using lattice basis reduction algorithms" by B. M. M. De Weger, J. No. Theory 
 * 26, 325-367 (1987). No change of basis matrix is returned. 
 * De Weger's algorithm has been changed to cater for arbitrary matrices. The 
 * the rows are now in general linearly dependent.  
 * We use the fact that the Gram Schmidt process detects the first row  
 * which is a linear combination of the preceding rows. We employ a modification 
 * of the LLL algorithm outlined by M. Pohst in J. Symbolic Computation (1987)4, 
 * 123-127.  We call this the MLLL algorithm. 
 * If we are using this algorithm to find small multipliers for the extended  
 * gcd problem, GCDFLAG is set in EXTGCD() and gcdflag is set below. 
 * m1 / n1 is usually taken to be 3 / 4. 
 */ 
{ 
	unsigned int i, k, l, n, m, t, flag = 0, Flag = 0, gcdflag = 0; 
	unsigned int flagg, beta, K1 = 0, tau = 2, sigma = 0, rho; 
	MPI **D, *X, *Y, *Z, *H, *Tmp, *R, *M1, *N1; 
	MPMATI *C, *L, *B1ptr; 
	unsigned int norig; 
 
	Z = NULL; 
	m = Bptr->C; 
	n = Bptr->R; 
	norig = n; 
	B1ptr = COPYMATI(Bptr); 
	D = (MPI **)mmalloc((1 + n) * sizeof(MPI *)); 
	D[0] = ONEI(); 
	for (i = 1; i <= n; i++) 
		D[i] = ZEROI(); 
	C = ZEROMNI(n, m); 
	L = ZEROMNI(n, n); 
 
	found: 
	n = B1ptr->R; 
	i = (K1 == 0) ? 1 : K1; 
	/* K1 = no. of consecutive rows of *B1ptr that don't need updating  
for the Gram Schmidt process. */ 
	while (i <= B1ptr->R) 
	{ 
		BASIS_UPDATE(i, m, &C, &L, B1ptr, D); 
		flag = 1; 
		for (t = 0; t < m; t++) 
		{ 
			if (!EQZEROI(C->V[i - 1][t])) 
			{ 
				flag = 0;	 
				break; 
			} 
		}	 
		if (flag) 
			break; 
		X = ZEROI(); 
		for (t = 0; t < m; t++) 
		{ 
			H = MULTI(C->V[i - 1][t], C->V[i - 1][t]); 
			Tmp = X; 
			X = ADDI(X, H); 
			FREEMPI(Tmp); 
			FREEMPI(H); 
		} 
		FREEMPI(D[i]); 
		D[i] = INT(X, D[i - 1]);	 
		FREEMPI(X); 
		i++; 
		if (MLLLVERBOSE) 
			printf("i = %u\n", i); 
	} 
	beta =  (flag) ? i : i - 1; 
	rho = K1 = i - 1; 
	if (MLLLVERBOSE) 
		printf("completed updating the basis\n"); 
/* Here K1 = no. of LI rows in *B1ptr found by Gram Schmidt process. 
   flag = 0 means all the rho = beta rows of *B1ptr are LI; 
   flag = 1 means that the first rho = beta - 1 rows of *B1ptr are LI, but the 
   beta-th row is a LC of the preceding rows. So beta = number of rows of *B1ptr 
   currently being examined by the LLL algorithm. */ 
	k = tau; 
	M1 = CHANGE(m1); 
	N1 = CHANGE(n1); 
	while (k <= beta) 
	{ 
		if (MLLLVERBOSE) 
			printf("beta - k = %u\n", beta -k); 
		l = k - 1; 
		Flag = STEP4000(k, l, &L, &B1ptr, D, N); 
		if (k >= norig && GCDFLAG) 
		{ 
			gcdflag = 1; 
			goto FOUND; 
		} 
		if (Flag)/* STEP 9 of POHST. */ 
		{ 
			sigma++; 
			if (MLLLVERBOSE) 
				printf("relation vector number %u found\n", sigma); 
			tau = k++; 
			goto found; 
		} 
		X = MULTI(D[k - 2], D[k]); 
		Y = MULTI(D[k - 1], D[k - 1]); 
		Tmp = Y; 
		Y = MULT_I(Y, m1); 
		FREEMPI(Tmp); 
		R = MULTI(L->V[k - 1][k - 2], L->V[k - 1][k - 2]); 
		Z = ADD0I(X, R); 
		Tmp = Z; 
		Z = MULT_I(Z, n1); 
		FREEMPI(Tmp); 
		if (RSV(Y, Z) == 1)/*& STEP 5 of POHST. */ 
		{ 
			flagg = 0; 
			if (EQZEROI(D[k]) && EQZEROI(R)) 
			{/* CASE B=0 of STEP 7 of POHST. */ 
				FREEMPI(D[k - 1]); 
				D[k - 1] = ZEROI(); 
				STEP8000(k, &B1ptr, &L, N); 
				if (k - 1 < K1) 
					K1 = k - 1; 
				/* The swap may have changed 2nd last row */ 
				/* of *B1ptr. */ 
				for (t = 0; t < m; t++) 
				{ 
					FREEMPI(C->V[k - 2][t]); 
					C->V[k - 2][t] = ZEROI(); 
				} 
				beta--; 
				flagg = 1; 
				if (k > 2) 
					k--; 
				FREEMPI(X); 
				FREEMPI(Y); 
				FREEMPI(R); 
				FREEMPI(Z); 
				continue; 
			} 
			if (flagg == 0) 
			{ 
				for (i = k + 1; i <= beta; i++) 
					STEP7(i, k, &L, D); 
			} 
			STEP8000(k, &B1ptr, &L, N); 
			if (k - 2 < K1) 
				K1 = k - 2; 
			/* swap will change last two rows of *B1ptr. */ 
			FREEMPI(R); 
			FREEMPI(Y); 
			Y = MULTI(L->V[k - 1][k - 2], L->V[k - 1][k - 2]); 
			Tmp = Y; 
			Y = ADD0I(Y, X); 
			FREEMPI(X); 
			FREEMPI(Tmp); 
			Tmp = D[k - 1]; 
			D[k - 1] = INT0(Y, D[k - 1]); 
			FREEMPI(Tmp); 
			FREEMPI(Y); 
			if (k > 2) 
				k--; 
		} 
		else 
		{ /* STEP 6 of POHST. */ 
			FREEMPI(R); 
			FREEMPI(X); 
			FREEMPI(Y); 
FOUND: 
			for (l = k - 2; l >= 1; l--) 
			{ 
				Flag = 	STEP4000(k, l, &L, &B1ptr, D, N); 
				if (Flag) 
				{ 
					FREEMPI(Z); 
					sigma++; 
					if (MLLLVERBOSE) 
						printf("relation vector number %u found\n", sigma); 
					tau = k++; 
					goto found; /* STEP 9 of POHST. */ 
				} 
			} 
			k++; 
		} 
		if (!gcdflag) 
			FREEMPI(Z); 
		else 
			break; 
	} 
	FREEMPI(M1); 
	FREEMPI(N1); 
	FREEMATI(C); 
	FREEMATI(L); 
	for (i = 0; i <= norig; i++) 
		FREEMPI(D[i]); 
	ffree((char *)D, (1 + norig) * sizeof(MPI *)); 
	if (MLLLVERBOSE) 
	{ 
		printf("number of basis vectors found = %u ;\n", rho); 
		printf("number of relation vectors found = %u .\n", sigma); 
	} 
	return (B1ptr); 
} 
 
unsigned int STEP4000(USI k, USI l, MPMATI **Lptr, MPMATI **Bptr, MPI *D[], MPI *N) 
/* 
 * updates *Lptr, *Bptr. 
 * returns 1 if row k of *Bptr becomes zero, returns zero otherwise. 
 */ 
{ 
	unsigned int i,  j, flag = 1, t, m, n; 
	MPI *X, *Y, *R, *Tmp, *Temp; 
	MPMATI *TmpMATI; 
 
	m = (*Bptr)->C; 
	Y = MULT_I((*Lptr)->V[k - 1][l - 1], 2); 
	if (RSV(Y, D[l]) == 1) 
	{ 
		R = NEAREST_INTI((*Lptr)->V[k - 1][l - 1], D[l]); 
		X = MINUSI(R); 
		TmpMATI = *Bptr; 
		*Bptr = ADD_MULT_ROWI(l - 1, k - 1, X, *Bptr); 
		FREEMATI(TmpMATI); 
	n = (*Bptr)->R; 
	for (i = 0; i < n; i++) 
	{ 
		for (j = n; j < m; j++) 
		{ 
			Temp = POWERI(N, m - j); 
			(*Bptr)->V[i][j] = INTI((*Bptr)->V[i][j], Temp); 
			FREEMPI(Temp); 
		} 
	} 
		if (HERMITEVERBOSE) 
		{ 
		printf("Row %u -> Row %u + ", k,k);PRINTI(X);printf(" x Row %u\n", l); 
		PRINTMATI(0,(*Bptr)->R-1,0,(*Bptr)->C-1,*Bptr); 
		GetReturn(); 
		} 
	for (i = 0; i < n; i++) 
	{ 
		for (j = n; j < m; j++) 
		{ 
			Temp = POWERI(N, m - j); 
			(*Bptr)->V[i][j] = MULTI((*Bptr)->V[i][j], Temp); 
			FREEMPI(Temp); 
		} 
	} 
/* 
		MAXI = UPDATEMAXI(MAXI, *Bptr); 
*/ 
		FREEMPI(X); 
		for (j = 1; j < l; j++) 
		{ 
			X = MULTI((*Lptr)->V[l - 1][j - 1], R); 
			Tmp = (*Lptr)->V[k - 1][j - 1]; 
			(*Lptr)->V[k - 1][j - 1] = SUBI((*Lptr)->V[k - 1][j - 1], X); 
			FREEMPI(Tmp); 
			FREEMPI(X); 
		} 
		X = MULTI(D[l], R); 
		Tmp = (*Lptr)->V[k - 1][l - 1]; 
		(*Lptr)->V[k - 1][l - 1] = SUBI((*Lptr)->V[k - 1][l - 1], X); 
 
		FREEMPI(Tmp); 
		FREEMPI(X); 
		FREEMPI(R); 
	} 
	for (t = 0; t < m; t++) 
	{ 
		if (!EQZEROI((*Bptr)->V[k - 1][t])) 
		{ 
			flag = 0;	 
			break; 
		} 
	}	 
	if (flag) 
	{ 
		TmpMATI = *Bptr; 
		*Bptr = DELETE_ROWI(k, *Bptr); 
		FREEMATI(TmpMATI); 
	} 
	FREEMPI(Y); 
	return (flag); 
} 
void STEP8000(USI k, MPMATI **B1ptr, MPMATI **Lptr, MPI *N) 
{ 
	MPI *T, *Temp; 
	USI i, j, n, m; 
 
	*B1ptr = SWAP_ROWSI1(k - 2, k - 1, *B1ptr); 
	T = COPYI((*Lptr)->V[k - 1][k - 2]); 
	*Lptr = SWAP_ROWSI1(k - 2, k - 1, *Lptr); 
	FREEMPI((*Lptr)->V[k - 1][k - 2]); 
	(*Lptr)->V[k - 1][k - 2] = T; 
	FREEMPI((*Lptr)->V[k - 2][k - 2]); 
	(*Lptr)->V[k - 2][k - 2] = ZEROI(); 
 
	n = (*B1ptr)->R; 
	m = (*B1ptr)->C; 
	for (i = 0; i < n; i++) 
	{ 
		for (j = n; j < m; j++) 
		{ 
			Temp = POWERI(N, m - j); 
			(*B1ptr)->V[i][j] = INTI((*B1ptr)->V[i][j], Temp); 
			FREEMPI(Temp); 
		} 
	} 
	if (HERMITEVERBOSE) 
	{ 
		printf("Swapping Rows %u and %u\n", k-1,k); 
		PRINTMATI(0,(*B1ptr)->R-1,0,(*B1ptr)->C-1,*B1ptr); 
		GetReturn(); 
	} 
	for (i = 0; i < n; i++) 
	{ 
		for (j = n; j < m; j++) 
		{ 
			Temp = POWERI(N, m - j); 
			(*B1ptr)->V[i][j] = MULTI((*B1ptr)->V[i][j], Temp); 
			FREEMPI(Temp); 
		} 
	} 
 
	return; 
}