//
// LiDIA - a library for computational number theory
//   Copyright (c) 1995 by the LiDIA Group
//
// File        : math_vector.h 
// Author      : Frank Lehmann (FL), Markus Maurer (MM),
//               Thomas Papanikolaou (TP), Patrick Theobald (PT)
// Last change : FL/MM, Feb 15 1995, initial version
//               FL/MM, May 10 1995, clean-up
//		 FL/MM, May 15 1995, changed type of size variables to base_vector<T>::size_type
//		 FL/MM, Jul  6 1995, replaced base_vector<T>::size_type by lidia_size_t
//               FL/MM, Jul 24 1995, added 'const' to T* parameters of constructors
//		 FL/MM, Aug 30 1995, changed "error_handler" to "lidia_error_handler"
//               PT     Oct 28 1995, new template concept
//

// ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
// *
// *    File        :  math_vector.h
// *
// *    Description :  -) definition of template class 'math_vector<T>'
// *                      to allow use of vectors with arithmetical
// *                      functions
// *
// *                   -) virtual base class is 'base_vector<T>'
// *
// *		       -) to use this class the type T must support the
// *			  operators + , - , * , /, - (unary), != 
// *
// ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **

#ifndef LIDIA_MATH_VECTOR_H
#define LIDIA_MATH_VECTOR_H

#if defined(HAVE_MAC_DIRS) || defined(__MWERKS__)
#include <LiDIA:base_vector.h>
#else
#include <LiDIA/base_vector.h>
#endif

template < class T > 
class math_vector : public virtual base_vector < T >
{

   /**
    ** constructors
    **/

 public:
  
  inline math_vector() : base_vector < T > (0, FIXED) {}
  inline math_vector(lidia_size_t all, char md) : base_vector < T > (all, md) {}
  inline math_vector(lidia_size_t all, lidia_size_t len) : base_vector < T > (all, len, FIXED) {}
  inline math_vector(lidia_size_t all, lidia_size_t len, char md) : base_vector < T > (all, len, md) {}
  inline math_vector(const base_vector < T > & v) : base_vector < T > (v, FIXED) {}
  inline math_vector(const base_vector < T > & v, char md) : base_vector < T > (v, md) {}
  inline math_vector(const T *v, lidia_size_t len) : base_vector < T > (v, len, FIXED) {}
  inline math_vector(const T *v, lidia_size_t len, char md) : base_vector < T > (v, len, md) {}
  
  /**
   ** destructor 
   **/

 public:
  
  inline ~math_vector() {}

  /**
   ** assignment 
   **/

 public:

  math_vector < T > & operator = (const math_vector < T > &  v);
  
  /**
   ** math operations
   **/
  
  /**
   ** addition
   **/
 
 public:
 
  inline friend math_vector < T > operator + (const math_vector < T > &v, const math_vector < T > &w)
    {math_vector < T > sum(v.length, FIXED); sum.add(v, w); return sum;}
  inline friend math_vector < T > operator + (const math_vector < T > &v, const T &t)
    {math_vector < T > sum(v.length, FIXED); sum.add(v, t); return sum;}
  inline friend math_vector < T > operator + (const T &t, const math_vector < T > &v)
    {math_vector < T > sum(v.length, FIXED); sum.add(t, v); return sum;}
  
  inline friend math_vector < T > & operator += (math_vector < T > &sum, const math_vector < T > &v)
    {sum.add(sum, v); return sum;}
  inline friend math_vector < T > & operator += (math_vector < T > &sum, const T &t)
    {sum.add(sum, t); return sum;}

  /**
   ** subtraction
   **/
 
 public:
 
  inline friend math_vector < T > operator - (const math_vector < T > &v, const math_vector < T > &w)
    {math_vector < T > dif(v.length, FIXED); dif.subtract(v, w); return dif;}
  inline friend math_vector < T > operator - (const math_vector < T > &v, const T &t)
    {math_vector < T > dif(v.length, FIXED); dif.subtract(v, t); return dif;}
  inline friend math_vector < T > operator - (const T &t, const math_vector < T > & v)
    {math_vector < T > dif(v.length, FIXED); dif.subtract(t, v); return dif;}

  inline friend math_vector < T > & operator -= (math_vector < T > &dif, const math_vector < T > &v)
    {dif.subtract(dif, v); return dif;}
  inline friend math_vector < T > & operator -= (math_vector < T > &dif, const T &t)
    {dif.subtract(dif, t); return dif;}

  /**
   ** multiplication
   **/
 
 public:
 
  inline friend T operator * (const math_vector < T > &v, const math_vector < T > &w)
    {T pro; v.multiply(pro, w); return pro;}
  inline friend math_vector < T > operator * (const math_vector < T > &v, const T &t) 
    {math_vector < T > pro(v.length, FIXED); pro.right_multiply(v, t); return pro;}
  inline friend math_vector < T > operator * (const T &t, const math_vector < T > &v)
    {math_vector < T > pro(v.length, FIXED); pro.left_multiply(t, v); return pro;}

  inline friend math_vector < T > & operator *= (math_vector < T > &pro, const T &t)
    {pro.right_multiply(pro, t); return pro;}

