// file: $isip/class/math/vector/MVector/MVector.h
// version: $Id: MVector.h 10636 2007-01-26 22:18:09Z tm334 $
//

// make sure definitions are only made once
//
#ifndef ISIP_MVECTOR
#define ISIP_MVECTOR

// isip include files
//
#ifndef ISIP_BYTE
#include <Byte.h>
#endif

#ifndef ISIP_ULONG
#include <Ulong.h>
#endif

#ifndef ISIP_USHORT
#include <Ushort.h>
#endif

#ifndef ISIP_ULLONG
#include <Ullong.h>
#endif

#ifndef ISIP_SHORT
#include <Short.h>
#endif

#ifndef ISIP_LONG
#include <Long.h>
#endif

#ifndef ISIP_LLONG
#include <Llong.h>
#endif

#ifndef ISIP_FLOAT
#include <Float.h>
#endif

#ifndef ISIP_DOUBLE
#include <Double.h>
#endif

#ifndef ISIP_COMPLEX_LONG
#include <ComplexLong.h>
#endif

#ifndef ISIP_COMPLEX_FLOAT
#include <ComplexFloat.h>
#endif

#ifndef ISIP_COMPLEX_DOUBLE
#include <ComplexDouble.h>
#endif

#ifndef ISIP_STRING
#include <String.h>
#endif

#ifndef ISIP_MVECTOR_METHODS
#include "MVectorMethods.h"
#endif

// MVector: the vector template class which is inherited by other
// vector classes. TScalar is a Scalar class, TIntegral is an Integral
// type. most of the methods in this class are inline wrappers to the
// MVectorMethods class functions. this is done to allow us to remove
// implementations from the header file, and thus avoid the
// compilation overhead inherent in compiling template classes with
// multiple explicit instantiations.
//
template<class TScalar, class TIntegral>
class MVector {
  
  //---------------------------------------------------------------------------
  //
  // public constants
  //
  //---------------------------------------------------------------------------
public:
  
  // define the class name
  //
  static const String CLASS_NAME;
  
  //----------------------------------------
  //
  // i/o related constants
  //
  //----------------------------------------  
  
  static const String DEF_PARAM;
  
  // i/o data buffering lengths
  //
  static const long TEXT_READ_SIZE = 128;
  static const long TEXT_PARTIAL_READ_SIZE = 33;
  static const long TEXT_WRITE_SIZE = 512;
  
  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------  
  
  // define the default value(s) of the class data
  //
  static const TIntegral DEF_VALUE;
  static const long DEF_LENGTH = 0;
  
  // default arguments to methods
  //
  static const TIntegral DEF_OFFSET;
  static const TIntegral DEF_INCR;
  static const unichar DEF_DELIM = L',';
  static const String DEF_DELIM_STR;
  static const long DEF_SHIFT = 1;
  
  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------  
  
  static const long ERR = 22000;
  static const long ERR_LEN = 22001;
  
  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:
  
  // vector elements
  //
  TScalar* v_d;
  
  // the number of elements of this vector
  //
  Long length_d;
  
  // the maximum number of elements
  //
  Long capacity_d;		     
  
  // declare a static debug level for all class instantiations
  //
  static Integral::DEBUG debug_level_d;
  
  //---------------------------------------------------------------------------
  //
  // required public methods
  //
  //---------------------------------------------------------------------------
public:
  
  // method: name
  //
  static const String& name() {
    return CLASS_NAME;
  }
  
  // other static methods
  //
  static boolean diagnose(Integral::DEBUG level) {
    return MVectorMethods::
      diagnose<MVector<TScalar, TIntegral>, TScalar, TIntegral>(level);
  }
  
  // method: setDebug
  //
  static boolean setDebug(Integral::DEBUG level) {
    debug_level_d = level;
    return true;
  }
  
  // method: debug
  //
  boolean debug(const unichar* message_a) const {
    return debug(name(), message_a);
  }
  
  // method: destructor
  //
  ~MVector();
  
  // method: default constructor
  //
  MVector();
  
  // method: copy constructor
  //
  MVector(const MVector& vector);
  
  // assign methods:
  //  this method is templatized so it can also do conversions
  //
  template<class TAScalar, class TAIntegral>
  boolean assign(const MVector<TAScalar, TAIntegral>& arg_a);
  
  // operator= methods:
  //  these methods are omitted because they are defined in the
  //  classes that instantiate this template
  //
  
  // i/o methods
  //
  long sofSize() const {
    return MVectorMethods::sofSize<TScalar, TIntegral>(*this);
  }
  
  boolean read(Sof& sof, long tag, const String& name = CLASS_NAME) {
    return MVectorMethods::read<TScalar,TIntegral>(*this, sof, tag, name);
  }
  
  boolean write(Sof& sof, long tag, const String& name = CLASS_NAME) const {
    return MVectorMethods::write<TScalar,TIntegral>(*this, sof, tag, name);
  }
  
  boolean readData(Sof& sof, const String& pname = DEF_PARAM,
		   long size = SofParser::FULL_OBJECT,
		   boolean param = true, boolean nested = true) {
    return MVectorMethods::readData<TScalar,TIntegral>(*this, sof, pname,
						       size, param, nested);
  }
  
  boolean writeData(Sof& sof, const String& name = DEF_PARAM) const {
    return MVectorMethods::writeData<TScalar,TIntegral>(*this, sof, name);
  }
  
  // equality methods
  //
  boolean eq(const MVector& vector) const;
  
