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


/* nfunc.c */ 
#ifdef _WIN32 
#include "unistd_DOS.h" 
#else 
#include  
#endif 
#include  
#include  
#include  
#include "integer.h" 
#include "fun.h" 
 
extern unsigned long PRIME[]; 
unsigned int MLLLVERBOSE; 
unsigned int HERMITEVERBOSE; 
unsigned int HERMITE1VERBOSE; 
unsigned int GCDVERBOSE; 
unsigned int HAVASFLAG = 0; 
unsigned int FPRINTMATIFLAG = 0; 
unsigned int GCD_MAX = 100000; 
extern unsigned int GCDFLAG; 
 
MPI *EUCLIDI(MPI *Pptr, MPI *Qptr, MPI **Hptr, MPI **Kptr) 
/* 
 * gcd(Pptr, Qptr) = Hptr * Pptr + Kptr * Qptr. 
 */ 
{ 
	MPI *Q, *A, *B, *C, *H1, *H2, *K1, *K2, *L1, *L2, *Tmp1, *Tmp2; 
	int s; 
 
	if (Qptr->S == 0) 
	{ 
		s = Pptr->S; 
		if (Pptr->S != 0) 
		{ 
			if (s == 1) 
				*Hptr = ONEI(); 
			else 
				*Hptr = MINUS_ONEI(); 
			*Kptr = ZEROI(); 
			return (ABSI(Pptr)); 
		} 
		else 
		{ 
			*Hptr = ZEROI(); 
			*Kptr = ZEROI(); 
			return (ZEROI()); 
		} 
	} 
	A = COPYI(Pptr); 
	B = ABSI(Qptr); 
	C = MOD(A, B); 
	s = Qptr->S; 
	if (C->S == 0) 
	{ 
		if (s == 1) 
			*Kptr = ONEI(); 
		else 
			*Kptr = MINUS_ONEI(); 
		*Hptr = ZEROI(); 
		FREEMPI(A); 
		FREEMPI(C); 
		return (B); 
	} 
	L1 = ONEI(); 
	K1 = ZEROI(); 
	L2 = ZEROI(); 
	K2 = ONEI(); 
	while (C->S != 0) 
	{ 
		Q = INT(A, B); 
		FREEMPI(A); 
		A = B; 
		B = C; 
		C = MOD0(A, B); 
		Tmp1 = MULTI(Q, K1); 
		Tmp2 = MULTI(Q, K2); 
		FREEMPI(Q); 
		H1 = SUBI(L1, Tmp1); 
		H2 = SUBI(L2, Tmp2); 
		FREEMPI(Tmp1); 
		FREEMPI(Tmp2); 
		FREEMPI(L1); 
		L1 = K1; 
		FREEMPI(L2); 
		L2 = K2; 
		K1 = H1; 
		K2 = H2; 
	} 
	*Hptr = K1; 
	if (s == -1) 
		K2->S = -(K2->S);		 
	*Kptr = K2; 
	FREEMPI(L1); 
	FREEMPI(L2); 
	FREEMPI(A); 
	FREEMPI(C); 
	return (B); 
} 
 
void SERRET(MPI *P, MPI **Xptr, MPI **Yptr) 
/* 
 * This program finds positive integers X, Y such that "X*X+Y*Y=P, where P is a 
 * prime, p=4n+1. The algorithm goes back to Serret and is from the book  
 * "Computational methods in number theory, part 1," edited by H.W.Lenstra and 
 * R.Tijdeman. 
 */ 
{ 
	int i, j; 
	MPI *Q, *N, *Z, *U, *V, *W, *Tmp; 
 
	j = 0; 
	Q = SUB0_I(P, (USL)1); 
	Z = BIG_MTHROOT(Q, 2); 
	W = MULTI(Z, Z); 
	if (EQUALI(W, Q)) 
	{ 
		PRINTI(P); printf(" = "); PRINTI(Z); printf("\n"); 
		*Xptr = Z; 
		*Yptr = ONEI(); 
		FREEMPI(Q); FREEMPI(W); 
		return; 
	} 
	N = INT_(Q, (USL)4); 
	FREEMPI(W); FREEMPI(Q); 
	for (i = 0; i <= Y0 - 1; i++) 
	{ 
		printf("PRIME[%d] = %lu\n", i, PRIME[i]); 
		U = MPOWER_((long)PRIME[i], N, P); 
		V = MULTI(U, U); 
		Tmp = V; V = MOD0(V, P); FREEMPI(Tmp); 
		Tmp = V; V = ADD0_I(V, (USL)1); FREEMPI(Tmp); 
		if (EQUALI(V, P)) 
		{ 
			j = 1; 
			printf("U = "); PRINTI(U); printf("\n"); 
			/* U is a square-root of -1 mod P */ 
			FREEMPI(V); FREEMPI(N); 
			break; 
		} 
		FREEMPI(U); FREEMPI(V); 
	} 
	if (j == 1) 
	{ 
		CONT_FRAC(P, U, Z, Xptr, Yptr); 
		printf("P = X^2 + Y^2, where\n"); 
		printf("P = "); PRINTI(P); printf("\n"); 
		printf("X = "); PRINTI(*Xptr); printf("\n"); 
		printf("Y = "); PRINTI(*Yptr); printf("\n"); 
		FREEMPI(U); FREEMPI(Z); 
		return; 
	} 
	printf("I don't think that "); PRINTI(P); 
	printf(" is a prime of the form 4n+1!\n"); 
} 
 
void PELL(MPI *Dptr, MPI *Eptr) 
/* 
 * This program finds the period of the regular continued 
 * fraction expansion of square-root d, as well as the least 
 * solution x,y of the Pellian equation x*x-d*y*y=+-1. 
 * The algorithm is from Sierpinski's 'Theory of Numbers', p.296. 
 * and Davenport's 'The Higher Arithmetic', p.109. 
 * Here sqrt(d)=a[0]+1/a[1]+...+1/a[n-1]+1/2*a[0]+1/... , 
 * The length n of the period a[1],...,a[n-1],2*a[0] is printed. 
 * The partial quotients are printed iff *Eptr != 0. 
 */ 
{ 
	MPI *B, *C, *Y, *Z, *A0, *A1, *L, *K, *M, *N, *H, *P, *Tmp; 
	unsigned int i, l, m; 
	int j; 
 
	Y = BIG_MTHROOT(Dptr, 2); 
	A0 = COPYI(Y); 
	B = COPYI(Y); 
	Z = MULTI(Y, Y); 
	if (EQUALI(Dptr, Z)) 
	{ 
		printf("You have inputted a perfect square\n"); 
		printf("The program is aborted\n"); 
		return; 
	} 
	C = SUB0I(Dptr, Z); 
	A1 = COPYI(C); 
	if (Eptr->S) 
	{ 
		printf("\nA[0] = "); PRINTI(Y); printf("\n"); 
	} 
	L = ONEI(); K = COPYI(A0); M = ZEROI(); N = ONEI(); 
	for (i = 1; 1; i++) 
	{ 
		FREEMPI(Z); Z = ADD0I(B, A0);  
		FREEMPI(Y); Y = INT0(Z, C); 
		if (Eptr->S) 
		{ 
			printf("A[%u] = ", i); PRINTI(Y); printf("\n"); 
		} 
		FREEMPI(Z); Z = MULTI(Y, C); 
		Tmp = B; B = SUB0I(Z, B); FREEMPI(Tmp); 
		FREEMPI(Z); Z = MULTI(B, B); 
		Tmp = Z; Z = SUB0I(Dptr, Z); FREEMPI(Tmp); 
		Tmp = C; C = INT0(Z, C); FREEMPI(Tmp); 
		FREEMPI(Z); Z = MULTI(K, Y); 
		H = ADDI(Z, L); 
		FREEMPI(Z); Z = MULTI(N, Y); 
		P = ADDI(Z, M); FREEMPI(M); 
		FREEMPI(L); L = K; 
		M = N; K = H; N = P; 
		if (EQUALI(B, A0)) 
		{ 
			if (EQUALI(C, A1)) 
			{ 
				printf("The continued fraction for sqrt("); 
				PRINTI(Dptr); 
				printf(") has period length equal to %u.\n", i); 
				printf("Also the least solution (x, y) of x*x - "); 
				PRINTI(Dptr); 
				j = i % 2 ? -1 : 1; 
				printf("y*y = %d\n",  j); 
				l = LENGTHI(L); m = LENGTHI(M); 
				printf(" x has %u digits;\n", l); 
				printf(" y has  %u digits;\n", m); 
				if (l>500) 
					return; 
				if (m>500) 
					return; 
				printf(" and \n"); 
				printf("x = "); PRINTI(L); printf("\n"); 
				printf("y = "); PRINTI(M); printf("\n"); 
				FREEMPI(Z); FREEMPI(L); FREEMPI(M); FREEMPI(K); 
				FREEMPI(N); FREEMPI(A0); FREEMPI(A1); 
				FREEMPI(B); FREEMPI(C); FREEMPI(Y); 
				return; 
			} 
		} 
		 
	} 
} 
 
MPI *CONGR(MPI *A, MPI *B, MPI *M, MPI **N) 
/* 
 * Returns the least solution (mod N) of the congruence AX=B(mod M), where 
 * N = M / gcd(A, M), otherwise returns the null pointer. 
 */ 
{ 
	MPI *D, *E, *U, *V, *X, *tmp1, *tmp2; 
	int t; 
 
	D = EUCLIDI(A, M, &U, &V); 
	FREEMPI(V); 
	*N = INT(M, D); 
	E = MOD(B, D); 
	t = E->S; 
	FREEMPI(E); 
	if (t) 
	{ 
		FREEMPI(U); 
		FREEMPI(D); 
		return ((MPI *)NULL); 
	} 
	tmp1 = MULTI(U, B); 
	FREEMPI(U); 
	tmp2 = INT(tmp1, D); 
	X = MOD(tmp2, *N); 
	FREEMPI(tmp1); 
	FREEMPI(tmp2); 
	FREEMPI(D); 
	return (X); 
} 
 
MPI *CHINESE(MPI *A, MPI *B, MPI *M, MPI *N, MPI **Mptr) 
/* 
 * Returns the solution mod *Mptr=lcm[M,N] of the congruences X = A (mod M) 
 * and X = B (mod N), if soluble; otherwise returns NULL. 
 */ 
{ 
	MPI * D, *E, *F, *R, *S, *T, *U, *V; 
	int t; 
 
	D = EUCLIDI(M, N, &U, &V); 
	S = SUBI(A, B); 
	R = MOD(S, D); 
	t = R->S; 
	FREEMPI(S); 
	FREEMPI(R); 
	*Mptr = LCM(M, N); 
	if (t) 
	{ 
		FREEMPI(D); 
		FREEMPI(U); 
		FREEMPI(V); 
		return ((MPI *)NULL); 
	} 
	S = MULTI3(B, U, M); 
	R = MULTI3(A, V, N); 
	FREEMPI(U); 
	FREEMPI(V); 
	T = ADDI(S, R); 
	FREEMPI(S); 
	FREEMPI(R); 
	E = INT(T, D); 
	FREEMPI(D); 
	FREEMPI(T); 
	F = MOD(E, *Mptr); 
	FREEMPI(E); 
	return (F); 
} 
 
MPI *CHINESE_ARRAY(MPI *A[], MPI *M[], MPI **Mptr, USI n) 
/* 
 * Returns the solution mod *Mptr=lcm[M[0],...,M[n-1] of the congruences 
 * X = A[i] (mod M[i]),0<=iS; 
			FREEMPI(D); 
			FREEMPI(S); 
			FREEMPI(T); 
			if (t) 
			{ 
				*Mptr = ZEROI(); 
				return ((MPI *)NULL); 
			} 
		} 
	MM = COPYI(M[0]); 
	Z = COPYI(A[0]); 
	for (i = 1; i < n; i++) 
	{ 
		tmpMM = MM; 
		tmpZ = Z; 
		Z = CHINESE(A[i], Z, M[i], MM, &tmp); 
		MM = tmp; 
		FREEMPI(tmpMM); 
		FREEMPI(tmpZ); 
	} 
	*Mptr = MM; 
	return (Z); 
} 
 
MPI *COLLATZT(MPI *Dptr) 
{ 
	MPI *Eptr, *one, *Tmp; 
 
	if (Dptr->V[0] & 1) 
	{ 
		one = ONEI(); 
		Eptr = MULT_I(Dptr, 3L); 
		Tmp = Eptr; 
		Eptr = ADDI(Tmp, one); 
		FREEMPI(Tmp); 
		Tmp = Eptr; 
		Eptr = INT_(Tmp, (USL)2); 
		FREEMPI(Tmp); 
		FREEMPI(one); 
	} 
	else 
		Eptr = INT_(Dptr, (USL)2); 
	return (Eptr); 
} 
 
void COLLATZ(MPI *Dptr, MPI *Eptr) 
/* The iterates are printed iff *Eptr != 0. */ 
{ 
	unsigned int i; 
	MPI *X, *Y, *Z, *Temp; 
 
	Y = BUILDMPI(1); 
	Y->S = -1; 
	Y->V[0] = 5; 
	Z = BUILDMPI(1); 
	Z->S = -1; 
	Z->V[0] = 17; 
 
	X = COPYI(Dptr); 
	if(EQZEROI(X)) 
	{ 
		printf("starting number = ");PRINTI(Dptr);printf("\n"); 
		printf("the number of iterations taken to reach 0 is %u\n", 0); 
		FREEMPI(X); 
		FREEMPI(Y); 
		FREEMPI(Z); 
		return; 
	} 
	for(i = 0; 1 ; i++) 
	{ 
		if(EQONEI(X)) 
		{ 
			printf("starting number = ");PRINTI(Dptr);printf("\n"); 
			printf("the number of iterations taken to reach 1 is %u\n", i); 
			break; 
		} 
		if(EQMINUSONEI(X)) 
		{ 
			printf("starting number = ");PRINTI(Dptr);printf("\n"); 
			printf("the number of iterations taken to reach -1 is %u\n", i); 
			break; 
		} 
		if(EQUALI(X, Y)) 
		{ 
			printf("starting number = ");PRINTI(Dptr);printf("\n"); 
			printf("the number of iterations taken to reach -5 is %u\n", i); 
			break; 
		} 
		if(EQUALI(X, Z)) 
		{ 
			printf("starting number = ");PRINTI(Dptr);printf("\n"); 
			printf("the number of iterations taken to reach -17 is %u\n", i); 
			break; 
		} 
		Temp = X; 
		X = COLLATZT(Temp); 
		FREEMPI(Temp); 
		if (Eptr->S) 
		{ 
			PRINTI(X);printf("\n"); 
		} 
	} 
	FREEMPI(X); 
	FREEMPI(Y); 
	FREEMPI(Z); 
	return; 
} 
 
