name: Math: public AlgorithmBase
synopsis:

>     g++ [flags ...] file ... -l /isip/tools/lib/$ISIP_BINARY/lib_algo.a

>     #include <Math.h>

>     Math();
>     Math(const Math& arg);
>     const String& className() const;
>     boolean setNumOperands(long num);
>     boolean setFunction(const String& functions);
>     boolean setOperation(const String& operations);
>     boolean compute(VectorFloat& output, const VectorFloat& input);

quick start:

>     // compute Y = 2.0 * X1 + 3.0 * X2 + 2.0
>     //
>     Math math;
>     math.setConstant(2.0);
>     math.setWeight(L"2.0, 3.0");

>     VectorFloat input;
>     VectorFloat output;
>     VectorFloat result;

>     input.assign(L"1.1, 4.0, 1.5, 2.3, 1.0, 1.0, 0.0, 0.0");
>     math.compute(output, input);

description:
This class allows users to build arbitrary mathematical expressions using a set of predefined building blocks. A general description of the capabilities of this class is summarized by this equation:
A formal description of the options available in this class is given below:
Notes:

1. The behavior of these options are the same for all functions supported. See the definition of the enumeration named FUNCTION above for an exhaustive list.
2. All function choices are implemented the same way as shown in these two examples. The selection of functions available is based on the math functions available in the Math Scalar classes.
3. Note that the input values can be matrices and vectors. In this case, limited linear algebra options (e.g., INVERSE, TRANSPOSE) are supported in addition to the normal math function (e.g., ADD).

This class is best described through a simple example:
This would be implemented by assigning the following parameters:
The first portion of this mathematical expression, corresponding to operand no. 0, is implemented using the ASSIGN operation and a LOG function, along with a weight of 0.5. The next part of the expression is implemented using an ADD operation and a ATAN function. The third part is implemented with the MULT operation and COS function. As you can see, the operation specification for a particular operand refers to the operator to the left of the operand.
The Math class is a vital part of isip_transform since it allows users to do somewhat arbitrary operations on feature values that might not be available through a standard algorithm class.
dependencies:

- AlgorithmBase
- VectorLong
- VectorFloat
- Long
- Float

public constants:

- define the class name:

      static const String CLASS_NAME = L"LinearTransform";

- define the algorithm choices:

      enum ALGORITHM { FUNCTION_CALCULATOR = 0, DEF_ALGORITHM = FUNCTION_CALCULATOR };

- define the implementation choices:

      enum IMPLEMENTATION { ENUMERATE = 0, DEF_IMPLEMENTATION = ENUMERATE };

- define the operation choices:

      enum OPERATION { ASSIGN = 0, ADD, SUBTRACT, MULTIPLY, DIVIDE, DEF_OPERATION = ASSIGN };

- define the function choices:

      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 };

- define static NameMap objects:

      static const NameMap ALGO_MAP = L"FUNCTION_CALCULATOR";

      static const NameMap IMPL_MAP = L"ENUMERATE";

      static const NameMap OPERATION_MAP = L"ADD, SUBTRACT, MULTIPLY, DIVIDE, ASSIGN";

      static const NameMap FUNCTION_MAP = L"IDENTITY, EXP, EXP2, EXP10, FACTORIAL, LOG,LOG2, LOG10, LOG1P, ABS, NEG, ROUND, CEIL, FLOOR, RFLOOR, SIN, COS, TAN, ASIN, ACOS, ATAN, SQRT, SQUARE, TRANSPOSE, INVERSE";

- define i/o related variables:

      static const String PARAM_NUMBER = L"num_operands";

      static const String PARAM_ALGORTITHM = L"algorithm";

      static const String PARAM_IMPLEMENTATION = L"implementation";

      static const String PARAM_CONST = L"constant";

      static const String PARAM_FUNCTION = L"function";

      static const String PARAM_OPERATION = L"operation";

      static const String PARAM_WEIGHT = L"weight";

      static const String DELIM = L",";

- define the default value(s) of class data:

      static const long DEF_NUM_OPERANDS = 2;

      static const float DEF_CONST = 0.0;

      static const AlgorithmData::COEF_TYPE DEF_COEF_TYPE = AlgorithmData::DEF_CTYPE;