  // memory management methods:
  //  the new and delete methods are omitted because they are defined in the
  //  classes that instantiate this template
  //
  boolean clear(Integral::CMODE cmode = Integral::DEF_CMODE);
  
  //-------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  extensions to required methods
  //
  //-------------------------------------------------------------------------
  
  // debug methods:
  //  this second debug method is used so that template instantiations can use
  //  a common debug method and just pass in their name
  //
  boolean debug(const String& name, const unichar* message) const;
  
  // constructor(s)
  //
  MVector(long len);
  
  // assign methods
  //
  boolean assign(TIntegral value);    
  boolean assign(long length, TIntegral value);
  
  // array conversion methods
  //
  template<class TAIntegral>
  boolean assign(long num_elem, const TAIntegral* arg) {
    return MVectorMethods::assign<TScalar,TIntegral>(*this, num_elem, arg);
  }
  
  // conversion from string methods
  //
  boolean assign(const String& arg, unichar delim = DEF_DELIM) {
    return MVectorMethods::assign<TScalar,TIntegral>(*this, arg, delim);
  }
  
  boolean assign(const unichar* arg, unichar delim = DEF_DELIM) {
    return MVectorMethods::assign<TScalar,TIntegral>(*this, arg, delim);
  }
  
  // conversion to string methods
  //
  boolean get(String& output, const String& delim = DEF_DELIM_STR) const {
    return MVectorMethods::get(*this, output, delim);
  }
  
  boolean get(String& output, const unichar* delim) const {
    String delim_str(delim);
    return MVectorMethods::get(*this, output, delim_str);
  }
  
  // swap methods:
  //  swap the current vector with the input vector
  //
  boolean swap(MVector& arg) {
    return MVectorMethods::swap<TScalar, TIntegral>(*this, arg);
  }
  
  // partial read methods
  //
  boolean readStart(Sof& sof, const String& pname = DEF_PARAM,
		    long size = SofParser::FULL_OBJECT,
		    boolean param = true,
		    boolean nested = true) {
    return MVectorMethods::
      readStart<TScalar, TIntegral>(*this, sof, pname, size, param, nested);
  }
  
  long readPartialData(Sof& sof, long start_pos, long num_elem,
		       const String& pname = DEF_PARAM,
		       long size = SofParser::FULL_OBJECT,
		       boolean param = true,
		       boolean nested = false) {
    return MVectorMethods::
      readPartialData<TScalar,TIntegral>(*this, sof, start_pos,
					 num_elem, pname, size, param, nested);
  }
  
  // method: readTerminate
  //
  boolean readTerminate(Sof& sof) {
    return sof.stopPartialRead();
  }
  
  // partial write methods
  //
  boolean writeStart(Sof& sof, const String& pname = DEF_PARAM) const {
    return MVectorMethods::writeStart<TScalar,TIntegral>(*this, sof, pname);
  }
  
  long writePartialData(Sof& sof, long start_pos, long num_elem) const {
    return MVectorMethods::
      writePartialData<TScalar, TIntegral>(*this, sof, start_pos, num_elem);
  }
  
  boolean writeTerminate(Sof& sof, const String& pname = DEF_PARAM) const {
    return MVectorMethods::
      writeTerminate<TScalar, TIntegral>(*this, sof, pname);
  }
  
  // memory size methods
  //
  long memSize() const {
    return MVectorMethods::memSize<TScalar, TIntegral>(*this);
  }
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  equality and comparison methods
  //
  //---------------------------------------------------------------------------
  
  // method: eq
  //
  boolean eq(TIntegral value) const {
    return apply(value, &TScalar::eq);
  }
  
  // method: ne
  //
  boolean ne(const MVector& vector) const {
    return (!eq(vector));
  }
  
  // method: ne
  //
  boolean ne(TIntegral value) const {
    return apply(value, &TScalar::ne);
  }
  
  // method: lt
  //
  boolean lt(TIntegral value) const {
    return apply(value, &TScalar::lt);
  }
  
  // method: le
  //
  boolean le(TIntegral value) const {
    return apply(value, &TScalar::le);
  }
  
  // method: gt
  //
  boolean gt(TIntegral value) const {
    return apply(value, &TScalar::gt);
  }
  
  // method: ge
  //
  boolean ge(TIntegral value) const {
    return apply(value, &TScalar::ge);
  }
  
  // method: operator ==
  //
  boolean operator == (TIntegral arg) const {
    return eq(arg);
  }
  
  // method: operator !=
  //
  boolean operator != (TIntegral arg) const {
    return ne(arg);
  }
  
  // method: operator <
  //
  boolean operator < (TIntegral arg) const {
    return lt(arg);
  }
  
  // method: operator <=
  //
  boolean operator <= (TIntegral arg) const {
    return le(arg);
  }
  
  // method: operator >
  //
  boolean operator > (TIntegral arg) const {
    return gt(arg);
  }
  
  // method: operator >=
  //
  boolean operator >= (TIntegral arg) const {
    return ge(arg);
  }
  
  // almostEqual methods
  //
  boolean almostEqual(const MVector& vector,
		      double percent = Integral::DEF_PERCENTAGE,
		      double bound = Integral::DEF_BOUND) const;
  boolean almostEqual(TIntegral value,
		      double percent = Integral::DEF_PERCENTAGE,
		      double bound = Integral::DEF_BOUND) const;
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  operator overloads, get and set methods
  //
  //---------------------------------------------------------------------------
  