  /** 
   ** division
   **/
 
 public: 

  inline friend math_vector < T > operator / (const math_vector < T > &v, const T &t)
    {math_vector < T > quo(v.length, FIXED); quo.divide(v, t); return quo;}
  inline friend math_vector < T > operator / (const T &t, const math_vector < T > &v)
    {math_vector < T > quo(v.length, FIXED); quo.divide(t, v); return quo;}
  
  inline friend math_vector < T > & operator /= (math_vector < T > &quo, const T &t)
    {quo.divide(quo, t); return quo;}

  /**
   ** negation
   **/
  
 public:

  inline friend math_vector < T > operator - (const math_vector < T > &v)
    {math_vector < T > neg(v.length, FIXED); neg.negate(v); return neg;}
  
  /**
   ** math procedures
   **/
  
  /**
   ** addition
   **/
  
 public:
 
#ifndef HEADBANGER 
  inline friend void add(math_vector < T > &r, const math_vector < T > &v, const math_vector < T > &w) 
    {r.add(v, w);}
  inline friend void add(math_vector < T > &r, const math_vector < T > &v, const T &t)
    {r.add(v, t);}
  inline friend void add(math_vector < T > &r, const T &t, const math_vector < T > &v)
    {r.add(t, v);}
#endif
  
 protected:
  
  void add(const math_vector < T > &, const math_vector < T > &);
  void add(const math_vector < T > &, const T &);
  void add(const T &, const math_vector < T > &);
  
  /**
   ** subtraction
   **/
  
 public:
  
#ifndef HEADBANGER
  inline friend void subtract(math_vector < T > &r, const math_vector < T > &v, const math_vector < T > &w)
    {r.subtract(v, w);}
  inline friend void subtract(math_vector < T > &r, const math_vector < T > &v, const T &t)
    {r.subtract(v, t);}
  inline friend void subtract(math_vector < T > &r, const T &t, const math_vector < T > &v)
    {r.subtract(t, v);}
#endif
  
 protected:
  
  void subtract(const math_vector < T > &, const math_vector < T > &);
  void subtract(const math_vector < T > &, const T &);
  void subtract(const T &, const math_vector < T > &);

  /**
   ** multiplication
   **/
  
 public:
  
  inline friend void compwise_multiply(math_vector < T > &r, const math_vector < T > &v, const math_vector < T > &w) 
    {r.compwise_multiply(v, w);}

#ifndef HEADBANGER
  inline friend void multiply(T &res, const math_vector < T > &v, const math_vector < T > &w)
    {v.multiply(res, w);}
  inline friend void multiply(math_vector < T > &r, const math_vector < T > &v, const T &t)
    {r.right_multiply(v, t);}
  inline friend void multiply(math_vector < T > &r, const T &t, const math_vector < T > &v)
    {r.left_multiply(t, v);}
#endif
  
 protected:
  
  void compwise_multiply(const math_vector < T > &, const math_vector < T > &);
  void multiply(T &, const math_vector < T > &) const;
  void right_multiply(const math_vector < T > &, const T &);
  void left_multiply(const T &, const math_vector < T > &);

  /**
   ** divide
   **/

 public:
  
  inline friend void compwise_divide(math_vector < T > &r, const math_vector < T > &v, const math_vector < T > &w)
    {r.compwise_divide(v, w);}

#ifndef HEADBANGER
  inline friend void divide(math_vector < T > &r, const math_vector < T > &v, const T &t)
    {r.divide(v, t);}
  inline friend void divide(math_vector < T > &r, const T &t, const math_vector < T > &v)
    {r.divide(t, v);}
#endif

 protected:
  
  void compwise_divide(const math_vector < T > &, const math_vector < T > &);
  void divide(const math_vector < T > &, const T &);
  void divide(const T &, const math_vector < T > &);
  
  /**
   ** negation
   **/
  
 public:
  
#ifndef HEADBANGER
  inline friend void negate(math_vector < T > &r, const math_vector < T > &v)
    {r.negate(v);}
#endif

 protected:
  
  void negate(const math_vector < T > &);

  /**
   ** miscellaneous 
   **/
    
 public:

  inline friend T sum_of_squares(const math_vector < T > &v)
    {return v.sum_of_squares();}
  T sum_of_squares() const;

  /**
   ** comparisons 
   **/
    
 public:

  inline friend bool operator == (const math_vector < T > &w, const math_vector < T > &v)
    {return w.equal(v);}

#ifndef HEADBANGER
  bool equal(const math_vector < T > &) const;
  inline friend bool equal(const math_vector < T > &w, const math_vector < T > &v)
    {return w.equal(v);}
#endif
  
  inline friend bool operator != (const math_vector < T > &w, const math_vector <T> &v)
    {return !w.equal(v);}

#ifndef HEADBANGER
  inline bool unequal(const math_vector < T > &v) const 
    {return (!equal(v));}
  inline friend bool unequal(const math_vector < T > &w, const math_vector < T > &v)
    {return !w.equal(v);}
#endif
};

#ifdef LIDIA_INCLUDE_C
#include <LiDIA/math_vector.c>
#endif 

#endif







