//
// LiDIA - a library for computational number theory
//   Copyright (c) 1994, 1995 by the LiDIA Group
//
// File        : lattice_defs.h
// Author      : Werner Backes (WB), Thorsten Lauer (TL)
// Last change : WB/TL, May 09 1996, 
//                      initial version, previously class 
//                      bigint_lattice_gensys/basis
//               WB/TL, Jul 27 1996, 
//                      redesign of class structure
//               WB/TL, Aug 06 1996,
//                      only defines, typedefs, structs remain in 
//                      this file
//

#ifndef __lattice_defs_h__
#define __lattice_defs_h__

#define LIDIA_POINTER_ACCESS

#ifdef LIDIA_INLINE_PROBLEM
#define NO_LATTICE_INLINE
#define NO_P_VECTOR_INLINE
#endif

//
// Special include format for compatibility with MAC's
//
#if defined(HAVE_MAC_DIRS) || defined(__MWERKS__)
#include <LiDIA:xdouble.h>
#include <LiDIA:bigint.h>
#include <LiDIA:bigfloat.h>
#include <LiDIA:p_vector.h>
#include <LiDIA:bigint_matrix.h>
#else
#include <LiDIA/xdouble.h>
#include <LiDIA/bigint.h>
#include <LiDIA/bigfloat.h>
#include <LiDIA/p_vector.h>
#include <LiDIA/bigint_matrix.h>
#endif

class bigint_lattice;
class bigfloat_lattice;

#ifdef NO_LATTICE_INLINE
#define LATTICE_INLINE
#else
#define LATTICE_INLINE inline
#endif

//
// Define for gcc 2.7.0 or higher
// !!! new ansi standard !!!
//
#if defined(__GNUC__) && __GNUC__ == 2 && __GNUC_MINOR__ > 6
#define cl(x)
#define fcl(x) register lidia_size_t x
#else
#define cl(x) lidia_size_t x
#define fcl(x) x
#endif

//
// typedef for sortfunction
//
typedef sdigit (*bin_cmp_func)(const bigint*, const bigint*, lidia_size_t);
typedef sdigit (*bfl_cmp_func)(const bigfloat*, const bigfloat*, lidia_size_t);

//
// typedef for scalarproduct
// the bigfloat - version is not allowed to change precision
// (if it's changed then restore after computation)
//
typedef void (*scal_dbl)(double&, double*, double*, lidia_size_t);
typedef void (*scal_xdbl)(xdouble&, xdouble*, xdouble*, lidia_size_t);
typedef void (*scal_bin)(bigint&, bigint*, bigint*, lidia_size_t);
typedef void (*scal_bfl)(bigfloat&, bigfloat*, bigfloat*, lidia_size_t);

typedef struct {
          scal_dbl dbl;
          scal_xdbl xdbl;
 	  scal_bin bin;
	  scal_bfl bfl;
        } user_SP;

//
// Information about the algorithms
//
typedef union {
          struct {
	    lidia_size_t rank;
            double y;
            sdigit y_nom;
            sdigit y_denom; 
            sdigit reduction_steps;
            sdigit correction_steps;
            sdigit swaps;
          } lll;
        } lattice_info;

//
// structure definition for internal class use
// to simplify parameters for algorithms 
//
typedef struct {
          double y;
          sdigit y_nom;
          sdigit y_denom;
          bool transpose;
          bool alg_trans;
          lidia_size_t rows;
          lidia_size_t columns;
          lidia_size_t rank; 
          lidia_size_t real_columns;
        } base_alg;


typedef struct {
 	  sdigit bit_prec;
	  sdigit cut_bit_prec;
 	  sdigit bit_factor;
          sdigit approx_prec;
          sdigit exact_prec;
          sdigit old_prec;
          sdigit read_prec;
        } info_dgts;

template <class T>
struct dense_struc
{
  T **value;
  T *delvalue;
  math_matrix<T> *TMatrix;
};

//
// Parameters for dense lattice algorithms
//
template <class T>
struct dense_alg 
{
  dense_struc<T> s;
  info_dgts d;
  base_alg b;
};

//
// Parameters for sparse lattice algorithms
//
struct sparse_alg
{
  base_alg b;
};
            

//
// Vector operations for the needed types using 
// the new class p_vector. These are put together to
// have one template argument instead of three
//

template <class E, class A>
struct vector_op
{
  p_vector<A>  approx;
  p_vector<E>  exact;
};

//
// See above, using function pointer defined scalarproduct
//
template <class E, class A>
struct vector_op_SP
{
  p_vector_SP<A>  approx;
  p_vector_SP<E>  exact;
};

const sdigit DOUBLE_MANTISSA_BITS=52;
const sdigit MANTISSA_CUT=bigint::bits_per_digit();


#define ALG_DEF(E,Vect,basis,Var)                                      \
struct LIDIA_CONCAT4(E,Vect,basis,Var) {                               \
  lll_kernel_op<E,double,Vect<E,double>,                               \
                LIDIA_CONCAT2(basis,_modules)<E,double,Var> > dbl;     \
  lll_kernel_op<E,xdouble,Vect<E,xdouble>,                             \
                LIDIA_CONCAT2(basis,_modules)<E,xdouble,Var> > xdbl;   \
  lll_kernel_fu<E,bigfloat,Vect<E,bigfloat>,                           \
                LIDIA_CONCAT2(basis,_modules)<E,bigfloat,Var> > bfl;   \
}

#define ALG_POINTER(alg,SP,ex)                                                              \
{                                                                                           \
  LIDIA_CONCAT2(alg,.dbl.vector_operations().approx.set_pointer)(LIDIA_CONCAT2(SP,.dbl));   \
  LIDIA_CONCAT2(alg,.dbl.vector_operations().exact.set_pointer)(LIDIA_CONCAT3(SP,.,ex));    \
  LIDIA_CONCAT2(alg,.xdbl.vector_operations().approx.set_pointer)(LIDIA_CONCAT2(SP,.xdbl)); \
  LIDIA_CONCAT2(alg,.xdbl.vector_operations().exact.set_pointer)(LIDIA_CONCAT3(SP,.,ex));   \
  LIDIA_CONCAT2(alg,.bfl.vector_operations().approx.set_pointer)(LIDIA_CONCAT2(SP,.bfl));   \
  LIDIA_CONCAT2(alg,.bfl.vector_operations().exact.set_pointer)(LIDIA_CONCAT3(SP,.,ex));    \
}

#define ALG_CALL(cl, alg, da, li, factor)     \
{                                             \
  if (factor < 2)                             \
    LIDIA_CONCAT3(cl,.dbl.,alg)(da, li);      \
  else                                        \
    {                                         \
      if (factor == 2)                        \
        LIDIA_CONCAT3(cl,.xdbl.,alg)(da, li); \
      else                                    \
        LIDIA_CONCAT3(cl,.bfl.,alg)(da, li);  \
    }                                         \
}

//
// Const for structure_info
//
const sdigit GRAM_MATRIX      = 0x80000000;

//
// Const for lattice_info
//
const sdigit REDUCE_ROWS   = 0x80000000;

static const bigfloat __dummy__=0.0;

#endif