  // method: operator()
  //
  TScalar& operator()(long index_a) {
    return v_d[index_a];
  }
  
  // method: operator()
  //
  const TScalar& operator()(long index_a) const {
    return v_d[index_a];
  }
  
  // method: length
  //
  long length() const {
    return (long)length_d;
  }
  
  // method: getCapacity
  //
  long getCapacity() const {
    return (long)capacity_d;
  }
  
  // resize methods
  //
  boolean setLength(long length, boolean preserve_values = true);
  boolean setCapacity(long capacity, boolean preserve_values = true);
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  bitwise methods, report error if TIntegral is float or double
  //
  //--------------------------------------------------------------------------
  
  // method: band
  //
  boolean band(const MVector& v2) {
    return apply(*this, v2, &TScalar::band);
  }
  
  // method: band
  //
  boolean band(const MVector& v1, const MVector& v2) {
    return apply(v1, v2, &TScalar::band);
  }
  
  // method: band
  //
  boolean band(TIntegral value) {
    return apply(*this, value, &TScalar::band);
  }
  
  // method: band
  //
  boolean band(const MVector& v1, TIntegral value) {
    return apply(v1, value, &TScalar::band);
  }
  
  // method: bor
  //
  boolean bor(const MVector& v2) {
    return apply(*this, v2, &TScalar::bor);
  }
  
  // method: bor
  //
  boolean bor(const MVector& v1, const MVector& v2) {
    return apply(v1, v2, &TScalar::bor);
  }
  
  // method: bor
  //
  boolean bor(TIntegral value) {
    return apply(*this, value, &TScalar::bor);
  }
  
  // method: bor
  //
  boolean bor(const MVector& v1, TIntegral value) {
    return apply(v1, value, &TScalar::bor);
  }
  
  // method: bxor
  //
  boolean bxor(const MVector& v2) {
    return apply(*this, v2, &TScalar::bxor);
  }
  
  // method: bxor
  //
  boolean bxor(const MVector& v1, const MVector& v2) {
    return apply(v1, v2, &TScalar::bxor);
  }
  
  // method: bxor
  //
  boolean bxor(TIntegral value) {
    return apply(*this, value, &TScalar::bxor);
  }
  
  // method: bxor
  //
  boolean bxor(const MVector& v1, TIntegral value) {
    return apply(v1, value, &TScalar::bxor);
  }
  
  // method: brs
  //
  boolean brs(TIntegral shift_amount = DEF_SHIFT) {
    return apply(*this, shift_amount, &TScalar::brs);
  }
  
  // method: brs
  //
  boolean brs(const MVector& v1, TIntegral shift_amount = DEF_SHIFT) {
    return apply(v1, shift_amount, &TScalar::brs);
  }
  
  // method: bls
  //
  boolean bls(TIntegral shift_amount = DEF_SHIFT) {
    return apply(*this, shift_amount, &TScalar::bls);
  }
  
  // method: bls
  //
  boolean bls(const MVector& v1, TIntegral shift_amount = DEF_SHIFT) {
    return apply(v1, shift_amount, &TScalar::bls);
  }
  
  // method: bcmpl
  //
  boolean bcmpl(const MVector& v1) {
    return apply(v1, &TScalar::bcmpl);
  }
  
  // method: bcmpl
  //
  boolean bcmpl() {
    return apply(*this, &TScalar::bcmpl);
  }
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  basic mathematical methods
  //
  //--------------------------------------------------------------------------
  
  // method: add
  //
  template<class TAScalar, class TAIntegral>
  boolean add(const MVector<TAScalar, TAIntegral>& vector) {
    return apply(*this, vector, &TScalar::add);
  }
  
  // method: add
  //
  template<class TAScalar, class TAIntegral>
  boolean add(const MVector& v1, const MVector<TAScalar, TAIntegral>& v2) {
    return apply(v1, v2, &TScalar::add);
  }
  
  // method: add
  //
  boolean add(TIntegral value) {
    return apply(*this, value, &TScalar::add);
  }
  
  // method: add
  //
  boolean add(const MVector& vector, TIntegral value) {
    return apply(vector, value, &TScalar::add);
  }
  
  // method: sub
  //
  template<class TAScalar, class TAIntegral>
  boolean sub(const MVector<TAScalar, TAIntegral>& vector) {
    return apply(*this, vector, &TScalar::sub);
  }
  
  // method: sub
  //
  template<class TAScalar, class TAIntegral>
  boolean sub(const MVector& v1, const MVector<TAScalar, TAIntegral>& v2) {
    return apply(v1, v2, &TScalar::sub);
  }
  
  // method: sub
  //
  boolean sub(TIntegral value) {
    return apply(*this, value, &TScalar::sub);
  }
  
  // method: sub
  //
  boolean sub(const MVector& vector, TIntegral value) {
    return apply(vector, value, &TScalar::sub);
  }
  
  // method: mult
  //
  template<class TAScalar, class TAIntegral>
  boolean mult(const MVector<TAScalar, TAIntegral>& vector) {
    return apply(*this, vector, &TScalar::mult);
  }
  
  // method: mult
  //
  template<class TAScalar, class TAIntegral>
  boolean mult(const MVector& v1, const MVector<TAScalar, TAIntegral>& v2) {
    return apply(v1, v2, &TScalar::mult);
  }
  
  // method: mult
  //
  boolean mult(TIntegral value) {
    return apply(*this, value, &TScalar::mult);
  }
  
