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

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

// isip include files
//
#ifndef ISIP_ALGORITHM_BASE
#include <AlgorithmBase.h>
#endif

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

#ifndef ISIP_VECTOR_LONG
#include <VectorLong.h>
#endif

#ifndef ISIP_VECTOR_FLOAT
#include <VectorFloat.h>
#endif

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

// Math : a class that performs linear combinations on matrix, vector
// and scalar objects, where scalar is represented as a vector of
// length one. this class is designed in such a way that it takes a
// vector of AlgorithmData as input, which allows it to transparently
// manipulate different data types.
//
class Math : public AlgorithmBase {

  //---------------------------------------------------------------------------
  //
  // public constants
  //
  //---------------------------------------------------------------------------
public:

  // define the class name
  //
  static const String CLASS_NAME;

  //----------------------------------------
  //
  // other important constants
  //
  //----------------------------------------
  
  // enumerate the algorithm
  //
  enum ALGORITHM { FUNCTION_CALCULATOR = 0,
		   DEF_ALGORITHM = FUNCTION_CALCULATOR };

  // enumerate the implementation
  //
  enum IMPLEMENTATION { ENUMERATE = 0, DEF_IMPLEMENTATION = ENUMERATE };

  // enumerate the operations
  //
  enum OPERATION { ASSIGN = 0, ADD, SUBTRACT, MULTIPLY, DIVIDE,
		   DEF_OPERATION = ASSIGN };

  // enumerate the functions
  //
  enum FUNCTION { IDENTITY = 0,
		  ABS, ACOS, ASIN, ATAN, CEIL, COS, 
		  EXP, EXP2, EXP10, FACTORIAL, FLOOR, IMAG, INVERSE,
		  LOG, LOG2, LOG10, LOG1P, MAG, NEG, REAL, RFLOOR, ROUND, 
		  SIN, SQRT, SQUARE, TAN, TRANSPOSE,
		  DEF_FUNCTION = IDENTITY };
  
  // define the static NameMap objects
  //
  static const NameMap ALGO_MAP;
  static const NameMap IMPL_MAP;  
  static const NameMap FUNC_MAP;
  static const NameMap OPER_MAP;
  
  //----------------------------------------
  //
  // i/o related constants
  //
  //----------------------------------------

  static const String PARAM_NUMBER;
  static const String PARAM_ALGORITHM;
  static const String PARAM_IMPLEMENTATION;  
  static const String PARAM_CONST;
  static const String PARAM_FUNCTION;
  static const String PARAM_OPERATION;
  static const String PARAM_WEIGHT;
  static const String DELIM;
  
  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------  

  // define the default value(s) of the class data
  //
  static const long DEF_NUM_OPERANDS = 2;
  static const float DEF_CONST = 0.0;
  
  // define default argument(s)
  //
  static const AlgorithmData::COEF_TYPE DEF_COEF_TYPE =
  AlgorithmData::DEF_CTYPE;

  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------  

  static const long ERR = 71300;
  static const long ERR_UNKFUN = 71301;
  static const long ERR_UNKOPE = 71302;
  static const long ERR_FNDTYP = 71303;
  static const long ERR_MATCH = 71304;  

  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:

  // algorithm type
  //
  ALGORITHM algorithm_d;

  // implementation name
  //
  IMPLEMENTATION implementation_d;
  
  // parameters for FUNCTION_CALCULATOR algorithm:
  //  the number of combinations
  //
  Long num_operands_d;
  
  // function, operations types and weights
  //
  VectorLong function_d;
  VectorLong operation_d;
  VectorFloat weight_d;

  // constant term: last additive scalar term
  //
  Float const_d;
  
  // a static memory manager
  //
  static MemoryManager mgr_d;
  
  //---------------------------------------------------------------------------
  //
  // required public methods
  //
  //---------------------------------------------------------------------------
public:
    
  // method: name
  //
  static const String& name() {
    return CLASS_NAME;
  }

  // other static methods
  //    
  static boolean diagnose(Integral::DEBUG debug_level);
  
  // debug methods:
  //  setDebug method is inherited from the base class
  //
  boolean debug(const unichar* msg) const;

  // method: destructor
  //
  ~Math() {}

  // constructor(s)
  //
  Math(ALGORITHM algorithm = DEF_ALGORITHM,
       IMPLEMENTATION implementation = DEF_IMPLEMENTATION,
       long num_operands_d = DEF_NUM_OPERANDS);

