#ifndef LIDIA_MATRIX_GL2Z_H
#define LIDIA_MATRIX_GL2Z_H

#include <LiDIA/lidia.h>
#include <LiDIA/bigint.h>

class matrix_GL2Z
{
friend class quadratic_form;
 private:

  // [ s u ]
  // [ t v ]
  //
  // determinant = sv - tu = +-1

  bigint s, u;
  bigint t, v;
  int determinant;

 public:

  matrix_GL2Z();
  matrix_GL2Z(const bigint & a, const bigint & c,
	      const bigint & b, const bigint & d);
  matrix_GL2Z(const matrix_GL2Z & a);
  ~matrix_GL2Z();

  const bigint &  get_s() const;
  const bigint &  get_t() const;
  const bigint &  get_u() const;
  const bigint &  get_v() const;

  int det();
  void invert();
  void assign_zero();
  void assign_one();

  matrix_GL2Z & operator = (const matrix_GL2Z & a);
  bigint operator()(int,int) const;

  friend int operator == (const matrix_GL2Z & , const matrix_GL2Z & ); 

  friend void multiply(matrix_GL2Z & c, 
		       const matrix_GL2Z & a, 
		       const matrix_GL2Z & b);

  friend void divide(matrix_GL2Z & c, 
                       const matrix_GL2Z & a, 
		       const matrix_GL2Z & b);
  
  friend matrix_GL2Z operator *( const matrix_GL2Z & a, const matrix_GL2Z & b);
  friend matrix_GL2Z operator /( const matrix_GL2Z & a, const matrix_GL2Z & b);

  friend matrix_GL2Z inverse(const matrix_GL2Z & a);
  
  void es(const bigint &);
  void te();
  void randomize(const bigint &);

  friend ostream & operator << (ostream & out, const matrix_GL2Z & a);
  friend istream & operator >> (istream & in, matrix_GL2Z & A); 

};

#endif