  // method: mult
  //
  boolean mult(const MVector& vector, TIntegral value) {
    return apply(vector, value, &TScalar::mult);
  }
  
  // method: div
  //
  template<class TAScalar, class TAIntegral>
  boolean div(const MVector<TAScalar, TAIntegral>& vector) {
    return apply(*this, vector, &TScalar::div);
  }
  
  // method: div
  //
  template<class TAScalar, class TAIntegral>
  boolean div(const MVector& v1, const MVector<TAScalar, TAIntegral>& v2) {
    return apply(v1, v2, &TScalar::div);
  }
  
  // method: div
  //
  boolean div(TIntegral value) {
    return apply(*this, value, &TScalar::div);
  }
  
  // method: div
  //
  boolean div(const MVector& vector, TIntegral value) {
    return apply(vector, value, &TScalar::div);
  }
  
  // method: mod
  //
  boolean mod(const MVector& vector) {
    return apply(*this, vector, &TScalar::mod);
  }
  
  // method: mod
  //
  boolean mod(const MVector& v1, const MVector& v2) {
    return apply(v1, v2, &TScalar::mod);
  }
  
  // method: mod
  //
  boolean mod(TIntegral value) {
    return apply(*this, value, &TScalar::mod);
  }
  
  // method: mod
  //
  boolean mod(const MVector& vector, TIntegral value) {
    return apply(vector, value, &TScalar::mod);
  }
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  other mathematical methods
  //
  //--------------------------------------------------------------------------
  
  // common mathematical methods
  //
  boolean pow(double y) {
    return MVectorMethods::pow<TScalar, TIntegral>(*this, *this, y);
  }
  
  boolean pow(const MVector& x, double y) {
    return MVectorMethods::pow<TScalar, TIntegral>(*this, x, y);
  }
  
  // method: exp
  //
  boolean exp() {
    return apply(*this, &TScalar::exp);
  }
  
  // method: exp
  //
  boolean exp(const MVector& vector) {
    return apply(vector, &TScalar::exp);
  }
  
  // method: exp2
  //
  boolean exp2() {
    return apply(*this, &TScalar::exp2);
  }
  
  // method: exp2
  //
  boolean exp2(const MVector& vector) {
    return apply(vector, &TScalar::exp2);
  }
  
  // method: exp10
  //
  boolean exp10() {
    return apply(*this, &TScalar::exp10);
  }
  
  // method: exp10
  //
  boolean exp10(const MVector& vector) {
    return apply(vector, &TScalar::exp10);
  }
  
  // method: factorial
  //
  boolean factorial() {
    return apply(*this, &TScalar::factorial);
  }
  
  // method: factorial
  //
  boolean factorial(const MVector& vector) {
    return apply(vector, &TScalar::factorial);
  }
  
  // method: log
  //
  boolean log() {
    return apply(*this, &TScalar::log);
  }
  
  // method: log
  //
  boolean log(const MVector& vector) {
    return apply(vector, &TScalar::log);
  }
  
  // method: log1p
  //
  boolean log1p() {
    return apply(*this, &TScalar::log1p);
  }
  
  // method: log1p
  //
  boolean log1p(const MVector& vector) {
    return apply(vector, &TScalar::log1p);
  }
  
  // method: log2
  //
  boolean log2() {
    return apply(*this, &TScalar::log2);
  }
  
  // method: log2
  //
  boolean log2(const MVector& vector) {
    return apply(vector, &TScalar::log2);
  }
  
  // method: log10
  //
  boolean log10() {
    return apply(*this, &TScalar::log10);
  }
  
  // method: log10
  //
  boolean log10(const MVector& vector) {
    return apply(vector, &TScalar::log10);
  }
  
  // sorting and indexing methods
  //
  boolean sort(Integral::ORDER order = Integral::DEF_ORDER) {
    return MVectorMethods::sort<TScalar, TIntegral>(*this, *this, order);
  }
  
  boolean sort(const MVector& vector,
	       Integral::ORDER order = Integral::DEF_ORDER) {
    return MVectorMethods::sort<TScalar, TIntegral>(*this, vector, order);
  }  
  
  boolean index(MVector<Long, long>& sort_index,
		Integral::ORDER order = Integral::DEF_ORDER) {
    return MVectorMethods::index<TScalar, TIntegral>(*this, order, sort_index);
  }
  
  boolean randperm(long size) {
    return MVectorMethods::randperm(*this, size);
  }
  
  // method: abs
  //
  boolean abs() {
    return apply(*this, &TScalar::abs);
  }
  
  // method: abs
  //
  boolean abs(const MVector& vector) {
    return apply(vector, &TScalar::abs);
  }
  
  // mathematical limits, ceiling, floor and rounding methods
  //
  TIntegral max() const {
    static long pos;
    return MVectorMethods::max<TScalar, TIntegral>(*this, pos);
  }
  
  TIntegral max(long& position) const {
    return MVectorMethods::max<TScalar, TIntegral>(*this, position);
  }
  
  TIntegral min() const {
    static long pos;
    return MVectorMethods::min<TScalar, TIntegral>(*this, pos);
  }
  
  TIntegral min(long& position) const {
    return MVectorMethods::min<TScalar, TIntegral>(*this, position);
  }
  
  double minMag() const {
    static long pos;
    return MVectorMethods::minMag<TScalar, TIntegral>(*this, pos);
  }
  
  double minMag(long& position) const {
    return MVectorMethods::minMag<TScalar, TIntegral>(*this, position);
  }
  