error codes:

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

- algorithm type:

      ALGORITHM algorithm_d;

- implementation name:

      IMPLEMENTATION implementation_d;

- the number of operands:

      Long num_operands_d;

- function and operations types and weights: we keep track of the function name as well as the pointers in the NameMap because we need to compute object size for i/o.

      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:

- static methods:

      static const String& name();

      static boolean diagnose(Integral::DEBUG debug_level);

- debug methods: setDebug method is inherited from the base class

      boolean debug(const unichar* message) const;

- destructor/constructor(s):

      ~Math();

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

      Math(const Math& arg);

- assign methods: boolean assign(const Math& arg);
- operator= methods:

      Math& operator= (const Math& arg);

- i/o methods:

      long sofSize() const;

      boolean read(Sof& sof, long tag);

      boolean write(Sof& sof, long tag) const;

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

      boolean writeData(Sof& sof, const String& pname) const;

- equality methods:

      boolean eq(const Math& arg) const;

- memory management methods:

      static void* operator new(size_t size);

      static void* operator new[](size_t size);

      static void operator delete(void* ptr);

      static void operator delete[](void* ptr);

      static boolean setGrowSize(long grow_size);

      boolean clear(Integral::CMODE ctype = Integral::DEF_CMODE);

class-specific public methods:

- set methods:

      boolean setAlgorithm(ALGORITHM algorithm);

      boolean setImplementation(IMPLEMENTATION implementation);

      boolean setNumOperands(long num);

      boolean setOperation(const VectorLong& operation);

      boolean setOperation(OPERATION operation, long index);

      boolean setOperation(const String& operations);

      boolean setFunction(const VectorLong& function);

      boolean setFunction(FUNCTION function, long index);

      boolean setFunction(const String& functions);

      boolean setWeight(const VectorFloat& weight);

      boolean setConstant(float constant);

      boolean set(ALGORITHM algorithm = DEF_ALGORITHM, IMPLEMENTATION implementation = DEF_IMPLEMENTATION, long num_operands = DEF_NUM_OPERANDS);

- get methods:

      ALGORITHM getAlgorithm();

      IMPLEMENTATION getImplementation();

      long getNumOperands();

      const VectorLong& getOperation() const;

      boolean getOperation(String& operation) const;

      const VectorLong& getFunction() const;

      boolean getFunction(String& function) const;

      const VectorFloat& getWeight() const;

      float getConstant() const;

      boolean get(ALGORITHM& algorithm, IMPLEMENTATION& implementation, long& num_operands) const;

- computational methods:

      boolean compute(AlgorithmData& output, const Vector<AlgorithmData>& input, AlgorithmData::COEF_TYPE input_coef_type = AlgorithmData::UNKNOWN, long index = DEF_CHANNEL_INDEX);

- AlgorithmBase interface contract methods:

      boolean assign(const AlgorithmBase& arg);

      boolean eq(const AlgorithmBase& arg) const;

      const String& className() const;

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

      boolean setParser(SofParser* parser);

private methods:

- algorithm-specific 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);

- algorithm-specific computational methods: function calculator

      boolean computeFuncCalcEnumerate(VectorFloat& output, const VectorFloat& input);

      boolean computeFuncCalcEnumerateFloat(VectorFloat& output, const VectorFloat& input);

      boolean computeFuncCalcEnumerateDouble(VectorFloat& output, const VectorFloat& input);

      boolean computeFuncCalcEnumerateCFloat(VectorFloat& output, const VectorFloat& input);

      boolean computeFuncCalcEnumerateCDouble(VectorFloat& output, const VectorFloat& input);

- compute methods: float

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

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

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

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

- compute methods: complex float

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

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

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

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

- compute methods: double

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

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

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

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

- compute methods: complex double

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

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

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

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

examples:

