// vector.h: declarations of integer vector classes
//////////////////////////////////////////////////////////////////////////
//
// Copyright 1990-2026 John Cremona
// 
// This file is part of the eclib package.
// 
// eclib is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version.
// 
// eclib is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
// 
// You should have received a copy of the GNU General Public License
// along with eclib; if not, write to the Free Software Foundation,
// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
// 
//////////////////////////////////////////////////////////////////////////
 
#if     !defined(_ECLIB_VECTOR_H)
#define _ECLIB_VECTOR_H      1       //flags that this file has been included

#include "marith.h"

template<class T> class Zvec;
template<class T> class sZvec;
template<class T> class sZmat;
template<class T> class sZmat_elim;
template<class T> class Zmat;
template<class T> class subZspace;
template<class T> class ssubZspace;
template<class T> class form_finderT;

typedef Zvec<int> vec_i;
typedef Zmat<int> mat_i;
typedef subZspace<int> subspace_i;
typedef sZvec<int> svec_i;
typedef sZmat<int> smat_i;
typedef sZmat_elim<int> smat_i_elim;
typedef ssubZspace<int> ssubspace_i;
typedef form_finderT<int> form_finder_i;

typedef Zvec<long> vec_l;
typedef Zmat<long> mat_l;
typedef subZspace<long> subspace_l;
typedef sZvec<long> svec_l;
typedef sZmat<long> smat_l;
typedef sZmat_elim<long> smat_l_elim;
typedef ssubZspace<long> ssubspace_l;
typedef form_finderT<long> form_finder_l;

typedef Zvec<ZZ> vec_m;
typedef Zmat<ZZ> mat_m;
typedef subZspace<ZZ> subspace_m;
typedef sZvec<ZZ> svec_m;
typedef sZmat<ZZ> smat_m;
typedef sZmat_elim<ZZ> smat_m_elim;
typedef ssubZspace<ZZ> ssubspace_m;
typedef form_finderT<ZZ> form_finder_m;

typedef Zvec<INT> vec_I;
typedef Zmat<INT> mat_I;
typedef subZspace<INT> subspace_I;
typedef sZvec<INT> svec_I;
typedef sZmat<INT> smat_I;
typedef sZmat_elim<INT> smat_I_elim;
typedef ssubZspace<INT> ssubspace_I;
typedef form_finderT<INT> form_finder_I;

template<class T> int dim(const Zvec<T>&);
template<class T> T operator*(const Zvec<T>&, const Zvec<T>&);
template<class T> T operator*(const sZvec<T>&, const Zvec<T>&);
template<class T> T content(const Zvec<T>&);
template<class T> T maxabs(const Zvec<T>&);
template<class T> int operator==(const Zvec<T>&, const Zvec<T>&);
template<class T> int operator!=(const Zvec<T>&, const Zvec<T>&);
template<class T> int trivial(const Zvec<T>&);
template<class T> int member(const T& a, const Zvec<T>& v);//tests if a=v[i] for some i
template<class T> Zvec<T> reverse(const Zvec<T>& order);
template<class T> void add_row_to_vec(Zvec<T>& v, const Zmat<T>& m, long i);
template<class T> void sub_row_to_vec(Zvec<T>& v, const Zmat<T>& m, long i);
template<class T> ostream& operator<< (ostream&s, const Zvec<T>&);
template<class T> istream& operator>> (istream&s, Zvec<T>&);
template<class T> void swapvec(Zvec<T>& v, Zvec<T>& w);
template<class T> Zvec<T> operator*(const Zmat<T>&, const Zvec<T>&);
template<class T> T dotmodp(const Zvec<T>& v1, const Zvec<T>& v2, const T& pr);