MPI  *FUND_UNIT(MPI *D, MPI **Xptr, MPI **Yptr) 
/* 
 * This is a program for finding the fundamental unit of Q(sqrt(D)). 
 * The algorithm is based on K. Rosen, Elementary number theory 
 * and its applications, p382, B.A. Venkov, Elementary Number theory, p.62  
 * and D. Knuth, Art of computer programming, Vol.2, p359, with Pohst's trick  
 * of using half the period. 
 * w=(1+sqrt(D))/2 if D=1 (mod 4), w=sqrt(D) otherwise. 
 * The norm of the fundamental unit (*Xptr) + (*Yptr)*w is returned. 
 */ 
{ 
	unsigned int i; 
	MPI *X, *B, *C, *H, *T, *G, *Y, *F, *E, *L, *M, *N, *U, *V, *tmp; 
	MPI *tmp1, *tmp2, *K, *R, *S; 
	unsigned int s, t; 
	 
	if ((D->D == 0) && (D->V[0]) == 5) 
	{ 
		*Xptr = ZEROI(); 
		*Yptr = ONEI(); 
		return (MINUS_ONEI()); 
	} 
	X = BIG_MTHROOT(D, 2); 
	B = COPYI(X); 
	C = ONEI(); 
	tmp = SUB0_I(X, (USL)1); H = INT0_(tmp, (USL)2); FREEMPI(tmp); 
	tmp = MULT_I(H, 2L); T = ADD0_I(tmp, (USL)1); FREEMPI(tmp); 
	s = (D->V[0]) % 4; 
	if (s == 1) 
	{ 
		FREEMPI(B); B = COPYI(T); 
		tmp = C; C = ADD0_I(C, (USL)1); FREEMPI(tmp); /* C = 2 */ 
	} 
	G = MULTI(X, X); tmp = ADD0_I(G, (USL)1); FREEMPI(G); 
	t = EQUALI(D, tmp); FREEMPI(tmp); 
	if (t) /* period 1, exceptional case */ 
	{ 
		if (s == 1) 
		{ 
			*Xptr = SUB0_I(X, (USL)1); 
			*Yptr = TWOI(); 
			FREEMPI(X); 
		} 
		else 
		{ 
			*Xptr = X; 
			*Yptr = ONEI(); 
		} 
		FREEMPI(B); FREEMPI(C); FREEMPI(T); FREEMPI(H); 
		return (MINUS_ONEI()); 
	} 
	tmp = MULTI(T, T); tmp1 = ADD0_I(tmp, (USL)4); FREEMPI(tmp); 
	t = EQUALI(D, tmp1); FREEMPI(tmp1); 
	if (t) /* period 1, exceptional case */ 
	{ 
		*Xptr = H; 
		*Yptr = ONEI(); 
		FREEMPI(B); FREEMPI(C); FREEMPI(T); FREEMPI(X); 
		return (MINUS_ONEI()); 
	} 
	FREEMPI(T); 
	L = ZEROI(); K = ONEI(); M = ONEI(); N = ZEROI(); 
	for (i = 0; 1; i++) 
	{ 
		tmp = ADDI(X, B); Y = INT(tmp, C); FREEMPI(tmp); 
		F = COPYI(B); 
		tmp = B; tmp1 = MULTI(Y, C); B = SUBI(tmp1, B);  
		FREEMPI(tmp); FREEMPI(tmp1); 
		E = COPYI(C); tmp = C; 
		tmp1 = MULTI(B, B); tmp2 = SUBI(D, tmp1); C = INT(tmp2, C); 
		FREEMPI(tmp); FREEMPI(tmp1); FREEMPI(tmp2); 
		if (i == 0) 
		{ 
			FREEMPI(Y); 
			if ((D->V[0]) % 4 == 1) 
				Y = COPYI(H); 
			else 
				Y = COPYI(X); 
			FREEMPI(H); 
		} 
		R = L; S = M; 
		tmp = MULTI(K, Y); U = ADDI(tmp, L); FREEMPI(tmp); 
		tmp = MULTI(N, Y); V = ADDI(tmp, M); FREEMPI(tmp); 
		FREEMPI(Y); 
		L = K; K = U; 
		M = N; N = V; 
/* U/V is the ith convergent to sqrt(D) or (sqrt(D)-1)/2 */ 
		if (i) 
		{ 
			if (EQUALI(B, F)) 
			/*\alpha_H=\alpha_{H+1}, even period 2H */ 
			{ 
				tmp = ADDI(U, R); tmp1 = MULTI(M, tmp); 
				FREEMPI(tmp); 
				if (i % 2 == 0) 
					*Xptr = ADD0_I(tmp1, (USL)1); 
				else 
					*Xptr = SUB0_I(tmp1, (USL)1); 
				FREEMPI(tmp1);  
				tmp = ADDI(V, S); *Yptr = MULTI(M, tmp); 
				FREEMPI(tmp); 
				FREEMPI(X); 
				FREEMPI(L); FREEMPI(M); 
				FREEMPI(U); FREEMPI(V); 
				FREEMPI(R); FREEMPI(S); 
				FREEMPI(C); FREEMPI(B); 
				FREEMPI(E); FREEMPI(F); 
				return (ONEI()); 
			} 
			if (EQUALI(C, E))  
			/*\beta_H=\beta_{H-1}, odd period 2H-1 */ 
			{ 
				tmp = MULTI(U, V); tmp1 = MULTI(L, M); 
				*Xptr = ADDI(tmp, tmp1); 
				FREEMPI(tmp); FREEMPI(tmp1); 
				tmp = MULTI(V, V); tmp1 = MULTI(M, M); 
				*Yptr = ADD0I(tmp, tmp1); 
				FREEMPI(tmp); FREEMPI(tmp1); 
				FREEMPI(X); 
				FREEMPI(L); FREEMPI(M); 
				FREEMPI(U); FREEMPI(V); 
				FREEMPI(R); FREEMPI(S); 
				FREEMPI(C); FREEMPI(B); 
				FREEMPI(E); FREEMPI(F); 
				return (MINUS_ONEI()); 
			} 
		} 
		FREEMPI(R); FREEMPI(S); FREEMPI(E); FREEMPI(F); 
	}  
} 
 
MPI  *PEL(MPI *D, MPI *Eptr, MPI **Xptr, MPI **Yptr) 
/* 
 * This is a program for finding the least solution of Pell's equation 
 * x*x - D*y*y = +-1. 
 * The algorithm is based on K. Rosen, Elementary number theory 
 * and its applications, p382, B.A. Venkov, Elementary Number theory, p.62  
 * and D. Knuth, Art of computer programming, Vol.2, p359, with Pohst's trick  
 * of using half the period. 
 * The norm of the least solution is returned. 
 * The partial quotients are printed iff *E != 0. 
 */ 
{ 
	unsigned int i; 
	MPI *X, *B, *C, *G, *Y, *F, *E, *L, *M, *N, *U, *V, *tmp; 
	MPI *tmp1, *tmp2, *K, *R, *S; 
	unsigned int t; 
	FILE *outfile; 
	char buff[20]; 
 
	X = BIG_MTHROOT(D, 2); 
	strcpy(buff, "pell.out"); 
	outfile = fopen(buff, "w"); 
	if (Eptr->S) 
	{ 
	printf("A[0] = "); PRINTI(X); printf("\n"); 
	fprintf(outfile, "A[0] = "); FPRINTI(outfile, X); fprintf(outfile,"\n"); 
	} 
	B = COPYI(X); 
	C = ONEI(); 
	G = MULTI(X, X); tmp = ADD0_I(G, (USL)1); FREEMPI(G); 
	t = EQUALI(D, tmp); FREEMPI(tmp); 
	if (t) /* period 1, exceptional case */ 
	{ 
		*Xptr = X; 
		*Yptr = ONEI(); 
		printf("period length 1\n"); 
		fprintf(outfile, "period length 1\n"); 
		fclose(outfile); 
		FREEMPI(B); FREEMPI(C); 
		return (MINUS_ONEI()); 
	} 
	L = ZEROI(); K = ONEI(); M = ONEI(); N = ZEROI(); 
	for (i = 0; 1; i++) 
	{ 
		tmp = ADDI(X, B); Y = INT(tmp, C); FREEMPI(tmp); 
		if (i && Eptr->S) 
		{ 
			printf("A[%u] = ", i); PRINTI(Y); printf("\n"); 
			fprintf(outfile, "A[%u] = ", i); FPRINTI(outfile, Y); fprintf(outfile,"\n"); 
		} 
		F = COPYI(B); 
		tmp = B; tmp1 = MULTI(Y, C); B = SUBI(tmp1, B);  
		FREEMPI(tmp); FREEMPI(tmp1); 
		E = COPYI(C); tmp = C; 
		tmp1 = MULTI(B, B); tmp2 = SUBI(D, tmp1); C = INT(tmp2, C); 
		FREEMPI(tmp); FREEMPI(tmp1); FREEMPI(tmp2); 
		if (i == 0) 
		{ 
			FREEMPI(Y); Y = COPYI(X); 
		} 
		R = L; S = M; 
		tmp = MULTI(K, Y); U = ADDI(tmp, L); FREEMPI(tmp); 
		tmp = MULTI(N, Y); V = ADDI(tmp, M); FREEMPI(tmp); 
		FREEMPI(Y); 
		L = K; K = U; 
		M = N; N = V; 
/* U/V is the ith convergent to sqrt(D) */ 
		if (i) 
		{ 
			if (EQUALI(B, F)) 
			/*\alpha_H=\alpha_{H+1}, even period 2H */ 
			{ 
				tmp = ADDI(U, R); tmp1 = MULTI(M, tmp); 
				FREEMPI(tmp); 
				if (i % 2 == 0) 
					*Xptr = ADD0_I(tmp1, (USL)1); 
				else 
					*Xptr = SUB0_I(tmp1, (USL)1); 
				FREEMPI(tmp1);  
				tmp = ADDI(V, S); *Yptr = MULTI(M, tmp); 
				FREEMPI(tmp); 
				FREEMPI(X); 
				FREEMPI(L); FREEMPI(M); 
				FREEMPI(U); FREEMPI(V); 
				FREEMPI(R); FREEMPI(S); 
				FREEMPI(C); FREEMPI(B); 
				FREEMPI(E); FREEMPI(F); 
				printf("even period length %u\n", 2*i); 
				fprintf(outfile, "even period length %u\n", 2*i); 
				fclose(outfile); 
				return (ONEI()); 
			} 
			if (EQUALI(C, E))  
			/*\beta_H=\beta_{H-1}, odd period 2H-1 */ 
			{ 
				tmp = MULTI(U, V); tmp1 = MULTI(L, M); 
				*Xptr = ADDI(tmp, tmp1); 
				FREEMPI(tmp); FREEMPI(tmp1); 
				tmp = MULTI(V, V); tmp1 = MULTI(M, M); 
				*Yptr = ADD0I(tmp, tmp1); 
				FREEMPI(tmp); FREEMPI(tmp1); 
				FREEMPI(X); 
				FREEMPI(L); FREEMPI(M); 
				FREEMPI(U); FREEMPI(V); 
				FREEMPI(R); FREEMPI(S); 
				FREEMPI(C); FREEMPI(B); 
				FREEMPI(E); FREEMPI(F); 
				printf("odd period length %u\n", 2*i+1); 
				fprintf(outfile, "odd period length %u\n", 2*i+1); 
				fclose(outfile); 
				return (MINUS_ONEI()); 
			} 
		} 
		FREEMPI(R); FREEMPI(S); FREEMPI(E); FREEMPI(F); 
	}  
} 
 
MPIA A_SURD; /* used in REDUCED() */ 
MPIA U_SURD; /* used in REDUCED() */ 
MPIA V_SURD; /* used in REDUCED() */ 
unsigned int REDUCED(MPI *D, MPI *U, MPI *V, USI i) 
/* 
 * This is a function for finding the period of the continued fraction 
 * expansion of reduced quadratic irrational a=(U+sqrt(D))/V. 
 * Here D is non-square, 1<(U+sqrt(D))/V, -1<(U-sqrt(D))/V<0. 
 * The algorithm also assumes that V divides d-U*U and is based on K. Rosen, 
 * Elementary Number theory and its applications, p.379-381 and Knuth's The art 
 * of computer programming, Vol. 2, p. 359. The period length is returned if 
 * a is reduced. 
 * variable i is created by SURD(D,T,U,V,P_ARRAY,Q_ARRAY) below and indexes  
 * the ith convergent of (U+T*sqrt(D))/V.  
*/ 
{ 
	MPI *A, *F, *R, *S, *tmp, *tmp1, *tmp2; 
	unsigned int j; 
	FILE *outfile; 
	char buff[20]; 
 
	F = BIG_MTHROOT(D, 2); 
	R = COPYI(U); S = COPYI(V); 
	strcpy(buff, "surd.out"); 
	outfile = fopen(buff, "a"); 
	for(j = i; 1; j++) 
	{ 
		tmp = ADD0I(F, R); A = INT0(tmp, S); FREEMPI(tmp); 
		ADD_TO_MPIA(A_SURD, A, j); 
		fprintf(outfile,", A[%u]=", j); FPRINTI(outfile, A); 
		fprintf(outfile,", PERIOD\n"); 
		tmp = MULTI(A, S); tmp1 = R; R = SUB0I(tmp, R); 
		 FREEMPI(tmp); FREEMPI(tmp1); 
		tmp = S; tmp1 = MULTI(R, R); 
		tmp2 = SUB0I(D, tmp1); S = INT0(tmp2, S); 
		ADD_TO_MPIA(U_SURD, R, j + 1); 
		fprintf(outfile,"P[%u]=", j + 1); 
		FPRINTI(outfile, R); 
		ADD_TO_MPIA(V_SURD, S, j + 1); 
		fprintf(outfile,", Q[%u]=", j + 1); 
		FPRINTI(outfile, S); 
		FREEMPI(tmp); FREEMPI(tmp1); FREEMPI(tmp2); 
		FREEMPI(A); 
		if (EQUALI(U, R) && EQUALI(V, S)) 
		{ 
			fprintf(outfile,"\n"); 
			FREEMPI(R); FREEMPI(S); FREEMPI(F); 
			fclose(outfile); 
			return (j + 1 - i); 
		} 
		if(j == R0){ 
			FREEMPI(R); FREEMPI(S); FREEMPI(F); 
			execerror("j = R0", ""); 
		} 
	} 
} 
 
unsigned int SURD(MPI *D, MPI *T, MPI *U, MPI *V, MPIA *AA_SURD, MPIA *UU_SURD, MPIA *VV_SURD, MPIA *P_SURD, MPIA *Q_SURD, USI surd_flag) 
/* 
 * This function uses the continued fraction algorithm expansion in K. Rosen, 
 * Elementary Number theory and its applications,p.379-381 and Knuth's 
 * The art of computer programming, Vol.2, p. 359. It locates the first complete 
 * quotient that is reduced and then uses the function REDUCED(D,U,V,i) above 
 * to locate and return the period of the continued fraction expansion 
 * of (U+T*sqrt(D))/V.  
 * AA_SURD is the sequence of partial quotients up to the end of the period; 
 * UU_SURD and VV_SDURD are the sequences of U[i] and V[i], where the i-th 
 * complete quotient is (U[i]+sqrt(D))/V[i]; 
 * P_SURD/Q_SURD give the convergents. 
 * Output is sent to surd.out. 
 * Regarding surd_flag (added 29th May 2000). This is needed in PATZ. 
 * If surd_flag = 1 and the period length is odd, we do an extra period. 
 */ 
{ 
	MPI *A, *DD, *F, *W, *tmp, *tmp1, *tmp2, *UU, *VV, *X; 
	unsigned int i, j, l; 
	int z, t; 
	FILE *outfile; 
	char buff[20]; 
 
	A_SURD = BUILDMPIA(); 
	U_SURD = BUILDMPIA(); 
	V_SURD = BUILDMPIA(); 
	F = BIG_MTHROOT(D, 2); 
	UU = COPYI(U); VV = COPYI(V); 
	z = T->S; 
	UU->S = (U->S) * z; 
	VV->S = (V->S) * z; 
	DD = MULTI3(D, T, T); 
	W = ABSI(VV); 
	tmp1 = MULTI(UU, UU); tmp2 = SUBI(DD, tmp1); FREEMPI(tmp1); 
	tmp1 = MOD(tmp2, W); FREEMPI(tmp2); 
	if (tmp1->S) 
	{ 
		tmp2 = DD; DD = MULTI3(DD, VV, VV); FREEMPI(tmp2); 
		tmp2 = UU; UU = MULTI(UU, W); FREEMPI(tmp2); 
		tmp2 = VV; VV = MULTI(VV, W); FREEMPI(tmp2); 
	} 
	FREEMPI(W); 
	FREEMPI(tmp1); 
	FREEMPI(F);  
	F = BIG_MTHROOT(DD, 2); 
	strcpy(buff, "surd.out"); 
	outfile = fopen(buff, "w"); 
	if (V->S == -1) 
		fprintf(outfile, "-"); 
	if (!EQONEI(V)) 
		fprintf(outfile, "("); 
	if(U->S) 
		FPRINTI(outfile, U);  
	if(T->S >0 && U->S) 
		fprintf(outfile," + "); 
	if(!EQONEI(T) && !EQMINUSONEI(T)) 
	{ 
		FPRINTI(outfile, T);  
		fprintf(outfile,"*"); 
	} 
	if (EQMINUSONEI(T)) 
        	fprintf(outfile,"-"); 
        fprintf(outfile,"sqrt("); 
	FPRINTI(outfile, D); fprintf(outfile,")"); 
	if(!EQONEI(V)) 
		fprintf(outfile,")"); 
	if (!EQONEI(V) && !EQMINUSONEI(V)) 
	{ 
		fprintf(outfile,"/"); 
		X = ABSI(V); 
		FPRINTI(outfile, X);  
		FREEMPI(X); 
	} 
	fprintf(outfile,":\n"); 
	for (j = 0; 1; j++) 
	{ 
		if(j == R0){ 
			FREEMPIA(A_SURD); 
			FREEMPIA(U_SURD); 
			FREEMPIA(V_SURD); 
			FREEMPI(DD); 
			FREEMPI(F); 
			FREEMPI(UU); 
			FREEMPI(VV); 
			fclose(outfile); 
			execerror("j = R0", ""); 
		} 
		ADD_TO_MPIA(U_SURD, UU, j); 
		fprintf(outfile,"P[%u]=", j); 
		FPRINTI(outfile, UU); 
		ADD_TO_MPIA(V_SURD, VV, j); 
		fprintf(outfile,", Q[%u]=", j); 
		FPRINTI(outfile, VV); 
		if (VV->S > 0 && UU->S > 0 && (RSV(UU, F) <= 0)) 
		{ 
			tmp1 = ADD0I(UU, VV); 
			z = RSV(tmp1, F); 
			FREEMPI(tmp1); 
			tmp1 = SUBI(VV, UU); 
			t = RSV(tmp1, F); 
			FREEMPI(tmp1); 
			if (z == 1 && t <= 0)/* (U+sqrt(D))/V is reduced */ 
			{ 
				fclose(outfile); 
				l = REDUCED(DD, UU, VV, j); 
				if(surd_flag && l % 2) 
					l = REDUCED(DD, UU, VV, j + l); 
				outfile = fopen(buff, "a"); 
				fprintf(outfile,"period length =  %u\n", l); 
				CONVERGENTS(A_SURD, P_SURD, Q_SURD); 
				FREEMPI(DD); 
				FREEMPI(F); 
				FREEMPI(UU); 
				FREEMPI(VV); 
				fprintf(outfile,"convergents:\n"); 
				for(i = 0; i < A_SURD->size; i++) 
				{ 
					fprintf(outfile,"A[%u]/B[%u]=", i, i); 
					FPRINTI(outfile, (*(P_SURD))->A[i]); 
					fprintf(outfile,"/"); 
					FPRINTI(outfile, (*(Q_SURD))->A[i]); 
					fprintf(outfile,"\n"); 
				} 
/* Actually U_SURD and V_SURD are one unit longer than A_SURD */ 
				 
				*(AA_SURD) = BUILDMPIA(); 
				for(i = 0; i < A_SURD->size; i++) 
					ADD_TO_MPIA(*(AA_SURD), A_SURD->A[i], i); 
				*(UU_SURD) = BUILDMPIA(); 
				*(VV_SURD) = BUILDMPIA(); 
				for(i = 0; i < A_SURD->size; i++) 
				{ 
					ADD_TO_MPIA(*(UU_SURD), U_SURD->A[i], i); 
					ADD_TO_MPIA(*(VV_SURD), V_SURD->A[i], i); 
				} 
				FREEMPIA(A_SURD); 
				FREEMPIA(U_SURD); 
				FREEMPIA(V_SURD); 
				fclose(outfile); 
				return (l); /* l is the period length */ 
			} 
		} 
		tmp1 = ADDI(F, UU); 
		if (VV->S > 0) 
			 A = INT(tmp1, VV); 
		else /* See Knuth p. 359 */ 
		{ 
			tmp = ONEI(); 
			tmp2 = ADDI(tmp1, tmp); A = INTI(tmp2, VV); 
			FREEMPI(tmp); FREEMPI(tmp2); 
		} 
		FREEMPI(tmp1);  
		fprintf(outfile,", A[%u]=", j); 
		FPRINTI(outfile, A); 
		fprintf(outfile,"\n"); 
		ADD_TO_MPIA(A_SURD, A, j); 
		tmp2 = MULTI(A, VV); tmp1 = UU; UU = SUBI(tmp2, UU); 
	 	FREEMPI(A); FREEMPI(tmp2); FREEMPI(tmp1); 
		tmp1 = MULTI(UU, UU); tmp2 = SUBI(DD, tmp1); FREEMPI(tmp1); 
		tmp1 = VV; VV = INTI(tmp2, VV); FREEMPI(tmp1); FREEMPI(tmp2); 
	} 
} 
  