  // method: copy constructor
  //
  Math(const Math& arg) {
    assign(arg);
  }
  
  // assign methods:
  //
  boolean assign(const Math& arg);

  // method: operator=
  //
  Math& operator= (const Math& copy_node) {
    assign(copy_node);
    return *this;
  }
  
  // i/o methods:
  //
  long sofSize() const;

  boolean read(Sof& sof, long tag, const String& name = CLASS_NAME);
  boolean write(Sof& sof, long tag, const String& name = CLASS_NAME) const;

  boolean readData(Sof& sof, const String& pname = String::EMPTY,
		   long size = SofParser::FULL_OBJECT,
		   boolean param = true,
                   boolean nested = false);
  boolean writeData(Sof& sof, const String& pname = String::EMPTY) const;

  // equality methods:
  //
  boolean eq(const Math& arg) const;

  // method: new
  //
  static void* operator new(size_t size) {
    return mgr_d.get();
  }

  // method: new[]
  //
  static void* operator new[](size_t size) {
    return mgr_d.getBlock(size);
  }

  // method: delete
  //
  static void operator delete(void* ptr) {
    mgr_d.release(ptr);
  }
  
  // method: delete[]
  //
  static void operator delete[](void* ptr) {
    mgr_d.releaseBlock(ptr);
  }
  
  // method: setGrowSize
  //
  static boolean setGrowSize(long grow_size) {
    return mgr_d.setGrow(grow_size);
  }

  // other memory management methods
  //  
  boolean clear(Integral::CMODE ctype = Integral::DEF_CMODE);

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  set methods  
  //
  //---------------------------------------------------------------------------

  // method: setAlgorithm
  //
  boolean setAlgorithm(ALGORITHM algorithm) {
    algorithm_d = algorithm;
    is_valid_d = false;
    return true;
  }

  // method: setImplementation
  //
  boolean setImplementation(IMPLEMENTATION implementation) {
    implementation_d = implementation;
    is_valid_d = false;
    return true;  
  }
  
  // method: setNumOperands
  //
  boolean setNumOperands(long num_a) {
    num_operands_d = num_a;
    function_d.assign(num_operands_d, (long)DEF_FUNCTION);
    operation_d.assign(num_operands_d, (long)DEF_OPERATION);
    operation_d(0).assign((long)ASSIGN);
    return weight_d.assign(num_operands_d, (float)1.0);
  }

  // method: setOperation
  //
  boolean setOperation(const VectorLong& operation_a) {
    return operation_d.assign(operation_a);
  }

  // method: setOperation
  //
  boolean setOperation(OPERATION operation_a, long index_a) {
    return operation_d(index_a).assign((long)operation_a);
  }

  // method: setFunction
  //
  boolean setFunction(const VectorLong& function_a) {
    return function_d.assign(function_a);
  }

  // method: setFunction
  //
  boolean setFunction(FUNCTION function_a, long index_a) {
    return function_d(index_a).assign((long)function_a);
  }

  // method: setWeight
  //
  boolean setWeight(const VectorFloat& weight) {
    weight_d.assign(weight);
    is_valid_d = false;
    return true;
  }

  // method: setConstant
  //  
  boolean setConstant(float constant) {
    const_d = constant;
    is_valid_d = false;
    return true;
  }

  // method: set
  //
  boolean set(ALGORITHM algorithm = DEF_ALGORITHM,
	      IMPLEMENTATION implementation = DEF_IMPLEMENTATION,
	      long num_operands = DEF_NUM_OPERANDS) {
    algorithm_d = algorithm;
    implementation_d = implementation;
    num_operands_d = num_operands;
    is_valid_d = false;
    return true;
  }

  // other set methods
  //
  boolean setFunction(const String& functions);
  boolean setOperation(const String& functions);
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  get methods  
  //
  //---------------------------------------------------------------------------

  // method: getAlgorithm
  //
  ALGORITHM getAlgorithm() const {
     return algorithm_d;
  }

  // method: getImplementation
  //
  IMPLEMENTATION getImplementation() const {
    return implementation_d;
  }
  
  // method: getNumOperands
  //  
  long getNumOperands() const {
    return num_operands_d;
  }

  // method: getOperation
  //
  const VectorLong& getOperation() const {
    return operation_d;
  }