  double maxMag() const {
    static long pos;
    return MVectorMethods::maxMag<TScalar, TIntegral>(*this, pos);
  }
  
  double maxMag(long& position) const {
    return MVectorMethods::maxMag<TScalar, TIntegral>(*this, position);
  }
  
  // method: neg
  //
  boolean neg() {
    return apply(*this, &TScalar::neg);
  }
  
  // method: neg
  //
  boolean neg(const MVector& vector) {
    return apply(vector, &TScalar::neg);
  }
  
  // method: round
  //
  boolean round() {
    return apply(*this, &TScalar::round);
  }
  
  // method: round
  //
  boolean round(const MVector& vector) {
    return apply(vector, &TScalar::round);
  }
  
  // method: ceil
  //
  boolean ceil() {
    return apply(*this, &TScalar::ceil);
  }
  
  // method: ceil
  //
  boolean ceil(const MVector& vector) {
    return apply(vector, &TScalar::ceil);
  }
  
  // method: rceil
  //
  boolean rceil() {
    return apply(*this, &TScalar::rceil);
  }
  
  // method: rceil
  //
  boolean rceil(const MVector& vector) {
    return apply(vector, &TScalar::rceil);
  }
  
  // method: floor
  //
  boolean floor() {
    return apply(*this, &TScalar::floor);
  }
  
  // method: floor
  //
  boolean floor(const MVector& vector) {
    return apply(vector, &TScalar::floor);
  }
  
  // method: rfloor
  //
  boolean rfloor() {
    return apply(*this, &TScalar::rfloor);
  }
  
  // method: rfloor
  //
  boolean rfloor(const MVector& vector) {
    return apply(vector, &TScalar::rfloor);
  }
  
  // method: fraction
  //
  boolean fraction() {
    return apply(*this, &TScalar::fraction);
  }
  
  // method: fraction
  //
  boolean fraction(const MVector& vector) {
    return apply(vector, &TScalar::fraction);
  }
  
  // method: sign
  //
  boolean sign() {
    return apply(*this, &TScalar::sign);
  }
  
  // method: sign
  //
  boolean sign(const MVector& vector) {
    return apply(vector, &TScalar::sign);
  }
  
  // method: sin
  //
  boolean sin() {
    return apply(*this, &TScalar::sin);
  }
  
  // method: sin
  //
  boolean sin(const MVector& vector) {
    return apply(vector, &TScalar::sin);
  }
  
  // method: sinh
  //
  boolean sinh() {
    return apply(*this, &TScalar::sinh);
  }
  
  // method: sinh
  //
  boolean sinh(const MVector& vector) {
    return apply(vector, &TScalar::sinh);
  }
  
  // method: cos
  //
  boolean cos() {
    return apply(*this, &TScalar::cos);
  }
  
  // method: cos
  //
  boolean cos(const MVector& vector) {
    return apply(vector, &TScalar::cos);
  }
  
  // method: cosh
  //
  boolean cosh() {
    return apply(*this, &TScalar::cosh);
  }
  
  // method: cosh
  //
  boolean cosh(const MVector& vector) {
    return apply(vector, &TScalar::cosh);
  }  
  
  // method: tan
  //
  boolean tan() {
    return apply(*this, &TScalar::tan);
  }
  
  // method: tan
  //
  boolean tan(const MVector& vector) {
    return apply(vector, &TScalar::tan);
  }

  // method: tanh
  //
  boolean tanh() {
    return apply(*this, &TScalar::tanh);
  }
  
  // method: tanh
  //
  boolean tanh(const MVector& vector) {
    return apply(vector, &TScalar::tanh);
  }
    
  // method: asin
  //
  boolean asin() {
    return apply(*this, &TScalar::asin);
  }
  
  // method: asin
  //
  boolean asin(const MVector& vector) {
    return apply(vector, &TScalar::asin);
  }

  // method: asinh
  //
  boolean asinh() {
    return apply(*this, &TScalar::asinh);
  }
  
  // method: asinh
  //
  boolean asinh(const MVector& vector) {
    return apply(vector, &TScalar::asinh);
  }  
  
  // method: acos
  //
  boolean acos() {
    return apply(*this, &TScalar::acos);
  }
  
  // method: acos
  //
  boolean acos(const MVector& vector) {
    return apply(vector, &TScalar::acos);
  }

  // method: acosh
  //
  boolean acosh() {
    return apply(*this, &TScalar::acosh);
  }
  
  // method: acosh
  //
  boolean acosh(const MVector& vector) {
    return apply(vector, &TScalar::acosh);
  }
  
  // method: atan
  //
  boolean atan() {
    return apply(*this, &TScalar::atan);
  }
  
  // method: atan
  //
  boolean atan(const MVector& vector) {
    return apply(vector, &TScalar::atan);
  }
  
  // method: atanh
  //
  boolean atanh() {
    return apply(*this, &TScalar::atanh);
  }
  
  // method: atanh
  //
  boolean atanh(const MVector& vector) {
    return apply(vector, &TScalar::atanh);
  }
  
  // ramp function generation methods
  //
  boolean ramp(TIntegral offset = DEF_OFFSET, TIntegral incr = DEF_INCR) {
    return MVectorMethods::ramp<TScalar,TIntegral>(*this, offset, incr);
  }
  
  // method: ramp
  //
  boolean ramp(TIntegral offset, TIntegral incr, TIntegral end) {
    return MVectorMethods::ramp<TScalar,TIntegral>(*this, offset, incr, end);
  }
  