MPI * JUGGLERT(MPI *Dptr) 
{ 
	MPI *N, *M; 
	unsigned long int t; 
 
	t = MOD0_(Dptr, 3); 
	printf("res class mod %lu\n", t); 
	if (t == 0) 
		N = COPYI(Dptr); 
	else if (t == 1) 
		N = POWERI(Dptr, 2); 
	else 
		N = POWERI(Dptr, 13); 
	M = BIG_MTHROOT(N, 3); 
	FREEMPI(N); 
	return (M); 
} 
 
void JUGGLER(MPI *Dptr, MPI *Iptr) 
{ 
	unsigned long i, k; 
	MPI *X, *Y, *Temp; 
 
	Y = BUILDMPI(1); 
	Y->S = 1; 
	Y->V[0] = 2; 
	k = CONVERTI(Iptr); 
	X = COPYI(Dptr); 
	for(i = 0; i <= k; i++) 
	{ 
		printf("i = %lu: size = %u\n", i, X->D); 
		if (EQUALI(X, Y)) 
		{ 
		  printf("starting number = ");PRINTI(Dptr);printf("\n"); 
		  printf("the number of iterations taken to reach 2 is %lu\n", i); 
			break; 
		} 
		else if (EQONEI(X)) 
		{ 
		  printf("starting number = ");PRINTI(Dptr);printf("\n"); 
		  printf("the number of iterations taken to reach 1 is %lu\n", i); 
			break; 
		} 
		Temp = X; 
		/*printf("i = %lu, LENGTHI(X[%lu])=%lu\n", i, i, LENGTHI(X));*/ 
		X = JUGGLERT(Temp); 
		FREEMPI(Temp); 
	/*	PRINTI(X);printf("\n"); */ 
	} 
	FREEMPI(X); 
	FREEMPI(Y); 
	return; 
} 
 