template<class T>
class Zvec {
  friend class sZvec<T>;
  friend class sZmat<T>;
  friend class sZmat_elim<T>;
  friend class Zmat<T>;
  friend class subZspace<T>;
public:
  // constructors
  explicit Zvec(long n=0);
  explicit Zvec(const vector<T>& arr);
  Zvec(const Zvec<T>&);                       // copy constructor
  // member functions & operators
  void init(long n=0);                 // (re)-initializes
  void clear();                        // sets all entries to 0
  Zvec& operator=(const Zvec<T>&);     // assignment
  inline int dim() const {return entries.size();}
  T& operator[](long i);            // the i'th component
  T operator[](long i) const;       // the i'th component
  Zvec& operator+=(const Zvec<T>&);
  void add_row(const Zmat<T>&m, int i);
  void addmodp(const Zvec<T>&, const T&);
  Zvec& operator-=(const Zvec<T>&);
  void sub_row(const Zmat<T>&m, int i);
  Zvec& operator*=(const T&);
  Zvec& operator/=(const T&);
  Zvec slice(long i, long j=-1) const;  // returns subZvec with indices i..j,  or 1..i if j=-1
  Zvec operator[](const Zvec<int>&) const;   // subscript composition
  Zvec operator[](const Zvec<long>&) const;   // subscript composition
  void set(long i, const T& x);                  // sets v[i]=x
  void add(long i, const T& x);                  // v[i]+=x
  void add_modp(long i, const T& x, const T& p);                  // v[i]+=x mod p
  void reduce_mod_p(const T& p);              // reduce mod p in place
  T sub(long i) const;                    // same as v[i] (no ref)
  const vector<T> get_entries()const {return entries;}
  static Zvec iota(long n);              // (1,2,...,n)
  static Zvec unit_vector(long n, long i); // 1 in i'th position of n
  // non-member (friend) functions and operators
  friend T operator*<>(const Zvec<T>&, const Zvec<T>&);   // dot product
  friend T operator*<>(const sZvec<T>&, const Zvec<T>&);
  friend T content<>(const Zvec<T>&);
  friend T maxabs<>(const Zvec<T>&);
  friend Zvec operator*<>(const Zmat<T>& m, const Zvec<T>& v);
  friend int operator==<>(const Zvec<T>&, const Zvec<T>&);
  friend int operator!=<>(const Zvec<T>&, const Zvec<T>&);
  friend int trivial<>(const Zvec<T>&);                  // is v all 0
  friend int member<>(const T& a, const Zvec<T>& v);//tests if a=v[i] for some i
  friend Zvec reverse<>(const Zvec<T>& order);
  // add/sub row i of Zmat to v (implemented in mat.cc)
  friend void add_row_to_vec<>(Zvec<T>& v, const Zmat<T>& m, long i);
  friend void sub_row_to_vec<>(Zvec<T>& v, const Zmat<T>& m, long i);
  friend ostream& operator<< <>(ostream&s, const Zvec<T>&);
  friend istream& operator>> <>(istream&s, Zvec<T>&);
  friend void swapvec<>(Zvec<T>& v, Zvec<T>& w);
  friend T dotmodp<>(const Zvec<T>& v1, const Zvec<T>& v2, const T& pr);

  // Implementation
private:
  vector<T> entries;
};

// Declaration of non-member, non-friend functions

template<class T> T content(const Zvec<T>&);
template<class T> Zvec<T> operator+(const Zvec<T>&);                   // unary
template<class T> Zvec<T> operator-(const Zvec<T>&);                   // unary
template<class T> Zvec<T> operator+(const Zvec<T>&, const Zvec<T>&);
template<class T> Zvec<T> addmodp(const Zvec<T>&, const Zvec<T>&, const T&);
template<class T> Zvec<T> operator-(const Zvec<T>&, const Zvec<T>&);
template<class T> Zvec<T> operator*(const T&, const Zvec<T>&);       // componentwise
template<class T> Zvec<T> operator/(const Zvec<T>&, const T&);       // componentwise
template<class T> void make_primitive(Zvec<T>& v);
template<class T> int lift(const Zvec<T>& v, const T& pr, Zvec<T>& ans);  //lifts a mod-p vector to a rational
                                   //and scales to a primitive vec in Z. Returns success flag

// non-member functions

template<class T> int dim(const Zvec<T>& v);
template<class T> int operator!=(const Zvec<T>& v, const Zvec<T>& w);
template<class T> Zvec<T> operator+(const Zvec<T>& v);
template<class T> Zvec<T> operator-(const Zvec<T>& v);
template<class T> Zvec<T> operator+(const Zvec<T>& v1, const Zvec<T>& v2);
template<class T> Zvec<T> addmodp(const Zvec<T>& v1, const Zvec<T>& v2, const T& pr);
template<class T> Zvec<T> reduce_mod_p(const Zvec<T>& v, const T& p);
template<class T> Zvec<T> operator-(const Zvec<T>& v1, const Zvec<T>& v2);
template<class T> Zvec<T> operator*(const T& scal, const Zvec<T>& v);
template<class T> Zvec<T> operator/(const Zvec<T>& v, const T& scal);
template<class T> void make_primitive(Zvec<T>& v);

// convert between vectors over different integer types
template<class T>
vec_m to_vec_m(const Zvec<T>& V);
template<class T>
vec_i to_vec_i(const Zvec<T>& V);
template<class T>
vec_l to_vec_l(const Zvec<T>& V);

// Function to generate a random nonzero integer vector of a given
// size with entries taken uniformly from [minv..maxv], optionally
// making the returned vector primitive.

vector<int> random_vector(size_t size, int minv, int maxv, int primitive=1);

#endif
