//
// 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

#if defined(HAVE_MAC_DIRS) || defined(__MWERKS__)
#include <LiDIA:math_vector.h>
#include <LiDIA:arith.inl>
#include <LiDIA:xerror.h>
#else
#include <LiDIA/math_vector.h>
#include <LiDIA/arith.inl>
#include <LiDIA/xerror.h>
#endif

/**
 ** debug defines / error defines
 **/

extern const char *PRT;
extern const char *vector_error_msg[];

#define DV_MV LDBL_VECTOR + 10   /* Debug value   */
#define DM_MV "math_vector"      /* Debug message / Error message */
#define LMV_ERROR vector_error_msg

/**
 ** debug level
 **
 **   0 : addtion
 **   1 : subtraction
 **   2 : multiplication
 **   3 : division
 **   4 : negation
 **   5 : comparisons
 **   6 : 
 **/

/**
 ** assignment 
 **/

template < class T >
math_vector< T > & math_vector < T >::
operator = (const math_vector < T > & v)
{
  debug_handler_l(DM_BV, "in operator "
		  "= (const math_vector < T > &)", DV_BV + 6);

  base_vector < T >::assign(v);
  return *this;
}

/**
 ** arithmetic procedures 
 **/

/**
 ** addition 
 **/

template < class T >
void math_vector < T >::
add(const math_vector < T > &v, const math_vector < T > &w)
{
  debug_handler_l(DM_MV, "in member - function "
		  "add(math_vector < T > &, math_vector < T > &)", DV_MV);
  
  register lidia_size_t i;
  if (w.length == v.length)
    {
      set_capacity(w.length);
      length = w.length;
      
      for (i = 0; i < w.length; i++)
	::add(data[i], v.data[i], w.data[i]);
    }
  else
    lidia_error_handler_para(w.length, "w.length", "w.length == v.length",
			     v.length, "v.length", "w.length == v.length",
			     "void math_vector < T >::"
			     "add(const math_vector < T > &v, const math_vector < T > &w)",
			     DM_MV, LMV_ERROR[14]);
}

template < class T >
void math_vector < T >::
add(const math_vector < T > &v, const T &t)
{
  debug_handler_l(DM_MV, "in member - function "
		  "add(const math_vector < T > &, const T &)", DV_MV);

  register lidia_size_t i;

  set_capacity(v.length);
  length = v.length;
  
  for (i = 0; i < v.length; i++)
      ::add(data[i], v.data[i], t);
}

template < class T >
void math_vector < T >::
add(const T &t, const math_vector < T > &v)
{
  debug_handler_l(DM_MV, "in member - function "
		  "add(const T &, const math_vector < T > &)", DV_MV);
  
  register lidia_size_t i;

  set_capacity(v.length);
  length = v.length;
  
  for (i = 0; i < v.length; i++)
    ::add(data[i], t, v.data[i]);
}

/**
 ** subtraction 
 **/

template < class T >
void math_vector < T >::
subtract(const math_vector < T > &v, const math_vector < T > &w)
{
  debug_handler_l(DM_MV, "in member - function "
		  "subtract(const math_vector < T > &, const math_vector < T > &)", DV_MV + 1);

  register lidia_size_t i;
  if (w.length == v.length)
    {
      set_capacity(w.length);
      length = w.length;
      
      for (i = 0; i < w.length; i++)
	::subtract(data[i], v.data[i], w.data[i]);
    }
  else
    lidia_error_handler_para(w.length, "w.length", "w.length == v.length",
			     v.length, "v.length", "w.length == v.length",
			     "void math_vector < T >::"
			     "void math_vector < T >::"
			     "subtract(const math_vector < T > &v, const math_vector < T > &w)",
			     DM_MV, LMV_ERROR[14]);
}

template < class T >
void math_vector < T >::
subtract(const math_vector < T > &v, const T &t)
{
  debug_handler_l(DM_MV, "in member - function "
		  "subtract(const math_vector < T > &, const T &)", DV_MV + 1);
  
  register lidia_size_t i;

  set_capacity(v.length);
  length = v.length;
  
  for (i = 0; i < v.length; i++)
    ::subtract(data[i], v.data[i], t);
}

template < class T >
void math_vector < T >::
subtract(const T &t, const math_vector < T > &v)
{
  debug_handler_l(DM_MV, "in member - function "
		  "subtract(const T &, const math_vector < T > &)", DV_MV + 1);
  
  register lidia_size_t i;
  
  set_capacity(v.length);
  length = v.length;
  
  for (i = 0; i < v.length; i++)
    ::subtract(data[i], t, v.data[i]);
}

/**
 ** multiplication 
 **/

template < class T >
void math_vector < T >::
compwise_multiply(const math_vector < T > &v, const math_vector < T > &w)
{
  debug_handler_l(DM_MV, "in member - function "
		  "compwise_multiply(const math_vector < T > &, const math_vector < T > &)", DV_MV + 2);
  
  register lidia_size_t i;
  if (w.length == v.length)
    {
      set_capacity(w.length);
      length = w.length;
      
      for (i = 0; i < w.length; i++)
	::multiply(data[i], v.data[i], w.data[i]);
    }
  else
    lidia_error_handler_para(w.length, "w.length", "w.length == v.length",
			     v.length, "v.length", "w.length == v.length",
			     "void math_vector < T >::"
			     "compwise_multiply(const math_vector < T > &v, const math_vector < T > &w)",
			     DM_MV, LMV_ERROR[14]);
}