  // method: sqrt
  //
  boolean sqrt() {
    return apply(*this, &TScalar::sqrt);
  }
  
  // method: sqrt
  //
  boolean sqrt(const MVector<TScalar,TIntegral>& vec) {
    return apply(vec, &TScalar::sqrt);
  }
  
  // method: square
  //
  boolean square() {
    return apply(*this, &TScalar::square);
  }
  
  // method: square
  //
  boolean square(const MVector<TScalar, TIntegral>& x) {
    return apply(x, &TScalar::square);
  }
  
  // inverse methods
  //
  boolean inverse() {
    return apply(*this, &TScalar::inverse);
  }
  
  boolean inverse(const MVector<TScalar, TIntegral>& x) {
    return apply(x, &TScalar::inverse);
  }
  
  // vector to scalar mathematical methods
  //
  TIntegral sum() const {
    return MVectorMethods::sum<TScalar, TIntegral>(*this);
  }
  
  TIntegral sumSquare() const {
    return MVectorMethods::sumSquare<TScalar, TIntegral>(*this);
  }
  
  TIntegral mean() const {
    return MVectorMethods::mean<TScalar, TIntegral>(*this);
  }
  
  TIntegral median() const {
    return MVectorMethods::median<TScalar, TIntegral>(*this);
  }
  
  TIntegral rms() const {
    return MVectorMethods::rms<TScalar, TIntegral>(*this);
  }
  
  TIntegral var() const {
    return MVectorMethods::var<TScalar, TIntegral>(*this);
  }
  
  TIntegral stdev() const {
    return MVectorMethods::stdev<TScalar, TIntegral>(*this);
  }
  
  TIntegral dotProduct(const MVector& vector) const {
    return MVectorMethods::dotProduct<TScalar, TIntegral>(*this, vector);
  }
  
  // method: norm
  //
  TIntegral norm() const {
    return (TIntegral)Integral::sqrt(dotProduct(*this));
  }
  
  // method: distance
  //
  TIntegral distance(const MVector& vector) const {
    return (TIntegral)Integral::sqrt(distanceSquare(vector));
  }
  
  TIntegral distanceSquare(const MVector& vector) const {
    return MVectorMethods::distanceSquare<TScalar, TIntegral>(*this, vector);
  }
  
  long numEqual(TIntegral test_value) const {
    return MVectorMethods::numEqual<TScalar, TIntegral>(*this, test_value);
  }
  
  long numNotEqual(TIntegral test_value) const {
    return MVectorMethods::numNotEqual<TScalar, TIntegral>(*this, test_value);
  }
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  dsp related methods 
  //
  //--------------------------------------------------------------------------

  // dsp methods
  // 
#ifdef ISIP_TEMPLATE_complex
  boolean limit(TIntegral min_val, TIntegral max_val) {
    return false;
  }
  
  boolean limit(TIntegral min_val, TIntegral max_val, const MVector& vector) {
    return false;
  }
  
  boolean limitMin(TIntegral min_val) {
    return false;
  }
  
  boolean limitMin(TIntegral min_val, const MVector& vector) {
    return false;
  }
  
  boolean limitMax(TIntegral max_val) {
    return false;
  }
  
  boolean limitMax(TIntegral max_val, const MVector& vector) {
    return false;
  }
  
  boolean limitMag(TIntegral cmp_val, TIntegral new_val) {
    return false;
  }
  
  boolean limitMag(TIntegral cmp_val, TIntegral new_val,
		   const MVector& vector) { 
    return false;
  }
  
  boolean centerClip(TIntegral min_val, TIntegral max_val) {
    return false;
  }
  
  boolean centerClip(TIntegral min_val, TIntegral max_val,
		     const MVector& vector) {
    return false;
  }
#else
  boolean limit(TIntegral min_val, TIntegral max_val) {
    return MVectorMethods::limit<TScalar, TIntegral>(*this, min_val, max_val,
						     *this);
  }
  
  boolean limit(TIntegral min_val, TIntegral max_val, const MVector& vector) {
    return MVectorMethods::limit<TScalar, TIntegral>(*this, min_val, max_val,
						     vector);
  }
  
  boolean limitMin(TIntegral min_val) {
    return MVectorMethods::limitMin<TScalar, TIntegral>(*this, min_val, *this);
  }
  
  boolean limitMin(TIntegral min_val, const MVector& vector) {
    return MVectorMethods::
      limitMin<TScalar, TIntegral>(*this, min_val, vector);
  }
  
  boolean limitMax(TIntegral max_val) {
    return MVectorMethods::limitMax<TScalar, TIntegral>(*this, max_val, *this);
  }
  
  boolean limitMax(TIntegral max_val, const MVector& vector) {
    return MVectorMethods::
      limitMax<TScalar, TIntegral>(*this, max_val, vector);
  }
  
  boolean limitMag(TIntegral cmp_val, TIntegral new_val) {
    return MVectorMethods::limitMag<TScalar, TIntegral>(*this, cmp_val,
							new_val, *this);
  }
  
  boolean limitMag(TIntegral cmp_val, TIntegral new_val,
		   const MVector& vector) { 
    return MVectorMethods::limitMag<TScalar, TIntegral>(*this, cmp_val,
							new_val, vector);
  }
  
  boolean centerClip(TIntegral min_val, TIntegral max_val) {
    return MVectorMethods::centerClip<TScalar, TIntegral>(*this, min_val,
							  max_val, *this);
  }
  