- This example shows how to compute an equation of the form:
  y = x(0) + x(1) - log(x(2)) - exp(x4)
  using the Math class. Note that inputs are numbered starting at zero.

      // isip include files
      //
      #include <Math.h>

      // main program starts here
      // compute Y = X1 + X2 - log(X3) - exp(X4)
      //
      int main(int argc, const char **argv) {

        // declare a Math object
        //
        Math math;

        // set the number of operands and weights for each operand
        //
        math.setNumOperands(4);
        math.setWeight(L"1.0, 2.0, 1.0, 1.0");

        // declare and set the functions
        //
        VectorLong values(4);
        values(0).assign((long)Math::IDENTITY);
        values(1).assign((long)Math::IDENTITY);
        values(2).assign((long)Math::LOG);
        values(3).assign((long)Math::EXP);
        math.setFunction(values);

        // declare and set the operations
        //
        VectorLong values_op(4);
        values_op(0).assign((long)Math::ASSIGN);
        values_op(1).assign((long)Math::ADD);
        values_op(2).assign((long)Math::SUBTRACT);
        values_op(3).assign((long)Math::SUBTRACT);
        math.setOperation(values_op);

        // declare the input, output and the expected result
        //
        Vector input;
        AlgorithmData output;
        VectorFloat result;

        // set the input object
        //
        input.setLength(4);
        input(0).makeVectorFloat().assign(L"1.1, 4.0");
        input(1).makeVectorFloat().assign(L"1.5, 2.3");
        input(2).makeVectorFloat().assign(L"1.0, 1.0");
        input(3).makeVectorFloat().assign(L"0.0, 0.0");

        // compute the output object
        //
        math.compute(output, input);

        // error if the expected output is not equal to the actual output
        //
        result.assign(L"3.1, 7.6");
        if (!result.almostEqual(output.getVectorFloat())) {
          input.debug(L"input:");
          output.debug(L"actual output:");
          result.debug(L"expected output:");
          return Error::handle(math.name(), L"compute", Error::TEST,
             __FILE__, __LINE__);
         }

        // print the input and output to console
        //
        input.debug(L"input:");
        output.debug(L"actual output:");

        // exit gracefully
        //
        Integral::exit();
      }

- In this example, we compute:
  y = x(0) + square(x(1)) + exp(x(2)) + 0.5
  using the Math class. In this case, we demonstrate how to use the setConstant method.

      // isip include files
      //
      #include

      // main program starts here
      // compute Y = X0 + square(X1) + exp(X2) + 0.5
      //
      int main(int argc, const char **argv) {

        // declare a Math object
        //
        Math math;

        // set the number of operands, weights for each operand and constant
        // value
        //
        math.setNumOperands(3);
        math.setWeight(L"1.0, 2.0, 1.0");
        math.setConstant(0.5);

        // declare and set the functions
        //
        VectorLong values(3);
        values(0).assign((long)Math::IDENTITY);
        values(1).assign((long)Math::SQUARE);
        values(2).assign((long)Math::EXP);
        math.setFunction(values);

        // declare and set the operations
        //
        VectorLong values_op(3);
        values_op(0).assign((long)Math::ASSIGN);
        values_op(1).assign((long)Math::ADD);
        values_op(2).assign((long)Math::ADD);
        math.setOperation(values_op);

        // declare the input, output and the expected result
        //
        Vector input;
        AlgorithmData output;
        VectorComplexFloat result;

        // set the input object
        //
        input.setLength(3);
        input(0).makeVectorComplexFloat().assign(L"1.1 + 1.1j, 4.0 + 4.0j");
        input(1).makeVectorComplexFloat().assign(L"1.5 + 1.5j, 2.3 + 2.3j");
        input(2).makeVectorComplexFloat().assign(L"1.0 + 1.0j, 1.0 + 1.0j");

        // compute the output object
        //
        math.compute(output, input);

        // error if the expected output is not equal to the actual output
        //
        result.assign(L"2.56869+12.3874j, 5.46869+27.4474j");
        if (!result.almostEqual(output.getVectorComplexFloat())) {
          input.debug(L"input:");
          output.debug(L"actual output:");
          result.debug(L"expected output:");
          return Error::handle(math.name(), L"compute", Error::TEST,
      			 __FILE__, __LINE__);
        }

        // print the input and output to console
        //
        input.debug(L"input:");
        output.debug(L"output:");

        // exit gracefully
        //
        Integral::exit();
      }

notes:

- Note that the function setNumOperands resets the function and operations specifications. Hence, it should be called first, since the previous settings will be lost.