template < class T >
void math_vector < T >::
right_multiply(const math_vector < T > &v, const T &t)
{
  debug_handler_l(DM_MV, "in member - function "
		  "multiply(const math_vector < T > &, const T &)" , DV_MV + 2);
  
  register lidia_size_t i;

  set_capacity(v.length);
  length = v.length;

  for (i = 0; i < v.length ;i++ )
    ::multiply(data[i], v.data[i], t);
}

template < class T >
void math_vector < T >::
left_multiply(const T &t, const math_vector < T > &v)
{
  debug_handler_l(DM_MV, "in member - function "
		  "multiply(const T &, const math_vector < T > &)", DV_MV + 2);
  
  register lidia_size_t i;

  set_capacity(v.length);
  length = v.length;
  
  for (i = 0; i < v.length; i++)
    ::multiply(  data[i], t, v.data[i]);
}

template < class T >
void math_vector < T >::
multiply(T &res, const math_vector < T > &w) const
{
  debug_handler_l(DM_MV, "in member - function "
		  "multiply(const math_vector < T > &)", DV_MV + 2);
  
  register lidia_size_t i;
  T TMP;
  
  if (length == w.length)
    {
      if (length > 0)
	::multiply(res, data[0], w.data[0]);
      
      for (i = 1; i < length; i++)
        {
	  ::multiply(TMP, data[i], w.data[i]);
	  ::add(res, res, TMP);
	}
    }
  else
    lidia_error_handler_para(length, "length", "length == w.length",
			     w.length, "w.length", "length == w.length",
			     "T math_vector < T >::"
			     "multiply(T &, const math_vector < T > &w) const",
			     DM_MV, LMV_ERROR[14]);
}

/**
 ** division   
 **/

template < class T >
void math_vector < T >::
compwise_divide(const math_vector < T > &v, const math_vector < T > &w)
{
  debug_handler_l(DM_MV, "in member - function "
		  "compwise_divide(const math_vector < T > &, const math_vector < T > &)", DV_MV + 3);

  register lidia_size_t i;
  if (w.length == v.length )
    {
      set_capacity(w.length);
      length = w.length;
      
      for (i = 0; i < w.length; i++)
	::divide(data[i], v.data[i], w.data[i]);
    }
  else
    lidia_error_handler_para(w.length, "w.length", "w.length == v.length",
			     v.length, "v.length", "w.length == v.length",
			     "void math_vector < T >::"
			     "compwise_divide(const math_vector < T > &v, const math_vector < T > &w)",
			     DM_MV, LMV_ERROR[14]);
}

template < class T >
void math_vector < T >::
divide(const math_vector < T > &v, const T &t)
{
  debug_handler_l(DM_MV, "in member - function "
		  "divide(const math_vector < T > &, const T &)", DV_MV + 4);

  register lidia_size_t i;

  set_capacity(v.length);
  length = v.length;
  
  for (i = 0; i < v.length; i++)
    ::divide(data[i], v.data[i], t);
}

template < class T >
void math_vector < T >::
divide(const T &t, const math_vector < T > &v)
{
  debug_handler_l(DM_MV, "in member - function "
		  "divide(const T &, const math_vector < T > &)", DV_MV + 4);

  if (0) cerr << PRT;
  register lidia_size_t i;

  set_capacity(v.length);
  length = v.length;

  for (i = 0; i < v.length; i++)
    ::divide(data[i], t, v.data[i]);
}

/**
 ** negation  
 **/

template < class T >
void math_vector < T >::
negate(const math_vector < T > &v)
{
  debug_handler_l(DM_MV, "in member - function "
		  "negate(const math_vector < T > &)", DV_MV + 4);

  register lidia_size_t i ;
  set_capacity(v.length);
  length = v.length;

  for (i = 0; i < v.length; i++)
    ::negate(data[i], v.data[i]);
}

/**
 ** sum of squares of two math_vectors  
 **/

template < class T >
T math_vector < T >:: 
sum_of_squares ( ) const
{
  debug_handler_l(DM_MV, "in member - function "
		  "sum_of_squares()", DV_MV + 6);

  register lidia_size_t i;
  T res, TMP;
  
  if (length > 0)
    ::multiply(res, data[0], data[0]);
  for (i = 1; i < length; i++)
    {
      ::multiply(TMP, data[i], data[i]);
      ::add(res, res, TMP);
    }
  return res;
}

/**
 ** testing for equality  
 **/

template < class T >
bool math_vector < T >::
equal(const math_vector < T > &v) const
{
  debug_handler_l(DM_MV, "in member - function "
		  "equal(const math_vector < T > &)", DV_MV + 5);
  
  register lidia_size_t i;
  
  if (length != v.length)
    return false;
  
  for (i = 0; i < length; i++)
    if ( data[i] != v.data[i] )
      return false;
  
  return true ;
}

#undef DV_MV 
#undef DM_MV 
#undef LMV_ERROR 