  boolean centerClip(TIntegral min_val, TIntegral max_val,
		     const MVector& vector) {
    return MVectorMethods::centerClip<TScalar, TIntegral>(*this, min_val,
							  max_val, vector);
  }
#endif
  
  // random number generation methods  
  //
  boolean rand(Random& generator = Random::GLOBAL_UNIFORM) {
    return MVectorMethods::rand<TScalar, TIntegral>(*this, generator);
  }
  
  boolean rand(TIntegral min_val, TIntegral max_val,
	       Random& generator = Random::GLOBAL_UNIFORM) {
    return MVectorMethods::rand<TScalar, TIntegral>(*this, min_val,
						    max_val, generator);
  }
  
  boolean grand(TIntegral mean, TIntegral stdev,
		Random& generator = Random::GLOBAL_GAUSSIAN) {
    return MVectorMethods::grand<TScalar, TIntegral>(*this, mean,
						     stdev, generator);
  }
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  position operation and search methods
  //
  //--------------------------------------------------------------------------
  
  // position operation methods
  //
  boolean move(const MVector& vector, long num_elements,
	       long source_offset, long dest_offset) {
    return MVectorMethods::move<TScalar, TIntegral>(*this,
						    vector, num_elements,
						    source_offset,
						    dest_offset);
  }
  
  boolean shift(long delta) {
    return MVectorMethods::shift<TScalar, TIntegral>(*this, delta);
  }
  
  boolean shift(const MVector& vector, long delta) {
    return MVectorMethods::shift<TScalar, TIntegral>(*this, vector, delta);
  }
  
  boolean concat(const MVector& v2) {
    return MVectorMethods::concat<TScalar, TIntegral>(*this, v2);
  }
  
  boolean concat(const MVector& v1, const MVector& v2) {
    return MVectorMethods::concat<TScalar, TIntegral>(*this, v1, v2);
  }
  
  boolean deleteRange(long offset, long num_elements) {
    return MVectorMethods::deleteRange<TScalar, TIntegral>(*this, *this,
							   offset,
							   num_elements);
  }
  
  boolean deleteRange(const MVector& v1, long offset, long num_elements) {
    return MVectorMethods::deleteRange<TScalar, TIntegral>(*this,
							   v1,
							   offset,
							   num_elements);
  }
  
  boolean setRange(long offset, long num_elements, TIntegral value) {
    return MVectorMethods::setRange<TScalar, TIntegral>(*this, offset,
							num_elements, value);
  }
  
  // search and ordering methods
  //
  long first(TIntegral value, long start_pos = Integral::NO_POS) {
    return MVectorMethods::first<TScalar, TIntegral>(*this, value, start_pos);
  }
  
  long last(TIntegral value, long end_pos = Integral::NO_POS) {
    return MVectorMethods::last<TScalar, TIntegral>(*this, value, end_pos);
  }
  
  boolean reorder(const MVector<Long, long>& indexes) {
    return MVectorMethods::reorder<TScalar, TIntegral>(*this, indexes);
  }
  
  boolean reorder(const MVector& arg, const MVector<Long,long>& indexes) {
    return MVectorMethods::reorder<TScalar, TIntegral>(*this, arg, indexes);
  }
  
  boolean reverse() {
    return MVectorMethods::reverse<TScalar, TIntegral>(*this);
  }

  
  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:
  
  // apply methods:
  //  these methods apply the specified function to each element of the vector
  //  
  boolean apply(const MVector& arg1, TIntegral (TScalar::*method)(TIntegral));
  
  template<class TAScalar, class TAIntegral>
  boolean apply(const MVector& arg1, const MVector<TAScalar,TAIntegral>& arg2,
		TIntegral (TScalar::*method) (TIntegral, TIntegral));
  
  boolean apply(const MVector& arg1, TIntegral arg2,
		TIntegral (TScalar::*method) (TIntegral, TIntegral));
  
  boolean apply(TIntegral arg2,
		boolean (TScalar::*method) (TIntegral) const) const;
  
  // friend classes:
  //  while friend classes and functions are generally discouraged,
  //  they are used in the MVector class to circumvent the
  //  template delayed compilation problem. 
  //
  friend class MVectorMethods;
};


// method: apply
// 
// arguments:
//  const MVector& v: (input) input vector
//  TIntegral (TScalar::*method_a) (TIntegral,TIntegral): (input) function
//                                                        pointer
//  
// return: a boolean value indicating status
//
// this method applies method_a function to every element of v_a
//
template<class TScalar, class TIntegral>
boolean MVector<TScalar, TIntegral>::
apply(const MVector& v_a, TIntegral (TScalar::*method_a) (TIntegral arg)) {
  
  if (!setLength((long)v_a.length_d, false)) {
    v_a.debug(L"v_a");
    return Error::handle(name(), L"apply", Error::NOMEM, 
			 __FILE__, __LINE__);
  }
  
  // compute piecewise
  //
  for (long index = (long)length_d - 1; index >= 0; index--) {
    (v_d[index].*method_a)(v_a.v_d[index]);
  }

  // exit gracefully
  // 
  return true;  
}