void HERMITE() 
{ 
	USI *alpha, nz, answer; 
	MPMATI *MATI1, *MATI2, *MATI3, *MATI4; 
	FILE *outfile; 
	char buff[20]; 
 
	printf("Do you wish to use an existing matrix from a file? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
	{ 
		MATI1 = FINPUTMATFILEI_I(); 
		if (MATI1 == NULL) 
			exit (0); 
	} 
	else 
	{ 
		printf("enter the matrix of integers (first row non-zero) :\n"); 
		MATI1 = INPUTMATI(); 
	} 
	printf("The matrix entered is\n\n"); 
	PRINTMATI(0,MATI1->R-1,0,MATI1->C-1,MATI1); 
	printf("Do you want the unimodular transformation matrix P? (Y/N)\n"); 
	answer = GetYN(); 
	if (!answer) 
	{ 
		alpha = KB_ROW(MATI1, &nz); 
		MATI2 = HERMITE1(MATI1, alpha, nz); 
		printf("The Hermite normal form = \n"); 
		PRINTMATI(0,MATI2->R-1,0,MATI2->C-1,MATI2); 
		strcpy(buff, "hermite.out"); 
		outfile = fopen(buff, "w"); 
		FPRINTMATI(outfile,0,MATI2->R-1,0,MATI2->C-1,MATI2); 
		fclose(outfile); 
	} 
	else 
	{ 
		alpha = KB_ROWP(MATI1, &MATI3, &nz); 
		MATI2 = HERMITE1P(MATI1, MATI3, &MATI4, alpha, nz); 
		FREEMATI(MATI3); 
		printf("The Hermite normal form = \n"); 
		PRINTMATI(0,MATI2->R-1,0,MATI2->C-1,MATI2); 
		strcpy(buff, "hermite.out"); 
		outfile = fopen(buff, "w"); 
		FPRINTMATI(outfile,0,MATI2->R-1,0,MATI2->C-1,MATI2); 
		fclose(outfile); 
		printf("The unimodular transformation matrix P = \n"); 
		PRINTMATI(0,MATI4->R-1,0,MATI4->C-1,MATI4); 
		strcpy(buff, "hermitep.out"); 
		outfile = fopen(buff, "w"); 
		FPRINTMATI(outfile,0,MATI4->R-1,0,MATI4->C-1,MATI4); 
		fprintf(outfile, "%u", nz); 
		fclose(outfile); 
		FREEMATI(MATI4); 
	} 
	FREEMATI(MATI2); 
	FREEMATI(MATI1); 
	ffree((char *)alpha, (MATI1->C) * sizeof(USI)); 
	return; 
} 
 
void MLLL() 
{ 
	USI answer, m1, n1; 
	MPMATI *MATI1, *MATI2, *MATI3; 
	char buff[20]; 
	FILE *outfile; 
 
	printf("Do you wish to use an existing matrix from a file? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
	{ 
		MATI1 = FINPUTMATFILEI_I(); 
		if (MATI1 == NULL) 
			exit (0); 
	} 
	else 
	{ 
		printf("enter the matrix of integers (first row non-zero) :\n"); 
		MATI1 = INPUTMATI(); 
	} 
	printf("The matrix entered is\n\n"); 
	PRINTMATI(0,MATI1->R-1,0,MATI1->C-1,MATI1); 
	MLLLVERBOSE = 0; 
	printf("VERBOSE? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
		MLLLVERBOSE = 1; 
	MATI3 = IDENTITYI(MATI1->R); 
	printf("enter the parameters m1 and n1 (normally 1 and 1) :"); 
	scanf("%u %u", &m1, &n1); 
	Flush(); 
	MATI2 = BASIS_REDUCTION(MATI1, &MATI3, 0, m1, n1); 
	printf("\n\n"); 
	printf("The corresponding transformation matrix is\n"); 
	PRINTMATI(0,MATI3->R-1,0,MATI3->C-1,MATI3); 
	strcpy(buff, "mllltran.out"); 
	outfile = fopen(buff, "w"); 
	FPRINTMATI(outfile,0,MATI3->R-1,0,MATI3->C-1,MATI3); 
	fclose(outfile); 
	printf("The corresponding reduced basis is\n"); 
	PRINTMATI(0,MATI2->R-1,0,MATI2->C-1,MATI2); 
	strcpy(buff, "mlllbas.out"); 
	outfile = fopen(buff, "w"); 
	FPRINTMATI(outfile,0,MATI2->R-1,0,MATI2->C-1,MATI2); 
	fclose(outfile); 
	FREEMATI(MATI1); 
	FREEMATI(MATI2); 
	FREEMATI(MATI3); 
	return; 
} 
 
void SMITH() 
{ 
	MPI **M, *MAX_ENTRY; 
	unsigned int i, j, u, r, z, answer, m1, n1; 
	MPMATI *MATI1, *MATI2, *MATI3, *Temp, *Temp1; 
	char buff[20]; 
	FILE *outfile; 
 
	printf("This program takes as input a rectangular matrix A of integers and computes\n"); 
	printf("unimodular integer matrices P, Q such that PAQ=D, where D is a diagonal matrix\n"); 
	printf("with positive integer diagonal elements d[1],...,d[r].\n"); 
 	printf("Here d[i] divides d[i+1], 1<=i<=r-1.\n"); 
	printf("d[1],...,d[r] are called the invariant factors of A.\n\n"); 
	printf("Do you wish to use an existing matrix from a file? (Y/N)\n\n"); 
	answer = GetYN(); 
	if (answer) 
	{ 
		MATI1 = FINPUTMATFILEI_I(); 
		if (MATI1 == NULL) 
			exit (0); 
	} 
	else 
	{ 
		printf("enter the matrix of integers:\n"); 
		MATI1 = INPUTMATI(); 
	} 
 
	printf(" The matrix entered is A = \n\n"); 
	PRINTMATI(0,MATI1->R-1,0,MATI1->C-1,MATI1); 
	z = MIN((int) MATI1->R, (int) MATI1->C); 
	printf("enter MAX_ENTRY:"); 
	MAX_ENTRY = INPUTI(&u); 
	Flush(); 
	printf("The test matrix is %u x %u\n\n", MATI1->R, MATI1->C); 
	printf("Enter alpha=m1/n1: select m1 and n1 (1/4 < alpha <= 1) :"); 
	scanf("%u %u", &m1, &n1); 
	Flush(); 
	printf("MAX_ENTRY CUTOFF= "); PRINTI(MAX_ENTRY);printf("\n\n"); 
	MLLLVERBOSE = 0; 
	printf("VERBOSE? (Y/N)\n\n"); 
	answer = GetYN(); 
	if (answer) 
		MLLLVERBOSE = 1; 
	printf("Do you want P and Q? (Y/N)\n\n"); 
	answer = GetYN(); 
	if (answer) 
	{ 
		M = SMITHI(MATI1, &MATI2, &MATI3, &r, MAX_ENTRY, m1, n1); 
		FREEMPI(MAX_ENTRY); 
		printf("The row unit matrix is P = \n"); 
		PRINTMATI(0,MATI2->R-1,0,MATI2->C-1,MATI2); 
		strcpy(buff, "smithp.out"); 
		outfile = fopen(buff, "w"); 
		FPRINTMATI(outfile,0,MATI2->R-1,0,MATI2->C-1,MATI2); 
		fclose(outfile); 
		printf("The column unit matrix is Q = \n"); 
		PRINTMATI(0,MATI3->R-1,0,MATI3->C-1,MATI3); 
		strcpy(buff, "smithq.out"); 
		outfile = fopen(buff, "w"); 
		FPRINTMATI(outfile,0,MATI3->R-1,0,MATI3->C-1,MATI3); 
		fclose(outfile); 
		printf("Do you want to check that PAQ is actually equal to the quoted SNF?(Y/N)\n\n"); 
		answer = GetYN(); 
		if (answer){ 
			Temp = MULTMATI(MATI2,MATI1); 
			Temp1 = MULTMATI(Temp,MATI3); 
			for (i = 0; i < Temp1->R; i++) 
			{ 
				for (j = 0; j < Temp1->C; j++) 
				{ 
					if (i !=j && (Temp1->V[i][j])->S ) 
					{ 
						fprintf(stderr, "PAQ is not diagonal!\n"); 
						exit (1); 
					} 
				} 
			} 
			for(i = 0; i < r; i++) 
			{ 
				if (!EQUALI(Temp1->V[i][i], M[i])) 
				{ 
					fprintf(stderr, "PAQ is diagonal, but the diagonals are not right!\n"); 
					exit (1); 
				} 
				 
			} 
			FREEMATI(Temp); 
			FREEMATI(Temp1); 
		} 
		FREEMATI(MATI2); 
		FREEMATI(MATI3); 
		printf("validated!\n\n"); 
	} 
	else 
	{ 
		M = SMITHI1(MATI1, &r, MAX_ENTRY, m1, n1); 
		FREEMPI(MAX_ENTRY); 
	} 
	MLLLVERBOSE = 0; 
	FREEMATI(MATI1); 
	strcpy(buff, "smith.out"); 
	outfile = fopen(buff, "w"); 
	fprintf(outfile, "%u %u\n", r, 1); 
	for(i = 0; i < r; i++) 
	{ 
		printf("invariant factor d[%u] = ", i + 1); 
		PRINTI(M[i]); 
		FPRINTI(outfile, M[i]); 
		fprintf(outfile, "\n"); 
		printf("\n"); 
		FREEMPI(M[i]); 
	} 
	printf("rank A = %u\n", r); 
	fclose(outfile); 
	ffree((char *)M, z * sizeof(MPI *)); 
	return; 
} 
 
void DECODEX(MPI *Eptr, MPI *Pptr, MPI *Qptr) 
/* 
 * *Eptr is the encrytion key, *Pptr and *Qptr are the RSA primes. 
 * The deciphering key *Dptr is computed and file "encoded" is decoded. 
 * The decoded message is sent to the screen and also to the file "decoded". 
 */ 
{ 
	MPI *Rptr, *Dptr; 
	MPI *Tmp1, *Tmp2, *Tmp3; 
 
	Rptr = MULTI(Pptr, Qptr); 
	Tmp1 = SUB0_I(Pptr, 1); 
	Tmp2 = SUB0_I(Qptr, 1); 
	Tmp3 = MULTI(Tmp1, Tmp2); 
	printf("(p-1)(q-1) =  :" );PRINTI(Tmp3);printf("\n"); 
	Dptr = INVERSEM(Eptr, Tmp3); 
	printf("d =  :" );PRINTI(Dptr);printf("\n"); 
	FREEMPI(Tmp1); 
	FREEMPI(Tmp2); 
	FREEMPI(Tmp3); 
	DECODE(Dptr, Rptr); 
	FREEMPI(Dptr); 
	FREEMPI(Rptr); 
	return; 
} 
/* 
MPI *RSAEX() 
{ 
	unsigned int u; 
	MPI *Pptr, *Qptr, *Eptr; 
 
	printf("enter a prime p > 355142:" ); 
	Pptr = INPUTI(&u); 
	printf("enter another prime q > 355142:" ); 
	Qptr = INPUTI(&u); 
	Flush();  
	Eptr = RSAE(Pptr, Qptr); 
	FREEMPI(Pptr); 
	FREEMPI(Qptr); 
	return (Eptr); 
} 
*/ 
 
MPI *GCD_ARRAYV(MPIA M, MPIA *Y) 
/* 
 * n is length of array 
 * Returns d=gcd(M[0],...,M[n-1]) and an array Y[] of MPI's such that 
 * d = M[0]*Y[0]+...+M[n-1]*Y[n-1]. Here n > 1. 
 */ 
{ 
	MPI *D; 
	int i; 
	unsigned long n = M->size; 
	MPMATI *Temp, *Temp1, *Q; 
	 
	Temp = BUILDMATI(n, 1); 
	for (i = 0; i < n; i++) 
	  Temp->V[i][0] = COPYI(M->A[i]); 
	Temp1 = EXTGCD(Temp, &D, &Q, 3, 4); 
	printf("The multipliers are\n"); 
	PRINTMATI(0,Temp1->R-1,0,Temp1->C-1,Temp1); 
	*Y = BUILDMPIA(); 
	for (i = 0; i < n; i++) 
	  ADD_TO_MPIA(*Y, Temp1->V[0][i], i); 
	FREEMATI(Temp); 
	FREEMATI(Temp1); 
	FREEMATI(Q); 
	return (D); 
 
/* 
	B = (MPI **)mmalloc((USL)(n * sizeof(MPI *))); 
	for (i = 0; i < n; i++) 
		B[i] = COPYI(M[i]);	 
	for (i = 1; i < n; i++) 
	{ 
		tmp = B[i]; 
		B[i] = GCD(B[i], B[i - 1]); 
		FREEMPI(tmp); 
	} 
	D = COPYI(B[n - 1]); 
	tmp = B[n - 1]; 
	B[n - 1] = COPYI(M[n - 1]); 
	FREEMPI(tmp); 
	k = ONEI(); 
	for (i = n - 1; i >= 1; i--) 
	{ 
		G = EUCLIDI(B[i], B[i - 1], &U, &V); 
		FREEMPI(G); 
		tmp = B[i]; 
		B[i] = MULTI(U, k); 
		FREEMPI(U); 
		FREEMPI(tmp); 
		if ( i == 1) 
			break; 
		tmp = k; 
		k = MULTI(k, V);	 
		FREEMPI(V); 
		FREEMPI(tmp); 
		tmp = B[i - 1]; 
		B[i - 1] = COPYI(M[i - 1]); 
		FREEMPI(tmp); 
	} 
	tmp = B[0]; 
	B[0] = MULTI(k, V); 
	FREEMPI(tmp); 
	FREEMPI(k); 
	FREEMPI(V); 
	*Y = B; 
	return (D); 
*/ 
} 
 
void EXTGCDX() 
/* This is algorthm 1 of Havas, Majewski, Matthews. */ 
{ 
	USI answer, m1, n1, m, n, i, j, p; 
	MPMATI *MATI1, *MATI2, *Q, *M, *MATI3; 
	char buff[20]; 
	FILE *outfile; 
	MPI *A, *T, **XX, **X, *Temp; 
	int e; 
 
	HAVASFLAG = 1; 
	printf("Do you wish to enter your sequence of numbers from an existing column matrix? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
	{ 
		MATI1 = FINPUTMATFILEI_I(); 
		if (MATI1 == NULL) 
			exit (0); 
	} 
	else 
	{ 
		printf("WARNING: Make sure the first integer in the sequence is non-zero) :\n"); 
		MATI1 = INPUTMATI(); 
	} 
	printf("The matrix entered is\n\n"); 
	PRINTMATI(0,MATI1->R-1,0,MATI1->C-1,MATI1); 
	MLLLVERBOSE = 0; 
	printf("VERBOSE? (Y/N)\n"); 
	answer = GetYN(); 
	printf("answer = %d\n", answer); 
	if (answer) 
		MLLLVERBOSE = 1; 
	printf("MLLLVERBOSE = %u\n", MLLLVERBOSE); 
	printf("to enter alpha=m1/n1: select m1 and n1 (normally 1 and 1) :"); 
	scanf("%u %u", &m1, &n1); 
	Flush(); 
	MATI3 = EXTGCD(MATI1, &A, &MATI2, m1, n1); 
	FREEMATI(MATI1); 
	printf("The multiplier matrix found by LLL is\n"); 
	PRINTMATI(0,MATI2->R-1,0,MATI2->C-1,MATI2); 
	printf("gcd = "); PRINTI(A); printf("\n"); 
	FREEMPI(A); 
	printf("The multipliers found by LLL are\n"); 
	PRINTMATI(0,MATI3->R-1,0,MATI3->C-1,MATI3); 
	m = MATI2->C; 
	T = LENGTHSQRI(MATI3, 0); 
	printf("The Euclidean norm squared = "); 
	PRINTI(T); 
	FREEMPI(T); 
	printf("\n"); 
	printf("Do you want to get a shortest multiplier using Fincke_Pohst? (Y/N)\n"); 
	answer = GetYN(); 
	p = m - 1; 
	XX = (MPI **)mmalloc((USL)(p * sizeof(MPI *))); 
	for (j = 0; j < p; j++) 
		XX[j] = ZEROI(); 
	if (answer) 
	{ 
		GCDVERBOSE = 1; 
		Q = MATI2; 
		n = Q->R; 
		while (1) 
		{ 
			M = SHORTESTT0(Q, &X); 
			for (j = 0; j < p; j++) 
			{ 
				Temp = XX[j]; 
				XX[j] = ADDI(XX[j], X[j]); 
				FREEMPI(Temp); 
				FREEMPI(X[j]); 
			} 
			ffree((char *)X, p * sizeof(MPI *)); 
			if (M == NULL) 
				break; 
			else 
			{ 
				for (j = 0; j < Q->C; j++) 
				{ 
					FREEMPI(Q->V[n - 1][j]); 
					Q->V[n - 1][j] = COPYI(M->V[0][j]); 
				} 
				FREEMATI(MATI3); 
				MATI3 = M; 
			} 
		} 
		printf("found a shortest multiplier vector:\n"); 
	} 
	else 
		Q = MATI2; 
	strcpy(buff, "egcdmat.out"); 
	outfile = fopen(buff, "w"); 
	FPRINTMATI(outfile,0,Q->R-1,0,Q->C-1,Q); 
	fclose(outfile); 
	strcpy(buff, "egcdmult.out"); 
	outfile = fopen(buff, "w"); 
	if (answer) 
		fprintf(outfile, "A Shortest multiplier is "); 
	else 
	{ 
		fprintf(outfile, "A not necessarily shortest multiplier is "); 
		fprintf(outfile, "b[%u]=", m); 
	} 
	if (answer) 
	{ 
		printf("b[%u]", m); 
		fprintf(outfile, "b[%u]", m); 
		for (j = 0; j < p; j++) 
		{ 
			e = XX[j]->S; 
			if (e == -1) 
			{ 
				printf("+"); 
				fprintf(outfile, "+"); 
				Temp = MINUSI(XX[j]); 
				if (!EQONEI(Temp)) 
				{ 
					PRINTI(Temp); 
					FPRINTI(outfile, Temp); 
				} 
				printf("b[%u]", j + 1); 
				fprintf(outfile, "b[%u]", j + 1); 
				FREEMPI(Temp); 
			} 
			if (e == 1) 
			{ 
				printf("-"); 
				fprintf(outfile, "-"); 
				if (!EQONEI(XX[j])) 
				{ 
					PRINTI(XX[j]); 
					FPRINTI(outfile, XX[j]); 
				} 
				printf("b[%u]", j + 1); 
				fprintf(outfile, "b[%u]", j + 1); 
			} 
		} 
	} 
	if (answer){ 
		printf("="); 
		fprintf(outfile, "="); 
		for (i = 0; i < MATI3->C; i++) 
		{ 
			PRINTI(MATI3->V[0][i]);  
			printf(" "); 
			FPRINTI(outfile, MATI3->V[0][i]);  
			fprintf(outfile," "); 
			 
		} 
		T = LENGTHSQRI(MATI3, 0); 
		printf(": "); 
		fprintf(outfile, ": "); 
		PRINTI(T); 
		FPRINTI(outfile, T); 
		printf("\n"); 
		fprintf(outfile,"\n"); 
		FREEMPI(T); 
	} 
	else 
	{ 
		for (i = 0; i < MATI3->C; i++) 
		{ 
			FPRINTI(outfile, MATI3->V[0][i]);  
			fprintf(outfile," "); 
			 
		} 
		T = LENGTHSQRI(MATI3, 0); 
		fprintf(outfile, ": "); 
		FPRINTI(outfile, T); 
		fprintf(outfile,"\n"); 
		FREEMPI(T); 
	} 
	fclose(outfile); 
	if (answer) 
	{ 
		printf("Do you want to get all the shortest multipliers? (Y/N)\n"); 
		answer = GetYN(); 
		if (answer) 
			SHORTEST(Q, XX, 1, 1); 
	} 
	for (j = 0; j < p; j++) 
		FREEMPI(XX[j]); 
	ffree((char *)XX, p * sizeof(MPI *)); 
	FREEMATI(MATI3); 
	FREEMATI(Q); 
	HAVASFLAG = 0; 
	GCDVERBOSE = 0; 
	return; 
} 
 
void FINCKE_POHSTX() 
{ 
	USI answer, i, j, m, n, u; 
	MPMATI *MATI1; 
	MPMATR *M; 
	MPR *C; 
 
	printf("Do you wish to use an existing matrix from a file? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
	{ 
		MATI1 = FINPUTMATFILEI_I(); 
		if (MATI1 == NULL) 
			exit (0); 
	} 
	else 
	{ 
		printf("enter the matrix of integers (first row non-zero) :\n"); 
		MATI1 = INPUTMATI(); 
	} 
	printf("The matrix entered is\n\n"); 
	PRINTMATI(0,MATI1->R-1,0,MATI1->C-1,MATI1); 
	m = MATI1->R; 
	n = MATI1->C; 
	M = BUILDMATR(m, n); 
	for (i = 0; i < m; i++) 
	{ 
		for (j = 0; j < n; j++) 
		{ 
			elt(M, i, j) = BUILDMPR(); 
			elt(M, i, j)->N = COPYI(MATI1->V[i][j]); 
			elt(M, i, j)->D = ONEI(); 
		} 
	} 
	FREEMATI(MATI1); 
	printf("Enter the upper bound for Q(X):"); 
	C = INPUTR(&u); 
	FINCKE_POHST(M, C, 1); 
	FREEMATR(M); 
	FREEMPR(C); 
	return; 
} 
 
void IMPROVEPX() 
{ 
	USI answer, m1, n1, norig, m, i; 
	MPMATI *MATI1, *MATI2; 
	char buff[20]; 
	FILE *outfile, *infile; 
	MPI ***temp; 
	int k; 
 
	strcpy(buff, "hermitep.out"); 
	infile = fopen(buff, "r"); 
	MATI1 = FINPUTMATI(infile); 
	fscanf(infile, "%u", &m); /* m = no of rows to be improved */ 
	fclose(infile); 
	norig = MATI1->R - m;/* norig = no of zero rows in HNF */ 
	if (norig == 0) 
	{ 
		printf("HNF has no non-zero rows - P cannot be improved\n"); 
		FREEMATI(MATI1); 
		return;	 
	} 
	temp = (MPI ***)mmalloc(m * sizeof(MPI **)); 
	for (i = 0; i < m; i++) 
		temp[i] = MATI1->V[i]; 
	for (i = 0; i < norig; i++) 
		MATI1->V[i] = MATI1->V[i + m]; 
	for (i = norig; i < MATI1->R; i++) 
		MATI1->V[i] = temp[i - norig]; 
	printf("The matrix entered is\n\n"); 
	PRINTMATI(0,MATI1->R-1,0,MATI1->C-1,MATI1); 
	MLLLVERBOSE = 0; 
	printf("VERBOSE? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
		MLLLVERBOSE = 1; 
	printf("enter the parameters m1 and n1 (normally 1 and 1) :"); 
	scanf("%u %u", &m1, &n1); 
	Flush(); 
	GCDFLAG = 1; 
	MATI2 = BASIS_REDUCTION00(MATI1, m1, n1, norig); 
	GCDFLAG = 0; 
	printf("\n\n"); 
	strcpy(buff, "improvep.out"); 
	outfile = fopen(buff, "w"); 
	for (i = norig; i < MATI2->R; i++) 
		temp[i - norig] = MATI2->V[i]; 
	for (k = norig - 1; k >= 0; k--) 
		MATI2->V[k + m] = MATI2->V[k]; 
	for (i = 0; i < m; i++) 
		MATI2->V[i] = temp[i]; 
	FPRINTMATI(outfile,0,MATI2->R-1,0,MATI2->C-1,MATI2); 
	fclose(outfile); 
	printf("The improved transformation matrix is\n"); 
	PRINTMATI(0,MATI2->R-1,0,MATI2->C-1,MATI2); 
	FREEMATI(MATI1); 
	FREEMATI(MATI2); 
	ffree((char *)temp, m * sizeof(MPI **)); 
	return; 
} 
 
void QSORTMPIX() 
/* 
 * Input: an array A[0],...,A[q] of MPI's. 
 * sorts nonnegative MPI's  A[m],...,A[n] in order of size. 
 */ 
{ 
	USI m, n, p, i, u, q; 
	MPI **A; 
 
	printf("enter 0<=m<= n<=q (q+1= no of elements, starting from A[0])  :"); 
	scanf("%u %u %u", &m, &n, &q); 
	p = q + 1; 
	A = (MPI **)mmalloc(p * sizeof(MPI *)); 
	printf("enter the array A[0],...,A[%u] of %u MPIs:",q, p); 
	for (i = 0; i < p; i++) 
		A[i] = INPUTI(&u); 
	for (i = 0; i < p; i++) 
	{ 
		printf("A[%u] = ", i); 
		PRINTI(A[i]); 
		printf("\n"); 
	} 
	QSORTMPI0(A, m, n); 
	for (i = 0; i < p; i++) 
	{ 
		printf("A[%u] = ", i); 
		PRINTI(A[i]); 
		FREEMPI(A[i]); 
		printf("\n"); 
	} 
	ffree((char *)A, p * sizeof(MPI *)); 
	return; 
} 
 
void QSORTMATIX() 
{ 
	USI answer, r, s; 
	MPMATI *MATI1; 
 
	printf("Do you wish to use an existing matrix from a file? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
	{ 
		MATI1 = FINPUTMATFILEI_I(); 
		if (MATI1 == NULL) 
			exit (0); 
	} 
	else 
	{ 
		printf("enter the matrix of integers (first row non-zero) :\n"); 
		MATI1 = INPUTMATI(); 
	} 
	printf("The matrix entered is\n\n"); 
	PRINTMATI(0,MATI1->R-1,0,MATI1->C-1,MATI1); 
	printf("enter the rows to be sorted :"); 
	scanf("%u %u", &r, &s); 
	QSORTMATI(MATI1, r, s); 
	printf("The sorted matrix is\n"); 
	PRINTMATI(0,MATI1->R-1,0,MATI1->C-1,MATI1); 
	FREEMATI(MATI1); 
	return; 
} 
 
void SCHNORRGCD(MPI *N) 
{ 
	USI answer, m1, n1, n, t, i, j; 
	MPMATI *MATI1, *MATI2, *MATI0; 
	char buff[20]; 
	FILE *outfile; 
 
	HAVASFLAG = 1; 
	printf("Do you wish to enter your sequence of numbers from an existing column matrix? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
	{ 
		MATI1 = FINPUTMATFILEI_I(); 
		if (MATI1 == NULL) 
			exit (0); 
	} 
	else 
	{ 
		printf("WARNING: Make sure the first integer in the sequence is non-zero) :\n"); 
		MATI1 = INPUTMATI(); 
	} 
	printf("The matrix entered is\n\n"); 
	PRINTMATI(0,MATI1->R-1,0,MATI1->C-1,MATI1); 
	MLLLVERBOSE = 0; 
	printf("VERBOSE? (Y/N)\n"); 
	answer = GetYN(); 
	printf("answer = %d\n", answer); 
	if (answer) 
		MLLLVERBOSE = 1; 
	printf("MLLLVERBOSE = %u\n", MLLLVERBOSE); 
	printf("to enter alpha=m1/n1: select m1 and n1 (normally 1 and 1) :"); 
	scanf("%u %u", &m1, &n1); 
	Flush(); 
	n = MATI1->R; 
	t = n + 1; 
	MATI0 = BUILDMATI(n, t); 
	for (i = 0; i < n; i++) 
	{ 
		for (j = 0; j < n; j++) 
		{ 
			if ( i == j) 
				MATI0->V[i][j] = ONEI(); 
			else 
				MATI0->V[i][j] = ZEROI(); 
		} 
		MATI0->V[i][n] = MULTI(MATI1->V[i][0], N); 
	} 
/* 
	MATI0 = BUILDMATI(t, t + 1); 
	for (i = 0; i < n; i++) 
	{ 
		for (j = 0; j < n; j++) 
		{ 
			if ( i == j) 
				MATI0->V[i][j] = ONEI(); 
			else 
				MATI0->V[i][j] = ZEROI(); 
		} 
		MATI0->V[i][n] = MULTI(MATI1->V[i][0], N); 
		MATI0->V[i][t] = ZEROI(); 
	} 
	for (j = 0; j < n; j++) 
		MATI0->V[n][j] = ONEI(); 
*/ 
	FREEMATI(MATI1); 
	strcpy(buff, "sgcdmat.out"); 
	outfile = fopen(buff, "w"); 
	FPRINTMATI(outfile,0,MATI0->R-1,0,MATI0->C-1,MATI0); 
	fclose(outfile); 
		 
GetReturn(); 
	MATI2 = BASIS_REDUCTION0(MATI0, m1, n1); 
	FREEMATI(MATI0); 
	printf("The corresponding reduced basis is\n"); 
	PRINTMATI(0,MATI2->R-1,0,MATI2->C-1,MATI2); 
	strcpy(buff, "sgcdbas.out"); 
	outfile = fopen(buff, "w"); 
	FPRINTMATI(outfile,0,MATI2->R-1,0,MATI2->C-1,MATI2); 
	fclose(outfile); 
	FREEMATI(MATI2); 
	HAVASFLAG = 0; 
	return; 
} 
 
void SHORTESTTTX() 
{ 
/* This is the inhomogenous Fincke-Pohst Algorithm . 
 * See Pohst-Zassenhaus . 
 */ 
	USI answer, u; 
	MPI *BOUND; 
	MPMATI *MATI1; 
 
	printf("Do you wish to enter your matrix from an existing matrix? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
	{ 
		MATI1 = FINPUTMATFILEI_I(); 
		if (MATI1 == NULL) 
			exit (0); 
	} 
	else 
		MATI1 = INPUTMATI(); 
	printf("The matrix entered is\n\n"); 
	PRINTMATI(0,MATI1->R-1,0,MATI1->C-1,MATI1); 
	MLLLVERBOSE = 0; 
	printf("VERBOSE? (Y/N)\n"); 
	answer = GetYN(); 
	printf("answer = %d\n", answer); 
	if (answer) 
		MLLLVERBOSE = 1; 
	printf("MLLLVERBOSE = %u\n", MLLLVERBOSE); 
	printf("enter a positive integer (the distance bound):"); 
	BOUND = INPUTI(&u); 
	Flush(); 
	if (BOUND->S <= 0) 
	{ 
	  printf("BOUND <= 0\n"); 
	  return; 
	} 
	SHORTESTTT(MATI1, BOUND); 
	FREEMATI(MATI1); 
	FREEMPI(BOUND); 
	return; 
} 
 
void FIB_MIN() 
{ 
	USI M1, M2, N1, N2, i, m, n; 
	MPMATI *MATI1, *MATI2, *Q; 
	MPI *A; 
	char buff[20]; 
	FILE *outfile; 
 
	printf("enter positive integers N1 <= N2, the test range:"); 
	scanf("%u%u", &N1, &N2); 
	printf("enter integers (>= 2) M1 <= M2, the sequence range:"); 
	scanf("%u%u", &M1, &M2); 
	Flush(); 
	strcpy(buff, "fibmin.out"); 
	outfile = fopen(buff, "w"); 
	outfile = fopen(buff, "a+"); 
	FPRINTMATIFLAG = 1; 
	MLLLVERBOSE = 0; 
for (m = M1; m <= M2; m++) 
{ 
	fprintf(outfile, "====================\n"); 
	for (n = N1; n <= N2; n++) 
	{ 
		printf("m=%u: n=%u:\n ", m,  n); 
		fprintf(outfile, "m=%u: n=%u:", m,  n); 
		MATI1 = BUILDMATI(m, 1); 
		for (i = 0; i < MATI1->R; i++) 
		{ 
			MATI1->V[i][0] = FIBONACCI(n + i);	 
/* 
			FPRINTI(outfile, MATI1->V[i][0]); 
			fprintf(outfile, " "); 
*/ 
		} 
		MATI2 = EXTGCD(MATI1, &A, &Q, 3, 4); 
		FREEMATI(MATI1); 
		FREEMATI(MATI2); 
		FREEMPI(A); 
		FPRINTMATI(outfile, Q->R - 1, Q->R-1, 0, Q->C-1, Q); 
		FREEMATI(Q); 
	} 
} 
	fprintf(outfile, "====================\n"); 
	fclose(outfile); 
	FPRINTMATIFLAG = 0; 
	return; 
} 
 
void PRINTW1(USI n, USI r) 
{ 
	USI x; 
	x = n - r - 2; 
	if (n % 2 == 0) 
	{ 
		if (r <= n - 4) 
			printf(" L[%u]       ", x); 
		if (r == n - 3) 
			printf(" 2           "); 
		if (r == n - 2) 
			printf(" 1           "); 
		if (r >= n - 1) 
			printf(" 0           "); 
	} 
	if (n % 2) 
	{ 
		if (r <= n - 3) 
			printf(" L[%u]       ", x); 
		if (r == n - 2) 
			printf(" 1           "); 
		if (r == n - 1) 
			printf(" 1           "); 
		if (r >= n) 
			printf(" 0           "); 
	} 
} 
 
void PRINTW2(USI n, USI r, USI m) 
{ 
	USI x,y,z; 
	x = n - r - 2; y = 2 * m - n; z = r - y - 3; 
	if (n % 2 == 0) 
	{ 
		if (r < m) 
		{ 
			if (r <= y + 1) 
				printf(" L[%u]       ", x); 
			if (r == y + 2) 
				printf(" L[%u]+1     ", x); 
			if (r == y + 3) 
				printf(" L[%u]-1     ", x); 
			if (r == y + 4) 
				printf(" L[%u]+2     ", x); 
			if (r == y + 5) 
				printf(" L[%u]-2     ", x); 
			if (r < m && r >= y + 6 && r % 2 == 0) 
				printf(" L[%u]+L[%u] ", x,z); 
			if (r < m && r >= y + 6 && r % 2) 
				printf(" L[%u]-L[%u] ", x,z); 
		} 
		if (r ==  m && n == m + 3) 
			printf(" 1           "); 
		if (r ==  m && n == m + 5) 
			printf(" 2           "); 
		if (r ==  m && n >= m + 6) 
			printf(" L[%u]       ",n - m - 4); 
	} 
	if (n % 2) 
	{ 
		if (r < m) 
		{ 
			if (r <= y) 
				printf(" L[%u]       ", x); 
			if (r == y + 1) 
				printf(" L[%u]+1     ", x); 
			if (r == y + 2) 
				printf(" L[%u]-1     ", x); 
			if (r == y + 3) 
				printf(" L[%u]+1     ", x); 
			if (r == y + 4) 
				printf(" L[%u]-2     ", x); 
			if (r < m && r >= y + 5 && r % 2 == 0) 
				printf(" L[%u]+L[%u] ", x,z); 
			if (r < m && r >= y + 6 && r % 2) 
				printf(" L[%u]-L[%u] ", x,z); 
		} 
		if (r ==  m && n == m + 4) 
			printf(" 1           "); 
		if (r ==  m && n >= m + 5) 
			printf(" L[%u]       ",n - m - 4); 
	} 
} 
 
 void PRINTWW() 
{ 
	USI m, t, w, x, y, z, n, r; 
 
	printf("enter m:"); 
	scanf("%u", &m); 
	x = m + 3; y = 2 * m, z = x - 2; w = m - 1; 
	for (n = 3; n <= z; n++) 
	{ 
		for (r = 1; r <= w; r++) 
			PRINTW1(n, r); 
		printf(" 0           "); 
		printf("\n"); 
	} 
	for (r = 1; r <= m; r++) 
	{ 
		t = m - r; 
		if (r < m - 1) 
			printf(" L[%u]       ", t); 
		else if (r == m - 1) 
			printf(" L[%u]+1     ", t); 
		else 
			printf(" 0           "); 
	} 
	printf("\n"); 
	for (n = x; n <= y; n++) 
	{ 
		for (r = 1; r <= m; r++) 
			PRINTW2(n, r, m); 
		printf("\n"); 
	} 
	return; 
} 
 
void PRINT_DEFECT() 
{ 
	USI M1, M2, N1, N2, i, m, n; 
	MPMATI *MATI, *MATI1, *MATI2, *MATI3, *Q1, *Q2, *Q3, *Q; 
	MPI *A; 
	char buff[20]; 
	FILE *outfile; 
 
	printf("enter positive integers N1 <= N2, the test range:"); 
	scanf("%u%u", &N1, &N2); 
	printf("enter integers (>= 2) M1 <= M2, the sequence range:"); 
	scanf("%u%u", &M1, &M2); 
	Flush(); 
	strcpy(buff, "defect.out"); 
	outfile = fopen(buff, "w"); 
	outfile = fopen(buff, "a+"); 
	FPRINTMATIFLAG = 1; 
	MLLLVERBOSE = 0; 
for (m = M1; m <= M2; m++) 
{ 
	printf("m=%u:\n ", m); 
	fprintf(outfile, "====================\n"); 
	for (n = N1; n <= N2; n++) 
	{ 
		printf("n=%u:\n ", n); 
		fprintf(outfile, "n=%u:", n); 
		MATI1 = BUILDMATI(m, 1); 
		MATI2 = BUILDMATI(m, 1); 
		MATI3 = BUILDMATI(m, 1); 
		for (i = 0; i < MATI1->R; i++) 
		{ 
			MATI1->V[i][0] = FIBONACCI(n + i);	 
			MATI2->V[i][0] = FIBONACCI(n + 1 + i);	 
			MATI3->V[i][0] = FIBONACCI(n + 2 + i);	 
		} 
		MATI = EXTGCD(MATI1, &A, &Q1, 3, 4); 
		FREEMATI(MATI); 
		FREEMATI(MATI1); 
		FREEMPI(A); 
		MATI = EXTGCD(MATI2, &A, &Q2, 3, 4); 
		FREEMATI(MATI); 
		FREEMATI(MATI2); 
		FREEMPI(A); 
		MATI = EXTGCD(MATI3, &A, &Q3, 3, 4); 
		FREEMATI(MATI); 
		FREEMATI(MATI3); 
		FREEMPI(A); 
		MATI = ADDMATI(Q3, Q2); 
		Q = SUBMATI(MATI, Q1); 
		FPRINTMATI(outfile, Q->R - 1, Q->R-1, 0, Q->C-1, Q); 
		FREEMATI(Q1); 
		FREEMATI(Q2); 
		FREEMATI(Q3); 
		FREEMATI(MATI); 
	} 
} 
	fprintf(outfile, "====================\n"); 
	fclose(outfile); 
	FPRINTMATIFLAG = 0; 
	return; 
} 
 
void LUCAS_MIN() 
{ 
	USI M1, M2, N1, N2, i, m, n; 
	MPMATI *MATI1, *MATI2, *Q; 
	MPI *A; 
	char buff[20]; 
	FILE *outfile; 
 
	printf("enter positive integers N1 <= N2, the test range:"); 
	scanf("%u%u", &N1, &N2); 
	printf("enter integers (>= 2) M1 <= M2, the sequence range:"); 
	scanf("%u%u", &M1, &M2); 
	Flush(); 
	strcpy(buff, "lucasmin.out"); 
	outfile = fopen(buff, "w"); 
	outfile = fopen(buff, "a+"); 
	FPRINTMATIFLAG = 1; 
	MLLLVERBOSE = 0; 
for (m = M1; m <= M2; m++) 
{ 
	fprintf(outfile, "====================\n"); 
	for (n = N1; n <= N2; n++) 
	{ 
		printf("m=%u: n=%u:\n ", m,  n); 
		fprintf(outfile, "m=%u: n=%u:", m,  n); 
		MATI1 = BUILDMATI(m, 1); 
		for (i = 0; i < MATI1->R; i++) 
		{ 
			MATI1->V[i][0] = LUCASS(n + i);	 
/* 
			FPRINTI(outfile, MATI1->V[i][0]); 
			fprintf(outfile, " "); 
*/ 
		} 
		MATI2 = EXTGCD(MATI1, &A, &Q, 3, 4); 
		FREEMATI(MATI1); 
		FREEMATI(MATI2); 
		FREEMPI(A); 
		FPRINTMATI(outfile, Q->R - 1, Q->R-1, 0, Q->C-1, Q); 
		FREEMATI(Q); 
	} 
} 
	fprintf(outfile, "====================\n"); 
	fclose(outfile); 
	FPRINTMATIFLAG = 0; 
	return; 
} 
 
void LLLGCDX() 
/* 
 * This executes the LLLGCD algorithm of Havas, Majewski and Matthews. 
 * 30/1/97. 
 */ 
{ 
	USI answer, m1, n1, m, n, i, j, p; 
	int e; 
	MPMATI *MATI1, *MATI2, *Q, *M, *MATI3; 
	char buff[20]; 
	FILE *outfile; 
	MPI *A, *T, **XX, **X, *Temp; 
 
	HAVASFLAG = 1; 
	printf("Do you wish to enter your sequence of numbers from an existing column matrix? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
	{ 
		MATI1 = FINPUTMATFILEI_I(); 
		if (MATI1 == NULL) 
			exit (0); 
	} 
	else 
	{ 
		printf("WARNING: Make sure the first integer in the sequence is non-zero) :\n"); 
		MATI1 = INPUTMATI(); 
	} 
	printf("The matrix entered is\n\n"); 
	PRINTMATI(0,MATI1->R-1,0,MATI1->C-1,MATI1); 
	GCDVERBOSE = 0; 
	printf("VERBOSE? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
		GCDVERBOSE = 1; 
	printf("to enter alpha=m1/n1: select m1 and n1 (normally 1 and 1) :"); 
	scanf("%u %u", &m1, &n1); 
	Flush(); 
	m = MATI1->R; 
	MATI2 = LLLGCD(MATI1, &A, m, m1, n1); 
	FREEMATI(MATI1); 
	printf("The multiplier matrix found by LLL is\n"); 
	PRINTMATI(0,MATI2->R-1,0,MATI2->C-1,MATI2); 
	printf("gcd = "); PRINTI(A); printf("\n"); 
	FREEMPI(A); 
	printf("The multiplier vector found by LLL is b[%u]=", m); 
	for (i = 0;i < MATI2->R;i++) 
	{ 
		PRINTI(MATI2->V[MATI2->R - 1][i]);  
		printf(" "); 
	} 
	printf("\n"); 
	MATI3 = BUILDMATI(1, m); 
	for (i = 0;i < m;i++) 
		MATI3->V[0][i] = COPYI(MATI2->V[m - 1][i]);  
	T = LENGTHSQRI(MATI3, 0); 
	printf("The Euclidean norm squared = "); 
	PRINTI(T); 
	FREEMPI(T); 
	printf("\n"); 
	printf("Do you want to get a shortest multiplier using Fincke_Pohst? (Y/N)\n"); 
	answer = GetYN(); 
	p = m - 1; 
	XX = (MPI **)mmalloc((USL)(p * sizeof(MPI *))); 
	for (j = 0; j < p; j++) 
		XX[j] = ZEROI(); 
	if (answer) 
	{ 
		GCDVERBOSE = 1; 
		Q = MATI2; 
		n = Q->R; 
		while (1) 
		{ 
			M = SHORTESTT0(Q, &X); 
			for (j = 0; j < p; j++) 
			{ 
				Temp = XX[j]; 
				XX[j] = ADDI(XX[j], X[j]); 
				FREEMPI(Temp); 
				FREEMPI(X[j]); 
			} 
			ffree((char *)X, p * sizeof(MPI *)); 
			if (M == NULL) 
				break; 
			else 
			{ 
				for (j = 0; j < Q->C; j++) 
				{ 
					FREEMPI(Q->V[n - 1][j]); 
					Q->V[n - 1][j] = COPYI(M->V[0][j]); 
				} 
				FREEMATI(MATI3); 
				MATI3 = M; 
			} 
		} 
		printf("found a shortest multiplier vector:\n"); 
	} 
	else 
		Q = MATI2; 
	strcpy(buff, "lllgcdmat.out"); 
	outfile = fopen(buff, "w"); 
	FPRINTMATI(outfile,0,Q->R-1,0,Q->C-1,Q); 
	fclose(outfile); 
	strcpy(buff, "lllgcdmult.out"); 
	outfile = fopen(buff, "w"); 
	if (answer) 
		fprintf(outfile, "A Shortest multiplier is "); 
	else 
	{ 
		fprintf(outfile, "A not necessarily shortest multiplier is "); 
		fprintf(outfile, "b[%u]=", m); 
	} 
	if (answer) 
	{ 
		printf("b[%u]", m); 
		fprintf(outfile, "b[%u]", m); 
		for (j = 0; j < p; j++) 
		{ 
			e = XX[j]->S; 
			if (e == -1) 
			{ 
				printf("+"); 
				fprintf(outfile, "+"); 
				Temp = MINUSI(XX[j]); 
				if (!EQONEI(Temp)) 
				{ 
					PRINTI(Temp); 
					FPRINTI(outfile, Temp); 
				} 
				printf("b[%u]", j + 1); 
				fprintf(outfile, "b[%u]", j + 1); 
				FREEMPI(Temp); 
			} 
			if (e == 1) 
			{ 
				printf("-"); 
				fprintf(outfile, "-"); 
				if (!EQONEI(XX[j])) 
				{ 
					PRINTI(XX[j]); 
					FPRINTI(outfile, XX[j]); 
				} 
				printf("b[%u]", j + 1); 
				fprintf(outfile, "b[%u]", j + 1); 
			} 
		} 
	} 
	if (answer){ 
		printf("="); 
		fprintf(outfile, "="); 
		for (i = 0; i < MATI3->C; i++) 
		{ 
			PRINTI(MATI3->V[0][i]);  
			printf(" "); 
			FPRINTI(outfile, MATI3->V[0][i]);  
			fprintf(outfile," "); 
			 
		} 
		T = LENGTHSQRI(MATI3, 0); 
		printf(": "); 
		fprintf(outfile, ": "); 
		PRINTI(T); 
		FPRINTI(outfile, T); 
		printf("\n"); 
		fprintf(outfile,"\n"); 
		FREEMPI(T); 
	} 
	else 
	{ 
		for (i = 0; i < MATI3->C; i++) 
		{ 
			FPRINTI(outfile, MATI3->V[0][i]);  
			fprintf(outfile," "); 
			 
		} 
		T = LENGTHSQRI(MATI3, 0); 
		fprintf(outfile, ": "); 
		FPRINTI(outfile, T); 
		fprintf(outfile,"\n"); 
		FREEMPI(T); 
	} 
	fclose(outfile); 
	if (answer) 
	{ 
		printf("Do you want to get all the shortest multipliers? (Y/N)\n"); 
		answer = GetYN(); 
		if (answer) 
			SHORTEST(Q, XX, 2, 1); 
	} 
	for (j = 0; j < p; j++) 
		FREEMPI(XX[j]); 
	ffree((char *)XX, p * sizeof(MPI *)); 
	FREEMATI(MATI3); 
	FREEMATI(Q); 
	GCDVERBOSE = 0; 
	HAVASFLAG = 0; 
	return; 
} 
 
void JACOBIGCDX() 
/* 
 * This executes the LLLGCD algorithm of Havas, Majewski and Matthews. 
 * 30/1/97. 
 */ 
{ 
	USI answer, m, i; 
	MPMATI *MATI1, *MATI2, *MATI3; 
	MPI *A, *T; 
 
	HAVASFLAG = 1; 
	printf("Do you wish to enter your sequence of numbers from an existing column matrix? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
	{ 
		MATI1 = FINPUTMATFILEI_I(); 
		if (MATI1 == NULL) 
			exit (0); 
	} 
	else 
	{ 
		printf("WARNING: Make sure the first integer in the sequence is non-zero) :\n"); 
		MATI1 = INPUTMATI(); 
	} 
	printf("The matrix entered is\n\n"); 
	PRINTMATI(0,MATI1->R-1,0,MATI1->C-1,MATI1); 
	m = MATI1->R; 
	MLLLVERBOSE = 0; 
	printf("VERBOSE? (Y/N)\n"); 
	answer = GetYN(); 
	printf("answer = %d\n", answer); 
	if (answer) 
		MLLLVERBOSE = 1; 
	printf("MLLLVERBOSE = %u\n", MLLLVERBOSE); 
	MATI2 = JACOBIGCD(MATI1, &A, m); 
	MLLLVERBOSE = 0; 
	FREEMATI(MATI1); 
	HAVASFLAG = 0; 
	printf("The multiplier matrix found by LLL is\n"); 
	PRINTMATI(0,MATI2->R-1,0,MATI2->C-1,MATI2); 
	printf("gcd = "); PRINTI(A); printf("\n"); 
	FREEMPI(A); 
	printf("The multipliers found by JACOBI are\n"); 
	for (i = 0;i < MATI2->R;i++) 
	{ 
		PRINTI(MATI2->V[m - 1][i]);  
		printf(" "); 
	} 
	printf("\n"); 
	MATI3 = BUILDMATI(1, m); 
	for (i = 0;i < m;i++) 
		MATI3->V[0][i] = COPYI(MATI2->V[m - 1][i]);  
	T = LENGTHSQRI(MATI3, 0); 
	printf("The Euclidean norm squared = "); 
	PRINTI(T); 
	FREEMPI(T); 
	FREEMATI(MATI2); 
	FREEMATI(MATI3); 
	printf("\n"); 
	 
} 
 
void SCHNORRHERMITE(MPI *N) 
{ 
	USI answer, m1, n1, m, n, t, i, j; 
	MPMATI *MATI1, *MATI2, *MATI0; 
	MPI *Temp; 
	char buff[20]; 
	FILE *outfile; 
 
	printf("Do you wish to enter your sequence of numbers from an existing column matrix? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
	{ 
		MATI1 = FINPUTMATFILEI_I(); 
		if (MATI1 == NULL) 
			exit (0); 
	} 
	else 
	{ 
		printf("WARNING: Make sure the first integer in the sequence is non-zero) :\n"); 
		MATI1 = INPUTMATI(); 
	} 
	printf("The matrix entered is\n\n"); 
	PRINTMATI(0,MATI1->R-1,0,MATI1->C-1,MATI1); 
	MLLLVERBOSE = 0; 
	HERMITEVERBOSE = 0;		 
	printf("VERBOSE? (Y/N)\n"); 
	answer = GetYN(); 
	printf("answer = %d\n", answer); 
	if (answer) 
	{ 
		MLLLVERBOSE = 1; 
		HERMITEVERBOSE = 1;		 
	} 
	printf("MLLLVERBOSE = %u\n", MLLLVERBOSE); 
	printf("to enter alpha=m1/n1: select m1 and n1 (normally 1 and 1) :"); 
	scanf("%u %u", &m1, &n1); 
	Flush(); 
	n = MATI1->R; 
	m = MATI1->C; 
	t = n + m; 
	MATI0 = BUILDMATI(n, t); 
	for (i = 0; i < n; i++) 
	{ 
		for (j = 0; j < n; j++) 
		{ 
			if ( i == j) 
				MATI0->V[i][j] = ONEI(); 
			else 
				MATI0->V[i][j] = ZEROI(); 
		} 
		for (j = n; j < t; j++) 
		{ 
			Temp = POWERI(N, t - j); 
			MATI0->V[i][j] = MULTI(MATI1->V[i][j - n], Temp); 
			FREEMPI(Temp); 
		} 
	} 
	FREEMATI(MATI1); 
	strcpy(buff, "shermitemat.out"); 
	outfile = fopen(buff, "w"); 
	FPRINTMATI(outfile,0,MATI0->R-1,0,MATI0->C-1,MATI0); 
	fclose(outfile); 
	MATI2 = BASIS_REDUCTION000(MATI0, m1, n1, N); 
	HERMITEVERBOSE = 0;		 
	FREEMATI(MATI0); 
	for (i = 0; i < n; i++) 
	{ 
		for (j = n; j < t; j++) 
		{ 
			Temp = POWERI(N, t - j); 
			MATI2->V[i][j] = INTI(MATI2->V[i][j], Temp); 
			FREEMPI(Temp); 
		} 
	} 
	printf("The corresponding reduced basis is\n"); 
	PRINTMATI(0,MATI2->R-1,0,MATI2->C-1,MATI2); 
	strcpy(buff, "shermitebas.out"); 
	outfile = fopen(buff, "w"); 
	FPRINTMATI(outfile,0,MATI2->R-1,0,MATI2->C-1,MATI2); 
	fclose(outfile); 
	FREEMATI(MATI2); 
	return; 
} 
 
void LLLHERMITE1X() 
{ 
	USI answer, rank, m1, n1; 
	MPMATI *MATI1, *MATI2, *MATI3; 
	char buff[20]; 
	FILE *outfile; 
 
	printf("Do you wish to use an existing matrix from a file? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
	{ 
		MATI1 = FINPUTMATFILEI_I(); 
		if (MATI1 == NULL) 
			exit (0); 
	} 
	else 
	{ 
		printf("enter the matrix of integers (first row non-zero) :\n"); 
		MATI1 = INPUTMATI(); 
	} 
	printf("The matrix entered is\n\n"); 
	PRINTMATI(0,MATI1->R-1,0,MATI1->C-1,MATI1); 
	HERMITE1VERBOSE = 0; 
	printf("VERBOSE? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
		HERMITE1VERBOSE = 1; 
	printf("enter the parameters m1 and n1 (normally 1 and 1) :"); 
	scanf("%u %u", &m1, &n1); 
	Flush(); 
	MATI2 = LLLHERMITE1(MATI1, &MATI3, &rank, m1, n1); 
	HERMITE1VERBOSE = 0; 
	printf("rank = %u\n\n", rank); 
	printf("The transformation matrix is\n"); 
	PRINTMATI(0,MATI2->R-1,0,MATI2->C-1,MATI2); 
	strcpy(buff, "lllhermitetrans.out"); 
	outfile = fopen(buff, "w"); 
	FPRINTMATI(outfile,0,MATI2->R-1,0,MATI2->C-1,MATI2); 
	fclose(outfile); 
	printf("The row echelon Form is\n"); 
	PRINTMATI(0,MATI3->R-1,0,MATI3->C-1,MATI3); 
	strcpy(buff, "lllhermitebas.out"); 
	outfile = fopen(buff, "w"); 
	FPRINTMATI(outfile,0,MATI3->R-1,0,MATI3->C-1,MATI3); 
	fclose(outfile); 
	FREEMATI(MATI1); 
	FREEMATI(MATI2); 
	FREEMATI(MATI3); 
	return; 
} 
 
void CLEMENS(MPI *N) 
/* constructs Clemens' matrix and then applies LLLHERMITE with alpha=3/4. */ 
{ 
	MPI *I; 
	USI rank; 
	USL i, j, n; 
	MPMATI *MATI1, *MATI2, *MATI3; 
 
	n = CONVERTI(N); 
	MATI1 = BUILDMATI(n, n); 
	for (j = 0; j < n; j++) 
		MATI1->V[0][j] = ONEI(); 
	for (i = 1; i < n; i++) 
		MATI1->V[i][0] = ZEROI(); 
	for (i = 1; i < n; i++) 
	{ 
		I = CHANGEI(i); 
		for (j = 1; j < n; j++) 
			MATI1->V[i][j] = MPOWER_(j, I, N); 
		FREEMPI(I); 
	} 
	PRINTMATI(0, MATI1->R -1, 0, MATI1->C -1, MATI1); 
	GetReturn(); 
	MATI2 = LLLHERMITE1(MATI1, &MATI3, &rank, 3, 4); 
	printf("The Hermite normal form = \n"); 
	PRINTMATI(0, MATI2->R -1, 0, MATI2->C -1, MATI2); 
	printf("The unimodular transformation matrix = \n"); 
	PRINTMATI(0, MATI3->R -1, 0, MATI3->C -1, MATI3); 
	FREEMATI(MATI1); 
	FREEMATI(MATI2); 
	FREEMATI(MATI3); 
} 
 
void CLEMENS1(MPI *N) 
/* constructs Clemens' matrix and then applies Kannan-Bachem. */ 
{ 
	MPI *I; 
	USI *alpha, nz; 
	USL i, j, n; 
	MPMATI *MATI1, *MATI2; 
 
	n = CONVERTI(N); 
	MATI1 = BUILDMATI(n, n); 
	for (j = 0; j < n; j++) 
		MATI1->V[0][j] = ONEI(); 
	for (i = 1; i < n; i++) 
		MATI1->V[i][0] = ZEROI(); 
	for (i = 1; i < n; i++) 
	{ 
		I = CHANGEI(i); 
		for (j = 1; j < n; j++) 
			MATI1->V[i][j] = MPOWER_(j, I, N); 
		FREEMPI(I); 
	} 
	alpha = KB_ROW(MATI1, &nz); 
	printf("rank = %u\n", nz); 
	MATI2 = HERMITE1(MATI1, alpha, nz); 
	printf("The Hermite normal form = \n"); 
	PRINTMATI(0, MATI2->R -1, 0, MATI2->C -1, MATI2); 
	FREEMATI(MATI2); 
	ffree((char *)alpha, (MATI1->C) * sizeof(USI)); 
	FREEMATI(MATI1); 
} 
 
void CLEMENS2(MPI *N) 
/* constructs Clemens' matrix and then applies Kannan-Bachem. */ 
/* Also produces the transformation matrix. */ 
{ 
	MPI *I; 
	USI *alpha, nz; 
	USL i, j, n; 
	MPMATI *MATI1, *MATI2, *MATI3, *MATI4; 
 
	n = CONVERTI(N); 
	MATI1 = BUILDMATI(n, n); 
	for (j = 0; j < n; j++) 
		MATI1->V[0][j] = ONEI(); 
	for (i = 1; i < n; i++) 
		MATI1->V[i][0] = ZEROI(); 
	for (i = 1; i < n; i++) 
	{ 
		I = CHANGEI(i); 
		for (j = 1; j < n; j++) 
			MATI1->V[i][j] = MPOWER_(j, I, N); 
		FREEMPI(I); 
	} 
	alpha = KB_ROWP(MATI1, &MATI3, &nz); 
	printf("rank = %u\n", nz); 
	MATI2 = HERMITE1P(MATI1, MATI3, &MATI4, alpha, nz); 
	FREEMATI(MATI3); 
	printf("The Hermite normal form = \n"); 
	PRINTMATI(0, MATI2->R -1, 0, MATI2->C -1, MATI2); 
	FREEMATI(MATI2); 
	printf("The unimodular transformation matrix = \n"); 
	PRINTMATI(0, MATI4->R -1, 0, MATI4->C -1, MATI4); 
	FREEMATI(MATI4); 
	ffree((char *)alpha, (MATI1->C) * sizeof(USI)); 
	FREEMATI(MATI1); 
} 
 
void AXB() 
{ 
	USI answer, m1, n1, rankA, nullA, i, j, k, r, s, flag, p, m, n; 
	MPMATI *MATI1, *MATI2, *MATI3, *MATI4, *MATI5, *MATI6, *MATI7; 
	MPMATI *Tmp, *Q, *M; 
	char buff[20]; 
	FILE *outfile; 
	MPI **XX, **X, *Temp; 
	int e; 
 
	printf("Do you wish to use an existing augmented matrix from a file? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
	{ 
		Tmp = FINPUTMATFILEI_I(); 
		if (Tmp == NULL) 
			exit (0); 
	} 
	else 
	{ 
		printf("enter the augmented matrix A|B of integers (first column non-zero) :\n"); 
		Tmp = INPUTMATI(); 
	} 
	MATI1 = TRANSPOSEI(Tmp); 
	FREEMATI(Tmp); 
	printf("The matrix entered in transposed form is\n\n"); 
	PRINTMATI(0,MATI1->R-1,0,MATI1->C-1,MATI1); 
	MLLLVERBOSE = 0; 
	printf("VERBOSE? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
		MLLLVERBOSE = 1; 
	MATI3 = IDENTITYI(MATI1->R); 
	printf("enter the parameters m1 and n1 (normally 1 and 1) :"); 
	scanf("%u %u", &m1, &n1); 
	Flush(); 
	MATI2 = BASIS_REDUCTION(MATI1, &MATI3, 0, m1, n1); 
	flag = 0; 
	r =  MATI3->R - 1; 
	s =  MATI3->C - 1; 
	k = 0; 
	while (k < r){ 
		if (!EQZEROI(MATI3->V[k][s])){ 
			flag = 1; 
			break; 
		} 
		k++; 
	} 
	if (flag){ 
		printf("No solution of AX=B\n"); 
		FREEMATI(MATI1); 
		FREEMATI(MATI2); 
		FREEMATI(MATI3); 
		MLLLVERBOSE = 0; 
		return; 
	} 
	printf("\n\n"); 
	if (MLLLVERBOSE){ 
		printf("The interim transformation matrix is\n"); 
		PRINTMATI(0,MATI3->R-1,0,MATI3->C-1,MATI3); 
		GetReturn(); 
	} 
/* 
	printf("The corresponding reduced basis for Rowspace(A^t) is\n"); 
	PRINTMATI(0,MATI2->R-1,0,MATI2->C-1,MATI2); 
	GetReturn(); 
	strcpy(buff, "axbimbas.out"); 
	outfile = fopen(buff, "w"); 
	FPRINTMATI(outfile,0,MATI2->R-1,0,MATI2->C-1,MATI2); 
	fclose(outfile); 
*/ 
	rankA = MATI2->R; 
	nullA = (MATI1->R) - (rankA + 1); 
	if (!nullA){ 
		printf("Unique solution\n"); 
		MATI6 = BUILDMATI(1, MATI1->R - 1); 
		for (j = 0; j < MATI1->R - 1; j++) 
			MATI6->V[0][j] = MINUSI(MATI3->V[MATI3->R - 1][j]); 
		FREEMATI(MATI1); 
		FREEMATI(MATI2); 
		FREEMATI(MATI3); 
		printf("The solution X of XA^t=B^t is\n"); 
		PRINTMATI(0,MATI6->R-1,0,MATI6->C-1,MATI6); 
		strcpy(buff, "axbsol.out"); 
		outfile = fopen(buff, "w"); 
		FPRINTMATI(outfile,0,MATI6->R-1,0,MATI6->C-1,MATI6); 
		fclose(outfile); 
		FREEMATI(MATI6); 
		MLLLVERBOSE = 0; 
		return; 
	} 
	MATI4 = BUILDMATI(1 + nullA, MATI1->R - 1); 
	for (i = 0; i <= nullA; i++){ 
		for (j = 0; j < MATI1->R - 1; j++){ 
			MATI4->V[i][j] = COPYI(MATI3->V[rankA + i][j]); 
		} 
        } 
        GCDFLAG = 1; 
	MATI5 = BASIS_REDUCTION0(MATI4, m1, n1); 
	MLLLVERBOSE = 0; 
	MATI6 = BUILDMATI(1, MATI1->R - 1); 
        for (j = 0; j < MATI1->R - 1; j++) 
	{ 
		(MATI5->V[MATI5->R - 1][j])->S = -((MATI5->V[MATI5->R - 1][j])->S); 
                MATI6->V[0][j] = COPYI(MATI5->V[MATI5->R - 1][j]); 
	} 
        GCDFLAG = 0; 
	MATI7 = DELETE_ROWI(MATI5->R, MATI5); 
	printf("The short basis for nullspace(A^t) is\n"); 
	PRINTMATI(0,MATI7->R-1,0,MATI7->C-1,MATI7); 
	GetReturn(); 
	strcpy(buff, "axbbas.out"); 
	outfile = fopen(buff, "w"); 
	FPRINTMATI(outfile,0,MATI7->R-1,0,MATI7->C-1,MATI7); 
	fclose(outfile); 
	p = nullA; 
	m = p + 1; 
 
	printf("A short solution X of XA^t=B^t is \n"); 
	printf("b[%u] = ",m); PRINTMATI(0,MATI6->R-1,0,MATI6->C-1,MATI6); 
/* 
	strcpy(buff, "axbsol.out"); 
	outfile = fopen(buff, "w"); 
	FPRINTMATI(outfile,0,MATI6->R-1,0,MATI6->C-1,MATI6); 
	fclose(outfile); 
*/ 
	printf("Do you want to get the shortest multipliers using Fincke_Pohst? (Y/N)\n"); 
	answer = GetYN(); 
	XX = (MPI **)mmalloc((USL)(p * sizeof(MPI *))); 
	for (j = 0; j < p; j++) 
		XX[j] = ZEROI(); 
	if (answer) 
	{ 
		GCDVERBOSE = 1; 
		Q = MATI5; 
		n = Q->R; 
		while (1) 
		{ 
			M = SHORTESTT0(Q, &X); 
			for (j = 0; j < p; j++) 
			{ 
				Temp = XX[j]; 
				XX[j] = ADDI(XX[j], X[j]); 
				FREEMPI(Temp); 
				FREEMPI(X[j]); 
			} 
			ffree((char *)X, p * sizeof(MPI *)); 
			if (M == NULL) 
				break; 
			else 
			{ 
				for (j = 0; j < Q->C; j++) 
				{ 
					FREEMPI(Q->V[n - 1][j]); 
					Q->V[n - 1][j] = COPYI(M->V[0][j]); 
				} 
				FREEMATI(MATI6); 
				MATI6 = M; 
			} 
		} 
		printf("found a shortest solution vector:\n"); 
	} 
	else 
		Q = MATI5; 
	strcpy(buff, "axb.out"); 
	outfile = fopen(buff, "w"); 
	if (answer) 
		fprintf(outfile, "A shortest solution vector is "); 
	else 
		fprintf(outfile, "A short multiplier is "); 
	if (answer) 
		printf("b[%u]", m); 
	fprintf(outfile, "b[%u]", m); 
	for (j = 0; j < p; j++) 
	{ 
		e = XX[j]->S; 
		if (e == -1) 
		{ 
			printf("+"); 
			fprintf(outfile, "+"); 
			Temp = MINUSI(XX[j]); 
			if (!EQONEI(Temp)) 
			{ 
				PRINTI(Temp); 
				FPRINTI(outfile, Temp); 
			} 
			printf("b[%u]", j + 1); 
			fprintf(outfile, "b[%u]", j + 1); 
			FREEMPI(Temp); 
		} 
		if (e == 1) 
		{ 
			printf("-"); 
			fprintf(outfile, "-"); 
			if (!EQONEI(XX[j])) 
			{ 
				PRINTI(XX[j]); 
				FPRINTI(outfile, XX[j]); 
			} 
			printf("b[%u]", j + 1); 
			fprintf(outfile, "b[%u]", j + 1); 
		} 
	} 
	printf("\n"); 
	fprintf(outfile, "\n="); 
	for (j = 0; j < p; j++) 
		FREEMPI(XX[j]); 
	ffree((char *)XX, p * sizeof(MPI *)); 
	for (i = 0; i < MATI6->C; i++) 
	{ 
		FPRINTI(outfile, MATI6->V[0][i]);  
		fprintf(outfile," "); 
		 
	} 
	fprintf(outfile,"\n"); 
	fclose(outfile); 
	GCDVERBOSE = 0; 
	FREEMATI(MATI1); 
	FREEMATI(MATI2); 
	FREEMATI(MATI3); 
	FREEMATI(MATI4); 
	FREEMATI(MATI5); 
	FREEMATI(MATI6); 
	FREEMATI(MATI7); 
	return; 
} 
 
void AXB1() 
{ 
	USI answer, m1, n1, nullA, i, j, p, m, n; 
	USI rank, t, u, v; 
	MPMATI *MATI1, *MATI2, *MATI3, *MATI5, *MATI6, *MATI7; 
	MPMATI *Tmp, *Tmp1, *Q, *M; 
	char buff[20]; 
	FILE *outfile; 
	MPI **XX, **X, *Temp; 
	int e; 
 
	printf("Do you wish to use an existing augmented matrix from a file? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
	{ 
		Tmp = FINPUTMATFILEI_I(); 
		if (Tmp == NULL) 
			exit (0); 
	} 
	else 
	{ 
		printf("enter the augmented matrix A|B of integers (first column non-zero) :\n"); 
		Tmp = INPUTMATI(); 
	} 
	Tmp1 = TRANSPOSEI(Tmp); 
	FREEMATI(Tmp); 
	printf("The matrix entered in transposed form is\n\n"); 
	PRINTMATI(0,Tmp1->R-1,0,Tmp1->C-1,Tmp1); 
	u = Tmp1->R; 
	v = Tmp1->C + 1; 
	MATI1 = BUILDMATI(u, v); 
	for (i = 0; i < u; i++){ 
		for (j = 0; j < v-1; j++) 
			MATI1->V[i][j] = COPYI(Tmp1->V[i][j]);	 
		MATI1->V[i][v - 1] = ZEROI(); 
	} 
	FREEMPI(MATI1->V[u - 1][v - 1]); 
	MATI1->V[u - 1][v - 1] = ONEI();	 
	FREEMATI(Tmp1); 
	HERMITE1VERBOSE = 0; 
	printf("VERBOSE? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
		HERMITE1VERBOSE = 1; 
	printf("enter the parameters m1 and n1 (normally 1 and 1) :"); 
	scanf("%u %u", &m1, &n1); 
	Flush(); 
	MATI3 = LLLHERMITE1(MATI1, &MATI2, &rank, m1, n1); 
 
	if (HERMITE1VERBOSE) 
	{ 
		printf("MATI2=\n\n"); 
		PRINTMATI(0,MATI2->R-1,0,MATI2->C-1,MATI2); 
		GetReturn(); 
		printf("MATI3=\n\n"); 
		PRINTMATI(0,MATI3->R-1,0,MATI3->C-1,MATI3); 
		GetReturn(); 
	} 
	strcpy(buff, "axbtrans.out"); 
	outfile = fopen(buff, "w"); 
	FPRINTMATI(outfile,0,MATI3->R-1,0,MATI3->C-1,MATI3); 
	fclose(outfile); 
	HERMITE1VERBOSE = 0; 
	t = EQONEI(MATI2->V[rank - 1][v - 1]); 
	if (t != 1){ 
		printf("No solution of AX=B\n"); 
		FREEMATI(MATI1); 
		FREEMATI(MATI2); 
		FREEMATI(MATI3); 
		return; 
	} 
	printf("\n\n"); 
	nullA = (MATI3->R) - rank; 
	if (!nullA){ 
		printf("Unique solution\n"); 
		MATI6 = BUILDMATI(1, MATI1->R - 1); 
		for (j = 0; j < MATI1->R - 1; j++) 
			MATI6->V[0][j] = MINUSI(MATI3->V[rank - 1][j]); 
		FREEMATI(MATI1); 
		FREEMATI(MATI2); 
		FREEMATI(MATI3); 
		printf("The solution X of XA^t=B^t is\n"); 
		PRINTMATI(0,MATI6->R-1,0,MATI6->C-1,MATI6); 
		strcpy(buff, "axbsol.out"); 
		outfile = fopen(buff, "w"); 
		FPRINTMATI(outfile,0,MATI6->R-1,0,MATI6->C-1,MATI6); 
		fclose(outfile); 
		FREEMATI(MATI6); 
		return; 
	} 
	v = MATI3->C - 1; 
	MATI5 = BUILDMATI(u + 1 - rank, v); 
        for (i = 0; i < u - rank; i++){ 
		for (j = 0; j < v; j++){ 
			MATI5->V[i][j] = COPYI(MATI3->V[i + rank][j]); 
		} 
	} 
	for (j = 0; j < v; j++){ 
		MATI5->V[u - rank][j] = MINUSI(MATI3->V[rank - 1][j]); 
	} 
	MATI6 = BUILDMATI(1, MATI5->C); 
        for (j = 0; j < MATI5->C; j++) 
                MATI6->V[0][j] = COPYI(MATI5->V[MATI5->R - 1][j]); 
	MATI7 = DELETE_ROWI(MATI5->R, MATI5); 
	printf("The short basis of %u vectors for nullspace(A^t):\n", nullA); 
	PRINTMATI(0,MATI7->R-1,0,MATI7->C-1,MATI7); 
	GetReturn(); 
	strcpy(buff, "axbbas.out"); 
	outfile = fopen(buff, "w"); 
	FPRINTMATI(outfile,0,MATI7->R-1,0,MATI7->C-1,MATI7); 
	fclose(outfile); 
	p = nullA; 
	m = p + 1; 
 
	printf("\n\n"); 
	printf("A short solution X of XA^t=B^t: \n"); 
	printf("b[%u] = ",m); PRINTMATI(0,MATI6->R-1,0,MATI6->C-1,MATI6); 
 
	printf("\n\n"); 
	printf("Do you want to get a shortest solution using Fincke_Pohst? (Y/N)\n"); 
	answer = GetYN(); 
	XX = (MPI **)mmalloc((USL)(p * sizeof(MPI *))); 
	for (j = 0; j < p; j++) 
		XX[j] = ZEROI(); 
	if (answer) 
	{ 
		GCDVERBOSE = 1; 
		Q = MATI5; 
		n = Q->R; 
		while (1) 
		{ 
			M = SHORTESTT0(Q, &X); 
			for (j = 0; j < p; j++) 
			{ 
				Temp = XX[j]; 
				XX[j] = ADDI(XX[j], X[j]); 
				FREEMPI(Temp); 
				FREEMPI(X[j]); 
			} 
			ffree((char *)X, p * sizeof(MPI *)); 
			if (M == NULL) 
				break; 
			else 
			{ 
				for (j = 0; j < Q->C; j++) 
				{ 
					FREEMPI(Q->V[n - 1][j]); 
					Q->V[n - 1][j] = COPYI(M->V[0][j]); 
				} 
				FREEMATI(MATI6); 
				MATI6 = M; 
			} 
		} 
		printf("found a shortest solution vector:\n"); 
	} 
	else 
		Q = MATI5; 
	strcpy(buff, "axb.out"); 
	outfile = fopen(buff, "w"); 
	if (answer) 
		fprintf(outfile, "A shortest solution is "); 
	else 
		fprintf(outfile, "A short solution is "); 
	if (answer) 
		printf("b[%u]", m); 
	fprintf(outfile, "b[%u]", m); 
	for (j = 0; j < p; j++) 
	{ 
		e = XX[j]->S; 
		if (e == -1) 
		{ 
			printf("+"); 
			fprintf(outfile, "+"); 
			Temp = MINUSI(XX[j]); 
			if (!EQONEI(Temp)) 
			{ 
				PRINTI(Temp); 
				FPRINTI(outfile, Temp); 
			} 
			printf("b[%u]", j + 1); 
			fprintf(outfile, "b[%u]", j + 1); 
			FREEMPI(Temp); 
		} 
		if (e == 1) 
		{ 
			printf("-"); 
			fprintf(outfile, "-"); 
			if (!EQONEI(XX[j])) 
			{ 
				PRINTI(XX[j]); 
				FPRINTI(outfile, XX[j]); 
			} 
			printf("b[%u]", j + 1); 
			fprintf(outfile, "b[%u]", j + 1); 
		} 
	} 
	printf("\n"); 
	fprintf(outfile, "\n="); 
	for (i = 0; i < MATI6->C; i++) 
	{ 
		FPRINTI(outfile, MATI6->V[0][i]);  
		fprintf(outfile," "); 
		 
	} 
	fprintf(outfile,"\n"); 
	fclose(outfile); 
	if (answer) 
	{ 
		printf("Do you want to get all the shortest multipliers? (Y/N)\n"); 
		answer = GetYN(); 
		if (answer) 
			SHORTEST(Q, XX, 5, 1); 
	} 
	for (j = 0; j < p; j++) 
		FREEMPI(XX[j]); 
	ffree((char *)XX, p * sizeof(MPI *)); 
	GCDVERBOSE = 0; 
	FREEMATI(MATI1); 
	FREEMATI(MATI2); 
	FREEMATI(MATI3); 
	FREEMATI(MATI5); 
	FREEMATI(MATI6); 
	FREEMATI(MATI7); 
	return; 
} 
 
void TESTAXB() 
{ 
	USI m1, n1, nullA, g, i, j, k, p, m, n, row, col; 
	USI rank, u, v, power, trial_no, answer; 
	MPMATI *MATI1, *MATI2, *MATI3, *MATI5, *MATI6, *MATI7; 
	MPMATI *Tmp1, *Q, *M, *TMATI1; 
	char buff[20]; 
	FILE *outfile; 
	MPI **XX, **X, *Temp, *MULTIPLIER, *SEED, *BASE, *temp, *T1, *T2; 
	MPR *ratio; 
	int e, equality; 
 
	strcpy(buff, "testaxb.out"); 
	if(access(buff, R_OK) == 0) 
	  unlink(buff); 
	outfile = fopen(buff, "a"); 
	printf("Enter alpha=m/n,  1/4 < m/n <= 1:  (ie enter  m  and n)"); 
        scanf("%u%u", &m1, &n1); 
        printf("Enter the power of 2: "); 
        scanf("%u", &power); 
        BASE = POWER_I((long)2, power); 
        printf("Enter row and column size: "); 
        scanf("%u%u", &row, &col); 
        printf("Enter number of trials: "); 
        scanf("%u", &trial_no); 
	Flush(); 
        printf("Enter the (odd) seed (eg 1): "); 
	SEED = INPUTI(&g); 
        printf("Enter the multiplier (4k+1, n odd) (eg 96069): "); 
	MULTIPLIER = INPUTI(&g); 
        printf("small random X? (Y/N)"); 
	answer = GetYN(); 
	for (k = 0; k < trial_no; k++) 
	{ 
		printf("k = %u\n", k); 
		if (answer) 
			TMATI1 = RANDOM_MATRIXA3(row, col, SEED, MULTIPLIER, BASE); 
		else 
			TMATI1 = RANDOM_MATRIXA(row, col, SEED, MULTIPLIER, BASE); 
/* 
		printf("TMATI1 :\n"); 
		PRINTMATI(0,TMATI1->R-1,0,TMATI1->C-1,TMATI1); 
		GetReturn(); 
*/ 
		temp = SEED; 
		SEED = RANDOMI(SEED, MULTIPLIER, BASE); 
		FREEMPI(temp); 
		Tmp1 = TRANSPOSEI(TMATI1); 
		FREEMATI(TMATI1); 
		u = Tmp1->R; 
		v = Tmp1->C + 1; 
		MATI1 = BUILDMATI(u, v); 
		for (i = 0; i < u; i++){ 
			for (j = 0; j < v-1; j++) 
				MATI1->V[i][j] = COPYI(Tmp1->V[i][j]);	 
			MATI1->V[i][v - 1] = ZEROI(); 
		} 
		FREEMPI(MATI1->V[u - 1][v - 1]); 
		MATI1->V[u - 1][v - 1] = ONEI();	 
		FREEMATI(Tmp1); 
		MATI3 = LLLHERMITE1(MATI1, &MATI2, &rank, m1, n1); 
		nullA = (MATI3->R) - rank; 
		v = MATI3->C - 1; 
		MATI5 = BUILDMATI(u + 1 - rank, v); 
		for (i = 0; i < u - rank; i++){ 
			for (j = 0; j < v; j++){ 
				MATI5->V[i][j] = COPYI(MATI3->V[i + rank][j]); 
			} 
		} 
		for (j = 0; j < v; j++) 
			MATI5->V[u - rank][j] = MINUSI(MATI3->V[rank - 1][j]); 
		MATI6 = BUILDMATI(1, MATI5->C); 
		for (j = 0; j < MATI5->C; j++) 
			MATI6->V[0][j] = COPYI(MATI5->V[MATI5->R - 1][j]); 
/* 
		printf("Short solution :\n"); 
		PRINTMATI(0,MATI6->R-1,0,MATI6->C-1,MATI6); 
		GetReturn(); 
*/ 
		T1 = LENGTHSQRI(MATI6, 0); 
		MATI7 = DELETE_ROWI(MATI5->R, MATI5); 
/* 
		printf("The short basis of %u vectors for nullspace(A^t):\n", nullA); 
		PRINTMATI(0,MATI7->R-1,0,MATI7->C-1,MATI7); 
		GetReturn(); 
*/ 
		p = nullA; 
		m = p + 1; 
 
 
		XX = (MPI **)mmalloc((USL)(p * sizeof(MPI *))); 
		for (j = 0; j < p; j++) 
			XX[j] = ZEROI(); 
		Q = MATI5; 
		n = Q->R; 
		while (1) 
		{ 
			M = SHORTESTT0(Q, &X); 
			for (j = 0; j < p; j++) 
			{ 
				Temp = XX[j]; 
				XX[j] = ADDI(XX[j], X[j]); 
				FREEMPI(Temp); 
				FREEMPI(X[j]); 
			} 
			ffree((char *)X, p * sizeof(MPI *)); 
			if (M == NULL) 
				break; 
			else 
			{ 
				for (j = 0; j < Q->C; j++) 
				{ 
					FREEMPI(Q->V[n - 1][j]); 
					Q->V[n - 1][j] = COPYI(M->V[0][j]); 
				} 
				FREEMATI(MATI6); 
				MATI6 = M; 
			} 
		} 
		T2 = LENGTHSQRI(MATI6, 0); 
/* 
		printf("Shortest solution :\n"); 
		PRINTMATI(0,MATI6->R-1,0,MATI6->C-1,MATI6); 
		GetReturn(); 
*/ 
		equality = EQUALI(T1,T2); 
		if(!equality) 
		{ 
			ratio = RATIOI(T1, T2); 
			FREEMPI(T1);  
			FREEMPI(T2);  
			fprintf(outfile, "%u:", k); 
			FPRINTDR(outfile, 3, ratio); 
			FREEMPR(ratio);  
			fprintf(outfile, ":b[%u]", m); 
			for (j = 0; j < p; j++) 
			{ 
				e = XX[j]->S; 
				if (e == -1) 
				{ 
					fprintf(outfile, "+"); 
					Temp = MINUSI(XX[j]); 
					if (!EQONEI(Temp)) 
						FPRINTI(outfile, Temp); 
					fprintf(outfile, "b[%u]", j + 1); 
					FREEMPI(Temp); 
				} 
				if (e == 1) 
				{ 
					fprintf(outfile, "-"); 
					if (!EQONEI(XX[j])) 
						FPRINTI(outfile, XX[j]); 
					fprintf(outfile, "b[%u]", j + 1); 
				} 
			} 
/* 
			fprintf(outfile, "\n="); 
			for (i = 0; i < MATI6->C; i++) 
			{ 
				FPRINTI(outfile, MATI6->V[0][i]);  
				fprintf(outfile," "); 
				 
			} 
*/ 
			fprintf(outfile,"\n"); 
		} 
		else 
                { 
			FREEMPI(T1); 
			FREEMPI(T2); 
		} 
	for (j = 0; j < p; j++) 
		FREEMPI(XX[j]); 
	ffree((char *)XX, p * sizeof(MPI *)); 
		FREEMATI(MATI1); 
		FREEMATI(MATI2); 
		FREEMATI(MATI3); 
		FREEMATI(MATI5); 
		FREEMATI(MATI6); 
		FREEMATI(MATI7); 
	} 
	FREEMPI(BASE); 
	FREEMPI(MULTIPLIER); 
	FREEMPI(SEED); 
	fclose(outfile); 
 
	return; 
} 
void CHANGELX(MPI *M) 
{ 
	USL n; 
	MPI *N; 
	int s; 
	long m; 
 
	s = M->S; 
	printf("M->D = %u\n", M->D); 
	n = CONVERTI(M); 
	printf("n = %lu\n", n); 
	m = n; 
	printf("m = %ld\n", m); 
	if (s == -1) 
		m = -m; 
	N = CHANGEL(m); 
	printf("CHANGEL(n)=");PRINTI(N);printf("\n"); 
	FREEMPI(N); 
	return; 
} 
 
void LLLGCD0X() 
/* 
 * This executes the LLLGCD algorithm of Havas, Majewski and Matthews. 
 * with a search for short multipliers using the method of Matthews. 
 * 17/12/98. 
 */ 
{ 
	USI answer, m1, n1, m, n, i, j, p; 
	int e; 
	MPMATI *MATI1, *MATI2, *Q, *M, *MATI3; 
	char buff[20]; 
	FILE *outfile; 
	MPI *A, *T, **XX, **X, *Temp; 
 
	HAVASFLAG = 1; 
	printf("Do you wish to enter your sequence of numbers from an existing column matrix? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
	{ 
		MATI1 = FINPUTMATFILEI_I(); 
		if (MATI1 == NULL) 
			exit (0); 
	} 
	else 
	{ 
		printf("WARNING: Make sure the first integer in the sequence is non-zero) :\n"); 
		MATI1 = INPUTMATI(); 
	} 
	printf("The matrix entered is\n\n"); 
	PRINTMATI(0,MATI1->R-1,0,MATI1->C-1,MATI1); 
	GCDVERBOSE = 0; 
	printf("VERBOSE? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
		GCDVERBOSE = 1; 
	printf("to enter alpha=m1/n1: select m1 and n1 (normally 1 and 1) :"); 
	scanf("%u %u", &m1, &n1); 
	Flush(); 
	m = MATI1->R; 
	MATI2 = LLLGCD0(MATI1, &A, m, m1, n1); 
	FREEMATI(MATI1); 
	MATI3 = BUILDMATI(1, m); 
	for (i = 0;i < m;i++) 
		MATI3->V[0][i] = COPYI(MATI2->V[m - 1][i]);  
	printf("\n"); 
	printf("The multiplier matrix found by LLL is\n"); 
	PRINTMATI(0,MATI2->R-1,0,MATI2->C-1,MATI2); 
	printf("gcd = "); PRINTI(A); printf("\n"); 
	GetReturn(); 
	FREEMPI(A); 
	printf("Do you want to get a shortest multiplier using Fincke_Pohst? (Y/N)\n"); 
	answer = GetYN(); 
	p = m - 1; 
	XX = (MPI **)mmalloc((USL)(p * sizeof(MPI *))); 
	for (j = 0; j < p; j++) 
		XX[j] = ZEROI(); 
	if (answer) 
	{ 
		GCDVERBOSE = 1; 
		Q = MATI2; 
		n = Q->R; 
		while (1) 
		{ 
			M = SHORTESTT0(Q, &X); 
			for (j = 0; j < p; j++) 
			{ 
				Temp = XX[j]; 
				XX[j] = ADDI(XX[j], X[j]); 
				FREEMPI(Temp); 
				FREEMPI(X[j]); 
			} 
			ffree((char *)X, p * sizeof(MPI *)); 
			if (M == NULL) 
				break; 
			else 
			{ 
				for (j = 0; j < Q->C; j++) 
				{ 
					FREEMPI(Q->V[n - 1][j]); 
					Q->V[n - 1][j] = COPYI(M->V[0][j]); 
				} 
				FREEMATI(MATI3); 
				MATI3 = M; 
			} 
		} 
		printf("found a shortest multiplier vector:\n"); 
	} 
	else 
		Q = MATI2; 
	strcpy(buff, "lllgcd0mat.out"); 
	outfile = fopen(buff, "w"); 
	FPRINTMATI(outfile,0,Q->R-1,0,Q->C-1,Q); 
	fclose(outfile); 
	strcpy(buff, "lllgcd0mult.out"); 
	outfile = fopen(buff, "a"); 
	if (answer) 
	{ 
		fprintf(outfile, "A Shortest multiplier is "); 
		printf("b[%u]", m); 
		fprintf(outfile, "b[%u]", m); 
	} 
	for (j = 0; j < p; j++) 
	{ 
		e = XX[j]->S; 
		if (e == -1) 
		{ 
			printf("+"); 
			fprintf(outfile, "+"); 
			Temp = MINUSI(XX[j]); 
			if (!EQONEI(Temp)) 
			{ 
				PRINTI(Temp); 
				FPRINTI(outfile, Temp); 
			} 
			printf("b[%u]", j + 1); 
			fprintf(outfile, "b[%u]", j + 1); 
			FREEMPI(Temp); 
		} 
		if (e == 1) 
		{ 
			printf("-"); 
			fprintf(outfile, "-"); 
			if (!EQONEI(XX[j])) 
			{ 
				PRINTI(XX[j]); 
				FPRINTI(outfile, XX[j]); 
			} 
			printf("b[%u]", j + 1); 
			fprintf(outfile, "b[%u]", j + 1); 
		} 
	} 
	if (answer) 
	{ 
		printf("="); 
		fprintf(outfile,"="); 
		for (i = 0; i < MATI3->C; i++) 
		{ 
			PRINTI(MATI3->V[0][i]);  
			FPRINTI(outfile, MATI3->V[0][i]);  
			fprintf(outfile," "); 
			printf(" "); 
		} 
		printf(": "); 
		fprintf(outfile,": "); 
		T = LENGTHSQRI(MATI3, 0); 
		PRINTI(T); 
		printf("\n"); 
		FPRINTI(outfile, T); 
		fprintf(outfile,"\n"); 
		FREEMPI(T); 
	} 
	fclose(outfile); 
	if (answer) 
	{ 
		printf("Do you want to get all the shortest multipliers? (Y/N)\n"); 
		answer = GetYN(); 
		if (answer) 
			SHORTEST(Q, XX, 3, 1); 
	} 
	for (j = 0; j < p; j++) 
		FREEMPI(XX[j]); 
	ffree((char *)XX, p * sizeof(MPI *)); 
	FREEMATI(MATI3); 
	FREEMATI(Q); 
	GCDVERBOSE = 0; 
	HAVASFLAG = 0; 
	return; 
} 
 
void SLVECTORX() 
{ 
	USI answer, i, j, m, n; 
	MPMATI *MATI1; 
	MPMATR *M; 
	MPR *C, *D, *tempR, *VALUE; 
 
	printf("Do you wish to use an existing matrix from a file? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
	{ 
		MATI1 = FINPUTMATFILEI_I(); 
		if (MATI1 == NULL) 
			exit (0); 
	} 
	else 
	{ 
		printf("enter the matrix of integers (first row non-zero) :\n"); 
		MATI1 = INPUTMATI(); 
	} 
	printf("The matrix entered is\n\n"); 
	PRINTMATI(0,MATI1->R-1,0,MATI1->C-1,MATI1); 
	C = BUILDMPR(); 
	C->N = LENGTHSQRI(MATI1, 0); 
	C->D = ONEI(); 
	m = MATI1->R; 
	n = MATI1->C; 
	M = BUILDMATR(m, n); 
	for (i = 0; i < m; i++) 
	{ 
		for (j = 0; j < n; j++) 
		{ 
			elt(M, i, j) = BUILDMPR(); 
			elt(M, i, j)->N = COPYI(MATI1->V[i][j]); 
			elt(M, i, j)->D = ONEI(); 
		} 
	} 
	FREEMATI(MATI1); 
	D = ZEROR(); 
	while ((C->N)->S) 
	{ 
		tempR = C; 
		C = SLVECTOR(M, C, &VALUE); 
		if (VALUE != NULL) 
		{ 
			FREEMPR(D); 
			D = COPYR(VALUE); 
			FREEMPR(VALUE); 
		} 
		FREEMPR(tempR); 
	} 
	FREEMPR(C); 
	FINCKE_POHST(M, D, 2); 
	FREEMPR(D); 
	FREEMATR(M); 
	return; 
} 
 
void GCD_CONJ() 
/* 
 * This tests a conjecture on the location of the shortest multipliers 
 * in the extended GCD problem. See paper off lll.html. 
 * Here we first get the matrices L (the mu{{ij}) and B (the LLLGCD 
 * trnaformation matrix. Then we test all the shortest multipliers to 
 * see if the associated X[0],...,X[m-2] satisfy the conjecture that 
 * |X[k]+SIGMA[k]| < 1 holds. 
 */ 
{ 
	USI answer, m1, n1, m, n, i, j, p, count; 
	int r, t, K; 
	MPMATI *MATI1, *MATI2, *Q, *M, *MATI3; 
	char buff[20]; 
	FILE *outfile; 
	MPI *A, **XX, **X, *Temp, ***COEFF, *tempI, *T; 
	MPMATR *LMATRIX; 
	MPR **SIGMA, *SUMR, *tR1, *tR2, *tR3, *tempR, *tempR1; 
 
	HAVASFLAG = 1; 
	printf("Do you wish to enter your sequence of numbers from an existing column matrix? (Y/N)\n"); 
	answer = GetYN(); 
	if (answer) 
	{ 
		MATI1 = FINPUTMATFILEI_I(); 
		if (MATI1 == NULL) 
			exit (0); 
	} 
	else 
	{ 
		printf("WARNING: Make sure the first integer in the sequence is non-zero) :\n"); 
		MATI1 = INPUTMATI(); 
	} 
	printf("The matrix entered is\n\n"); 
	PRINTMATI(0,MATI1->R-1,0,MATI1->C-1,MATI1); 
	printf("to enter alpha=m1/n1: select m1 and n1 (normally 1 and 1) :"); 
	scanf("%u %u", &m1, &n1); 
	Flush(); 
	m = MATI1->R; 
	MATI2 = LLLGCDL(MATI1, &A, m, m1, n1, &LMATRIX); 
	printf("The multiplier matrix found by LLL is\n"); 
	PRINTMATI(0,MATI2->R-1,0,MATI2->C-1,MATI2); 
	printf("gcd = "); PRINTI(A); printf("\n"); 
	FREEMPI(A); 
	printf("The multiplier vector found by LLL is b[%u]=", m); 
	for (i = 0;i < MATI2->R;i++) 
	{ 
		PRINTI(MATI2->V[MATI2->R - 1][i]);  
		printf(" "); 
	} 
	printf("\n"); 
	MATI3 = BUILDMATI(1, m); 
	for (i = 0;i < m;i++) 
		MATI3->V[0][i] = COPYI(MATI2->V[m - 1][i]);  
	T = LENGTHSQRI(MATI3, 0); 
	printf("The Euclidean norm squared = "); 
	PRINTI(T); 
	FREEMPI(T); 
	printf("\n"); 
	p = m - 1; 
	XX = (MPI **)mmalloc((USL)(p * sizeof(MPI *))); 
	for (j = 0; j < p; j++) 
		XX[j] = ZEROI(); 
 
	Q = MATI2; 
	n = Q->R; 
	while (1) 
	{ 
		M = SHORTESTT0(Q, &X); 
		for (j = 0; j < p; j++) 
		{ 
			Temp = XX[j]; 
			XX[j] = ADDI(XX[j], X[j]); 
			FREEMPI(Temp); 
			FREEMPI(X[j]); 
		} 
		ffree((char *)X, p * sizeof(MPI *)); 
		if (M == NULL) 
			break; 
		else 
		{ 
			for (j = 0; j < Q->C; j++) 
			{ 
				FREEMPI(Q->V[n - 1][j]); 
				Q->V[n - 1][j] = COPYI(M->V[0][j]); 
			} 
			FREEMATI(MATI3); 
			MATI3 = M; 
		} 
	} 
	printf("found a shortest multiplier lengthsquared:\n"); 
	T = LENGTHSQRI(MATI3, 0); 
	printf(" = "); 
	PRINTI(T); 
	printf("\n"); 
	FREEMPI(T); 
 
        strcpy(buff, "gcdconj.out"); 
	if(access(buff, R_OK) == 0) 
	  unlink(buff); 
	outfile = fopen(buff, "a"); 
 
 
	COEFF = SHORTESTX(Q, XX, &count); 
 
	for (j = 0; j < count; j++) 
	{ 
		printf("COEFF[%u] = ", j + 1); 
		fprintf(outfile, "COEFF[%u] = ", j + 1); 
		for (i = 0; i < p; i++) 
		{ 
			PRINTI(COEFF[j][i]); 
			FPRINTI(outfile, COEFF[j][i]); 
			printf(" "); 
			fprintf(outfile, " "); 
		} 
		printf("\n"); 
		fprintf(outfile, "\n"); 
	} 
	for (j = 0; j < p; j++) 
		FREEMPI(XX[j]); 
	ffree((char *)XX, p * sizeof(MPI *)); 
	SIGMA = (MPR **)mmalloc(p * sizeof(MPR *)); 
	for (j = 0; j < count; j++) 
	{ 
		for (K = p - 1; K >= 0; K--) 
		{ 
			SUMR = COPYR(elt(LMATRIX, m - 1, K)); 
			for (r = p - 1; r > K; r--) 
			{ 
				tR2 = COPYR(elt(LMATRIX, r, K)); 
				tempR = BUILDMPR(); 
				tempR->N = COPYI(COEFF[j][r]); 
				tempR->D = ONEI(); 
				tR3 = MULTR(tR2, tempR); 
				FREEMPR(tempR); 
				FREEMPR(tR2); 
				tR1 = SUMR; 
				SUMR = ADDR(SUMR, tR3); 
				FREEMPR(tR1); 
				FREEMPR(tR3); 
			} 
			SIGMA[K] = SUMR; 
			tempR = BUILDMPR(); 
			tempR->N = COPYI(COEFF[j][K]); 
			tempR->D = ONEI(); 
			tempR1 = ADDR(tempR, SIGMA[K]); 
			tempI = ABSI(tempR1->N); 
			t = RSV(tempI, tempR1->D); 
			FREEMPR(tempR); 
			FREEMPR(tempR1); 
			FREEMPI(tempI); 
			if (t >= 0) 
			{ 
				fprintf(stderr, "conjecture false for SIGMA[%u]: K = %d\n", j + 1, K + 1); 
				fprintf(outfile, "conjecture false for SIGMA[%u]: K = %d\n", j + 1, K + 1); 
			} 
		} 
		printf("COEFF[%u], ", j + 1); 
		fprintf(outfile, "COEFF[%u], ", j + 1); 
		printf("SIGMA[%u]:\n", j + 1); 
		fprintf(outfile, "SIGMA[%u]:\n", j + 1); 
		for (K = 0; K < p; K++) 
		{ 
			printf("COEFF[%u][%d]=",j + 1, K + 1); 
			fprintf(outfile, "COEFF[%u][%d]=",j + 1, K + 1); 
			PRINTI(COEFF[j][K]); 
			FPRINTI(outfile, COEFF[j][K]); 
			printf(", "); 
			fprintf(outfile, ", "); 
			printf("SIGMA[%u][%d]=", j + 1, K + 1); 
			fprintf(outfile, "SIGMA[%u][%d]=", j + 1, K + 1); 
			PRINTR(SIGMA[K]); 
			FPRINTR(outfile, SIGMA[K]); 
			printf("\n"); 
			fprintf(outfile, "\n"); 
			FREEMPR(SIGMA[K]); 
		} 
		printf("\n"); 
		fprintf(outfile, "\n"); 
	} 
	fclose(outfile); 
	ffree((char *)SIGMA, p * sizeof(MPR *)); 
 
	for (j = 0; j < count; j++) 
	{ 
		for (i = 0; i < p; i++) 
			FREEMPI(COEFF[j][i]); 
		ffree((char *)COEFF[j], p * sizeof(MPI *)); 
	} 
	ffree((char *)COEFF, GCD_MAX * sizeof(MPI **)); 
	FREEMATI(MATI3); 
	FREEMATI(MATI1); 
	FREEMATI(Q); 
	FREEMATR(LMATRIX); 
	HAVASFLAG = 0; 
	return; 
} 
 
MPI *LEASTQNRX(MPI *P) 
/* 
 * Returns NP, the least quadratic non-residue (mod P) 
 * if NP < R0, else returns 0. 
 */ 
{ 
	MPI *NP, *T; 
	int t; 
 
	if (P->S <= 0 || (P->D == 0 && P->V[0] <= 2)) 
	{ 
	  printf("P <= 2\n"); 
	  return NULL; 
	} 
	T = LUCAS(P); 
	t = T->S; 
	FREEMPI(T); 
	if (!t) 
	{ 
	  PRINTI(P); 
	  printf(" is not a prime\n"); 
	  return NULL; 
	} 
	NP = LEASTQNR(P); 
	if (NP->S == 0) 
	{ 
		fprintf(stderr, "np > %lu\n", (USL)R0); 
		printf("search failed\n"); 
		return NULL; 
	}	 
	else 
		return (NP); 
}