  // method: getFunction
  //
  const VectorLong& getFunction() const {
    return function_d;
  }

  // method: getWeight
  //
  const VectorFloat& getWeight() const {
    return weight_d;
  }

  // method: getConstant
  //  
  float getConstant() const {
    return const_d;
  }

  // method: get
  //
  boolean get(ALGORITHM& algorithm,
	      IMPLEMENTATION& implementation,
	      long& num_operands) const {
    algorithm = algorithm_d;
    implementation = implementation_d;
    num_operands = num_operands_d;
    return true;
  }

  // other get methods
  //
  boolean getFunction(String& out) const;
  boolean getOperation(String& out) const;
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  computational methods
  //
  //---------------------------------------------------------------------------
  
  // compute methods
  //
  boolean compute(AlgorithmData& output,
		  const Vector<AlgorithmData>& input,
		  AlgorithmData::COEF_TYPE input_coef_type = DEF_COEF_TYPE,
		  long index = DEF_CHANNEL_INDEX);

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:  
  //  AlgorithmBase interface contract methods
  //
  //---------------------------------------------------------------------------

  // assign method
  //
  boolean assign(const AlgorithmBase& arg);

  // equality method
  //  
  boolean eq(const AlgorithmBase& arg) const;
  
  // method: className
  //
  const String& className() const {
    return CLASS_NAME;
  }
  
  // apply method
  //
  boolean apply(Vector<AlgorithmData>& output,
		const Vector<  CircularBuffer<AlgorithmData> >& input);

  // parser methods
  //
  boolean setParser(SofParser* parser);

  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:

  // common I/O methods
  //
  boolean readDataCommon(Sof& sof, const String& pname,
			 long size = SofParser::FULL_OBJECT,
			 boolean param = true,
			 boolean nested = false);
  boolean writeDataCommon(Sof& sof, const String& pname) const;
    
  // algorithm-specific computational methods: function calculator
  //  these methods are private because of AlgorithmBase interface
  //  contracts which work on "apply" method's interface.
  //
  boolean computeFuncCalcEnumerate(AlgorithmData& output,
				   const Vector<AlgorithmData>& input);

  boolean computeFuncCalcEnumerateFloat(AlgorithmData& output,
					const Vector<AlgorithmData>& input);

  boolean computeFuncCalcEnumerateDouble(AlgorithmData& output,
					 const Vector<AlgorithmData>& input);

  boolean computeFuncCalcEnumerateCFloat(AlgorithmData& output,
					 const Vector<AlgorithmData>& input);

  boolean computeFuncCalcEnumerateCDouble(AlgorithmData& output,
					  const Vector<AlgorithmData>& input);

  // compute methods: float
  //  
  boolean computeAddFloat(AlgorithmData& output,
			  const AlgorithmData& input) const;

  boolean computeSubFloat(AlgorithmData& output,
			  const AlgorithmData& input) const;

  boolean computeMultFloat(AlgorithmData& output,
			   const AlgorithmData& input) const;

  boolean computeDivFloat(AlgorithmData& output,
			  const AlgorithmData& input) const;

  // compute methods: complex float
  //  
  boolean computeAddCFloat(AlgorithmData& output,
			   const AlgorithmData& input) const;

  boolean computeSubCFloat(AlgorithmData& output,
			   const AlgorithmData& input) const;

  boolean computeMultCFloat(AlgorithmData& output,
			    const AlgorithmData& input) const;

  boolean computeDivCFloat(AlgorithmData& output,
			   const AlgorithmData& input) const;

  // compute methods: double
  //  
  boolean computeAddDouble(AlgorithmData& output,
			   const AlgorithmData& input) const;

  boolean computeSubDouble(AlgorithmData& output,
			   const AlgorithmData& input) const;

  boolean computeMultDouble(AlgorithmData& output,
			    const AlgorithmData& input) const;

  boolean computeDivDouble(AlgorithmData& output,
			   const AlgorithmData& input) const;

  // compute methods: complex double
  //  
  boolean computeAddCDouble(AlgorithmData& output,
			   const AlgorithmData& input) const;

  boolean computeSubCDouble(AlgorithmData& output,
			   const AlgorithmData& input) const;

  boolean computeMultCDouble(AlgorithmData& output,
			    const AlgorithmData& input) const;

  boolean computeDivCDouble(AlgorithmData& output,
			   const AlgorithmData& input) const;
};

// end of include file
//
#endif