// method: apply
// 
// arguments:
//  const MVector& v1: (input) input vector
//  const MVector<TAScalar, TAIntegral>& v2: (input) input vector
//  TIntegral (TScalar::*method_a) (TIntegral,TIntegral): (input) function
//                                                        pointer
//
// return: a boolean value indicating status
//
// this method applies method_a function to every element of v1_a and v2_a
//
template<class TScalar, class TIntegral>
template<class TAScalar, class TAIntegral>
boolean MVector<TScalar, TIntegral>::
apply(const MVector& v1_a, const MVector<TAScalar, TAIntegral>& v2_a,
      TIntegral (TScalar::*method_a) (TIntegral,TIntegral)) {
  
  // make sure the lengths are equal
  //
  long last_index = (long)v1_a.length_d;
  
  if (last_index != (long)v2_a.length()) {
    v1_a.debug(L"v1_a");        
    v2_a.debug(L"v2_a");    
    return Error::handle(name(), L"apply", Error::ARG, __FILE__, __LINE__);
    
  }
  
  // resize
  //
  if (!setLength(last_index, false)) {
    this->debug(L"this");
    return Error::handle(name(), L"apply", Error::NOMEM, __FILE__, __LINE__);
  }
  
  // loop through each element
  //
  for (long index = 0; index < last_index; index++) {
    (v_d[index].*method_a)((TIntegral)v1_a.v_d[index], 
			   (TIntegral)v2_a(index));
  }

  // exit gracefully
  //
  return true;
}

// method: apply
// 
// arguments:
//  const MVector& v: (input) input vector
//  TIntegral val: (input) input parameter
//  TIntegral (TScalar::*method_a) (TIntegral,TIntegral): (input) function
//                                                        pointer
//  
// return: a boolean value indicating status
//
// this method applies method_a function to every element of v with
// parameter val
//
template<class TScalar, class TIntegral>
boolean MVector<TScalar, TIntegral>::
apply(const MVector& v_a, TIntegral val_a,
      TIntegral (TScalar::*method_a) (TIntegral,TIntegral)) {
  
  // make sure the lengths are equal
  //
  long last_index = (long)v_a.length_d;
  
  // resize
  //
  if (!setLength(last_index, false)) {
    v_a.debug(L"v_a");        
    this->debug(L"this");
    return Error::handle(name(), L"apply", Error::NOMEM, __FILE__, __LINE__);
  }
  
  // loop through each element
  //
  for (long index = 0; index < last_index; index++) {
    (v_d[index].*method_a)((TIntegral)v_a.v_d[index], val_a);
  }

  // exit gracefully
  //
  return true;
}

// method: apply
// 
// arguments:
//  TIntegral val: (input) input parameter
//  TIntegral (TScalar::*method_a) (TIntegral,TIntegral): (input) function
//                                                        pointer
//  
// return: a boolean value indicating status
//
// this method applies method_a function to every element of the current vector
//
template<class TScalar, class TIntegral>
boolean MVector<TScalar, TIntegral>::
apply(TIntegral val_a, boolean (TScalar::*method_a) (TIntegral) const) const {
  
  // make sure the lengths are equal
  //
  long last_index = (long)length_d;
  
  // loop through each element
  //
  for (long index = 0; index < last_index; index++) {
    if (!(v_d[index].*method_a)(val_a)) {
      return false;
    }
  }

  // exit gracefully
  //
  return true;
}

// method: assign
//
// arguments:
//  const MVector<TAScalar, TAIntegral>& vector: (input) operand
//
// return: a boolean value indicating status
//
// this method copies the input vector to the current vector
// 
template<class TScalar, class TIntegral>
template<class TAScalar, class TAIntegral>
boolean MVector<TScalar, TIntegral>::
assign(const MVector<TAScalar, TAIntegral>& vector_a) {
  
  // resize
  // 
  if (!setLength(vector_a.length(), false)) {
    this->debug(L"this");
    vector_a.debug(L"vector_a");        
    return Error::handle(name(), L"assign", Error::NOMEM, __FILE__, __LINE__);
  }
  if (!setCapacity(vector_a.getCapacity(), false)) {
    this->debug(L"this");
    vector_a.debug(L"vector_a");        
    return Error::handle(name(), L"assign", Error::NOMEM, __FILE__, __LINE__);
  }
  
  // copy the data
  // 
  long last_index = (long)length_d;
  for (long index = 0; index < last_index; index++) {
    v_d[index] = (TIntegral)vector_a(index);
  }
  
  // exit gracefully
  // 
  return true;
}

// method: assign
//
// arguments:
//  MVector<TScalar, TIntegral>& this: (output) class operand
//  long length: (input) length
//  const TAIntegral* v: (input) Vector data
//
// return: a boolean value indicating status
//
// this method creates a vector from a TAIntegral* array
//
template<class TScalar, class TIntegral, class TAIntegral>
boolean MVectorMethods::assign(MVector<TScalar, TIntegral>& this_a, 
			       long length_a, const TAIntegral* v_a) {
  
  // check argument
  //
  if (length_a <= 0) {
    this_a.debug(L"this_a");        
    return Error::handle(name(), L"assign", Error::ARG, __FILE__, __LINE__);
  }
  
  // resize
  // 
  if (!this_a.setLength(length_a, false)) {
    this_a.debug(L"this_a");    
    return Error::handle(name(), L"assign", Error::NOMEM, __FILE__, __LINE__);
  }
  
  // copy the data
  //
  TAIntegral* ptr_cdata = (TAIntegral*)v_a;
  
  for (long index = 0; index < length_a; index++) {
    this_a.v_d[index] = (TIntegral)(*ptr_cdata++);
  }
  
  // exit gracefully
  // 
  return true;
}

// end of include file
//
#endif
