
/*****************************************************************************\

MODULE: LLL

SUMMARY:

Routines are provided for lattice basis reduction.

\*****************************************************************************/

#include "mat_ZZ.h"

long LLL(ZZ& det, matrix(ZZ)& B, long verbose = 0);
long LLL(ZZ& det, matrix(ZZ)& B, matrix(ZZ)& U, long verbose = 0);

long LLL(ZZ& det, matrix(ZZ)& B, long a, long b, long verbose = 0);
long LLL(ZZ& det, matrix(ZZ)& B, matrix(ZZ)& U, long a, long b, 
         long verbose = 0);


// performs LLL reduction.
// B is an m x n matrix, viewed as m rows of n-vectors.
// m may be less than, equal to, or greater than n, and 
// the rows need not be linearly independent.
// B is transformed into an LLL-reduced basis, and the return value
// is the rank r of B.  The first m-r rows of B are zero.
// det is calculated as the determinant of the lattice
// (for nonsingular square matrices B, this is det(B)^2).
// In the second version, U is set to the transformation matrix,
// so that U is a unimodular m x m matrix with U * old-B = new-B.
// In both of these versions, the reduction parameter is 3/4
// (as in the original LLL algorithm).
// The third and fourth versions allow an arbitrary reduction
// parameter a/b, where 1/4 < a/b <= 1, where a and b are positive integers.


// The algorithm employed is essentially that of de Weger
// [Algorithms for Diophantine Equations, Disseration,
// CWI, Amsterdam, 1988], modified to allow linear dependent 
// inputs.


long image(ZZ& det, matrix(ZZ)& B, long verbose = 0);
long image(ZZ& det, matrix(ZZ)& B, matrix(ZZ)& U, long verbose = 0);

// This computes the image of B using a cheap version of LLL algorithm.
// As above the return value is the rank r of B, and the first
// m-r rows will be zero.  U is a unimodular m x m matrix
// with U * old-B = new-B.
// det is calculated as the determinant of the lattice
// (for nonsingular square matrices B, this is det(B)^2).


typedef long (*LLLCheckFct)(const vector(ZZ)&);

long LLL_FP(matrix(ZZ)& B, double delta = 0.99, long deep = 0,
           LLLCheckFct check = 0);
long LLL_FP(matrix(ZZ)& B, matrix(ZZ)& U, double delta = 0.99, long deep = 0,
           LLLCheckFct check = 0);



// These routines have the same semantics as the LLL routines above.
// The difference is that these routines implement the Schnorr-Euchner
// algorithm [C. P. Schnorr and M. Euchner, Proc. Fundamentals of
// Computation Theory, LNCS 529, pp. 68-85, 1991].

// This algorithm uses (double precision) floating point approximations,
// and due to round-off errors, it is not guaranteed to terminate,
// and it is also possible that the resulting basis is not actually
// LLL reduced.  
// Also note that because of the double precision approximations,
// the entries in the input basis should not too big (more than
// about 500 bits each); otherwise, overflow will occur and
// the results are unpredictable...in this case you need to use
// the routine LLL_XD (or BKZ_XD), see below.
// Despite these limitations, the algorithm produces very
// good results in practice and is significantly faster than LLL.


// The optional argument delta is the reduction parameter, and may be
// set so that 0.25 < delta <= 1.  
// Setting it close to 1 yields shorter vectors, but increases the
// running time.  It is recommended to keep delta bounded away
// from 0.25 and 1.

// The optional parameter deep can be set to any positive integer,
// which allows deep insertions of row k into row i, 
// provided i <= deep or k-i <= deep. 
// Larger values of deep will usually yield shorter vectors,
// but the running increases exponentially.

// The optional parameter check is function that
// is invoked after a size reduction with the current row
// as an argument.
// If this function returns a non-zero value, the LLL procedure
// is immediately terminated.
// Note that it is possible that some linear dependencies remain
// undiscovered, so that the calculated rank value is in fact too large.
// In any case, any zero rows in the final matrix will be, as usual,
// placed at the beginning.

long BKZ_FP(matrix(ZZ)& BB, double delta=0.99, long BlockSize=10, long prune=0,
         LLLCheckFct check = 0);

long BKZ_FP(matrix(ZZ)& BB, matrix(ZZ)& U, double delta=0.99,
         long BlockSize=10, long prune=0, LLLCheckFct check = 0);


// This routine implements the Block Korkin-Zolotarev reduction
// algorithm as described in [Schnorr and Euchner, loc. cit.].

// In the second version, the matrix U is set to the transformation
// matrix, so that new-B = U * old-B.

// The optional argument delta is the reduction parameter, and may be
// set so that 0.25 < delta <= 1.  
// Setting it close to 1 yields shorter vectors, but increases the
// running time.  It is recommended to keep delta bounded away
// from 0.25 and 1.

// The optional parameter BlockSize specifies the size of the
// blocks in the reduction.  High values yield shorter vectors,
// but the running time increases exponentially.

// The optional parameter prune may be set to 1, which causes
// the pruning heuristic in [Schnorr and Euchner, loc. cit.]
// to be used.  This is useful in conjunction with large BlockSize;
// the computation runs faster, but the quality of the resulting basis
// is not as good.

// The optional parameter check is function that
// is invoked from time to time on rows in the matrix.
// If this function returns a non-zero value, the BKZ procedure
// is immediately terminated.

// The return value is the rank of B.
// All zero vectors in the reduced basis are placed at the beginning.
// The rank might be overestimated if the check routine causes
// termination before all linear dependencies are discovered.

// As in LLL_FP, these algorithms use floating point arithmetic,
// and the same caveats noted above apply here as well.


long LLL_XD(matrix(ZZ)& B, double delta = 0.99, long deep = 0,
           LLLCheckFct check = 0);
long LLL_XD(matrix(ZZ)& B, matrix(ZZ)& U, double delta = 0.99, long deep = 0,
           LLLCheckFct check = 0);


long BKZ_XD(matrix(ZZ)& BB, double delta=0.99, long BlockSize=10, long prune=0,
         LLLCheckFct check = 0);
long BKZ_XD(matrix(ZZ)& BB, matrix(ZZ)& U, double delta=0.99,
         long BlockSize=10, long prune=0, LLLCheckFct check = 0);

// These routines have exactly the same sematics as the LLL_FP and BKZ_FP
// routines above, except that the type xdouble (see xdouble.doc) is used
// for the floating point approximation, which avoids the overflow
// problems one might incur with the FP routines.  Roundoff, though, 
// could still be a problem.




long LLL_RR(matrix(ZZ)& B, double delta = 0.99, long deep = 0,
           LLLCheckFct check = 0);
long LLL_RR(matrix(ZZ)& B, matrix(ZZ)& U, double delta = 0.99, long deep = 0,
           LLLCheckFct check = 0);


long BKZ_RR(matrix(ZZ)& BB, double delta=0.99, long BlockSize=10, long prune=0,
         LLLCheckFct check = 0);

long BKZ_RR(matrix(ZZ)& BB, matrix(ZZ)& U, double delta=0.99,
         long BlockSize=10, long prune=0, LLLCheckFct check = 0);

// These routines have exactly the same sematics as those above, except
// that the class RR is used for the floating point approximations,
// using the current value of RR::precision().




