/* -*- C++ -*- */
//    Copyright (C) 2002  Otto Skrove Bagge
//
//    This program 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.
//
//    This program 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 this program; if not, write to the Free Software
//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

template<class T>
class Vector
{
   public:
      Vector();
      Vector(const Vector<T>&);
      Vector(const T&);
      
      inline T& operator[](const int);
      inline T operator[](const int) const;
      
      template<class INDABLE_t0h, class IELT_t0h, class NELT_t0h>
      inline void um_map_1u(T (*argmapfun)(const int &, const T&, const IELT_t0h&, const NELT_t0h&), const INDABLE_t0h &INDABLE_iav0h, const NELT_t0h &NELT_nev0h);

      inline void operator+=(const Vector<T>&);
      inline void operator+=(const T&);
      inline void operator-=(const Vector<T>&);
      inline void operator-=(const T&);
      inline void operator*=(const Vector<T>&);
      inline void operator*=(const T&);
      inline void operator/=(const Vector<T>&);
      inline void operator/=(const T&);
      
      void rules()
      {
	 Vector<T> v, w;
	 T t, u;

 	bottomup: (v + w) = mapcs(v, lambda((T)x, (T)y, (T)(x + y)), w); 
	bottomup: (v - w) = mapcs(v, lambda((T)x, (T)y, (T)(x - y)), w);
	bottomup: (v * w) = mapcs(v, lambda((T)x, (T)y, (T)(x * y)), w);
	bottomup: (v / w) = mapcs(v, lambda((T)x, (T)y, (T)(x / y)), w);

	bottomup: (v + t) = mapcs(v, lambda((T)x, (T)y, (T)(x + y)), t);
	bottomup: (v - t) = mapcs(v, lambda((T)x, (T)y, (T)(x - y)), t);
	bottomup: (v * t) = mapcs(v, lambda((T)x, (T)y, (T)(x * y)), t);
	bottomup: (v / t) = mapcs(v, lambda((T)x, (T)y, (T)(x / y)), t);

//	bottomup: mapcs(mapcs(v, f, _list_(w)), g, _list_(x))
//		     = mapcs(v, compose<1>(g, f), _list_(x), _list_(w));
//	bottomup: mapcs(mapcs(v, f, _list_(w)), g, _list_(x))
//		     = mapcs(v, g, _list_(x), _list_(w));
	 Vector<T> x, y;
	 __any_t xs, ys, zs;
	 T (*f)(const T&, __any_t);
	 T (*g)(const T&, __any_t);
	 int i;
	 
	bottomupr: mapcs(x, f, _list_(xs), mapcs(y, g, _list_(ys)), _list_(zs))
		     = mapcs(x, compose<i>(f, g), _list_(xs), y, _list_(ys),
			     _list_(zs)), i = len(x, _list_(xs));
	bottomupr: mapcs(mapcs(y, g, _list_(ys)), f, _list_(xs))
		     = mapcs(y, compose<0>(f, g), _list_(ys), _list_(xs));

//	bottomupr: mapcn(v, g, _list_(x), mapcn(w, f, _list_(z)), _list_(y))
//		     = mapcn(v, compose<i>(g, f), _list_(x), _list_(z),
//			     _list_(y)), i = len(v, _list_(x));
//	bottomupr: mapcn(mapcn(v, f, _list_(w)), g, _list_(x))
//		     = mapcn(v, g, _list_(x));

      }
   
   private:
      T data[VSIZE];
};

   

template<class T>
Vector<T>::Vector()
{
}

template<class T>
inline Vector<T>::Vector(const Vector<T>& v)
{
   for(int i = 0; i < VSIZE; i++)
      data[i] = v.data[i];
}

template<class T>
inline Vector<T>::Vector(const T& e)
{
   for(int i = 0; i < VSIZE; i++)
      data[i] = e;
}

template<class T>
inline T& Vector<T>::operator[](const int i)
{
   return data[i];
}

template<class T>
inline T Vector<T>::operator[](const int i) const
{
   return data[i];
}

template<class T>
template<class INDABLE_t0h, class IELT_t0h, class NELT_t0h>
inline void Vector<T>::um_map_1u(T (*argmapfun)(const int &, const T&, const IELT_t0h&, const NELT_t0h&), const INDABLE_t0h &INDABLE_iav0h, const NELT_t0h &NELT_nev0h)
{
   for(int i = 0; i < VSIZE; i++)
      data[i] = argmapfun(i, data[i], INDABLE_iav0h[i], NELT_nev0h);
}

template<class T>
inline void Vector<T>::operator+=(const T& e)
{
   for(int i = 0; i < VSIZE; i++)
      data[i] += e;
}

template<class T>
inline void Vector<T>::operator-=(const T& e)
{
   for(int i = 0; i < VSIZE; i++)
      data[i] -= e;
}

template<class T>
inline void Vector<T>::operator*=(const T& e)
{
   for(int i = 0; i < VSIZE; i++)
      data[i] *= e;
}

template<class T>
inline void Vector<T>::operator/=(const T& e)
{
   for(int i = 0; i < VSIZE; i++)
      data[i] /= e;
}

template<class T>
inline void Vector<T>::operator+=(const Vector<T>& a)
{
   for(int i = 0; i < VSIZE; i++)
      data[i] += a[i];
}

template<class T>
inline void Vector<T>::operator-=(const Vector<T>& a)
{
   for(int i = 0; i < VSIZE; i++)
      data[i] -= a[i];
}

template<class T>
inline void Vector<T>::operator*=(const Vector<T>& a)
{
   for(int i = 0; i < VSIZE; i++)
      data[i] *= a[i];
}

template<class T>
inline void Vector<T>::operator/=(const Vector<T>& a)
{
   for(int i = 0; i < VSIZE; i++)
      data[i] /= a[i];
}

